UNPKG

deepvue-aadhaar-ekyc-digilocker-switch

Version:

A SDK powered by DeepVue.Tech for Aadhaar eKYC and DigiLocker authentication flows

1,383 lines (1,380 loc) 70.8 kB
import { useState, useEffect, useCallback } from 'react'; import { TextField, Button, Paper, Box, useTheme, Fade, Typography, CircularProgress, Stack, Chip, Divider, useMediaQuery, Stepper, Step, StepLabel, InputAdornment, IconButton, FormControlLabel, Checkbox, Alert, alpha as alpha$1 } from '@mui/material'; import { createSvgIcon } from '@mui/material/utils'; import { jsx, jsxs, Fragment } from 'react/jsx-runtime'; import axios from 'axios'; import { useFormik } from 'formik'; import { styled, alpha } from '@mui/material/styles'; // src/components/FlowSelector.tsx var AccountBox_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2m-7 3c1.93 0 3.5 1.57 3.5 3.5S13.93 13 12 13s-3.5-1.57-3.5-3.5S10.07 6 12 6m7 13H5v-.23c0-.62.28-1.2.76-1.58C7.47 15.82 9.64 15 12 15s4.53.82 6.24 2.19c.48.38.76.97.76 1.58z" }), "AccountBox"); var Cloud_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96" }), "Cloud"); var CloudQueue_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96M19 18H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h.71C7.37 7.69 9.48 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3s-1.34 3-3 3" }), "CloudQueue"); var client = axios.create({ baseURL: import.meta.env.VITE_API_URL || "https://production.deepvue.tech", headers: { "Content-Type": "application/json" } }); async function generateOtp(aadhaarNumber, apiKey, clientId, purpose) { const res = await client.post( "/v2/ekyc/aadhaar/generate-otp", null, { params: { aadhaar_number: aadhaarNumber, consent: "Y", purpose }, headers: { "x-api-key": apiKey, "client-id": clientId } } ); return res.data; } async function verifyOtp(referenceId, otp, apiKey, clientId, generate_pdf) { const res = await client.post( "/v2/ekyc/aadhaar/verify-otp", null, { params: { reference_id: referenceId, otp, consent: "Y", purpose: "For KYC", generate_pdf }, headers: { "x-api-key": apiKey, "client-id": clientId }, responseType: "json" } ); return res.data; } async function initiateDigiLockerSession(apiKey, clientId, redirectUrl) { const res = await client.post( "/v1/kyc/digilocker/initiate-session", { consent: "Y", purpose: "KYC", redirect_url: redirectUrl }, { headers: { "x-api-key": apiKey, "client-id": clientId } } ); return res.data; } async function getDigiLockerAccessToken(transactionId, code, apiKey, clientId) { const res = await client.post( "/v1/kyc/digilocker/access-token", { consent: "Y", purpose: "KYC", initial_deepvue_transaction_id: transactionId, digilocker_code: code }, { headers: { "x-api-key": apiKey, "client-id": clientId } } ); return res.data; } async function getEAadhaarData(transactionId, apiKey, clientId) { const res = await client.post( "/v1/kyc/digilocker/eaadhaar", { consent: "Y", purpose: "KYC", initial_deepvue_transaction_id: transactionId }, { headers: { "x-api-key": apiKey, "client-id": clientId } } ); return res.data; } async function initiateSession(apiKey, clientId) { const res = await client.get( "/v2/ekyc/aadhaar/sdk/initiate-session", { headers: { "x-api-key": apiKey, "client-id": clientId } } ); return res.data; } async function updateSessionStatus(sessionId, status, apiKey, clientId, aadhaar_reference_id) { const params = { session_id: sessionId, status }; if (aadhaar_reference_id) { params.aadhaar_reference_id = aadhaar_reference_id; } const res = await client.get( `/v2/ekyc/aadhaar/sdk/update-session`, { params, headers: { "x-api-key": apiKey, "client-id": clientId } } ); return res.data; } async function getSessionStatus(sessionId, apiKey, clientId) { const res = await client.get( `/v2/ekyc/aadhaar/sdk/session-status`, { params: { session_id: sessionId }, headers: { "x-api-key": apiKey, "client-id": clientId } } ); return res.data; } // src/assets/Logo.svg?base64 var Logo_default = 'data:image/svg+xml,<svg width="77" height="90" viewBox="0 0 77 90" fill="none" xmlns="http://www.w3.org/2000/svg">%0A<path d="M19.5312 12.0884L38.3566 0.972656V23.2307L19.5312 12.0884Z" fill="%23EA637D"/>%0A<path d="M0.679688 23.2302L19.5311 12.0879V34.3459L0.679688 23.2302Z" fill="%23E84278"/>%0A<path d="M0.679688 45.4885V23.2305L19.5311 34.3462L0.679688 45.4885Z" fill="%23EA637D"/>%0A<path d="M57.2029 12.0879V34.3459L38.3516 23.2302L57.2029 12.0879Z" fill="%23CE78C2"/>%0A<path d="M38.3516 0.972656L57.2029 12.0884L38.3516 23.2307V0.972656Z" fill="%23E84278"/>%0A<path d="M76.0623 23.2305V45.4885L57.2109 34.3462L76.0623 23.2305Z" fill="%23CE78C2"/>%0A<path d="M57.2109 12.0879L76.0623 23.2302L57.2109 34.3459V12.0879Z" fill="%236B2B80"/>%0A<path d="M76.0623 45.4863V67.7178L57.2109 56.602L76.0623 45.4863Z" fill="%23CE78C2"/>%0A<path d="M57.2109 56.6035L76.0623 67.7192L57.2109 78.8615V56.6035Z" fill="%236B2B80"/>%0A<path d="M38.3566 89.9787L19.5312 78.863L38.3566 67.7207V89.9787Z" fill="%23EA637D"/>%0A<path d="M38.3516 67.7207L57.4818 78.8239L38.3516 89.9787V67.7207Z" fill="%23E84278"/>%0A<path d="M0.679688 45.488L19.5311 34.3457V56.6037L0.679688 45.488Z" fill="%23FF83B0"/>%0A<path d="M0.679688 67.7178V45.4863L19.5311 56.602L0.679688 67.7178Z" fill="%23CE78C2"/>%0A<path d="M19.5311 78.8615L0.679688 67.7192L19.5311 56.6035V78.8615Z" fill="%236B2B80"/>%0A<path d="M38.3906 67.7996L57.4942 56.7461V78.8232L38.3906 67.7996Z" fill="%23CE78C2"/>%0A<path d="M76.1687 45.4177L57.6864 34.3984L57.5 56.7467L76.1687 45.4177Z" fill="%23FF83B0"/>%0A</svg>%0A'; var Logo = () => /* @__PURE__ */ jsx( Box, { component: "img", src: Logo_default, alt: "DeepVue Logo", sx: { height: 30, width: "auto", filter: "drop-shadow(0px 2px 4px rgba(0,0,0,0.1))", transition: "transform 0.2s ease", "&:hover": { transform: "scale(1.05)" } } } ); var FlowSelector = ({ apiKey, clientId, onSelectAadhaar, onAutoSelectDigiLocker, autoDetectCallback = true }) => { const theme = useTheme(); const sdkCallbackUrl = `${window.location.origin}/callback.html`; const [isRedirecting, setIsRedirecting] = useState(false); const [sessionId, setSessionId] = useState(null); useEffect(() => { const initializeSession = async () => { try { const existingSessionId = localStorage.getItem("deepvue_session_id"); if (existingSessionId) { try { const sessionStatus = await getSessionStatus( existingSessionId, apiKey, clientId ); if (sessionStatus.status === "aadhaar_otp_send_success" && sessionStatus.aadhaar_reference_id) { const nowMs = Date.now(); const expMs = sessionStatus.aadhaar_reference_id_exp; if (expMs && nowMs < expMs) { setSessionId(existingSessionId); return; } else { localStorage.removeItem("deepvue_session_id"); } } else if (sessionStatus.status === "aadhaar_otp_verification_success" || sessionStatus.status === "digilocker_success") { localStorage.removeItem("deepvue_session_id"); } } catch (statusError) { console.error("Failed to check session status:", statusError); localStorage.removeItem("deepvue_session_id"); } } const response = await initiateSession(apiKey, clientId); if (response?.session_id) { localStorage.setItem("deepvue_session_id", response.session_id); setSessionId(response.session_id); } else { console.error("No session_id in response:", response); } } catch (error) { console.error("Failed to initialize session:", error); if (error instanceof Error && error.message.includes("already in the required status")) { const existing = localStorage.getItem("deepvue_session_id"); if (existing) { setSessionId(existing); return; } } localStorage.removeItem("deepvue_session_id"); setSessionId(null); } }; initializeSession(); }, [apiKey, clientId]); useEffect(() => { if (!autoDetectCallback) return; const checkDigiLockerCallback = () => { const callbackReceived = sessionStorage.getItem( "digilocker_callback_received" ); const flowActive = sessionStorage.getItem("digilocker_flow_active"); if (callbackReceived === "true" && flowActive === "true") { onAutoSelectDigiLocker(); return; } const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get("code"); const state = urlParams.get("state"); if (code && state) { sessionStorage.setItem("digilocker_callback_code", code); sessionStorage.setItem("digilocker_callback_state", state); sessionStorage.setItem("digilocker_callback_received", "true"); sessionStorage.setItem("digilocker_flow_active", "true"); sessionStorage.setItem("digilocker_api_key", apiKey); sessionStorage.setItem("digilocker_client_id", clientId); window.history.replaceState( {}, document.title, window.location.pathname ); onAutoSelectDigiLocker(); return; } }; checkDigiLockerCallback(); }, [autoDetectCallback, onAutoSelectDigiLocker, apiKey, clientId]); const handleDigilocker = async () => { if (!sessionId) { const existing = localStorage.getItem("deepvue_session_id"); if (existing) { setSessionId(existing); setTimeout(() => handleDigilocker(), 100); return; } alert( "Session initialization failed. Please refresh the page and try again." ); return; } try { setIsRedirecting(true); await updateSessionStatus( sessionId, "method_digilocker_selected", apiKey, clientId ); sessionStorage.setItem("digilocker_flow_active", "true"); sessionStorage.setItem("digilocker_api_key", apiKey); sessionStorage.setItem("digilocker_client_id", clientId); const response = await initiateDigiLockerSession( apiKey, clientId, sdkCallbackUrl ); if (!response.data.authorization_url) { throw new Error("No authorization URL received from DigiLocker"); } const authUrl = new URL(response.data.authorization_url); setTimeout(() => { window.location.replace(authUrl.toString()); }, 3e3); } catch (error) { console.error("DigiLocker error:", error); alert("Failed to start DigiLocker session. Please try again."); setIsRedirecting(false); sessionStorage.removeItem("digilocker_flow_active"); sessionStorage.removeItem("digilocker_api_key"); sessionStorage.removeItem("digilocker_client_id"); } }; const handleAadhaar = async () => { if (!sessionId) { const existing = localStorage.getItem("deepvue_session_id"); if (existing) { setSessionId(existing); setTimeout(() => handleAadhaar(), 100); return; } alert( "Session initialization failed. Please refresh the page and try again." ); return; } try { const sessionStatus = await getSessionStatus(sessionId, apiKey, clientId); if (sessionStatus.status === "aadhaar_otp_send_success" && sessionStatus.aadhaar_reference_id) { const nowMs = Date.now(); const expMs = sessionStatus.aadhaar_reference_id_exp; if (expMs && nowMs < expMs) { onSelectAadhaar(); return; } else { localStorage.removeItem("deepvue_session_id"); const newSession = await initiateSession(apiKey, clientId); if (newSession?.session_id) { localStorage.setItem("deepvue_session_id", newSession.session_id); setSessionId(newSession.session_id); } } } await updateSessionStatus( sessionId, "method_aadhaar_selected", apiKey, clientId ); onSelectAadhaar(); } catch (error) { console.error("Failed to check/update session status:", error); try { const newSession = await initiateSession(apiKey, clientId); if (newSession?.session_id) { localStorage.setItem("deepvue_session_id", newSession.session_id); setSessionId(newSession.session_id); await updateSessionStatus( newSession.session_id, "method_aadhaar_selected", apiKey, clientId ); } } catch { } onSelectAadhaar(); } }; if (isRedirecting) { return /* @__PURE__ */ jsx( Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "100vh", backgroundColor: theme.palette.background.default }, children: /* @__PURE__ */ jsx(Fade, { in: true, timeout: 500, children: /* @__PURE__ */ jsxs( Paper, { elevation: 4, sx: { width: "100%", maxWidth: 450, p: theme.spacing(5), borderRadius: theme.spacing(2), backgroundColor: "#ffffff", textAlign: "center" }, children: [ /* @__PURE__ */ jsx( CloudQueue_default, { sx: { fontSize: 64, color: theme.palette.primary.main, mb: 2 } } ), /* @__PURE__ */ jsx(Typography, { variant: "h5", fontWeight: "bold", gutterBottom: true, children: "Connecting to DigiLocker" }), /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "text.secondary", sx: { mb: 4 }, children: "Please wait while we securely connect you to DigiLocker..." }), /* @__PURE__ */ jsx( CircularProgress, { size: 40, thickness: 4, sx: { color: theme.palette.primary.main } } ) ] } ) }) } ); } return /* @__PURE__ */ jsx( Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", p: { xs: 1.5, sm: 3 }, backgroundColor: theme.palette.grey[50] }, children: /* @__PURE__ */ jsxs( Paper, { elevation: 4, sx: { width: "100%", maxWidth: 420, p: { xs: theme.spacing(2), sm: theme.spacing(4) }, borderRadius: theme.spacing(2), backgroundColor: "#ffffff", textAlign: "center", boxShadow: "0 8px 24px rgba(0,0,0,0.08)" }, children: [ /* @__PURE__ */ jsx( Typography, { variant: "h6", fontWeight: "bold", gutterBottom: true, sx: { color: theme.palette.primary.main, mb: 0.5 }, children: "Choose Your Verification Method" } ), /* @__PURE__ */ jsx( Typography, { variant: "body2", color: "text.secondary", sx: { mb: 3, maxWidth: "420px", mx: "auto", lineHeight: 1.5 }, children: "Select your preferred secure eKYC method to verify your identity" } ), /* @__PURE__ */ jsxs(Stack, { spacing: 2, children: [ /* @__PURE__ */ jsxs( Box, { sx: { p: 2, borderRadius: theme.spacing(1.5), border: `1px solid ${theme.palette.primary.main}`, backgroundColor: theme.palette.primary.light + "08", transition: "all 0.2s ease", position: "relative", overflow: "visible", "&:hover": { backgroundColor: theme.palette.primary.light + "12", transform: "translateY(-2px)", boxShadow: "0 4px 12px rgba(0,0,0,0.05)" }, cursor: "pointer" }, children: [ /* @__PURE__ */ jsx( Chip, { label: "Recommended", size: "small", sx: { position: "absolute", top: 2, right: 2, background: theme.palette.success.light + "15", color: theme.palette.success.main, fontWeight: 500, fontSize: "0.7rem", height: "22px", boxShadow: "none", border: `1px solid ${theme.palette.success.light + "40"}`, backdropFilter: "blur(4px)", zIndex: 1, "& .MuiChip-label": { px: 1.2, py: 0.3 }, "& .MuiChip-icon": { color: theme.palette.success.light, marginLeft: "4px", marginRight: "-4px" }, "&:hover": { background: theme.palette.success.light + "25" } } } ), /* @__PURE__ */ jsx( Cloud_default, { sx: { fontSize: 32, color: theme.palette.info.main, mb: 1 } } ), /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", fontWeight: "600", gutterBottom: true, children: "DigiLocker" }), /* @__PURE__ */ jsx( Typography, { variant: "body2", color: "text.secondary", sx: { mb: 1.5, fontSize: "0.875rem" }, children: "Verify your identity using your Digilocker E-Aadhaar" } ), /* @__PURE__ */ jsx( Button, { fullWidth: true, variant: "contained", size: "medium", sx: { textTransform: "none", fontWeight: 600, py: 1, borderRadius: theme.spacing(1), fontSize: "0.875rem", "&:hover": { backgroundColor: theme.palette.primary.dark } }, onClick: handleDigilocker, children: "Continue with DigiLocker" } ) ] } ), /* @__PURE__ */ jsx( Typography, { variant: "caption", color: "text.secondary", sx: { position: "relative", display: "block", my: 1, "&::before, &::after": { content: '""', position: "absolute", top: "50%", width: "25%", height: "1px", backgroundColor: theme.palette.divider }, "&::before": { left: 0 }, "&::after": { right: 0 } }, children: "OR" } ), /* @__PURE__ */ jsxs( Box, { sx: { p: 2, borderRadius: theme.spacing(1.5), border: `1px solid ${theme.palette.grey[300]}`, backgroundColor: theme.palette.grey[50], transition: "all 0.2s ease", "&:hover": { backgroundColor: theme.palette.grey[100], transform: "translateY(-2px)", boxShadow: "0 4px 12px rgba(0,0,0,0.05)" }, cursor: "pointer" }, children: [ /* @__PURE__ */ jsx( AccountBox_default, { sx: { fontSize: 32, color: theme.palette.primary.main, mb: 1 } } ), /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", fontWeight: "600", gutterBottom: true, children: "Aadhaar eKYC" }), /* @__PURE__ */ jsx( Typography, { variant: "body2", color: "text.secondary", sx: { mb: 1.5, fontSize: "0.875rem" }, children: "Verify your identity using your Aadhaar number and OTP" } ), /* @__PURE__ */ jsx( Button, { fullWidth: true, variant: "outlined", size: "medium", sx: { textTransform: "none", fontWeight: 600, py: 1, borderRadius: theme.spacing(1), fontSize: "0.875rem", borderColor: theme.palette.info.main, color: theme.palette.info.main, "&:hover": { borderColor: theme.palette.info.dark, backgroundColor: theme.palette.info.light + "12" } }, onClick: handleAadhaar, children: "Continue with Aadhaar" } ) ] } ) ] }), /* @__PURE__ */ jsx(Divider, { sx: { my: 4, opacity: 0.6 } }), /* @__PURE__ */ jsxs( Box, { sx: { display: "flex", alignItems: "center", justifyContent: "center", gap: 1.5 }, children: [ /* @__PURE__ */ jsx( Typography, { variant: "caption", sx: { color: theme.palette.text.secondary, fontSize: "0.75rem", letterSpacing: "0.5px", fontWeight: 500 }, children: "Powered By" } ), /* @__PURE__ */ jsx(Logo, {}) ] } ) ] } ) } ); }; function useCountdown(seconds) { const [count, setCount] = useState(0); useEffect(() => { let timer; if (count > 0) { timer = setTimeout(() => setCount(count - 1), 1e3); } return () => clearTimeout(timer); }, [count]); const start = useCallback(() => setCount(seconds), [seconds]); return { count, start }; } // src/hooks/useAadhaarEkyc.ts function useAadhaarEkyc(apiKey, clientId, generate_pdf, purpose) { const [referenceId, setReferenceId] = useState(); const [data, setData] = useState(); const [loading, setLoading] = useState(false); const [error, setError] = useState(); const [hasActiveSession, setHasActiveSession] = useState(false); const { count, start } = useCountdown(30); useEffect(() => { const checkActiveSession = async () => { const sessionId = localStorage.getItem("deepvue_session_id"); if (!sessionId) return false; try { const sessionStatus = await getSessionStatus(sessionId, apiKey, clientId); if (sessionStatus.status === "aadhaar_otp_send_success" && sessionStatus.aadhaar_reference_id) { const currentTimeMs = Date.now(); const expirationTimeMs = sessionStatus.aadhaar_reference_id_exp; if (expirationTimeMs && currentTimeMs < expirationTimeMs) { setReferenceId(sessionStatus.aadhaar_reference_id); setHasActiveSession(true); start(); return true; } else { localStorage.removeItem("deepvue_session_id"); } } if (sessionStatus.status === "aadhaar_otp_verification_success" || sessionStatus.status === "digilocker_success") { localStorage.removeItem("deepvue_session_id"); } } catch (err) { console.error("Failed to check session status:", err); localStorage.removeItem("deepvue_session_id"); } return false; }; checkActiveSession(); }, [apiKey, clientId, start]); const requestOtp = async (aadhaarNumber) => { setLoading(true); setError(void 0); const sessionId = localStorage.getItem("deepvue_session_id"); try { const res = await generateOtp(aadhaarNumber, apiKey, clientId, purpose); setReferenceId(res.reference_id); if (sessionId) { await updateSessionStatus( sessionId, "aadhaar_otp_send_success", apiKey, clientId, res.reference_id ); } start(); return res; } catch (e) { if (sessionId) { try { await updateSessionStatus( sessionId, "aadhaar_otp_send_failure", apiKey, clientId ); } catch { } } setError(e.message); throw e; } finally { setLoading(false); } }; const confirmOtp = async (otp) => { if (!referenceId) { const msg = "No OTP session. Please resend."; setError(msg); return { code: 0, message: msg }; } setLoading(true); setError(void 0); try { const res = await verifyOtp( referenceId, otp, apiKey, clientId, generate_pdf ); if (res.code === 200 && res.data) { setData(res.data); } const sessionId = localStorage.getItem("deepvue_session_id"); if (sessionId) { if (res.code === 200) { await updateSessionStatus( sessionId, "aadhaar_otp_verification_success", apiKey, clientId ); setHasActiveSession(false); } else { await updateSessionStatus( sessionId, "aadhaar_otp_verification_failure", apiKey, clientId ); setError(res.message); } } return res; } catch (e) { const errorMessage = e.response?.data?.message || e.message; setError(errorMessage); const sessionId = localStorage.getItem("deepvue_session_id"); if (sessionId) { try { await updateSessionStatus( sessionId, "aadhaar_otp_verification_failure", apiKey, clientId ); } catch { } } return { code: 0, message: errorMessage }; } finally { setLoading(false); } }; const clearOtpSession = () => { setReferenceId(void 0); setHasActiveSession(false); }; return { requestOtp, confirmOtp, data, loading, error, count, hasActiveSession, clearOtpSession }; } var StyledTextField = styled(TextField)(({ theme }) => ({ width: "100%", "& .MuiOutlinedInput-root": { borderRadius: theme.spacing(1.5), transition: "all 0.2s ease-in-out", backgroundColor: alpha(theme.palette.background.paper, 0.8), "&:hover": { backgroundColor: alpha(theme.palette.background.paper, 0.9), transform: "translateY(-1px)", boxShadow: theme.shadows[2] }, "&.Mui-focused": { boxShadow: theme.shadows[3], backgroundColor: theme.palette.background.paper }, "& fieldset": { borderColor: alpha(theme.palette.primary.main, 0.2) }, "&:hover fieldset": { borderColor: theme.palette.primary.main } } })); var ResendButton = styled(Button)(({ theme }) => ({ borderRadius: theme.spacing(1.5), textTransform: "none", transition: "all 0.2s ease-in-out", "&:hover": { transform: "translateY(-1px)", boxShadow: theme.shadows[2] } })); var VerifyButton = styled(Button)(({ theme }) => ({ maxWidth: "220px", borderRadius: theme.spacing(1.5), textTransform: "none", transition: "all 0.2s ease-in-out", background: `linear-gradient(45deg, ${theme.palette.primary.main} 30%, ${theme.palette.primary.dark} 90%)`, "&:hover": { transform: "translateY(-1px)", boxShadow: theme.shadows[4] }, "&:disabled": { background: theme.palette.action.disabledBackground } })); var OtpForm = ({ onVerify, loading: verifyLoading, countdown, onResend, error }) => { const [otp, setOtp] = useState(""); const [resendLoading, setResendLoading] = useState(false); const handleResend = async () => { setResendLoading(true); try { await onResend(); } finally { setResendLoading(false); } }; const handleKeyPress = (e) => { if (e.key === "Enter") { e.preventDefault(); if (otp.length === 6 && !verifyLoading && !resendLoading) { onVerify(otp); } } }; return /* @__PURE__ */ jsx(Fade, { in: true, timeout: 500, children: /* @__PURE__ */ jsxs( Box, { component: "form", onSubmit: (e) => e.preventDefault(), sx: { display: "flex", flexDirection: "column", gap: 2, alignItems: "center", width: "100%", py: 1 }, children: [ /* @__PURE__ */ jsxs( Box, { sx: { display: "flex", flexDirection: { xs: "column", sm: "row" }, gap: 2, width: "100%", alignItems: "center" }, children: [ /* @__PURE__ */ jsx( StyledTextField, { placeholder: "Enter 6-digit OTP", value: otp, onChange: (e) => setOtp(e.target.value.replace(/\D/g, "").slice(0, 6)), onKeyDown: handleKeyPress, disabled: verifyLoading || resendLoading, slotProps: { input: { inputProps: { maxLength: 6, pattern: "[0-9]*", inputMode: "numeric" } } } } ), /* @__PURE__ */ jsx( ResendButton, { variant: "outlined", disabled: countdown !== 0 || resendLoading || verifyLoading, onClick: handleResend, sx: { width: { xs: "100%", sm: "120px" }, height: "40px", whiteSpace: "nowrap", flexShrink: 0 }, children: resendLoading ? "Sending..." : countdown > 0 ? `Resend (${countdown}s)` : "Resend OTP" } ) ] } ), /* @__PURE__ */ jsx( Box, { sx: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ jsx( VerifyButton, { variant: "contained", onClick: () => onVerify(otp), disabled: verifyLoading || resendLoading || !otp || otp.length !== 6, sx: { py: 1, px: 2, mt: 2, fontSize: "1.1rem", width: "100%", height: "48px" }, children: verifyLoading ? "Verifying..." : "Verify OTP" } ) } ), /* @__PURE__ */ jsx(Fade, { in: !!error, timeout: 300, children: /* @__PURE__ */ jsx(Box, { sx: { width: "100%" }, children: error && /* @__PURE__ */ jsx( Alert, { severity: "error", variant: "filled", sx: { borderRadius: 2, boxShadow: 2 }, children: error } ) }) }) ] } ) }); }; var OtpForm_default = OtpForm; var CheckCircle_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m-2 15-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8z" }), "CheckCircle"); var Fingerprint_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-.44.28M3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7s-.54.11-.7-.12c-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36.7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21m6.25 12.07c-.13 0-.26-.05-.35-.15-.87-.87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39s-4.66 1.97-4.66 4.39c0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71-.11.1-.24.15-.37.15m7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2.38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1.07.12-1.21.12M14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4-1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94s3.08 1.32 3.08 2.94c0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64-.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08-1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38" }), "Fingerprint"); var Message_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2m-2 12H6v-2h12zm0-3H6V9h12zm0-3H6V6h12z" }), "Message"); var ArrowBack_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20z" }), "ArrowBack"); var Visibility_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5M12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5m0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3" }), "Visibility"); var VisibilityOff_default = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7M2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2m4.31-.78 3.15 3.15.02-.16c0-1.66-1.34-3-3-3z" }), "VisibilityOff"); var StyledPaper = styled(Paper)(({ theme }) => ({ padding: theme.spacing(4), maxWidth: 450, margin: "2rem auto", borderRadius: theme.spacing(2), boxShadow: theme.shadows[4], [theme.breakpoints.down("sm")]: { padding: theme.spacing(1.5), margin: "1rem" } })); var StyledTextField2 = styled(TextField)(({ theme }) => ({ "& .MuiOutlinedInput-root": { borderRadius: theme.spacing(1), "&:hover fieldset": { borderColor: theme.palette.primary.main } } })); var ResultRow = styled(Box)(({ theme }) => ({ display: "flex", alignItems: "center", padding: theme.spacing(1.5, 0), "&:last-child": { borderBottom: "none" }, [theme.breakpoints.down("sm")]: { flexDirection: "column", alignItems: "flex-start", gap: theme.spacing(1) } })); var AadhaarFlow = ({ apiKey, clientId, generatePdf, redirectUrl, onBack, companyName, purpose }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down("sm")); const { requestOtp, confirmOtp, data, loading, error, count, hasActiveSession, clearOtpSession } = useAadhaarEkyc(apiKey, clientId, generatePdf, purpose); const [stage, setStage] = useState(hasActiveSession ? "otp" : "init"); const [redirectCount, setRedirectCount] = useState(5); const [apiError, setApiError] = useState(""); const [showAadhaar, setShowAadhaar] = useState(false); const [showSuccess, setShowSuccess] = useState(false); const [showError, setShowError] = useState(false); const [showInitError, setShowInitError] = useState(false); const [consentChecked, setConsentChecked] = useState(false); const cleanupSession = () => { if (stage === "result" || showSuccess) { localStorage.removeItem("deepvue_session_id"); } }; useEffect(() => { return () => { cleanupSession(); }; }, [stage, showSuccess]); useEffect(() => { if (hasActiveSession && stage !== "result" && !data) { setStage("otp"); setShowSuccess(true); const timer = setTimeout(() => { setShowSuccess(false); }, 5e3); return () => clearTimeout(timer); } }, [hasActiveSession, stage, data]); const handleBack = () => { if (stage === "init") { cleanupSession(); onBack(); } else { clearOtpSession(); setStage("init"); setShowSuccess(false); setShowError(false); setApiError(""); } }; const handleVerify = async (otp) => { try { const res = await confirmOtp(otp); if (res.code === 200) { setStage("result"); } else { setApiError(res.message || "Verification failed"); setShowError(true); setTimeout(() => { setShowError(false); setApiError(""); }, 5e3); } } catch (error2) { const errorMessage = error2.response?.data?.message || (error2.response?.data?.sub_code === "INVALID_OTP" ? "Invalid OTP" : "An error occurred while verifying OTP"); setApiError(errorMessage); setShowError(true); setTimeout(() => { setShowError(false); setApiError(""); }, 5e3); } }; useEffect(() => { if (data && stage === "result") { const timer = setInterval(() => { setRedirectCount((prev) => { if (prev <= 1) { clearInterval(timer); cleanupSession(); window.location.href = redirectUrl; return 0; } return prev - 1; }); }, 1e3); return () => { clearInterval(timer); cleanupSession(); }; } }, [data, stage, redirectUrl]); const formik = useFormik({ initialValues: { aadhaar: "", consent: false }, validate: (values) => { const errs = {}; if (!values.aadhaar) { errs.aadhaar = "Aadhaar number is required"; } else if (!/^\d{12}$/.test(values.aadhaar)) { errs.aadhaar = "Enter a valid 12-digit Aadhaar number"; } if (!values.consent) { errs.consent = "Please provide consent to proceed"; } return errs; }, onSubmit: async ({ aadhaar }) => { if (!consentChecked) return; try { setApiError(""); setShowInitError(false); await requestOtp(aadhaar); setStage("otp"); } catch (error2) { const errorMessage = error2.response?.data?.message || "An error occurred while requesting OTP"; setApiError(errorMessage); setShowInitError(true); setTimeout(() => setShowInitError(false), 5e3); } } }); const steps = ["Verify Aadhaar", "Verify OTP", "Fetch Details"]; const getActiveStep = () => { switch (stage) { case "init": return 0; case "otp": return 1; case "result": return 2; default: return 0; } }; const transformValue = (val) => { if (val == null) return ""; if (typeof val === "boolean") return val ? "Yes" : "No"; return val; }; const renderData = (obj) => { if (!obj || typeof obj !== "object") { return []; } const fieldsToShow = [ { key: "maskedNumber", label: "Aadhaar Number" }, { key: "name", label: "Name" }, { key: "dateOfBirth", label: "Date Of Birth" }, { key: "gender", label: "Gender" }, { key: "address", label: "Address" }, { key: "photo", label: "Photo" } ]; return fieldsToShow.flatMap(({ key, label }, idx) => { const value = obj[key]; if (key === "photo" && typeof value === "string") { return [ /* @__PURE__ */ jsxs(ResultRow, { children: [ /* @__PURE__ */ jsx( Typography, { variant: "subtitle2", sx: { width: "180px", fontWeight: 600 }, children: label } ), /* @__PURE__ */ jsx( Box, { component: "img", src: `data:image/jpeg;base64,${value}`, alt: "Aadhaar Photo", sx: { width: 100, height: "auto", borderRadius: 1 } } ) ] }, key), idx < fieldsToShow.length - 1 && /* @__PURE__ */ jsx(Divider, {}, `${key}-div`) ]; } if (key === "address" && value && typeof value === "object") { const address = value; const addressParts = [ address.house, address.street, address.locality, address.landmark, address.vtc, address.subDistrict, address.district, address.state, address.pin, address.country ].filter(Boolean).join(", "); return [ /* @__PURE__ */ jsxs(ResultRow, { children: [ /* @__PURE__ */ jsx( Typography, { variant: "subtitle2", sx: { width: "180px", fontWeight: 600 }, children: label } ), /* @__PURE__ */ jsx(Typography, { variant: "body2", children: addressParts }) ] }, key), idx < fieldsToShow.length - 1 && /* @__PURE__ */ jsx(Divider, {}, `${key}-div`) ]; } return [ /* @__PURE__ */ jsxs(ResultRow, { children: [ /* @__PURE__ */ jsx( Typography, { variant: "subtitle2", sx: { width: "180px", fontWeight: 600 }, children: label } ), /* @__PURE__ */ jsx(Typography, { variant: "body2", children: transformValue(value) }) ] }, key), idx < fieldsToShow.length - 1 && /* @__PURE__ */ jsx(Divider, {}, `${key}-div`) ]; }); }; const handleAadhaarChange = (e) => { const inputValue = e.target.value; if (!showAadhaar) { const inputLength = inputValue.length; const currentLength = formik.values.aadhaar.length; if (inputLength > currentLength) { const newChar = inputValue.slice(-1); if (/^\d$/.test(newChar)) { const newValue = formik.values.aadhaar + newChar; if (newValue.length <= 12) { formik.setFieldValue("aadhaar", newValue); } } } else if (inputLength < currentLength) { const newValue = formik.values.aadhaar.slice(0, inputLength); formik.setFieldValue("aadhaar", newValue); } } else { if (/^\d*$/.test(inputValue) && inputValue.length <= 12) { formik.setFieldValue("aadhaar", inputValue); } } }; const getDisplayValue = () => { if (showAadhaar) { return formik.values.aadhaar; } else { return formik.values.aadhaar.replace(/./g, "x"); } }; const toggleAadhaarVisibility = () => { setShowAadhaar(!showAadhaar); }; return /* @__PURE__ */ jsx(Fade, { in: true, timeout: 500, children: /* @__PURE__ */ jsxs(StyledPaper, { elevation: 4, children: [ /* @__PURE__ */ jsx( Stepper, { activeStep: getActiveStep(), alternativeLabel: true, sx: { mb: 4, display: { xs: "none", sm: "flex" } }, children: steps.map((label) => /* @__PURE__ */ jsx(Step, { children: /* @__PURE__ */ jsx(StepLabel, { children: label }) }, label)) } ), stage !== "result" ? /* @__PURE__ */ jsxs(Box, { children: [ /* @__PURE__ */ jsxs( Box, { sx: { display: "flex", flexDirection: "column", gap: 2, mb: 4 }, children: [ /* @__PURE__ */ jsxs( Box, { sx: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [ /* @__PURE__ */ jsx( Typography, { variant: "h5", fontWeight: 600, sx: { display: "flex", alignItems: "center", gap: 1 }, children: stage === "init" ? /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(Fingerprint_default, { color: "primary" }), "Verify Aadhaar" ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(Message_default, { color: "primary" }), "Verify OTP" ] }) } ), /* @__PURE__ */ jsx( Button, { variant: "outlined", onClick: handleBack, sx: { borderRadius: 2, lineHeight: "15px" }, startIcon: /* @__PURE__ */ jsx(ArrowBack_default, { sx: { width: "16px" } }), children: "Back" } ) ] } ), /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "text.secondary", children: stage === "init" ? "Enter your 12-digit aadhaar number to get an OTP on your aadhaar-linked mobile" : hasActiveSession ? "Resuming your verification. Enter the OTP sent to your aadhaar-linked mobile number" : "Enter the OTP sent to your aadhaar-linked mobile number" }) ] } ), /* @__PURE__ */ jsxs(Box, { component: "div", sx: { mt: 3 }, children: [ stage === "init" ? /* @__PURE__ */ jsxs(Box, { sx: { mb: 3 }, children: [ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", sx: { mb: 1 }, children: "Aadhaar Number" }), /* @__PURE__ */ jsx( StyledTextField2, { fullWidth: true, required: true, placeholder: "Enter Aadhaar Number", value: getDisplayValue(), onChange: handleAadhaarChange, helperText: formik.touched.aadhaar && formik.errors.aad