diff --git a/src/components/applications/ApplicationDetails.tsx b/src/components/applications/ApplicationDetails.tsx index e4a8ab0..618e09c 100644 --- a/src/components/applications/ApplicationDetails.tsx +++ b/src/components/applications/ApplicationDetails.tsx @@ -4,6 +4,7 @@ import { toast } from 'sonner'; import { mockWorkNotes, Application, ApplicationStatus } from '../../lib/mock-data'; import { onboardingService } from '../../services/onboarding.service'; import { auditService } from '../../services/audit.service'; +import { eorService } from '../../services/eor.service'; import QuestionnaireResponseView from './QuestionnaireResponseView'; import { useSelector } from 'react-redux'; import { RootState } from '../../store'; @@ -34,7 +35,8 @@ import { ChevronRight, GitBranch, Star, - Zap + Zap, + ShieldCheck } from 'lucide-react'; import { Progress } from '../ui/progress'; import { Textarea } from '../ui/textarea'; @@ -307,6 +309,7 @@ export function ApplicationDetails() { eorCompleteDate: getStageDate('EOR Complete'), inaugurationDate: getStageDate('Inauguration'), participants: data.participants || [], + dealerCode: data.dealerCode, }; setApplication(mappedApp); } catch (error) { @@ -321,6 +324,40 @@ export function ApplicationDetails() { fetchApplication(); } }, [applicationId]); + + const [eorData, setEorData] = useState(null); + + const fetchEorData = async () => { + if (!applicationId) return; + try { + const resp = await eorService.getChecklist(applicationId); + if (resp.success && resp.data) { + setEorData(resp.data); + } else { + // Auto-create if not found + await eorService.createChecklist(applicationId); + const retry = await eorService.getChecklist(applicationId); + if (retry.success) setEorData(retry.data); + } + } catch (err) { + console.log('EOR not found, attempting auto-create...'); + try { + await eorService.createChecklist(applicationId); + const retry = await eorService.getChecklist(applicationId); + if (retry.success) setEorData(retry.data); + } catch (createErr) { + console.error('Fetch/Create EOR error:', createErr); + } + } + }; + + useEffect(() => { + if (['EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application?.status || '')) { + fetchEorData(); + } + }, [applicationId, application?.status]); + + const eorProgress = eorData?.items ? (eorData.items.filter((item: any) => item.isCompliant).length / eorData.items.length) * 100 : 0; // Audit Trail State const [auditLogs, setAuditLogs] = useState([]); const [auditLoading, setAuditLoading] = useState(false); @@ -347,6 +384,7 @@ export function ApplicationDetails() { const [activeTab, setActiveTab] = useState('questionnaire'); const [showApproveModal, setShowApproveModal] = useState(false); const [showRejectModal, setShowRejectModal] = useState(false); + const [showWorkNoteModal, setShowWorkNoteModal] = useState(false); const [showScheduleModal, setShowScheduleModal] = useState(false); const [showKTMatrixModal, setShowKTMatrixModal] = useState(false); @@ -738,6 +776,9 @@ export function ApplicationDetails() { // Refresh documents const docs = await onboardingService.getDocuments(applicationId); setDocuments(docs || []); + + // Refresh EOR Data in case an EOR document was uploaded + fetchEorData(); } catch (error) { console.error('Upload failed', error); alert('Failed to upload document'); @@ -754,6 +795,10 @@ export function ApplicationDetails() { return
Application not found
; } + const isDocumentUploaded = (docType: string) => { + return (documents || []).some(d => d.documentType === docType); + }; + const processStages: ProcessStage[] = [ { id: 1, @@ -774,7 +819,7 @@ export function ApplicationDetails() { { id: 3, name: 'Shortlist', - status: ['Shortlisted', 'Level 1 Pending', 'Level 1 Approved', 'Level 2 Pending', 'Level 2 Approved', 'Level 2 Recommended', 'Level 3 Pending', 'Level 3 Interview Pending', 'Level 3 Approved', 'FDD Verification', 'Payment Pending', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : 'pending', + status: ['Shortlisted', 'Level 1 Interview Pending', 'Level 1 Approved', 'Level 2 Interview Pending', 'Level 2 Approved', 'Level 2 Recommended', 'Level 3 Interview Pending', 'Level 3 Approved', 'FDD Verification', 'LOI In Progress', 'Payment Pending', 'LOI Issued', 'Statutory LOI Ack', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : 'pending', date: '2025-10-04', description: 'Application shortlisted by DD', documentsUploaded: 2 @@ -782,7 +827,7 @@ export function ApplicationDetails() { { id: 4, name: '1st Level Interview', - status: ['Level 1 Approved', 'Level 2 Pending', 'Level 2 Approved', 'Level 2 Recommended', 'Level 3 Pending', 'Level 3 Interview Pending', 'Level 3 Approved', 'FDD Verification', 'Payment Pending', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Level 1 Pending' ? 'active' : 'pending', + status: ['Level 1 Approved', 'Level 2 Interview Pending', 'Level 2 Approved', 'Level 2 Recommended', 'Level 3 Interview Pending', 'Level 3 Approved', 'FDD Verification', 'LOI In Progress', 'Payment Pending', 'LOI Issued', 'Statutory LOI Ack', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Level 1 Interview Pending' ? 'active' : 'pending', date: application.level1InterviewDate, description: 'DD-ZM + RBM evaluation', evaluators: ['DD-ZM', 'RBM'], @@ -791,7 +836,7 @@ export function ApplicationDetails() { { id: 5, name: '2nd Level Interview', - status: ['Level 2 Approved', 'Level 2 Recommended', 'Level 3 Pending', 'Level 3 Interview Pending', 'Level 3 Approved', 'FDD Verification', 'Payment Pending', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : ['Level 2 Pending', 'Level 2 Interview Pending'].includes(application.status) ? 'active' : 'pending', + status: ['Level 2 Approved', 'Level 2 Recommended', 'Level 3 Interview Pending', 'Level 3 Approved', 'FDD Verification', 'LOI In Progress', 'Payment Pending', 'LOI Issued', 'Statutory LOI Ack', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : ['Level 2 Interview Pending'].includes(application.status) ? 'active' : 'pending', date: application.level2InterviewDate, description: 'DD Lead + ZBH evaluation', evaluators: ['DD Lead', 'ZBH'], @@ -800,7 +845,7 @@ export function ApplicationDetails() { { id: 6, name: '3rd Level Interview', - status: ['Level 3 Approved', 'FDD Verification', 'Payment Pending', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : ['Level 3 Pending', 'Level 3 Interview Pending'].includes(application.status) ? 'active' : 'pending', + status: ['Level 3 Approved', 'FDD Verification', 'LOI In Progress', 'Payment Pending', 'LOI Issued', 'Statutory LOI Ack', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : ['Level 3 Interview Pending'].includes(application.status) ? 'active' : 'pending', date: application.level3InterviewDate, description: 'NBH + DD-Head evaluation', evaluators: ['NBH', 'DD-Head'], @@ -809,7 +854,7 @@ export function ApplicationDetails() { { id: 7, name: 'FDD', - status: ['Payment Pending', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'FDD Verification' ? 'active' : 'pending', + status: ['LOI In Progress', 'Payment Pending', 'LOI Issued', 'Statutory LOI Ack', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'FDD Verification' ? 'active' : 'pending', date: application.fddDate, description: 'Financial Due Diligence', documentsUploaded: 5 @@ -817,7 +862,7 @@ export function ApplicationDetails() { { id: 8, name: 'LOI Approval', - status: ['Payment Pending', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : 'pending', + status: ['Payment Pending', 'LOI Issued', 'Statutory LOI Ack', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'LOI In Progress' ? 'active' : 'pending', date: application.loiApprovalDate, description: 'Letter of Intent approval', documentsUploaded: 1 @@ -833,7 +878,7 @@ export function ApplicationDetails() { { id: 10, name: 'LOI Issue', - status: ['Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Payment Pending' ? 'active' : 'pending', + status: ['Statutory LOI Ack', 'Dealer Code Generation', 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : ['Payment Pending', 'LOI Issued'].includes(application.status) ? 'active' : 'pending', date: application.loiIssueDate, description: 'Letter of Intent issued', documentsUploaded: 1 @@ -841,7 +886,7 @@ export function ApplicationDetails() { { id: 11, name: 'Dealer Code Generation', - status: ['Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'Statutory GST', 'Statutory PAN', 'Statutory Nodal', 'Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Dealer Code Generation' ? 'active' : 'pending', + status: (application.dealerCode || ['Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', 'Statutory GST', 'Statutory PAN', 'Statutory NODAL', 'Statutory NODAL', 'Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status)) ? 'completed' : application.status === 'Dealer Code Generation' ? 'active' : 'pending', date: application.dealerCodeDate, description: 'Dealer code generated and assigned', documentsUploaded: 0, @@ -854,7 +899,7 @@ export function ApplicationDetails() { { id: '11a-1', name: 'Assigned to Architecture Team', - status: ['Architecture Document Upload', 'Architecture Team Completion', 'Statutory GST', 'Statutory PAN', 'Statutory Nodal', 'Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Architecture Team Assigned' ? 'active' : 'pending', + status: application.architectureAssignedTo || ['Architecture Document Upload', 'Architecture Team Completion', 'Statutory GST', 'Statutory PAN', 'Statutory Nodal', 'Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) || application.architectureStatus === 'COMPLETED' || isDocumentUploaded('Architecture Assignment Document') ? 'completed' : application.status === 'Architecture Team Assigned' ? 'active' : 'pending', date: application.architectureAssignedDate, description: 'Assigned to architecture team for site planning', documentsUploaded: 0 @@ -862,18 +907,18 @@ export function ApplicationDetails() { { id: '11a-2', name: 'Architectural Document Upload', - status: ['Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Architecture Document Upload' ? 'active' : 'pending', + status: isDocumentUploaded('Architecture Blueprint') || isDocumentUploaded('Site Plan') || ['Architecture Team Completion', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) || application.architectureStatus === 'COMPLETED' ? 'completed' : (application.architectureAssignedTo || application.status === 'Architecture Document Upload' || application.architectureStatus === 'IN_PROGRESS') ? 'active' : 'pending', date: application.architectureDocumentDate, description: 'Architectural documents and blueprints uploaded', - documentsUploaded: 8 + documentsUploaded: (documents || []).filter(d => ['Architecture Blueprint', 'Site Plan'].includes(d.documentType)).length }, { id: '11a-3', name: 'Architecture Team Completion', - status: ['LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Architecture Team Completion' ? 'active' : 'pending', + status: ['LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) || application.architectureStatus === 'COMPLETED' || isDocumentUploaded('Architecture Completion Certificate') ? 'completed' : application.status === 'Architecture Team Completion' ? 'active' : 'pending', date: application.architectureCompletionDate, description: 'Architecture team work completed', - documentsUploaded: 4 + documentsUploaded: 0 } ] }, @@ -884,79 +929,79 @@ export function ApplicationDetails() { { id: '11b-1', name: 'GST', - status: ['Statutory PAN', 'Statutory Nodal', 'Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory GST' ? 'active' : 'pending', + status: isDocumentUploaded('GST Certificate') || ['Statutory PAN', 'Statutory Nodal', 'Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory GST' ? 'active' : 'pending', description: 'GST certificate', - documentsUploaded: 1 + documentsUploaded: (documents || []).filter(d => d.documentType === 'GST Certificate').length }, { id: '11b-2', name: 'PAN', - status: ['Statutory Nodal', 'Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory PAN' ? 'active' : 'pending', + status: isDocumentUploaded('PAN Card') || ['Statutory Nodal', 'Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory PAN' ? 'active' : 'pending', description: 'PAN card', - documentsUploaded: 1 + documentsUploaded: (documents || []).filter(d => d.documentType === 'PAN Card').length }, { id: '11b-3', name: 'Nodal Agreement', - status: ['Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Nodal' ? 'active' : 'pending', + status: isDocumentUploaded('Nodal Agreement') || ['Statutory Check', 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Nodal' ? 'active' : 'pending', description: 'Nodal agreement document', - documentsUploaded: 1 + documentsUploaded: (documents || []).filter(d => d.documentType === 'Nodal Agreement').length }, { id: '11b-4', name: 'Cancelled Check', - status: ['Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Check' ? 'active' : 'pending', + status: isDocumentUploaded('Cancelled Check') || ['Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Check' ? 'active' : 'pending', description: 'Cancelled check copy', - documentsUploaded: 1 + documentsUploaded: (documents || []).filter(d => d.documentType === 'Cancelled Check').length }, { id: '11b-5', name: 'Partnership Deed/LLP/MOA/AOA/COI', - status: ['Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Partnership' ? 'active' : 'pending', + status: isDocumentUploaded('Partnership Deed') || isDocumentUploaded('LLP Agreement') || isDocumentUploaded('Certificate of Incorporation') || isDocumentUploaded('MOA') || isDocumentUploaded('AOA') || ['Statutory Firm Reg', 'Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Partnership' ? 'active' : 'pending', description: 'Business entity documents', - documentsUploaded: 2 + documentsUploaded: (documents || []).filter(d => ['Partnership Deed', 'LLP Agreement', 'Certificate of Incorporation', 'MOA', 'AOA'].includes(d.documentType)).length }, { id: '11b-6', name: 'Firm Registration Certificate', - status: ['Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Firm Reg' ? 'active' : 'pending', + status: isDocumentUploaded('Firm Registration') || ['Statutory Rental', 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Firm Reg' ? 'active' : 'pending', description: 'Firm registration certificate', - documentsUploaded: 1 + documentsUploaded: (documents || []).filter(d => d.documentType === 'Firm Registration').length }, { id: '11b-7', name: 'Rental agreement/ Lease agreement / Own/ Land agreement', - status: ['Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Rental' ? 'active' : 'pending', + status: isDocumentUploaded('Rental Agreement') || isDocumentUploaded('Property Documents') || ['Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Rental' ? 'active' : 'pending', description: 'Property agreement document', - documentsUploaded: 1 + documentsUploaded: (documents || []).filter(d => ['Rental Agreement', 'Property Documents'].includes(d.documentType)).length }, { id: '11b-8', name: 'Virtual Code', - status: ['Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Virtual Code' ? 'active' : 'pending', + status: isDocumentUploaded('Virtual Code Confirmation') || ['Statutory Domain', 'Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Virtual Code' ? 'active' : 'pending', description: 'Virtual code availability', - documentsUploaded: 0 + documentsUploaded: (documents || []).filter(d => d.documentType === 'Virtual Code Confirmation').length }, { id: '11b-9', name: 'Domain ID', - status: ['Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Domain' ? 'active' : 'pending', + status: isDocumentUploaded('Domain ID Setup') || ['Statutory MSD', 'Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory Domain' ? 'active' : 'pending', description: 'Domain ID setup', - documentsUploaded: 0 + documentsUploaded: (documents || []).filter(d => d.documentType === 'Domain ID Setup').length }, { id: '11b-10', name: 'MSD Configuration', - status: ['Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory MSD' ? 'active' : 'pending', + status: isDocumentUploaded('MSD Configuration') || ['Statutory LOI Ack', 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory MSD' ? 'active' : 'pending', description: 'Microsoft Dynamics configuration', - documentsUploaded: 0 + documentsUploaded: (documents || []).filter(d => d.documentType === 'MSD Configuration').length }, { id: '11b-11', name: 'LOI Acknowledgement Copy', - status: ['LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory LOI Ack' ? 'active' : 'pending', + status: isDocumentUploaded('LOI Acknowledgement') || ['LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) ? 'completed' : application.status === 'Statutory LOI Ack' ? 'active' : 'pending', description: 'LOI acknowledgement copy', - documentsUploaded: 1 + documentsUploaded: (documents || []).filter(d => d.documentType === 'LOI Acknowledgement').length } ] } @@ -989,21 +1034,38 @@ export function ApplicationDetails() { ]; const eorChecklist = [ - { id: 1, item: 'Sales Standards', completed: true }, - { id: 2, item: 'Service & Spares', completed: true }, - { id: 3, item: 'DMS infra', completed: application.status === 'Approved' }, - { id: 4, item: 'Manpower Training', completed: application.status === 'Approved' }, + { id: 1, item: 'Sales Standards', completed: false }, + { id: 2, item: 'Service & Spares', completed: false }, + { id: 3, item: 'DMS infra', completed: false }, + { id: 4, item: 'Manpower Training', completed: false }, { id: 5, item: 'Trade certificate with test ride bikes registration', completed: false }, - { id: 6, item: 'GST certificate including Accessories & Apparels billing', completed: true }, + { id: 6, item: 'GST certificate including Accessories & Apparels billing', completed: false }, { id: 7, item: 'Inventory Funding', completed: false }, - { id: 8, item: 'Virtual code availability', completed: true }, + { id: 8, item: 'Virtual code availability', completed: false }, { id: 9, item: 'Vendor payments', completed: false }, - { id: 10, item: 'Details for website submission', completed: true }, + { id: 10, item: 'Details for website submission', completed: false }, { id: 11, item: 'Infra Insurance both Showroom and Service center', completed: false }, - { id: 12, item: 'Auto ordering', completed: application.status === 'Approved' } + { id: 12, item: 'Auto ordering', completed: false } ]; - const eorProgress = (eorChecklist.filter(item => item.completed).length / eorChecklist.length) * 100; + const flattenedStages: any[] = processStages.reduce((acc: any[], stage) => { + acc.push({ name: stage.name }); + if (stage.branches) { + stage.branches.forEach((branch: any) => { + branch.stages.forEach((subStage: any) => { + acc.push({ name: subStage.name, parentBranch: branch.name }); + }); + }); + } + if (stage.name === 'EOR In Progress' || stage.name === 'EOR Complete') { + (eorData?.items || eorChecklist).forEach((item: any) => { + acc.push({ name: `EOR: ${item.description || item.item}`, parentBranch: 'EOR' }); + }); + } + return acc; + }, []); + + @@ -1038,9 +1100,9 @@ export function ApplicationDetails() { // Fallback for document stage if it's a general approval if (!stageName) { - if (application.status === 'Shortlisted' || application.status === 'Level 1 Pending') stageName = '1st Level Interview'; - else if (application.status === 'Level 1 Approved' || application.status === 'Level 2 Pending') stageName = '2nd Level Interview'; - else if (application.status === 'Level 2 Approved' || application.status === 'Level 3 Pending') stageName = '3rd Level Interview'; + if (application.status === 'Shortlisted' || application.status === 'Level 1 Interview Pending') stageName = '1st Level Interview'; + else if (application.status === 'Level 1 Approved' || application.status === 'Level 2 Interview Pending') stageName = '2nd Level Interview'; + else if (application.status === 'Level 2 Approved' || application.status === 'Level 3 Interview Pending') stageName = '3rd Level Interview'; } if (stageName) { @@ -1085,11 +1147,58 @@ export function ApplicationDetails() { } try { - // Application level approval - const newStatus = application.status === 'Inauguration' ? 'Approved' : - application.status === 'EOR Complete' ? 'Inauguration' : - application.status === 'LOA Pending' ? 'EOR Complete' : - application.status === 'Statutory LOI Ack' ? 'LOA Pending' : 'Approved'; // Default fallback + // Application level approval - Robust State Machine + let newStatus = application.status; + + switch (application.status) { + case 'Shortlisted': + case 'Level 1 Interview Pending': + newStatus = 'Level 1 Approved'; break; + case 'Level 1 Approved': + case 'Level 2 Interview Pending': + newStatus = 'Level 2 Approved'; break; + case 'Level 2 Approved': + case 'Level 3 Interview Pending': + newStatus = 'Level 3 Approved'; break; + case 'Level 3 Approved': + newStatus = 'FDD Verification'; break; + case 'FDD Verification': + newStatus = 'LOI In Progress'; break; + case 'LOI In Progress': + newStatus = 'LOI Issued'; break; + case 'LOI Issued': + newStatus = 'Dealer Code Generation'; break; + case 'Dealer Code Generation': + newStatus = 'Architecture Team Assigned'; break; + case 'Architecture Team Assigned': + newStatus = 'Architecture Document Upload'; break; + case 'Architecture Document Upload': + newStatus = 'Architecture Team Completion'; break; + case 'Architecture Team Completion': + newStatus = 'Statutory GST'; break; + case 'Statutory GST': + case 'Statutory PAN': + case 'Statutory Nodal': + case 'Statutory Check': + case 'Statutory Partnership': + case 'Statutory Firm Reg': + case 'Statutory Rental': + case 'Statutory Virtual Code': + case 'Statutory Domain': + case 'Statutory MSD': + case 'Statutory LOI Ack': + newStatus = 'LOA Pending'; break; + case 'LOA Pending': + newStatus = 'EOR In Progress'; break; + case 'EOR In Progress': + newStatus = 'EOR Complete'; break; + case 'EOR Complete': + newStatus = 'Inauguration'; break; + case 'Inauguration': + newStatus = 'Approved'; break; + default: + newStatus = 'Approved'; // Final fallback + } await onboardingService.updateApplicationStatus(applicationId!, { status: newStatus, @@ -1281,7 +1390,23 @@ export function ApplicationDetails() { currentUserEvaluation?.decision === 'Selected'; // Maintain compatibility if needed // Final visibility flags - const shouldShowApproveReject = !hasMadeDecisionForUser && hasSubmittedFeedbackForActive; + const isAdmin = currentUser && ['DD Admin', 'Super Admin'].includes(currentUser.role); + const isAdministrativeStage = [ + 'Shortlisted', 'Level 3 Approved', 'FDD Verification', + 'LOI In Progress', 'LOI Issued', 'Statutory LOI Ack', + 'Architecture Team Assigned', 'Architecture Document Upload', 'Architecture Team Completion', + 'Statutory GST', 'Statutory PAN', 'Statutory Nodal', 'Statutory Check', + 'Statutory Partnership', 'Statutory Firm Reg', 'Statutory Rental', + 'Statutory Virtual Code', 'Statutory Domain', 'Statutory MSD', + 'LOA Pending', 'EOR Complete', 'Inauguration' + ].includes(application.status); + + // Show Approve/Reject if: + // 1. It's an interview and feedback is submitted + // 2. OR it's an administrative stage and user is Admin + const shouldShowApproveReject = + (!hasMadeDecisionForUser && hasSubmittedFeedbackForActive) || + (isAdmin && isAdministrativeStage); @@ -1547,7 +1672,7 @@ export function ApplicationDetails() { className="text-xs font-medium text-amber-700 hover:text-amber-800 flex items-center gap-1 bg-amber-50 px-2 py-0.5 rounded border border-amber-200" > - {stageDocsCount} Documents Uploaded + {stageDocsCount > 0 ? `${stageDocsCount} Documents Uploaded` : 'Upload Document'} ); @@ -1648,7 +1773,7 @@ export function ApplicationDetails() { className="text-xs font-medium text-blue-700 hover:text-blue-800 flex items-center gap-1 bg-blue-50 px-2 py-0.5 rounded border border-blue-200" > - {branchDocsCount} Documents Uploaded + {branchDocsCount > 0 ? `${branchDocsCount} Documents Uploaded` : 'Upload Document'} ); @@ -1874,7 +1999,7 @@ export function ApplicationDetails() { )} - {['Level 2 Approved', 'Level 3 Pending', 'Approved'].includes(application.status) && ( + {['Level 2 Approved', 'Level 3 Interview Pending', 'Approved'].includes(application.status) && (

Level 2 Interview Summary

@@ -1894,18 +2019,136 @@ export function ApplicationDetails() {
- {eorChecklist.map((item) => ( -
- - - {item.item} - - {item.completed && ( - - )} -
- ))} + {(eorData?.items || eorChecklist).map((item: any) => { + const docType = item.description || item.item; + const hasDocument = !!item.proofDocument; + + return ( +
+ + + {/* Clickable Info Area */} +
{ + setSelectedStage(`EOR: ${docType}`); + setUploadDocType(docType); + setShowDocumentsModal(true); + if (!hasDocument) setShowUploadForm(true); + else setShowUploadForm(false); + }} + > +
+ + {docType} + + {hasDocument && !item.isCompliant && ( + + Needs Verification + + )} +
+ {hasDocument && ( +
+ + {item.proofDocument.fileName} +
+ )} + {!hasDocument && ( + Click to upload proof + )} +
+ + {/* Separate Action Area (No modal trigger) */} +
+ {hasDocument && !item.isCompliant && isAdmin && ( +
+ + +
+ )} + + {(item.isCompliant || item.completed) && ( +
+ +
+ )} + + {!hasDocument && ( +
+ +
+ )} +
+
+ ); + })}
+ + {eorProgress === 100 && isAdmin && (application.status === 'EOR In Progress' || application.status === 'LOA Pending') && ( +
+
+
+ +
+
+

EOR Checklist Complete

+

All 12 mandatory requirements have been verified. You can now complete the audit and move to final inauguration.

+
+ +
+
+ )} {/* Payments Tab */} @@ -2091,22 +2334,26 @@ export function ApplicationDetails() { {currentUser && ['DD Admin', 'Super Admin'].includes(currentUser.role) && application.status === 'Dealer Code Generation' && ( <> - + {!application.dealerCode && ( + + )} - + {application.dealerCode && ( + + )} )} @@ -2161,6 +2408,27 @@ export function ApplicationDetails() { )} + {/* Dedicated Onboarding Button - Appears when logic is ready to onboard as a dealer */} + {isAdmin && ['Dealer Code Generation', 'Architecture Team Completion', 'LOA Pending', 'EOR Complete', 'Inauguration'].includes(application.status) && ( + + )} + {currentUser && ['DD Admin', 'Super Admin'].includes(currentUser.role) && ( @@ -3156,8 +3424,10 @@ export function ApplicationDetails() { General / No Stage - {processStages.map((s) => ( - {s.name} + {flattenedStages.map((s, idx) => ( + + {s.parentBranch ? `${s.parentBranch}: ${s.name}` : s.name} + ))} @@ -3171,11 +3441,35 @@ export function ApplicationDetails() { PAN Card GST Certificate - Aadhaar Card - Trade License + Aadhaar + Nodal Agreement + Cancelled Check + Partnership Deed + LLP Agreement + Certificate of Incorporation + MOA + AOA + Board Resolution + Firm Registration + Rental Agreement + Property Documents + Virtual Code Confirmation + Domain ID Setup + MSD Configuration + LOI Acknowledgement Copy + Architecture Assignment Document + Architecture Blueprint + Architecture Completion Certificate + Site Plan Bank Statement - Property Document + Inauguration Photos + Inauguration Report Other + {(eorData?.items || eorChecklist).map((item: any, idx: number) => ( + + {item.description || item.item} + + ))}
diff --git a/src/lib/mock-data.ts b/src/lib/mock-data.ts index 5f11357..0b154d2 100644 --- a/src/lib/mock-data.ts +++ b/src/lib/mock-data.ts @@ -24,14 +24,17 @@ export type ApplicationStatus = | 'Questionnaire Pending' | 'Questionnaire Completed' | 'Shortlisted' - | 'Level 1 Pending' + | 'In Review' + | 'Level 1 Interview Pending' | 'Level 1 Approved' - | 'Level 2 Pending' + | 'Level 2 Interview Pending' | 'Level 2 Approved' | 'Level 2 Recommended' - | 'Level 3 Pending' + | 'Level 3 Interview Pending' + | 'Level 3 Approved' | 'FDD Verification' | 'Payment Pending' + | 'LOI In Progress' | 'LOI Issued' | 'Dealer Code Generation' | 'Architecture Team Assigned' @@ -48,9 +51,9 @@ export type ApplicationStatus = | 'Statutory Domain' | 'Statutory MSD' | 'Statutory LOI Ack' + | 'LOA Pending' | 'EOR In Progress' | 'EOR Complete' - | 'LOA Pending' | 'Inauguration' | 'Approved' | 'Rejected' @@ -108,6 +111,7 @@ export interface Application { participants?: Participant[]; architectureAssignedTo?: string; architectureStatus?: string; + dealerCode?: any; } export interface Participant { @@ -248,7 +252,7 @@ export const mockApplications: Application[] = [ state: 'Maharashtra', ownsBike: true, pastExperience: '5 years in automobile sales, previously worked with Honda', - status: 'Level 1 Pending', + status: 'Level 1 Interview Pending', questionnaireMarks: 85, rank: 1, totalApplicantsAtLocation: 3, diff --git a/src/services/eor.service.ts b/src/services/eor.service.ts new file mode 100644 index 0000000..4f28f2e --- /dev/null +++ b/src/services/eor.service.ts @@ -0,0 +1,32 @@ +import client from '../api/client'; + +export const eorService = { + getChecklist: async (applicationId: string) => { + const response = await client.get(`/eor/${applicationId}`); + return response.data as any; + }, + + createChecklist: async (applicationId: string) => { + const response = await client.post('/eor', { applicationId }); + return response.data as any; + }, + + updateItem: async (checklistId: string, data: { + itemType: string; + description: string; + isCompliant: boolean; + remarks?: string; + proofDocumentId?: string; + }) => { + const response = await client.post(`/eor/item/${checklistId}`, data); + return response.data as any; + }, + + submitAudit: async (checklistId: string, data: { + status: string; + overallComments?: string; + }) => { + const response = await client.post(`/eor/audit/${checklistId}`, data); + return response.data as any; + } +};