+47
-32
src/components/migration/accountDetailsForm.tsx
+47
-32
src/components/migration/accountDetailsForm.tsx
···
1
-
import { useState, useEffect } from 'react';
1
+
import { useState, useEffect, useCallback } from 'react';
2
2
import { ServerDescription } from '../../lib/migration/serverDescription';
3
3
import { validateHandle } from '../../lib/migration/accountDetailsValidation';
4
4
···
33
33
const domainNames = Object.values(availableDomains);
34
34
const { isUsingDefaultDomain, customHandle } = validateHandle(currentHandle, domainNames);
35
35
36
+
36
37
setIsUsingDefaultDomain(isUsingDefaultDomain);
37
38
if (isUsingDefaultDomain) {
38
39
// Set initial handle value from current handle
···
61
62
return '';
62
63
};
63
64
64
-
const handleSubmit = (e: React.FormEvent) => {
65
-
e.preventDefault();
65
+
// Debounced validation functions
66
+
const debouncedValidateHandle = useCallback((value: string) => {
67
+
const timeoutId = setTimeout(() => {
68
+
setHandleError(validateHandleInput(value));
69
+
}, 500);
70
+
return () => clearTimeout(timeoutId);
71
+
}, []);
66
72
67
-
// Reset errors
68
-
setEmailError('');
69
-
setPasswordError('');
70
-
setHandleError('');
73
+
const debouncedValidateEmail = useCallback((value: string) => {
74
+
const timeoutId = setTimeout(() => {
75
+
setEmailError(validateEmail(value) ? '' : 'Please enter a valid email address');
76
+
}, 500);
77
+
return () => clearTimeout(timeoutId);
78
+
}, []);
71
79
72
-
// Validate handle
80
+
const debouncedValidatePassword = useCallback((value: string) => {
81
+
const timeoutId = setTimeout(() => {
82
+
setPasswordError(validatePassword(value) ? '' : 'Password must be at least 8 characters long');
83
+
}, 500);
84
+
return () => clearTimeout(timeoutId);
85
+
}, []);
86
+
87
+
const handleSubmit = (e: React.FormEvent) => {
88
+
e.preventDefault();
89
+
90
+
// Validate all fields
73
91
const handleValidationError = validateHandleInput(handle);
74
-
if (handleValidationError) {
75
-
setHandleError(handleValidationError);
76
-
return;
77
-
}
78
-
79
-
// Validate email
80
-
if (!validateEmail(email)) {
81
-
setEmailError('Please enter a valid email address');
82
-
return;
83
-
}
84
-
85
-
// Validate password
86
-
if (!validatePassword(password)) {
87
-
setPasswordError('Password must be at least 8 characters long');
88
-
return;
92
+
const emailValidationError = !validateEmail(email) ? 'Please enter a valid email address' : '';
93
+
const passwordValidationError = !validatePassword(password) ? 'Password must be at least 8 characters long' : '';
94
+
95
+
setHandleError(handleValidationError);
96
+
setEmailError(emailValidationError);
97
+
setPasswordError(passwordValidationError);
98
+
99
+
// Only submit if all validations pass
100
+
if (!handleValidationError && !emailValidationError && !passwordValidationError) {
101
+
onSubmit(handle, email, password);
89
102
}
90
-
91
-
onSubmit(handle, email, password);
92
103
};
93
104
94
105
// Get the first available domain from the new server description
···
114
125
id="handle"
115
126
value={handle}
116
127
onChange={(e) => {
117
-
setHandle(e.target.value);
118
-
setHandleError('');
128
+
const newValue = e.target.value;
129
+
setHandle(newValue);
130
+
debouncedValidateHandle(newValue);
119
131
}}
120
132
placeholder="alice"
121
133
className={`form-input ${handleError ? 'error' : ''}`}
···
123
135
<span className="handle-domain">{newFirstAvailableDomain}</span>
124
136
</div>
125
137
{handleError && <div className="error-message">{handleError}</div>}
138
+
{handleError && <div className="error-message">{handleError}</div>}
126
139
</div>
127
140
</div>
128
141
)}
···
134
147
id="email"
135
148
value={email}
136
149
onChange={(e) => {
137
-
setEmail(e.target.value);
138
-
setEmailError('');
150
+
const newValue = e.target.value;
151
+
setEmail(newValue);
152
+
debouncedValidateEmail(newValue);
139
153
}}
140
154
placeholder="popbob@example.com"
141
155
required
···
151
165
id="password"
152
166
value={password}
153
167
onChange={(e) => {
154
-
setPassword(e.target.value);
155
-
setPasswordError('');
168
+
const newValue = e.target.value;
169
+
setPassword(newValue);
170
+
debouncedValidatePassword(newValue);
156
171
}}
157
172
placeholder="hunter2"
158
173
required
···
161
176
{passwordError && <div className="error-message">{passwordError}</div>}
162
177
</div>
163
178
<small>We recommend using a new, unique password for your new account.</small>
164
-
179
+
165
180
<div className="button-container">
166
181
<button
167
182
type="button"