import React, { useEffect, useMemo, useState } from 'react'; import type { ExtractedField, FileData } from '../types'; import { AlertTriangle, ArrowRight, Check, Download, ExternalLink, FileText, RefreshCw, XCircle, } from 'lucide-react'; import { createFilledPdf } from '../services/pdfService'; interface ReviewPanelProps { fields: ExtractedField[]; formFile: FileData; summary: string; onReset: () => void; } type FilterMode = 'ALL' | 'ATTENTION'; export const ReviewPanel: React.FC = ({ fields: initialFields, formFile, summary, onReset, }) => { const [fields, setFields] = useState(initialFields); const [activeField, setActiveField] = useState(null); const [previewUrl, setPreviewUrl] = useState(null); const [filterMode, setFilterMode] = useState('ALL'); const verifiedCount = fields.filter((f) => f.isVerified).length; const totalCount = fields.length; const progressPercent = totalCount === 0 ? 0 : Math.round((verifiedCount / totalCount) * 100); const fieldsRequiresAttention = useMemo( () => fields.filter((f) => f.validation?.status !== 'VALID'), [fields] ); useEffect(() => { let active = true; const handle = setTimeout(async () => { try { const bytes = await createFilledPdf(formFile.base64, fields); if (!active) return; const blob = new Blob([bytes as BlobPart], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); setPreviewUrl((prev) => { if (prev && prev.startsWith('blob:')) URL.revokeObjectURL(prev); return url; }); } catch (e) { console.error('[ReviewPanel] preview failed', e); } }, 600); return () => { active = false; clearTimeout(handle); }; }, [fields, formFile]); useEffect(() => { return () => { setPreviewUrl((prev) => { if (prev && prev.startsWith('blob:')) URL.revokeObjectURL(prev); return null; }); }; }, []); const handleUpdate = (index: number, newValue: string) => { setFields((prev) => { const next = [...prev]; next[index] = { ...next[index], value: newValue, isVerified: true, validation: { ...(next[index].validation ?? { status: 'VALID' }), status: 'VALID', message: 'Manuell bestätigt', }, }; return next; }); }; const toggleVerify = (index: number) => { setFields((prev) => { const next = [...prev]; next[index] = { ...next[index], isVerified: !next[index].isVerified }; return next; }); }; const applySuggestion = (index: number) => { const suggestion = fields[index].validation?.suggestion; if (suggestion) handleUpdate(index, suggestion); }; const handleDownload = async () => { const bytes = await createFilledPdf(formFile.base64, fields); const blob = new Blob([bytes as BlobPart], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `filled_${formFile.file.name}`; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(() => URL.revokeObjectURL(url), 0); }; const displayedFields = fields .map((f, i) => ({ ...f, originalIndex: i })) .sort((a, b) => { const aAttn = a.validation?.status !== 'VALID'; const bAttn = b.validation?.status !== 'VALID'; if (aAttn && !bAttn) return -1; if (!aAttn && bAttn) 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 (

Review & Verify

{summary}

{verifiedCount} / {totalCount} verifiziert
{/* Preview */}
PDF Preview (live) {formFile.file.name}
{previewUrl ? ( <>