Skip to content

Commit a2185d9

Browse files
authored
fix: sms and whatsapp reminder issue with seated event (calcom#25294)
* fix: sms reminder issue with seated event * fix seated event and workflow issue * fix whatsapp reminder * Refactor imports in reminderScheduler.ts * use repository
1 parent 7a66add commit a2185d9

6 files changed

Lines changed: 108 additions & 31 deletions

File tree

packages/features/bookings/lib/handleSeats/handleSeats.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,14 @@ const handleSeats = async (newSeatedBookingObject: NewSeatedBookingObject) => {
107107
...(typeof resultBooking.metadata === "object" && resultBooking.metadata),
108108
...reqBodyMetadata,
109109
};
110+
// For seated events, use the phone number from the specific attendee being added
111+
const attendeePhoneNumber = invitee[0]?.phoneNumber || smsReminderNumber || null;
110112
try {
111113
const creditService = new CreditService();
112114

113115
await WorkflowService.scheduleWorkflowsForNewBooking({
114116
workflows: workflows,
115-
smsReminderNumber: smsReminderNumber || null,
117+
smsReminderNumber: attendeePhoneNumber,
116118
calendarEvent: {
117119
...evt,
118120
uid: seatedBooking.uid,
@@ -154,7 +156,7 @@ const handleSeats = async (newSeatedBookingObject: NewSeatedBookingObject) => {
154156
metadata,
155157
eventTypeId,
156158
status: "ACCEPTED",
157-
smsReminderNumber: seatedBooking?.smsReminderNumber || undefined,
159+
smsReminderNumber: attendeePhoneNumber || undefined,
158160
rescheduledBy,
159161
};
160162

packages/features/bookings/repositories/BookingSeatRepository.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,26 @@ export class BookingSeatRepository {
1717
},
1818
});
1919
}
20+
21+
getByReferenceUidWithAttendeeDetails(referenceUid: string) {
22+
return this.prismaClient.bookingSeat.findUnique({
23+
where: {
24+
referenceUid,
25+
},
26+
select: {
27+
attendee: {
28+
select: {
29+
name: true,
30+
id: true,
31+
bookingId: true,
32+
noShow: true,
33+
phoneNumber: true,
34+
email: true,
35+
locale: true,
36+
timeZone: true,
37+
},
38+
},
39+
},
40+
});
41+
}
2042
}

packages/features/ee/workflows/api/scheduleSMSReminders.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { NextResponse } from "next/server";
55
import dayjs from "@calcom/dayjs";
66
import { bulkShortenLinks } from "@calcom/ee/workflows/lib/reminders/utils";
77
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
8+
import { BookingSeatRepository } from "@calcom/features/bookings/repositories/BookingSeatRepository";
89
import { CreditService } from "@calcom/features/ee/billing/credit-service";
910
import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer";
1011
import { isAttendeeAction } from "@calcom/features/ee/workflows/lib/actionHelperFunctions";
@@ -61,32 +62,42 @@ export async function handler(req: NextRequest) {
6162
const teamId = reminder.workflowStep.workflow.teamId;
6263

6364
try {
65+
// For seated events, get the correct attendee based on seatReferenceId
66+
let targetAttendee = reminder.booking?.attendees[0];
67+
if (reminder.seatReferenceId) {
68+
const bookingSeatRepository = new BookingSeatRepository(prisma);
69+
const seatAttendeeData = await bookingSeatRepository.getByReferenceUidWithAttendeeDetails(
70+
reminder.seatReferenceId
71+
);
72+
if (seatAttendeeData?.attendee) {
73+
targetAttendee = seatAttendeeData.attendee;
74+
}
75+
}
76+
6477
const sendTo =
6578
reminder.workflowStep.action === WorkflowActions.SMS_NUMBER
6679
? reminder.workflowStep.sendTo
67-
: reminder.booking?.smsReminderNumber;
80+
: targetAttendee?.phoneNumber;
6881

6982
const userName =
70-
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
71-
? reminder.booking?.attendees[0].name
72-
: "";
83+
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE ? targetAttendee?.name || "" : "";
7384

7485
const attendeeName =
7586
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
7687
? reminder.booking?.user?.name
77-
: reminder.booking?.attendees[0].name;
88+
: targetAttendee?.name;
7889

7990
const timeZone =
8091
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
81-
? reminder.booking?.attendees[0].timeZone
92+
? targetAttendee?.timeZone
8293
: reminder.booking?.user?.timeZone;
8394

8495
const senderID = getSenderId(sendTo, reminder.workflowStep.sender);
8596

8697
const locale =
8798
reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE ||
8899
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
89-
? reminder.booking?.attendees[0].locale
100+
? targetAttendee?.locale
90101
: reminder.booking?.user?.locale;
91102

92103
let message: string | null = reminder.workflowStep.reminderBody || null;
@@ -111,7 +122,7 @@ export async function handler(req: NextRequest) {
111122

112123
const recipientEmail = getWorkflowRecipientEmail({
113124
action: reminder.workflowStep.action || WorkflowActions.SMS_NUMBER,
114-
attendeeEmail: reminder.booking.attendees[0].email,
125+
attendeeEmail: targetAttendee?.email,
115126
organizerEmail: reminder.booking.user?.email,
116127
});
117128

@@ -131,8 +142,8 @@ export async function handler(req: NextRequest) {
131142
const variables: VariablesType = {
132143
eventName: reminder.booking?.eventType?.title,
133144
organizerName: reminder.booking?.user?.name || "",
134-
attendeeName: reminder.booking?.attendees[0].name,
135-
attendeeEmail: reminder.booking?.attendees[0].email,
145+
attendeeName: targetAttendee?.name,
146+
attendeeEmail: targetAttendee?.email,
136147
eventDate: dayjs(reminder.booking?.startTime).tz(timeZone),
137148
eventEndTime: dayjs(reminder.booking?.endTime).tz(timeZone),
138149
timeZone: timeZone,
@@ -142,13 +153,9 @@ export async function handler(req: NextRequest) {
142153
meetingUrl,
143154
cancelLink,
144155
rescheduleLink,
145-
attendeeTimezone: reminder.booking.attendees[0].timeZone,
146-
eventTimeInAttendeeTimezone: dayjs(reminder.booking.startTime).tz(
147-
reminder.booking.attendees[0].timeZone
148-
),
149-
eventEndTimeInAttendeeTimezone: dayjs(reminder.booking?.endTime).tz(
150-
reminder.booking.attendees[0].timeZone
151-
),
156+
attendeeTimezone: targetAttendee?.timeZone,
157+
eventTimeInAttendeeTimezone: dayjs(reminder.booking.startTime).tz(targetAttendee?.timeZone),
158+
eventEndTimeInAttendeeTimezone: dayjs(reminder.booking?.endTime).tz(targetAttendee?.timeZone),
152159
};
153160
const customMessage = customTemplate(
154161
reminder.workflowStep.reminderBody || "",
@@ -190,7 +197,7 @@ export async function handler(req: NextRequest) {
190197
fallbackData:
191198
reminder.workflowStep.action && isAttendeeAction(reminder.workflowStep.action)
192199
? {
193-
email: reminder.booking.attendees[0].email,
200+
email: targetAttendee?.email,
194201
t: await getTranslation(locale || "en", "common"),
195202
replyTo: reminder.booking?.user?.email ?? "",
196203
workflowStepId: reminder.workflowStep.id,

packages/features/ee/workflows/api/scheduleWhatsappReminders.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { NextRequest } from "next/server";
33
import { NextResponse } from "next/server";
44

55
import dayjs from "@calcom/dayjs";
6+
import { BookingSeatRepository } from "@calcom/features/bookings/repositories/BookingSeatRepository";
67
import { CreditService } from "@calcom/features/ee/billing/credit-service";
78
import { getTranslation } from "@calcom/lib/server/i18n";
89
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
@@ -53,24 +54,34 @@ export async function handler(req: NextRequest) {
5354
const teamId = reminder.workflowStep.workflow.teamId;
5455

5556
try {
57+
// For seated events, get the correct attendee based on seatReferenceId
58+
let targetAttendee = reminder.booking?.attendees[0];
59+
if (reminder.seatReferenceId) {
60+
const bookingSeatRepository = new BookingSeatRepository(prisma);
61+
const seatAttendeeData = await bookingSeatRepository.getByReferenceUidWithAttendeeDetails(
62+
reminder.seatReferenceId
63+
);
64+
if (seatAttendeeData?.attendee) {
65+
targetAttendee = seatAttendeeData.attendee;
66+
}
67+
}
68+
5669
const sendTo =
5770
reminder.workflowStep.action === WorkflowActions.WHATSAPP_NUMBER
5871
? reminder.workflowStep.sendTo
59-
: reminder.booking?.smsReminderNumber;
72+
: targetAttendee?.phoneNumber;
6073

6174
const userName =
62-
reminder.workflowStep.action === WorkflowActions.WHATSAPP_ATTENDEE
63-
? reminder.booking?.attendees[0].name
64-
: "";
75+
reminder.workflowStep.action === WorkflowActions.WHATSAPP_ATTENDEE ? targetAttendee?.name || "" : "";
6576

6677
const attendeeName =
6778
reminder.workflowStep.action === WorkflowActions.WHATSAPP_ATTENDEE
6879
? reminder.booking?.user?.name
69-
: reminder.booking?.attendees[0].name;
80+
: targetAttendee?.name;
7081

7182
const timeZone =
7283
reminder.workflowStep.action === WorkflowActions.WHATSAPP_ATTENDEE
73-
? reminder.booking?.attendees[0].timeZone
84+
? targetAttendee?.timeZone
7485
: reminder.booking?.user?.timeZone;
7586

7687
const startTime = reminder.booking?.startTime.toISOString();
@@ -121,8 +132,8 @@ export async function handler(req: NextRequest) {
121132
fallbackData:
122133
reminder.workflowStep.action && isAttendeeAction(reminder.workflowStep.action)
123134
? {
124-
email: reminder.booking.attendees[0].email,
125-
t: await getTranslation(reminder.booking.attendees[0].locale || "en", "common"),
135+
email: targetAttendee?.email,
136+
t: await getTranslation(targetAttendee?.locale || "en", "common"),
126137
replyTo: reminder.booking?.user?.email ?? "",
127138
workflowStepId: reminder.workflowStep.id,
128139
}

packages/features/ee/workflows/lib/getWorkflowReminders.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ type PartialBooking =
4949

5050
export type PartialWorkflowReminder = Pick<
5151
WorkflowReminder,
52-
"id" | "isMandatoryReminder" | "scheduledDate" | "uuid"
52+
"id" | "isMandatoryReminder" | "scheduledDate" | "uuid" | "seatReferenceId"
5353
> & {
5454
booking: PartialBooking | null;
5555
} & { workflowStep: PartialWorkflowStep };
@@ -134,6 +134,7 @@ export const select = {
134134
scheduledDate: true,
135135
isMandatoryReminder: true,
136136
uuid: true,
137+
seatReferenceId: true,
137138
workflowStep: {
138139
select: {
139140
action: true,

packages/features/ee/workflows/lib/reminders/reminderScheduler.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,30 @@ export type ScheduleWorkflowRemindersArgs = ProcessWorkflowStepParams & {
6363
creditCheckFn: CreditCheckFn;
6464
};
6565

66+
const getReminderPhoneNumber = async (
67+
action: WorkflowActions,
68+
seatReferenceUid: string | undefined,
69+
smsReminderNumber: string | null,
70+
stepSendTo: string | null
71+
) => {
72+
const isAttendeeAction =
73+
action === WorkflowActions.SMS_ATTENDEE || action === WorkflowActions.WHATSAPP_ATTENDEE;
74+
75+
if (!isAttendeeAction) {
76+
return stepSendTo;
77+
}
78+
79+
if (seatReferenceUid) {
80+
const bookingSeatRepository = new BookingSeatRepository(prisma);
81+
const seatAttendeeData = await bookingSeatRepository.getByReferenceUidWithAttendeeDetails(
82+
seatReferenceUid
83+
);
84+
return seatAttendeeData?.attendee?.phoneNumber || smsReminderNumber;
85+
}
86+
87+
return smsReminderNumber;
88+
};
89+
6690
const processWorkflowStep = async (
6791
workflow: Workflow,
6892
step: WorkflowStep,
@@ -101,7 +125,12 @@ const processWorkflowStep = async (
101125

102126
if (isSMSAction(step.action)) {
103127
const { scheduleSMSReminder } = await import("./smsReminderManager");
104-
const sendTo = step.action === WorkflowActions.SMS_ATTENDEE ? smsReminderNumber : step.sendTo;
128+
const sendTo = await getReminderPhoneNumber(
129+
step.action,
130+
seatReferenceUid,
131+
smsReminderNumber,
132+
step.sendTo
133+
);
105134

106135
await scheduleSMSReminder({
107136
...scheduleFunctionParams,
@@ -139,7 +168,12 @@ const processWorkflowStep = async (
139168
}
140169

141170
const { scheduleWhatsappReminder } = await import("./whatsappReminderManager");
142-
const sendTo = step.action === WorkflowActions.WHATSAPP_ATTENDEE ? smsReminderNumber : step.sendTo;
171+
const sendTo = await getReminderPhoneNumber(
172+
step.action,
173+
seatReferenceUid,
174+
smsReminderNumber,
175+
step.sendTo
176+
);
143177

144178
await scheduleWhatsappReminder({
145179
...scheduleFunctionParams,

0 commit comments

Comments
 (0)