Skip to content

Commit 6c93647

Browse files
feat: add cancelledBy and rescheduledBy parameters to workflow links (calcom#22438)
* feat: add cancelledBy and rescheduledBy parameters to workflow links - Extended workflow reminder selection to include user and team data - Added getWorkflowAssigneeEmail helper function to resolve assignee email - Updated email and SMS workflow templates to include assignee in cancel/reschedule links - For user workflows, uses user email; for team workflows, uses team owner email - Maintains backward compatibility when assignee data is unavailable Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: use workflow recipient email instead of assignee email for link parameters - Updated getWorkflowRecipientEmail to determine recipient based on workflow action type - EMAIL_ADDRESS uses sendTo email, EMAIL_HOST uses organizer, EMAIL_ATTENDEE uses attendee - SMS_ATTENDEE/WHATSAPP_ATTENDEE use attendee email for cancelledBy/rescheduledBy params - Maintains backward compatibility when recipient data unavailable Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: use emailReminderManager for email workflows with recipient parameters - Updated emailReminderManager to include recipient email in cancel/reschedule links - Added getEmailWorkflowRecipientEmail function for proper recipient determination - Removed changes from deprecated scheduleEmailReminders.ts - SMS_ATTENDEE correctly uses attendee email like EMAIL_ATTENDEE Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * Get attendee's email when sending SMS * Remove unused query * feat: add cancelledBy and rescheduledBy parameters to getSMSMessageWithVariables Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * Clean up Devin --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 3b82367 commit 6c93647

5 files changed

Lines changed: 89 additions & 10 deletions

File tree

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
getAllRemindersToCancel,
2222
getAllRemindersToDelete,
2323
getAllUnscheduledReminders,
24+
getWorkflowRecipientEmail,
2425
} from "../lib/getWorkflowReminders";
2526
import { sendOrScheduleWorkflowEmails } from "../lib/reminders/providers/emailProvider";
2627
import {
@@ -187,6 +188,13 @@ export async function handler(req: NextRequest) {
187188
reminder.booking.eventType?.team?.parentId ?? organizerOrganizationId ?? null
188189
);
189190

191+
const recipientEmail = getWorkflowRecipientEmail({
192+
action: reminder.workflowStep.action || WorkflowActions.EMAIL_ADDRESS,
193+
attendeeEmail: reminder.booking.attendees[0].email,
194+
organizerEmail: reminder.booking.user?.email,
195+
sendToEmail: reminder.workflowStep.sendTo,
196+
});
197+
190198
const variables: VariablesType = {
191199
eventName: reminder.booking.eventType?.title || "",
192200
organizerName: reminder.booking.user?.name || "",
@@ -199,8 +207,12 @@ export async function handler(req: NextRequest) {
199207
additionalNotes: reminder.booking.description,
200208
responses: responses,
201209
meetingUrl: bookingMetadataSchema.parse(reminder.booking.metadata || {})?.videoCallUrl,
202-
cancelLink: `${bookerUrl}/booking/${reminder.booking.uid}?cancel=true`,
203-
rescheduleLink: `${bookerUrl}/reschedule/${reminder.booking.uid}`,
210+
cancelLink: `${bookerUrl}/booking/${reminder.booking.uid}?cancel=true${
211+
recipientEmail ? `&cancelledBy=${encodeURIComponent(recipientEmail)}` : ""
212+
}`,
213+
rescheduleLink: `${bookerUrl}/reschedule/${reminder.booking.uid}${
214+
recipientEmail ? `?rescheduledBy=${encodeURIComponent(recipientEmail)}` : ""
215+
}`,
204216
ratingUrl: `${bookerUrl}/booking/${reminder.booking.uid}?rating`,
205217
noShowUrl: `${bookerUrl}/booking/${reminder.booking.uid}?noShow=true`,
206218
attendeeTimezone: reminder.booking.attendees[0].timeZone,

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
1616

1717
import { getSenderId } from "../lib/alphanumericSenderIdSupport";
1818
import type { PartialWorkflowReminder } from "../lib/getWorkflowReminders";
19-
import { select } from "../lib/getWorkflowReminders";
19+
import { select, getWorkflowRecipientEmail } from "../lib/getWorkflowReminders";
2020
import type { VariablesType } from "../lib/reminders/templates/customTemplate";
2121
import customTemplate from "../lib/reminders/templates/customTemplate";
2222
import smsReminderTemplate from "../lib/reminders/templates/smsReminderTemplate";
@@ -108,10 +108,20 @@ export async function handler(req: NextRequest) {
108108
reminder.booking.eventType?.team?.parentId ?? organizerOrganizationId ?? null
109109
);
110110

111+
const recipientEmail = getWorkflowRecipientEmail({
112+
action: reminder.workflowStep.action || WorkflowActions.SMS_NUMBER,
113+
attendeeEmail: reminder.booking.attendees[0].email,
114+
organizerEmail: reminder.booking.user?.email,
115+
});
116+
111117
const urls = {
112118
meetingUrl: bookingMetadataSchema.parse(reminder.booking?.metadata || {})?.videoCallUrl || "",
113-
cancelLink: `${bookerUrl}/booking/${reminder.booking.uid}?cancel=true` || "",
114-
rescheduleLink: `${bookerUrl}/reschedule/${reminder.booking.uid}` || "",
119+
cancelLink: `${bookerUrl}/booking/${reminder.booking.uid}?cancel=true${
120+
recipientEmail ? `&cancelledBy=${recipientEmail}` : ""
121+
}`,
122+
rescheduleLink: `${bookerUrl}/reschedule/${reminder.booking.uid}${
123+
recipientEmail ? `?rescheduledBy=${recipientEmail}` : ""
124+
}`,
115125
};
116126

117127
const [{ shortLink: meetingUrl }, { shortLink: cancelLink }, { shortLink: rescheduleLink }] =

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

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import type { EventType, User, WorkflowReminder, WorkflowStep, Prisma } from "@c
44
import { WorkflowMethods } from "@calcom/prisma/enums";
55

66
type PartialWorkflowStep =
7-
| (Partial<WorkflowStep> & { workflow: { userId?: number; teamId?: number } })
7+
| (Partial<WorkflowStep> & {
8+
workflow: {
9+
userId?: number;
10+
teamId?: number;
11+
};
12+
})
813
| null;
914

1015
type Booking = Prisma.BookingGetPayload<{
@@ -219,3 +224,35 @@ export async function getAllUnscheduledReminders(): Promise<PartialWorkflowRemin
219224

220225
return unscheduledReminders;
221226
}
227+
228+
export function getWorkflowRecipientEmail({
229+
action,
230+
organizerEmail,
231+
attendeeEmail,
232+
sendToEmail,
233+
}: {
234+
action: string;
235+
organizerEmail?: string;
236+
attendeeEmail?: string;
237+
sendToEmail?: string | null;
238+
}): string | null {
239+
// const action = reminder.workflowStep.action;
240+
241+
switch (action) {
242+
case "EMAIL_ADDRESS":
243+
return sendToEmail || null;
244+
case "EMAIL_HOST":
245+
return organizerEmail || null;
246+
case "EMAIL_ATTENDEE":
247+
return attendeeEmail || null;
248+
case "SMS_ATTENDEE":
249+
return attendeeEmail || null;
250+
case "WHATSAPP_ATTENDEE":
251+
return attendeeEmail || null;
252+
case "SMS_NUMBER":
253+
case "WHATSAPP_NUMBER":
254+
return null;
255+
default:
256+
return null;
257+
}
258+
}

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
} from "@calcom/prisma/enums";
2020
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
2121

22+
import { getWorkflowRecipientEmail } from "../getWorkflowReminders";
2223
import { sendOrScheduleWorkflowEmails } from "./providers/emailProvider";
2324
import { getBatchId, sendSendgridMail } from "./providers/sendgridProvider";
2425
import type { AttendeeInBookingInfo, BookingInfo, timeUnitLowerCase } from "./smsReminderManager";
@@ -139,6 +140,12 @@ export const scheduleEmailReminder = async (args: scheduleEmailReminderArgs) =>
139140
const bookerUrl = evt.bookerUrl ?? WEBSITE_URL;
140141

141142
if (emailBody) {
143+
const recipientEmail = getWorkflowRecipientEmail({
144+
action,
145+
attendeeEmail: attendeeToBeUsedInMail.email,
146+
organizerEmail: evt.organizer.email,
147+
sendToEmail: sendTo[0],
148+
});
142149
const variables: VariablesType = {
143150
eventName: evt.title || "",
144151
organizerName: evt.organizer.name,
@@ -153,9 +160,13 @@ export const scheduleEmailReminder = async (args: scheduleEmailReminderArgs) =>
153160
additionalNotes: evt.additionalNotes,
154161
responses: evt.responses,
155162
meetingUrl: bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl,
156-
cancelLink: `${bookerUrl}/booking/${evt.uid}?cancel=true`,
163+
cancelLink: `${bookerUrl}/booking/${evt.uid}?cancel=true${
164+
recipientEmail ? `&cancelledBy=${encodeURIComponent(recipientEmail)}` : ""
165+
}`,
157166
cancelReason: evt.cancellationReason,
158-
rescheduleLink: `${bookerUrl}/reschedule/${evt.uid}`,
167+
rescheduleLink: `${bookerUrl}/reschedule/${evt.uid}${
168+
recipientEmail ? `?rescheduledBy=${encodeURIComponent(recipientEmail)}` : ""
169+
}`,
159170
rescheduleReason: evt.rescheduleReason,
160171
ratingUrl: `${bookerUrl}/booking/${evt.uid}?rating`,
161172
noShowUrl: `${bookerUrl}/booking/${evt.uid}?noShow=true`,

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { WEBSITE_URL } from "@calcom/lib/constants";
44
import { WorkflowActions, WorkflowTriggerEvents } from "@calcom/prisma/enums";
55
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
66

7+
import { getWorkflowRecipientEmail } from "../getWorkflowReminders";
78
import type { AttendeeInBookingInfo, BookingInfo } from "./smsReminderManager";
89
import type { VariablesType } from "./templates/customTemplate";
910
import customTemplate from "./templates/customTemplate";
@@ -40,10 +41,18 @@ export const getSMSMessageWithVariables = async (
4041
attendeeToBeUsedInSMS: AttendeeInBookingInfo,
4142
action: WorkflowActions
4243
) => {
44+
const recipientEmail = getWorkflowRecipientEmail({
45+
action,
46+
attendeeEmail: attendeeToBeUsedInSMS.email,
47+
});
4348
const urls = {
4449
meetingUrl: bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl || "",
45-
cancelLink: `${evt.bookerUrl ?? WEBSITE_URL}/booking/${evt.uid}?cancel=true`,
46-
rescheduleLink: `${evt.bookerUrl ?? WEBSITE_URL}/reschedule/${evt.uid}`,
50+
cancelLink: `${evt.bookerUrl ?? WEBSITE_URL}/booking/${evt.uid}?cancel=true${
51+
recipientEmail ? `&cancelledBy=${recipientEmail}` : ""
52+
}`,
53+
rescheduleLink: `${evt.bookerUrl ?? WEBSITE_URL}/reschedule/${evt.uid}${
54+
recipientEmail ? `?rescheduledBy=${recipientEmail}` : ""
55+
}`,
4756
};
4857

4958
const [{ shortLink: meetingUrl }, { shortLink: cancelLink }, { shortLink: rescheduleLink }] =

0 commit comments

Comments
 (0)