update validate
This commit is contained in:
@@ -23,10 +23,9 @@ export default function SignUpForm() {
|
|||||||
const [errorMsg, setErrorMsg] = useState("");
|
const [errorMsg, setErrorMsg] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
// Hàm handle thay đổi input
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||||
setErrorMsg(""); // Xoá lỗi khi user gõ lại
|
setErrorMsg("");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hàm validate email
|
// Hàm validate email
|
||||||
@@ -35,12 +34,18 @@ export default function SignUpForm() {
|
|||||||
return emailRegex.test(email);
|
return emailRegex.test(email);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Hàm validate mật khẩu mới
|
||||||
|
const isValidPassword = (pass: string) => {
|
||||||
|
// Tối thiểu 8 ký tự, 1 chữ in hoa, 1 chữ số, 1 ký tự đặc biệt
|
||||||
|
const passwordRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$/;
|
||||||
|
return passwordRegex.test(pass);
|
||||||
|
};
|
||||||
|
|
||||||
// Xử lý khi bấm nút Sign Up (Step 1)
|
// Xử lý khi bấm nút Sign Up (Step 1)
|
||||||
const handleSignUpClick = async (e: React.FormEvent<HTMLFormElement>) => {
|
const handleSignUpClick = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setErrorMsg("");
|
setErrorMsg("");
|
||||||
|
|
||||||
// Validate cơ bản
|
|
||||||
if (!formData.fname || !formData.lname || !formData.email || !formData.password) {
|
if (!formData.fname || !formData.lname || !formData.email || !formData.password) {
|
||||||
setErrorMsg("Vui lòng điền đầy đủ thông tin.");
|
setErrorMsg("Vui lòng điền đầy đủ thông tin.");
|
||||||
return;
|
return;
|
||||||
@@ -49,12 +54,14 @@ export default function SignUpForm() {
|
|||||||
setErrorMsg("Email không đúng định dạng.");
|
setErrorMsg("Email không đúng định dạng.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!isValidPassword(formData.password)) {
|
||||||
|
setErrorMsg("Mật khẩu chưa đủ điều kiện. Vui lòng nhập tối thiểu 8 ký tự, 1 in hoa, 1 số và 1 ký tự đặc biệt.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// Gọi hàm CREATEOTP
|
|
||||||
await apiCreateOTP(formData.email);
|
await apiCreateOTP(formData.email);
|
||||||
// Nếu thành công, chuyển sang màn hình OTP
|
|
||||||
setStep(2);
|
setStep(2);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setErrorMsg("Lỗi khi tạo OTP. Vui lòng thử lại.");
|
setErrorMsg("Lỗi khi tạo OTP. Vui lòng thử lại.");
|
||||||
@@ -91,6 +98,7 @@ export default function SignUpForm() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const signupRes = await apiSignUp(signupPayload);
|
const signupRes = await apiSignUp(signupPayload);
|
||||||
|
console.log("API Sign Up Response:", signupRes);
|
||||||
|
|
||||||
console.log("Đăng ký thành công!", signupRes);
|
console.log("Đăng ký thành công!", signupRes);
|
||||||
alert("Đăng ký thành công! Đang chuyển hướng...");
|
alert("Đăng ký thành công! Đang chuyển hướng...");
|
||||||
@@ -139,15 +147,12 @@ export default function SignUpForm() {
|
|||||||
{/* ----- STEP 1: FORM SIGN UP ----- */}
|
{/* ----- STEP 1: FORM SIGN UP ----- */}
|
||||||
{step === 1 && (
|
{step === 1 && (
|
||||||
<>
|
<>
|
||||||
{/* Các nút đăng ký Social (Bỏ qua xử lý logic trong ví dụ này) */}
|
{/* Các nút đăng ký Social */}
|
||||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-5">
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-5">
|
||||||
{/* ... (Giữ nguyên các nút Sign up with Google / X của bạn) ... */}
|
|
||||||
<button className="inline-flex items-center justify-center gap-3 py-3 text-sm font-normal text-gray-700 transition-colors bg-gray-100 rounded-lg px-7 hover:bg-gray-200 hover:text-gray-800 dark:bg-white/5 dark:text-white/90 dark:hover:bg-white/10">
|
<button className="inline-flex items-center justify-center gap-3 py-3 text-sm font-normal text-gray-700 transition-colors bg-gray-100 rounded-lg px-7 hover:bg-gray-200 hover:text-gray-800 dark:bg-white/5 dark:text-white/90 dark:hover:bg-white/10">
|
||||||
{/* Icon Google */}
|
|
||||||
Sign up with Google
|
Sign up with Google
|
||||||
</button>
|
</button>
|
||||||
<button className="inline-flex items-center justify-center gap-3 py-3 text-sm font-normal text-gray-700 transition-colors bg-gray-100 rounded-lg px-7 hover:bg-gray-200 hover:text-gray-800 dark:bg-white/5 dark:text-white/90 dark:hover:bg-white/10">
|
<button className="inline-flex items-center justify-center gap-3 py-3 text-sm font-normal text-gray-700 transition-colors bg-gray-100 rounded-lg px-7 hover:bg-gray-200 hover:text-gray-800 dark:bg-white/5 dark:text-white/90 dark:hover:bg-white/10">
|
||||||
{/* Icon X */}
|
|
||||||
Sign up with X
|
Sign up with X
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -209,41 +214,41 @@ export default function SignUpForm() {
|
|||||||
|
|
||||||
{/* Password */}
|
{/* Password */}
|
||||||
<div>
|
<div>
|
||||||
<Label>
|
<Label>Password<span className="text-error-500">*</span></Label>
|
||||||
Password<span className="text-error-500">*</span>
|
|
||||||
</Label>
|
{/* Thêm style báo đỏ ô nhập nếu pass chưa hợp lệ */}
|
||||||
<div className="relative">
|
<div className={`relative ${formData.password.length > 0 && !isValidPassword(formData.password) ? 'border border-red-500 ring-1 ring-red-500 rounded-lg' : ''}`}>
|
||||||
<Input
|
<Input
|
||||||
name="password"
|
name="password"
|
||||||
defaultValue={formData.password}
|
defaultValue={formData.password}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder="Enter your password"
|
placeholder="Min. 8 characters"
|
||||||
type={showPassword ? "text" : "password"}
|
type={showPassword ? "text" : "password"}
|
||||||
/>
|
/>
|
||||||
<span
|
<span onClick={() => setShowPassword(!showPassword)} className="absolute z-30 -translate-y-1/2 cursor-pointer right-4 top-1/2">
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
{showPassword ? <EyeIcon /> : <EyeCloseIcon />}
|
||||||
className="absolute z-30 -translate-y-1/2 cursor-pointer right-4 top-1/2"
|
|
||||||
>
|
|
||||||
{showPassword ? (
|
|
||||||
<span className="fill-gray-500 dark:fill-gray-400">
|
|
||||||
<EyeIcon />
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span className="fill-gray-500 dark:fill-gray-400">
|
|
||||||
<EyeCloseIcon />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Gợi ý trực quan cho người dùng */}
|
||||||
|
<p className={`mt-2 text-xs ${formData.password.length === 0 ? 'text-gray-400' : isValidPassword(formData.password) ? 'text-green-500' : 'text-red-500'}`}>
|
||||||
|
Mật khẩu phải chứa tối thiểu 8 ký tự, 1 chữ cái in hoa, 1 chữ số và 1 ký tự đặc biệt.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Checkbox */}
|
{/* Checkbox */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
|
<div className={formData.password.length > 0 && !isValidPassword(formData.password) ? "opacity-50 cursor-not-allowed" : ""}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className="w-5 h-5"
|
className="w-5 h-5"
|
||||||
checked={isChecked}
|
checked={isChecked}
|
||||||
onChange={setIsChecked}
|
// Chặn bấm check nếu password chưa hợp lệ
|
||||||
|
onChange={(val) => {
|
||||||
|
if (isValidPassword(formData.password)) setIsChecked(val);
|
||||||
|
}}
|
||||||
|
disabled={!isValidPassword(formData.password)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<p className="inline-block font-normal text-gray-500 dark:text-gray-400">
|
<p className="inline-block font-normal text-gray-500 dark:text-gray-400">
|
||||||
By creating an account means you agree to the{" "}
|
By creating an account means you agree to the{" "}
|
||||||
<span className="text-gray-800 dark:text-white/90">
|
<span className="text-gray-800 dark:text-white/90">
|
||||||
@@ -260,9 +265,9 @@ export default function SignUpForm() {
|
|||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!isChecked || loading}
|
disabled={!isChecked || loading || !isValidPassword(formData.password)}
|
||||||
className={`flex items-center justify-center w-full px-4 py-3 text-sm font-medium text-white transition rounded-lg bg-brand-500 shadow-theme-xs
|
className={`flex items-center justify-center w-full px-4 py-3 text-sm font-medium text-white transition rounded-lg bg-brand-500 shadow-theme-xs
|
||||||
${!isChecked ? "opacity-50 cursor-not-allowed" : "hover:bg-brand-600"}`}
|
${(!isChecked || !isValidPassword(formData.password)) ? "opacity-50 cursor-not-allowed" : "hover:bg-brand-600"}`}
|
||||||
>
|
>
|
||||||
{loading ? "Processing..." : "Sign Up"}
|
{loading ? "Processing..." : "Sign Up"}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user