import { Upload, File, X, FileText } from 'lucide-react' import { useState, useCallback, useEffect, useRef } from 'react' import { Button } from '@/components/ui/button' import { cn } from '@/lib/utils' interface UploadedFile { id: string name: string size: string type: string } interface FileDropzoneProps { onFilesChange?: (files: Array) => void acceptedTypes?: string maxFiles?: number title?: string description?: string } export function FileDropzone({ onFilesChange, acceptedTypes = '.doc,.docx,.pdf', maxFiles = 5, title = 'Arrastra archivos aquí', description = 'o haz clic para seleccionar', }: FileDropzoneProps) { const [isDragging, setIsDragging] = useState(false) const [files, setFiles] = useState>([]) const onFilesChangeRef = useRef(onFilesChange) const addFiles = useCallback( (newFiles: Array) => { const toUpload: Array = newFiles.map((file) => ({ id: typeof crypto !== 'undefined' && 'randomUUID' in crypto ? (crypto as any).randomUUID() : `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, name: file.name, size: formatFileSize(file.size), type: file.name.split('.').pop() || 'file', })) setFiles((prev) => { const room = Math.max(0, maxFiles - prev.length) const next = [...prev, ...toUpload.slice(0, room)].slice(0, maxFiles) return next }) }, [maxFiles], ) 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 droppedFiles = Array.from(e.dataTransfer.files) addFiles(droppedFiles) }, [addFiles], ) const handleFileInput = useCallback( (e: React.ChangeEvent) => { if (e.target.files) { const selectedFiles = Array.from(e.target.files) addFiles(selectedFiles) } }, [addFiles], ) const removeFile = useCallback((fileId: string) => { setFiles((prev) => { const next = prev.filter((f) => f.id !== fileId) return next }) }, []) // Keep latest callback in a ref to avoid retriggering effect on identity change useEffect(() => { onFilesChangeRef.current = onFilesChange }, [onFilesChange]) // Only emit when files actually change to avoid parent update loops useEffect(() => { if (onFilesChangeRef.current) onFilesChangeRef.current(files) }, [files]) 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' } const getFileIcon = (type: string) => { switch (type.toLowerCase()) { case 'pdf': return case 'doc': case 'docx': return default: return } } return (
{/* Uploaded files list */} {files.length > 0 && (
{files.map((file) => (
{getFileIcon(file.type)}

{file.name}

{file.size}

))}
)} {files.length >= maxFiles && (

Máximo de {maxFiles} archivos alcanzado

)}
) }