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 ? (
) : (
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 (
{etiqueta}
{documento.nombre} · {formatoTamano(documento.tamano)}
{etiqueta}
Arrastra el archivo aquí · PDF/JPG/PNG · máx 10 MB
Archivo rechazado: formato no permitido o mayor a 10 MB
)}