mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-19 15:55:26 +02:00
refactor: Improve i18n for complete account
This commit is contained in:
parent
7229078778
commit
e5d1ee73c6
@ -13,6 +13,17 @@
|
|||||||
},
|
},
|
||||||
"recoveryCode": {
|
"recoveryCode": {
|
||||||
"label": "Recovery Code"
|
"label": "Recovery Code"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"label": "Password",
|
||||||
|
"placeholder": "********"
|
||||||
|
},
|
||||||
|
"passwordConfirmation": {
|
||||||
|
"label": "Confirm Password",
|
||||||
|
"placeholder": "********",
|
||||||
|
"errors": {
|
||||||
|
"mismatch": "Passwords do not match."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"messages": {
|
"messages": {
|
||||||
@ -21,6 +32,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"cancelLabel": "Cancel"
|
"cancelLabel": "Cancel",
|
||||||
|
"yesLabel": "Yes",
|
||||||
|
"noLabel": "No",
|
||||||
|
"continueLabel": "Continue"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
public/locales/en-US/complete-account.json
Normal file
12
public/locales/en-US/complete-account.json
Normal file
@ -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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,12 +28,6 @@
|
|||||||
},
|
},
|
||||||
"CompleteAccountRoute": {
|
"CompleteAccountRoute": {
|
||||||
"forms": {
|
"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": {
|
"password": {
|
||||||
"title": "Set up your password",
|
"title": "Set up your password",
|
||||||
"description": "Please enter a safe password so that we can encrypt your data.",
|
"description": "Please enter a safe password so that we can encrypt your data.",
|
||||||
|
@ -5,12 +5,13 @@ import React, {ReactElement, useEffect, useState} from "react"
|
|||||||
import {Alert, Button, Grid, Snackbar, Typography, TypographyProps} from "@mui/material"
|
import {Alert, Button, Grid, Snackbar, Typography, TypographyProps} from "@mui/material"
|
||||||
import {LoadingButton} from "@mui/lab"
|
import {LoadingButton} from "@mui/lab"
|
||||||
import {OverrideProps} from "@mui/types"
|
import {OverrideProps} from "@mui/types"
|
||||||
|
import {useTranslation} from "react-i18next"
|
||||||
|
|
||||||
export interface SimpleFormProps {
|
export interface SimpleFormProps {
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
continueActionLabel: string
|
|
||||||
|
|
||||||
|
continueActionLabel?: string
|
||||||
children?: ReactElement[]
|
children?: ReactElement[]
|
||||||
cancelActionLabel?: string
|
cancelActionLabel?: string
|
||||||
isSubmitting?: boolean
|
isSubmitting?: boolean
|
||||||
@ -32,6 +33,8 @@ export default function SimpleForm({
|
|||||||
titleComponent = "h1",
|
titleComponent = "h1",
|
||||||
isSubmitting = false,
|
isSubmitting = false,
|
||||||
}: SimpleFormProps): ReactElement {
|
}: SimpleFormProps): ReactElement {
|
||||||
|
const {t} = useTranslation("common")
|
||||||
|
|
||||||
const [showSnackbar, setShowSnackbar] = useState<boolean>(false)
|
const [showSnackbar, setShowSnackbar] = useState<boolean>(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -101,7 +104,7 @@ export default function SimpleForm({
|
|||||||
type="submit"
|
type="submit"
|
||||||
startIcon={<MdChevronRight />}
|
startIcon={<MdChevronRight />}
|
||||||
>
|
>
|
||||||
{continueActionLabel}
|
{continueActionLabel || t("general.continueLabel")}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -17,7 +17,7 @@ export default function GenerateEmailReportsForm({
|
|||||||
onNo,
|
onNo,
|
||||||
onYes,
|
onYes,
|
||||||
}: GenerateEmailReportsFormProps): ReactElement {
|
}: GenerateEmailReportsFormProps): ReactElement {
|
||||||
const {t} = useTranslation()
|
const {t} = useTranslation(["complete-account", "common"])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultiStepFormElement>
|
<MultiStepFormElement>
|
||||||
@ -37,9 +37,7 @@ export default function GenerateEmailReportsForm({
|
|||||||
<Grid container spacing={4} direction="column">
|
<Grid container spacing={4} direction="column">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Typography variant="h6" component="h2" align="center">
|
<Typography variant="h6" component="h2" align="center">
|
||||||
{t(
|
{t("forms.askForGeneration.title")}
|
||||||
"routes.CompleteAccountRoute.forms.generateReports.title",
|
|
||||||
)}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
@ -49,9 +47,7 @@ export default function GenerateEmailReportsForm({
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Typography variant="subtitle1" component="p">
|
<Typography variant="subtitle1" component="p">
|
||||||
{t(
|
{t("forms.askForGeneration.description")}
|
||||||
"routes.CompleteAccountRoute.forms.generateReports.description",
|
|
||||||
)}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -62,9 +58,7 @@ export default function GenerateEmailReportsForm({
|
|||||||
<Grid container spacing={2} direction="row">
|
<Grid container spacing={2} direction="row">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Button startIcon={<TiCancel />} color="secondary" onClick={onNo}>
|
<Button startIcon={<TiCancel />} color="secondary" onClick={onNo}>
|
||||||
{t(
|
{t("general.noLabel", {ns: "common"})}
|
||||||
"routes.CompleteAccountRoute.forms.generateReports.cancelAction",
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
@ -73,9 +67,7 @@ export default function GenerateEmailReportsForm({
|
|||||||
color="primary"
|
color="primary"
|
||||||
onClick={onYes}
|
onClick={onYes}
|
||||||
>
|
>
|
||||||
{t(
|
{t("general.yesLabel", {ns: "common"})}
|
||||||
"routes.CompleteAccountRoute.forms.generateReports.continueAction",
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -11,7 +11,7 @@ import {Box, InputAdornment} from "@mui/material"
|
|||||||
import {useMutation} from "@tanstack/react-query"
|
import {useMutation} from "@tanstack/react-query"
|
||||||
|
|
||||||
import {AuthContext, PasswordField, SimpleForm} from "~/components"
|
import {AuthContext, PasswordField, SimpleForm} from "~/components"
|
||||||
import {setupEncryptionForUser} from "~/utils"
|
import {parseFastAPIError, setupEncryptionForUser} from "~/utils"
|
||||||
import {useExtensionHandler, useNavigateToNext, useSystemPreferredTheme, useUser} from "~/hooks"
|
import {useExtensionHandler, useNavigateToNext, useSystemPreferredTheme, useUser} from "~/hooks"
|
||||||
import {ServerSettings, ServerUser} from "~/server-types"
|
import {ServerSettings, ServerUser} from "~/server-types"
|
||||||
import {UpdateAccountData, updateAccount} from "~/apis"
|
import {UpdateAccountData, updateAccount} from "~/apis"
|
||||||
@ -27,7 +27,7 @@ interface Form {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function PasswordForm({onDone}: PasswordFormProps): ReactElement {
|
export default function PasswordForm({onDone}: PasswordFormProps): ReactElement {
|
||||||
const {t} = useTranslation()
|
const {t} = useTranslation(["complete-account", "common"])
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const theme = useSystemPreferredTheme()
|
const theme = useSystemPreferredTheme()
|
||||||
const serverSettings = useLoaderData() as ServerSettings
|
const serverSettings = useLoaderData() as ServerSettings
|
||||||
@ -36,17 +36,18 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
|
|||||||
const $password = useRef<HTMLInputElement | null>(null)
|
const $password = useRef<HTMLInputElement | null>(null)
|
||||||
const $passwordConfirmation = useRef<HTMLInputElement | null>(null)
|
const $passwordConfirmation = useRef<HTMLInputElement | null>(null)
|
||||||
const schema = yup.object().shape({
|
const schema = yup.object().shape({
|
||||||
password: yup.string().required(),
|
password: yup
|
||||||
|
.string()
|
||||||
|
.required()
|
||||||
|
.label(t("fields.password.label", {ns: "common"})),
|
||||||
passwordConfirmation: yup
|
passwordConfirmation: yup
|
||||||
.string()
|
.string()
|
||||||
.required()
|
.required()
|
||||||
.oneOf(
|
.oneOf(
|
||||||
[yup.ref("password"), null],
|
[yup.ref("password"), null],
|
||||||
t(
|
t("fields.passwordConfirmation.errors.mismatch", {ns: "common"}) as string,
|
||||||
"routes.CompleteAccountRoute.forms.password.form.passwordConfirm.mustMatchHelperText",
|
|
||||||
) as string,
|
|
||||||
)
|
)
|
||||||
.label(t("routes.CompleteAccountRoute.forms.password.form.passwordConfirm.label")),
|
.label(t("fields.passwordConfirmation.label", {ns: "common"})),
|
||||||
})
|
})
|
||||||
|
|
||||||
const {_setEncryptionPassword, login} = useContext(AuthContext)
|
const {_setEncryptionPassword, login} = useContext(AuthContext)
|
||||||
@ -89,7 +90,7 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setErrors({detail: t("general.defaultError")})
|
setErrors(parseFastAPIError(error as AxiosError))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -109,11 +110,8 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
|
|||||||
<Box maxWidth="80vw">
|
<Box maxWidth="80vw">
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={formik.handleSubmit}>
|
||||||
<SimpleForm
|
<SimpleForm
|
||||||
title={t("routes.CompleteAccountRoute.forms.password.title")}
|
title={t("forms.enterPassword.title")}
|
||||||
description={t("routes.CompleteAccountRoute.forms.password.description")}
|
description={t("forms.enterPassword.description")}
|
||||||
continueActionLabel={t(
|
|
||||||
"routes.CompleteAccountRoute.forms.password.continueAction",
|
|
||||||
)}
|
|
||||||
nonFieldError={formik.errors.detail}
|
nonFieldError={formik.errors.detail}
|
||||||
>
|
>
|
||||||
{[
|
{[
|
||||||
@ -123,12 +121,8 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
|
|||||||
autoFocus
|
autoFocus
|
||||||
id="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
label={t(
|
label={t("fields.password.label", {ns: "common"})}
|
||||||
"routes.CompleteAccountRoute.forms.password.form.password.label",
|
placeholder={t("fields.password.placeholder", {ns: "common"})}
|
||||||
)}
|
|
||||||
placeholder={t(
|
|
||||||
"routes.CompleteAccountRoute.forms.password.form.password.placeholder",
|
|
||||||
)}
|
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
value={formik.values.password}
|
value={formik.values.password}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
@ -148,12 +142,10 @@ export default function PasswordForm({onDone}: PasswordFormProps): ReactElement
|
|||||||
fullWidth
|
fullWidth
|
||||||
id="passwordConfirmation"
|
id="passwordConfirmation"
|
||||||
name="passwordConfirmation"
|
name="passwordConfirmation"
|
||||||
label={t(
|
label={t("fields.passwordConfirmation.label", {ns: "common"})}
|
||||||
"routes.CompleteAccountRoute.forms.password.form.passwordConfirm.label",
|
placeholder={t("fields.passwordConfirmation.placeholder", {
|
||||||
)}
|
ns: "common",
|
||||||
placeholder={t(
|
})}
|
||||||
"routes.CompleteAccountRoute.forms.password.form.passwordConfirm.placeholder",
|
|
||||||
)}
|
|
||||||
value={formik.values.passwordConfirmation}
|
value={formik.values.passwordConfirmation}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
disabled={formik.isSubmitting}
|
disabled={formik.isSubmitting}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import {Outlet} from "react-router-dom"
|
import {Outlet} from "react-router-dom"
|
||||||
import React, {ReactElement} from "react"
|
import React, {ReactElement, Suspense} from "react"
|
||||||
|
|
||||||
import {AppLoadingScreen, AuthContextProvider, ExtensionSignalHandler} from "~/components"
|
import {AppLoadingScreen, AuthContextProvider, ExtensionSignalHandler} from "~/components"
|
||||||
|
import LoadingPage from "~/components/widgets/LoadingPage"
|
||||||
|
|
||||||
export default function RootRoute(): ReactElement {
|
export default function RootRoute(): ReactElement {
|
||||||
return (
|
return (
|
||||||
<AuthContextProvider>
|
<Suspense fallback={<LoadingPage />}>
|
||||||
<AppLoadingScreen>
|
<AuthContextProvider>
|
||||||
<Outlet />
|
<AppLoadingScreen>
|
||||||
</AppLoadingScreen>
|
<Outlet />
|
||||||
<ExtensionSignalHandler />
|
</AppLoadingScreen>
|
||||||
</AuthContextProvider>
|
<ExtensionSignalHandler />
|
||||||
|
</AuthContextProvider>
|
||||||
|
</Suspense>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user