diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 2d7c7413b2..ba1a53e756 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -130,7 +130,9 @@ "download_your_transcripts": "Download your Transcripts", "your_meeting_has_been_booked": "Your meeting has been booked", "event_type_has_been_rescheduled_on_time_date": "Your {{title}} has been rescheduled to {{date}}.", + "event_type_has_been_updated": "Your {{title}} has been updated.", "event_has_been_rescheduled": "Updated - Your event has been rescheduled", + "event_has_been_updated": "Event has been updated", "your_event_has_been_rescheduled": "Your event has been rescheduled", "request_reschedule_subtitle": "{{organizer}} has canceled the booking and requested you to pick another time.", "request_reschedule_title_organizer": "You have requested {{attendee}} to reschedule", diff --git a/packages/emails/email-manager.ts b/packages/emails/email-manager.ts index 5e18e8e3d7..9279450067 100644 --- a/packages/emails/email-manager.ts +++ b/packages/emails/email-manager.ts @@ -38,6 +38,7 @@ import AttendeeLocationChangeEmail from "./templates/attendee-location-change-em 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 type { EmailVerifyCode } from "./templates/attendee-verify-email"; import AttendeeVerifyEmail from "./templates/attendee-verify-email"; import AttendeeWasRequestedToRescheduleEmail from "./templates/attendee-was-requested-to-reschedule-email"; @@ -195,6 +196,22 @@ export const sendRoundRobinRescheduledEmailsAndSMS = async ( 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[], diff --git a/packages/emails/src/templates/AttendeeUpdatedEmail.tsx b/packages/emails/src/templates/AttendeeUpdatedEmail.tsx new file mode 100644 index 0000000000..f9721c5341 --- /dev/null +++ b/packages/emails/src/templates/AttendeeUpdatedEmail.tsx @@ -0,0 +1,10 @@ +import { AttendeeScheduledEmail } from "./AttendeeScheduledEmail"; + +export const AttendeeUpdatedEmail = (props: React.ComponentProps) => ( + +); diff --git a/packages/emails/src/templates/index.ts b/packages/emails/src/templates/index.ts index c5df13bc2f..129c9ac89e 100644 --- a/packages/emails/src/templates/index.ts +++ b/packages/emails/src/templates/index.ts @@ -6,6 +6,7 @@ export { AttendeeLocationChangeEmail } from "./AttendeeLocationChangeEmail"; export { AttendeeRequestEmail } from "./AttendeeRequestEmail"; export { AttendeeWasRequestedToRescheduleEmail } from "./AttendeeWasRequestedToRescheduleEmail"; export { AttendeeRescheduledEmail } from "./AttendeeRescheduledEmail"; +export { AttendeeUpdatedEmail } from "./AttendeeUpdatedEmail"; export { AttendeeScheduledEmail } from "./AttendeeScheduledEmail"; export { DisabledAppEmail } from "./DisabledAppEmail"; export { SlugReplacementEmail } from "./SlugReplacementEmail"; diff --git a/packages/emails/templates/attendee-updated-email.ts b/packages/emails/templates/attendee-updated-email.ts new file mode 100644 index 0000000000..5d4fa9c39b --- /dev/null +++ b/packages/emails/templates/attendee-updated-email.ts @@ -0,0 +1,33 @@ +import type { CalendarEvent, Person } from "@calcom/types/Calendar"; + +import { renderEmail } from "../"; +import generateIcsFile, { GenerateIcsRole } from "../lib/generateIcsFile"; +import AttendeeScheduledEmail from "./attendee-scheduled-email"; + +export default class AttendeeUpdatedEmail extends AttendeeScheduledEmail { + protected async getNodeMailerPayload(): Promise> { + return { + icalEvent: generateIcsFile({ + calEvent: this.calEvent, + role: GenerateIcsRole.ATTENDEE, + status: "CONFIRMED", + }), + to: `${this.attendee.name} <${this.attendee.email}>`, + from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, + replyTo: [...this.calEvent.attendees.map(({ email }) => email), this.calEvent.organizer.email], + subject: `${this.attendee.language.translate("event_type_has_been_updated", { + title: this.calEvent.title, + date: this.getFormattedDate(), + })}`, + html: await this.getHtml(this.calEvent, this.attendee), + text: this.getTextBody("event_has_been_updated", "emailed_you_and_any_other_attendees"), + }; + } + + async getHtml(calEvent: CalendarEvent, attendee: Person) { + return await renderEmail("AttendeeUpdatedEmail", { + calEvent, + attendee, + }); + } +} diff --git a/packages/features/ee/round-robin/roundRobinManualReassignment.ts b/packages/features/ee/round-robin/roundRobinManualReassignment.ts index 92d805e208..25f3432124 100644 --- a/packages/features/ee/round-robin/roundRobinManualReassignment.ts +++ b/packages/features/ee/round-robin/roundRobinManualReassignment.ts @@ -4,7 +4,11 @@ import { cloneDeep } from "lodash"; import { OrganizerDefaultConferencingAppType, getLocationValueForDB } from "@calcom/app-store/locations"; import { getEventName } from "@calcom/core/event"; import dayjs from "@calcom/dayjs"; -import { sendRoundRobinCancelledEmailsAndSMS, sendRoundRobinScheduledEmailsAndSMS } from "@calcom/emails"; +import { + sendRoundRobinCancelledEmailsAndSMS, + sendRoundRobinScheduledEmailsAndSMS, + sendRoundRobinUpdatedEmailsAndSMS, +} from "@calcom/emails"; import getBookingResponsesSchema from "@calcom/features/bookings/lib/getBookingResponsesSchema"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { getEventTypesFromDB } from "@calcom/features/bookings/lib/handleNewBooking/getEventTypesFromDB"; @@ -339,6 +343,13 @@ export const roundRobinManualReassignment = async ({ } if (hasOrganizerChanged) { + if (emailsEnabled) { + // send email with event updates to attendees + await sendRoundRobinUpdatedEmailsAndSMS({ + calEvent: evtWithoutCancellationReason, + }); + } + // Handle changing workflows with organizer await handleWorkflowsUpdate({ booking, diff --git a/packages/features/ee/round-robin/roundRobinReassignment.ts b/packages/features/ee/round-robin/roundRobinReassignment.ts index 709b4e8aed..42ea0d2f2f 100644 --- a/packages/features/ee/round-robin/roundRobinReassignment.ts +++ b/packages/features/ee/round-robin/roundRobinReassignment.ts @@ -4,7 +4,11 @@ import { cloneDeep } from "lodash"; import { OrganizerDefaultConferencingAppType, getLocationValueForDB } from "@calcom/app-store/locations"; import { getEventName } from "@calcom/core/event"; import dayjs from "@calcom/dayjs"; -import { sendRoundRobinCancelledEmailsAndSMS, sendRoundRobinScheduledEmailsAndSMS } from "@calcom/emails"; +import { + sendRoundRobinCancelledEmailsAndSMS, + sendRoundRobinScheduledEmailsAndSMS, + sendRoundRobinUpdatedEmailsAndSMS, +} from "@calcom/emails"; import getBookingResponsesSchema from "@calcom/features/bookings/lib/getBookingResponsesSchema"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { ensureAvailableUsers } from "@calcom/features/bookings/lib/handleNewBooking/ensureAvailableUsers"; @@ -389,6 +393,13 @@ export const roundRobinReassignment = async ({ // Handle changing workflows with organizer if (hasOrganizerChanged) { + if (emailsEnabled) { + // send email with event updates to attendees + await sendRoundRobinUpdatedEmailsAndSMS({ + calEvent: evtWithoutCancellationReason, + }); + } + const scheduledWorkflowReminders = await prisma.workflowReminder.findMany({ where: { bookingUid: booking.uid, diff --git a/packages/platform/libraries/index.ts b/packages/platform/libraries/index.ts index e53978b604..dd977dd3b8 100644 --- a/packages/platform/libraries/index.ts +++ b/packages/platform/libraries/index.ts @@ -10,6 +10,7 @@ import AttendeeDeclinedEmail from "@calcom/emails/templates/attendee-declined-em import AttendeeRequestEmail from "@calcom/emails/templates/attendee-request-email"; import AttendeeRescheduledEmail from "@calcom/emails/templates/attendee-rescheduled-email"; import AttendeeScheduledEmail from "@calcom/emails/templates/attendee-scheduled-email"; +import AttendeeUpdatedEmail from "@calcom/emails/templates/attendee-updated-email"; import OrganizerCancelledEmail from "@calcom/emails/templates/organizer-cancelled-email"; import OrganizerReassignedEmail from "@calcom/emails/templates/organizer-reassigned-email"; import OrganizerRequestEmail from "@calcom/emails/templates/organizer-request-email"; @@ -212,6 +213,8 @@ export { OrganizerRescheduledEmail }; export { AttendeeRescheduledEmail }; +export { AttendeeUpdatedEmail }; + export { OrganizerRequestEmail }; export { AttendeeRequestEmail };