feat: admin editable email templates

addresses #869eg7ptr
This commit is contained in:
Björn Fromme
2026-08-17 10:39:19 +02:00
parent 804dab335f
commit 3e08965e48
49 changed files with 1760 additions and 276 deletions
@@ -0,0 +1,27 @@
{{ form_start(form) }}
<div class="flex flex-col space-y-4 pb-8">
{{ form_row(form.subject) }}
{{ form_row(form.headline) }}
{{ form_row(form.body) }}
<div class="bg-gray-100 rounded-md p-4 text-sm">
<div class="font-bold pb-2">
Verfügbare Platzhalter
</div>
<ul class="space-y-1">
{% for name, description in definition.placeholders %}
<li>
<code class="font-bold">{{ '{' ~ name ~ '}' }}</code> &ndash; {{ description }}
</li>
{% endfor %}
</ul>
<div class="pt-2">
Platzhalter ohne Wert werden als <code class="font-bold">-</code> ausgegeben.
</div>
</div>
</div>
<button type="submit" class="btn">
Speichern
</button>
{{ form_rest(form) }}
{{ form_end(form) }}
@@ -0,0 +1,77 @@
{% extends 'admin/layout.html.twig' %}
{% block title %}Einstellungen - E-Mail-Texte{% endblock %}
{% block content %}
<h1 class="text-2xl font-bold pb-2">
E-Mail-Texte
</h1>
<div class="data-table-wrapper">
<div class="data-table-wrapper__inner">
<table class="data-table">
<thead>
<tr>
<th>
E-Mail
</th>
<th>
Betreff
</th>
<th>
Status
</th>
<th></th>
</tr>
</thead>
<tbody>
{% for key, definition in definitions %}
{% set emailText = emailTexts[key]|default(null) %}
<tr>
<td>
{{ definition.label }}
</td>
<td>
{{ emailText ? emailText.subject : definition.defaultSubject }}
</td>
<td>
{% if emailText %}
Angepasst
{% else %}
Standard
{% endif %}
</td>
<td>
<div class="flex items-center space-x-2 justify-end">
{% if emailText %}
<button type="button"
class="text-red-500"
title="Auf Standardtext zurücksetzen"
hx-get="{{ path('app_admin_system_email_text_reset', { 'key': key }) }}"
hx-target="body"
hx-swap="beforeend">
{{ icon('refresh') }}
</button>
{% endif %}
<button type="button"
title="Vorschau anzeigen"
hx-get="{{ path('app_admin_system_email_text_preview', { 'key': key }) }}"
hx-target="body"
hx-swap="beforeend">
{{ icon('eye') }}
</button>
<button type="button"
title="E-Mail-Text bearbeiten"
hx-get="{{ path('app_admin_system_email_text_edit', { 'key': key }) }}"
hx-target="body"
hx-swap="beforeend">
{{ icon('edit') }}
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
@@ -0,0 +1,7 @@
{% extends 'htmx_modal.html.twig' %}
{% block title %}{{ definition.label }}{% endblock %}
{% block content %}
{% include 'admin/system/email_text/_form.html.twig' %}
{% endblock %}
@@ -0,0 +1,27 @@
{% extends 'htmx_modal.html.twig' %}
{% block title %}Vorschau: {{ definition.label }}{% endblock %}
{% block content %}
<div class="pb-4">
<span class="font-bold">Betreff:</span> {{ text.subject }}
</div>
{# The renderer escaped everything before it added a tag, see RenderedEmailTextDto. #}
<div class="border border-gray-200 rounded-md p-4">
{% if text.headline is not empty %}
<h1 class="text-xl font-bold pb-2">{{ text.headline | raw }}</h1>
{% endif %}
{# The paragraphs come from the mail body, where email/layout.html.twig styles every
<p> with padding-bottom:16px - pb-4 is the same spacing, so the preview matches. #}
<div class="[&>p]:pb-4 [&_a]:underline">
{{ text.bodyHtml | raw }}
</div>
<p>
<span class="btn inline-block">Zum Portal</span>
</p>
</div>
<div class="pt-4 text-sm text-gray-500">
Platzhalter sind als <code>[name]</code> dargestellt und werden beim Versand durch
die echten Werte ersetzt. Logo und Fußzeile der E-Mail sind hier nicht abgebildet.
</div>
{% endblock %}
@@ -0,0 +1,10 @@
{% extends 'htmx_confirmation_modal.html.twig' %}
{% block content %}
<div class="pb-4">
Möchtest du den Text der E-Mail <em>{{ definition.label }}</em> wirklich auf den
Standardtext zurücksetzen? Deine Änderungen gehen dabei verloren.
</div>
{% endblock %}
{% block button_confirm %}Zurücksetzen{% endblock %}