diff --git a/public/locales/en-US/common.json b/public/locales/en-US/common.json index a382f1b..cd42469 100644 --- a/public/locales/en-US/common.json +++ b/public/locales/en-US/common.json @@ -13,6 +13,17 @@ }, "recoveryCode": { "label": "Recovery Code" + }, + "password": { + "label": "Password", + "placeholder": "********" + }, + "passwordConfirmation": { + "label": "Confirm Password", + "placeholder": "********", + "errors": { + "mismatch": "Passwords do not match." + } } }, "messages": { @@ -21,6 +32,9 @@ } }, "general": { - "cancelLabel": "Cancel" + "cancelLabel": "Cancel", + "yesLabel": "Yes", + "noLabel": "No", + "continueLabel": "Continue" } } diff --git a/public/locales/en-US/complete-account.json b/public/locales/en-US/complete-account.json new file mode 100644 index 0000000..eb7f1ca --- /dev/null +++ b/public/locales/en-US/complete-account.json @@ -0,0 +1,12 @@ +{ + "forms": { + "askForGeneration": { + "title": "Generate Email Reports?", + "description": "Would you like to create fully encrypted email reports for your mails? Only you will be able to access them. Not even we can decrypt them." + }, + "enterPassword": { + "title": "Set up your password", + "description": "Please enter a safe password so that we can encrypt your data." + } + } +} diff --git a/public/locales/en-US/translation.json b/public/locales/en-US/translation.json index 1f9d057..48e310c 100644 --- a/public/locales/en-US/translation.json +++ b/public/locales/en-US/translation.json @@ -28,12 +28,6 @@ }, "CompleteAccountRoute": { "forms": { - "generateReports": { - "title": "Generate Email Reports?", - "description": "Would you like to create fully encrypted email reports for your mails? Only you will be able to access them. Not even we can decrypt them.", - "continueAction": "Yes", - "cancelAction": "No" - }, "password": { "title": "Set up your password", "description": "Please enter a safe password so that we can encrypt your data.", diff --git a/src/components/widgets/SimpleForm.tsx b/src/components/widgets/SimpleForm.tsx index 36fc510..bd295c6 100644 --- a/src/components/widgets/SimpleForm.tsx +++ b/src/components/widgets/SimpleForm.tsx @@ -5,12 +5,13 @@ import React, {ReactElement, useEffect, useState} from "react" import {Alert, Button, Grid, Snackbar, Typography, TypographyProps} from "@mui/material" import {LoadingButton} from "@mui/lab" import {OverrideProps} from "@mui/types" +import {useTranslation} from "react-i18next" export interface SimpleFormProps { title: string description: string - continueActionLabel: string + continueActionLabel?: string children?: ReactElement[] cancelActionLabel?: string isSubmitting?: boolean @@ -32,6 +33,8 @@ export default function SimpleForm({ titleComponent = "h1", isSubmitting = false, }: SimpleFormProps): ReactElement { + const {t} = useTranslation("common") + const [showSnackbar, setShowSnackbar] = useState(false) useEffect(() => { @@ -101,7 +104,7 @@ export default function SimpleForm({ type="submit" startIcon={} > - {continueActionLabel} + {continueActionLabel || t("general.continueLabel")} diff --git a/src/route-widgets/CompleteAccountRoute/GenerateEmailReportsForm.tsx b/src/route-widgets/CompleteAccountRoute/GenerateEmailReportsForm.tsx index 291ba68..814bb0e 100644 --- a/src/route-widgets/CompleteAccountRoute/GenerateEmailReportsForm.tsx +++ b/src/route-widgets/CompleteAccountRoute/GenerateEmailReportsForm.tsx @@ -17,7 +17,7 @@ export default function GenerateEmailReportsForm({ onNo, onYes, }: GenerateEmailReportsFormProps): ReactElement { - const {t} = useTranslation() + const {t} = useTranslation(["complete-account", "common"]) return ( @@ -37,9 +37,7 @@ export default function GenerateEmailReportsForm({ - {t( - "routes.CompleteAccountRoute.forms.generateReports.title", - )} + {t("forms.askForGeneration.title")} @@ -49,9 +47,7 @@ export default function GenerateEmailReportsForm({ - {t( - "routes.CompleteAccountRoute.forms.generateReports.description", - )} + {t("forms.askForGeneration.description")} @@ -62,9 +58,7 @@ export default function GenerateEmailReportsForm({ @@ -73,9 +67,7 @@ export default function GenerateEmailReportsForm({ color="primary" onClick={onYes} > - {t( - "routes.CompleteAccountRoute.forms.generateReports.continueAction", - )} + {t("general.yesLabel", {ns: "common"})} diff --git a/src/route-widgets/CompleteAccountRoute/PasswordForm.tsx b/src/route-widgets/CompleteAccountRoute/PasswordForm.tsx index 6c90a8a..6c0a929 100644 --- a/src/route-widgets/CompleteAccountRoute/PasswordForm.tsx +++ b/src/route-widgets/CompleteAccountRoute/PasswordForm.tsx @@ -11,7 +11,7 @@ import {Box, InputAdornment} from "@mui/material" import {useMutation} from "@tanstack/react-query" import {AuthContext, PasswordField, SimpleForm} from "~/components" -import {setupEncryptionForUser} from "~/utils" +import {parseFastAPIError, setupEncryptionForUser} from "~/utils" import {useExtensionHandler, useNavigateToNext, useSystemPreferredTheme, useUser} from "~/hooks" import {ServerSettings, ServerUser} from "~/server-types" import {UpdateAccountData, updateAccount} from "~/apis" @@ -27,7 +27,7 @@ interface Form { } export default function PasswordForm({onDone}: PasswordFormProps): ReactElement { - const {t} = useTranslation() + const {t} = useTranslation(["complete-account", "common"]) const user = useUser() const theme = useSystemPreferredTheme() const serverSettings = useLoaderData() as ServerSettings @@ -36,17 +36,18 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement const $password = useRef(null) const $passwordConfirmation = useRef(null) const schema = yup.object().shape({ - password: yup.string().required(), + password: yup + .string() + .required() + .label(t("fields.password.label", {ns: "common"})), passwordConfirmation: yup .string() .required() .oneOf( [yup.ref("password"), null], - t( - "routes.CompleteAccountRoute.forms.password.form.passwordConfirm.mustMatchHelperText", - ) as string, + t("fields.passwordConfirmation.errors.mismatch", {ns: "common"}) as string, ) - .label(t("routes.CompleteAccountRoute.forms.password.form.passwordConfirm.label")), + .label(t("fields.passwordConfirmation.label", {ns: "common"})), }) const {_setEncryptionPassword, login} = useContext(AuthContext) @@ -89,7 +90,7 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement }, ) } catch (error) { - setErrors({detail: t("general.defaultError")}) + setErrors(parseFastAPIError(error as AxiosError)) } }, }) @@ -109,11 +110,8 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
{[ @@ -123,12 +121,8 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement autoFocus id="password" name="password" - label={t( - "routes.CompleteAccountRoute.forms.password.form.password.label", - )} - placeholder={t( - "routes.CompleteAccountRoute.forms.password.form.password.placeholder", - )} + label={t("fields.password.label", {ns: "common"})} + placeholder={t("fields.password.placeholder", {ns: "common"})} autoComplete="new-password" value={formik.values.password} onChange={formik.handleChange} @@ -148,12 +142,10 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement fullWidth id="passwordConfirmation" name="passwordConfirmation" - label={t( - "routes.CompleteAccountRoute.forms.password.form.passwordConfirm.label", - )} - placeholder={t( - "routes.CompleteAccountRoute.forms.password.form.passwordConfirm.placeholder", - )} + label={t("fields.passwordConfirmation.label", {ns: "common"})} + placeholder={t("fields.passwordConfirmation.placeholder", { + ns: "common", + })} value={formik.values.passwordConfirmation} onChange={formik.handleChange} disabled={formik.isSubmitting} diff --git a/src/routes/Root.tsx b/src/routes/Root.tsx index f560233..0c4b05c 100644 --- a/src/routes/Root.tsx +++ b/src/routes/Root.tsx @@ -1,15 +1,18 @@ import {Outlet} from "react-router-dom" -import React, {ReactElement} from "react" +import React, {ReactElement, Suspense} from "react" import {AppLoadingScreen, AuthContextProvider, ExtensionSignalHandler} from "~/components" +import LoadingPage from "~/components/widgets/LoadingPage" export default function RootRoute(): ReactElement { return ( - - - - - - + }> + + + + + + + ) }