fix: Email reminder issue with seated event (#26136)

* fix emailworkflow reminder attendee

* update
This commit is contained in:
Anik Dhabal Babu
2025-12-22 18:26:40 +00:00
committed by GitHub
parent f5b9b6b0f9
commit 33eee8dfc3
2 changed files with 61 additions and 28 deletions
@@ -8,6 +8,7 @@ import { v4 as uuidv4 } from "uuid";
import dayjs from "@calcom/dayjs";
import generateIcsString from "@calcom/emails/lib/generateIcsString";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { BookingSeatRepository } from "@calcom/features/bookings/repositories/BookingSeatRepository";
import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer";
import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
@@ -121,6 +122,18 @@ export async function handler(req: NextRequest) {
}
const referenceUid = reminder.uuid ?? uuidv4();
// For seated events, get the correct attendee based on seatReferenceId
let targetAttendee = reminder.booking?.attendees[0];
if (reminder.seatReferenceId) {
const bookingSeatRepository = new BookingSeatRepository(prisma);
const seatAttendeeData = await bookingSeatRepository.getByReferenceUidWithAttendeeDetails(
reminder.seatReferenceId
);
if (seatAttendeeData?.attendee) {
targetAttendee = seatAttendeeData.attendee;
}
}
if (!reminder.isMandatoryReminder && reminder.workflowStep) {
try {
let sendTo;
@@ -143,7 +156,7 @@ export async function handler(req: NextRequest) {
}
break;
case WorkflowActions.EMAIL_ATTENDEE:
sendTo = reminder.booking.attendees[0].email;
sendTo = targetAttendee?.email;
break;
case WorkflowActions.EMAIL_ADDRESS:
sendTo = reminder.workflowStep.sendTo;
@@ -151,23 +164,23 @@ export async function handler(req: NextRequest) {
const name =
reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE
? reminder.booking.attendees[0].name
? targetAttendee?.name
: reminder.booking.user?.name;
const attendeeName =
reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE
? reminder.booking.user?.name
: reminder.booking.attendees[0].name;
: targetAttendee?.name;
const timeZone =
reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE
? reminder.booking.attendees[0].timeZone
? targetAttendee?.timeZone
: reminder.booking.user?.timeZone;
const locale =
reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE ||
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
? reminder.booking.attendees[0].locale
? targetAttendee?.locale
: reminder.booking.user?.locale;
let emailContent = {
@@ -199,7 +212,7 @@ export async function handler(req: NextRequest) {
const recipientEmail = getWorkflowRecipientEmail({
action: reminder.workflowStep.action || WorkflowActions.EMAIL_ADDRESS,
attendeeEmail: reminder.booking.attendees[0].email,
attendeeEmail: targetAttendee?.email,
organizerEmail: reminder.booking.user?.email,
sendToEmail: reminder.workflowStep.sendTo,
});
@@ -207,8 +220,8 @@ export async function handler(req: NextRequest) {
const variables: VariablesType = {
eventName: reminder.booking.eventType?.title || "",
organizerName: reminder.booking.user?.name || "",
attendeeName: reminder.booking.attendees[0].name,
attendeeEmail: reminder.booking.attendees[0].email,
attendeeName: targetAttendee?.name || "",
attendeeEmail: targetAttendee?.email || "",
eventDate: dayjs(reminder.booking.startTime).tz(timeZone),
eventEndTime: dayjs(reminder.booking?.endTime).tz(timeZone),
timeZone: timeZone,
@@ -224,13 +237,9 @@ export async function handler(req: NextRequest) {
}`,
ratingUrl: `${bookerUrl}/booking/${reminder.booking.uid}?rating`,
noShowUrl: `${bookerUrl}/booking/${reminder.booking.uid}?noShow=true`,
attendeeTimezone: reminder.booking.attendees[0].timeZone,
eventTimeInAttendeeTimezone: dayjs(reminder.booking.startTime).tz(
reminder.booking.attendees[0].timeZone
),
eventEndTimeInAttendeeTimezone: dayjs(reminder.booking?.endTime).tz(
reminder.booking.attendees[0].timeZone
),
attendeeTimezone: targetAttendee?.timeZone,
eventTimeInAttendeeTimezone: dayjs(reminder.booking.startTime).tz(targetAttendee?.timeZone),
eventEndTimeInAttendeeTimezone: dayjs(reminder.booking?.endTime).tz(targetAttendee?.timeZone),
};
const emailLocale = locale || "en";
const brandingDisabled = reminder.booking.eventType?.team
@@ -408,10 +417,10 @@ export async function handler(req: NextRequest) {
}
} else if (reminder.isMandatoryReminder) {
try {
const sendTo = reminder.booking.attendees[0].email;
const name = reminder.booking.attendees[0].name;
const sendTo = targetAttendee?.email;
const name = targetAttendee?.name;
const attendeeName = reminder.booking.user?.name;
const timeZone = reminder.booking.attendees[0].timeZone;
const timeZone = targetAttendee?.timeZone;
let emailContent = {
emailSubject: "",
@@ -283,13 +283,37 @@ export class EmailWorkflowService {
timeZone = evt.organizer.timeZone;
break;
case WorkflowActions.EMAIL_ATTENDEE: {
// check if first attendee of sendTo is present in the attendees list, if not take the evt attendee
const attendeeEmailToBeUsedInMailFromEvt = evt.attendees.find(
(attendee) => attendee.email === sendTo[0]
);
attendeeToBeUsedInMail = attendeeEmailToBeUsedInMailFromEvt
? attendeeEmailToBeUsedInMailFromEvt
: evt.attendees[0];
// For seated events, get the correct attendee based on seatReferenceUid
if (seatReferenceUid) {
const seatAttendeeData = await this.bookingSeatRepository.getByReferenceUidWithAttendeeDetails(
seatReferenceUid
);
if (seatAttendeeData?.attendee) {
const nameParts = seatAttendeeData.attendee.name.split(" ").map((part: string) => part.trim());
const firstName = nameParts[0];
const lastName = nameParts.slice(1).join(" ");
attendeeToBeUsedInMail = {
name: seatAttendeeData.attendee.name,
firstName,
lastName: lastName || undefined,
email: seatAttendeeData.attendee.email,
phoneNumber: seatAttendeeData.attendee.phoneNumber || null,
timeZone: seatAttendeeData.attendee.timeZone,
language: { locale: seatAttendeeData.attendee.locale || "en" },
};
} else {
// Fallback to first attendee if seat attendee not found
attendeeToBeUsedInMail = evt.attendees[0];
}
} else {
// For non-seated events, check if first attendee of sendTo is present in the attendees list, if not take the evt attendee
const attendeeEmailToBeUsedInMailFromEvt = evt.attendees.find(
(attendee) => attendee.email === sendTo[0]
);
attendeeToBeUsedInMail = attendeeEmailToBeUsedInMailFromEvt
? attendeeEmailToBeUsedInMailFromEvt
: evt.attendees[0];
}
name = attendeeToBeUsedInMail.name;
attendeeName = evt.organizer.name;
timeZone = attendeeToBeUsedInMail.timeZone;
@@ -350,9 +374,9 @@ export class EmailWorkflowService {
rescheduleReason: evt.rescheduleReason,
ratingUrl: `${bookerUrl}/booking/${evt.uid}?rating`,
noShowUrl: `${bookerUrl}/booking/${evt.uid}?noShow=true`,
attendeeTimezone: evt.attendees[0].timeZone,
eventTimeInAttendeeTimezone: dayjs(startTime).tz(evt.attendees[0].timeZone),
eventEndTimeInAttendeeTimezone: dayjs(endTime).tz(evt.attendees[0].timeZone),
attendeeTimezone: attendeeToBeUsedInMail.timeZone,
eventTimeInAttendeeTimezone: dayjs(startTime).tz(attendeeToBeUsedInMail.timeZone),
eventEndTimeInAttendeeTimezone: dayjs(endTime).tz(attendeeToBeUsedInMail.timeZone),
};
const locale = isEmailAttendeeAction