import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { toast, ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import { useDocumentUpload } from '../features/documentUpload/hooks/useDocumentUpload'; import { useKycContext } from '../contexts/KycContext'; import { COMPLETED_STEPS } from '../services/kycApiService'; import type { DocumentType } from '../features/documentUpload/types'; interface DocumentUploadModalProps { onComplete?: (file: File, docType: string) => void; } function DocumentUploadModal({ onComplete }: DocumentUploadModalProps) { const navigate = useNavigate(); const { apiService } = useKycContext(); const [sessionError, setSessionError] = useState(null); const [kycCompleted, setKycCompleted] = useState(false); const { state, setState, fileInputRef, docVideoRef, handleDocumentUpload, handleConfirmDocumentUpload, handleManualCapture, startDocCamera, } = useDocumentUpload({ onDocumentUpload: async (blob: Blob, docType: string) => { if (!apiService) { throw new Error('API service not initialized'); } await apiService.uploadDocument(blob, docType); // Check if KYC is completed after document upload try { const statusResponse = await apiService.getSessionStatus(); const { completed_steps, next_step } = statusResponse.data; if (next_step === 'completed' || completed_steps.includes(COMPLETED_STEPS.COMPLETED)) { setKycCompleted(true); } } catch (error) { console.error('Error checking completion status:', error); } }, onUpload: (file, docType) => { if (onComplete) { onComplete(file, docType); } }, onScan: (file, docType) => { if (onComplete) { onComplete(file, docType); } }, onError: (err: any) => { // Normalize and display errors from upload/scan/camera using toastify let message: string | undefined; // Prefer API-style error structures if (err?.response?.data?.message) { message = String(err.response.data.message); } else if (err?.message) { message = String(err.message); } else { message = String(err || ''); } // Try to parse JSON-encoded error messages if present if (message && message.trim().startsWith('{')) { try { const parsed = JSON.parse(message); if (parsed && typeof parsed.message === 'string') { message = parsed.message; } } catch { // ignore JSON parse errors } } // For messages like: // "Invalid Document has been provided for Facial Recognition. The document is expired or invalid. Point Id: ..." // strip the internal "Point Id" technical detail if (message && message.includes('Point Id')) { message = message.split('Point Id')[0].trim(); // Ensure it ends with a period if (!/[.!?]$/.test(message)) { message = `${message}.`; } } const lower = (message || '').toLowerCase(); if (!message) { toast.error('Document error occurred. Please try again.'); return; } if (lower.includes('expired') && lower.includes('document')) { // Specific case for expired/invalid documents toast.error(message); } else if (lower.includes('expired')) { toast.error('Session expired. Please start a new KYC session.'); } else { toast.error(message); } }, }); // Check session status on mount useEffect(() => { const checkSession = async () => { if (!apiService) return; try { const statusResponse = await apiService.getSessionStatus(); const { completed_steps, next_step, status } = statusResponse.data; // Check if KYC is completed if (status === 'COMPLETED' || completed_steps.includes(COMPLETED_STEPS.COMPLETED)) { setKycCompleted(true); return; } // Check if session is active if (status !== 'ACTIVE') { throw new Error('Session expired or inactive'); } // If document_upload is already completed, show completion message if (completed_steps.includes(COMPLETED_STEPS.DOCS)) { // Check if all steps are completed if (completed_steps.includes(COMPLETED_STEPS.FACE) && completed_steps.includes(COMPLETED_STEPS.DOCS)) { setKycCompleted(true); return; } } // If next_step is not document_upload and face_scan is not completed, redirect to face scan if (next_step === COMPLETED_STEPS.FACE && !completed_steps.includes(COMPLETED_STEPS.FACE)) { // Should not happen if we're in document upload modal, but handle it console.warn('Face scan not completed, but in document upload modal'); } setSessionError(null); } catch (error: any) { const message = error.message || 'Session expired or inactive'; setSessionError(message); // Redirect to QR page after showing error setTimeout(() => { navigate('/qr', { replace: true }); }, 2000); } }; checkSession(); }, [apiService, navigate]); if (kycCompleted) { return (
✅

KYC Completed

All steps have been completed successfully.

Please return to your desktop to continue.

); } // Show session error if present if (sessionError) { return (

Session Expired

{sessionError}

Redirecting to QR code page...

); } return ( <>

Document

{!state.isDocScanMode && (
)}
{state.isDocScanMode && (

{state.loading ? "Processing document..." : "Position your document in the frame and tap 'Capture Document' when ready."}

)} {state.docFileName && !state.isDocScanMode && (
✔ File selected
)} {state.loading && !state.isDocScanMode && (

Processing...

)} {!state.isDocScanMode && state.docPreviewUrl && (
Preview
Document preview
)} {!state.isDocScanMode && !state.docFileName && !state.docPreviewUrl && (

After uploading or scanning, return to your desktop to check status.

)}
); } export default DocumentUploadModal;