From c4565da50a4ee2eab100af289c88a92b29a2b71e Mon Sep 17 00:00:00 2001 From: Dmytro Hryshyn Date: Wed, 29 Nov 2023 15:18:00 +0200 Subject: [PATCH] chore: migrate trpc, ssgInit, ssrInit --- apps/web/app/_trpc/createTRPCNextLayout.ts | 212 ++++++++++++++++++ apps/web/app/_trpc/serverClient.ts | 3 + apps/web/app/_trpc/ssgInit.ts | 34 +++ apps/web/app/_trpc/ssrInit.ts | 50 +++++ apps/web/next.config.js | 5 + apps/web/pages/api/email.ts | 2 +- .../emails/templates/response-email.ts | 4 +- packages/emails/README.md | 2 +- packages/emails/email-manager.ts | 46 +--- packages/emails/src/renderEmail.ts | 5 +- .../AdminOrganizationNotificationEmail.tsx | 2 + .../src/templates/BrokenIntegrationEmail.tsx | 2 + .../src/templates/SlugReplacementEmail.tsx | 2 + .../emails/src/templates/TeamInviteEmail.tsx | 8 +- packages/emails/templates/_base-email.ts | 19 +- .../emails/templates/account-verify-email.ts | 4 +- .../admin-organization-notification.ts | 4 +- .../attendee-awaiting-payment-email.ts | 4 +- .../templates/attendee-cancelled-email.ts | 4 +- .../attendee-cancelled-seat-email.ts | 4 +- ...ee-daily-video-download-recording-email.ts | 4 +- .../templates/attendee-declined-email.ts | 4 +- .../attendee-location-change-email.ts | 4 +- .../templates/attendee-request-email.ts | 4 +- .../templates/attendee-rescheduled-email.ts | 4 +- .../templates/attendee-scheduled-email.ts | 4 +- .../emails/templates/attendee-verify-email.ts | 4 +- ...endee-was-requested-to-reschedule-email.ts | 4 +- .../templates/broken-integration-email.ts | 4 +- .../emails/templates/disabled-app-email.ts | 6 +- packages/emails/templates/feedback-email.ts | 4 +- .../emails/templates/forgot-password-email.ts | 4 +- .../emails/templates/monthly-digest-email.ts | 4 +- .../templates/no-show-fee-charged-email.ts | 4 +- .../emails/templates/org-auto-join-invite.ts | 4 +- .../organization-email-verification.ts | 4 +- ...organizer-attendee-cancelled-seat-email.ts | 4 +- .../templates/organizer-cancelled-email.ts | 4 +- ...er-daily-video-download-recording-email.ts | 4 +- .../organizer-location-change-email.ts | 4 +- .../organizer-payment-refund-failed-email.ts | 4 +- .../templates/organizer-request-email.ts | 4 +- .../organizer-request-reminder-email.ts | 4 +- ...organizer-requested-to-reschedule-email.ts | 4 +- .../templates/organizer-rescheduled-email.ts | 4 +- .../templates/organizer-scheduled-email.ts | 4 +- .../templates/slug-replacement-email.ts | 4 +- .../emails/templates/team-invite-email.ts | 4 +- 48 files changed, 402 insertions(+), 128 deletions(-) create mode 100644 apps/web/app/_trpc/createTRPCNextLayout.ts create mode 100644 apps/web/app/_trpc/serverClient.ts create mode 100644 apps/web/app/_trpc/ssgInit.ts create mode 100644 apps/web/app/_trpc/ssrInit.ts diff --git a/apps/web/app/_trpc/createTRPCNextLayout.ts b/apps/web/app/_trpc/createTRPCNextLayout.ts new file mode 100644 index 00000000000000..646257bd132856 --- /dev/null +++ b/apps/web/app/_trpc/createTRPCNextLayout.ts @@ -0,0 +1,212 @@ +// originally from in the "experimental playground for tRPC + next.js 13" repo owned by trpc team +// file link: https://github.com/trpc/next-13/blob/main/%40trpc/next-layout/createTRPCNextLayout.ts +// repo link: https://github.com/trpc/next-13 +// code is / will continue to be adapted for our usage +import { dehydrate, QueryClient } from "@tanstack/query-core"; +import type { DehydratedState, QueryKey } from "@tanstack/react-query"; + +import type { Maybe, TRPCClientError, TRPCClientErrorLike } from "@calcom/trpc"; +import { + callProcedure, + type AnyProcedure, + type AnyQueryProcedure, + type AnyRouter, + type DataTransformer, + type inferProcedureInput, + type inferProcedureOutput, + type inferRouterContext, + type MaybePromise, + type ProcedureRouterRecord, +} from "@calcom/trpc/server"; + +import { createRecursiveProxy, createFlatProxy } from "@trpc/server/shared"; + +export function getArrayQueryKey( + queryKey: string | [string] | [string, ...unknown[]] | unknown[], + type: string +): QueryKey { + const queryKeyArrayed = Array.isArray(queryKey) ? queryKey : [queryKey]; + const [arrayPath, input] = queryKeyArrayed; + + if (!input && (!type || type === "any")) { + return arrayPath.length ? [arrayPath] : ([] as unknown as QueryKey); + } + + return [ + arrayPath, + { + ...(typeof input !== "undefined" && { input: input }), + ...(type && type !== "any" && { type: type }), + }, + ]; +} + +// copy starts +// copied from trpc/trpc repo +// ref: https://github.com/trpc/trpc/blob/main/packages/next/src/withTRPC.tsx#L37-#L58 +function transformQueryOrMutationCacheErrors< + TState extends DehydratedState["queries"][0] | DehydratedState["mutations"][0] +>(result: TState): TState { + const error = result.state.error as Maybe>; + if (error instanceof Error && error.name === "TRPCClientError") { + const newError: TRPCClientErrorLike = { + message: error.message, + data: error.data, + shape: error.shape, + }; + return { + ...result, + state: { + ...result.state, + error: newError, + }, + }; + } + return result; +} +// copy ends + +interface CreateTRPCNextLayoutOptions { + router: TRouter; + createContext: () => MaybePromise>; + transformer?: DataTransformer; +} + +/** + * @internal + */ +export type DecorateProcedure = TProcedure extends AnyQueryProcedure + ? { + fetch(input: inferProcedureInput): Promise>; + fetchInfinite(input: inferProcedureInput): Promise>; + prefetch(input: inferProcedureInput): Promise>; + prefetchInfinite(input: inferProcedureInput): Promise>; + } + : never; + +type OmitNever = Pick< + TType, + { + [K in keyof TType]: TType[K] extends never ? never : K; + }[keyof TType] +>; +/** + * @internal + */ +export type DecoratedProcedureRecord< + TProcedures extends ProcedureRouterRecord, + TPath extends string = "" +> = OmitNever<{ + [TKey in keyof TProcedures]: TProcedures[TKey] extends AnyRouter + ? DecoratedProcedureRecord + : TProcedures[TKey] extends AnyQueryProcedure + ? DecorateProcedure + : never; +}>; + +type CreateTRPCNextLayout = DecoratedProcedureRecord & { + dehydrate(): Promise; + queryClient: QueryClient; +}; + +const getStateContainer = (opts: CreateTRPCNextLayoutOptions) => { + let _trpc: { + queryClient: QueryClient; + context: inferRouterContext; + } | null = null; + + return () => { + if (_trpc === null) { + _trpc = { + context: opts.createContext(), + queryClient: new QueryClient(), + }; + } + + return _trpc; + }; +}; + +export function createTRPCNextLayout( + opts: CreateTRPCNextLayoutOptions +): CreateTRPCNextLayout { + const getState = getStateContainer(opts); + + const transformer = opts.transformer ?? { + serialize: (v) => v, + deserialize: (v) => v, + }; + + return createFlatProxy((key) => { + const state = getState(); + const { queryClient } = state; + if (key === "queryClient") { + return queryClient; + } + + if (key === "dehydrate") { + // copy starts + // copied from trpc/trpc repo + // ref: https://github.com/trpc/trpc/blob/main/packages/next/src/withTRPC.tsx#L214-#L229 + const dehydratedCache = dehydrate(queryClient, { + shouldDehydrateQuery() { + // makes sure errors are also dehydrated + return true; + }, + }); + + // since error instances can't be serialized, let's make them into `TRPCClientErrorLike`-objects + const dehydratedCacheWithErrors = { + ...dehydratedCache, + queries: dehydratedCache.queries.map(transformQueryOrMutationCacheErrors), + mutations: dehydratedCache.mutations.map(transformQueryOrMutationCacheErrors), + }; + + return () => transformer.serialize(dehydratedCacheWithErrors); + } + // copy ends + + return createRecursiveProxy(async (callOpts) => { + const path = [key, ...callOpts.path]; + const utilName = path.pop(); + const ctx = await state.context; + + const caller = opts.router.createCaller(ctx); + + const pathStr = path.join("."); + const input = callOpts.args[0]; + + if (utilName === "fetchInfinite") { + return queryClient.fetchInfiniteQuery(getArrayQueryKey([path, input], "infinite"), () => + caller.query(pathStr, input) + ); + } + + if (utilName === "prefetch") { + return queryClient.prefetchQuery({ + queryKey: getArrayQueryKey([path, input], "query"), + queryFn: async () => { + const res = await callProcedure({ + procedures: opts.router._def.procedures, + path: pathStr, + rawInput: input, + ctx, + type: "query", + }); + return res; + }, + }); + } + + if (utilName === "prefetchInfinite") { + return queryClient.prefetchInfiniteQuery(getArrayQueryKey([path, input], "infinite"), () => + caller.query(pathStr, input) + ); + } + + return queryClient.fetchQuery(getArrayQueryKey([path, input], "query"), () => + caller.query(pathStr, input) + ); + }) as CreateTRPCNextLayout; + }); +} diff --git a/apps/web/app/_trpc/serverClient.ts b/apps/web/app/_trpc/serverClient.ts new file mode 100644 index 00000000000000..bf453ccd2b4968 --- /dev/null +++ b/apps/web/app/_trpc/serverClient.ts @@ -0,0 +1,3 @@ +import { appRouter } from "@calcom/trpc/server/routers/_app"; + +export const serverClient = appRouter.createCaller({}); diff --git a/apps/web/app/_trpc/ssgInit.ts b/apps/web/app/_trpc/ssgInit.ts new file mode 100644 index 00000000000000..cd8929541b1bc4 --- /dev/null +++ b/apps/web/app/_trpc/ssgInit.ts @@ -0,0 +1,34 @@ +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { headers } from "next/headers"; +import superjson from "superjson"; + +import { CALCOM_VERSION } from "@calcom/lib/constants"; +import prisma from "@calcom/prisma"; +import { appRouter } from "@calcom/trpc/server/routers/_app"; + +import { createTRPCNextLayout } from "./createTRPCNextLayout"; + +export async function ssgInit() { + const locale = headers().get("x-locale") ?? "en"; + + const i18n = (await serverSideTranslations(locale, ["common"])) || "en"; + + const ssg = createTRPCNextLayout({ + router: appRouter, + transformer: superjson, + createContext() { + return { prisma, session: null, locale, i18n }; + }, + }); + + // i18n translations are already retrieved from serverSideTranslations call, there is no need to run a i18n.fetch + // we can set query data directly to the queryClient + const queryKey = [ + ["viewer", "public", "i18n"], + { input: { locale, CalComVersion: CALCOM_VERSION }, type: "query" }, + ]; + + ssg.queryClient.setQueryData(queryKey, { i18n }); + + return ssg; +} diff --git a/apps/web/app/_trpc/ssrInit.ts b/apps/web/app/_trpc/ssrInit.ts new file mode 100644 index 00000000000000..ce6f89cd9a03db --- /dev/null +++ b/apps/web/app/_trpc/ssrInit.ts @@ -0,0 +1,50 @@ +import { type GetServerSidePropsContext } from "next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { headers, cookies } from "next/headers"; +import superjson from "superjson"; + +import { getLocale } from "@calcom/features/auth/lib/getLocale"; +import { CALCOM_VERSION } from "@calcom/lib/constants"; +import prisma from "@calcom/prisma"; +import { appRouter } from "@calcom/trpc/server/routers/_app"; + +import { createTRPCNextLayout } from "./createTRPCNextLayout"; + +export async function ssrInit(options?: { noI18nPreload: boolean }) { + const req = { + headers: headers(), + cookies: cookies(), + }; + + const locale = await getLocale(req); + + const i18n = (await serverSideTranslations(locale, ["common", "vital"])) || "en"; + + const ssr = createTRPCNextLayout({ + router: appRouter, + transformer: superjson, + createContext() { + return { prisma, session: null, locale, i18n, req: req as unknown as GetServerSidePropsContext["req"] }; + }, + }); + + // i18n translations are already retrieved from serverSideTranslations call, there is no need to run a i18n.fetch + // we can set query data directly to the queryClient + const queryKey = [ + ["viewer", "public", "i18n"], + { input: { locale, CalComVersion: CALCOM_VERSION }, type: "query" }, + ]; + if (!options?.noI18nPreload) { + ssr.queryClient.setQueryData(queryKey, { i18n }); + } + + await Promise.allSettled([ + // So feature flags are available on first render + ssr.viewer.features.map.prefetch(), + // Provides a better UX to the users who have already upgraded. + ssr.viewer.teams.hasTeamPlan.prefetch(), + ssr.viewer.public.session.prefetch(), + ]); + + return ssr; +} diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 24d6ceb2fcf091..f65204aa727257 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -154,6 +154,9 @@ const matcherConfigUserTypeEmbedRoute = { /** @type {import("next").NextConfig} */ const nextConfig = { + experimental: { + serverComponentsExternalPackages: ["next-i18next"], + }, i18n: { ...i18n, localeDetection: false, @@ -231,6 +234,8 @@ const nextConfig = { ...config.resolve.fallback, // if you miss it, all the other options in fallback, specified // by next.js will be dropped. Doesn't make much sense, but how it is fs: false, + "pg-native": false, + "superagent-proxy": false, }; /** diff --git a/apps/web/pages/api/email.ts b/apps/web/pages/api/email.ts index b855eccee2f1be..9ca6337d3217a4 100644 --- a/apps/web/pages/api/email.ts +++ b/apps/web/pages/api/email.ts @@ -13,7 +13,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { res.setHeader("Content-Type", "text/html"); res.setHeader("Cache-Control", "no-cache, no-store, private, must-revalidate"); res.write( - renderEmail("MonthlyDigestEmail", { + await renderEmail("MonthlyDigestEmail", { language: t, Created: 12, Completed: 13, diff --git a/packages/app-store/routing-forms/emails/templates/response-email.ts b/packages/app-store/routing-forms/emails/templates/response-email.ts index 0fa84b8ae63ba9..16e421184d56fe 100644 --- a/packages/app-store/routing-forms/emails/templates/response-email.ts +++ b/packages/app-store/routing-forms/emails/templates/response-email.ts @@ -25,14 +25,14 @@ export default class ResponseEmail extends BaseEmail { this.toAddresses = toAddresses; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = this.toAddresses; const subject = `${this.form.name} has a new response`; return { from: `Cal.com <${this.getMailerOptions().from}>`, to: toAddresses.join(","), subject, - html: renderEmail("ResponseEmail", { + html: await renderEmail("ResponseEmail", { form: this.form, orderedResponses: this.orderedResponses, subject, diff --git a/packages/emails/README.md b/packages/emails/README.md index 520b7e1ffd0bf2..ea27acba56541d 100644 --- a/packages/emails/README.md +++ b/packages/emails/README.md @@ -8,7 +8,7 @@ ```ts import { renderEmail } from "@calcom/emails"; -renderEmail("TeamInviteEmail", */{ +await renderEmail("TeamInviteEmail", */{ language: t, from: "teampro@example.com", to: "pro@example.com", diff --git a/packages/emails/email-manager.ts b/packages/emails/email-manager.ts index 8774278fa1fd53..8a8f5bd799b263 100644 --- a/packages/emails/email-manager.ts +++ b/packages/emails/email-manager.ts @@ -87,7 +87,6 @@ export const sendScheduledEmails = async ( new AttendeeScheduledEmail( { ...calEvent, - ...(calEvent.hideCalendarNotes && { additionalNotes: undefined }), ...(eventNameObject && { title: getEventName({ ...eventNameObject, t: attendee.language.translate }), }), @@ -102,37 +101,6 @@ export const sendScheduledEmails = async ( await Promise.all(emailsToSend); }; -// for rescheduled round robin booking that assigned new members -export const sendRoundRobinScheduledEmails = async (calEvent: CalendarEvent, members: Person[]) => { - const emailsToSend: Promise[] = []; - - for (const teamMember of members) { - emailsToSend.push(sendEmail(() => new OrganizerScheduledEmail({ calEvent, teamMember }))); - } - - await Promise.all(emailsToSend); -}; - -export const sendRoundRobinRescheduledEmails = async (calEvent: CalendarEvent, members: Person[]) => { - const emailsToSend: Promise[] = []; - - for (const teamMember of members) { - emailsToSend.push(sendEmail(() => new OrganizerRescheduledEmail({ calEvent, teamMember }))); - } - - await Promise.all(emailsToSend); -}; - -export const sendRoundRobinCancelledEmails = async (calEvent: CalendarEvent, members: Person[]) => { - const emailsToSend: Promise[] = []; - - for (const teamMember of members) { - emailsToSend.push(sendEmail(() => new OrganizerCancelledEmail({ calEvent, teamMember }))); - } - - await Promise.all(emailsToSend); -}; - export const sendRescheduledEmails = async (calEvent: CalendarEvent) => { const emailsToSend: Promise[] = []; @@ -184,19 +152,7 @@ export const sendScheduledSeatsEmails = async ( } if (!attendeeEmailDisabled) { - emailsToSend.push( - sendEmail( - () => - new AttendeeScheduledEmail( - { - ...calEvent, - ...(calEvent.hideCalendarNotes && { additionalNotes: undefined }), - }, - invitee, - showAttendees - ) - ) - ); + emailsToSend.push(sendEmail(() => new AttendeeScheduledEmail(calEvent, invitee, showAttendees))); } await Promise.all(emailsToSend); }; diff --git a/packages/emails/src/renderEmail.ts b/packages/emails/src/renderEmail.ts index 4404c94a472824..4ada467b557fd6 100644 --- a/packages/emails/src/renderEmail.ts +++ b/packages/emails/src/renderEmail.ts @@ -1,12 +1,11 @@ -import * as ReactDOMServer from "react-dom/server"; - import * as templates from "./templates"; -function renderEmail( +async function renderEmail( template: K, props: React.ComponentProps<(typeof templates)[K]> ) { const Component = templates[template]; + const ReactDOMServer = (await import("react-dom/server")).default; return ( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error diff --git a/packages/emails/src/templates/AdminOrganizationNotificationEmail.tsx b/packages/emails/src/templates/AdminOrganizationNotificationEmail.tsx index 1449a2ed98954e..b6e9198e56f08e 100644 --- a/packages/emails/src/templates/AdminOrganizationNotificationEmail.tsx +++ b/packages/emails/src/templates/AdminOrganizationNotificationEmail.tsx @@ -1,3 +1,5 @@ +"use client"; + import { Trans, type TFunction } from "next-i18next"; import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/BrokenIntegrationEmail.tsx b/packages/emails/src/templates/BrokenIntegrationEmail.tsx index 4271d68c9108e6..d7ebe70026c383 100644 --- a/packages/emails/src/templates/BrokenIntegrationEmail.tsx +++ b/packages/emails/src/templates/BrokenIntegrationEmail.tsx @@ -1,3 +1,5 @@ +"use client"; + import type { TFunction } from "next-i18next"; import { Trans } from "react-i18next"; diff --git a/packages/emails/src/templates/SlugReplacementEmail.tsx b/packages/emails/src/templates/SlugReplacementEmail.tsx index 8a889456ef3ce1..c40ebdb55815eb 100644 --- a/packages/emails/src/templates/SlugReplacementEmail.tsx +++ b/packages/emails/src/templates/SlugReplacementEmail.tsx @@ -1,3 +1,5 @@ +"use client"; + import type { TFunction } from "next-i18next"; import { Trans } from "next-i18next"; diff --git a/packages/emails/src/templates/TeamInviteEmail.tsx b/packages/emails/src/templates/TeamInviteEmail.tsx index 4edc91c4e6603f..693acfa2e56c49 100644 --- a/packages/emails/src/templates/TeamInviteEmail.tsx +++ b/packages/emails/src/templates/TeamInviteEmail.tsx @@ -78,13 +78,13 @@ export const TeamInviteEmail = ( marginTop: "48px", lineHeightStep: "24px", }}> - {/* <> + <> {props.language("email_no_user_invite_steps_intro", { entity: props.language(props.isOrg ? "organization" : "team").toLowerCase(), })} - */} +

- {/* + {!props.isCalcomMember && (
- )} */} + )}

{ + protected async getNodeMailerPayload(): Promise> { return {}; } public async sendEmail() { @@ -38,17 +38,27 @@ export default class BaseEmail { if (process.env.INTEGRATION_TEST_MODE === "true") { // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-expect-error - setTestEmail(this.getNodeMailerPayload()); + setTestEmail(await this.getNodeMailerPayload()); console.log( "Skipped Sending Email as process.env.NEXT_PUBLIC_UNIT_TESTS is set. Emails are available in globalThis.testEmails" ); return new Promise((r) => r("Skipped sendEmail for Unit Tests")); } - const payload = this.getNodeMailerPayload(); + const payload = await this.getNodeMailerPayload(); const parseSubject = z.string().safeParse(payload?.subject); const payloadWithUnEscapedSubject = { - headers: this.getMailerOptions().headers, + headers: { + "X-SMTPAPI": JSON.stringify({ + filters: { + bypass_list_management: { + settings: { + enable: 1, + }, + }, + }, + }), + }, ...payload, ...(parseSubject.success && { subject: decodeHTML(parseSubject.data) }), }; @@ -74,7 +84,6 @@ export default class BaseEmail { return { transport: serverConfig.transport, from: serverConfig.from, - headers: serverConfig.headers, }; } diff --git a/packages/emails/templates/account-verify-email.ts b/packages/emails/templates/account-verify-email.ts index 74a651ac00ee99..6f692898aa167e 100644 --- a/packages/emails/templates/account-verify-email.ts +++ b/packages/emails/templates/account-verify-email.ts @@ -23,14 +23,14 @@ export default class AccountVerifyEmail extends BaseEmail { this.verifyAccountInput = passwordEvent; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.verifyAccountInput.user.name} <${this.verifyAccountInput.user.email}>`, from: `${APP_NAME} <${this.getMailerOptions().from}>`, subject: this.verifyAccountInput.language("verify_email_subject", { appName: APP_NAME, }), - html: renderEmail("VerifyAccountEmail", this.verifyAccountInput), + html: await renderEmail("VerifyAccountEmail", this.verifyAccountInput), text: this.getTextBody(), }; } diff --git a/packages/emails/templates/admin-organization-notification.ts b/packages/emails/templates/admin-organization-notification.ts index 680add21d09e60..01b6f469ab875e 100644 --- a/packages/emails/templates/admin-organization-notification.ts +++ b/packages/emails/templates/admin-organization-notification.ts @@ -22,12 +22,12 @@ export default class AdminOrganizationNotification extends BaseEmail { this.input = input; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { from: `${APP_NAME} <${this.getMailerOptions().from}>`, to: this.input.instanceAdmins.map((admin) => admin.email).join(","), subject: `${this.input.t("admin_org_notification_email_subject")}`, - html: renderEmail("AdminOrganizationNotificationEmail", { + html: await renderEmail("AdminOrganizationNotificationEmail", { orgSlug: this.input.orgSlug, webappIPAddress: this.input.webappIPAddress, language: this.input.t, diff --git a/packages/emails/templates/attendee-awaiting-payment-email.ts b/packages/emails/templates/attendee-awaiting-payment-email.ts index 772b55c10b445c..24eef1262cceac 100644 --- a/packages/emails/templates/attendee-awaiting-payment-email.ts +++ b/packages/emails/templates/attendee-awaiting-payment-email.ts @@ -2,7 +2,7 @@ import { renderEmail } from "../"; import AttendeeScheduledEmail from "./attendee-scheduled-email"; export default class AttendeeAwaitingPaymentEmail extends AttendeeScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.attendee.name} <${this.attendee.email}>`, from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, @@ -11,7 +11,7 @@ export default class AttendeeAwaitingPaymentEmail extends AttendeeScheduledEmail title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("AttendeeAwaitingPaymentEmail", { + html: await renderEmail("AttendeeAwaitingPaymentEmail", { calEvent: this.calEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/attendee-cancelled-email.ts b/packages/emails/templates/attendee-cancelled-email.ts index ecc128cadccc07..e3cb71b54add6b 100644 --- a/packages/emails/templates/attendee-cancelled-email.ts +++ b/packages/emails/templates/attendee-cancelled-email.ts @@ -2,7 +2,7 @@ import { renderEmail } from "../"; import AttendeeScheduledEmail from "./attendee-scheduled-email"; export default class AttendeeCancelledEmail extends AttendeeScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.attendee.name} <${this.attendee.email}>`, from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, @@ -11,7 +11,7 @@ export default class AttendeeCancelledEmail extends AttendeeScheduledEmail { title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("AttendeeCancelledEmail", { + html: await renderEmail("AttendeeCancelledEmail", { calEvent: this.calEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/attendee-cancelled-seat-email.ts b/packages/emails/templates/attendee-cancelled-seat-email.ts index 396891800c5b1f..610274732e6dd7 100644 --- a/packages/emails/templates/attendee-cancelled-seat-email.ts +++ b/packages/emails/templates/attendee-cancelled-seat-email.ts @@ -2,7 +2,7 @@ import { renderEmail } from "../"; import AttendeeScheduledEmail from "./attendee-scheduled-email"; export default class AttendeeCancelledSeatEmail extends AttendeeScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.attendee.name} <${this.attendee.email}>`, from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, @@ -11,7 +11,7 @@ export default class AttendeeCancelledSeatEmail extends AttendeeScheduledEmail { title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("AttendeeCancelledSeatEmail", { + html: await renderEmail("AttendeeCancelledSeatEmail", { calEvent: this.calEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/attendee-daily-video-download-recording-email.ts b/packages/emails/templates/attendee-daily-video-download-recording-email.ts index 7fc0a74d5231c9..76cfaff69017ca 100644 --- a/packages/emails/templates/attendee-daily-video-download-recording-email.ts +++ b/packages/emails/templates/attendee-daily-video-download-recording-email.ts @@ -21,7 +21,7 @@ export default class AttendeeDailyVideoDownloadRecordingEmail extends BaseEmail this.downloadLink = downloadLink; this.t = attendee.language.translate; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.attendee.name} <${this.attendee.email}>`, from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, @@ -30,7 +30,7 @@ export default class AttendeeDailyVideoDownloadRecordingEmail extends BaseEmail title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("DailyVideoDownloadRecordingEmail", { + html: await renderEmail("DailyVideoDownloadRecordingEmail", { title: this.calEvent.title, date: this.getFormattedDate(), downloadLink: this.downloadLink, diff --git a/packages/emails/templates/attendee-declined-email.ts b/packages/emails/templates/attendee-declined-email.ts index 2d7fe6d33ba5c0..8ff713332cbabb 100644 --- a/packages/emails/templates/attendee-declined-email.ts +++ b/packages/emails/templates/attendee-declined-email.ts @@ -2,7 +2,7 @@ import { renderEmail } from "../"; import AttendeeScheduledEmail from "./attendee-scheduled-email"; export default class AttendeeDeclinedEmail extends AttendeeScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.attendee.name} <${this.attendee.email}>`, from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, @@ -11,7 +11,7 @@ export default class AttendeeDeclinedEmail extends AttendeeScheduledEmail { title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("AttendeeDeclinedEmail", { + html: await renderEmail("AttendeeDeclinedEmail", { calEvent: this.calEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/attendee-location-change-email.ts b/packages/emails/templates/attendee-location-change-email.ts index 925ba0806df7c0..af15fec058bd30 100644 --- a/packages/emails/templates/attendee-location-change-email.ts +++ b/packages/emails/templates/attendee-location-change-email.ts @@ -2,7 +2,7 @@ import { renderEmail } from "../"; import AttendeeScheduledEmail from "./attendee-scheduled-email"; export default class AttendeeLocationChangeEmail extends AttendeeScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { icalEvent: { filename: "event.ics", @@ -16,7 +16,7 @@ export default class AttendeeLocationChangeEmail extends AttendeeScheduledEmail name: this.calEvent.team?.name || this.calEvent.organizer.name, date: this.getFormattedDate(), })}`, - html: renderEmail("AttendeeLocationChangeEmail", { + html: await renderEmail("AttendeeLocationChangeEmail", { calEvent: this.calEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/attendee-request-email.ts b/packages/emails/templates/attendee-request-email.ts index 22367aaa501dc8..3f5d555b7c6832 100644 --- a/packages/emails/templates/attendee-request-email.ts +++ b/packages/emails/templates/attendee-request-email.ts @@ -4,7 +4,7 @@ import { renderEmail } from "../"; import AttendeeScheduledEmail from "./attendee-scheduled-email"; export default class AttendeeRequestEmail extends AttendeeScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = this.calEvent.attendees.map((attendee) => attendee.email); return { @@ -15,7 +15,7 @@ export default class AttendeeRequestEmail extends AttendeeScheduledEmail { title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("AttendeeRequestEmail", { + html: await renderEmail("AttendeeRequestEmail", { calEvent: this.calEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/attendee-rescheduled-email.ts b/packages/emails/templates/attendee-rescheduled-email.ts index 0c7e183335f88b..85bc7543caa207 100644 --- a/packages/emails/templates/attendee-rescheduled-email.ts +++ b/packages/emails/templates/attendee-rescheduled-email.ts @@ -2,7 +2,7 @@ import { renderEmail } from "../"; import AttendeeScheduledEmail from "./attendee-scheduled-email"; export default class AttendeeRescheduledEmail extends AttendeeScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { icalEvent: { filename: "event.ics", @@ -15,7 +15,7 @@ export default class AttendeeRescheduledEmail extends AttendeeScheduledEmail { title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("AttendeeRescheduledEmail", { + html: await renderEmail("AttendeeRescheduledEmail", { calEvent: this.calEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/attendee-scheduled-email.ts b/packages/emails/templates/attendee-scheduled-email.ts index 0d228911183985..c2dba8dcc5c163 100644 --- a/packages/emails/templates/attendee-scheduled-email.ts +++ b/packages/emails/templates/attendee-scheduled-email.ts @@ -82,7 +82,7 @@ export default class AttendeeScheduledEmail extends BaseEmail { return icsEvent.value; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const clonedCalEvent = cloneDeep(this.calEvent); this.getiCalEventAsString(); @@ -97,7 +97,7 @@ export default class AttendeeScheduledEmail extends BaseEmail { from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, replyTo: [...this.calEvent.attendees.map(({ email }) => email), this.calEvent.organizer.email], subject: `${this.calEvent.title}`, - html: renderEmail("AttendeeScheduledEmail", { + html: await renderEmail("AttendeeScheduledEmail", { calEvent: clonedCalEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/attendee-verify-email.ts b/packages/emails/templates/attendee-verify-email.ts index 99e9e3e31fb862..7919b8aa34de91 100644 --- a/packages/emails/templates/attendee-verify-email.ts +++ b/packages/emails/templates/attendee-verify-email.ts @@ -23,14 +23,14 @@ export default class AttendeeVerifyEmail extends BaseEmail { this.verifyAccountInput = passwordEvent; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.verifyAccountInput.user.name} <${this.verifyAccountInput.user.email}>`, from: `${APP_NAME} <${this.getMailerOptions().from}>`, subject: this.verifyAccountInput.language("verify_email_subject", { appName: APP_NAME, }), - html: renderEmail("VerifyEmailByCode", this.verifyAccountInput), + html: await renderEmail("VerifyEmailByCode", this.verifyAccountInput), text: this.getTextBody(), }; } diff --git a/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts b/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts index 184cbf4065d39b..e5f11807a9aa18 100644 --- a/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts +++ b/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts @@ -16,7 +16,7 @@ export default class AttendeeWasRequestedToRescheduleEmail extends OrganizerSche this.metadata = metadata; this.t = this.calEvent.attendees[0].language.translate; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.calEvent.attendees[0].email]; return { @@ -30,7 +30,7 @@ export default class AttendeeWasRequestedToRescheduleEmail extends OrganizerSche eventType: this.calEvent.type, name: this.calEvent.attendees[0].name, })}`, - html: renderEmail("AttendeeWasRequestedToRescheduleEmail", { + html: await renderEmail("AttendeeWasRequestedToRescheduleEmail", { calEvent: this.calEvent, attendee: this.calEvent.attendees[0], metadata: this.metadata, diff --git a/packages/emails/templates/broken-integration-email.ts b/packages/emails/templates/broken-integration-email.ts index 12d7800a895628..1cbba4c6f168e5 100644 --- a/packages/emails/templates/broken-integration-email.ts +++ b/packages/emails/templates/broken-integration-email.ts @@ -21,7 +21,7 @@ export default class BrokenIntegrationEmail extends BaseEmail { this.type = type; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.calEvent.organizer.email]; return { @@ -32,7 +32,7 @@ export default class BrokenIntegrationEmail extends BaseEmail { name: this.calEvent.attendees[0].name, date: this.getFormattedDate(), })}`, - html: renderEmail("BrokenIntegrationEmail", { + html: await renderEmail("BrokenIntegrationEmail", { calEvent: this.calEvent, attendee: this.calEvent.organizer, type: this.type, diff --git a/packages/emails/templates/disabled-app-email.ts b/packages/emails/templates/disabled-app-email.ts index 0a927a179c0a7f..724bed66e1fce2 100644 --- a/packages/emails/templates/disabled-app-email.ts +++ b/packages/emails/templates/disabled-app-email.ts @@ -1,4 +1,4 @@ -import { TFunction } from "next-i18next"; +import type { TFunction } from "next-i18next"; import { renderEmail } from ".."; import BaseEmail from "./_base-email"; @@ -28,7 +28,7 @@ export default class DisabledAppEmail extends BaseEmail { this.eventTypeId = eventTypeId; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { from: `Cal.com <${this.getMailerOptions().from}>`, to: this.email, @@ -36,7 +36,7 @@ export default class DisabledAppEmail extends BaseEmail { this.title && this.eventTypeId ? this.t("disabled_app_affects_event_type", { appName: this.appName, eventType: this.title }) : this.t("admin_has_disabled", { appName: this.appName }), - html: renderEmail("DisabledAppEmail", { + html: await renderEmail("DisabledAppEmail", { title: this.title, appName: this.appName, eventTypeId: this.eventTypeId, diff --git a/packages/emails/templates/feedback-email.ts b/packages/emails/templates/feedback-email.ts index e0dd9e5d0f733a..4eef2a9f34054c 100644 --- a/packages/emails/templates/feedback-email.ts +++ b/packages/emails/templates/feedback-email.ts @@ -18,12 +18,12 @@ export default class FeedbackEmail extends BaseEmail { this.feedback = feedback; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { from: `${APP_NAME} <${this.getMailerOptions().from}>`, to: process.env.SEND_FEEDBACK_EMAIL, subject: `User Feedback`, - html: renderEmail("FeedbackEmail", this.feedback), + html: await renderEmail("FeedbackEmail", this.feedback), text: this.getTextBody(), }; } diff --git a/packages/emails/templates/forgot-password-email.ts b/packages/emails/templates/forgot-password-email.ts index 6c21606cc69d3d..7f041693b71e62 100644 --- a/packages/emails/templates/forgot-password-email.ts +++ b/packages/emails/templates/forgot-password-email.ts @@ -23,14 +23,14 @@ export default class ForgotPasswordEmail extends BaseEmail { this.passwordEvent = passwordEvent; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.passwordEvent.user.name} <${this.passwordEvent.user.email}>`, from: `${APP_NAME} <${this.getMailerOptions().from}>`, subject: this.passwordEvent.language("reset_password_subject", { appName: APP_NAME, }), - html: renderEmail("ForgotPasswordEmail", this.passwordEvent), + html: await renderEmail("ForgotPasswordEmail", this.passwordEvent), text: this.getTextBody(), }; } diff --git a/packages/emails/templates/monthly-digest-email.ts b/packages/emails/templates/monthly-digest-email.ts index 5230732f3a175f..629b389329c668 100644 --- a/packages/emails/templates/monthly-digest-email.ts +++ b/packages/emails/templates/monthly-digest-email.ts @@ -12,12 +12,12 @@ export default class MonthlyDigestEmail extends BaseEmail { this.eventData = eventData; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { from: `${APP_NAME} <${this.getMailerOptions().from}>`, to: this.eventData.admin.email, subject: `${APP_NAME}: Your monthly digest`, - html: renderEmail("MonthlyDigestEmail", this.eventData), + html: await renderEmail("MonthlyDigestEmail", this.eventData), text: "", }; } diff --git a/packages/emails/templates/no-show-fee-charged-email.ts b/packages/emails/templates/no-show-fee-charged-email.ts index 500e4393eb233b..3ede12d7195ee0 100644 --- a/packages/emails/templates/no-show-fee-charged-email.ts +++ b/packages/emails/templates/no-show-fee-charged-email.ts @@ -2,7 +2,7 @@ import { renderEmail } from "../"; import AttendeeScheduledEmail from "./attendee-scheduled-email"; export default class NoShowFeeChargedEmail extends AttendeeScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { if (!this.calEvent.paymentInfo?.amount) throw new Error("No payment into"); return { to: `${this.attendee.name} <${this.attendee.email}>`, @@ -14,7 +14,7 @@ export default class NoShowFeeChargedEmail extends AttendeeScheduledEmail { amount: this.calEvent.paymentInfo.amount / 100, formatParams: { amount: { currency: this.calEvent.paymentInfo?.currency } }, })}`, - html: renderEmail("NoShowFeeChargedEmail", { + html: await renderEmail("NoShowFeeChargedEmail", { calEvent: this.calEvent, attendee: this.attendee, }), diff --git a/packages/emails/templates/org-auto-join-invite.ts b/packages/emails/templates/org-auto-join-invite.ts index 002ebf7482aa75..64a2811ec66681 100644 --- a/packages/emails/templates/org-auto-join-invite.ts +++ b/packages/emails/templates/org-auto-join-invite.ts @@ -22,7 +22,7 @@ export default class OrgAutoJoinEmail extends BaseEmail { this.orgAutoInviteEvent = orgAutoInviteEvent; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: this.orgAutoInviteEvent.to, from: `${APP_NAME} <${this.getMailerOptions().from}>`, @@ -32,7 +32,7 @@ export default class OrgAutoJoinEmail extends BaseEmail { appName: APP_NAME, entity: this.orgAutoInviteEvent.language("organization").toLowerCase(), }), - html: renderEmail("OrgAutoInviteEmail", this.orgAutoInviteEvent), + html: await renderEmail("OrgAutoInviteEmail", this.orgAutoInviteEvent), text: "", }; } diff --git a/packages/emails/templates/organization-email-verification.ts b/packages/emails/templates/organization-email-verification.ts index cfbc591df6c38a..89cfec56f48ecf 100644 --- a/packages/emails/templates/organization-email-verification.ts +++ b/packages/emails/templates/organization-email-verification.ts @@ -22,12 +22,12 @@ export default class OrganizationEmailVerification extends BaseEmail { this.orgVerifyInput = orgVerifyInput; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { from: `${APP_NAME} <${this.getMailerOptions().from}>`, to: this.orgVerifyInput.user.email, subject: this.orgVerifyInput.language("verify_email_organization"), - html: renderEmail("OrganisationAccountVerifyEmail", this.orgVerifyInput), + html: await renderEmail("OrganisationAccountVerifyEmail", this.orgVerifyInput), text: this.getTextBody(), }; } diff --git a/packages/emails/templates/organizer-attendee-cancelled-seat-email.ts b/packages/emails/templates/organizer-attendee-cancelled-seat-email.ts index fe6ce757265844..5fa17765b1bb9b 100644 --- a/packages/emails/templates/organizer-attendee-cancelled-seat-email.ts +++ b/packages/emails/templates/organizer-attendee-cancelled-seat-email.ts @@ -4,7 +4,7 @@ import { renderEmail } from "../"; import OrganizerScheduledEmail from "./organizer-scheduled-email"; export default class OrganizerCancelledEmail extends OrganizerScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.calEvent.organizer.email]; if (this.calEvent.team) { this.calEvent.team.members.forEach((member) => { @@ -22,7 +22,7 @@ export default class OrganizerCancelledEmail extends OrganizerScheduledEmail { title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("OrganizerAttendeeCancelledSeatEmail", { + html: await renderEmail("OrganizerAttendeeCancelledSeatEmail", { attendee: this.calEvent.organizer, calEvent: this.calEvent, }), diff --git a/packages/emails/templates/organizer-cancelled-email.ts b/packages/emails/templates/organizer-cancelled-email.ts index d0e2fb315cc4d9..3c3792e2a35bd5 100644 --- a/packages/emails/templates/organizer-cancelled-email.ts +++ b/packages/emails/templates/organizer-cancelled-email.ts @@ -4,7 +4,7 @@ import { renderEmail } from "../"; import OrganizerScheduledEmail from "./organizer-scheduled-email"; export default class OrganizerCancelledEmail extends OrganizerScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.teamMember?.email || this.calEvent.organizer.email]; return { @@ -14,7 +14,7 @@ export default class OrganizerCancelledEmail extends OrganizerScheduledEmail { title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("OrganizerCancelledEmail", { + html: await renderEmail("OrganizerCancelledEmail", { attendee: this.calEvent.organizer, calEvent: this.calEvent, }), diff --git a/packages/emails/templates/organizer-daily-video-download-recording-email.ts b/packages/emails/templates/organizer-daily-video-download-recording-email.ts index 714ba4f7e449af..34e1549132b60b 100644 --- a/packages/emails/templates/organizer-daily-video-download-recording-email.ts +++ b/packages/emails/templates/organizer-daily-video-download-recording-email.ts @@ -19,7 +19,7 @@ export default class OrganizerDailyVideoDownloadRecordingEmail extends BaseEmail this.downloadLink = downloadLink; this.t = this.calEvent.organizer.language.translate; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: `${this.calEvent.organizer.email}>`, from: `${APP_NAME} <${this.getMailerOptions().from}>`, @@ -28,7 +28,7 @@ export default class OrganizerDailyVideoDownloadRecordingEmail extends BaseEmail title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("DailyVideoDownloadRecordingEmail", { + html: await renderEmail("DailyVideoDownloadRecordingEmail", { title: this.calEvent.title, date: this.getFormattedDate(), downloadLink: this.downloadLink, diff --git a/packages/emails/templates/organizer-location-change-email.ts b/packages/emails/templates/organizer-location-change-email.ts index a0ed9e79934211..8eb1110e52f73a 100644 --- a/packages/emails/templates/organizer-location-change-email.ts +++ b/packages/emails/templates/organizer-location-change-email.ts @@ -4,7 +4,7 @@ import { renderEmail } from "../"; import OrganizerScheduledEmail from "./organizer-scheduled-email"; export default class OrganizerLocationChangeEmail extends OrganizerScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.teamMember?.email || this.calEvent.organizer.email]; return { @@ -20,7 +20,7 @@ export default class OrganizerLocationChangeEmail extends OrganizerScheduledEmai name: this.calEvent.attendees[0].name, date: this.getFormattedDate(), })}`, - html: renderEmail("OrganizerLocationChangeEmail", { + html: await renderEmail("OrganizerLocationChangeEmail", { attendee: this.calEvent.organizer, calEvent: this.calEvent, }), diff --git a/packages/emails/templates/organizer-payment-refund-failed-email.ts b/packages/emails/templates/organizer-payment-refund-failed-email.ts index 26818b1fd7a897..fd907ba1b52623 100644 --- a/packages/emails/templates/organizer-payment-refund-failed-email.ts +++ b/packages/emails/templates/organizer-payment-refund-failed-email.ts @@ -4,7 +4,7 @@ import { renderEmail } from "../"; import OrganizerScheduledEmail from "./organizer-scheduled-email"; export default class OrganizerPaymentRefundFailedEmail extends OrganizerScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.teamMember?.email || this.calEvent.organizer.email]; return { @@ -15,7 +15,7 @@ export default class OrganizerPaymentRefundFailedEmail extends OrganizerSchedule name: this.calEvent.attendees[0].name, date: this.getFormattedDate(), })}`, - html: renderEmail("OrganizerPaymentRefundFailedEmail", { + html: await renderEmail("OrganizerPaymentRefundFailedEmail", { calEvent: this.calEvent, attendee: this.calEvent.organizer, }), diff --git a/packages/emails/templates/organizer-request-email.ts b/packages/emails/templates/organizer-request-email.ts index 0267df22612563..47b82627f5715c 100644 --- a/packages/emails/templates/organizer-request-email.ts +++ b/packages/emails/templates/organizer-request-email.ts @@ -4,7 +4,7 @@ import { renderEmail } from "../"; import OrganizerScheduledEmail from "./organizer-scheduled-email"; export default class OrganizerRequestEmail extends OrganizerScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.teamMember?.email || this.calEvent.organizer.email]; return { @@ -12,7 +12,7 @@ export default class OrganizerRequestEmail extends OrganizerScheduledEmail { to: toAddresses.join(","), replyTo: [this.calEvent.organizer.email, ...this.calEvent.attendees.map(({ email }) => email)], subject: `${this.t("awaiting_approval")}: ${this.calEvent.title}`, - html: renderEmail("OrganizerRequestEmail", { + html: await renderEmail("OrganizerRequestEmail", { calEvent: this.calEvent, attendee: this.calEvent.organizer, }), diff --git a/packages/emails/templates/organizer-request-reminder-email.ts b/packages/emails/templates/organizer-request-reminder-email.ts index b9f2c1b53c4f94..b8d5130a7acba0 100644 --- a/packages/emails/templates/organizer-request-reminder-email.ts +++ b/packages/emails/templates/organizer-request-reminder-email.ts @@ -4,7 +4,7 @@ import { renderEmail } from "../"; import OrganizerRequestEmail from "./organizer-request-email"; export default class OrganizerRequestReminderEmail extends OrganizerRequestEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.teamMember?.email || this.calEvent.organizer.email]; return { @@ -15,7 +15,7 @@ export default class OrganizerRequestReminderEmail extends OrganizerRequestEmail title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("OrganizerRequestReminderEmail", { + html: await renderEmail("OrganizerRequestReminderEmail", { calEvent: this.calEvent, attendee: this.calEvent.organizer, }), diff --git a/packages/emails/templates/organizer-requested-to-reschedule-email.ts b/packages/emails/templates/organizer-requested-to-reschedule-email.ts index 7a601af696876d..7f8bdfb2fb18f4 100644 --- a/packages/emails/templates/organizer-requested-to-reschedule-email.ts +++ b/packages/emails/templates/organizer-requested-to-reschedule-email.ts @@ -15,7 +15,7 @@ export default class OrganizerRequestedToRescheduleEmail extends OrganizerSchedu super({ calEvent }); this.metadata = metadata; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.calEvent.organizer.email]; return { @@ -30,7 +30,7 @@ export default class OrganizerRequestedToRescheduleEmail extends OrganizerSchedu name: this.calEvent.attendees[0].name, date: this.getFormattedDate(), })}`, - html: renderEmail("OrganizerRequestedToRescheduleEmail", { + html: await renderEmail("OrganizerRequestedToRescheduleEmail", { calEvent: this.calEvent, attendee: this.calEvent.organizer, }), diff --git a/packages/emails/templates/organizer-rescheduled-email.ts b/packages/emails/templates/organizer-rescheduled-email.ts index 26da823a1ebd9d..9dfa5fe9ba675a 100644 --- a/packages/emails/templates/organizer-rescheduled-email.ts +++ b/packages/emails/templates/organizer-rescheduled-email.ts @@ -4,7 +4,7 @@ import { renderEmail } from "../"; import OrganizerScheduledEmail from "./organizer-scheduled-email"; export default class OrganizerRescheduledEmail extends OrganizerScheduledEmail { - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const toAddresses = [this.teamMember?.email || this.calEvent.organizer.email]; return { @@ -19,7 +19,7 @@ export default class OrganizerRescheduledEmail extends OrganizerScheduledEmail { title: this.calEvent.title, date: this.getFormattedDate(), })}`, - html: renderEmail("OrganizerRescheduledEmail", { + html: await renderEmail("OrganizerRescheduledEmail", { calEvent: { ...this.calEvent, attendeeSeatId: undefined }, attendee: this.calEvent.organizer, }), diff --git a/packages/emails/templates/organizer-scheduled-email.ts b/packages/emails/templates/organizer-scheduled-email.ts index 76b036252e02f2..bd1a490e399a5c 100644 --- a/packages/emails/templates/organizer-scheduled-email.ts +++ b/packages/emails/templates/organizer-scheduled-email.ts @@ -70,7 +70,7 @@ export default class OrganizerScheduledEmail extends BaseEmail { return icsEvent.value; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { const clonedCalEvent = cloneDeep(this.calEvent); const toAddresses = [this.teamMember?.email || this.calEvent.organizer.email]; @@ -83,7 +83,7 @@ export default class OrganizerScheduledEmail extends BaseEmail { to: toAddresses.join(","), replyTo: [this.calEvent.organizer.email, ...this.calEvent.attendees.map(({ email }) => email)], subject: `${this.newSeat ? `${this.t("new_attendee")}: ` : ""}${this.calEvent.title}`, - html: renderEmail("OrganizerScheduledEmail", { + html: await renderEmail("OrganizerScheduledEmail", { calEvent: clonedCalEvent, attendee: this.calEvent.organizer, teamMember: this.teamMember, diff --git a/packages/emails/templates/slug-replacement-email.ts b/packages/emails/templates/slug-replacement-email.ts index c9316cb28dd6db..2a2655718d0064 100644 --- a/packages/emails/templates/slug-replacement-email.ts +++ b/packages/emails/templates/slug-replacement-email.ts @@ -19,12 +19,12 @@ export default class SlugReplacementEmail extends BaseEmail { this.t = t; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { from: `Cal.com <${this.getMailerOptions().from}>`, to: this.email, subject: this.t("email_subject_slug_replacement", { slug: this.slug }), - html: renderEmail("SlugReplacementEmail", { + html: await renderEmail("SlugReplacementEmail", { slug: this.slug, name: this.name, teamName: this.teamName || "", diff --git a/packages/emails/templates/team-invite-email.ts b/packages/emails/templates/team-invite-email.ts index d583f7dc966841..6d272bd22521df 100644 --- a/packages/emails/templates/team-invite-email.ts +++ b/packages/emails/templates/team-invite-email.ts @@ -24,7 +24,7 @@ export default class TeamInviteEmail extends BaseEmail { this.teamInviteEvent = teamInviteEvent; } - protected getNodeMailerPayload(): Record { + protected async getNodeMailerPayload(): Promise> { return { to: this.teamInviteEvent.to, from: `${APP_NAME} <${this.getMailerOptions().from}>`, @@ -36,7 +36,7 @@ export default class TeamInviteEmail extends BaseEmail { .language(this.teamInviteEvent.isOrg ? "organization" : "team") .toLowerCase(), }), - html: renderEmail("TeamInviteEmail", this.teamInviteEvent), + html: await renderEmail("TeamInviteEmail", this.teamInviteEvent), text: "", }; }