diff --git a/project.inlang/messages/de.json b/project.inlang/messages/de.json
index 80b619e..d0bbc76 100644
--- a/project.inlang/messages/de.json
+++ b/project.inlang/messages/de.json
@@ -951,6 +951,11 @@
"introduction": "Ihr Termin wurde abgelehnt.",
"reason": "Sie erhalten diese E-Mail, weil jemand mit Ihrer E-Mail Adresse einen Termin bei angefragt hat."
},
+ "appointmentCancelled": {
+ "subject": "Ihr Termin für {channel} bei {tenant} wurde abgesagt",
+ "introduction": "Ihr Termin wurde abgesagt.",
+ "reason": "Sie erhalten diese E-Mail, weil jemand mit Ihrer E-Mail Adresse einen Termin bei angefragt hat."
+ },
"confirmation": {
"subject": "E-Mail Adresse bestätigen",
"introduction": "willkommen bei unserem Terminbuchungsportal. Bitte bestätige Deine E-Mail Adresse.",
diff --git a/project.inlang/messages/en.json b/project.inlang/messages/en.json
index 8ae8457..3b5fc6e 100644
--- a/project.inlang/messages/en.json
+++ b/project.inlang/messages/en.json
@@ -960,6 +960,11 @@
"introduction": "your appointment was requested. You will be notified once it is confirmed.",
"reason": "You are receiving this email because someone requested an appointment with your e-mail address."
},
+ "appointmentCancelled": {
+ "subject": "Your appointment for {channel} at {tenant} was cancelled",
+ "introduction": "Your appointment was cancelled.",
+ "reason": "You are receiving this email because someone booked an appointment with your e-mail address."
+ },
"confirmation": {
"subject": "Confirm your E-Mail Address",
"introduction": "welcome our appointment booking platform. Please confirm your e-mail address.",
diff --git a/src/lib/emails/AppointmentCancelled.svelte b/src/lib/emails/AppointmentCancelled.svelte
new file mode 100644
index 0000000..3052fd1
--- /dev/null
+++ b/src/lib/emails/AppointmentCancelled.svelte
@@ -0,0 +1,63 @@
+
+
+
+ {m["emails.greeting"]({ name: user.email })}
+
+ {m["emails.appointmentCancelled.introduction"]()}
+
+ {channel}
+
+ {appointment.agentName}
+ {renderAppointmentDate(appointment.appointmentDate, locale)}
+ {renderAppointmentTime(appointment.appointmentDate, locale)}
+ {m["emails.oclock"]()}
+
+ {tenant.longName}
+
+ {address.street}
+ {address.number}
+ {#if address.additionalAddressInfo}{address.additionalAddressInfo}
{/if}
+ {address.zip}
+ {address.city}
+
+
+ {m["emails.appointmentCancelled.reason"]()}
+
+
diff --git a/src/lib/server/email/email-service.ts b/src/lib/server/email/email-service.ts
index 19a3c2b..8c1ba2d 100644
--- a/src/lib/server/email/email-service.ts
+++ b/src/lib/server/email/email-service.ts
@@ -15,6 +15,7 @@ import { m } from "$i18n/messages";
import { render } from "svelte/server";
import AppointmentBooked from "$lib/emails/AppointmentBooked.svelte";
import AppointmentRejected from "$lib/emails/AppointmentRejected.svelte";
+import AppointmentCancelled from "$lib/emails/AppointmentCancelled.svelte";
import { htmlToText, renderOutputToHtml } from "$lib/emails/utils";
import { AgentService } from "../services/agent-service";
import { TenantService } from "../db/tenant-service";
@@ -529,17 +530,25 @@ export async function sendAppointmentCancelledEmail(
channelTitle?: string,
): Promise {
// Create recipient directly for SelectClient type, use helper for SelectUser
- const recipient: EmailRecipient =
- "email" in user && typeof user.email === "string" && "language" in user && !("name" in user)
- ? { email: user.email, language: user.language }
- : createEmailRecipient(user);
-
- const language = (recipient.language as Language) || "en";
- const subject = language === "en" ? "Appointment Cancelled" : "Termin storniert";
-
- await sendTemplatedEmail("appointment-cancelled", recipient, subject, language, tenant, {
- appointment,
- appointmentDate: appointment.appointmentDate,
- title: channelTitle || appointment.channelId,
+ const { recipient, locale } = await getRecipient(user);
+ // Generate email
+ const subject = m["emails.appointmentCancelled.subject"]({
+ channel: channelTitle || appointment.channelId,
+ tenant: tenant.longName,
});
+ const emailRender = render(AppointmentCancelled, {
+ props: {
+ locale,
+ channel: channelTitle || appointment.channelId,
+ user,
+ tenant,
+ appointment: { ...appointment, agentName: "---" },
+ address: await getAddressFromTenant(tenant.id),
+ },
+ });
+ const html = renderOutputToHtml(emailRender);
+ const text = htmlToText(html);
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ await sendEmail(recipient as any, subject, html, text);
}
diff --git a/src/lib/server/services/appointment-service.ts b/src/lib/server/services/appointment-service.ts
index f9c27e7..fd3e533 100644
--- a/src/lib/server/services/appointment-service.ts
+++ b/src/lib/server/services/appointment-service.ts
@@ -282,7 +282,7 @@ export class AppointmentService {
public async cancelAppointment(id: string): Promise {
const log = logger.setContext("AppointmentService");
- log.debug("Confirming appointment by ID", { appointmentId: id, tenantId: this.tenantId });
+ log.debug("Cancelling appointment by ID", { appointmentId: id, tenantId: this.tenantId });
const db = await this.getDb();
const result = await db