@@ -9,49 +9,62 @@ import Button from '../../../common/Button';
9
9
import apiClient from '../../../utils/apiClient' ;
10
10
import useSyncFormTranslations from '../../../common/useSyncFormTranslations' ;
11
11
12
- function asyncValidate ( fieldToValidate , value ) {
12
+ const debounce = ( func , delay ) => {
13
+ let timer ;
14
+ return ( ...args ) =>
15
+ new Promise ( ( resolve ) => {
16
+ clearTimeout ( timer ) ;
17
+ timer = setTimeout ( ( ) => resolve ( func ( ...args ) ) , delay ) ;
18
+ } ) ;
19
+ } ;
20
+
21
+ // API Validation Function
22
+ async function asyncValidate ( fieldToValidate , value ) {
13
23
if ( ! value || value . trim ( ) . length === 0 ) {
14
24
return '' ;
15
25
}
16
- const queryParams = { } ;
17
- queryParams [ fieldToValidate ] = value ;
18
- queryParams . check_type = fieldToValidate ;
19
- return apiClient
20
- . get ( '/signup/duplicate_check' , { params : queryParams } )
21
- . then ( ( response ) => {
22
- if ( response . data . exists ) {
23
- return response . data . message ;
24
- }
25
- return '' ;
26
+ const queryParams = {
27
+ [ fieldToValidate ] : value ,
28
+ check_type : fieldToValidate
29
+ } ;
30
+
31
+ try {
32
+ const response = await apiClient . get ( '/signup/duplicate_check' , {
33
+ params : queryParams
26
34
} ) ;
35
+ return response . data . exists ? response . data . message : '' ;
36
+ } catch ( error ) {
37
+ return 'Error validating field.' ;
38
+ }
27
39
}
28
40
41
+ const debouncedAsyncValidate = debounce ( asyncValidate , 300 ) ;
42
+
29
43
function validateUsername ( username ) {
30
- return asyncValidate ( 'username' , username ) ;
44
+ return debouncedAsyncValidate ( 'username' , username ) ;
31
45
}
32
46
33
47
function validateEmail ( email ) {
34
- return asyncValidate ( 'email' , email ) ;
48
+ return debouncedAsyncValidate ( 'email' , email ) ;
35
49
}
36
50
37
51
function SignupForm ( ) {
38
52
const { t, i18n } = useTranslation ( ) ;
39
-
40
53
const dispatch = useDispatch ( ) ;
41
- function onSubmit ( formProps ) {
42
- return dispatch ( validateAndSignUpUser ( formProps ) ) ;
43
- }
54
+ const formRef = useRef ( null ) ;
44
55
const [ showPassword , setShowPassword ] = useState ( false ) ;
45
56
const [ showConfirmPassword , setShowConfirmPassword ] = useState ( false ) ;
46
- const formRef = useRef ( null ) ;
47
- const handleVisibility = ( ) => {
48
- setShowPassword ( ! showPassword ) ;
49
- } ;
50
- const handleConfirmVisibility = ( ) => {
51
- setShowConfirmPassword ( ! showConfirmPassword ) ;
52
- } ;
57
+
53
58
useSyncFormTranslations ( formRef , i18n . language ) ;
54
59
60
+ const handleVisibility = ( ) => setShowPassword ( ! showPassword ) ;
61
+ const handleConfirmVisibility = ( ) =>
62
+ setShowConfirmPassword ( ! showConfirmPassword ) ;
63
+
64
+ function onSubmit ( formProps ) {
65
+ return dispatch ( validateAndSignUpUser ( formProps ) ) ;
66
+ }
67
+
55
68
return (
56
69
< Form
57
70
fields = { [ 'username' , 'email' , 'password' , 'confirmPassword' ] }
@@ -62,12 +75,13 @@ function SignupForm() {
62
75
formRef . current = form ;
63
76
return (
64
77
< form className = "form" onSubmit = { handleSubmit } >
78
+ { /* Username Field */ }
65
79
< Field
66
80
name = "username"
67
81
validate = { validateUsername }
68
82
validateFields = { [ ] }
69
83
>
70
- { ( field ) => (
84
+ { ( { input , meta } ) => (
71
85
< div className = "form__field" >
72
86
< label htmlFor = "username" className = "form__label" >
73
87
{ t ( 'SignupForm.Title' ) }
@@ -79,18 +93,20 @@ function SignupForm() {
79
93
id = "username"
80
94
autoComplete = "username"
81
95
autoCapitalize = "none"
82
- { ...field . input }
96
+ { ...input }
83
97
/>
84
- { field . meta . touched && field . meta . error && (
98
+ { meta . touched && meta . error && (
85
99
< span className = "form-error" aria-live = "polite" >
86
- { field . meta . error }
100
+ { meta . error }
87
101
</ span >
88
102
) }
89
103
</ div >
90
104
) }
91
105
</ Field >
106
+
107
+ { /* Email Field */ }
92
108
< Field name = "email" validate = { validateEmail } validateFields = { [ ] } >
93
- { ( field ) => (
109
+ { ( { input , meta } ) => (
94
110
< div className = "form__field" >
95
111
< label htmlFor = "email" className = "form__label" >
96
112
{ t ( 'SignupForm.Email' ) }
@@ -101,18 +117,20 @@ function SignupForm() {
101
117
type = "email"
102
118
id = "email"
103
119
autoComplete = "email"
104
- { ...field . input }
120
+ { ...input }
105
121
/>
106
- { field . meta . touched && field . meta . error && (
122
+ { meta . touched && meta . error && (
107
123
< span className = "form-error" aria-live = "polite" >
108
- { field . meta . error }
124
+ { meta . error }
109
125
</ span >
110
126
) }
111
127
</ div >
112
128
) }
113
129
</ Field >
130
+
131
+ { /* Password Field */ }
114
132
< Field name = "password" >
115
- { ( field ) => (
133
+ { ( { input , meta } ) => (
116
134
< div className = "form__field" >
117
135
< label htmlFor = "password" className = "form__label" >
118
136
{ t ( 'SignupForm.Password' ) }
@@ -124,7 +142,7 @@ function SignupForm() {
124
142
type = { showPassword ? 'text' : 'password' }
125
143
id = "password"
126
144
autoComplete = "new-password"
127
- { ...field . input }
145
+ { ...input }
128
146
/>
129
147
< button
130
148
className = "form__eye__icon"
@@ -139,28 +157,30 @@ function SignupForm() {
139
157
) }
140
158
</ button >
141
159
</ div >
142
- { field . meta . touched && field . meta . error && (
160
+ { meta . touched && meta . error && (
143
161
< span className = "form-error" aria-live = "polite" >
144
- { field . meta . error }
162
+ { meta . error }
145
163
</ span >
146
164
) }
147
165
</ div >
148
166
) }
149
167
</ Field >
168
+
169
+ { /* Confirm Password Field */ }
150
170
< Field name = "confirmPassword" >
151
- { ( field ) => (
171
+ { ( { input , meta } ) => (
152
172
< div className = "form__field" >
153
173
< label htmlFor = "confirmPassword" className = "form__label" >
154
174
{ t ( 'SignupForm.ConfirmPassword' ) }
155
175
</ label >
156
176
< div className = "form__field__password" >
157
177
< input
158
178
className = "form__input"
159
- type = { showConfirmPassword ? 'text' : 'password' }
160
179
aria-label = { t ( 'SignupForm.ConfirmPasswordARIA' ) }
161
- id = "confirmPassword" // Match the id with htmlFor
180
+ type = { showConfirmPassword ? 'text' : 'password' }
181
+ id = "confirmPassword"
162
182
autoComplete = "new-password"
163
- { ...field . input }
183
+ { ...input }
164
184
/>
165
185
< button
166
186
className = "form__eye__icon"
@@ -175,14 +195,16 @@ function SignupForm() {
175
195
) }
176
196
</ button >
177
197
</ div >
178
- { field . meta . touched && field . meta . error && (
198
+ { meta . touched && meta . error && (
179
199
< span className = "form-error" aria-live = "polite" >
180
- { field . meta . error }
200
+ { meta . error }
181
201
</ span >
182
202
) }
183
203
</ div >
184
204
) }
185
205
</ Field >
206
+
207
+ { /* Submit Button */ }
186
208
< Button type = "submit" disabled = { submitting || invalid || pristine } >
187
209
{ t ( 'SignupForm.SubmitSignup' ) }
188
210
</ Button >
0 commit comments