import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { pdfTemplateApi, contractApi } from '../../services/api'; import type { PdfTemplate, CrmField, Contract } from '../../types'; import Card from '../../components/ui/Card'; import Button from '../../components/ui/Button'; import Input from '../../components/ui/Input'; import Badge from '../../components/ui/Badge'; import Modal from '../../components/ui/Modal'; import { ArrowLeft, Plus, Edit, Trash2, FileText, Upload, Link2, Eye, Play } from 'lucide-react'; export default function PdfTemplates() { const navigate = useNavigate(); const queryClient = useQueryClient(); const [showCreateModal, setShowCreateModal] = useState(false); const [editingTemplate, setEditingTemplate] = useState(null); const [mappingTemplate, setMappingTemplate] = useState(null); const [testTemplate, setTestTemplate] = useState(null); const { data: templatesData, isLoading } = useQuery({ queryKey: ['pdf-templates'], queryFn: () => pdfTemplateApi.getAll(), }); const deleteMutation = useMutation({ mutationFn: (id: number) => pdfTemplateApi.delete(id), onSuccess: () => queryClient.invalidateQueries({ queryKey: ['pdf-templates'] }), }); const templates = templatesData?.data || []; return (

Auftragsvorlagen

Laden Sie PDF-Formulare hoch (z.B. EWE Auftragsformular) und verknüpfen Sie die Formularfelder mit CRM-Daten. Beim Erstellen eines Auftrags werden die Felder automatisch mit den Kundendaten befüllt.

{isLoading ? (
Laden...
) : templates.length === 0 ? (
Noch keine Vorlagen vorhanden. Laden Sie eine PDF-Vorlage hoch.
) : (
{templates.map((t) => (

{t.name}

{t.providerName && {t.providerName}} {!t.isActive && Inaktiv}
{t.description &&

{t.description}

}

Datei: {t.originalName} {t.maxPhoneFields && ` · Max. ${t.maxPhoneFields} Rufnummern`}

{(() => { const mapping = JSON.parse(t.fieldMapping || '{}'); const count = Object.keys(mapping).length; return (

{count > 0 ? `${count} Felder verknüpft` : 'Noch keine Felder verknüpft'}

); })()}
))}
)} {/* Erstellen Modal */} {showCreateModal && ( { setShowCreateModal(false); queryClient.invalidateQueries({ queryKey: ['pdf-templates'] }); }} /> )} {/* Bearbeiten Modal */} {editingTemplate && ( { setEditingTemplate(null); queryClient.invalidateQueries({ queryKey: ['pdf-templates'] }); }} /> )} {/* Feld-Mapping Modal */} {mappingTemplate && ( { setMappingTemplate(null); queryClient.invalidateQueries({ queryKey: ['pdf-templates'] }); }} /> )} {/* Test-Vorschau Modal */} {testTemplate && ( setTestTemplate(null)} /> )}
); } // ==================== CREATE MODAL ==================== function CreateTemplateModal({ onClose }: { onClose: () => void }) { const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [providerName, setProviderName] = useState(''); const [maxPhoneFields, setMaxPhoneFields] = useState('8'); const [file, setFile] = useState(null); const createMutation = useMutation({ mutationFn: async () => { const formData = new FormData(); formData.append('name', name); if (description) formData.append('description', description); if (providerName) formData.append('providerName', providerName); formData.append('maxPhoneFields', maxPhoneFields); formData.append('template', file!); return pdfTemplateApi.create(formData); }, onSuccess: () => onClose(), }); return (
setName(e.target.value)} placeholder="z.B. EWE Auftragsformular" required /> setProviderName(e.target.value)} placeholder="z.B. EWE" /> setDescription(e.target.value)} placeholder="Optionale Beschreibung" /> setMaxPhoneFields(e.target.value)} />

Die PDF muss Formularfelder enthalten. Diese werden nach dem Hochladen automatisch erkannt.

{createMutation.isError && (
{createMutation.error instanceof Error ? createMutation.error.message : 'Fehler beim Erstellen'}
)}
); } // ==================== EDIT MODAL ==================== function EditTemplateModal({ template, onClose }: { template: PdfTemplate; onClose: () => void }) { const [name, setName] = useState(template.name); const [description, setDescription] = useState(template.description || ''); const [providerName, setProviderName] = useState(template.providerName || ''); const [maxPhoneFields, setMaxPhoneFields] = useState(template.maxPhoneFields?.toString() || '8'); const [isActive, setIsActive] = useState(template.isActive); const updateMutation = useMutation({ mutationFn: () => pdfTemplateApi.update(template.id, { name, description, providerName, maxPhoneFields: parseInt(maxPhoneFields), isActive }), onSuccess: () => onClose(), }); return (
setName(e.target.value)} required /> setProviderName(e.target.value)} /> setDescription(e.target.value)} /> setMaxPhoneFields(e.target.value)} />
); } // ==================== FIELD MAPPING MODAL ==================== function FieldMappingModal({ template, onClose }: { template: PdfTemplate; onClose: () => void }) { const [mapping, setMapping] = useState>(JSON.parse(template.fieldMapping || '{}')); const { data: fieldsData } = useQuery({ queryKey: ['pdf-fields', template.id], queryFn: () => pdfTemplateApi.getFields(template.id), }); const { data: crmFieldsData } = useQuery({ queryKey: ['crm-fields', template.maxPhoneFields], queryFn: () => pdfTemplateApi.getCrmFields(template.maxPhoneFields || 8), }); const saveMutation = useMutation({ mutationFn: () => pdfTemplateApi.update(template.id, { fieldMapping: mapping }), onSuccess: () => onClose(), }); const pdfFields = fieldsData?.data || []; const totalPages = (fieldsData as any)?.totalPages || 1; const crmFields = crmFieldsData?.data || []; // CRM-Felder nach Gruppe const crmGroups = crmFields.reduce((acc, f) => { if (!acc[f.group]) acc[f.group] = []; acc[f.group].push(f); return acc; }, {} as Record); const [highlightedField, setHighlightedField] = useState(null); return (
{/* PDF-Vorschau links (nur zur Ansicht, nicht interaktiv) */}
PDF-Vorschau mit Feldnamen [Feldname] zeigt wo das Feld in der PDF liegt