import { ActionIcon, Anchor, Badge, Box, Button, FileButton, Group, Image, Loader, Paper, Stack, Text, Tooltip, } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { IconDownload, IconFile, IconFileSpreadsheet, IconFileText, IconFileTypePdf, IconPhoto, IconTrash, IconUpload, } from "@tabler/icons-react"; import { useCallback, useEffect, useState } from "react"; import * as api from "../api"; import type { CardFile } from "../types"; interface Props { cardId: string; refreshKey?: number; } function formatSize(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / 1024 / 1024).toFixed(2)} MB`; } function isImage(mime: string): boolean { return mime.startsWith("image/"); } function fileIcon(mime: string, size = 18) { const m = mime.toLowerCase(); if (m.startsWith("image/")) return ; if (m === "application/pdf") return ; if ( m.includes("spreadsheet") || m.includes("excel") || m === "text/csv" || m === "application/vnd.ms-excel" ) { return ; } if (m.startsWith("text/")) return ; return ; } function sourceBadge(s: CardFile["source"]) { if (s === "description") return { color: "blue", label: "descripcion" }; if (s === "chat") return { color: "teal", label: "chat" }; return { color: "gray", label: "subido" }; } export function CardFilesPanel({ cardId, refreshKey }: Props) { const [files, setFiles] = useState([]); const [loading, setLoading] = useState(true); const [uploading, setUploading] = useState(false); const reload = useCallback(async () => { try { const list = await api.listCardFiles(cardId); setFiles(list); } catch (e) { notifications.show({ color: "red", message: (e as Error).message }); } finally { setLoading(false); } }, [cardId]); useEffect(() => { reload(); }, [reload, refreshKey]); const onUpload = async (file: File | null) => { if (!file) return; setUploading(true); try { const cf = await api.uploadCardFile(cardId, file, "upload"); setFiles((prev) => [...prev, cf]); } catch (e) { notifications.show({ color: "red", message: (e as Error).message }); } finally { setUploading(false); } }; const onDelete = async (id: string) => { if (!window.confirm("¿Borrar este archivo?")) return; try { await api.deleteCardFile(id); setFiles((prev) => prev.filter((f) => f.id !== id)); } catch (e) { notifications.show({ color: "red", message: (e as Error).message }); } }; return ( {files.length} archivo{files.length === 1 ? "" : "s"} {(props) => ( )} {loading ? ( ) : files.length === 0 ? ( Sin archivos Sube archivos con el boton, arrastra al chat o a la descripcion. ) : ( {files.map((f) => { const badge = sourceBadge(f.source); return ( {isImage(f.mime) ? ( {f.filename} ) : ( {fileIcon(f.mime, 28)} )} {f.filename} {badge.label} {formatSize(f.size)} {f.mime || "?"} onDelete(f.id)} aria-label="Borrar" > ); })} )} ); }