improvements & bugfixes

This commit is contained in:
Myzel394 2022-10-15 10:36:17 +02:00
parent 457ef7bc8c
commit 30c52cdaeb
10 changed files with 153 additions and 121 deletions

View File

@ -26,15 +26,20 @@ function MultiStepForm({
const [currentSize, setCurrentSize] = useState<any>(null)
const [nextSize, setNextSize] = useState<any>(null)
const isTransitioning = currentIndex !== index
const isTransitioning = currentIndex < index
useEffect(() => {
if (index !== currentIndex) {
if (index > currentIndex) {
$timeout.current = setTimeout(() => {
setCurrentSize(null)
setNextSize(null)
setCurrentIndex(index)
}, duration)
} else if (index < currentIndex) {
// "Going-back" animation is not supported
setCurrentIndex(index)
setCurrentSize(null)
setNextSize(null)
}
return $timeout.current?.cancel!

View File

@ -19,7 +19,7 @@ export default function OpenMailButton({
return (
<Button
startIcon={<IoMdMailOpen />}
variant="contained"
variant="text"
href={APP_LINK_MAP[domain].android}
>
Open Mail

View File

@ -1,37 +1,66 @@
import * as yup from "yup"
import {useFormik} from "formik"
import {MdEmail} from "react-icons/md"
import {AxiosError} from "axios"
import React, {ReactElement} from "react"
import {InputAdornment, TextField} from "@mui/material"
import {MultiStepFormElement, SimpleForm} from "~/components"
import {signup} from "~/apis"
import {handleErrors} from "~/utils"
import {ServerSettings} from "~/types"
import {checkIsDomainDisposable, signup} from "~/apis"
import {parseFastapiError} from "~/utils"
import {ServerSettings} from "~/server-types"
import DetectEmailAutofillService from "./DetectEmailAutofillService"
import useSchema, {Form} from "./use-schema"
interface EmailFormProps {
export interface EmailFormProps {
serverSettings: ServerSettings
onSignUp: (email: string) => void
}
interface Form {
email: string
detail?: string
}
const SCHEMA = yup.object().shape({
email: yup.string().email().required(),
})
export default function EmailForm({
onSignUp,
serverSettings,
}: EmailFormProps): ReactElement {
const schema = useSchema(serverSettings)
const formik = useFormik<Form>({
validationSchema: schema,
validationSchema: SCHEMA,
initialValues: {
email: "",
},
onSubmit: (values, {setErrors}) =>
handleErrors(
values.email,
setErrors,
)(signup).then(({normalized_email}) => onSignUp(normalized_email)),
onSubmit: async (values, {setErrors}) => {
// Check is email disposable
try {
const isDisposable = await checkIsDomainDisposable(values.email)
if (isDisposable) {
setErrors({
email: "Disposable email addresses are not allowed",
})
return
}
} catch {
setErrors({
detail: "An error occurred",
})
return
}
try {
await signup(values.email)
onSignUp(values.email)
} catch (error) {
setErrors(parseFastapiError(error as AxiosError))
}
},
})
return (

View File

@ -1,44 +0,0 @@
import * as yup from "yup"
import {checkIsDomainDisposable} from "~/apis"
import {ServerSettings} from "~/types"
export interface Form {
email: string
detail?: string
}
export default function useSchema(
serverSettings: ServerSettings,
): yup.BaseSchema {
return yup.object().shape({
email: yup
.string()
.email()
.required()
.test(
"notDisposable",
"Disposable email addresses are not allowed",
async (value, context) => {
if (serverSettings.disposable_emails_enabled) {
return true
}
try {
await yup.string().email().validate(value, {
strict: true,
})
const isDisposable = await checkIsDomainDisposable(
value!.split("@")[1],
)
return !isDisposable
} catch ({message}) {
// @ts-ignore
context.createError({message})
return false
}
},
),
})
}

View File

@ -8,7 +8,7 @@ import {LoadingButton} from "@mui/lab"
import {Box, Grid, InputAdornment, Typography} from "@mui/material"
import {PasswordField} from "~/components"
import {encryptString, handleErrors} from "~/utils"
import {encryptString} from "~/utils"
import {isDev} from "~/constants/development"
export interface PasswordFormProps {
@ -18,6 +18,7 @@ export interface PasswordFormProps {
interface Form {
password: string
passwordConfirmation: string
detail?: string
}
const schema = yup.object().shape({
@ -47,11 +48,8 @@ export default function PasswordForm({email}: PasswordFormProps): ReactElement {
password: "",
passwordConfirmation: "",
},
onSubmit: (values, {setErrors}) =>
handleErrors(
values,
setErrors,
)(async () => {
onSubmit: async (values, {setErrors}) => {
try {
const keyPair = await awaitGenerateKey
const encryptedPrivateKey = encryptString(
@ -60,7 +58,10 @@ export default function PasswordForm({email}: PasswordFormProps): ReactElement {
)
console.log(encryptedPrivateKey)
}),
} catch (error) {
setErrors({detail: "An error occurred"})
}
},
})
return (

View File

@ -1,18 +1,36 @@
import React, {ReactElement} from "react"
import {MdCancel, MdEdit} from "react-icons/md"
import React, {ReactElement, useState} from "react"
import {Grid, Typography} from "@mui/material"
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Grid,
IconButton,
Typography,
} from "@mui/material"
import {MultiStepFormElement, OpenMailButton} from "~/components"
import ResendMailButton from "~/route-widgets/root/YouGotMail/ResendMailButton"
export interface YouGotMailProps {
email: string
onGoBack: () => void
}
export default function YouGotMail({email}: YouGotMailProps): ReactElement {
export default function YouGotMail({
email,
onGoBack,
}: YouGotMailProps): ReactElement {
const [askToEditEmail, setAskToEditEmail] = useState<boolean>(false)
const domain = email.split("@")[1]
return (
<>
<MultiStepFormElement>
<Grid
container
@ -30,11 +48,30 @@ export default function YouGotMail({email}: YouGotMailProps): ReactElement {
</Grid>
<Grid item>
<Typography variant="subtitle1" component="p">
We sent you an email with a link to confirm your email
address. Please check your inbox and click on the link
to continue.
We sent you an email with a link to confirm your
email address. Please check your inbox and click on
the link to continue.
</Typography>
</Grid>
<Grid item>
<Grid
container
alignItems="center"
direction="row"
spacing={2}
>
<Grid item>
<code>{email}</code>
</Grid>
<Grid item>
<IconButton
onClick={() => setAskToEditEmail(true)}
>
<MdEdit />
</IconButton>
</Grid>
</Grid>
</Grid>
<Grid item>
<OpenMailButton domain={domain} />
</Grid>
@ -43,5 +80,24 @@ export default function YouGotMail({email}: YouGotMailProps): ReactElement {
</Grid>
</Grid>
</MultiStepFormElement>
<Dialog open={askToEditEmail}>
<DialogTitle>Edit email address?</DialogTitle>
<DialogContent>
<DialogContentText>
Would you like to return to the previous step and edit
your email address?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
startIcon={<MdCancel />}
onClick={() => setAskToEditEmail(false)}
>
Cancel
</Button>
<Button onClick={onGoBack}>Yes, edit email</Button>
</DialogActions>
</Dialog>
</>
)
}

View File

@ -3,7 +3,7 @@ import {useLocalStorage} from "react-use"
import {useLoaderData} from "react-router-dom"
import {MultiStepForm} from "~/components"
import {ServerSettings} from "~/types"
import {ServerSettings} from "~/server-types"
import EmailForm from "~/route-widgets/root/EmailForm"
import YouGotMail from "~/route-widgets/root/YouGotMail"
@ -24,7 +24,11 @@ export default function SignupRoute(): ReactElement {
onSignUp={setEmail}
key="email"
/>,
<YouGotMail email={email || ""} key="you_got_mail" />,
<YouGotMail
onGoBack={() => setEmail("")}
email={email || ""}
key="you_got_mail"
/>,
]}
index={index}
/>

View File

@ -6,7 +6,7 @@ import React, {ReactElement} from "react"
import {Grid, Paper, Typography, useTheme} from "@mui/material"
import {ServerSettings} from "~/types"
import {ServerSettings} from "~/server-types"
import {validateEmail} from "~/apis"
const emailSchema = yup.string().email()

View File

@ -1,17 +0,0 @@
import {FormikHelpers} from "formik"
import parseFastAPIError from "./parse-fastapi-error"
import {AxiosError} from "axios"
export default function handleErrors<T = any, Result = any, Values = any>(
values: T,
setErrors: FormikHelpers<Values>["setErrors"],
) {
return async (callback: (values: T) => Promise<Result>) => {
try {
const result = await callback(values)
return result
} catch (error) {
setErrors(parseFastAPIError(error as AxiosError))
}
}
}

View File

@ -2,8 +2,6 @@ export * from "./app-url-links"
export {default as APP_LINK_MAP} from "./app-url-links"
export * from "./encrypt-string"
export {default as encryptString} from "./encrypt-string"
export * from "./handle-errors"
export {default as handleErrors} from "./handle-errors"
export * from "./parse-fastapi-error"
export {default as parseFastapiError} from "./parse-fastapi-error"
export * from "./when-element-has-bounds"