mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-19 15:55:26 +02:00
adding password form
This commit is contained in:
parent
2b20d129ae
commit
455ecf2a37
@ -11,6 +11,8 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.4",
|
||||
"@emotion/styled": "^11.10.4",
|
||||
"@mdi/js": "^7.0.96",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@mui/lab": "^5.0.0-alpha.103",
|
||||
"@mui/material": "^5.10.9",
|
||||
"@tanstack/react-query": "^4.12.0",
|
||||
|
@ -11,6 +11,7 @@ import AliasesRoute from "~/routes/AliasesRoute"
|
||||
import AuthContextProvider from "~/AuthContext/AuthContextProvider"
|
||||
import AuthenticateRoute from "~/routes/AuthenticateRoute"
|
||||
import AuthenticatedRoute from "~/routes/AuthenticatedRoute"
|
||||
import CompleteAccountRoute from "~/routes/CompleteAccountRoute"
|
||||
import RootRoute from "~/routes/Root"
|
||||
import SignupRoute from "~/routes/SignupRoute"
|
||||
import VerifyEmailRoute from "~/routes/VerifyEmailRoute"
|
||||
@ -35,6 +36,10 @@ const router = createBrowserRouter([
|
||||
path: "/auth/signup",
|
||||
element: <SignupRoute />,
|
||||
},
|
||||
{
|
||||
path: "/auth/complete-account",
|
||||
element: <CompleteAccountRoute />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -5,7 +5,7 @@ import {User} from "~/server-types"
|
||||
interface AuthContextTypeBase {
|
||||
user: User | null
|
||||
isAuthenticated: boolean
|
||||
login: (user: User) => Promise<void>
|
||||
login: (user: User, callback: () => void) => Promise<void>
|
||||
logout: () => void
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,10 @@ export default function AuthContextProvider({
|
||||
}
|
||||
}, [])
|
||||
|
||||
const login = useCallback(async (user: User) => {
|
||||
const login = useCallback(async (user: User, callback?: () => void) => {
|
||||
setUser(user)
|
||||
|
||||
callback?.()
|
||||
}, [])
|
||||
|
||||
const {mutateAsync: refresh} = useMutation<
|
||||
|
@ -24,12 +24,12 @@ interface CreateAliasDataBase extends CreateAliasDataOther {
|
||||
}
|
||||
|
||||
interface CreateAliasDataRandomType extends CreateAliasDataBase {
|
||||
type: AliasType.Random
|
||||
type: AliasType.RANDOM
|
||||
local?: undefined
|
||||
}
|
||||
|
||||
interface CreateAliasDataCustomType extends CreateAliasDataBase {
|
||||
type: AliasType.Custom
|
||||
type: AliasType.CUSTOM
|
||||
local: string
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ export default async function createAlias(
|
||||
): Promise<Alias> {
|
||||
const {data} = await axios.post(
|
||||
`${import.meta.env.VITE_SERVER_BASE_URL}/alias`,
|
||||
aliasData,
|
||||
{},
|
||||
)
|
||||
|
||||
return parseAlias(data)
|
||||
|
4
src/apis/update-account.ts
Normal file
4
src/apis/update-account.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface UpdateAccountData {
|
||||
password: string
|
||||
publicKey: string
|
||||
}
|
@ -10,7 +10,7 @@ export default function MultiStepFormElement({
|
||||
children,
|
||||
}: MultiStepFormElementProps): ReactElement {
|
||||
return (
|
||||
<Box width="90vw" justifyContent="center" alignItems="center">
|
||||
<Box maxWidth="90vw" justifyContent="center" alignItems="center">
|
||||
<Container maxWidth="xs">{children}</Container>
|
||||
</Box>
|
||||
)
|
||||
|
@ -5,7 +5,7 @@ import {AxiosError} from "axios"
|
||||
import {Button} from "@mui/material"
|
||||
import {useMutation} from "@tanstack/react-query"
|
||||
|
||||
import {createAlias, CreateAliasData} from "~/apis"
|
||||
import {CreateAliasData, createAlias} from "~/apis"
|
||||
import {Alias, AliasType} from "~/server-types"
|
||||
|
||||
export interface CreateRandomAliasButtonProps {
|
||||
@ -27,7 +27,7 @@ export default function CreateRandomAliasButton({
|
||||
startIcon={<BsArrowClockwise />}
|
||||
onClick={() =>
|
||||
mutate({
|
||||
type: AliasType.Random,
|
||||
type: AliasType.RANDOM,
|
||||
})
|
||||
}
|
||||
>
|
||||
|
@ -1,10 +1,11 @@
|
||||
import {ReactElement} from "react"
|
||||
import {BiStats} from "react-icons/bi"
|
||||
import {MdMail, MdSettings} from "react-icons/md"
|
||||
import {IoMdDocument} from "react-icons/io"
|
||||
import {Link as RouterLink, useLocation} from "react-router-dom"
|
||||
|
||||
import {Button} from "@mui/material"
|
||||
import {mdiTextBoxMultiple} from "@mdi/js/commonjs/mdi"
|
||||
import Icon from "@mdi/react"
|
||||
|
||||
export enum NavigationSection {
|
||||
Overview,
|
||||
@ -20,7 +21,7 @@ export interface NavigationButtonProps {
|
||||
const SECTION_ICON_MAP: Record<NavigationSection, ReactElement> = {
|
||||
[NavigationSection.Overview]: <BiStats />,
|
||||
[NavigationSection.Aliases]: <MdMail />,
|
||||
[NavigationSection.Reports]: <IoMdDocument />,
|
||||
[NavigationSection.Reports]: <Icon path={mdiTextBoxMultiple} size={0.8} />,
|
||||
[NavigationSection.Settings]: <MdSettings />,
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,9 @@ import {TiCancel} from "react-icons/ti"
|
||||
import React, {ReactElement} from "react"
|
||||
|
||||
import {Box, Button, Grid, Typography} from "@mui/material"
|
||||
import {MultiStepFormElement} from "~/components"
|
||||
import {mdiTextBoxMultiple} from "@mdi/js/commonjs/mdi"
|
||||
import Icon from "@mdi/react"
|
||||
|
||||
export interface GenerateEmailReportsFormProps {
|
||||
onYes: () => void
|
||||
@ -14,7 +17,7 @@ export default function GenerateEmailReportsForm({
|
||||
onYes,
|
||||
}: GenerateEmailReportsFormProps): ReactElement {
|
||||
return (
|
||||
<Box width="80vw">
|
||||
<MultiStepFormElement>
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
@ -33,7 +36,7 @@ export default function GenerateEmailReportsForm({
|
||||
alignItems="center"
|
||||
>
|
||||
<Grid item>
|
||||
<Grid container spacing={2} direction="column">
|
||||
<Grid container spacing={4} direction="column">
|
||||
<Grid item>
|
||||
<Typography
|
||||
variant="h6"
|
||||
@ -43,6 +46,14 @@ export default function GenerateEmailReportsForm({
|
||||
Generate Email Reports?
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Box display="flex" justifyContent="center">
|
||||
<Icon
|
||||
path={mdiTextBoxMultiple}
|
||||
size={2}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
@ -81,6 +92,6 @@ export default function GenerateEmailReportsForm({
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</MultiStepFormElement>
|
||||
)
|
||||
}
|
@ -10,10 +10,8 @@ import {Box, Grid, InputAdornment, Typography} from "@mui/material"
|
||||
import {PasswordField} from "~/components"
|
||||
import {encryptString} from "~/utils"
|
||||
import {isDev} from "~/constants/development"
|
||||
|
||||
export interface PasswordFormProps {
|
||||
email: string
|
||||
}
|
||||
import {useUser} from "~/hooks"
|
||||
import {useMutation} from "@tanstack/react-query"
|
||||
|
||||
interface Form {
|
||||
password: string
|
||||
@ -29,7 +27,9 @@ const schema = yup.object().shape({
|
||||
.oneOf([yup.ref("password"), null], "Passwords must match"),
|
||||
})
|
||||
|
||||
export default function PasswordForm({email}: PasswordFormProps): ReactElement {
|
||||
export default function PasswordForm(): ReactElement {
|
||||
const user = useUser()
|
||||
const {} = useMutation()
|
||||
const awaitGenerateKey = useMemo(
|
||||
() =>
|
||||
generateKey({
|
||||
@ -54,7 +54,7 @@ export default function PasswordForm({email}: PasswordFormProps): ReactElement {
|
||||
|
||||
const encryptedPrivateKey = encryptString(
|
||||
keyPair.privateKey,
|
||||
`${values.password}-${email}`,
|
||||
`${values.password}-${user.email.address}`,
|
||||
)
|
||||
|
||||
console.log(encryptedPrivateKey)
|
@ -6,13 +6,14 @@ import React, {ReactElement} from "react"
|
||||
|
||||
import {InputAdornment, TextField} from "@mui/material"
|
||||
|
||||
import {useMutation} from "@tanstack/react-query"
|
||||
import DetectEmailAutofillService from "./DetectEmailAutofillService"
|
||||
|
||||
import {MultiStepFormElement, SimpleForm} from "~/components"
|
||||
import {checkIsDomainDisposable, signup} from "~/apis"
|
||||
import {SignupResult, checkIsDomainDisposable, signup} from "~/apis"
|
||||
import {parseFastapiError} from "~/utils"
|
||||
import {ServerSettings} from "~/server-types"
|
||||
|
||||
import DetectEmailAutofillService from "./DetectEmailAutofillService"
|
||||
|
||||
export interface EmailFormProps {
|
||||
serverSettings: ServerSettings
|
||||
onSignUp: (email: string) => void
|
||||
@ -31,6 +32,12 @@ export default function EmailForm({
|
||||
onSignUp,
|
||||
serverSettings,
|
||||
}: EmailFormProps): ReactElement {
|
||||
const {mutateAsync} = useMutation<SignupResult, AxiosError, string>(
|
||||
signup,
|
||||
{
|
||||
onSuccess: ({normalized_email}) => onSignUp(normalized_email),
|
||||
},
|
||||
)
|
||||
const formik = useFormik<Form>({
|
||||
validationSchema: SCHEMA,
|
||||
initialValues: {
|
||||
@ -57,8 +64,7 @@ export default function EmailForm({
|
||||
}
|
||||
|
||||
try {
|
||||
await signup(values.email)
|
||||
onSignUp(values.email)
|
||||
await mutateAsync(values.email)
|
||||
} catch (error) {
|
||||
setErrors(parseFastapiError(error as AxiosError))
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
} from "@mui/material"
|
||||
|
||||
import {MultiStepFormElement, OpenMailButton} from "~/components"
|
||||
import ResendMailButton from "~/route-widgets/root/YouGotMail/ResendMailButton"
|
||||
import ResendMailButton from "~/route-widgets/SignupRoute/YouGotMail/ResendMailButton"
|
||||
|
||||
export interface YouGotMailProps {
|
||||
email: string
|
||||
|
@ -24,7 +24,7 @@ export default function AuthenticateRoute(): ReactElement {
|
||||
<Grid item>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/signup"
|
||||
to="/auth/signup"
|
||||
color="inherit"
|
||||
size="small"
|
||||
startIcon={<MdAdd />}
|
||||
@ -35,7 +35,7 @@ export default function AuthenticateRoute(): ReactElement {
|
||||
<Grid item>
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/login"
|
||||
to="/auth/login"
|
||||
color="inherit"
|
||||
size="small"
|
||||
startIcon={<MdLogin />}
|
||||
|
@ -25,7 +25,7 @@ export default function AuthenticatedRoute(): ReactElement {
|
||||
justifyContent="center"
|
||||
height="100vh"
|
||||
>
|
||||
<Box width="90vw" justifyContent="center" alignItems="center">
|
||||
<Box maxWidth="90vw" justifyContent="center" alignItems="center">
|
||||
<Container
|
||||
maxWidth="md"
|
||||
style={{
|
||||
|
27
src/routes/CompleteAccountRoute.tsx
Normal file
27
src/routes/CompleteAccountRoute.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import {ReactElement, useState} from "react"
|
||||
import {useNavigate} from "react-router-dom"
|
||||
|
||||
import {MultiStepForm} from "~/components"
|
||||
import GenerateEmailReportsForm from "~/route-widgets/CompleteAccountRoute/GenerateEmailReportsForm"
|
||||
import PasswordForm from "~/route-widgets/CompleteAccountRoute/PasswordForm"
|
||||
|
||||
export default function CompleteAccountRoute(): ReactElement {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [showGenerationReportForm, setShowGenerationReportForm] =
|
||||
useState(false)
|
||||
|
||||
return (
|
||||
<MultiStepForm
|
||||
steps={[
|
||||
<GenerateEmailReportsForm
|
||||
key="generate_email_reports"
|
||||
onYes={() => setShowGenerationReportForm(true)}
|
||||
onNo={() => navigate("/")}
|
||||
/>,
|
||||
<PasswordForm key="password_form" />,
|
||||
]}
|
||||
index={showGenerationReportForm ? 1 : 0}
|
||||
/>
|
||||
)
|
||||
}
|
@ -46,8 +46,7 @@ export default function VerifyEmailRoute(): ReactElement {
|
||||
>(validateEmail, {
|
||||
onSuccess: async ({user}) => {
|
||||
setEmail("")
|
||||
await login(user)
|
||||
navigate("/")
|
||||
await login(user, () => navigate("/auth/complete-account"))
|
||||
},
|
||||
})
|
||||
const {loading} = useAsync(async () => {
|
||||
|
@ -14,8 +14,8 @@ export enum ProxyUserAgentType {
|
||||
}
|
||||
|
||||
export enum AliasType {
|
||||
Random = "random",
|
||||
Custom = "custom",
|
||||
RANDOM = "random",
|
||||
CUSTOM = "custom",
|
||||
}
|
||||
|
||||
export interface User {
|
Loading…
x
Reference in New Issue
Block a user