import React, { useState, useEffect, useMemo, useCallback } from 'react'; import { ExtractedField, FileData } from '../types'; import { Check, Edit2, Download, RefreshCw, FileText, AlertTriangle, XCircle, ArrowRight, PenTool, CheckCircle2, Circle, FileCode, Loader2 } from 'lucide-react'; import { createFilledPdf } from '../services/pdfService'; import { generateLatexPdf, isLatexServiceAvailable, detectTemplate, base64ToBlob } from '../services/latexService'; import { jsPDF } from "jspdf"; interface ReviewPanelProps { fields: ExtractedField[]; formFile: FileData; sourceFile: FileData; summary: string; isFillablePdf: boolean; onReset: () => void; } type PdfMode = 'overlay' | 'fillable' | 'latex'; 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'); const [latexAvailable, setLatexAvailable] = useState(null); const [pdfMode, setPdfMode] = useState(isFillablePdf ? 'fillable' : 'overlay'); const [isGenerating, setIsGenerating] = useState(false); const [latexPdfBase64, setLatexPdfBase64] = useState(null); // Detect template from form file name const detectedTemplate = useMemo(() => detectTemplate(formFile.file.name), [formFile.file.name]); // Check LaTeX service availability on mount useEffect(() => { const checkLatex = async () => { const available = await isLatexServiceAvailable(); setLatexAvailable(available); // Auto-switch to LaTeX mode if available and template detected if (available && detectedTemplate && !isFillablePdf) { setPdfMode('latex'); } }; checkLatex(); }, [detectedTemplate, isFillablePdf]); // 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 LaTeX PDF const generateLatexPreview = useCallback(async () => { if (!detectedTemplate || pdfMode !== 'latex') return; setIsGenerating(true); try { const result = await generateLatexPdf(detectedTemplate, fields); if (result.success && result.pdf) { setLatexPdfBase64(result.pdf); const blob = base64ToBlob(result.pdf); const url = URL.createObjectURL(blob); setPreviewUrl(url); } else { console.error('LaTeX generation failed:', result.error); // Fallback to overlay mode setPdfMode('overlay'); } } catch (e) { console.error('LaTeX generation error:', e); setPdfMode('overlay'); } finally { setIsGenerating(false); } }, [detectedTemplate, fields, pdfMode]); // Generate preview useEffect(() => { const updatePreview = async () => { // LaTeX mode - handled separately with button click if (pdfMode === 'latex') { // Only auto-generate if we don't have a preview yet if (!latexPdfBase64) { generateLatexPreview(); } return; } if (formFile.type === 'application/pdf') { try { const filledPdfBytes = await createFilledPdf(formFile.base64, fields, pdfMode === 'fillable'); const blob = new Blob([filledPdfBytes], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); setPreviewUrl(url); return () => URL.revokeObjectURL(url); } catch (e) { console.error("Failed to generate PDF preview", e); } } else { setPreviewUrl(formFile.previewUrl); } }; // Debounce slightly to avoid rapid updates on typing const timer = setTimeout(updatePreview, 600); return () => clearTimeout(timer); }, [fields, pdfMode, formFile.base64, formFile.type, latexPdfBase64, generateLatexPreview]); const handleUpdate = (index: number, newValue: string) => { const newFields = [...fields]; newFields[index] = { ...newFields[index], value: newValue, // Auto-verify when manually edited 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 () => { // LaTeX mode - regenerate fresh PDF for download if (pdfMode === 'latex' && detectedTemplate) { setIsGenerating(true); try { const result = await generateLatexPdf(detectedTemplate, fields); if (result.success && result.pdf) { const blob = base64ToBlob(result.pdf); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${detectedTemplate}_filled.pdf`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } else { alert(`PDF generation failed: ${result.error}`); } } finally { setIsGenerating(false); } return; } 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"); } }; // Regenerate LaTeX preview const handleRegenerateLatex = () => { setLatexPdfBase64(null); generateLatexPreview(); }; // Sort: Unverified/Issues first, then verified const displayedFields = fields.map((f, i) => ({ ...f, originalIndex: i })) .sort((a, b) => { // Priority 1: Attention needed const aNeedsAttn = a.validation?.status !== 'VALID'; const bNeedsAttn = b.validation?.status !== 'VALID'; if (aNeedsAttn && !bNeedsAttn) return -1; if (!aNeedsAttn && bNeedsAttn) return 1; // Priority 2: Unverified 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}

{/* Verification Progress */}
{verifiedCount} / {totalCount} Verified
{/* Left Column: Visual Reference */}
Preview {pdfMode === 'latex' && ( LaTeX Template Mode )} {pdfMode === 'overlay' && ( Visual Overlay Mode )} {pdfMode === 'fillable' && ( Fillable PDF Mode )}
{/* Mode Switcher */} {latexAvailable && detectedTemplate && ( )} {pdfMode === 'latex' && ( )} {formFile.file.name}
{isGenerating && pdfMode === 'latex' ? (

Generating LaTeX PDF...

Compiling template with your data

) : previewUrl ? ( formFile.type === 'application/pdf' || pdfMode === 'latex' ? (