import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { FileText, Loader2, ExternalLink } from 'lucide-react'; import toast from 'react-hot-toast'; import Modal from '../ui/Modal'; import Button from '../ui/Button'; import { contractApi, EmailAttachment } from '../../services/api'; import { serverFileToAttachment, totalAttachmentBytes } from './composeAttachmentHelpers'; import { viewUrl } from '../../utils/fileUrl'; interface Props { isOpen: boolean; onClose: () => void; contractId: number; currentAttachments: EmailAttachment[]; onAttach: (added: EmailAttachment[]) => void; } const MAX_TOTAL_SIZE = 25 * 1024 * 1024; // identisch zur Compose-Modal export default function AttachContractDocumentsModal({ isOpen, onClose, contractId, currentAttachments, onAttach, }: Props) { const [selected, setSelected] = useState>(new Set()); const [busy, setBusy] = useState(false); const { data, isLoading } = useQuery({ queryKey: ['contract-documents', contractId], queryFn: () => contractApi.getDocuments(contractId), enabled: isOpen, }); const documents = data?.data || []; const toggle = (id: number) => { setSelected((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); }; const handleClose = () => { if (busy) return; // Kein Abbruch während Download läuft setSelected(new Set()); onClose(); }; const handleAttach = async () => { if (selected.size === 0) { handleClose(); return; } setBusy(true); const docsToFetch = documents.filter((d) => selected.has(d.id)); const newAttachments: EmailAttachment[] = []; let runningSize = totalAttachmentBytes(currentAttachments); try { for (const doc of docsToFetch) { try { const att = await serverFileToAttachment(doc.documentPath, doc.originalName); const approxBytes = Math.ceil(att.content.length * 0.75); if (runningSize + approxBytes > MAX_TOTAL_SIZE) { toast.error( `Maximale Gesamtgröße erreicht (25 MB). "${doc.originalName}" und folgende übersprungen.`, { duration: 6000 }, ); break; } newAttachments.push(att); runningSize += approxBytes; } catch (err: any) { toast.error(err?.message || `Fehler beim Anhängen von "${doc.originalName}"`); } } if (newAttachments.length > 0) { onAttach(newAttachments); toast.success( newAttachments.length === 1 ? '1 Dokument angehängt' : `${newAttachments.length} Dokumente angehängt`, ); } setSelected(new Set()); onClose(); } finally { setBusy(false); } }; // Nach documentType gruppieren für übersichtliche Darstellung const grouped = documents.reduce>((acc, doc) => { const key = doc.documentType || 'Sonstiges'; if (!acc[key]) acc[key] = []; acc[key].push(doc); return acc; }, {}); return (
{isLoading ? (
Dokumente werden geladen…
) : documents.length === 0 ? (

Keine Dokumente am Vertrag hinterlegt

) : (
{Object.entries(grouped).map(([type, docs]) => ( ))}
)}
{selected.size > 0 ? `${selected.size} ausgewählt` : 'Keine Auswahl'}
); }