import { useState, useEffect, useMemo } from "react"; import { useSearchParams } from "react-router-dom"; import { Input } from "@/shared/common/ui/input"; import { Button } from "@/shared/common/ui/button"; import { toast } from "sonner"; import { useAuthUser } from "../hooks/useAuthUser"; import { useErrorHandler } from "../hooks/useErrorHandler"; import { Lock, Mail, Eye, EyeOff, RefreshCw, ArrowLeft } from "lucide-react"; import { motion } from "framer-motion"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; const SetPasswordPage = () => { const navigate = useNavigate(); const { t } = useTranslation(); const { handleError } = useErrorHandler(t); const [searchParams] = useSearchParams(); const { setPassword, isSettingPassword, setPasswordError, setPasswordSuccess, resendVerificationCode, isResendingCode, resendError, resendSuccess, } = useAuthUser(); const email = searchParams.get("email"); const verificationCode = searchParams.get("verificationCode") || ""; const phoneNumber = searchParams.get("phoneNumber"); const userId = searchParams.get("userId"); const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const [resendAttempted, setResendAttempted] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [submitAttempted, setSubmitAttempted] = useState(false); const [showPassword, setShowPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false); const [error, setError] = useState(""); // Password validation rules const getPasswordValidation = (password: string) => { return { minLength: password.length >= 8, hasLowercase: /[a-z]/.test(password), hasUppercase: /[A-Z]/.test(password), hasNumber: /\d/.test(password), hasSymbol: /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password), }; }; const passwordValidation = useMemo( () => getPasswordValidation(newPassword), [newPassword] ); const isPasswordStrong = Object.values(passwordValidation).every(Boolean); const isPasswordMatch = confirmPassword.length > 0 && newPassword === confirmPassword; const canSubmit = Boolean(newPassword && confirmPassword && isPasswordStrong && isPasswordMatch); const handlePasswordChange = (e: React.ChangeEvent) => { const password = e.target.value; setNewPassword(password); if (error) setError(""); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setSubmitAttempted(true); setError(""); if (!newPassword || !confirmPassword) { setError("Please fill in both fields"); return; } // Validate password strength if (!isPasswordStrong) { const missingRequirements = []; if (!passwordValidation.minLength) missingRequirements.push("at least 8 characters"); if (!passwordValidation.hasLowercase) missingRequirements.push("one lowercase letter"); if (!passwordValidation.hasUppercase) missingRequirements.push("one uppercase letter"); if (!passwordValidation.hasNumber) missingRequirements.push("one number"); if (!passwordValidation.hasSymbol) missingRequirements.push("one symbol (!@#$%^&*...)"); setError(`Password must contain: ${missingRequirements.join(", ")}`); return; } if (!isPasswordMatch) { setError("Passwords don't match"); return; } // Prepare payload - include userId and email when available const payload: any = { verificationCode, newPassword, confirmPassword, }; if (userId) { payload.userId = userId; } if (email) { payload.email = email; } else if (phoneNumber) { // Apply the same phone number formatting logic let processedPhoneNumber = phoneNumber; if (processedPhoneNumber.startsWith("0")) { processedPhoneNumber = "+251" + processedPhoneNumber.slice(1); } payload.phoneNumber = processedPhoneNumber; } setIsSubmitting(true); setPassword(payload); }; const handleResendCode = () => { if (!phoneNumber && !email) { toast.error("User ID is missing. Cannot resend verification code."); return; } setResendAttempted(true); resendVerificationCode({ phoneNumber: phoneNumber || "", email: email || undefined }); }; useEffect(() => { if (setPasswordSuccess) { toast.success("Password updated successfully! You can now login"); setIsSubmitting(false); navigate("/login"); } }, [setPasswordSuccess, navigate]); useEffect(() => { if (!submitAttempted) return; if (setPasswordError?.message) { setIsSubmitting(false); // Use handleError hook to process backend errors handleError(setPasswordError); } }, [setPasswordError?.message, handleError, submitAttempted]); useEffect(() => { if (resendSuccess && resendAttempted) { toast.success("Verification code resent successfully!"); setResendAttempted(false); } if (resendError && resendAttempted) { // Use handleError hook to process backend errors handleError(resendError); setResendAttempted(false); } }, [resendSuccess, resendError, resendAttempted, handleError]); return (
Smart Office Logo

Set Password

Set a new password for your account

{email && (

Email: {email}

)} {phoneNumber && (

Phone: {phoneNumber}

)}
setShowPassword(!showPassword)} > {showPassword ? ( ) : ( )}
{/* Password strength indicator */} {newPassword && (

Password Requirements:

{passwordValidation.minLength && }
At least 8 characters
{passwordValidation.hasUppercase && }
One uppercase letter (A-Z)
{passwordValidation.hasLowercase && }
One lowercase letter (a-z)
{passwordValidation.hasNumber && }
One number (0-9)
{passwordValidation.hasSymbol && }
One symbol (!@#$%^&*...)
)}
{ setConfirmPassword(e.target.value); if (error) setError(""); }} required />
setShowConfirmPassword(!showConfirmPassword)} > {showConfirmPassword ? ( ) : ( )}
{error &&

{error}

}
); }; export default SetPasswordPage;