From 80662c5da4451ccbfa6d66d14ebfaa97cfb5057d Mon Sep 17 00:00:00 2001 From: Karl Ludwig Weise Date: Fri, 21 Nov 2025 15:19:25 +0100 Subject: [PATCH] Added poc of new email renderer --- src/lib/emails/AppointmentBooked.svelte | 33 +++++++ src/lib/emails/components/EmailButton.svelte | 31 +++++++ src/lib/emails/components/EmailLayout.svelte | 88 +++++++++++++++++++ src/lib/emails/components/EmailText.svelte | 29 ++++++ src/lib/emails/utils.ts | 21 +++++ src/params/dev.ts | 7 ++ .../[test=dev]/e-mail-templates/+server.ts | 14 +++ src/server-hooks/i18nHandle.ts | 6 ++ 8 files changed, 229 insertions(+) create mode 100644 src/lib/emails/AppointmentBooked.svelte create mode 100644 src/lib/emails/components/EmailButton.svelte create mode 100644 src/lib/emails/components/EmailLayout.svelte create mode 100644 src/lib/emails/components/EmailText.svelte create mode 100644 src/lib/emails/utils.ts create mode 100644 src/params/dev.ts create mode 100644 src/routes/(local-only)/[test=dev]/e-mail-templates/+server.ts diff --git a/src/lib/emails/AppointmentBooked.svelte b/src/lib/emails/AppointmentBooked.svelte new file mode 100644 index 0000000..fd8ec61 --- /dev/null +++ b/src/lib/emails/AppointmentBooked.svelte @@ -0,0 +1,33 @@ + + + +

{m["absences.add.description"]()} {name},

+

your appointment has been booked.

+

Vaccination Appointment

+

+ Dr. John Doe
+ June 30, 2024
+ 10:00 AM - 10:15 AM +

+

Praxis Dr. Jane Doe

+

+ Musterstraße 10
+ Etage 4
+ 12345 Musterstadt +

+ View Appointments + + You are receiving this email because someone booked an appointment with your e-mail address. + +
diff --git a/src/lib/emails/components/EmailButton.svelte b/src/lib/emails/components/EmailButton.svelte new file mode 100644 index 0000000..e16724e --- /dev/null +++ b/src/lib/emails/components/EmailButton.svelte @@ -0,0 +1,31 @@ + + +
+ {@render children?.()} +
+ + + + diff --git a/src/lib/emails/components/EmailLayout.svelte b/src/lib/emails/components/EmailLayout.svelte new file mode 100644 index 0000000..04346b6 --- /dev/null +++ b/src/lib/emails/components/EmailLayout.svelte @@ -0,0 +1,88 @@ + + +
+
+
+
+ {@render children?.()} +
+
+
+ + Powered by OpenReception + +
+
+
+ + + + diff --git a/src/lib/emails/components/EmailText.svelte b/src/lib/emails/components/EmailText.svelte new file mode 100644 index 0000000..95734c9 --- /dev/null +++ b/src/lib/emails/components/EmailText.svelte @@ -0,0 +1,29 @@ + + +{@render children?.()} + + + + diff --git a/src/lib/emails/utils.ts b/src/lib/emails/utils.ts new file mode 100644 index 0000000..b7ce3f4 --- /dev/null +++ b/src/lib/emails/utils.ts @@ -0,0 +1,21 @@ +// is not exported from svelte +export type RenderOutput = { + head: string; + body: string; +}; + +export const renderOutputToHtml = (renderOutput: RenderOutput) => { + return ` + + + + + + ${renderOutput.head} + + + ${renderOutput.body} + + + `; +}; diff --git a/src/params/dev.ts b/src/params/dev.ts new file mode 100644 index 0000000..12653b8 --- /dev/null +++ b/src/params/dev.ts @@ -0,0 +1,7 @@ +import { dev } from "$app/environment"; +import type { ParamMatcher } from "@sveltejs/kit"; + +export const match: ParamMatcher = (param) => { + // Doesn't have to be include, but needs to return a boolean + return dev && param.includes("local-only"); +}; diff --git a/src/routes/(local-only)/[test=dev]/e-mail-templates/+server.ts b/src/routes/(local-only)/[test=dev]/e-mail-templates/+server.ts new file mode 100644 index 0000000..18d3e6b --- /dev/null +++ b/src/routes/(local-only)/[test=dev]/e-mail-templates/+server.ts @@ -0,0 +1,14 @@ +import AppointmentBooked from "$lib/emails/AppointmentBooked.svelte"; +import { renderOutputToHtml } from "$lib/emails/utils"; +import type { RequestHandler } from "@sveltejs/kit"; +import { render } from "svelte/server"; + +export const GET: RequestHandler = async () => { + const emailRender = render(AppointmentBooked, { props: { name: "John Doe", locale: "de" } }); + + return new Response(renderOutputToHtml(emailRender), { + headers: { + "Content-Type": "text/html", + }, + }); +}; diff --git a/src/server-hooks/i18nHandle.ts b/src/server-hooks/i18nHandle.ts index dd4d410..600e928 100644 --- a/src/server-hooks/i18nHandle.ts +++ b/src/server-hooks/i18nHandle.ts @@ -11,6 +11,12 @@ import type { Handle } from "@sveltejs/kit"; * @returns {Promise} The response with applied headers and rate limiting */ export const i18nHandle: Handle = ({ event, resolve }) => { + // Disable i18n for API and local-only routes + // Avoids using i18n middleware where emails are rendered + if (event.url.pathname.startsWith("/api") || event.url.pathname.startsWith("/local-only")) { + return resolve(event); + } + // Determine browser locale and use it const cookieLocale = event.cookies.get(cookieName); let locale: Locale | undefined = cookieLocale as Locale;