Skip to content

Commit f7b4c8c

Browse files
authored
Merge pull request #3345 from Jatin24062005/Jatin-issue-#3235
Enhance SignupForm with Debounced Validation
2 parents 0b3851c + 0305dc4 commit f7b4c8c

File tree

1 file changed

+64
-42
lines changed

1 file changed

+64
-42
lines changed

client/modules/User/components/SignupForm.jsx

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,62 @@ import Button from '../../../common/Button';
99
import apiClient from '../../../utils/apiClient';
1010
import useSyncFormTranslations from '../../../common/useSyncFormTranslations';
1111

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) {
1323
if (!value || value.trim().length === 0) {
1424
return '';
1525
}
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
2634
});
35+
return response.data.exists ? response.data.message : '';
36+
} catch (error) {
37+
return 'Error validating field.';
38+
}
2739
}
2840

41+
const debouncedAsyncValidate = debounce(asyncValidate, 300);
42+
2943
function validateUsername(username) {
30-
return asyncValidate('username', username);
44+
return debouncedAsyncValidate('username', username);
3145
}
3246

3347
function validateEmail(email) {
34-
return asyncValidate('email', email);
48+
return debouncedAsyncValidate('email', email);
3549
}
3650

3751
function SignupForm() {
3852
const { t, i18n } = useTranslation();
39-
4053
const dispatch = useDispatch();
41-
function onSubmit(formProps) {
42-
return dispatch(validateAndSignUpUser(formProps));
43-
}
54+
const formRef = useRef(null);
4455
const [showPassword, setShowPassword] = useState(false);
4556
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+
5358
useSyncFormTranslations(formRef, i18n.language);
5459

60+
const handleVisibility = () => setShowPassword(!showPassword);
61+
const handleConfirmVisibility = () =>
62+
setShowConfirmPassword(!showConfirmPassword);
63+
64+
function onSubmit(formProps) {
65+
return dispatch(validateAndSignUpUser(formProps));
66+
}
67+
5568
return (
5669
<Form
5770
fields={['username', 'email', 'password', 'confirmPassword']}
@@ -62,12 +75,13 @@ function SignupForm() {
6275
formRef.current = form;
6376
return (
6477
<form className="form" onSubmit={handleSubmit}>
78+
{/* Username Field */}
6579
<Field
6680
name="username"
6781
validate={validateUsername}
6882
validateFields={[]}
6983
>
70-
{(field) => (
84+
{({ input, meta }) => (
7185
<div className="form__field">
7286
<label htmlFor="username" className="form__label">
7387
{t('SignupForm.Title')}
@@ -79,18 +93,20 @@ function SignupForm() {
7993
id="username"
8094
autoComplete="username"
8195
autoCapitalize="none"
82-
{...field.input}
96+
{...input}
8397
/>
84-
{field.meta.touched && field.meta.error && (
98+
{meta.touched && meta.error && (
8599
<span className="form-error" aria-live="polite">
86-
{field.meta.error}
100+
{meta.error}
87101
</span>
88102
)}
89103
</div>
90104
)}
91105
</Field>
106+
107+
{/* Email Field */}
92108
<Field name="email" validate={validateEmail} validateFields={[]}>
93-
{(field) => (
109+
{({ input, meta }) => (
94110
<div className="form__field">
95111
<label htmlFor="email" className="form__label">
96112
{t('SignupForm.Email')}
@@ -101,18 +117,20 @@ function SignupForm() {
101117
type="email"
102118
id="email"
103119
autoComplete="email"
104-
{...field.input}
120+
{...input}
105121
/>
106-
{field.meta.touched && field.meta.error && (
122+
{meta.touched && meta.error && (
107123
<span className="form-error" aria-live="polite">
108-
{field.meta.error}
124+
{meta.error}
109125
</span>
110126
)}
111127
</div>
112128
)}
113129
</Field>
130+
131+
{/* Password Field */}
114132
<Field name="password">
115-
{(field) => (
133+
{({ input, meta }) => (
116134
<div className="form__field">
117135
<label htmlFor="password" className="form__label">
118136
{t('SignupForm.Password')}
@@ -124,7 +142,7 @@ function SignupForm() {
124142
type={showPassword ? 'text' : 'password'}
125143
id="password"
126144
autoComplete="new-password"
127-
{...field.input}
145+
{...input}
128146
/>
129147
<button
130148
className="form__eye__icon"
@@ -139,28 +157,30 @@ function SignupForm() {
139157
)}
140158
</button>
141159
</div>
142-
{field.meta.touched && field.meta.error && (
160+
{meta.touched && meta.error && (
143161
<span className="form-error" aria-live="polite">
144-
{field.meta.error}
162+
{meta.error}
145163
</span>
146164
)}
147165
</div>
148166
)}
149167
</Field>
168+
169+
{/* Confirm Password Field */}
150170
<Field name="confirmPassword">
151-
{(field) => (
171+
{({ input, meta }) => (
152172
<div className="form__field">
153173
<label htmlFor="confirmPassword" className="form__label">
154174
{t('SignupForm.ConfirmPassword')}
155175
</label>
156176
<div className="form__field__password">
157177
<input
158178
className="form__input"
159-
type={showConfirmPassword ? 'text' : 'password'}
160179
aria-label={t('SignupForm.ConfirmPasswordARIA')}
161-
id="confirmPassword" // Match the id with htmlFor
180+
type={showConfirmPassword ? 'text' : 'password'}
181+
id="confirmPassword"
162182
autoComplete="new-password"
163-
{...field.input}
183+
{...input}
164184
/>
165185
<button
166186
className="form__eye__icon"
@@ -175,14 +195,16 @@ function SignupForm() {
175195
)}
176196
</button>
177197
</div>
178-
{field.meta.touched && field.meta.error && (
198+
{meta.touched && meta.error && (
179199
<span className="form-error" aria-live="polite">
180-
{field.meta.error}
200+
{meta.error}
181201
</span>
182202
)}
183203
</div>
184204
)}
185205
</Field>
206+
207+
{/* Submit Button */}
186208
<Button type="submit" disabled={submitting || invalid || pristine}>
187209
{t('SignupForm.SubmitSignup')}
188210
</Button>

0 commit comments

Comments
 (0)