diff --git a/src/pages/authentication/LoginWithOtp.jsx b/src/pages/authentication/LoginWithOtp.jsx index e0328b1b..82340757 100644 --- a/src/pages/authentication/LoginWithOtp.jsx +++ b/src/pages/authentication/LoginWithOtp.jsx @@ -17,11 +17,8 @@ const otpSchema = z.object({ const LoginWithOtp = () => { const navigate = useNavigate(); - - const [ loading, setLoading ] = useState( false ); - const [ timeLeft, setTimeLeft ] = useState( 0 ); - - + const [loading, setLoading] = useState(false); + const [timeLeft, setTimeLeft] = useState(0); const inputRefs = useRef([]); const { @@ -29,69 +26,68 @@ const LoginWithOtp = () => { handleSubmit, formState: { errors, isSubmitted }, getValues, + setValue } = useForm({ resolver: zodResolver(otpSchema), }); const onSubmit = async (data) => { const finalOtp = data.otp1 + data.otp2 + data.otp3 + data.otp4; - const username = localStorage.getItem( "otpUsername" ); + const username = localStorage.getItem("otpUsername"); setLoading(true); try { - let requestedData = { - email: username, - otp:finalOtp - } - const response = await AuthRepository.verifyOTP( requestedData ) - - localStorage.setItem("jwtToken", response.data.token); - localStorage.setItem("refreshToken", response.data.refreshToken); - setLoading( false ); - localStorage.removeItem( "otpUsername" ); - localStorage.removeItem( "otpSentTime" ); - navigate( "/dashboard" ); - + const requestedData = { + email: username, + otp: finalOtp, + }; + const response = await AuthRepository.verifyOTP(requestedData); + localStorage.setItem("jwtToken", response.data.token); + localStorage.setItem("refreshToken", response.data.refreshToken); + localStorage.removeItem("otpUsername"); + localStorage.removeItem("otpSentTime"); + navigate("/dashboard"); } catch (err) { - showToast( "Invalid or expired OTP.", "error" ); - - setLoading(false); + showToast("Invalid or expired OTP.", "error"); + } finally { + setLoading(false); } }; -const formatTime = (seconds) => { - const min = Math.floor(seconds / 60).toString().padStart(2, "0"); - const sec = (seconds % 60).toString().padStart(2, "0"); - return `${min}:${sec}`; -}; -useEffect(() => { - const otpSentTime = localStorage.getItem("otpSentTime"); - const now = Date.now(); + const formatTime = (seconds) => { + const min = Math.floor(seconds / 60).toString().padStart(2, "0"); + const sec = (seconds % 60).toString().padStart(2, "0"); + return `${min}:${sec}`; + }; - if (otpSentTime) { - const elapsed = Math.floor((now - Number(otpSentTime)) / 1000); // in seconds - const remaining = Math.max(OTP_EXPIRY_SECONDS - elapsed, 0); // prevent negatives - setTimeLeft(remaining); - } -}, []); -useEffect(() => { - if (timeLeft <= 0) return; + useEffect(() => { + const otpSentTime = localStorage.getItem("otpSentTime"); + const now = Date.now(); - const timer = setInterval(() => { - setTimeLeft((prev) => { - if (prev <= 1) { - clearInterval(timer); - localStorage.removeItem( "otpSentTime" ); - localStorage.removeItem("otpUsername"); - return 0; - } - return prev - 1; - }); - }, 1000); + if (otpSentTime) { + const elapsed = Math.floor((now - Number(otpSentTime)) / 1000); + const remaining = Math.max(OTP_EXPIRY_SECONDS - elapsed, 0); + setTimeLeft(remaining); + } + }, []); - return () => clearInterval(timer); -}, [timeLeft]); + useEffect(() => { + if (timeLeft <= 0) return; + const timer = setInterval(() => { + setTimeLeft((prev) => { + if (prev <= 1) { + clearInterval(timer); + localStorage.removeItem("otpSentTime"); + localStorage.removeItem("otpUsername"); + return 0; + } + return prev - 1; + }); + }, 1000); + + return () => clearInterval(timer); + }, [timeLeft]); return ( @@ -100,7 +96,7 @@ useEffect(() => {

Please enter the 4-digit code sent to your email.

-
+
{[1, 2, 3, 4].map((num, idx) => { const { ref, onChange, ...rest } = register(`otp${num}`); @@ -132,6 +128,24 @@ useEffect(() => { inputRefs.current[idx - 1]?.focus(); } }} + onPaste={ + idx === 0 + ? (e) => { + const pasteData = e.clipboardData.getData("Text").trim(); + if (/^\d{4}$/.test(pasteData)) { + e.preventDefault(); + pasteData.split("").forEach((char, i) => { + const ref = inputRefs.current[i]; + if (ref) { + ref.value = char; + setValue(`otp${i + 1}`, char); + } + }); + inputRefs.current[3]?.focus(); + } + } + : undefined + } style={{ width: "40px", height: "40px", fontSize: "15px" }} {...rest} /> @@ -140,10 +154,7 @@ useEffect(() => {
{isSubmitted && Object.values(errors).some((e) => e?.message) && ( -
+
Please fill all four digits.
)} @@ -157,23 +168,21 @@ useEffect(() => { {timeLeft > 0 ? ( -

+

This OTP will expire in {formatTime(timeLeft)}

- ) : ( -
-

- OTP has expired. Please request a new one. -

- navigate('/auth/login')}>Try Again -
- + ) : ( +
+

+ OTP has expired. Please request a new one. +

+ navigate("/auth/login")} + > + Try Again + +
)}