Files
cal.diy/packages/emails/email-manager.ts
T
Syed Ali Shahbaz 0103321b71 feat: managed event reassignment (#24809)
* init

* --

* update dialog

* reassignment

* further changes

* add unit test

* fix

* type fix??

* fix type??

* emails

* workflows

* reason recorder

* refactor reassigned email

* fix reassigned reason

* fix type

* improve dialog

* add integration tests

* -

* remove unnecessary comments --1

* removed unnecessary comments

* fix type?

* address cubic

* address feedback

* --

* fix type?

* address cubic

* type-fix?

* fix type

* further fixes

* fix location update

* type fix

* propagate error to top

* fix mocking

* fix reported bugs

* fix

* fix success page video URL

* remove PII from logs

* persist video URL

* better audit trail

* revert email function name change

* fix test

* fix flake

* di

* fixes

* extract logic and other repo access from BookingRepository

* fixes

* (☞゚∀゚)☞ udit

* integration test fixes

* mroe fixes

* extract to repo

* extract to repo --2

* fix type

* cubic

* address feedback --1

* --2

* wip

* addressed feedback

* type fixes

* type fixes

* fix issues

* feedback --1

* feedback --2

* BookingAccessService DI

* fix

* break down function into small functions

* fixes --1

* fixes

* typefix

* addressing feedback

* fix merge conflict lost change
2025-12-01 14:04:24 +04:00

655 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
// or for reassignment of a managed event
export const sendReassignedScheduledEmailsAndSMS = 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 sendReassignedUpdatedEmailsAndSMS = 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 sendReassignedEmailsAndSMS = 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);
};