@@ -6,12 +6,14 @@ import {
6
6
IonText ,
7
7
IonRow ,
8
8
IonCol ,
9
+ IonIcon ,
9
10
} from '@ionic/react' ;
10
11
import { useRef , useState } from 'react' ;
11
12
import classNames from 'classnames' ;
12
- import { Form , Formik } from 'formik' ;
13
+ import { Form , Formik , useFormikContext } from 'formik' ;
13
14
import { object , string , ref } from 'yup' ;
14
15
import { useTranslation } from 'react-i18next' ;
16
+ import { checkmarkCircle , closeCircle } from 'ionicons/icons' ;
15
17
16
18
import './SignUpForm.scss' ;
17
19
import { BaseComponentProps } from 'common/components/types' ;
@@ -40,6 +42,44 @@ interface SignUpFormValues {
40
42
confirmPassword : string ;
41
43
}
42
44
45
+ /**
46
+ * Password guidelines component
47
+ */
48
+ const PasswordGuidelines = ( ) => {
49
+ const { values } = useFormikContext < SignUpFormValues > ( ) ;
50
+ const password = values . password || '' ;
51
+ const { t } = useTranslation ( ) ;
52
+
53
+ const hasMinLength = password . length >= 8 ;
54
+ const hasUppercase = / [ A - Z ] / . test ( password ) ;
55
+ const hasNumber = / [ 0 - 9 ] / . test ( password ) ;
56
+ const hasSpecialChar = / [ ^ A - Z a - z 0 - 9 ] / . test ( password ) ;
57
+
58
+ const renderGuideline = ( isValid : boolean , text : string ) => {
59
+ return (
60
+ < div className = { `ls-signup-form__password-guidelines-item ls-signup-form__password-guidelines-item-${ isValid ? 'valid' : 'invalid' } ` } >
61
+ < IonIcon
62
+ icon = { isValid ? checkmarkCircle : closeCircle }
63
+ className = "ls-signup-form__password-guidelines-item-icon"
64
+ />
65
+ < span > { text } </ span >
66
+ </ div >
67
+ ) ;
68
+ } ;
69
+
70
+ return (
71
+ < div className = "ls-signup-form__password-guidelines" >
72
+ < div className = "ls-signup-form__password-guidelines-header" >
73
+ { t ( 'password-requirements' , { ns : 'auth' } ) }
74
+ </ div >
75
+ { renderGuideline ( hasMinLength , t ( 'validation.min-length' , { length : 8 , ns : 'auth' } ) ) }
76
+ { renderGuideline ( hasUppercase , t ( 'validation.uppercase' , { ns : 'auth' } ) ) }
77
+ { renderGuideline ( hasNumber , t ( 'validation.number' , { ns : 'auth' } ) ) }
78
+ { renderGuideline ( hasSpecialChar , t ( 'validation.special-char' , { ns : 'auth' } ) ) }
79
+ </ div >
80
+ ) ;
81
+ } ;
82
+
43
83
/**
44
84
* The `SignUpForm` component renders a form for user registration.
45
85
* @param {SignUpFormProps } props - Component properties.
@@ -71,6 +111,9 @@ const SignUpForm = ({ className, testid = 'form-signup' }: SignUpFormProps): JSX
71
111
. required ( t ( 'validation.required' , { ns : 'auth' } ) ) ,
72
112
password : string ( )
73
113
. min ( 8 , t ( 'validation.min-length' , { length : 8 , ns : 'auth' } ) )
114
+ . matches ( / [ A - Z ] / , t ( 'validation.uppercase' , { ns : 'auth' } ) )
115
+ . matches ( / [ 0 - 9 ] / , t ( 'validation.number' , { ns : 'auth' } ) )
116
+ . matches ( / [ ^ A - Z a - z 0 - 9 ] / , t ( 'validation.special-char' , { ns : 'auth' } ) )
74
117
. required ( t ( 'validation.required' , { ns : 'auth' } ) ) ,
75
118
confirmPassword : string ( )
76
119
. oneOf ( [ ref ( 'password' ) ] , t ( 'validation.passwords-match' , { ns : 'auth' } ) )
@@ -180,6 +223,8 @@ const SignUpForm = ({ className, testid = 'form-signup' }: SignUpFormProps): JSX
180
223
< IonInputPasswordToggle slot = "end" > </ IonInputPasswordToggle >
181
224
</ Input >
182
225
226
+ < PasswordGuidelines />
227
+
183
228
< Input
184
229
type = "password"
185
230
name = "confirmPassword"
0 commit comments