Spaces:
Sleeping
Sleeping
| /** | |
| * File Upload Component | |
| * Drag-and-drop file upload interface | |
| */ | |
| import { useState, useCallback } from 'react'; | |
| interface FileUploadProps { | |
| onFileUpload: (file: File) => void; | |
| } | |
| export function FileUpload({ onFileUpload }: FileUploadProps) { | |
| const [isDragging, setIsDragging] = useState(false); | |
| const [selectedFile, setSelectedFile] = useState<File | null>(null); | |
| const handleDragOver = useCallback((e: React.DragEvent) => { | |
| e.preventDefault(); | |
| setIsDragging(true); | |
| }, []); | |
| const handleDragLeave = useCallback((e: React.DragEvent) => { | |
| e.preventDefault(); | |
| setIsDragging(false); | |
| }, []); | |
| const handleDrop = useCallback((e: React.DragEvent) => { | |
| e.preventDefault(); | |
| setIsDragging(false); | |
| const files = Array.from(e.dataTransfer.files); | |
| const pdfFile = files.find(file => file.type === 'application/pdf'); | |
| if (pdfFile) { | |
| setSelectedFile(pdfFile); | |
| } else { | |
| alert('Please upload a PDF file'); | |
| } | |
| }, []); | |
| const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => { | |
| const files = e.target.files; | |
| if (files && files.length > 0) { | |
| const file = files[0]; | |
| if (file.type === 'application/pdf') { | |
| setSelectedFile(file); | |
| } else { | |
| alert('Please upload a PDF file'); | |
| } | |
| } | |
| }, []); | |
| const handleUpload = () => { | |
| if (selectedFile) { | |
| onFileUpload(selectedFile); | |
| } | |
| }; | |
| const formatFileSize = (bytes: number): string => { | |
| if (bytes < 1024) return bytes + ' B'; | |
| if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; | |
| return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; | |
| }; | |
| return ( | |
| <div className="bg-white rounded-xl shadow-lg p-8 max-w-2xl mx-auto"> | |
| <h2 className="text-2xl font-bold text-gray-900 mb-2 text-center"> | |
| Upload Medical Report | |
| </h2> | |
| <p className="text-gray-600 mb-6 text-center"> | |
| Upload a PDF medical report for comprehensive AI analysis | |
| </p> | |
| <div | |
| onDragOver={handleDragOver} | |
| onDragLeave={handleDragLeave} | |
| onDrop={handleDrop} | |
| className={` | |
| border-2 border-dashed rounded-lg p-8 text-center transition-all | |
| ${isDragging | |
| ? 'border-blue-500 bg-blue-50' | |
| : 'border-gray-300 hover:border-blue-400 hover:bg-gray-50' | |
| } | |
| `} | |
| > | |
| <div className="flex flex-col items-center"> | |
| <svg | |
| className={`w-16 h-16 mb-4 ${isDragging ? 'text-blue-500' : 'text-gray-400'}`} | |
| fill="none" | |
| stroke="currentColor" | |
| viewBox="0 0 24 24" | |
| > | |
| <path | |
| strokeLinecap="round" | |
| strokeLinejoin="round" | |
| strokeWidth={2} | |
| d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" | |
| /> | |
| </svg> | |
| {selectedFile ? ( | |
| <div className="space-y-3"> | |
| <div className="bg-blue-50 border border-blue-200 rounded-lg p-4"> | |
| <div className="flex items-center gap-3"> | |
| <svg className="w-8 h-8 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /> | |
| </svg> | |
| <div className="text-left flex-1"> | |
| <p className="font-medium text-gray-900">{selectedFile.name}</p> | |
| <p className="text-sm text-gray-500">{formatFileSize(selectedFile.size)}</p> | |
| </div> | |
| <button | |
| onClick={() => setSelectedFile(null)} | |
| className="text-gray-400 hover:text-red-500 transition-colors" | |
| > | |
| <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| <button | |
| onClick={handleUpload} | |
| className="w-full px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors" | |
| > | |
| Start Analysis | |
| </button> | |
| </div> | |
| ) : ( | |
| <> | |
| <p className="text-lg font-medium text-gray-700 mb-2"> | |
| Drop your PDF file here | |
| </p> | |
| <p className="text-sm text-gray-500 mb-4"> | |
| or click to browse | |
| </p> | |
| <label className="cursor-pointer"> | |
| <span className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors inline-block"> | |
| Select File | |
| </span> | |
| <input | |
| type="file" | |
| accept=".pdf" | |
| onChange={handleFileSelect} | |
| className="hidden" | |
| /> | |
| </label> | |
| </> | |
| )} | |
| </div> | |
| </div> | |
| <div className="mt-6 grid grid-cols-2 gap-4 text-sm text-gray-600"> | |
| <div className="flex items-start gap-2"> | |
| <svg className="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /> | |
| </svg> | |
| <span>Supports all medical report types</span> | |
| </div> | |
| <div className="flex items-start gap-2"> | |
| <svg className="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /> | |
| </svg> | |
| <span>Encrypted & secure processing</span> | |
| </div> | |
| <div className="flex items-start gap-2"> | |
| <svg className="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /> | |
| </svg> | |
| <span>Multi-modal AI analysis</span> | |
| </div> | |
| <div className="flex items-start gap-2"> | |
| <svg className="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /> | |
| </svg> | |
| <span>Real-time processing status</span> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |