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