```refactor Add reset password form component with Zod validation, email input handling, and internationalization support for custom auth flow
```
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
"node": "==22"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "next dev -H 0.0.0.0",
|
||||
"build": "next build",
|
||||
"build:w": "pnpx nodemon --ext ts,tsx,json,mjs,js,jsx --delay 15 --exec \"pnpm run build\"",
|
||||
"start": "next start",
|
||||
@@ -117,4 +117,4 @@
|
||||
"protobufjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,130 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import Button from '@mui/material/Button';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import FormHelperText from '@mui/material/FormHelperText';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z as zod } from 'zod';
|
||||
|
||||
import { paths } from '@/paths';
|
||||
import { authClient } from '@/lib/auth/custom/client';
|
||||
|
||||
export function ResetPasswordForm(): React.JSX.Element {
|
||||
const { t } = useTranslation(['sign_in']);
|
||||
const router = useRouter();
|
||||
const [isPending, setIsPending] = React.useState<boolean>(false);
|
||||
|
||||
const schema = zod.object({
|
||||
email: zod
|
||||
.string()
|
||||
.min(1, { message: t('email-is-required') })
|
||||
.email(),
|
||||
});
|
||||
|
||||
type Values = zod.infer<typeof schema>;
|
||||
|
||||
const defaultValues = { email: '' } satisfies Values;
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setError,
|
||||
formState: { errors },
|
||||
} = useForm<Values>({ defaultValues, resolver: zodResolver(schema) });
|
||||
|
||||
const onSubmit = React.useCallback(
|
||||
async (values: Values): Promise<void> => {
|
||||
setIsPending(true);
|
||||
|
||||
const { error } = await authClient.resetPassword(values);
|
||||
|
||||
if (error) {
|
||||
setError('root', { type: 'server', message: error });
|
||||
setIsPending(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsPending(false);
|
||||
|
||||
// Redirect to confirm password reset
|
||||
},
|
||||
[setError]
|
||||
);
|
||||
|
||||
function handleBackToLoginClick(): void {
|
||||
router.replace(paths.auth.custom.signIn);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
{/*
|
||||
<div>
|
||||
<Box
|
||||
component={RouterLink}
|
||||
href={paths.home}
|
||||
sx={{ display: 'inline-block', fontSize: 0 }}
|
||||
>
|
||||
<DynamicLogo
|
||||
colorDark="light"
|
||||
colorLight="dark"
|
||||
height={32}
|
||||
width={122}
|
||||
/>
|
||||
</Box>
|
||||
</div>
|
||||
*/}
|
||||
<Typography variant="h5">{t('reset-password')}</Typography>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack spacing={2}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormControl error={Boolean(errors.email)}>
|
||||
<InputLabel>{t('email-address')}</InputLabel>
|
||||
<OutlinedInput
|
||||
{...field}
|
||||
type="email"
|
||||
/>
|
||||
{errors.email ? <FormHelperText>{errors.email.message}</FormHelperText> : null}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
{errors.root ? <Alert color="error">{errors.root.message}</Alert> : null}
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={4}
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Button
|
||||
disabled={isPending}
|
||||
type="reset"
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={handleBackToLoginClick}
|
||||
>
|
||||
{t('back-to-login')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
disabled={isPending}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
>
|
||||
{t('send-recovery-link')}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</form>
|
||||
</Stack>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user