import { useCallback, useState } from 'react' import { useDropzone } from 'react-dropzone' import { extractDocument } from '../lib/extractor' import { chunkPages } from '../lib/chunker' import { uploadChunks } from '../api/api' import { useToast } from './Toast' const ACCEPTED = { 'application/pdf': ['.pdf'], 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], 'application/vnd.ms-excel': ['.xls'], 'image/png': ['.png'], 'image/jpeg': ['.jpg', '.jpeg'], } const STAGES = [ 'Extracting text in browser…', 'Chunking document…', 'Embedding & indexing…', 'Done!', ] export default function FileUpload({ onUploaded }) { const toast = useToast() const [uploading, setUploading] = useState(false) const [stage, setStage] = useState('') const [stageIndex, setStageIndex] = useState(0) const [fileName, setFileName] = useState('') const [uploadError, setUploadError] = useState('') const onDrop = useCallback(async (accepted, rejected) => { if (rejected.length) { toast.error('Unsupported file type. Use PDF, DOCX, XLSX, PNG or JPG.'); return } if (!accepted.length) return const file = accepted[0] setUploading(true); setUploadError(''); setFileName(file.name); setStageIndex(0); setStage(STAGES[0]) try { const pages = await extractDocument(file) if (!pages.length) { toast.error('No text could be extracted.'); return } setStageIndex(1); setStage(STAGES[1]) const chunks = chunkPages(pages) setStageIndex(2); setStage(STAGES[2]) const result = await uploadChunks(file.name, chunks) setStageIndex(3); setStage(STAGES[3]) toast.success(`"${result.documentName}" ready — ${result.chunksCreated} chunks embedded`) onUploaded?.() } catch (err) { const msg = err.response?.data?.error ?? err.message ?? 'Upload failed.' setUploadError(msg) toast.error(msg) } finally { setUploading(false); setStage(''); setFileName(''); setStageIndex(0) } }, [onUploaded, toast]) const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, accept: ACCEPTED, multiple: false, disabled: uploading, }) const progress = uploading ? Math.round((stageIndex / (STAGES.length - 1)) * 100) : 0 return (
Drop to upload
) : ( <>Drag & drop a document
or click to browse
Upload failed
{uploadError}
{fileName}
)}