import { useState } from 'react'; import { FileText, User, CreditCard, IdCard, AlertTriangle, Check, ChevronDown, ChevronRight, Receipt, FolderOpen } from 'lucide-react'; import Modal from '../ui/Modal'; import Button from '../ui/Button'; import Input from '../ui/Input'; import Select from '../ui/Select'; import { cachedEmailApi, AttachmentTargetSlot, AttachmentEntityWithSlots } from '../../services/api'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import toast from 'react-hot-toast'; import type { InvoiceType } from '../../types'; const CONTRACT_DOCUMENT_TYPES = [ 'Auftragsformular', 'Auftragsbestätigung', 'Lieferbestätigung', 'Vertragsunterlagen', 'Vollmacht', 'Widerrufsbelehrung', 'Preisblatt', 'Sonstiges', ]; interface SaveAttachmentModalProps { isOpen: boolean; onClose: () => void; emailId: number; attachmentFilename: string; onSuccess?: () => void; } type SelectedTarget = { entityType: 'customer' | 'identityDocument' | 'bankCard' | 'contract'; entityId?: number; targetKey: string; hasDocument: boolean; label: string; }; type SaveMode = 'document' | 'invoice' | 'contractDocument'; export default function SaveAttachmentModal({ isOpen, onClose, emailId, attachmentFilename, onSuccess, }: SaveAttachmentModalProps) { const [selectedTarget, setSelectedTarget] = useState(null); const [expandedSections, setExpandedSections] = useState>(new Set(['customer'])); const [saveMode, setSaveMode] = useState('document'); const [invoiceData, setInvoiceData] = useState({ invoiceDate: new Date().toISOString().split('T')[0], invoiceType: 'INTERIM' as InvoiceType, notes: '', }); const [contractDocumentData, setContractDocumentData] = useState({ documentType: CONTRACT_DOCUMENT_TYPES[0], notes: '', }); const queryClient = useQueryClient(); // Ziele laden const { data: targetsData, isLoading, error } = useQuery({ queryKey: ['attachment-targets', emailId], queryFn: () => cachedEmailApi.getAttachmentTargets(emailId), enabled: isOpen, }); const targets = targetsData?.data; // Vertrag zugeordnet? → dann Rechnung + Vertragsdokument möglich const hasContract = !!targets?.contract; const saveMutation = useMutation({ mutationFn: () => { if (!selectedTarget) throw new Error('Kein Ziel ausgewählt'); return cachedEmailApi.saveAttachmentTo(emailId, attachmentFilename, { entityType: selectedTarget.entityType, entityId: selectedTarget.entityId, targetKey: selectedTarget.targetKey, }); }, onSuccess: () => { toast.success('Anhang gespeichert'); queryClient.invalidateQueries({ queryKey: ['attachment-targets', emailId] }); queryClient.invalidateQueries({ queryKey: ['customers'] }); queryClient.invalidateQueries({ queryKey: ['contracts'] }); // Spezifische Ansichten aktualisieren (IDs als String, da URL-Params Strings sind) if (targets?.customer?.id) { queryClient.invalidateQueries({ queryKey: ['customer', targets.customer.id.toString()] }); } if (targets?.contract?.id) { queryClient.invalidateQueries({ queryKey: ['contract', targets.contract.id.toString()] }); } onSuccess?.(); handleClose(); }, onError: (error: Error) => { toast.error(error.message || 'Fehler beim Speichern'); }, }); const saveInvoiceMutation = useMutation({ mutationFn: () => { return cachedEmailApi.saveAttachmentAsInvoice(emailId, attachmentFilename, { invoiceDate: invoiceData.invoiceDate, invoiceType: invoiceData.invoiceType, notes: invoiceData.notes || undefined, }); }, onSuccess: () => { toast.success('Anhang als Rechnung gespeichert'); queryClient.invalidateQueries({ queryKey: ['attachment-targets', emailId] }); queryClient.invalidateQueries({ queryKey: ['customers'] }); queryClient.invalidateQueries({ queryKey: ['contracts'] }); if (targets?.contract?.id) { queryClient.invalidateQueries({ queryKey: ['contract', targets.contract.id.toString()] }); } onSuccess?.(); handleClose(); }, onError: (error: Error) => { toast.error(error.message || 'Fehler beim Speichern der Rechnung'); }, }); const saveContractDocumentMutation = useMutation({ mutationFn: () => { return cachedEmailApi.saveAttachmentAsContractDocument(emailId, attachmentFilename, { documentType: contractDocumentData.documentType, notes: contractDocumentData.notes || undefined, }); }, onSuccess: () => { toast.success('Anhang als Vertragsdokument gespeichert'); queryClient.invalidateQueries({ queryKey: ['attachment-targets', emailId] }); queryClient.invalidateQueries({ queryKey: ['contracts'] }); if (targets?.contract?.id) { queryClient.invalidateQueries({ queryKey: ['contract', targets.contract.id.toString()] }); queryClient.invalidateQueries({ queryKey: ['contract-documents', targets.contract.id] }); } onSuccess?.(); handleClose(); }, onError: (error: Error) => { toast.error(error.message || 'Fehler beim Speichern des Vertragsdokuments'); }, }); const handleClose = () => { setSelectedTarget(null); setSaveMode('document'); setInvoiceData({ invoiceDate: new Date().toISOString().split('T')[0], invoiceType: 'INTERIM', notes: '', }); setContractDocumentData({ documentType: CONTRACT_DOCUMENT_TYPES[0], notes: '', }); onClose(); }; const toggleSection = (section: string) => { const newExpanded = new Set(expandedSections); if (newExpanded.has(section)) { newExpanded.delete(section); } else { newExpanded.add(section); } setExpandedSections(newExpanded); }; const handleSelectSlot = ( entityType: 'customer' | 'identityDocument' | 'bankCard' | 'contract', slot: AttachmentTargetSlot, entityId?: number, parentLabel?: string ) => { setSelectedTarget({ entityType, entityId, targetKey: slot.key, hasDocument: slot.hasDocument, label: parentLabel ? `${parentLabel} → ${slot.label}` : slot.label, }); }; const renderSlots = ( slots: AttachmentTargetSlot[], entityType: 'customer' | 'identityDocument' | 'bankCard' | 'contract', entityId?: number, parentLabel?: string ) => { return slots.map((slot) => { const isSelected = selectedTarget?.entityType === entityType && selectedTarget?.entityId === entityId && selectedTarget?.targetKey === slot.key; return (
handleSelectSlot(entityType, slot, entityId, parentLabel)} className={` flex items-center gap-3 p-3 cursor-pointer transition-colors rounded-lg ml-4 ${isSelected ? 'bg-blue-100 ring-2 ring-blue-500' : 'hover:bg-gray-100'} `} >
{slot.label} {slot.hasDocument && ( Vorhanden )}
{isSelected && }
); }); }; const renderEntityWithSlots = ( entity: AttachmentEntityWithSlots, entityType: 'identityDocument' | 'bankCard' ) => { return (
{entity.label}
{renderSlots(entity.slots, entityType, entity.id, entity.label)}
); }; const renderSection = ( title: string, sectionKey: string, icon: React.ReactNode, children: React.ReactNode, isEmpty: boolean = false ) => { const isExpanded = expandedSections.has(sectionKey); return (
{isExpanded && (
{isEmpty ? (

Keine Einträge vorhanden

) : ( children )}
)}
); }; return (
{/* Attachment Info */}

Datei: {attachmentFilename}

{/* Loading */} {isLoading && (
)} {/* Error */} {error && (
Fehler beim Laden der Dokumentziele
)} {targets && ( <> {/* Mode Toggle (nur wenn ein Vertrag zugeordnet ist) */} {hasContract && (
)} {/* Document Mode */} {saveMode === 'document' && (
{/* Kunde */} {renderSection( `Kunde: ${targets.customer.name}`, 'customer', , renderSlots(targets.customer.slots, 'customer'), targets.customer.slots.length === 0 )} {/* Ausweise */} {renderSection( 'Ausweisdokumente', 'identityDocuments', , targets.identityDocuments.map((doc) => renderEntityWithSlots(doc, 'identityDocument') ), targets.identityDocuments.length === 0 )} {/* Bankkarten */} {renderSection( 'Bankkarten', 'bankCards', , targets.bankCards.map((card) => renderEntityWithSlots(card, 'bankCard')), targets.bankCards.length === 0 )} {/* Vertrag */} {targets.contract && renderSection( `Vertrag: ${targets.contract.contractNumber}`, 'contract', , renderSlots(targets.contract.slots, 'contract'), targets.contract.slots.length === 0 )} {!targets.contract && (
E-Mail ist keinem Vertrag zugeordnet. Ordnen Sie die E-Mail einem Vertrag zu, um Vertragsdokumente als Ziel auswählen zu können.
)}
)} {/* Invoice Mode */} {saveMode === 'invoice' && hasContract && (

Der Anhang wird als Rechnung für den Vertrag {targets.contract?.contractNumber} gespeichert.

setInvoiceData({ ...invoiceData, invoiceDate: e.target.value })} required /> setInvoiceData({ ...invoiceData, notes: e.target.value })} placeholder="Optionale Anmerkungen..." />
)} {/* Contract Document Mode */} {saveMode === 'contractDocument' && hasContract && (

Der Anhang wird als Vertragsdokument für den Vertrag {targets.contract?.contractNumber} gespeichert.

setContractDocumentData({ ...contractDocumentData, notes: e.target.value }) } placeholder="Optionale Anmerkungen..." />
)} )} {/* Warning if replacing */} {saveMode === 'document' && selectedTarget?.hasDocument && (
Achtung: An diesem Feld ist bereits ein Dokument hinterlegt. Das vorhandene Dokument wird durch den neuen Anhang ersetzt.
)} {/* Actions */}
{saveMode === 'document' && ( )} {saveMode === 'invoice' && ( )} {saveMode === 'contractDocument' && ( )}
); }