'use client' import { useRef, useState } from 'react' const ACCEPTED = [ 'image/jpeg', 'image/png', 'image/heic', 'image/webp', 'video/mp4', 'video/quicktime', 'application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', ].join(',') const MAX_SIZE = { 'video/mp4': 200 * 1024 * 1024, 'video/quicktime': 200 * 1024 * 1024, default: 10 * 1024 * 1024, } interface Props { onFilesChange: (files: File[]) => void disabled?: boolean } export function FileUpload({ onFilesChange, disabled = false }: Props) { const inputRef = useRef(null) const [files, setFiles] = useState([]) const [errors, setErrors] = useState([]) const [dragging, setDragging] = useState(false) function validate(incoming: File[]): { valid: File[]; errs: string[] } { const valid: File[] = [] const errs: string[] = [] for (const f of incoming) { const limit = MAX_SIZE[f.type as keyof typeof MAX_SIZE] ?? MAX_SIZE.default if (f.size > limit) { errs.push(`${f.name}: exceeds ${limit / 1024 / 1024}MB limit`) } else { valid.push(f) } } return { valid, errs } } function addFiles(incoming: File[]) { const { valid, errs } = validate(incoming) const next = [...files, ...valid] setFiles(next) setErrors(errs) onFilesChange(next) } function remove(index: number) { const next = files.filter((_, i) => i !== index) setFiles(next) onFilesChange(next) } return (
inputRef.current?.click()} onDragOver={e => { e.preventDefault(); setDragging(true) }} onDragLeave={() => setDragging(false)} onDrop={e => { e.preventDefault() setDragging(false) addFiles(Array.from(e.dataTransfer.files)) }} >

Tap to add photos / videos / documents

Photos/docs up to 10MB ยท Videos up to 200MB

addFiles(Array.from(e.target.files ?? []))} disabled={disabled} /> {errors.map((err, i) => (

{err}

))} {files.length > 0 && (
    {files.map((f, i) => (
  • {f.name}
  • ))}
)}
) }