import { useCallback, useEffect, useState } from 'react' import { useDropzone } from 'react-dropzone' import type { DocumentoCargado, SlotDocumento } from '../types' import { TAMANO_MAX_DOCUMENTO } from '../data/constantes' interface Props { slot: SlotDocumento etiqueta: string documento?: DocumentoCargado onAgregar: (doc: DocumentoCargado) => void onQuitar: (slot: SlotDocumento) => void } function formatoTamano(bytes: number): string { return bytes >= 1024 * 1024 ? `${(bytes / (1024 * 1024)).toFixed(1)} MB` : `${Math.round(bytes / 1024)} KB` } /** Miniatura del documento: imagen con object-cover o recuadro plano para PDF */ function Miniatura({ documento, url }: { documento: DocumentoCargado; url: string }) { const esImagen = documento.tipoMime.startsWith('image/') return ( {esImagen ? ( {`Vista ) : ( PDF {documento.nombre} )} ) } /** Slot de carga de un documento (PDF/JPG/PNG, máx 10 MB) con vista previa */ export default function FileUploader({ slot, etiqueta, documento, onAgregar, onQuitar }: Props) { const [urlObjeto, setUrlObjeto] = useState('') // URL de objeto para la miniatura y para abrir en pestaña nueva; se revoca al quitar/desmontar useEffect(() => { if (!documento) { setUrlObjeto('') return } const url = URL.createObjectURL(documento.archivo) setUrlObjeto(url) return () => URL.revokeObjectURL(url) }, [documento]) const onDrop = useCallback( (aceptados: File[]) => { const archivo = aceptados[0] if (!archivo) return onAgregar({ slot, nombre: archivo.name, tamano: archivo.size, tipoMime: archivo.type, archivo }) }, [slot, onAgregar], ) const { getRootProps, getInputProps, isDragActive, fileRejections } = useDropzone({ onDrop, multiple: false, maxSize: TAMANO_MAX_DOCUMENTO, accept: { 'application/pdf': ['.pdf'], 'image/jpeg': ['.jpg', '.jpeg'], 'image/png': ['.png'], }, }) if (documento) { return (
{urlObjeto && }

{etiqueta}

{documento.nombre} · {formatoTamano(documento.tamano)}

) } return (

{etiqueta}

Arrastra el archivo aquí · PDF/JPG/PNG · máx 10 MB

{fileRejections.length > 0 && (

Archivo rechazado: formato no permitido o mayor a 10 MB

)}
) }