From d76f59284b62ae988423fc40664a873b4d9513df Mon Sep 17 00:00:00 2001 From: Malini Date: Mon, 19 Jan 2026 18:15:24 +0530 Subject: [PATCH] added icon --- ipi-survey-platform/index.html | 6 +- .../public/assets/images/image.png | Bin 0 -> 803 bytes .../pages/OTPVerification/OTPVerification.jsx | 146 +++++++++--------- 3 files changed, 76 insertions(+), 76 deletions(-) create mode 100644 ipi-survey-platform/public/assets/images/image.png diff --git a/ipi-survey-platform/index.html b/ipi-survey-platform/index.html index 3610742..079de56 100644 --- a/ipi-survey-platform/index.html +++ b/ipi-survey-platform/index.html @@ -2,7 +2,7 @@ - + IIP Survey Platform - + - + \ No newline at end of file diff --git a/ipi-survey-platform/public/assets/images/image.png b/ipi-survey-platform/public/assets/images/image.png new file mode 100644 index 0000000000000000000000000000000000000000..20ee319ebb2bd0943c58991795149deb863a6241 GIT binary patch literal 803 zcmV+;1Kj+HP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0=P*;K~!i%?VE3C z5@8(2e`?v1Ep09nw1Qq0u?XsAZ-N*RK@da{g+xZg3Rf_Q39$$Yii%Z4y@)9>h}Mgu z$k+Xaiq>Gv7wwN5=WMmLd2a7wcj@iNXfO16!Kgc7h-X(#BeZpXvjL!y)Bm(y{XqX=AN%r>ncXbo<39#4nwdZm1Qm-*{A< zhs&gyT+_BRE6A?t#^5dp2G?ODi_hBtpWZ&hRvxi<*_Q0YR+)6<3Z_L=ujy=dQkOXs zJ&KPYPj+rrc5?H1+`BTSy}Y+KZ-K~(L)eVPH0jInR!qiYigfH;1X}j)#%4T*OCQ+3 z2d;LuVKWCqrAyClPx2Nv^Ds>M__2fV{OP@=w+%DVUE1SW4YzN0z=ONhz0VqfuF|JZ z9fAI@FClvJFmAC1vS(z8eK8Ohq+Jxzl88env>ux_N@rx=`!Q_gaTb?OzO@V6BC5{F zc4P|0;S~=lVLdSP=xr5jX;!eMS;3Yj#qatRaH0KL#W53Iq>}*w9(VVaohLmna8Gj} zF8$f>g4cch*sKY0>7+P|$+{4gezVyFgQH{EtP3$|!R>+s_XC@?AtwE5s~3Jv&0w=O zM5Gs7PDl<|`{4CIM5I&2wftwMx-Z(T01@flTm};zXqNuC(F0=>Ke5q)X6ckzz(fz4 zq&c4(-Vda)(Ss)G58*mYbfHN)l^MoF7pkSxO>P*Un8ZdGs-;Vxrf5aA^t&8~i9S?G zbN)IQ<#O2QLzVR4rZt%8M3wZn!Zap2Q6>FlXap0TD3%`gu7o^4hmB4YOOG_I!bC5M zrH7q=G0}@+>7jWZ6TK*w&hb2i!$D0G2>9{ds%Jw(qwIw0*W%ulv47;w3br&W*#FjH h?tfV { const navigate = useNavigate(); const location = useLocation(); - + const [otp, setOtp] = useState(['', '', '', '', '', '']); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const [toast, setToast] = useState(null); const [resendDisabled, setResendDisabled] = useState(false); - const [countdown, setCountdown] = useState(600); + const [countdown, setCountdown] = useState(600); const [attemptsRemaining, setAttemptsRemaining] = useState(3); - + const inputRefs = useRef(Array(6).fill(null).map(() => React.createRef())); const toastTimeoutRef = useRef(null); const countdownRef = useRef(null); - + // Get email from location state or use a default - const maskedEmail = location.state?.email ? - `${location.state.email.split('@')[0].substring(0, 2)}***@${location.state.email.split('@')[1]}` : + const maskedEmail = location.state?.email ? + `${location.state.email.split('@')[0].substring(0, 2)}***@${location.state.email.split('@')[1]}` : 'na***@company.com'; - + // Toast handling const closeToast = useCallback(() => { if (toastTimeoutRef.current) { @@ -34,7 +34,7 @@ const OTPVerification = () => { } setToast(null); }, []); - + const showToast = useCallback((type, message) => { if (!message) return; if (toastTimeoutRef.current) { @@ -47,24 +47,24 @@ const OTPVerification = () => { toastTimeoutRef.current = null; }, 4000); }, []); - + // Handle OTP input change const handleOtpChange = (e, index) => { const value = e.target.value; - + // Only allow numbers and limit to 1 character if (value && !/^\d*$/.test(value)) return; - + const newOtp = [...otp]; newOtp[index] = value.slice(-1); setOtp(newOtp); - + // Move to next input if there's a value and we're not on the last input if (value && index < 5 && inputRefs.current[index + 1]?.current) { inputRefs.current[index + 1].current.focus(); } }; - + // Handle backspace const handleKeyDown = (e, index) => { if (e.key === 'Backspace' && !otp[index] && index > 0 && inputRefs.current[index - 1]?.current) { @@ -72,7 +72,7 @@ const OTPVerification = () => { inputRefs.current[index - 1].current.focus(); } }; - + // Handle paste const handlePaste = (e) => { e.preventDefault(); @@ -82,40 +82,40 @@ const OTPVerification = () => { setOtp([...newOtp, ...Array(6 - newOtp.length).fill('')]); } }; - + // Handle verify OTP const handleVerify = async (e) => { e.preventDefault(); const otpValue = otp.join(''); - + if (otpValue.length !== 6) { setError('Please enter a valid 6-digit code'); return; } - + setLoading(true); setError(''); - + try { - const response = await verifyOtp({ - registered_email: location.state?.email, - otp: otpValue + const response = await verifyOtp({ + registered_email: location.state?.email, + otp: otpValue }); - + if (response?.status === 'success') { // Show success message immediately showToast('success', 'Verified! You are signed in. Redirecting to your dashboard.'); - + // Get the user role from the most reliable source - const userRole = response?.data?.user?.role || - response?.data?.role || + const userRole = response?.data?.user?.role || + response?.data?.role || localStorage.getItem('user_role'); - + // Set the role in localStorage if not already set if (userRole && !localStorage.getItem('user_role')) { localStorage.setItem('user_role', userRole); } - + // Update user profile in local storage with OTP verification status try { const userProfile = JSON.parse(localStorage.getItem('user_profile') || '{}'); @@ -128,22 +128,22 @@ const OTPVerification = () => { } catch (error) { console.error('Failed to update user profile:', error); } - + // Determine the appropriate dashboard based on user role let redirectPath = '/dashboard'; - + // Check if user is admin (case-insensitive check) if (userRole && userRole.toLowerCase() === 'admin') { redirectPath = '/admin/dashboard'; console.log('Admin user detected, redirecting to admin dashboard'); } - + // If there's a saved path from before login, use that const savedPath = location.state?.from?.pathname; if (savedPath) { redirectPath = savedPath; } - + // Redirect after a short delay setLoading(true); setTimeout(() => { @@ -152,20 +152,20 @@ const OTPVerification = () => { } else { throw new Error(response?.message || 'Invalid OTP'); } - + } catch (err) { console.error('OTP verification failed', err); - const errorMessage = err.response?.data?.message || - err.message || + const errorMessage = err.response?.data?.message || + err.message || 'An error occurred during OTP verification. Please try again.'; - + const newAttempts = attemptsRemaining - 1; setAttemptsRemaining(newAttempts); - + // Set the error message for incorrect OTP const displayError = errorMessage || 'Invalid verification code'; setError(displayError); - + if (newAttempts <= 0) { setOtp(Array(6).fill('')); // Show error message and redirect to login after a short delay @@ -184,76 +184,76 @@ const OTPVerification = () => { setLoading(false); } }; - + // Handle resend OTP const handleResend = async () => { if (resendDisabled) return; - + // Show loading state immediately setResendDisabled(true); setLoading(true); - + try { // Call the API to resend OTP const response = await requestOtp(location.state?.email); - + // Update state and show success toast immediately - const tenMinutesInSeconds = 10 * 60; + const tenMinutesInSeconds = 10 * 60; setCountdown(tenMinutesInSeconds); setAttemptsRemaining(3); setError(''); setOtp(Array(6).fill('')); - + // Use setTimeout to ensure the toast shows up in the next tick setTimeout(() => { showToast('success', response.message || 'A new OTP has been sent to your email.'); }, 0); - + } catch (error) { console.error('Error resending OTP:', error); showToast('error', 'An error occurred while sending OTP. Please try again.'); } finally { setLoading(false); - + // Re-enable resend after 60 seconds const timer = setTimeout(() => { setResendDisabled(false); }, 60000); - + // Cleanup timer on component unmount return () => clearTimeout(timer); } }; - + // Start countdown on component mount useEffect(() => { // Always use 10 minutes for the countdown const tenMinutesInMs = 10 * 60 * 1000; const expiryTime = Date.now() + tenMinutesInMs; - + const updateCountdown = () => { const now = Date.now(); const remainingSeconds = Math.max(0, Math.floor((expiryTime - now) / 1000)); - + setCountdown(remainingSeconds); - + if (remainingSeconds <= 0) { clearInterval(countdownRef.current); setResendDisabled(false); } }; - + // Initial update updateCountdown(); - + // Set up interval for countdown updates countdownRef.current = setInterval(updateCountdown, 1000); - + return () => { if (countdownRef.current) clearInterval(countdownRef.current); }; }, []); - + // Cleanup on unmount useEffect(() => { return () => { @@ -261,10 +261,10 @@ const OTPVerification = () => { if (countdownRef.current) clearInterval(countdownRef.current); }; }, []); - + const minutes = Math.floor(countdown / 60); const seconds = countdown % 60; - + return (
{/* Toast Notification */} @@ -297,7 +297,7 @@ const OTPVerification = () => {
)} - +
{/* Logo Section */} @@ -309,13 +309,13 @@ const OTPVerification = () => { IIP (Index of Industrial Production)
- +
{/*

Email OTP

Step 2 of 2

*/} - +
@@ -324,7 +324,7 @@ const OTPVerification = () => { We sent a 6-digit authentication code to {maskedEmail}

- + {/* OTP Inputs */}
@@ -341,8 +341,8 @@ const OTPVerification = () => { onKeyDown={(e) => handleKeyDown(e, index)} onPaste={handlePaste} className={`w-12 h-12 text-center text-xl bg-transparent border-2 rounded focus:outline-none focus:ring-0 ${ - error ? 'border-red-500' : - digit ? 'border-[#92722A]' : + error ? 'border-red-500' : + digit ? 'border-[#92722A]' : 'border-gray-300 hover:border-gray-400 focus:border-[#92722A] focus:border-b-2 focus:border-b-[#92722A]' }`} autoFocus={index === 0} @@ -350,14 +350,14 @@ const OTPVerification = () => { /> ))}
- + {error && (
{error}
)} - +
@@ -365,10 +365,10 @@ const OTPVerification = () => { Code expires in {minutes}:{seconds < 10 ? `0${seconds}` : seconds}
- Attempts: {attemptsRemaining}/3 + Attempts: {attemptsRemaining} of 3
-
- +
+
- +
- +

Having trouble?{' '} -

); }; - -export default OTPVerification; + +export default OTPVerification; \ No newline at end of file