import * as yup from "yup" import {useFormik} from "formik" import {MdCheckCircle, MdLock} from "react-icons/md" import {readKey} from "openpgp" import {AxiosError} from "axios" import {useTranslation} from "react-i18next" import {useLoaderData} from "react-router-dom" import React, {ReactElement, useCallback, useContext, useRef} from "react" import {Box, InputAdornment} from "@mui/material" import {useMutation} from "@tanstack/react-query" import {AuthContext, PasswordField, SimpleForm} from "~/components" import {parseFastAPIError, setupEncryptionForUser} from "~/utils" import {useExtensionHandler, useNavigateToNext, useSystemPreferredTheme, useUser} from "~/hooks" import {ServerSettings, ServerUser} from "~/server-types" import {UpdateAccountData, updateAccount} from "~/apis" export interface PasswordFormProps { onDone: () => void } interface Form { password: string passwordConfirmation: string detail?: string } export default function PasswordForm({onDone}: PasswordFormProps): ReactElement { const {t} = useTranslation(["complete-account", "common"]) const user = useUser() const theme = useSystemPreferredTheme() const serverSettings = useLoaderData() as ServerSettings const navigateToNext = useNavigateToNext() const $password = useRef(null) const $passwordConfirmation = useRef(null) const schema = yup.object().shape({ password: yup .string() .required() .label(t("fields.password.label", {ns: "common"})), passwordConfirmation: yup .string() .required() .oneOf( [yup.ref("password"), null], t("fields.passwordConfirmation.errors.mismatch", {ns: "common"}) as string, ) .label(t("fields.passwordConfirmation.label", {ns: "common"})), }) const {_setEncryptionPassword, login} = useContext(AuthContext) const {mutateAsync} = useMutation(updateAccount) const formik = useFormik
({ validationSchema: schema, initialValues: { password: "", passwordConfirmation: "", }, onSubmit: async ({password}, {setErrors}) => { try { const {encryptionPassword, encryptedPassword, encryptedNotes, publicKey} = await setupEncryptionForUser({ password, user, serverSettings, theme, }) await mutateAsync( { encryptedPassword, publicKey: ( await readKey({ armoredKey: publicKey, }) ) .toPublic() .armor(), encryptedNotes, }, { onSuccess: newUser => { login(newUser) _setEncryptionPassword(encryptionPassword) navigateToNext() }, }, ) } catch (error) { setErrors(parseFastAPIError(error as AxiosError)) } }, }) const focusPassword = useCallback(() => { if ($password.current?.value !== "") { $passwordConfirmation.current?.focus() } else { $password.current?.focus() } }, []) useExtensionHandler({ onEnterPassword: focusPassword, }) return ( {[ ), }} />, ), }} />, ]}
) }