Dealer_Onboard_Frontend/src/features/onboarding/pages/FDDApplicationDetails.tsx

669 lines
45 KiB
TypeScript

import { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { API } from '@/api/API';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { useSelector } from 'react-redux';
import { RootState } from '@/store';
import {
ArrowLeft,
FileText,
Upload,
Loader2,
Eye,
CheckCircle2,
Clock
} from 'lucide-react';
import { WorkNotesPage } from './WorkNotesPage';
import { toast } from 'sonner';
import { DocumentPreviewModal } from '@/components/ui/DocumentPreviewModal';
import { formatDateTime } from '@/components/ui/utils';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { AlertTriangle, Info, ShieldCheck } from 'lucide-react';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
export function FDDApplicationDetails() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const [application, setApplication] = useState<any>(null);
const [assignment, setAssignment] = useState<any>(null);
const [loading, setLoading] = useState(true);
const [uploading, setUploading] = useState(false);
const [selectedDocType, setSelectedDocType] = useState('');
const [activeTab, setActiveTab] = useState<'details' | 'worknotes'>('details');
const [isPreviewOpen, setIsPreviewOpen] = useState(false);
const [selectedPreviewDoc, setSelectedPreviewDoc] = useState<any>(null);
const [showFinalizeModal, setShowFinalizeModal] = useState(false);
const [showFlagModal, setShowFlagModal] = useState(false);
const [fddAuditFindings, setFddAuditFindings] = useState<string>('');
const user = useSelector((state: RootState) => state.auth.user);
const isFddRole = user?.role === 'FDD';
useEffect(() => {
if (id) fetchApplication();
}, [id]);
const fetchApplication = async () => {
setLoading(true);
try {
const [appRes, assRes]: any = await Promise.all([
API.getApplicationById(id!),
API.getFddAssignment(id!)
]);
if (appRes.data?.success) {
setApplication(appRes.data.data);
}
if (assRes.data?.success) {
setAssignment(assRes.data.data);
}
} catch (error) {
console.error('Error fetching application:', error);
const errorMsg = (error as any).response?.data?.message || 'Access Denied: Not authorized for FDD access';
toast.error(errorMsg);
navigate('/fdd-dashboard');
} finally {
setLoading(false);
}
};
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file || !selectedDocType) {
if (!selectedDocType) toast.error('Please select a document type first');
return;
}
setUploading(true);
const formData = new FormData();
formData.append('file', file);
formData.append('documentType', selectedDocType);
formData.append('stage', 'FDD');
formData.append('applicationId', id!);
formData.append('requestType', 'application');
try {
const response: any = await API.uploadDocument(id!, formData);
if (response.data?.success) {
// Automatically link if it's the final report category
if (selectedDocType === 'FDD Final Audit Report') {
const docId = response.data.data?.id || response.data.id;
await API.submitFddReport({
assignmentId: assignment?.id,
applicationId: id,
reportDocumentId: docId,
findings: 'Final Audit Report submitted.',
recommendation: 'REVIEW_PENDING'
});
}
toast.success(`${selectedDocType} uploaded successfully`);
fetchApplication();
setSelectedDocType('');
}
} catch (error) {
toast.error('Failed to upload document');
} finally {
setUploading(false);
}
};
const handlePreview = (doc: any) => {
if (!doc || !doc.filePath) {
toast.error('Document source file not found');
return;
}
setSelectedPreviewDoc({
fileName: doc.originalName || doc.fileName || 'Document',
filePath: doc.filePath,
documentType: doc.documentType,
createdAt: doc.createdAt,
mimeType: doc.mimeType
});
setIsPreviewOpen(true);
};
if (loading) {
return (
<div className="flex flex-col items-center justify-center h-[70vh] bg-slate-50/50 rounded-2xl border border-slate-200 border-dashed">
<Loader2 className="w-12 h-12 animate-spin text-blue-600 mb-4" />
<p className="text-slate-500 font-medium">Authenticating and loading secure data...</p>
</div>
);
}
if (!application) return null;
const isFDDStageActive = application.currentStage === 'FDD_VERIFICATION' || application.currentStage === 'FDD';
// Check if report is already submitted in assignment
const isReportSubmitted = assignment?.status === 'Report Submitted';
// Check if the application has already passed the FDD stage
const isCompleted = !isFDDStageActive && (application.overallStatus !== 'Active' || application.currentProgress >= 75) || isReportSubmitted;
// Check if the application has not yet arrived at the FDD stage
const isNotReachedYet = !isFDDStageActive && application.currentProgress < 70 && !isReportSubmitted;
return (
<div className="flex flex-col gap-6 max-w-7xl mx-auto mb-10">
{application?.statutoryStatus === 'Flagged' && (
<div className="bg-red-50 border border-red-200 p-4 rounded-xl flex items-center gap-4 animate-in fade-in slide-in-from-top-4 duration-500" data-testid="onboarding-fdd-details-flag-banner">
<div className="bg-red-100 p-2 rounded-lg">
<AlertTriangle className="w-5 h-5 text-red-600" />
</div>
<div>
<h4 className="text-sm font-bold text-red-900 leading-none">APPLICATION FLAGGED BY YOU</h4>
<p className="text-red-700 text-[10px] font-bold uppercase tracking-wider mt-1 opacity-80">Marked as non-responsive for follow-up by DD Team</p>
</div>
</div>
)}
{/* Action Bar */}
<div className="flex items-center justify-between">
<button
onClick={() => navigate('/fdd-dashboard')}
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 font-medium transition-all group"
data-testid="onboarding-fdd-details-back-btn"
>
<div className="p-2 rounded-full group-hover:bg-slate-100 transition-colors">
<ArrowLeft className="w-5 h-5" />
</div>
Back to Dashboard
</button>
<div className="flex items-center gap-3">
{isNotReachedYet ? (
<div className="flex items-center gap-2 px-4 py-2 bg-slate-100 border border-slate-200 text-slate-500 font-bold text-[10px] uppercase tracking-[0.1em] rounded-lg" data-testid="onboarding-fdd-details-awaiting-badge">
<Clock className="w-4 h-4" />
Awaiting Previous Stages
</div>
) : !isCompleted ? (
<>
{isFddRole && (
<button
disabled={uploading}
onClick={() => setShowFlagModal(true)}
className="px-4 py-2 bg-red-50 text-red-600 font-bold text-xs uppercase tracking-wider hover:bg-red-100 rounded-lg transition-all flex items-center gap-2 border border-red-100 shadow-sm"
data-testid="onboarding-fdd-details-flag-btn"
>
<AlertTriangle className="w-4 h-4" />
Flag Non-Responsive
</button>
)}
</>
) : (
<div className="flex items-center gap-2 px-4 py-2 bg-green-50 border border-green-200 text-green-700 font-bold text-[10px] uppercase tracking-[0.1em] rounded-lg shadow-inner" data-testid="onboarding-fdd-details-submitted-badge">
<CheckCircle2 className="w-4 h-4" />
Final Audit Report Submitted
</div>
)}
</div>
</div>
{/* Header Card */}
<Card className="border border-slate-200 shadow-sm bg-white" data-testid="onboarding-fdd-details-header">
<CardContent className="p-6">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6">
<div className="flex items-center gap-4">
<div className="w-14 h-14 bg-slate-900 text-white rounded-lg flex items-center justify-center font-bold text-xl" data-testid="onboarding-fdd-details-avatar">
{application.applicantName.charAt(0)}
</div>
<div>
<div className="flex items-center gap-2 mb-0.5">
<h1 className="text-2xl font-bold text-slate-900 tracking-tight" data-testid="onboarding-fdd-details-name">{application.applicantName}</h1>
<Badge variant="outline" className="text-slate-500 font-medium px-2 py-0" data-testid="onboarding-fdd-details-id-badge">
{application.applicationId}
</Badge>
</div>
<div className="flex items-center gap-3 text-sm text-slate-500" data-testid="onboarding-fdd-details-meta">
<span>{application.city}, {application.state}</span>
<span className="text-slate-300"></span>
<span>{application.businessType || 'Dealership'}</span>
</div>
</div>
</div>
<div className="flex items-center gap-3">
<div className="text-right hidden md:block">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Status</p>
<p className="text-sm font-bold text-slate-700">Financial Due Diligence</p>
</div>
</div>
</div>
</CardContent>
</Card>
{/* Navigation Tabs */}
<div className="flex items-center gap-8 border-b border-slate-200" data-testid="onboarding-fdd-details-tabs">
<button
onClick={() => setActiveTab('details')}
className={`pb-3 text-sm font-semibold transition-all relative ${
activeTab === 'details' ? 'text-blue-600' : 'text-slate-500 hover:text-slate-700'
}`}
data-testid="onboarding-fdd-details-tab-workspace"
>
Workspace
{activeTab === 'details' && <div className="absolute bottom-[-1px] left-0 right-0 h-0.5 bg-blue-600" />}
</button>
<button
onClick={() => setActiveTab('worknotes')}
className={`pb-3 text-sm font-semibold transition-all relative ${
activeTab === 'worknotes' ? 'text-blue-600' : 'text-slate-500 hover:text-slate-700'
}`}
data-testid="onboarding-fdd-details-tab-worknotes"
>
<div className="flex items-center gap-2">
Work Notes
</div>
{activeTab === 'worknotes' && <div className="absolute bottom-[-1px] left-0 right-0 h-0.5 bg-blue-600" />}
</button>
</div>
{activeTab === 'details' ? (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Left Column: Financial Data & Uploads */}
<div className="lg:col-span-2 space-y-6">
<Card className="border border-slate-200 shadow-sm bg-white" data-testid="onboarding-fdd-details-workspace-card">
<CardHeader className="border-b border-slate-100 px-6 py-4">
<CardTitle className="text-base font-bold flex items-center gap-2 text-slate-800">
<Upload className="w-4 h-4 text-slate-500" />
{isCompleted ? 'Finalized Financial Reports' : isNotReachedYet ? 'Audit Workspace' : 'Financial Report Submission'}
</CardTitle>
</CardHeader>
<CardContent className="p-6">
{isNotReachedYet && (
<div className="mb-6 p-8 bg-slate-50 border border-dashed border-slate-200 rounded-xl flex flex-col items-center justify-center text-center" data-testid="onboarding-fdd-details-not-active">
<div className="w-16 h-16 bg-white rounded-full flex items-center justify-center text-slate-300 mb-4 shadow-sm">
<Clock className="w-8 h-8" />
</div>
<h4 className="text-lg font-bold text-slate-900 mb-2">Stage Not Yet Active</h4>
<p className="text-sm text-slate-500 max-w-sm mb-6">This application is still being processed in previous documentation or interview stages. The FDD workspace will activate once the previous stages are approved.</p>
<div className="flex items-center gap-2 text-[10px] font-bold text-slate-400 uppercase tracking-widest px-4 py-1.5 bg-white rounded-full border border-slate-200">
Status: {application.status || 'Pending Review'}
</div>
</div>
)}
{isCompleted && (
<div className="mb-6 p-4 bg-green-50/50 border border-green-100 rounded-xl flex items-center gap-4" data-testid="onboarding-fdd-details-completed-alert">
<div className="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center text-green-600 shrink-0">
<CheckCircle2 className="w-5 h-5" />
</div>
<div>
<p className="text-sm font-bold text-green-800">Verification Stage Completed</p>
<p className="text-[11px] text-green-600 font-medium">The FDD report has been submitted and the case is now locked for further audits.</p>
</div>
</div>
)}
{!isCompleted && !isNotReachedYet && (
<div className="p-10 border-2 border-dashed border-slate-200 rounded-lg flex flex-col items-center justify-center text-center" data-testid="onboarding-fdd-details-upload-section">
<div className="w-12 h-12 bg-slate-50 text-slate-400 rounded-full flex items-center justify-center mb-4">
<FileText className="w-6 h-6" />
</div>
<p className="text-slate-600 font-medium mb-1" data-testid="onboarding-fdd-details-upload-title">
{isFddRole ? 'Select and upload the due diligence report' : 'View Authorized Documents'}
</p>
<p className="text-slate-400 text-xs mb-6" data-testid="onboarding-fdd-details-upload-hint">
{isFddRole ? 'PDF or JPG formats accepted (Max 10MB)' : 'You are in View-Only mode for this Audit'}
</p>
{isFddRole && (
<div className="w-full max-w-sm space-y-4">
<select
value={selectedDocType}
onChange={(e) => setSelectedDocType(e.target.value)}
className="w-full px-3 py-2 bg-slate-50 border border-slate-200 rounded text-sm font-medium text-slate-700 outline-none focus:ring-1 focus:ring-blue-500 transition-all"
data-testid="onboarding-fdd-details-doc-type-select"
>
<option value="">Select Document Category...</option>
<option value="FDD Final Audit Report">FDD Final Audit Report</option>
<option value="Bank Statement">Bank Statement</option>
<option value="Income Tax Returns (ITR)">Income Tax Returns (ITR)</option>
<option value="CIBIL Report">CIBIL Report</option>
<option value="Business Valuation Report">Business Valuation Report</option>
<option value="Property Documents">Property Documents</option>
</select>
<div className="relative">
{uploading ? (
<div className="w-full py-2.5 bg-slate-100 rounded flex items-center justify-center gap-2" data-testid="onboarding-fdd-details-uploading-state">
<Loader2 className="w-4 h-4 animate-spin text-slate-400" />
<span className="text-slate-500 text-xs font-bold uppercase tracking-wider">Uploading...</span>
</div>
) : (
<>
<input
type="file"
className="absolute inset-0 opacity-0 cursor-pointer"
onChange={handleFileUpload}
disabled={!selectedDocType}
data-testid="onboarding-fdd-details-file-input"
/>
<div className={`w-full py-2.5 text-center font-bold uppercase tracking-wider text-xs rounded transition-all ${
!selectedDocType ? 'bg-slate-100 text-slate-300' : 'bg-slate-900 text-white hover:bg-slate-800'
}`} data-testid="onboarding-fdd-details-browse-btn">
Browse & Upload
</div>
</>
)}
</div>
</div>
)}
</div>
)}
{/* List of Uploaded Documents */}
<div className="mt-8 border-t border-slate-100 pt-8" data-testid="onboarding-fdd-details-documents-section">
<h3 className="text-sm font-bold text-slate-800 mb-4 px-1">Submitted Documentation</h3>
<div className="space-y-6">
{/* SECTION 1: APPLICANT DOCUMENTS */}
<div data-testid="onboarding-fdd-details-applicant-docs">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-2 flex items-center gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-blue-500"></div>
Applicant's KYC & Financials
</p>
<div className="space-y-2">
{application.uploadedDocuments?.filter((d: any) => !d.uploader || d.uploader.roleCode !== 'FDD').map((doc: any, i: number) => (
<div key={i} className="p-3 border border-slate-100 rounded flex items-center justify-between hover:bg-slate-50 transition-all group" data-testid={`onboarding-fdd-details-applicant-doc-row-${i}`}>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded bg-slate-100 flex items-center justify-center text-slate-400 group-hover:bg-white transition-colors">
<FileText className="w-4 h-4" />
</div>
<div>
<div className="flex items-center gap-2">
<p className="text-xs font-bold text-slate-900" data-testid={`onboarding-fdd-details-applicant-doc-name-${i}`}>{doc.originalName || doc.fileName}</p>
<span className="text-[8px] bg-slate-100 text-slate-500 px-1 py-0.5 rounded uppercase font-bold tracking-tighter">APPLICANT</span>
</div>
<p className="text-[10px] text-slate-400 font-medium" data-testid={`onboarding-fdd-details-applicant-doc-meta-${i}`}>
{doc.documentType} • {formatDateTime(doc.createdAt)}
{doc.uploader?.fullName && ` • by ${doc.uploader.fullName}`}
</p>
</div>
</div>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => handlePreview(doc)}
className="p-1.5 hover:bg-white rounded text-slate-400 hover:text-blue-600 transition-all"
data-testid={`onboarding-fdd-details-applicant-doc-preview-${i}`}
>
<Eye className="w-4 h-4" />
</button>
</div>
</div>
))}
{application.uploadedDocuments?.filter((d: any) => !d.uploader || d.uploader.roleCode !== 'FDD').length === 0 && (
<p className="text-[10px] text-slate-400 italic px-1" data-testid="onboarding-fdd-details-applicant-docs-empty">No documents from applicant yet.</p>
)}
</div>
</div>
{/* SECTION 2: MY SUBMISSIONS */}
<div data-testid="onboarding-fdd-details-my-submissions">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-2 flex items-center gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-amber-500"></div>
My Uploaded Reports
</p>
<div className="space-y-2">
{application.uploadedDocuments?.filter((d: any) => d.uploader?.roleCode === 'FDD').map((doc: any, i: number) => (
<div key={i} className="p-3 border border-amber-100 bg-amber-50/30 rounded flex items-center justify-between hover:bg-amber-50 transition-all group" data-testid={`onboarding-fdd-details-my-report-row-${i}`}>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded bg-amber-100 flex items-center justify-center text-amber-500">
<FileText className="w-4 h-4" />
</div>
<div>
<div className="flex items-center gap-2">
<p className="text-xs font-bold text-slate-900" data-testid={`onboarding-fdd-details-my-report-name-${i}`}>{doc.originalName || doc.fileName}</p>
<span className="text-[8px] bg-amber-500 text-white px-1 py-0.5 rounded uppercase font-bold tracking-tighter">YOUR AUDIT REPORT</span>
</div>
<p className="text-[10px] text-slate-400 font-medium" data-testid={`onboarding-fdd-details-my-report-meta-${i}`}>
{doc.documentType} • {formatDateTime(doc.createdAt)}
{doc.uploader?.fullName && ` • by ${doc.uploader.fullName}`}
</p>
</div>
</div>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => handlePreview(doc)}
className="p-1.5 hover:bg-white rounded text-slate-400 hover:text-amber-600 transition-all"
data-testid={`onboarding-fdd-details-my-report-preview-${i}`}
>
<Eye className="w-4 h-4" />
</button>
</div>
</div>
))}
{application.uploadedDocuments?.filter((d: any) => d.uploader?.roleCode === 'FDD').length === 0 && (
<div className="text-center py-4 bg-slate-50 border border-dashed border-slate-200 rounded-lg" data-testid="onboarding-fdd-details-my-submissions-empty">
<p className="text-slate-400 text-[10px]">No audit reports uploaded yet.</p>
</div>
)}
</div>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
{/* Right Column: Applicant Meta & Guidelines */}
<div className="space-y-6">
<Card className="border border-slate-200 shadow-sm bg-white" data-testid="onboarding-fdd-details-profile-card">
<CardHeader className="border-b border-slate-100 px-6 py-4">
<CardTitle className="text-xs font-bold uppercase tracking-wider text-slate-500">Applicant Profile</CardTitle>
</CardHeader>
<CardContent className="p-6 space-y-4">
<div className="space-y-1 pb-4 border-b border-slate-50" data-testid="onboarding-fdd-details-target-loc">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Target Location</p>
<p className="text-sm font-extrabold text-slate-900">{application.city}, {application.state}</p>
</div>
<div className="grid grid-cols-2 gap-4 text-xs" data-testid="onboarding-fdd-details-profile-meta">
<div className="space-y-1">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Education</p>
<p className="font-bold text-slate-800">{application.education || 'N/A'}</p>
</div>
<div className="space-y-1">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Experience</p>
<p className="font-bold text-slate-800">{application.experienceYears || '0'} Years</p>
</div>
<div className="space-y-1">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Investment Cap</p>
<p className="font-bold text-slate-800">{application.investmentCapacity || 'N/A'}</p>
</div>
<div className="space-y-1">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Age</p>
<p className="font-bold text-slate-800">{application.age || 'N/A'}</p>
</div>
</div>
<div className="space-y-1 pt-4 border-t border-slate-50 text-xs" data-testid="onboarding-fdd-details-communication">
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Communication</p>
<p className="font-bold text-slate-800">{application.email}</p>
<p className="text-slate-500 font-medium">{application.phone}</p>
</div>
</CardContent>
</Card>
<div className="p-6 bg-slate-900 rounded-lg text-white font-medium" data-testid="onboarding-fdd-details-instructions">
<h4 className="text-sm font-bold mb-2">Instructions</h4>
<ul className="text-xs text-slate-300 space-y-2 list-disc pl-4">
<li>Bank statements must cover 12 months.</li>
<li>GST discrepancies must be noted.</li>
<li>Verify property papers with originals.</li>
</ul>
</div>
</div>
</div>
) : (
<div className="bg-white rounded-lg border border-slate-200 min-h-[600px] overflow-hidden">
<WorkNotesPage onBack={() => setActiveTab('details')} requestId={id} requestType="application" />
</div>
)}
<DocumentPreviewModal
isOpen={isPreviewOpen}
onClose={() => setIsPreviewOpen(false)}
document={selectedPreviewDoc}
/>
{/* Finalize Confirmation Modal */}
<Dialog open={showFinalizeModal} onOpenChange={setShowFinalizeModal}>
<DialogContent className="max-w-md p-0 overflow-hidden border-none shadow-2xl" data-testid="onboarding-fdd-details-finalize-modal">
<div className="bg-slate-950 p-6 flex items-center justify-center relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-br from-amber-600/20 to-transparent" />
<div className="w-16 h-16 bg-amber-600/20 rounded-full flex items-center justify-center animate-pulse relative z-10">
<ShieldCheck className="w-8 h-8 text-amber-500" />
</div>
</div>
<div className="p-8 space-y-4">
<DialogHeader>
<DialogTitle className="text-2xl font-bold text-slate-900 text-center" data-testid="onboarding-fdd-details-finalize-title">Submit Audit Report</DialogTitle>
<DialogDescription className="text-slate-500 text-center pt-2 leading-relaxed text-base" data-testid="onboarding-fdd-details-finalize-desc">
You are about to submit your final findings. This action will <span className="font-bold text-slate-800 underline decoration-amber-500 decoration-2">notify the Admin</span> for review and approval.
</DialogDescription>
</DialogHeader>
<div className="bg-amber-50 p-4 rounded-xl flex gap-3 border border-amber-100 italic" data-testid="onboarding-fdd-details-finalize-info">
<Info className="w-5 h-5 text-amber-600 shrink-0 mt-0.5" />
<p className="text-xs text-amber-800 leading-normal">
Once submitted, you cannot edit the findings. Ensure all documents are uploaded.
</p>
</div>
<div className="space-y-4 pt-2">
<div className="space-y-2">
<Label className="text-[10px] font-black uppercase tracking-widest text-slate-400">Detailed Audit Findings & Remarks</Label>
<Textarea
placeholder="Enter detailed financial observations..."
className="min-h-[120px] bg-slate-50 border-slate-200 rounded-xl focus:ring-amber-500 text-sm resize-none"
value={fddAuditFindings}
onChange={(e) => setFddAuditFindings(e.target.value)}
data-testid="onboarding-fdd-details-finalize-remarks"
/>
</div>
</div>
<DialogFooter className="flex flex-col sm:flex-row gap-3 pt-4 sm:pt-6">
<Button
variant="outline"
className="w-full sm:flex-1 h-12 rounded-xl font-bold text-slate-600 hover:bg-slate-50 border-slate-200"
onClick={() => setShowFinalizeModal(false)}
disabled={uploading}
data-testid="onboarding-fdd-details-finalize-cancel"
>
Cancel
</Button>
<Button
className="w-full sm:flex-1 h-12 rounded-xl font-bold bg-slate-950 hover:bg-slate-900 text-white shadow-lg shadow-slate-200 transition-all active:scale-95 border-b-2 border-amber-600"
data-testid="onboarding-fdd-details-finalize-confirm"
onClick={async () => {
try {
if (!fddAuditFindings.trim()) {
toast.error('Please provide findings.');
return;
}
setUploading(true);
const latestReport = assignment?.reports?.[0];
const res: any = await API.submitFddReport({
assignmentId: assignment?.id,
applicationId: id,
reportDocumentId: latestReport?.reportDocumentId,
findings: fddAuditFindings,
recommendation: null
});
if (res.data?.success) {
toast.success('FDD Report submitted successfully.');
setShowFinalizeModal(false);
fetchApplication();
}
} catch (e) {
toast.error('Failed to submit report');
} finally {
setUploading(false);
}
}}
disabled={uploading}
>
{uploading ? <Loader2 className="w-5 h-5 animate-spin" /> : 'Confirm & Submit'}
</Button>
</DialogFooter>
</div>
</DialogContent>
</Dialog>
{/* Flag Non-Responsive Confirmation Modal */}
<Dialog open={showFlagModal} onOpenChange={setShowFlagModal}>
<DialogContent className="max-w-md p-0 overflow-hidden border-none shadow-2xl" data-testid="onboarding-fdd-details-flag-modal">
<div className="bg-slate-950 p-6 flex items-center justify-center relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-br from-red-600/20 to-transparent" />
<div className="w-16 h-16 bg-red-600/20 rounded-full flex items-center justify-center relative z-10">
<AlertTriangle className="w-8 h-8 text-red-500" />
</div>
</div>
<div className="p-8 space-y-4">
<DialogHeader>
<DialogTitle className="text-2xl font-bold text-slate-900 text-center" data-testid="onboarding-fdd-details-flag-modal-title">Flag Applicant</DialogTitle>
<DialogDescription className="text-slate-500 text-center pt-2 leading-relaxed text-base" data-testid="onboarding-fdd-details-flag-modal-desc">
Are you sure you want to flag this applicant as <span className="font-bold text-red-600">Non-Responsive</span>?
</DialogDescription>
</DialogHeader>
<div className="bg-red-50 p-4 rounded-xl flex gap-3 border border-red-100 italic">
<p className="text-xs text-red-800 leading-normal text-center w-full" data-testid="onboarding-fdd-details-flag-modal-text">
"Applicant is non-responsive to FDD queries."
</p>
</div>
<DialogFooter className="flex flex-col sm:flex-row gap-3 pt-4 sm:pt-6">
<Button
variant="outline"
className="w-full sm:flex-1 h-12 rounded-xl font-bold text-slate-600 hover:bg-slate-50 border-slate-200"
onClick={() => setShowFlagModal(false)}
disabled={uploading}
data-testid="onboarding-fdd-details-flag-modal-cancel"
>
Go Back
</Button>
<Button
className="w-full sm:flex-1 h-12 rounded-xl font-bold bg-slate-950 hover:bg-slate-900 text-white shadow-lg shadow-slate-200 transition-all active:scale-95 border-b-2 border-red-600"
data-testid="onboarding-fdd-details-flag-modal-confirm"
onClick={async () => {
try {
setUploading(true);
// Use dedicated API that updates model AND creates a specific Audit Log entry
await API.flagNonResponsive({
applicationId: id,
remarks: 'Applicant is non-responsive to FDD queries.'
});
toast.error('Application flagged for non-responsiveness.');
setShowFlagModal(false);
fetchApplication();
} catch (e) {
toast.error('Action failed');
} finally {
setUploading(false);
}
}}
disabled={uploading}
>
{uploading ? <Loader2 className="w-5 h-5 animate-spin" /> : 'Flag Applicant'}
</Button>
</DialogFooter>
</div>
</DialogContent>
</Dialog>
</div>
);
}