/** * Signature manager — CRUD for mail signatures with rich text editor. * Supports placeholder variables for user/tenant data. */ import React, { useState, useEffect, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; import { Card } from '@/components/ui/Card'; import { EmptyState } from '@/components/ui/EmptyState'; import { useToast } from '@/components/ui/Toast'; import { ConfirmDialog } from '@/components/ui/ConfirmDialog'; import { RichTextEditor } from './RichTextEditor'; import { fetchSignatures, createSignature, updateSignature, deleteSignature, type MailSignature, } from '@/api/mail'; /** Available placeholder variables for signatures. */ const SIGNATURE_VARIABLES = [ { token: '{{user.name}}', label: 'Vollständiger Name', description: 'Max Mustermann' }, { token: '{{user.first_name}}', label: 'Vorname', description: 'Max' }, { token: '{{user.last_name}}', label: 'Nachname', description: 'Mustermann' }, { token: '{{user.email}}', label: 'E-Mail', description: 'max@firma.de' }, { token: '{{user.role}}', label: 'Rolle', description: 'Admin' }, { token: '{{tenant.name}}', label: 'Firma/Organisation', description: 'HMS Licht & Ton' }, { token: '{{date}}', label: 'Aktuelles Datum', description: '16.07.2026' }, ]; export function SignatureManager() { const { t } = useTranslation(); const toast = useToast(); const [signatures, setSignatures] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [editing, setEditing] = useState(null); const [showForm, setShowForm] = useState(false); const [name, setName] = useState(''); const [bodyHtml, setBodyHtml] = useState(''); const [isDefault, setIsDefault] = useState(false); const [saving, setSaving] = useState(false); const [deleteTarget, setDeleteTarget] = useState(null); const load = useCallback(() => { setLoading(true); fetchSignatures() .then((data) => { setSignatures(data); setError(null); }) .catch((err: any) => { setError(err?.message || err?.detail || (typeof err === 'string' ? err : 'Failed to load signatures')); }) .finally(() => setLoading(false)); }, []); useEffect(() => { load(); }, [load]); const handleNew = () => { setEditing(null); setName(''); setBodyHtml(''); setIsDefault(false); setShowForm(true); }; const handleEdit = (sig: MailSignature) => { setEditing(sig); setName(sig.name); setBodyHtml(sig.body_html); setIsDefault(sig.is_default); setShowForm(true); }; const handleSave = useCallback(async () => { if (!name.trim()) return; setSaving(true); try { if (editing) { const updated = await updateSignature(editing.id, { name, body_html: bodyHtml, is_default: isDefault }); setSignatures((prev) => prev.map((s) => (s.id === editing.id ? updated : s))); toast.success(t('mail.signatureUpdated')); } else { const created = await createSignature({ name, body_html: bodyHtml, is_default: isDefault }); setSignatures((prev) => [...prev, created]); toast.success(t('mail.signatureCreated')); } setShowForm(false); } catch (err: any) { toast.error(err?.message || err?.detail || (typeof err === 'string' ? err : 'Save failed')); } finally { setSaving(false); } }, [editing, name, bodyHtml, isDefault, toast, t]); const handleDelete = useCallback(async () => { if (!deleteTarget) return; try { await deleteSignature(deleteTarget.id); setSignatures((prev) => prev.filter((s) => s.id !== deleteTarget.id)); toast.success(t('mail.signatureDeleted')); setDeleteTarget(null); } catch (err: any) { toast.error(err?.message || err?.detail || (typeof err === 'string' ? err : 'Delete failed')); } }, [deleteTarget, toast, t]); if (loading) { return (
); } if (error) { return (

{error}

); } return (

{t('mail.signatures')}

{showForm && (
setName(e.target.value)} placeholder={t('mail.signatureName')} required />
{/* Placeholder variable buttons */}
{SIGNATURE_VARIABLES.map((v) => ( ))}
)} {signatures.length === 0 && !showForm ? ( ) : (
{signatures.map((sig) => (

{sig.name}

{sig.is_default && {t('mail.defaultSignature')}}

))}
)} setDeleteTarget(null)} />
); }