@@ -7,56 +7,125 @@ import { Button, TextField } from "@/Components/v2/inputs";
77import Stack from "@mui/material/Stack" ;
88import { useTheme } from "@mui/material/styles" ;
99import { useTranslation } from "react-i18next" ;
10+ import { useForm , Controller } from "react-hook-form" ;
11+ import { zodResolver } from "@hookform/resolvers/zod/dist/zod.js" ;
12+ import { useSetNewPasswordForm } from "@/Hooks/useSetNewPasswordForm" ;
13+ import type { SetNewPasswordFormData } from "@/Validation/setNewPassword" ;
14+ import { specialCharPattern } from "@/Validation/patterns" ;
15+ import { useParams , useNavigate } from "react-router-dom" ;
16+ import { usePost } from "@/Hooks/UseApi" ;
17+ import { useDispatch } from "react-redux" ;
18+ import { setAuthState } from "@/Features/Auth/authSlice" ;
1019
1120const SetNewPasswordPage = ( ) => {
1221 const theme = useTheme ( ) ;
1322 const { t } = useTranslation ( ) ;
23+ const { token } = useParams < { token : string } > ( ) ;
24+ const navigate = useNavigate ( ) ;
25+ const dispatch = useDispatch ( ) ;
26+ const { post, loading } = usePost ( ) ;
27+
28+ const { schema, defaults } = useSetNewPasswordForm ( ) ;
29+
30+ const { control, handleSubmit, watch } = useForm < SetNewPasswordFormData > ( {
31+ resolver : zodResolver ( schema ) ,
32+ defaultValues : defaults ,
33+ } ) ;
34+
35+ const password = watch ( "password" ) ;
36+ const confirm = watch ( "confirm" ) ;
37+
38+ const getVariant = ( condition : boolean ) : "success" | "info" => {
39+ return condition ? "success" : "info" ;
40+ } ;
41+
42+ const hasLength = password . length >= 8 ;
43+ const hasSpecial = specialCharPattern . test ( password ) ;
44+ const hasNumber = / \d / . test ( password ) ;
45+ const hasUppercase = / [ A - Z ] / . test ( password ) ;
46+ const hasLowercase = / [ a - z ] / . test ( password ) ;
47+ const passwordsMatch = password . length > 0 && password === confirm ;
48+
49+ const onSubmit = async ( data : SetNewPasswordFormData ) => {
50+ if ( loading ) return ;
51+
52+ const result = await post ( "/auth/recovery/reset" , {
53+ password : data . password ,
54+ recoveryToken : token ,
55+ } ) ;
56+
57+ if ( result ?. success ) {
58+ dispatch ( setAuthState ( result ) ) ;
59+ navigate ( "/uptime" ) ;
60+ }
61+ } ;
1462
1563 return (
1664 < BaseAuthPage
65+ component = "form"
66+ onSubmit = { handleSubmit ( onSubmit ) }
1767 title = { t ( "pages.auth.setNewPassword.title" ) }
1868 subtitle = { t ( "pages.auth.setNewPassword.subtitle" ) }
1969 >
20- < TextField
21- type = "password"
22- fieldLabel = { t ( "pages.auth.common.form.option.password.label" ) }
23- placeholder = { t ( "pages.auth.common.form.option.password.placeholder" ) }
70+ < Controller
71+ name = "password"
72+ control = { control }
73+ render = { ( { field, fieldState } ) => (
74+ < TextField
75+ { ...field }
76+ type = "password"
77+ fieldLabel = { t ( "pages.auth.common.form.option.password.label" ) }
78+ placeholder = { t ( "pages.auth.common.form.option.password.placeholder" ) }
79+ error = { ! ! fieldState . error }
80+ helperText = { fieldState . error ?. message ?? "" }
81+ />
82+ ) }
2483 />
25- < TextField
26- type = "password"
27- fieldLabel = { t ( "pages.auth.common.form.option.confirmPassword.label" ) }
28- placeholder = { t ( "pages.auth.common.form.option.password.placeholder" ) }
84+ < Controller
85+ name = "confirm"
86+ control = { control }
87+ render = { ( { field, fieldState } ) => (
88+ < TextField
89+ { ...field }
90+ type = "password"
91+ fieldLabel = { t ( "pages.auth.common.form.option.confirmPassword.label" ) }
92+ placeholder = { t ( "pages.auth.common.form.option.password.placeholder" ) }
93+ error = { ! ! fieldState . error }
94+ helperText = { fieldState . error ?. message ?? "" }
95+ />
96+ ) }
2997 />
3098 < Stack gap = { theme . spacing ( 4 ) } >
3199 < BulletPointCheck
32100 text = { t ( "auth.common.passwordRules.length" ) }
33- variant = "info"
101+ variant = { getVariant ( hasLength ) }
34102 />
35103 < BulletPointCheck
36104 text = { t ( "auth.common.passwordRules.special" ) }
37- variant = "info"
105+ variant = { getVariant ( hasSpecial ) }
38106 />
39107 < BulletPointCheck
40108 text = { t ( "auth.common.passwordRules.number" ) }
41- variant = "info"
109+ variant = { getVariant ( hasNumber ) }
42110 />
43111 < BulletPointCheck
44112 text = { t ( "auth.common.passwordRules.uppercase" ) }
45- variant = "info"
113+ variant = { getVariant ( hasUppercase ) }
46114 />
47115 < BulletPointCheck
48116 text = { t ( "auth.common.passwordRules.lowercase" ) }
49- variant = "info"
117+ variant = { getVariant ( hasLowercase ) }
50118 />
51119 < BulletPointCheck
52120 text = { t ( "auth.common.passwordRules.match" ) }
53- variant = "info"
121+ variant = { getVariant ( passwordsMatch ) }
54122 />
55123 </ Stack >
56124 < Button
57125 variant = "contained"
58126 type = "submit"
59127 fullWidth
128+ loading = { loading }
60129 >
61130 { t ( "auth.forgotPassword.buttons.resetPassword" ) }
62131 </ Button >
0 commit comments