feat(mail): rich text editor for signatures + placeholder variables

- Replace textarea in SignatureManager with TipTap RichTextEditor
- Add placeholder variable buttons: {{user.name}}, {{user.first_name}},
  {{user.last_name}}, {{user.email}}, {{user.role}}, {{tenant.name}}, {{date}}
- Add replaceSignatureVariables() utility in mail API
- ComposeModal now replaces variables with actual user/tenant data when inserting signature
- Variables resolved from auth store (user name, email, role, tenant name)
This commit is contained in:
Agent Zero
2026-07-16 21:55:38 +02:00
parent 178bd84fd6
commit 7cb1341a28
3 changed files with 68 additions and 10 deletions
@@ -1,5 +1,6 @@
/**
* Signature manager — CRUD for mail signatures.
* Signature manager — CRUD for mail signatures with rich text editor.
* Supports placeholder variables for user/tenant data.
*/
import React, { useState, useEffect, useCallback } from 'react';
@@ -10,6 +11,7 @@ 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,
@@ -18,6 +20,17 @@ import {
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();
@@ -134,12 +147,24 @@ export function SignatureManager() {
/>
<div>
<label className="block text-sm font-medium text-secondary-700 mb-1">{t('mail.signatureBody')}</label>
<textarea
value={bodyHtml}
onChange={(e) => setBodyHtml(e.target.value)}
className="w-full min-h-24 border border-secondary-300 rounded-md p-3 text-sm focus:outline-none focus:ring-2 focus:ring-primary-500"
placeholder="<p>Regards, John</p>"
data-testid="signature-body"
{/* Placeholder variable buttons */}
<div className="flex flex-wrap gap-1 mb-2" data-testid="signature-variables">
{SIGNATURE_VARIABLES.map((v) => (
<button
key={v.token}
type="button"
onClick={() => setBodyHtml((prev) => `${prev}${v.token}`)}
className="inline-flex items-center px-2 py-0.5 text-xs rounded border border-secondary-300 bg-secondary-50 hover:bg-secondary-100 text-secondary-700"
title={v.description}
>
{v.label} <code className="ml-1 text-primary-600">{v.token}</code>
</button>
))}
</div>
<RichTextEditor
content={bodyHtml}
onChange={setBodyHtml}
placeholder="<p>Mit freundlichen Grüßen,<br>{{user.name}}</p>"
/>
</div>
<label className="flex items-center gap-2 text-sm text-secondary-700">