import { motion } from 'framer-motion'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Upload, FileText, Eye, X, Plus } from 'lucide-react'; interface DocumentPolicy { maxFileSizeMB: number; allowedFileTypes: string[]; } interface DocumentsStepProps { documentPolicy: DocumentPolicy; isEditing: boolean; documents: File[]; existingDocuments: any[]; documentsToDelete: string[]; onDocumentsChange: (documents: File[]) => void; onExistingDocumentsChange: (documents: any[]) => void; onDocumentsToDeleteChange: (ids: string[]) => void; onPreviewDocument: (doc: any, isExisting: boolean) => void; onDocumentErrors?: (errors: Array<{ fileName: string; reason: string }>) => void; fileInputRef: React.RefObject; } /** * Component: DocumentsStep * * Purpose: Step 5 - Document upload and management * * Features: * - File upload with validation * - Preview existing documents * - Delete documents * - Test IDs for testing */ export function DocumentsStep({ documentPolicy, isEditing, documents, existingDocuments, documentsToDelete, onDocumentsChange, onExistingDocumentsChange: _onExistingDocumentsChange, onDocumentsToDeleteChange, onPreviewDocument, onDocumentErrors, fileInputRef }: DocumentsStepProps) { const handleFileChange = (event: React.ChangeEvent) => { const files = Array.from(event.target.files || []); if (files.length === 0) return; // Validate files const maxSizeBytes = documentPolicy.maxFileSizeMB * 1024 * 1024; const validationErrors: Array<{ fileName: string; reason: string }> = []; const validFiles: File[] = []; files.forEach(file => { // Check file size if (file.size > maxSizeBytes) { validationErrors.push({ fileName: file.name, reason: `File size exceeds the maximum allowed size of ${documentPolicy.maxFileSizeMB}MB. Current size: ${(file.size / (1024 * 1024)).toFixed(2)}MB` }); return; } // Check file extension const fileName = file.name.toLowerCase(); const fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1); if (!documentPolicy.allowedFileTypes.includes(fileExtension)) { validationErrors.push({ fileName: file.name, reason: `File type "${fileExtension}" is not allowed. Allowed types: ${documentPolicy.allowedFileTypes.join(', ')}` }); return; } validFiles.push(file); }); // Update parent with valid files if (validFiles.length > 0) { onDocumentsChange([...documents, ...validFiles]); } // Show errors if any if (validationErrors.length > 0 && onDocumentErrors) { onDocumentErrors(validationErrors); } // Reset file input if (event.target) { event.target.value = ''; } }; const handleRemove = (index: number) => { const newDocs = documents.filter((_, i) => i !== index); onDocumentsChange(newDocs); }; const handleDeleteExisting = (docId: string) => { onDocumentsToDeleteChange([...documentsToDelete, docId]); }; const canPreview = (doc: any, isExisting: boolean = false): boolean => { if (isExisting) { const type = (doc.fileType || doc.file_type || '').toLowerCase(); const name = (doc.originalFileName || doc.fileName || '').toLowerCase(); return type.includes('image') || type.includes('pdf') || name.endsWith('.jpg') || name.endsWith('.jpeg') || name.endsWith('.png') || name.endsWith('.gif') || name.endsWith('.pdf'); } else { const type = (doc.type || '').toLowerCase(); const name = (doc.name || '').toLowerCase(); return type.includes('image') || type.includes('pdf') || name.endsWith('.jpg') || name.endsWith('.jpeg') || name.endsWith('.png') || name.endsWith('.gif') || name.endsWith('.pdf'); } }; return (

Documents & Attachments

Upload supporting documents, files, and any additional materials for your request.

File Upload Attach supporting documents. Max {documentPolicy.maxFileSizeMB}MB per file. Allowed types: {documentPolicy.allowedFileTypes.join(', ')}

Upload Files

Drag and drop files here, or click to browse

`.${ext}`).join(',')} onChange={handleFileChange} className="hidden" id="file-upload" ref={fileInputRef} data-testid="documents-file-input" />

Supported formats: {documentPolicy.allowedFileTypes.map(ext => ext.toUpperCase()).join(', ')} (Max {documentPolicy.maxFileSizeMB}MB per file)

{/* Existing Documents */} {isEditing && existingDocuments.length > 0 && ( Existing Documents {existingDocuments.filter(d => !documentsToDelete.includes(d.documentId || d.document_id || '')).length} file{existingDocuments.filter(d => !documentsToDelete.includes(d.documentId || d.document_id || '')).length !== 1 ? 's' : ''}
{existingDocuments.map((doc: any) => { const docId = doc.documentId || doc.document_id || ''; const isDeleted = documentsToDelete.includes(docId); if (isDeleted) return null; return (

{doc.originalFileName || doc.fileName || 'Document'}

{doc.fileSize ? (Number(doc.fileSize) / (1024 * 1024)).toFixed(2) + ' MB' : 'Unknown size'}
{canPreview(doc, true) && ( )}
); })}
)} {/* New Documents */} {documents.length > 0 && ( New Files to Upload {documents.length} file{documents.length !== 1 ? 's' : ''}
{documents.map((file, index) => (

{file.name}

{(file.size / (1024 * 1024)).toFixed(2)} MB
{canPreview(file, false) && ( )}
))}
)}
); }