import { useRef, useState, useCallback } from 'react'; import { FiUpload, FiX } from 'react-icons/fi'; import { FilePreview, FileMetadata } from './file-preview'; export interface FileUploadProps { onFilesChange: (files: File[]) => void; acceptedTypes?: string; maxFiles?: number; maxSize?: number; // in bytes disabled?: boolean; } export function FileUpload({ onFilesChange, acceptedTypes = '*/*', maxFiles = 10, maxSize = 50 * 1024 * 1024, // 50MB default disabled = false, }: FileUploadProps) { const [files, setFiles] = useState([]); const [isDragging, setIsDragging] = useState(false); const fileInputRef = useRef(null); const validateFile = (file: File): string | null => { if (file.size > maxSize) { return `File ${file.name} exceeds maximum size of ${(maxSize / (1024 * 1024)).toFixed(0)}MB`; } return null; }; const handleFiles = useCallback( (fileList: FileList | null) => { if (!fileList) return; const newFiles: File[] = []; const errors: string[] = []; Array.from(fileList).forEach(file => { const error = validateFile(file); if (error) { errors.push(error); } else if (files.length + newFiles.length < maxFiles) { newFiles.push(file); } else { errors.push(`Maximum ${maxFiles} files allowed`); } }); if (errors.length > 0) { alert(errors.join('\n')); } if (newFiles.length > 0) { const updatedFiles = [...files, ...newFiles]; setFiles(updatedFiles); onFilesChange(updatedFiles); } }, [files, maxFiles, maxSize, onFilesChange], ); const handleFileInputChange = (e: React.ChangeEvent) => { handleFiles(e.target.files); if (fileInputRef.current) { fileInputRef.current.value = ''; } }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); if (!disabled) { setIsDragging(true); } }; const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); }; const handleDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); if (disabled) return; handleFiles(e.dataTransfer.files); }; const removeFile = (index: number) => { const updatedFiles = files.filter((_, i) => i !== index); setFiles(updatedFiles); onFilesChange(updatedFiles); }; const clearFiles = () => { setFiles([]); onFilesChange([]); }; return (
!disabled && fileInputRef.current?.click()} >

Drag and drop files here, or click to select

Max {maxFiles} files, {(maxSize / (1024 * 1024)).toFixed(0)}MB per file

{files.length > 0 && (

{files.length} file{files.length > 1 ? 's' : ''} selected

{files.map((file, index) => { const fileMetadata: FileMetadata = { type: file.type.startsWith('audio/') ? 'audio' : file.type.startsWith('image/') ? 'image' : file.type.includes('pdf') || file.type.includes('word') || file.type.includes('text') ? 'document' : file.type.includes('spreadsheet') || file.type.includes('excel') || file.name.endsWith('.csv') ? 'spreadsheet' : 'other', mimeType: file.type, size: file.size, originalName: file.name, url: URL.createObjectURL(file), }; return ( removeFile(index)} showRemove={true} compact={true} /> ); })}
)}
); }