/** * PrintTemplateEditor — Druckvorlagen-Editor (Phase L2). * * Combines a letterhead reference, an entity type (selects the module's * placeholder palette) and the drag&drop block composition (BlockEditor). */ import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Modal } from '@/components/ui/Modal'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; import { useToast } from '@/components/ui/Toast'; import { useCreatePrintTemplate, useUpdatePrintTemplate, useDocumentPlaceholders, type DocBlock, type Letterhead, type PrintTemplate, } from '@/api/documents'; import { BlockEditor } from './BlockEditor'; interface PrintTemplateEditorProps { template: PrintTemplate | null; letterheads: Letterhead[]; onClose: () => void; } export function PrintTemplateEditor({ template, letterheads, onClose }: PrintTemplateEditorProps) { const { t } = useTranslation(); const toast = useToast(); const [name, setName] = useState(template?.name ?? ''); const [description, setDescription] = useState(template?.description ?? ''); const [letterheadId, setLetterheadId] = useState(template?.letterhead_id ?? ''); const [entityType, setEntityType] = useState(template?.entity_type ?? 'contact'); const [blocks, setBlocks] = useState(template?.blocks ?? []); const createMutation = useCreatePrintTemplate(); const updateMutation = useUpdatePrintTemplate(); // discover available entity types from the placeholder registry const { data: placeholderMap } = useDocumentPlaceholders(); const entityTypes = useMemo(() => Object.keys(placeholderMap ?? {}).sort(), [placeholderMap]); useEffect(() => { if (template) { setName(template.name); setDescription(template.description); setLetterheadId(template.letterhead_id ?? ''); setEntityType(template.entity_type); setBlocks(template.blocks ?? []); } }, [template]); const selectedLetterhead = useMemo( () => letterheads.find((l) => l.id === letterheadId) ?? null, [letterheads, letterheadId] ); const handleSave = async () => { if (!name.trim()) { toast.error(t('documents.template.nameRequired', 'Name ist erforderlich')); return; } const input = { name: name.trim(), description, letterhead_id: letterheadId || null, entity_type: entityType, blocks, output_format: 'pdf' as const, }; try { if (template) { await updateMutation.mutateAsync({ id: template.id, input }); toast.success(t('documents.template.saved', 'Vorlage gespeichert')); } else { await createMutation.mutateAsync(input); toast.success(t('documents.template.created', 'Vorlage angelegt')); } onClose(); } catch (e) { toast.error(t('documents.template.saveFailed', 'Speichern fehlgeschlagen — Blöcke prüfen')); } }; return (
{/* Meta */}
setName(e.target.value)} data-testid="template-name-input" />
setDescription(e.target.value)} />
{/* Entity type */}

{t('documents.template.entityTypeHint', 'Bestimmt die verfügbaren Platzhalter (Modul-Beitrag)')}

{/* Block editor (content blocks + letterhead frame preview) */} {/* Actions */}
); }