189 lines
5.3 KiB
TypeScript
189 lines
5.3 KiB
TypeScript
import { zodResolver } from '@hookform/resolvers/zod';
|
|
import Box from '@mui/material/Box';
|
|
import Button from '@mui/material/Button';
|
|
import IconButton from '@mui/material/IconButton';
|
|
import InputAdornment from '@mui/material/InputAdornment';
|
|
import { useBoolean, useCountdownSeconds } from 'minimal-shared/hooks';
|
|
import { useCallback } from 'react';
|
|
import { useForm } from 'react-hook-form';
|
|
import { SentIcon } from 'src/assets/icons';
|
|
import { Field, Form } from 'src/components/hook-form';
|
|
import { Iconify } from 'src/components/iconify';
|
|
import { useRouter, useSearchParams } from 'src/routes/hooks';
|
|
import { paths } from 'src/routes/paths';
|
|
import { z as zod } from 'zod';
|
|
import { FormHead } from '../../components/form-head';
|
|
import { FormResendCode } from '../../components/form-resend-code';
|
|
import { FormReturnLink } from '../../components/form-return-link';
|
|
import { resetPassword, updatePassword } from '../../context/amplify';
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
export type UpdatePasswordSchemaType = zod.infer<typeof UpdatePasswordSchema>;
|
|
|
|
export const UpdatePasswordSchema = zod
|
|
.object({
|
|
code: zod
|
|
.string()
|
|
.min(1, { message: 'Code is required!' })
|
|
.min(6, { message: 'Code must be at least 6 characters!' }),
|
|
email: zod
|
|
.string()
|
|
.min(1, { message: 'Email is required!' })
|
|
.email({ message: 'Email must be a valid email address!' }),
|
|
password: zod
|
|
.string()
|
|
.min(1, { message: 'Password is required!' })
|
|
.min(6, { message: 'Password must be at least 6 characters!' }),
|
|
confirmPassword: zod.string().min(1, { message: 'Confirm password is required!' }),
|
|
})
|
|
.refine((data) => data.password === data.confirmPassword, {
|
|
message: 'Passwords do not match!',
|
|
path: ['confirmPassword'],
|
|
});
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
export function AmplifyUpdatePasswordView() {
|
|
const router = useRouter();
|
|
|
|
const searchParams = useSearchParams();
|
|
|
|
const email = searchParams.get('email');
|
|
|
|
const showPassword = useBoolean();
|
|
|
|
const countdown = useCountdownSeconds(5);
|
|
|
|
const defaultValues: UpdatePasswordSchemaType = {
|
|
code: '',
|
|
email: email || '',
|
|
password: '',
|
|
confirmPassword: '',
|
|
};
|
|
|
|
const methods = useForm<UpdatePasswordSchemaType>({
|
|
resolver: zodResolver(UpdatePasswordSchema),
|
|
defaultValues,
|
|
});
|
|
|
|
const {
|
|
watch,
|
|
handleSubmit,
|
|
formState: { isSubmitting },
|
|
} = methods;
|
|
|
|
const values = watch();
|
|
|
|
const onSubmit = handleSubmit(async (data) => {
|
|
try {
|
|
await updatePassword({
|
|
username: data.email,
|
|
confirmationCode: data.code,
|
|
newPassword: data.password,
|
|
});
|
|
|
|
router.push(paths.auth.amplify.signIn);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
});
|
|
|
|
const handleResendCode = useCallback(async () => {
|
|
if (!countdown.isCounting) {
|
|
try {
|
|
countdown.reset();
|
|
countdown.start();
|
|
|
|
await resetPassword({ username: values.email });
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
}, [countdown, values.email]);
|
|
|
|
const renderForm = () => (
|
|
<Box sx={{ gap: 3, display: 'flex', flexDirection: 'column' }}>
|
|
<Field.Text
|
|
name="email"
|
|
label="Email address"
|
|
placeholder="example@gmail.com"
|
|
slotProps={{ inputLabel: { shrink: true } }}
|
|
disabled
|
|
/>
|
|
|
|
<Field.Code name="code" />
|
|
|
|
<Field.Text
|
|
name="password"
|
|
label="Password"
|
|
placeholder="6+ characters"
|
|
type={showPassword.value ? 'text' : 'password'}
|
|
slotProps={{
|
|
inputLabel: { shrink: true },
|
|
input: {
|
|
endAdornment: (
|
|
<InputAdornment position="end">
|
|
<IconButton onClick={showPassword.onToggle} edge="end">
|
|
<Iconify icon={showPassword.value ? 'solar:eye-bold' : 'solar:eye-closed-bold'} />
|
|
</IconButton>
|
|
</InputAdornment>
|
|
),
|
|
},
|
|
}}
|
|
/>
|
|
|
|
<Field.Text
|
|
name="confirmPassword"
|
|
label="Confirm new password"
|
|
type={showPassword.value ? 'text' : 'password'}
|
|
slotProps={{
|
|
inputLabel: { shrink: true },
|
|
input: {
|
|
endAdornment: (
|
|
<InputAdornment position="end">
|
|
<IconButton onClick={showPassword.onToggle} edge="end">
|
|
<Iconify icon={showPassword.value ? 'solar:eye-bold' : 'solar:eye-closed-bold'} />
|
|
</IconButton>
|
|
</InputAdornment>
|
|
),
|
|
},
|
|
}}
|
|
/>
|
|
|
|
<Button
|
|
fullWidth
|
|
size="large"
|
|
type="submit"
|
|
variant="contained"
|
|
loading={isSubmitting}
|
|
loadingIndicator="Update password..."
|
|
>
|
|
Update password
|
|
</Button>
|
|
</Box>
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<FormHead
|
|
icon={<SentIcon />}
|
|
title="Request sent successfully!"
|
|
description={`We've sent a 6-digit confirmation email to your email. \nPlease enter the code in below box to verify your email.`}
|
|
/>
|
|
|
|
<Form methods={methods} onSubmit={onSubmit}>
|
|
{renderForm()}
|
|
</Form>
|
|
|
|
<FormResendCode
|
|
onResendCode={handleResendCode}
|
|
value={countdown.value}
|
|
disabled={countdown.isCounting}
|
|
/>
|
|
|
|
<FormReturnLink href={paths.auth.amplify.signIn} />
|
|
</>
|
|
);
|
|
}
|