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

647 lines
40 KiB
TypeScript

import { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { useSelector } from 'react-redux';
import { RootState } from '@/store';
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger
} from '@/components/ui/tabs';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import {
ArrowLeft,
ShieldCheck,
CheckCircle,
XCircle,
FileText,
User,
Clock,
Download,
Eye,
AlertCircle,
MessageSquare,
FileCheck,
RotateCcw,
History,
Send
} from 'lucide-react';
import { toast } from 'sonner';
import { onboardingService } from '@/services/onboarding.service';
import { worknoteService } from '@/services/worknote.service';
import { DocumentPreviewModal } from '@/components/ui/DocumentPreviewModal';
import { formatDateTime } from '@/components/ui/utils';
// Simple helper for class merging
const cn = (...classes: any[]) => classes.filter(Boolean).join(' ');
interface FinanceFddDetailPageProps {
applicationId: string;
onBack: () => void;
}
export function FinanceFddDetailPage({ applicationId, onBack }: FinanceFddDetailPageProps) {
const { user: currentUser } = useSelector((state: RootState) => state.auth);
const [application, setApplication] = useState<any>(null);
const [loading, setLoading] = useState(true);
const [isSubmitting, setIsSubmitting] = useState(false);
const [approvalRemark, setApprovalRemark] = useState('');
const [newNote, setNewNote] = useState('');
const [isNoteSubmitting, setIsNoteSubmitting] = useState(false);
const [showPreviewModal, setShowPreviewModal] = useState(false);
const [previewDoc, setPreviewDoc] = useState<any>(null);
useEffect(() => {
fetchData();
}, [applicationId]);
const fetchData = async () => {
try {
setLoading(true);
const appData = await onboardingService.getApplicationById(applicationId);
setApplication(appData);
} catch (error) {
console.error('Fetch error:', error);
toast.error('Failed to load application data');
} finally {
setLoading(false);
}
};
const handleDecision = async (decision: 'Approved' | 'Rejected') => {
if (!approvalRemark.trim()) {
toast.warning('Please enter a remark or justification');
return;
}
try {
setIsSubmitting(true);
// Map current status to next status for LOI stage
let nextStatus = 'LOI Issued'; // Default
if (application.status === 'LOI In Progress') {
nextStatus = 'LOI Issued';
}
const response = await onboardingService.submitStageDecision({
applicationId: application.id,
stageCode: 'LOI_APPROVAL',
decision,
remarks: approvalRemark,
nextStatus
});
if (response.data?.statusUpdated) {
toast.success(response.message || `Application ${decision.toLowerCase()} successfully`);
} else {
toast.info(response.message || 'Decision recorded. Waiting for other mandatory approvers.');
}
setApprovalRemark('');
await fetchData();
} catch (error) {
console.error('Decision error:', error);
toast.error('Failed to process decision');
} finally {
setIsSubmitting(false);
}
};
const handlePostNote = async () => {
if (!newNote.trim()) return;
try {
setIsNoteSubmitting(true);
await worknoteService.addWorknote({
requestId: application.id,
requestType: 'application',
noteText: newNote,
noteType: 'fdd_query'
});
setNewNote('');
toast.success('Work note posted successfully');
await fetchData();
} catch (error) {
console.error('Add note error:', error);
toast.error('Failed to post work note');
} finally {
setIsNoteSubmitting(false);
}
};
if (loading) {
return (
<div className="flex items-center justify-center p-20">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-amber-600"></div>
</div>
);
}
if (!application) {
return <div className="p-20 text-center">Application not found</div>;
}
const isFinance = currentUser?.role === 'Finance' || currentUser?.role === 'Finance Admin';
const isReadOnly = !isFinance;
const assignments = application.fddAssignments || [];
const workNotes = application.workNotes || [];
const hasMadeDecision = application.stageApprovals?.some(
(a: any) => a.stageCode === 'LOI_APPROVAL' && String(a.actorUserId) === String(currentUser?.id)
);
const MANDATORY_FINANCIAL_DOCS = [
{ type: 'Bank Statement', label: 'Bank Statements' },
{ type: 'Income Tax Returns (ITR)', label: 'ITR (Last 3 Years)' },
{ type: 'Credit Reports', label: 'CIBIL / Credit Reports' },
{ type: 'Property Documents', label: 'Property Documents' },
{ type: 'Business Valuation Report', label: 'Valuation Reports' }
];
const getDocByTypeName = (typeName: string) => {
return application.uploadedDocuments?.find((d: any) => d.documentType === typeName);
};
return (
<div className="space-y-6 max-w-7xl mx-auto">
{/* Header */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div className="flex items-center gap-4">
<Button variant="outline" size="icon" onClick={onBack} className="shrink-0 rounded-xl" data-testid="onboarding-finance-fdd-back-btn">
<ArrowLeft className="w-4 h-4" />
</Button>
<div>
<h1 className="text-2xl font-black text-slate-900 tracking-tight" data-testid="onboarding-finance-fdd-title">FDD Audit Detail</h1>
<p className="text-slate-500 text-sm font-medium">Review findings and provide finance sign-off for LOI stage</p>
</div>
</div>
<div className="flex items-center gap-2">
<Badge variant="outline" className="bg-slate-50 text-slate-600 border-slate-200 py-1.5 px-3 rounded-full text-[10px] font-black uppercase tracking-widest" data-testid="onboarding-finance-fdd-app-id">
APP ID: {application.applicationId || application.id}
</Badge>
<Badge className="bg-amber-100 text-amber-700 hover:bg-amber-100 py-1.5 px-3 rounded-full text-[10px] font-black uppercase tracking-widest border border-amber-200" data-testid="onboarding-finance-fdd-status">
{application.status}
</Badge>
</div>
</div>
<Tabs defaultValue="audit" className="w-full">
<TabsList className="bg-slate-100 p-1 rounded-xl mb-6">
<TabsTrigger value="audit" className="rounded-lg px-6 font-bold data-[state=active]:bg-white data-[state=active]:shadow-sm" data-testid="onboarding-finance-fdd-tab-audit">
Audit Review
</TabsTrigger>
<TabsTrigger value="worknotes" className="rounded-lg px-6 font-bold data-[state=active]:bg-white data-[state=active]:shadow-sm flex items-center gap-2" data-testid="onboarding-finance-fdd-tab-worknotes">
<MessageSquare className="w-4 h-4" /> Work Notes
{workNotes.length > 0 && <Badge className="ml-1 h-5 w-5 p-0 flex items-center justify-center bg-blue-600 rounded-full text-[10px] text-white font-black" data-testid="onboarding-finance-fdd-worknotes-count">{workNotes.length}</Badge>}
</TabsTrigger>
<TabsTrigger value="history" className="rounded-lg px-6 font-bold data-[state=active]:bg-white data-[state=active]:shadow-sm flex items-center gap-2" data-testid="onboarding-finance-fdd-tab-history">
<History className="w-4 h-4" /> Audit Trail
</TabsTrigger>
</TabsList>
<TabsContent value="audit">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Main Content Area */}
<div className="lg:col-span-2 space-y-8">
{/* Applicant Summary Card */}
<Card className="border-slate-200 shadow-sm overflow-hidden rounded-2xl" data-testid="onboarding-finance-fdd-summary-card">
<CardHeader className="bg-slate-50/50 border-b border-slate-100 py-4">
<CardTitle className="text-sm font-black uppercase tracking-widest text-slate-500 flex items-center gap-2">
<User className="w-4 h-4" /> Applicant Summary
</CardTitle>
</CardHeader>
<CardContent className="p-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-1">
<Label className="text-[10px] text-slate-400 uppercase font-black tracking-tighter">Business Name</Label>
<p className="text-slate-900 font-bold" data-testid="onboarding-finance-fdd-summary-name">{application.name || application.applicantName}</p>
</div>
<div className="space-y-1">
<Label className="text-[10px] text-slate-400 uppercase font-black tracking-tighter">Location</Label>
<p className="text-slate-900 font-bold" data-testid="onboarding-finance-fdd-summary-location">{application.city || application.preferredLocation}, {application.state}</p>
</div>
<div className="space-y-1">
<Label className="text-[10px] text-slate-400 uppercase font-black tracking-tighter">Contact Details</Label>
<div className="flex flex-col text-sm font-medium text-slate-600" data-testid="onboarding-finance-fdd-summary-contact">
<span>{application.email}</span>
<span>{application.phone}</span>
</div>
</div>
<div className="space-y-1">
<Label className="text-[10px] text-slate-400 uppercase font-black tracking-tighter">Constitution</Label>
<p className="text-slate-800 font-bold" data-testid="onboarding-finance-fdd-summary-constitution">{application.constitutionType || 'N/A'}</p>
</div>
</div>
</CardContent>
</Card>
{/* Financial Document Checklist Card */}
<Card className="border-slate-200 shadow-sm overflow-hidden rounded-2xl" data-testid="onboarding-finance-fdd-artefacts-card">
<CardHeader className="bg-slate-50/50 border-b border-slate-100 py-4">
<CardTitle className="text-sm font-black uppercase tracking-widest text-slate-500 flex items-center justify-between">
<div className="flex items-center gap-2"><FileCheck className="w-4 h-4" /> Financial Artefacts Checklist</div>
<Badge variant="outline" className="text-[10px] bg-white">Mandatory for FDD Sign-off</Badge>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<div className="divide-y divide-slate-100">
{MANDATORY_FINANCIAL_DOCS.map((docType) => {
const doc = getDocByTypeName(docType.type);
return (
<div key={docType.type} className="flex items-center justify-between p-4 px-6 hover:bg-slate-50/50 transition-colors" data-testid={`onboarding-finance-fdd-artefact-row-${docType.type}`}>
<div className="flex items-center gap-4">
<div className={cn(
"w-8 h-8 rounded-lg flex items-center justify-center",
doc ? "bg-emerald-50 text-emerald-600" : "bg-slate-50 text-slate-300"
)} data-testid={`onboarding-finance-fdd-artefact-status-${docType.type}`}>
{doc ? <CheckCircle className="w-5 h-5" /> : <AlertCircle className="w-5 h-5" />}
</div>
<div>
<p className="text-sm font-bold text-slate-800" data-testid={`onboarding-finance-fdd-artefact-label-${docType.type}`}>{docType.label}</p>
<p className="text-[10px] text-slate-400 font-bold uppercase tracking-tighter" data-testid={`onboarding-finance-fdd-artefact-date-${docType.type}`}>
{doc ? `Uploaded: ${formatDateTime(doc.createdAt)}` : 'Missing in Documentation'}
</p>
</div>
</div>
{doc && (
<div className="flex gap-2">
<Button variant="ghost" size="sm" className="h-8 text-blue-600 font-black text-[10px] uppercase tracking-widest"
onClick={() => {
setPreviewDoc(doc);
setShowPreviewModal(true);
}}
data-testid={`onboarding-finance-fdd-artefact-preview-${docType.type}`}
>
Preview
</Button>
</div>
)}
</div>
);
})}
</div>
</CardContent>
</Card>
{/* Audit Reports Section */}
<div className="space-y-4" data-testid="onboarding-finance-fdd-reports-section">
<div className="flex items-center justify-between px-1">
<h3 className="text-lg font-black text-slate-900 flex items-center gap-2">
<ShieldCheck className="w-5 h-5 text-amber-600" /> Audit Findings & Reports
</h3>
<Badge variant="outline" className="bg-white text-slate-500 font-bold border-slate-200" data-testid="onboarding-finance-fdd-reports-count-badge">
{assignments.length} Reports Found
</Badge>
</div>
{assignments.length === 0 ? (
<div className="bg-slate-50 rounded-2xl border-2 border-dashed border-slate-200 p-12 text-center" data-testid="onboarding-finance-fdd-no-reports">
<AlertCircle className="w-12 h-12 text-slate-300 mx-auto mb-4" />
<h4 className="text-slate-900 font-bold">No Audit Reports Available</h4>
<p className="text-slate-500 text-sm max-w-sm mx-auto mt-2 italic">The FDD team has not yet uploaded the audit reports for this application.</p>
</div>
) : (
<div className="space-y-6">
{assignments.map((assignment: any, idx: number) => (
<Card key={assignment.id} className="border-slate-200 shadow-sm overflow-hidden rounded-2xl group hover:border-amber-400 transition-all duration-300" data-testid={`onboarding-finance-fdd-assignment-card-${idx}`}>
<div className="bg-white p-6 border-b border-slate-50">
<div className="flex items-center justify-between mb-6">
<div className="flex items-center gap-3">
<div className="w-12 h-12 bg-amber-50 rounded-2xl flex items-center justify-center border border-amber-100 shadow-inner group-hover:scale-105 transition-transform">
<ShieldCheck className="w-6 h-6 text-amber-600" />
</div>
<div>
<h4 className="text-slate-900 font-black text-lg leading-none">FDD Audit Assignment</h4>
<p className="text-[10px] text-slate-400 uppercase font-bold tracking-widest mt-1">Status: {assignment.status}</p>
</div>
</div>
<Badge className={cn(
"py-1 px-3 rounded-full text-[10px] font-black uppercase tracking-widest",
assignment.status === 'completed' ? "bg-green-100 text-green-700" : "bg-amber-100 text-amber-700"
)} data-testid={`onboarding-finance-fdd-assignment-status-${idx}`}>
{assignment.status}
</Badge>
</div>
{!assignment.reports || assignment.reports.length === 0 ? (
<div className="py-8 text-center bg-slate-50 rounded-xl border border-slate-100" data-testid={`onboarding-finance-fdd-assignment-empty-${idx}`}>
<Clock className="w-6 h-6 text-slate-300 mx-auto mb-2" />
<p className="text-slate-500 text-xs italic">Waiting for agency report submission...</p>
</div>
) : (
<div className="space-y-8" data-testid={`onboarding-finance-fdd-reports-list-${idx}`}>
{assignment.reports.map((report: any, reportIdx: number) => (
<div key={report.id} className="grid grid-cols-1 md:grid-cols-2 gap-8 pt-2" data-testid={`onboarding-finance-fdd-report-row-${idx}-${reportIdx}`}>
<div className="space-y-5">
<div>
<Label className="text-[10px] text-slate-400 uppercase tracking-widest font-black mb-2 block">Auditor Recommendation</Label>
<div className={cn(
"inline-flex items-center gap-2 px-4 py-2 rounded-xl border text-xs font-black shadow-sm",
report.recommendation === 'Green' ? "bg-green-50 border-green-200 text-green-700" :
report.recommendation === 'Amber' ? "bg-amber-50 border-amber-200 text-amber-700" :
"bg-red-50 border-red-200 text-red-700"
)} data-testid={`onboarding-finance-fdd-report-signal-${idx}-${reportIdx}`}>
<div className={cn("w-2.5 h-2.5 rounded-full animate-pulse",
report.recommendation === 'Green' ? "bg-green-500" :
report.recommendation === 'Amber' ? "bg-amber-500" : "bg-red-500"
)} />
{report.recommendation?.toUpperCase()} SIGNAL
</div>
</div>
<div className="bg-slate-50/50 p-5 rounded-2xl border border-slate-100 relative">
<Label className="text-[10px] text-slate-400 uppercase tracking-widest font-black mb-3 block">Findings Summary</Label>
<p className="text-slate-700 text-sm leading-relaxed italic font-medium" data-testid={`onboarding-finance-fdd-report-findings-${idx}-${reportIdx}`}>
"{report.findings || 'No detail findings provided.'}"
</p>
</div>
</div>
<div className="space-y-5">
<Label className="text-[10px] text-slate-400 uppercase tracking-widest font-black mb-2 block">Available Documents</Label>
{report.reportDocument ? (
<div className="bg-white border-2 border-slate-100 rounded-2xl p-4 flex items-center justify-between hover:border-amber-400 transition-all hover:shadow-lg cursor-default" data-testid={`onboarding-finance-fdd-report-doc-${idx}-${reportIdx}`}>
<div className="flex items-center gap-4">
<div className="w-12 h-12 rounded-xl bg-red-50 flex items-center justify-center shadow-sm">
<FileText className="w-6 h-6 text-red-500" />
</div>
<div className="overflow-hidden">
<p className="text-slate-900 font-black text-sm truncate max-w-[140px] uppercase" data-testid={`onboarding-finance-fdd-report-filename-${idx}-${reportIdx}`}>{report.reportDocument.fileName}</p>
<p className="text-slate-500 text-[10px] font-bold">SUBMITTED {formatDateTime(report.createdAt)}</p>
</div>
</div>
<div className="flex gap-1">
<Button
variant="ghost"
size="icon"
className="h-10 w-10 text-slate-400 hover:text-amber-600 hover:bg-amber-50 rounded-xl"
onClick={() => window.open(`http://localhost:5000/${report.reportDocument.filePath}`, '_blank')}
data-testid={`onboarding-finance-fdd-report-download-${idx}-${reportIdx}`}
>
<Download className="w-5 h-5" />
</Button>
<Button
variant="ghost"
size="icon"
className="h-10 w-10 text-slate-400 hover:text-amber-600 hover:bg-amber-50 rounded-xl"
onClick={() => {
setPreviewDoc(report.reportDocument);
setShowPreviewModal(true);
}}
data-testid={`onboarding-finance-fdd-report-preview-${idx}-${reportIdx}`}
>
<Eye className="w-5 h-5" />
</Button>
</div>
</div>
) : (
<div className="p-6 bg-slate-50 rounded-2xl border border-dashed border-slate-200 text-center text-slate-400 text-xs font-bold uppercase tracking-tighter" data-testid={`onboarding-finance-fdd-report-doc-empty-${idx}-${reportIdx}`}>
No report file attached
</div>
)}
<div className="pt-4 flex items-center gap-3">
{report.verifiedAt ? (
<div className="flex items-center gap-2 bg-green-50 border border-green-100 px-4 py-2 rounded-full shadow-sm" data-testid={`onboarding-finance-fdd-report-verified-${idx}-${reportIdx}`}>
<CheckCircle className="w-4 h-4 text-green-600" />
<span className="text-[10px] font-black text-green-700 uppercase tracking-widest">Audited & Verified</span>
</div>
) : (
<div className="flex items-center gap-2 bg-amber-50 border border-amber-100 px-4 py-2 rounded-full shadow-sm" data-testid={`onboarding-finance-fdd-report-pending-${idx}-${reportIdx}`}>
<Clock className="w-4 h-4 text-amber-600" />
<span className="text-[10px] font-black text-amber-700 uppercase tracking-widest">Pending Verification</span>
</div>
)}
</div>
</div>
</div>
))}
</div>
)}
</div>
</Card>
))}
</div>
)}
</div>
</div>
{/* Action Sidebar */}
<div className="space-y-6">
<Card className="border-slate-200 shadow-sm overflow-hidden rounded-2xl sticky top-6" data-testid="onboarding-finance-fdd-action-sidebar">
<CardHeader className="bg-slate-900 border-b border-slate-800 py-5">
<CardTitle className="text-white text-sm font-black uppercase tracking-widest flex items-center gap-2">
<CheckCircle className="w-4 h-4 text-amber-400" /> Finance Action
</CardTitle>
</CardHeader>
<CardContent className="p-6 space-y-6">
<div>
<Label htmlFor="remarks" className="text-[10px] text-slate-400 font-black uppercase tracking-widest mb-2 block">Approval Remarks / Notes</Label>
<Textarea
id="remarks"
placeholder="Enter your assessment or audit sign-off remarks here..."
className="min-h-[150px] bg-slate-50 border-slate-200 rounded-xl focus:ring-amber-500 focus:border-amber-500 text-sm font-medium"
value={approvalRemark}
onChange={(e) => setApprovalRemark(e.target.value)}
disabled={hasMadeDecision || isSubmitting}
data-testid="onboarding-finance-fdd-remarks-input"
/>
</div>
{!hasMadeDecision ? (
!isReadOnly ? (
<div className="space-y-3 pt-2">
<Button
className="w-full h-14 bg-amber-600 hover:bg-amber-700 text-white font-black uppercase tracking-widest rounded-xl shadow-lg shadow-amber-200/50 transition-all active:scale-95"
onClick={() => handleDecision('Approved')}
disabled={isSubmitting}
data-testid="onboarding-finance-fdd-approve-btn"
>
{isSubmitting ? (
<span className="flex items-center gap-2">
<Clock className="w-4 h-4 animate-spin" /> Processing...
</span>
) : (
<><CheckCircle className="w-5 h-5 mr-2" /> Approve Audit</>
)}
</Button>
<Button
variant="outline"
className="w-full h-12 text-amber-600 border-amber-200 hover:bg-amber-50 font-black uppercase tracking-widest rounded-xl"
onClick={() => toast.info('Clarification request functionality coming soon')}
disabled={isSubmitting}
data-testid="onboarding-finance-fdd-revision-btn"
>
<RotateCcw className="w-5 h-5 mr-2" /> Request Revision
</Button>
<Button
variant="ghost"
className="w-full h-12 text-red-600 hover:text-red-700 hover:bg-red-50 font-black uppercase tracking-widest rounded-xl"
onClick={() => handleDecision('Rejected')}
disabled={isSubmitting}
data-testid="onboarding-finance-fdd-reject-btn"
>
<XCircle className="w-5 h-5 mr-2" /> Disqualify Candidate
</Button>
</div>
) : (
<div className="p-6 bg-slate-50 border border-slate-200 rounded-2xl text-center space-y-2" data-testid="onboarding-finance-fdd-readonly-alert">
<Eye className="w-8 h-8 text-slate-400 mx-auto" />
<h4 className="text-slate-800 font-black uppercase tracking-widest text-xs">Read-only View</h4>
<p className="text-slate-500 text-[10px] font-bold">Only Finance team members can take actions on this stage.</p>
</div>
)
) : (
<div className="p-6 bg-green-50 border border-green-100 rounded-2xl text-center space-y-2" data-testid="onboarding-finance-fdd-decision-badge">
<CheckCircle className="w-8 h-8 text-green-600 mx-auto" />
<h4 className="text-green-800 font-black uppercase tracking-widest text-xs">Action Recorded</h4>
<p className="text-green-700 text-[10px] font-bold">You have already submitted your decision for this stage.</p>
</div>
)}
<div className="pt-4 border-t border-slate-100">
<h5 className="text-[10px] text-slate-400 font-black uppercase tracking-widest mb-4">Verification Policy</h5>
<ul className="space-y-3">
<li className="flex items-start gap-3" data-testid="onboarding-finance-fdd-policy-1">
<div className="w-1.5 h-1.5 rounded-full bg-amber-500 mt-1.5 shrink-0" />
<p className="text-[10px] text-slate-500 font-bold leading-tight">Must review PDF audit report for financial discrepancies before approval.</p>
</li>
<li className="flex items-start gap-3" data-testid="onboarding-finance-fdd-policy-2">
<div className="w-1.5 h-1.5 rounded-full bg-amber-500 mt-1.5 shrink-0" />
<p className="text-[10px] text-slate-500 font-bold leading-tight">Approval triggers the progression to Security Deposit payment state.</p>
</li>
<li className="flex items-start gap-3" data-testid="onboarding-finance-fdd-policy-3">
<div className="w-1.5 h-1.5 rounded-full bg-amber-500 mt-1.5 shrink-0" />
<p className="text-[10px] text-slate-500 font-bold leading-tight">Remarks are mandatory for audit trail and compliance tracking.</p>
</li>
</ul>
</div>
</CardContent>
</Card>
<Card className="bg-slate-50 border-slate-200 rounded-2xl" data-testid="onboarding-finance-fdd-progress-card">
<CardContent className="p-6 flex items-center gap-4">
<div className="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center shrink-0">
<Clock className="w-5 h-5 text-blue-600" />
</div>
<div>
<h5 className="text-[10px] font-black uppercase tracking-widest text-slate-400">Current Progress</h5>
<p className="text-slate-900 font-bold">75% Complete</p>
</div>
</CardContent>
</Card>
</div>
</div>
</TabsContent>
<TabsContent value="worknotes">
<Card className="border-slate-200 shadow-sm overflow-hidden rounded-2xl min-h-[600px] flex flex-col" data-testid="onboarding-finance-fdd-worknotes-card">
<CardHeader className="bg-slate-50/50 border-b border-slate-100 py-4 px-6">
<CardTitle className="text-sm font-black uppercase tracking-widest text-slate-500 flex items-center justify-between">
<div className="flex items-center gap-2"><MessageSquare className="w-4 h-4" /> Communication History</div>
<Badge variant="outline" className="bg-white">Queries & Escalations</Badge>
</CardTitle>
</CardHeader>
<CardContent className="p-0 flex-1 overflow-y-auto max-h-[600px]">
{workNotes.length === 0 ? (
<div className="p-20 text-center text-slate-400 italic" data-testid="onboarding-finance-fdd-worknotes-empty">No communication logged yet.</div>
) : (
<div className="divide-y divide-slate-100">
{workNotes.map((note: any, nIdx: number) => (
<div key={note.id} className="p-6 hover:bg-slate-50 transition-colors" data-testid={`onboarding-finance-fdd-worknote-row-${nIdx}`}>
<div className="flex items-start gap-4">
<Avatar className="h-10 w-10 border border-slate-200">
<AvatarFallback className="bg-indigo-100 text-indigo-700 font-black text-xs" data-testid={`onboarding-finance-fdd-worknote-avatar-${nIdx}`}>
{note.author?.fullName?.substring(0, 2).toUpperCase() || 'SYS'}
</AvatarFallback>
</Avatar>
<div className="flex-1 space-y-1">
<div className="flex items-center justify-between">
<h4 className="text-sm font-black text-slate-900" data-testid={`onboarding-finance-fdd-worknote-author-${nIdx}`}>{note.author?.fullName || 'System'}</h4>
<span className="text-[10px] font-bold text-slate-400 uppercase" data-testid={`onboarding-finance-fdd-worknote-date-${nIdx}`}>{formatDateTime(note.createdAt)}</span>
</div>
<p className="text-[10px] text-slate-500 font-bold uppercase tracking-widest" data-testid={`onboarding-finance-fdd-worknote-role-${nIdx}`}>{note.author?.roleCode || 'RE Stakeholder'}</p>
<div className="mt-4 p-4 bg-white rounded-xl border border-slate-100 text-sm text-slate-700 leading-relaxed shadow-sm" data-testid={`onboarding-finance-fdd-worknote-text-${nIdx}`}>
{note.noteText}
</div>
</div>
</div>
</div>
))}
</div>
)}
</CardContent>
<div className="p-6 bg-slate-50 border-t border-slate-100">
<Label className="text-[10px] text-slate-400 font-black uppercase tracking-widest mb-2 block">Direct Query to FDD Agency</Label>
<div className="flex gap-2">
<Textarea
placeholder="Need clarification from the FDD agency? Post a note here..."
className="min-h-[60px] bg-white border-slate-200 rounded-xl text-sm"
value={newNote}
onChange={(e) => setNewNote(e.target.value)}
disabled={isNoteSubmitting}
data-testid="onboarding-finance-fdd-new-note-input"
/>
<Button
className="shrink-0 bg-blue-600 hover:bg-blue-700 h-auto self-stretch rounded-xl px-6"
onClick={handlePostNote}
disabled={isNoteSubmitting || !newNote.trim()}
data-testid="onboarding-finance-fdd-send-note-btn"
>
{isNoteSubmitting ? <Clock className="w-4 h-4 animate-spin" /> : <Send className="w-4 h-4" />}
</Button>
</div>
</div>
</Card>
</TabsContent>
<TabsContent value="history">
<Card className="border-slate-200 shadow-sm overflow-hidden rounded-2xl" data-testid="onboarding-finance-fdd-history-card">
<CardHeader className="bg-slate-50/50 border-b border-slate-100 py-4 px-6">
<CardTitle className="text-sm font-black uppercase tracking-widest text-slate-500 flex items-center gap-2">
<History className="w-4 h-4" /> Complete Application Journey
</CardTitle>
</CardHeader>
<CardContent className="p-6">
<div className="space-y-6">
{(application.progressTracking || []).map((step: any, idx: number) => (
<div key={idx} className="flex gap-4 relative" data-testid={`onboarding-finance-fdd-journey-step-${idx}`}>
{idx !== application.progressTracking.length - 1 && (
<div className="absolute left-3 top-6 bottom-[-24px] w-0.5 bg-slate-100" />
)}
<div className={cn(
"w-6 h-6 rounded-full flex items-center justify-center shrink-0 z-10",
step.stageCompletedAt ? "bg-emerald-500 text-white" : "bg-slate-200 text-slate-400"
)} data-testid={`onboarding-finance-fdd-journey-icon-${idx}`}>
{step.stageCompletedAt ? <CheckCircle className="w-4 h-4" /> : <div className="w-1.5 h-1.5 rounded-full bg-current" />}
</div>
<div>
<p className="text-sm font-bold text-slate-900" data-testid={`onboarding-finance-fdd-journey-name-${idx}`}>{step.stageName}</p>
<p className="text-[10px] text-slate-400 font-bold uppercase tracking-widest" data-testid={`onboarding-finance-fdd-journey-date-${idx}`}>
{step.stageCompletedAt ? `Completed ${formatDateTime(step.stageCompletedAt)}` : 'Pending'}
</p>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</TabsContent>
</Tabs>
{/* Global Preview Modal */}
<DocumentPreviewModal
isOpen={showPreviewModal}
onClose={() => setShowPreviewModal(false)}
document={previewDoc}
/>
</div>
);
}