// Upload Modal Component for ID Card Extraction const { useState, useRef } = React; const UploadModal = ({ onClose, onExtracted }) => { const toast = useToast(); const [mode, setMode] = useState('single'); // 'single' or 'split' const [singleFile, setSingleFile] = useState(null); const [files, setFiles] = useState({ front: null, back: null }); const [extracting, setExtracting] = useState(false); const singleInputRef = useRef(); const frontInputRef = useRef(); const backInputRef = useRef(); const hasSingleFile = !!singleFile; const hasFront = !!files.front; const hasBack = !!files.back; const hasAnyImage = mode === 'single' ? hasSingleFile : (hasFront || hasBack); const validateFile = (file) => { if (!file) return false; const validTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']; if (!validTypes.includes(file.type)) { toast('Formato file non valido. Usa JPG, PNG, WebP o GIF', 'error'); return false; } if (file.size > 10 * 1024 * 1024) { toast('File troppo grande. Massimo 10 MB', 'error'); return false; } return true; }; const handleSingleFileSelect = (file) => { if (!validateFile(file)) return; setSingleFile(file); toast('Immagine selezionata', 'info'); }; const handleFileSelect = (side, file) => { if (!validateFile(file)) return; setFiles(prev => ({ ...prev, [side]: file })); toast(`Immagine ${side === 'front' ? 'fronte' : 'retro'} selezionata`, 'info'); }; const handleRemoveFile = (side) => { setFiles(prev => ({ ...prev, [side]: null })); }; const handleExtract = async () => { if (!hasAnyImage) { toast('Carica almeno un\'immagine del documento', 'error'); return; } setExtracting(true); const formData = new FormData(); if (mode === 'single') { formData.append('files', singleFile); } else { // Add files in order: front first, then back if (files.front) { formData.append('files', files.front); } if (files.back) { formData.append('files', files.back); } } try { const response = await fetch('/extract', { method: 'POST', body: formData }); const data = await response.json(); if (data.status === 'success') { toast('Dati estratti con successo!', 'success'); onExtracted(data); } else if (data.status === 'empty') { toast('Nessun dato estratto dalle immagini', 'warning'); onExtracted(data); } else { toast(data.message || 'Estrazione fallita', 'error'); } } catch (error) { toast(`Errore: ${error.message}`, 'error'); } finally { setExtracting(false); } }; const DropZone = ({ side, file, inputRef }) => { const label = side === 'front' ? 'Fronte' : 'Retro'; const hasImage = !!file; return (
{label}
{hasImage ? (
{file.name}
{(file.size / 1024).toFixed(1)} KB
handleFileSelect(side, e.target.files[0])} className="hidden" />
) : (
inputRef.current?.click()} onDragOver={e => e.preventDefault()} onDrop={e => { e.preventDefault(); handleFileSelect(side, e.dataTransfer.files[0]); }} >
{side === 'front' ? '🪪' : '🔄'}

Trascina o clicca

Max 10 MB

handleFileSelect(side, e.target.files[0])} className="hidden" />
)}
); }; const SingleDropZone = () => { return (
{hasSingleFile ? (
{singleFile.name}
{(singleFile.size / 1024).toFixed(1)} KB
handleSingleFileSelect(e.target.files[0])} className="hidden" />
) : (
singleInputRef.current?.click()} onDragOver={e => e.preventDefault()} onDrop={e => { e.preventDefault(); handleSingleFileSelect(e.dataTransfer.files[0]); }} >
🪪

Trascina o clicca per caricare

JPG, PNG, WebP, GIF - Max 10 MB

handleSingleFileSelect(e.target.files[0])} className="hidden" />
)}
); }; return (
e.stopPropagation()}>

🪪 Carica Documento di Identità

Carica le immagini del documento per estrarre automaticamente i dati.

{/* Mode Toggle */}
{/* Upload Zones */} {mode === 'single' ? ( ) : (
)}
); }; window.UploadModal = UploadModal;