diff --git a/apps/mana/apps/web/src/lib/modules/broadcast/index.ts b/apps/mana/apps/web/src/lib/modules/broadcast/index.ts index 0804cba47..9a511460f 100644 --- a/apps/mana/apps/web/src/lib/modules/broadcast/index.ts +++ b/apps/mana/apps/web/src/lib/modules/broadcast/index.ts @@ -26,6 +26,9 @@ export { export { broadcastCampaignsStore } from './stores/campaigns.svelte'; export { broadcastSettingsStore, ensureSettings } from './stores/settings.svelte'; +export { renderEmailHtml } from './render/email-html'; +export { renderPlainText } from './render/plain-text'; + export { STATUS_LABELS, STATUS_COLORS, diff --git a/apps/mana/apps/web/src/lib/modules/broadcast/preview/EmailPreview.svelte b/apps/mana/apps/web/src/lib/modules/broadcast/preview/EmailPreview.svelte new file mode 100644 index 000000000..a43046916 --- /dev/null +++ b/apps/mana/apps/web/src/lib/modules/broadcast/preview/EmailPreview.svelte @@ -0,0 +1,98 @@ + + + +
+
+ + + + {viewport === 'mobile' ? 'Mobile' : 'Desktop'} +
+ +
+ + diff --git a/apps/mana/apps/web/src/lib/modules/broadcast/preview/PreviewTabs.svelte b/apps/mana/apps/web/src/lib/modules/broadcast/preview/PreviewTabs.svelte new file mode 100644 index 000000000..467763f07 --- /dev/null +++ b/apps/mana/apps/web/src/lib/modules/broadcast/preview/PreviewTabs.svelte @@ -0,0 +1,160 @@ + + + +
+
+ + + +
+ + {#if tab === 'desktop'} + + {:else if tab === 'mobile'} + + {:else} +
+
{plainText}
+

+ Der Text wird als text/plain zusätzlich zur HTML-Version verschickt — wichtig für + Spam-Filter und Clients, die kein HTML anzeigen. +

+
+ {/if} +
+ + diff --git a/apps/mana/apps/web/src/lib/modules/broadcast/render/email-html.test.ts b/apps/mana/apps/web/src/lib/modules/broadcast/render/email-html.test.ts new file mode 100644 index 000000000..2b16487e8 --- /dev/null +++ b/apps/mana/apps/web/src/lib/modules/broadcast/render/email-html.test.ts @@ -0,0 +1,134 @@ +import { describe, it, expect } from 'vitest'; +import { renderEmailHtml } from './email-html'; + +const campaign = { + subject: 'Hallo Welt', + preheader: 'Ein kurzer Vorschautext', + fromName: 'Till', + fromEmail: 'till@example.ch', +}; + +const settings = { + defaultFooter: 'Weitere Infos auf mana.how', + legalAddress: 'Till AG\nBahnhofstr. 1\n8000 Zürich', +}; + +describe('renderEmailHtml', () => { + it('produces a full HTML document', () => { + const html = renderEmailHtml({ + tiptapHtml: '

Hallo

', + campaign, + settings, + }); + expect(html.toLowerCase()).toContain(''); + expect(html).toContain(''); + }); + + it('includes the subject as the document title', () => { + const html = renderEmailHtml({ + tiptapHtml: '

body

', + campaign, + settings, + }); + expect(html).toContain('Hallo Welt'); + }); + + it('HTML-escapes the subject to prevent injection', () => { + const html = renderEmailHtml({ + tiptapHtml: '

body

', + campaign: { ...campaign, subject: 'Alert ' }, + settings, + }); + expect(html).not.toContain('