diff --git a/components/ReviewPanel.tsx b/components/ReviewPanel.tsx index 60aae8d..b064188 100644 --- a/components/ReviewPanel.tsx +++ b/components/ReviewPanel.tsx @@ -1,8 +1,7 @@ -import React, { useState, useEffect, useMemo, useCallback } from 'react'; +import React, { useState, useEffect, useMemo } 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 { Check, Edit2, Download, RefreshCw, FileText, AlertTriangle, XCircle, ArrowRight, PenTool, CheckCircle2, Circle, FileCheck } from 'lucide-react'; import { createFilledPdf } from '../services/pdfService'; -import { generateLatexPdf, isLatexServiceAvailable, detectTemplate, base64ToBlob } from '../services/latexService'; import { jsPDF } from "jspdf"; interface ReviewPanelProps { @@ -14,8 +13,6 @@ interface ReviewPanelProps { onReset: () => void; } -type PdfMode = 'overlay' | 'fillable' | 'latex'; - export const ReviewPanel: React.FC = ({ fields: initialFields, formFile, @@ -28,80 +25,28 @@ export const ReviewPanel: React.FC = ({ 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'), + + 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 + // Generate preview - fills the original PDF directly 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 filledPdfBytes = await createFilledPdf(formFile.base64, fields, isFillablePdf); const blob = new Blob([filledPdfBytes], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); - setPreviewUrl(url); - return () => URL.revokeObjectURL(url); + setPreviewUrl(prev => { + if (prev) URL.revokeObjectURL(prev); + return url; + }); } catch (e) { console.error("Failed to generate PDF preview", e); } @@ -110,17 +55,15 @@ export const ReviewPanel: React.FC = ({ } }; - // Debounce slightly to avoid rapid updates on typing - const timer = setTimeout(updatePreview, 600); + const timer = setTimeout(updatePreview, 500); return () => clearTimeout(timer); - }, [fields, pdfMode, formFile.base64, formFile.type, latexPdfBase64, generateLatexPreview]); + }, [fields, isFillablePdf, formFile.base64, formFile.type, formFile.previewUrl]); const handleUpdate = (index: number, newValue: string) => { const newFields = [...fields]; - newFields[index] = { - ...newFields[index], + newFields[index] = { + ...newFields[index], value: newValue, - // Auto-verify when manually edited isVerified: true, validation: { ...newFields[index].validation!, status: 'VALID', message: 'Manually verified' } }; @@ -129,9 +72,9 @@ export const ReviewPanel: React.FC = ({ const toggleVerify = (index: number) => { const newFields = [...fields]; - newFields[index] = { - ...newFields[index], - isVerified: !newFields[index].isVerified + newFields[index] = { + ...newFields[index], + isVerified: !newFields[index].isVerified }; setFields(newFields); }; @@ -144,30 +87,6 @@ export const ReviewPanel: React.FC = ({ }; 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; @@ -187,25 +106,15 @@ export const ReviewPanel: React.FC = ({ } }; - // 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)); @@ -218,106 +127,61 @@ export const ReviewPanel: React.FC = ({

Review & Verify

{summary}

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

Generating LaTeX PDF...

-

Compiling template with your data

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