import { useRef, useState } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { X, Upload, FileText, CheckCircle, AlertCircle, Loader } from 'lucide-react' import { docsApi } from '../../api/client' import toast from 'react-hot-toast' const ALLOWED_TYPES = [ 'application/pdf', 'text/plain', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', ] export default function UploadModal({ onClose, conversationId }) { const [files, setFiles] = useState([]) const [title, setTitle] = useState('') const [source, setSource] = useState('') const [status, setStatus] = useState('idle') const [errorMsg, setErrorMsg] = useState('') const fileRef = useRef() const isSingleFile = files.length === 1 const selectFiles = (fileList) => { const picked = Array.from(fileList || []).filter((file) => { const ok = ALLOWED_TYPES.includes(file.type) || /\.(pdf|txt|docx)$/i.test(file.name) if (!ok) toast.error(`Unsupported file skipped: ${file.name}`) return ok }) if (!picked.length) return setFiles(picked) if (picked.length === 1) { setTitle((prev) => prev || picked[0].name.replace(/\.[^.]+$/, '').replace(/[-_]/g, ' ')) } else { setTitle('') } } const handleDrop = (e) => { e.preventDefault() selectFiles(e.dataTransfer.files) } const submit = async () => { if (!conversationId) { setErrorMsg('Create a conversation before uploading documents') setStatus('error') return } if (!files.length || (isSingleFile && !title.trim())) return setStatus('uploading') setErrorMsg('') try { const fd = new FormData() files.forEach((file) => fd.append('files', file)) fd.append('conversation_id', conversationId) if (isSingleFile) fd.append('title', title.trim()) if (source.trim()) fd.append('source', source.trim()) const result = await docsApi.upload(fd) setStatus('success') toast.success(result.message || 'Documents queued for ingestion') setTimeout(onClose, 1800) } catch (err) { setErrorMsg(err.response?.data?.detail || 'Upload failed') setStatus('error') } } const totalSizeMb = (files.reduce((sum, file) => sum + file.size, 0) / 1024 / 1024).toFixed(2) return ( e.target === e.currentTarget && onClose()} >

Upload Medical Documents

PDF, DOCX, or TXT. One or many files.

e.preventDefault()} onDrop={handleDrop} onClick={() => fileRef.current?.click()} className={`border-2 border-dashed rounded-xl p-6 text-center cursor-pointer transition-all duration-200 mb-4 ${ files.length ? 'border-med-teal/40 bg-med-teal/5' : 'border-white/10 hover:border-accent/40 hover:bg-accent/5' }`} > selectFiles(e.target.files)} /> {files.length ? (

{isSingleFile ? files[0].name : `${files.length} files selected`}

{totalSizeMb} MB total

{files.length > 1 && (
{files.map((file) => (
{file.name}
))}
)}
) : (

Drop files here or browse

)}
{isSingleFile && (
setTitle(e.target.value)} />
)} {files.length > 1 && (
Titles will be generated automatically from the filenames.
)}
setSource(e.target.value)} />
{status === 'error' && (
{errorMsg}
)} {status === 'success' && (
Upload accepted and queued for background ingestion. Closing...
)}
) }