Skip to content

Commit

Permalink
onboarding flow first pass
Browse files Browse the repository at this point in the history
  • Loading branch information
kayra1 committed Aug 1, 2024
1 parent 8c3383f commit 7a49030
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 4 deletions.
14 changes: 12 additions & 2 deletions ui/src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
"use client"

import { login } from "../queries"
import { useMutation } from "react-query"
import { getStatus, login } from "../queries"
import { useMutation, useQuery } from "react-query"
import { useState, ChangeEvent } from "react"
import { useCookies } from "react-cookie"
import { useRouter } from "next/navigation"

type statusResponse = {
initialized: boolean
}

export default function LoginPage() {
const router = useRouter()
const [cookies, setCookie, removeCookie] = useCookies(['user_token']);
const statusQuery = useQuery<statusResponse, Error>({
queryFn: () => getStatus()
})
if (statusQuery.data && !statusQuery.data.initialized) {
router.push("/onboarding")
}
const mutation = useMutation(login, {
onSuccess: (e) => {
setErrorText("")
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export default function Navigation({
children: React.ReactNode;
}>) {
const activePath = usePathname()
const noNavRoutes = ['/login'];
const noNavRoutes = ['/login', '/onboarding'];

const shouldRenderNavigation = !noNavRoutes.includes(activePath);
const [sidebarVisible, setSidebarVisible] = useState<boolean>(true)
Expand Down
68 changes: 68 additions & 0 deletions ui/src/app/onboarding/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"use client"

import { useState, ChangeEvent } from "react"
import { postFirstUser } from "../queries"
import { useMutation } from "react-query"
import { useRouter } from "next/router"


export default function Onboarding() {
const router = useRouter()
const mutation = useMutation(postFirstUser, {
onSuccess: () => {
setErrorText("")
router.push("/login")
},
onError: (e: Error) => {
setErrorText(e.message)
}
})
const [username, setUsername] = useState<string>("")
const [password1, setPassword1] = useState<string>("")
const [password2, setPassword2] = useState<string>("")
const passwordsMatch = password1 === password2
const [errorText, setErrorText] = useState<string>("")
const handleUsernameChange = (event: ChangeEvent<HTMLInputElement>) => { setUsername(event.target.value) }
const handlePassword1Change = (event: ChangeEvent<HTMLInputElement>) => { setPassword1(event.target.value) }
const handlePassword2Change = (event: ChangeEvent<HTMLInputElement>) => { setPassword2(event.target.value) }
return (
<div className="p-panel" >
<div className="p-panel__header">
<h4 className="p-panel__title">Welcome to GoCert</h4>
<p>Please create an admin user to get started</p>
</div>
<div className="p-panel__content">
<form className={"p-form-validation " + (!passwordsMatch ? "is-error" : "")}>
<div className="p-form__group row">
<label className="p-form__label">User Name</label>
<input type="text" id="InputUsername" name="InputUsername" onChange={handleUsernameChange} />
<label className="p-form__label">Password</label>
<input className="p-form-validation__input" type="password" id="password1" name="password" placeholder="******" autoComplete="current-password" required={true} onChange={handlePassword1Change} />
<p className="p-form-help-text">
Password must have 8 or more characters, must include at least one capital letter, one lowercase letter, and either a number or a symbol.
</p>
<label htmlFor="p-form__label">Password Again</label>
<input className="p-form-validation__input" type="password" id="InputPassword" name="password2" placeholder="******" autoComplete="current-password" onChange={handlePassword2Change} />
{!passwordsMatch && <p className="p-form-validation__message">Passwords do not match</p>}
{errorText &&
<div className="p-notification--negative">
<div className="p-notification__content">
<h5 className="p-notification__title">Error</h5>
<p className="p-notification__message">{errorText.split("error: ")}</p>
</div>
</div>
}
{!passwordsMatch ? (
<>
<button type="submit" name="submit" disabled={true}>Submit</button>
</>
) : (
<button type="submit" name="submit" onClick={(event) => { event.preventDefault(); mutation.mutate({ username: username, password: password1 }) }}>Submit</button>
)
}
</div>
</form>
</div>
</div >
)
}
27 changes: 26 additions & 1 deletion ui/src/app/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ export type RequiredCSRParams = {
cert?: string
}

export async function getStatus() {
const response = await fetch("/status")
if (!response.ok) {
throw new Error(`${response.status}: ${HTTPStatus(response.status)}`)
}
return response.json()
}

export async function getCertificateRequests(params: { authToken: string }): Promise<CSREntry[]> {
const response = await fetch("/api/v1/certificate_requests", {
headers: { "Authorization": "Bearer " + params.authToken }
Expand Down Expand Up @@ -159,7 +167,7 @@ export async function deleteUser(params: { authToken: string, id: string }) {
return response.json()
}

export async function postUser(userForm: { authToken: string, username: string, password: string }) {
export async function postFirstUser(userForm: { username: string, password: string }) {
const response = await fetch("/api/v1/accounts", {
method: "POST",
headers: {
Expand All @@ -172,4 +180,21 @@ export async function postUser(userForm: { authToken: string, username: string,
throw new Error(`${response.status}: ${HTTPStatus(response.status)}. ${responseText}`)
}
return responseText
}

export async function postUser(userForm: { authToken: string, username: string, password: string }) {
const response = await fetch("/api/v1/accounts", {
method: "POST",
body: JSON.stringify({
"username": userForm.username, "password": userForm.password
}),
headers: {
'Authorization': "Bearer " + userForm.authToken
}
})
const responseText = await response.text()
if (!response.ok) {
throw new Error(`${response.status}: ${HTTPStatus(response.status)}. ${responseText}`)
}
return responseText
}

0 comments on commit 7a49030

Please sign in to comment.