fix: accounts review

This commit is contained in:
Koosha Lahouti
2025-09-22 12:04:54 +03:30
parent a42da2d4c4
commit 21b7fb27ce
16 changed files with 210 additions and 157 deletions

View File

@@ -64,10 +64,8 @@ export function UserCompletionPage() {
const correctEmail = isEmail(email);
const { execute: sendCode, loading: isSendingCode } = useApi(sendEmailOtpApi);
const { execute: verifyCode, loading: isVerifyingCode } =
useApi(confirmEmailOtpApi);
const { execute: submitForm, loading: isSubmitting } = useApi(
completeUserInformationApi,
);
@@ -89,13 +87,30 @@ export function UserCompletionPage() {
return () => clearInterval(timer);
}, [buttonState, countdown]);
useEffect(() => {
if (buttonState === 'default') {
setCodeSent(false);
setVerificationCode('');
// setEmailVerified(false);
setTouched((prev) => {
const n = { ...prev };
delete n.verificationCode;
return n;
});
setErrors((prev) => {
const n = { ...prev };
delete n.verificationCode;
return n;
});
}
}, [buttonState]);
const handleSendCode = async () => {
if (!isEmail(email)) {
setTouched((prev) => ({ ...prev, email: true }));
setErrors((prev) => ({ ...prev, email: t('validation.emailInvalid') }));
return;
}
setTouched((prev) => {
const newTouched = { ...prev };
delete newTouched.verificationCode;
@@ -106,13 +121,11 @@ export function UserCompletionPage() {
delete newErrors.verificationCode;
return newErrors;
});
const res = await sendCode({ email });
if (res) {
if (res.success) {
showToast({
message: res.message || t('completion.successfulCodeSent'),
message: t('completion.successfulCodeSent'),
severity: 'success',
});
setCodeSent(true);
@@ -129,8 +142,6 @@ export function UserCompletionPage() {
const handleVerifyCode = async () => {
const trimmedCode = verificationCode.trim();
// Manually trigger the validation error and stop
if (!trimmedCode) {
setTouched((prev) => ({ ...prev, verificationCode: true }));
setErrors((prev) => ({
@@ -146,9 +157,7 @@ export function UserCompletionPage() {
}));
return;
}
const res = await verifyCode({ email, otpCode: verificationCode });
if (res) {
if (res.success) {
setEmailVerified(true);
@@ -178,12 +187,10 @@ export function UserCompletionPage() {
confirmPassword: showPasswordSection,
sex: true,
});
const isValid = validateForm();
if (!isValid) {
return; // Stop the submission
return;
}
const res = await submitForm({
firstName,
lastName,
@@ -196,16 +203,13 @@ export function UserCompletionPage() {
birthDate,
countryCode: country,
});
if (res) {
if (res.success) {
showToast({
message: res.message || t('completion.submitSuccess'),
severity: 'success',
});
const returnUrl = params.get('returnUrl');
navigate(
returnUrl ? `/account-created?returnUrl=${returnUrl}` : '/setting',
);
@@ -223,7 +227,6 @@ export function UserCompletionPage() {
setCodeSent(false);
setEmailVerified(false);
setVerificationCode('');
// We clear both touched and errors
setTouched((prev) => {
const newTouched = { ...prev };
delete newTouched.email;
@@ -240,77 +243,49 @@ export function UserCompletionPage() {
const validateForm = () => {
const newErrors: { [key: string]: string } = {};
// Rule 1: First Name is required
if (!firstName.trim())
newErrors.firstName = t('validation.firstNameRequired');
// Rule 2: Last Name is required
if (!lastName.trim()) newErrors.lastName = t('validation.lastNameRequired');
// Rule 3: Country is required
if (!country) newErrors.country = t('validation.countryRequired');
// Rule 4: Email is required and must be valid IF the section is shown
if (showEmail && !isEmail(email)) {
newErrors.email = t('validation.emailInvalid');
}
// Rule 5: National ID must be 10 digits IF it's not empty
if (nationalId && !nationalIdRegex.test(nationalId)) {
newErrors.nationalId = t('validation.nationalIdInvalid');
}
// Rule 6: If verification code sent and email section is active
if (showEmail && codeSent && !emailVerified) {
const trimmedCode = verificationCode.trim();
if (!trimmedCode) {
// Case 1: The code is required but the field is empty.
newErrors.verificationCode = t('validation.verificationCodeRequired');
} else if (trimmedCode.length < 4) {
// Case 2 : The code is entered but is less than 4 digits.
newErrors.verificationCode = t('validation.verificationCodeInvalid');
} else {
// Case 3: The user has typed a code but hasn't clicked "Verify" yet.
newErrors.verificationCode = t('validation.mustVerifyCode');
}
}
// Rule 7: Password validation
if (showPasswordSection) {
// Rule 1: Check if the main password is valid
if (!password.trim()) {
newErrors.password = t('validation.passwordRequired');
} else if (!validPassword) {
// 'validPassword' is the boolean you already calculate
newErrors.password = t('validation.passwordInvalid');
}
// Rule 2: Check if the confirmation password matches
if (!confirmPassword.trim()) {
newErrors.confirmPassword = t('validation.confirmPasswordRequired');
} else if (!matchPassword) {
// 'matchPassword' is the boolean you already calculate
newErrors.confirmPassword = t('validation.passwordsDoNotMatch');
}
}
if (sex === null) {
newErrors.sex = t('validation.genderRequired');
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0; // Returns true if form is valid
return Object.keys(newErrors).length === 0;
};
const handleBlur = (field: string) => {
setTouched((prev) => ({ ...prev, [field]: true }));
};
const handleBlur = (_field: string) => {};
useEffect(() => {
if (!showPasswordSection) {
// We clear both touched and errors to prevent lingering validation messages
setTouched((prev) => {
const newTouched = { ...prev };
delete newTouched.password;
@@ -326,10 +301,8 @@ export function UserCompletionPage() {
}
}, [showPasswordSection]);
// This effect resets email fields when the section is hidden
useEffect(() => {
if (!showEmail) {
// We clear both touched and errors
setTouched((prev) => {
const newTouched = { ...prev };
delete newTouched.email;
@@ -345,9 +318,7 @@ export function UserCompletionPage() {
}
}, [showEmail]);
// re-validate whenever a field the user has touched changes value
useEffect(() => {
// Only run validation if at least one field has been touched
if (Object.keys(touched).length > 0) {
validateForm();
}