* refactor: Split EmailManager into focused service files - Created separate service files for different email categories: - auth-email-service.ts: Authentication and verification emails - organization-email-service.ts: Organization and team emails - billing-email-service.ts: Payment and credit-related emails - integration-email-service.ts: Integration and app-related emails - workflow-email-service.ts: Workflow and custom emails - recording-email-service.ts: Recording and transcript emails - Refactored email-manager.ts to keep only core booking lifecycle functions - Removed unused imports from email-manager.ts - Updated index.ts to export from all new service files - Updated all imports across the codebase to use package root (@calcom/emails) - Fixed lint warnings in handleChildrenEventTypes.ts This reduces the import cost of EmailManager by allowing consumers to import only the specific email services they need. Co-Authored-By: morgan@cal.com <morgan@cal.com> * refactor: Update all imports to use direct service file paths - Update 49 files to import directly from service files instead of barrel file - Update packages/emails/index.ts to keep only email-manager and renderEmail exports - Fix dynamic import in passwordResetRequest.ts - Update renderEmail imports to use direct path - Update test file to import from specific service module - Fix ESLint warnings in modified files (unused variables, unused expressions) This ensures consumers only import the specific email services they need, reducing import cost by avoiding the barrel file pattern for service files. Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: Use default import for renderEmail renderEmail is exported as a default export, not a named export. Changed from 'import { renderEmail }' to 'import renderEmail'. Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: Update test mocks to use direct service file imports - Update handleNoShowFee.test.ts to mock @calcom/emails/billing-email-service - Update credit-service.test.ts to mock @calcom/emails/billing-email-service - These tests were failing because they were mocking the barrel file @calcom/emails which no longer exports service functions after the refactoring Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: unit test spy * fix: unit test mock * address cubic comments * fix: type error sendMonthlyDigestEmail * remove barrel file and sendEmail unused task * fixup! remove barrel file and sendEmail unused task * fixup! fixup! remove barrel file and sendEmail unused task * fix: integration test mock emails --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: hbjORbj <sldisek783@gmail.com>
654 lines
23 KiB
TypeScript
654 lines
23 KiB
TypeScript
import { default as cloneDeep } from "lodash/cloneDeep";
|
|
import type { z } from "zod";
|
|
|
|
import dayjs from "@calcom/dayjs";
|
|
import type BaseEmail from "@calcom/emails/templates/_base-email";
|
|
import type { EventNameObjectType } from "@calcom/features/eventtypes/lib/eventNaming";
|
|
import { getEventName } from "@calcom/features/eventtypes/lib/eventNaming";
|
|
import { formatCalEvent } from "@calcom/lib/formatCalendarEvent";
|
|
import logger from "@calcom/lib/logger";
|
|
import { safeStringify } from "@calcom/lib/safeStringify";
|
|
import { withReporting } from "@calcom/lib/sentryWrapper";
|
|
import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
|
import type { CalendarEvent, Person } from "@calcom/types/Calendar";
|
|
|
|
import AwaitingPaymentSMS from "../sms/attendee/awaiting-payment-sms";
|
|
import CancelledSeatSMS from "../sms/attendee/cancelled-seat-sms";
|
|
import EventCancelledSMS from "../sms/attendee/event-cancelled-sms";
|
|
import EventDeclinedSMS from "../sms/attendee/event-declined-sms";
|
|
import EventLocationChangedSMS from "../sms/attendee/event-location-changed-sms";
|
|
import EventRequestSMS from "../sms/attendee/event-request-sms";
|
|
import EventRequestToRescheduleSMS from "../sms/attendee/event-request-to-reschedule-sms";
|
|
import EventSuccessfullyReScheduledSMS from "../sms/attendee/event-rescheduled-sms";
|
|
import EventSuccessfullyScheduledSMS from "../sms/attendee/event-scheduled-sms";
|
|
import AttendeeAddGuestsEmail from "./templates/attendee-add-guests-email";
|
|
import AttendeeAwaitingPaymentEmail from "./templates/attendee-awaiting-payment-email";
|
|
import AttendeeCancelledEmail from "./templates/attendee-cancelled-email";
|
|
import AttendeeCancelledSeatEmail from "./templates/attendee-cancelled-seat-email";
|
|
import AttendeeDeclinedEmail from "./templates/attendee-declined-email";
|
|
import AttendeeLocationChangeEmail from "./templates/attendee-location-change-email";
|
|
import AttendeeRequestEmail from "./templates/attendee-request-email";
|
|
import AttendeeRescheduledEmail from "./templates/attendee-rescheduled-email";
|
|
import AttendeeScheduledEmail from "./templates/attendee-scheduled-email";
|
|
import AttendeeUpdatedEmail from "./templates/attendee-updated-email";
|
|
import AttendeeWasRequestedToRescheduleEmail from "./templates/attendee-was-requested-to-reschedule-email";
|
|
import OrganizerAddGuestsEmail from "./templates/organizer-add-guests-email";
|
|
import OrganizerAttendeeCancelledSeatEmail from "./templates/organizer-attendee-cancelled-seat-email";
|
|
import OrganizerCancelledEmail from "./templates/organizer-cancelled-email";
|
|
import OrganizerLocationChangeEmail from "./templates/organizer-location-change-email";
|
|
import OrganizerReassignedEmail from "./templates/organizer-reassigned-email";
|
|
import OrganizerRequestEmail from "./templates/organizer-request-email";
|
|
import OrganizerRequestReminderEmail from "./templates/organizer-request-reminder-email";
|
|
import OrganizerRequestedToRescheduleEmail from "./templates/organizer-requested-to-reschedule-email";
|
|
import OrganizerRescheduledEmail from "./templates/organizer-rescheduled-email";
|
|
import OrganizerScheduledEmail from "./templates/organizer-scheduled-email";
|
|
|
|
type EventTypeMetadata = z.infer<typeof EventTypeMetaDataSchema>;
|
|
|
|
const sendEmail = (prepare: () => BaseEmail) => {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
const email = prepare();
|
|
resolve(email.sendEmail());
|
|
} catch (e) {
|
|
reject(console.error(`${prepare.constructor.name}.sendEmail failed`, e));
|
|
}
|
|
});
|
|
};
|
|
|
|
const eventTypeDisableAttendeeEmail = (metadata?: EventTypeMetadata) => {
|
|
return !!metadata?.disableStandardEmails?.all?.attendee;
|
|
};
|
|
|
|
const eventTypeDisableHostEmail = (metadata?: EventTypeMetadata) => {
|
|
return !!metadata?.disableStandardEmails?.all?.host;
|
|
};
|
|
|
|
const _sendScheduledEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
eventNameObject?: EventNameObjectType,
|
|
hostEmailDisabled?: boolean,
|
|
attendeeEmailDisabled?: boolean,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const formattedCalEvent = formatCalEvent(calEvent);
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
if (!hostEmailDisabled && !eventTypeDisableHostEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(sendEmail(() => new OrganizerScheduledEmail({ calEvent: formattedCalEvent })));
|
|
|
|
if (formattedCalEvent.team) {
|
|
for (const teamMember of formattedCalEvent.team.members) {
|
|
emailsToSend.push(
|
|
sendEmail(() => new OrganizerScheduledEmail({ calEvent: formattedCalEvent, teamMember }))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!attendeeEmailDisabled && !eventTypeDisableAttendeeEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(
|
|
...formattedCalEvent.attendees.map((attendee) => {
|
|
return sendEmail(
|
|
() =>
|
|
new AttendeeScheduledEmail(
|
|
{
|
|
...formattedCalEvent,
|
|
...(formattedCalEvent.hideCalendarNotes && { additionalNotes: undefined }),
|
|
...(eventNameObject && {
|
|
title: getEventName({ ...eventNameObject, t: attendee.language.translate }),
|
|
}),
|
|
},
|
|
attendee
|
|
)
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
await Promise.all(emailsToSend);
|
|
const successfullyScheduledSms = new EventSuccessfullyScheduledSMS(calEvent);
|
|
await successfullyScheduledSms.sendSMSToAttendees();
|
|
};
|
|
|
|
export const sendScheduledEmailsAndSMS = withReporting(
|
|
_sendScheduledEmailsAndSMS,
|
|
"sendScheduledEmailsAndSMS"
|
|
);
|
|
|
|
// for rescheduled round robin booking that assigned new members
|
|
export const sendRoundRobinScheduledEmailsAndSMS = async ({
|
|
calEvent,
|
|
members,
|
|
eventTypeMetadata,
|
|
reassigned,
|
|
}: {
|
|
calEvent: CalendarEvent;
|
|
members: Person[];
|
|
eventTypeMetadata?: EventTypeMetadata;
|
|
reassigned?: { name: string | null; email: string; reason?: string; byUser?: string };
|
|
}) => {
|
|
if (eventTypeDisableHostEmail(eventTypeMetadata)) return;
|
|
const formattedCalEvent = formatCalEvent(calEvent);
|
|
const emailsAndSMSToSend: Promise<unknown>[] = [];
|
|
const eventScheduledSMS = new EventSuccessfullyScheduledSMS(calEvent);
|
|
|
|
for (const teamMember of members) {
|
|
emailsAndSMSToSend.push(
|
|
sendEmail(() => new OrganizerScheduledEmail({ calEvent: formattedCalEvent, teamMember, reassigned }))
|
|
);
|
|
if (teamMember.phoneNumber) {
|
|
emailsAndSMSToSend.push(eventScheduledSMS.sendSMSToAttendee(teamMember));
|
|
}
|
|
}
|
|
|
|
await Promise.all(emailsAndSMSToSend);
|
|
};
|
|
|
|
export const sendRoundRobinRescheduledEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
teamMembersAndAttendees: Person[],
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
const emailsAndSMSToSend: Promise<unknown>[] = [];
|
|
const successfullyReScheduledSMS = new EventSuccessfullyReScheduledSMS(calEvent);
|
|
|
|
for (const person of teamMembersAndAttendees) {
|
|
const isAttendee = calendarEvent.attendees.some((attendee) => attendee.email === person.email);
|
|
const isTeamMember = !!calendarEvent.team?.members.some((member) => member.email === person.email);
|
|
|
|
if (isAttendee && !isTeamMember) {
|
|
if (!eventTypeDisableAttendeeEmail(eventTypeMetadata)) {
|
|
emailsAndSMSToSend.push(sendEmail(() => new AttendeeRescheduledEmail(calendarEvent, person)));
|
|
if (person.phoneNumber) {
|
|
emailsAndSMSToSend.push(successfullyReScheduledSMS.sendSMSToAttendee(person));
|
|
}
|
|
}
|
|
} else if (!eventTypeDisableHostEmail(eventTypeMetadata)) {
|
|
emailsAndSMSToSend.push(
|
|
sendEmail(() => new OrganizerRescheduledEmail({ calEvent: calendarEvent, teamMember: person }))
|
|
);
|
|
if (person.phoneNumber) {
|
|
emailsAndSMSToSend.push(successfullyReScheduledSMS.sendSMSToAttendee(person));
|
|
}
|
|
}
|
|
}
|
|
|
|
await Promise.all(emailsAndSMSToSend);
|
|
};
|
|
|
|
export const sendRoundRobinUpdatedEmailsAndSMS = async ({
|
|
calEvent,
|
|
eventTypeMetadata,
|
|
}: {
|
|
calEvent: CalendarEvent;
|
|
eventTypeMetadata?: EventTypeMetadata;
|
|
}) => {
|
|
if (eventTypeDisableAttendeeEmail(eventTypeMetadata)) return;
|
|
|
|
const emailsToSend = calEvent.attendees.map((attendee) =>
|
|
sendEmail(() => new AttendeeUpdatedEmail(calEvent, attendee))
|
|
);
|
|
|
|
await Promise.all(emailsToSend);
|
|
};
|
|
|
|
export const sendRoundRobinCancelledEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
members: Person[],
|
|
eventTypeMetadata?: EventTypeMetadata,
|
|
reassignedTo?: { name: string | null; email: string; reason?: string }
|
|
) => {
|
|
if (eventTypeDisableHostEmail(eventTypeMetadata)) return;
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
const emailsAndSMSToSend: Promise<unknown>[] = [];
|
|
const successfullyReScheduledSMS = new EventCancelledSMS(calEvent);
|
|
for (const teamMember of members) {
|
|
emailsAndSMSToSend.push(
|
|
sendEmail(
|
|
() => new OrganizerCancelledEmail({ calEvent: calendarEvent, teamMember, reassigned: reassignedTo })
|
|
)
|
|
);
|
|
|
|
if (teamMember.phoneNumber) {
|
|
emailsAndSMSToSend.push(successfullyReScheduledSMS.sendSMSToAttendee(teamMember));
|
|
}
|
|
}
|
|
|
|
await Promise.all(emailsAndSMSToSend);
|
|
};
|
|
|
|
export const sendRoundRobinReassignedEmailsAndSMS = async (args: {
|
|
calEvent: CalendarEvent;
|
|
members: Person[];
|
|
reassignedTo: { name: string | null; email: string };
|
|
eventTypeMetadata?: EventTypeMetadata;
|
|
}) => {
|
|
const { calEvent, members, reassignedTo, eventTypeMetadata } = args;
|
|
if (eventTypeDisableHostEmail(eventTypeMetadata)) return;
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
const emailsAndSMSToSend: Promise<unknown>[] = [];
|
|
const successfullyReScheduledSMS = new EventCancelledSMS(calEvent);
|
|
for (const teamMember of members) {
|
|
emailsAndSMSToSend.push(
|
|
sendEmail(
|
|
() => new OrganizerReassignedEmail({ calEvent: calendarEvent, teamMember, reassigned: reassignedTo })
|
|
)
|
|
);
|
|
|
|
if (teamMember.phoneNumber) {
|
|
emailsAndSMSToSend.push(successfullyReScheduledSMS.sendSMSToAttendee(teamMember));
|
|
}
|
|
}
|
|
|
|
await Promise.all(emailsAndSMSToSend);
|
|
};
|
|
|
|
const _sendRescheduledEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
if (!eventTypeDisableHostEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(sendEmail(() => new OrganizerRescheduledEmail({ calEvent: calendarEvent })));
|
|
|
|
if (calendarEvent.team) {
|
|
for (const teamMember of calendarEvent.team.members) {
|
|
emailsToSend.push(
|
|
sendEmail(() => new OrganizerRescheduledEmail({ calEvent: calendarEvent, teamMember }))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!eventTypeDisableAttendeeEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(
|
|
...calendarEvent.attendees.map((attendee) => {
|
|
return sendEmail(() => new AttendeeRescheduledEmail(calendarEvent, attendee));
|
|
})
|
|
);
|
|
}
|
|
|
|
await Promise.all(emailsToSend);
|
|
const successfullyReScheduledSms = new EventSuccessfullyReScheduledSMS(calEvent);
|
|
await successfullyReScheduledSms.sendSMSToAttendees();
|
|
};
|
|
export const sendRescheduledEmailsAndSMS = withReporting(
|
|
_sendRescheduledEmailsAndSMS,
|
|
"sendRescheduledEmailsAndSMS"
|
|
);
|
|
|
|
export const sendRescheduledSeatEmailAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
attendee: Person,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
|
|
const clonedCalEvent = cloneDeep(calendarEvent);
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
if (!eventTypeDisableHostEmail(eventTypeMetadata))
|
|
emailsToSend.push(sendEmail(() => new OrganizerRescheduledEmail({ calEvent: calendarEvent })));
|
|
if (!eventTypeDisableAttendeeEmail(eventTypeMetadata))
|
|
emailsToSend.push(sendEmail(() => new AttendeeRescheduledEmail(clonedCalEvent, attendee)));
|
|
|
|
const successfullyReScheduledSMS = new EventSuccessfullyReScheduledSMS(calEvent);
|
|
await successfullyReScheduledSMS.sendSMSToAttendee(attendee);
|
|
|
|
await Promise.all(emailsToSend);
|
|
};
|
|
|
|
export const sendScheduledSeatsEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
invitee: Person,
|
|
newSeat: boolean,
|
|
showAttendees: boolean,
|
|
hostEmailDisabled?: boolean,
|
|
attendeeEmailDisabled?: boolean,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
if (!hostEmailDisabled && !eventTypeDisableHostEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(sendEmail(() => new OrganizerScheduledEmail({ calEvent: calendarEvent, newSeat })));
|
|
|
|
if (calendarEvent.team) {
|
|
for (const teamMember of calendarEvent.team.members) {
|
|
emailsToSend.push(
|
|
sendEmail(() => new OrganizerScheduledEmail({ calEvent: calendarEvent, newSeat, teamMember }))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!attendeeEmailDisabled && !eventTypeDisableAttendeeEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(
|
|
sendEmail(
|
|
() =>
|
|
new AttendeeScheduledEmail(
|
|
{
|
|
...calendarEvent,
|
|
...(calendarEvent.hideCalendarNotes && { additionalNotes: undefined }),
|
|
},
|
|
invitee,
|
|
showAttendees
|
|
)
|
|
)
|
|
);
|
|
}
|
|
await Promise.all(emailsToSend);
|
|
const eventScheduledSMS = new EventSuccessfullyScheduledSMS(calendarEvent);
|
|
await eventScheduledSMS.sendSMSToAttendee(invitee);
|
|
};
|
|
|
|
export const sendCancelledSeatEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
cancelledAttendee: Person,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const formattedCalEvent = formatCalEvent(calEvent);
|
|
const clonedCalEvent = cloneDeep(formattedCalEvent);
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
if (!eventTypeDisableAttendeeEmail(eventTypeMetadata))
|
|
emailsToSend.push(sendEmail(() => new AttendeeCancelledSeatEmail(clonedCalEvent, cancelledAttendee)));
|
|
if (!eventTypeDisableHostEmail(eventTypeMetadata))
|
|
emailsToSend.push(
|
|
sendEmail(
|
|
() =>
|
|
new OrganizerAttendeeCancelledSeatEmail({
|
|
calEvent: formattedCalEvent,
|
|
attendee: cancelledAttendee,
|
|
})
|
|
)
|
|
);
|
|
|
|
await Promise.all(emailsToSend);
|
|
const cancelledSeatSMS = new CancelledSeatSMS(clonedCalEvent);
|
|
await cancelledSeatSMS.sendSMSToAttendee(cancelledAttendee);
|
|
};
|
|
|
|
const _sendOrganizerRequestEmail = async (calEvent: CalendarEvent, eventTypeMetadata?: EventTypeMetadata) => {
|
|
if (eventTypeDisableHostEmail(eventTypeMetadata)) return;
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
emailsToSend.push(sendEmail(() => new OrganizerRequestEmail({ calEvent: calendarEvent })));
|
|
|
|
if (calendarEvent.team?.members) {
|
|
for (const teamMember of calendarEvent.team.members) {
|
|
emailsToSend.push(sendEmail(() => new OrganizerRequestEmail({ calEvent: calendarEvent, teamMember })));
|
|
}
|
|
}
|
|
|
|
await Promise.all(emailsToSend);
|
|
};
|
|
|
|
export const sendOrganizerRequestEmail = withReporting(
|
|
_sendOrganizerRequestEmail,
|
|
"sendOrganizerRequestEmail"
|
|
);
|
|
|
|
const _sendAttendeeRequestEmailAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
attendee: Person,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
if (eventTypeDisableAttendeeEmail(eventTypeMetadata)) return;
|
|
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
await sendEmail(() => new AttendeeRequestEmail(calendarEvent, attendee));
|
|
const eventRequestSms = new EventRequestSMS(calendarEvent);
|
|
await eventRequestSms.sendSMSToAttendee(attendee);
|
|
};
|
|
|
|
export const sendAttendeeRequestEmailAndSMS = withReporting(
|
|
_sendAttendeeRequestEmailAndSMS,
|
|
"sendAttendeeRequestEmailAndSMS"
|
|
);
|
|
|
|
export const sendDeclinedEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
if (eventTypeDisableAttendeeEmail(eventTypeMetadata)) return;
|
|
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
emailsToSend.push(
|
|
...calendarEvent.attendees.map((attendee) => {
|
|
return sendEmail(() => new AttendeeDeclinedEmail(calendarEvent, attendee));
|
|
})
|
|
);
|
|
|
|
await Promise.all(emailsToSend);
|
|
const eventDeclindedSms = new EventDeclinedSMS(calEvent);
|
|
await eventDeclindedSms.sendSMSToAttendees();
|
|
};
|
|
|
|
export const sendCancelledEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
eventNameObject: Pick<EventNameObjectType, "eventName">,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
const calEventLength = calendarEvent.length;
|
|
const eventDuration = dayjs(calEvent.endTime).diff(calEvent.startTime, "minutes");
|
|
|
|
if (typeof calEventLength !== "number") {
|
|
logger.error(
|
|
"`calEventLength` is not a number",
|
|
safeStringify({ calEventLength, calEventTitle: calEvent.title, bookingId: calEvent.bookingId })
|
|
);
|
|
}
|
|
|
|
if (!eventTypeDisableHostEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(sendEmail(() => new OrganizerCancelledEmail({ calEvent: calendarEvent })));
|
|
|
|
if (calendarEvent.team?.members) {
|
|
for (const teamMember of calendarEvent.team.members) {
|
|
emailsToSend.push(
|
|
sendEmail(() => new OrganizerCancelledEmail({ calEvent: calendarEvent, teamMember }))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!eventTypeDisableAttendeeEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(
|
|
...calendarEvent.attendees.map((attendee) => {
|
|
return sendEmail(
|
|
() =>
|
|
new AttendeeCancelledEmail(
|
|
{
|
|
...calendarEvent,
|
|
title: getEventName({
|
|
...eventNameObject,
|
|
t: attendee.language.translate,
|
|
attendeeName: attendee.name,
|
|
host: calendarEvent.organizer.name,
|
|
eventType: calendarEvent.title,
|
|
eventDuration,
|
|
...(calendarEvent.responses && { bookingFields: calendarEvent.responses }),
|
|
...(calendarEvent.location && { location: calendarEvent.location }),
|
|
}),
|
|
},
|
|
attendee
|
|
)
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
await Promise.all(emailsToSend);
|
|
const eventCancelledSms = new EventCancelledSMS(calEvent);
|
|
await eventCancelledSms.sendSMSToAttendees();
|
|
};
|
|
|
|
export const sendOrganizerRequestReminderEmail = async (
|
|
calEvent: CalendarEvent,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
if (eventTypeDisableHostEmail(eventTypeMetadata)) return;
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
emailsToSend.push(sendEmail(() => new OrganizerRequestReminderEmail({ calEvent: calendarEvent })));
|
|
|
|
if (calendarEvent.team?.members) {
|
|
for (const teamMember of calendarEvent.team.members) {
|
|
emailsToSend.push(
|
|
sendEmail(() => new OrganizerRequestReminderEmail({ calEvent: calendarEvent, teamMember }))
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
export const sendAwaitingPaymentEmailAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
if (eventTypeDisableAttendeeEmail(eventTypeMetadata)) return;
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
emailsToSend.push(
|
|
...calEvent.attendees.map((attendee) => {
|
|
return sendEmail(() => new AttendeeAwaitingPaymentEmail(calEvent, attendee));
|
|
})
|
|
);
|
|
await Promise.all(emailsToSend);
|
|
const awaitingPaymentSMS = new AwaitingPaymentSMS(calEvent);
|
|
await awaitingPaymentSMS.sendSMSToAttendees();
|
|
};
|
|
|
|
|
|
export const sendRequestRescheduleEmailAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
metadata: { rescheduleLink: string },
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
|
|
if (!eventTypeDisableHostEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(sendEmail(() => new OrganizerRequestedToRescheduleEmail(calendarEvent, metadata)));
|
|
}
|
|
if (!eventTypeDisableAttendeeEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(sendEmail(() => new AttendeeWasRequestedToRescheduleEmail(calendarEvent, metadata)));
|
|
}
|
|
|
|
await Promise.all(emailsToSend);
|
|
const eventRequestToReschedule = new EventRequestToRescheduleSMS(calendarEvent);
|
|
await eventRequestToReschedule.sendSMSToAttendees();
|
|
};
|
|
|
|
export const sendLocationChangeEmailsAndSMS = async (
|
|
calEvent: CalendarEvent,
|
|
eventTypeMetadata?: EventTypeMetadata
|
|
) => {
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
|
|
if (!eventTypeDisableHostEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(sendEmail(() => new OrganizerLocationChangeEmail({ calEvent: calendarEvent })));
|
|
|
|
if (calendarEvent.team?.members) {
|
|
for (const teamMember of calendarEvent.team.members) {
|
|
emailsToSend.push(
|
|
sendEmail(() => new OrganizerLocationChangeEmail({ calEvent: calendarEvent, teamMember }))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!eventTypeDisableAttendeeEmail(eventTypeMetadata)) {
|
|
emailsToSend.push(
|
|
...calendarEvent.attendees.map((attendee) => {
|
|
return sendEmail(() => new AttendeeLocationChangeEmail(calendarEvent, attendee));
|
|
})
|
|
);
|
|
}
|
|
|
|
await Promise.all(emailsToSend);
|
|
const eventLocationChangedSMS = new EventLocationChangedSMS(calendarEvent);
|
|
await eventLocationChangedSMS.sendSMSToAttendees();
|
|
};
|
|
export const sendAddGuestsEmails = async (calEvent: CalendarEvent, newGuests: string[]) => {
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
|
|
const emailsToSend: Promise<unknown>[] = [];
|
|
emailsToSend.push(sendEmail(() => new OrganizerAddGuestsEmail({ calEvent: calendarEvent })));
|
|
|
|
if (calendarEvent.team?.members) {
|
|
for (const teamMember of calendarEvent.team.members) {
|
|
emailsToSend.push(
|
|
sendEmail(() => new OrganizerAddGuestsEmail({ calEvent: calendarEvent, teamMember }))
|
|
);
|
|
}
|
|
}
|
|
|
|
emailsToSend.push(
|
|
...calendarEvent.attendees.map((attendee) => {
|
|
if (newGuests.includes(attendee.email)) {
|
|
return sendEmail(() => new AttendeeScheduledEmail(calendarEvent, attendee));
|
|
} else {
|
|
return sendEmail(() => new AttendeeAddGuestsEmail(calendarEvent, attendee));
|
|
}
|
|
})
|
|
);
|
|
|
|
await Promise.all(emailsToSend);
|
|
};
|
|
|
|
export const sendAddGuestsEmailsAndSMS = async (args: {
|
|
calEvent: CalendarEvent;
|
|
newGuests: string[];
|
|
eventTypeMetadata?: EventTypeMetadata;
|
|
}) => {
|
|
const { calEvent, newGuests, eventTypeMetadata } = args;
|
|
const calendarEvent = formatCalEvent(calEvent);
|
|
|
|
const emailsAndSMSToSend: Promise<unknown>[] = [];
|
|
|
|
if (!eventTypeDisableHostEmail(eventTypeMetadata)) {
|
|
emailsAndSMSToSend.push(sendEmail(() => new OrganizerAddGuestsEmail({ calEvent: calendarEvent })));
|
|
|
|
if (calendarEvent.team?.members) {
|
|
for (const teamMember of calendarEvent.team.members) {
|
|
emailsAndSMSToSend.push(
|
|
sendEmail(() => new OrganizerAddGuestsEmail({ calEvent: calendarEvent, teamMember }))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!eventTypeDisableAttendeeEmail(eventTypeMetadata)) {
|
|
const eventScheduledSMS = new EventSuccessfullyScheduledSMS(calEvent);
|
|
|
|
for (const attendee of calendarEvent.attendees) {
|
|
if (newGuests.includes(attendee.email)) {
|
|
emailsAndSMSToSend.push(sendEmail(() => new AttendeeScheduledEmail(calendarEvent, attendee)));
|
|
|
|
if (attendee.phoneNumber) {
|
|
emailsAndSMSToSend.push(eventScheduledSMS.sendSMSToAttendee(attendee));
|
|
}
|
|
} else {
|
|
emailsAndSMSToSend.push(sendEmail(() => new AttendeeAddGuestsEmail(calendarEvent, attendee)));
|
|
}
|
|
}
|
|
}
|
|
|
|
await Promise.all(emailsAndSMSToSend);
|
|
};
|