feat(stellungnahme): E-Mail, Name in Grußformel, Datum-Fix, UX-Polish
- E-Mail-Button: mailto-Link wenn recipientEmail im Block gesetzt - Name in Grußformel: "Mit freundlichen Grüßen\n\nMax Mustermann" - Datum-Fix: heute in buildText() berechnet, nicht beim Render - Disabled-Hint: roter Hinweis wenn Name fehlt - "Alle ab" klappt Gruppe ein (Symmetrie zu "Alle" öffnet) - Schritt X von Y unter Step-Indikator - recipientEmail-Feld in StellingnahmeGeneratorBlockData Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -470,5 +470,7 @@ export interface StellingnahmeGeneratorBlockData {
|
|||||||
allgemeineArgumente?: TextFragment[];
|
allgemeineArgumente?: TextFragment[];
|
||||||
/** ISO-Datum: Einwendungsfrist-Ende (z.B. "2026-07-04"). */
|
/** ISO-Datum: Einwendungsfrist-Ende (z.B. "2026-07-04"). */
|
||||||
deadline?: string;
|
deadline?: string;
|
||||||
|
/** E-Mail der Planungsstelle — aktiviert Mail-Button. */
|
||||||
|
recipientEmail?: string;
|
||||||
layout?: BlockLayout;
|
layout?: BlockLayout;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,13 +169,12 @@
|
|||||||
else next.add(s);
|
else next.add(s);
|
||||||
}
|
}
|
||||||
selectedSlugs = next;
|
selectedSlugs = next;
|
||||||
// Expand group when selecting so user sees what they picked
|
// Expand on select, collapse on deselect
|
||||||
if (!allSelected) {
|
|
||||||
const nextGroups = new Set(expandedGroups);
|
const nextGroups = new Set(expandedGroups);
|
||||||
nextGroups.add(group.slug);
|
if (allSelected) nextGroups.delete(group.slug);
|
||||||
|
else nextGroups.add(group.slug);
|
||||||
expandedGroups = nextGroups;
|
expandedGroups = nextGroups;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Combined selection for output — ortskonkrete first, then allgemeine
|
// Combined selection for output — ortskonkrete first, then allgemeine
|
||||||
const selectedFragments = $derived([
|
const selectedFragments = $derived([
|
||||||
@@ -196,46 +195,35 @@ Regionale Planungsstelle
|
|||||||
Karl-Liebknecht-Straße 4
|
Karl-Liebknecht-Straße 4
|
||||||
98527 Suhl`;
|
98527 Suhl`;
|
||||||
|
|
||||||
const heute = $derived(
|
|
||||||
new Date().toLocaleDateString("de-DE", { day: "2-digit", month: "2-digit", year: "numeric" }),
|
|
||||||
);
|
|
||||||
const gebietsBez = $derived(
|
const gebietsBez = $derived(
|
||||||
windArea
|
windArea
|
||||||
? `${windArea.gebiets_nr}${windArea.bezeichnung ? " – " + windArea.bezeichnung : ""}`
|
? `${windArea.gebiets_nr}${windArea.bezeichnung ? " – " + windArea.bezeichnung : ""}`
|
||||||
: "",
|
: "",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const mailtoLink = $derived.by(() => {
|
||||||
|
if (!block.recipientEmail || !outputText) return "";
|
||||||
|
const subject = `Einwendung Regionalplan Südwestthüringen – Vorranggebiet ${gebietsBez}`;
|
||||||
|
return `mailto:${block.recipientEmail}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(outputText)}`;
|
||||||
|
});
|
||||||
|
|
||||||
function buildText(): string {
|
function buildText(): string {
|
||||||
|
const heute = new Date().toLocaleDateString("de-DE", { day: "2-digit", month: "2-digit", year: "numeric" });
|
||||||
const sender = [absenderName.trim(), absenderAnschrift.trim(), absenderOrt.trim()]
|
const sender = [absenderName.trim(), absenderAnschrift.trim(), absenderOrt.trim()]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
const betreff = `Einwendung zum Entwurf des Regionalplans Südwestthüringen (2. Entwurf)\nWindenergie-Vorranggebiet ${gebietsBez}`;
|
const betreff = `Einwendung zum Entwurf des Regionalplans Südwestthüringen (2. Entwurf)\nWindenergie-Vorranggebiet ${gebietsBez}`;
|
||||||
let body = "";
|
const closing = absenderName.trim()
|
||||||
|
? `Mit freundlichen Grüßen\n\n${absenderName.trim()}`
|
||||||
if (mode === "fertig") {
|
: "Mit freundlichen Grüßen";
|
||||||
body += `ich erhebe Einwendung gegen die Ausweisung des Windenergie-Vorranggebiets ${gebietsBez} im 2. Entwurf des Regionalplans Südwestthüringen.\n\n`;
|
let body = `ich erhebe Einwendung gegen die Ausweisung des Windenergie-Vorranggebiets ${gebietsBez} im 2. Entwurf des Regionalplans Südwestthüringen.\n\n`;
|
||||||
for (const f of selectedFragments) {
|
for (const f of selectedFragments) {
|
||||||
if (f.title) body += `${f.title}\n\n`;
|
if (f.title) body += `${f.title}\n\n`;
|
||||||
if (f.text) body += `${stripMd(f.text)}\n\n`;
|
if (f.text) body += `${stripMd(f.text)}\n\n`;
|
||||||
}
|
}
|
||||||
if (persoenlicheEingabe.trim())
|
if (persoenlicheEingabe.trim())
|
||||||
body += `Persönliche Betroffenheit\n\n${persoenlicheEingabe.trim()}\n\n`;
|
body += `Persönliche Betroffenheit\n\n${persoenlicheEingabe.trim()}\n\n`;
|
||||||
body +=
|
body += `Ich fordere die Regionalplanung auf, das Vorranggebiet aus dem Regionalplan zu streichen oder zumindest einer erneuten, umfassenden Überprüfung zu unterziehen.\n\n${closing}`;
|
||||||
"Ich fordere die Regionalplanung auf, das Vorranggebiet aus dem Regionalplan zu streichen oder zumindest einer erneuten, umfassenden Überprüfung zu unterziehen.\n\nMit freundlichen Grüßen";
|
|
||||||
} else {
|
|
||||||
body += `Gliederung meiner Einwendung (bitte in eigenen Worten ausformulieren):\n\n`;
|
|
||||||
let i = 1;
|
|
||||||
for (const f of selectedFragments) {
|
|
||||||
body += `${i}. ${f.title ?? f._slug.replace(/_/g, " ")}\n`;
|
|
||||||
if (f.bulletPoints?.length)
|
|
||||||
for (const bp of f.bulletPoints) body += ` - ${bp}\n`;
|
|
||||||
body += "\n";
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (persoenlicheEingabe.trim())
|
|
||||||
body += `${i}. Persönliche Betroffenheit\n ${persoenlicheEingabe.trim()}\n\n`;
|
|
||||||
body += "Ich fordere die Regionalplanung auf, das Vorranggebiet aus dem Regionalplan zu streichen oder zumindest einer erneuten, umfassenden Überprüfung zu unterziehen.\n\nMit freundlichen Grüßen";
|
|
||||||
}
|
|
||||||
|
|
||||||
return [sender, "", heute, "", "An:", RECIPIENT, "", "Betreff: " + betreff.split("\n")[0], betreff.split("\n")[1] ?? "", "", "Sehr geehrte Damen und Herren,", "", body.trimEnd()]
|
return [sender, "", heute, "", "An:", RECIPIENT, "", "Betreff: " + betreff.split("\n")[0], betreff.split("\n")[1] ?? "", "", "Sehr geehrte Damen und Herren,", "", body.trimEnd()]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
@@ -473,7 +461,7 @@ Karl-Liebknecht-Straße 4
|
|||||||
<div class="prose prose-wald mb-6 max-w-none text-stein-700">{@html md(block.intro)}</div>
|
<div class="prose prose-wald mb-6 max-w-none text-stein-700">{@html md(block.intro)}</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Step indicator -->
|
<!-- Step indicator -->
|
||||||
<div class="mb-2 flex items-center gap-1 text-xs font-medium">
|
<div class="mb-2 flex items-center gap-1 text-xs font-medium">
|
||||||
{#each Array.from({ length: TOTAL_STEPS }, (_, i) => i) as s}
|
{#each Array.from({ length: TOTAL_STEPS }, (_, i) => i) as s}
|
||||||
<button
|
<button
|
||||||
@@ -492,6 +480,7 @@ Karl-Liebknecht-Straße 4
|
|||||||
<div class="h-px flex-1 {s < step ? 'bg-wald-400' : 'bg-stein-200'}"></div>
|
<div class="h-px flex-1 {s < step ? 'bg-wald-400' : 'bg-stein-200'}"></div>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
</div>
|
||||||
<p class="mb-6 text-right text-xs text-stein-400">Schritt {step + 1} von {TOTAL_STEPS} – {STEP_LABELS[step]}</p>
|
<p class="mb-6 text-right text-xs text-stein-400">Schritt {step + 1} von {TOTAL_STEPS} – {STEP_LABELS[step]}</p>
|
||||||
|
|
||||||
<!-- ── Step 0: Gebietskontext ─────────────────────────────────────────────── -->
|
<!-- ── Step 0: Gebietskontext ─────────────────────────────────────────────── -->
|
||||||
@@ -811,7 +800,7 @@ Karl-Liebknecht-Straße 4
|
|||||||
<div class="mb-1 font-semibold text-stein-700">Einzureichen bei:</div>
|
<div class="mb-1 font-semibold text-stein-700">Einzureichen bei:</div>
|
||||||
<div class="whitespace-pre">{RECIPIENT}</div>
|
<div class="whitespace-pre">{RECIPIENT}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-2 flex gap-3">
|
<div class="mb-2 flex gap-3">
|
||||||
<button
|
<button
|
||||||
class="rounded-lg bg-wald-700 px-6 py-2.5 font-semibold text-white transition hover:bg-wald-800 disabled:opacity-40"
|
class="rounded-lg bg-wald-700 px-6 py-2.5 font-semibold text-white transition hover:bg-wald-800 disabled:opacity-40"
|
||||||
@@ -819,6 +808,11 @@ Karl-Liebknecht-Straße 4
|
|||||||
onclick={generateOutput}
|
onclick={generateOutput}
|
||||||
>Text erstellen</button>
|
>Text erstellen</button>
|
||||||
<button class="rounded-lg border border-stein-300 px-4 py-2 text-sm text-stein-600 hover:bg-stein-50" onclick={() => goTo(3)}>← Zurück</button>
|
<button class="rounded-lg border border-stein-300 px-4 py-2 text-sm text-stein-600 hover:bg-stein-50" onclick={() => goTo(3)}>← Zurück</button>
|
||||||
|
</div>
|
||||||
|
{#if !absenderName.trim()}
|
||||||
|
<p class="mb-4 text-xs text-erde-600">Bitte Namen eintragen, um den Text zu erstellen.</p>
|
||||||
|
{:else}
|
||||||
|
<div class="mb-4"></div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if showOutput}
|
{#if showOutput}
|
||||||
@@ -828,6 +822,9 @@ Karl-Liebknecht-Straße 4
|
|||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<button class="rounded-md border border-stein-300 px-3 py-1.5 text-xs font-medium text-stein-700 hover:bg-stein-50" onclick={copyText}>{copyFeedback || "Kopieren"}</button>
|
<button class="rounded-md border border-stein-300 px-3 py-1.5 text-xs font-medium text-stein-700 hover:bg-stein-50" onclick={copyText}>{copyFeedback || "Kopieren"}</button>
|
||||||
<button class="rounded-md border border-stein-300 px-3 py-1.5 text-xs font-medium text-stein-700 hover:bg-stein-50" onclick={downloadText}>Herunterladen</button>
|
<button class="rounded-md border border-stein-300 px-3 py-1.5 text-xs font-medium text-stein-700 hover:bg-stein-50" onclick={downloadText}>Herunterladen</button>
|
||||||
|
<button class="rounded-md border border-stein-300 px-3 py-1.5 text-xs font-medium text-stein-700 hover:bg-stein-50" onclick={printText}>Drucken</button>
|
||||||
|
{#if mailtoLink}
|
||||||
|
<a href={mailtoLink} class="rounded-md border border-wald-400 bg-wald-50 px-3 py-1.5 text-xs font-medium text-wald-700 hover:bg-wald-100">Per E-Mail senden</a>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user