import React, { useState, useEffect, useMemo } from 'react'; import { ExtractedField, FileData } from '../types'; import { Check, Edit2, Download, RefreshCw, FileText, AlertTriangle, XCircle, ArrowRight, PenTool, CheckCircle2, Circle, FileCheck } from 'lucide-react'; import { createFilledPdf } from '../services/pdfService'; import { jsPDF } from "jspdf"; interface ReviewPanelProps { fields: ExtractedField[]; formFile: FileData; sourceFile: FileData; summary: string; isFillablePdf: boolean; onReset: () => void; } export const ReviewPanel: React.FC = ({ fields: initialFields, formFile, sourceFile, summary, isFillablePdf, onReset }) => { const [fields, setFields] = useState(initialFields); const [activeField, setActiveField] = useState(null); const [previewUrl, setPreviewUrl] = useState(null); const [filterMode, setFilterMode] = useState<'ALL' | 'ATTENTION'>('ALL'); // Derived state for progress const verifiedCount = fields.filter(f => f.isVerified).length; const totalCount = fields.length; const progressPercent = Math.round((verifiedCount / totalCount) * 100); const fieldsRequiresAttention = useMemo(() => fields.filter(f => f.validation?.status !== 'VALID'), [fields]); // Generate preview - fills the original PDF directly useEffect(() => { const updatePreview = async () => { if (formFile.type === 'application/pdf') { try { const filledPdfBytes = await createFilledPdf(formFile.base64, fields, isFillablePdf); const blob = new Blob([filledPdfBytes], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); setPreviewUrl(prev => { if (prev) URL.revokeObjectURL(prev); return url; }); } catch (e) { console.error("Failed to generate PDF preview", e); } } else { setPreviewUrl(formFile.previewUrl); } }; const timer = setTimeout(updatePreview, 500); return () => clearTimeout(timer); }, [fields, isFillablePdf, formFile.base64, formFile.type, formFile.previewUrl]); const handleUpdate = (index: number, newValue: string) => { const newFields = [...fields]; newFields[index] = { ...newFields[index], value: newValue, isVerified: true, validation: { ...newFields[index].validation!, status: 'VALID', message: 'Manually verified' } }; setFields(newFields); }; const toggleVerify = (index: number) => { const newFields = [...fields]; newFields[index] = { ...newFields[index], isVerified: !newFields[index].isVerified }; setFields(newFields); }; const applySuggestion = (index: number) => { const field = fields[index]; if (field.validation?.suggestion) { handleUpdate(index, field.validation.suggestion); } }; const handleDownload = async () => { if (formFile.type === 'application/pdf' && previewUrl) { const a = document.createElement('a'); a.href = previewUrl; a.download = `filled_${formFile.file.name}`; document.body.appendChild(a); a.click(); document.body.removeChild(a); } else { const doc = new jsPDF(); doc.text("Extracted Data", 20, 20); let y = 40; fields.forEach(f => { doc.text(`${f.label}: ${f.value}`, 20, y); y += 10; }); doc.save("data_report.pdf"); } }; // Sort: Unverified/Issues first, then verified const displayedFields = fields.map((f, i) => ({ ...f, originalIndex: i })) .sort((a, b) => { const aNeedsAttn = a.validation?.status !== 'VALID'; const bNeedsAttn = b.validation?.status !== 'VALID'; if (aNeedsAttn && !bNeedsAttn) return -1; if (!aNeedsAttn && bNeedsAttn) return 1; if (!a.isVerified && b.isVerified) return -1; if (a.isVerified && !b.isVerified) return 1; return a.originalIndex - b.originalIndex; }) .filter(f => filterMode === 'ALL' || (f.validation?.status !== 'VALID' && !f.isVerified)); return (
{/* Header Section */}

Review & Verify

{summary}

{verifiedCount} / {totalCount} Verified
{/* Left Column: PDF Preview */}
Preview {isFillablePdf ? ( Fillable PDF ) : ( Visual Overlay )}
{formFile.file.name}
{previewUrl ? ( formFile.type === 'application/pdf' ? (