feat: add cancelledBy and rescheduledBy parameters to workflow links (#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>
This commit is contained in:
5 files changed
+89
-10
No files matched your search
@@ -21,6 +21,7 @@ import {
|
||||
getAllRemindersToCancel,
|
||||
getAllRemindersToDelete,
|
||||
getAllUnscheduledReminders,
|
||||
getWorkflowRecipientEmail,
|
||||
} from "../lib/getWorkflowReminders";
|
||||
import { sendOrScheduleWorkflowEmails } from "../lib/reminders/providers/emailProvider";
|
||||
import {
|
||||
@@ -187,6 +188,13 @@ export async function handler(req: NextRequest) {
|
||||
reminder.booking.eventType?.team?.parentId ?? organizerOrganizationId ?? null
|
||||
);
|
||||
|
||||
const recipientEmail = getWorkflowRecipientEmail({
|
||||
action: reminder.workflowStep.action || WorkflowActions.EMAIL_ADDRESS,
|
||||
attendeeEmail: reminder.booking.attendees[0].email,
|
||||
organizerEmail: reminder.booking.user?.email,
|
||||
sendToEmail: reminder.workflowStep.sendTo,
|
||||
});
|
||||
|
||||
const variables: VariablesType = {
|
||||
eventName: reminder.booking.eventType?.title || "",
|
||||
organizerName: reminder.booking.user?.name || "",
|
||||
@@ -199,8 +207,12 @@ export async function handler(req: NextRequest) {
|
||||
additionalNotes: reminder.booking.description,
|
||||
responses: responses,
|
||||
meetingUrl: bookingMetadataSchema.parse(reminder.booking.metadata || {})?.videoCallUrl,
|
||||
cancelLink: `${bookerUrl}/booking/${reminder.booking.uid}?cancel=true`,
|
||||
rescheduleLink: `${bookerUrl}/reschedule/${reminder.booking.uid}`,
|
||||
cancelLink: `${bookerUrl}/booking/${reminder.booking.uid}?cancel=true${
|
||||
recipientEmail ? `&cancelledBy=${encodeURIComponent(recipientEmail)}` : ""
|
||||
}`,
|
||||
rescheduleLink: `${bookerUrl}/reschedule/${reminder.booking.uid}${
|
||||
recipientEmail ? `?rescheduledBy=${encodeURIComponent(recipientEmail)}` : ""
|
||||
}`,
|
||||
ratingUrl: `${bookerUrl}/booking/${reminder.booking.uid}?rating`,
|
||||
noShowUrl: `${bookerUrl}/booking/${reminder.booking.uid}?noShow=true`,
|
||||
attendeeTimezone: reminder.booking.attendees[0].timeZone,
|
||||
|
||||
@@ -16,7 +16,7 @@ import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { getSenderId } from "../lib/alphanumericSenderIdSupport";
|
||||
import type { PartialWorkflowReminder } from "../lib/getWorkflowReminders";
|
||||
import { select } from "../lib/getWorkflowReminders";
|
||||
import { select, getWorkflowRecipientEmail } from "../lib/getWorkflowReminders";
|
||||
import type { VariablesType } from "../lib/reminders/templates/customTemplate";
|
||||
import customTemplate from "../lib/reminders/templates/customTemplate";
|
||||
import smsReminderTemplate from "../lib/reminders/templates/smsReminderTemplate";
|
||||
@@ -108,10 +108,20 @@ export async function handler(req: NextRequest) {
|
||||
reminder.booking.eventType?.team?.parentId ?? organizerOrganizationId ?? null
|
||||
);
|
||||
|
||||
const recipientEmail = getWorkflowRecipientEmail({
|
||||
action: reminder.workflowStep.action || WorkflowActions.SMS_NUMBER,
|
||||
attendeeEmail: reminder.booking.attendees[0].email,
|
||||
organizerEmail: reminder.booking.user?.email,
|
||||
});
|
||||
|
||||
const urls = {
|
||||
meetingUrl: bookingMetadataSchema.parse(reminder.booking?.metadata || {})?.videoCallUrl || "",
|
||||
cancelLink: `${bookerUrl}/booking/${reminder.booking.uid}?cancel=true` || "",
|
||||
rescheduleLink: `${bookerUrl}/reschedule/${reminder.booking.uid}` || "",
|
||||
cancelLink: `${bookerUrl}/booking/${reminder.booking.uid}?cancel=true${
|
||||
recipientEmail ? `&cancelledBy=${recipientEmail}` : ""
|
||||
}`,
|
||||
rescheduleLink: `${bookerUrl}/reschedule/${reminder.booking.uid}${
|
||||
recipientEmail ? `?rescheduledBy=${recipientEmail}` : ""
|
||||
}`,
|
||||
};
|
||||
|
||||
const [{ shortLink: meetingUrl }, { shortLink: cancelLink }, { shortLink: rescheduleLink }] =
|
||||
|
||||
@@ -4,7 +4,12 @@ import type { EventType, User, WorkflowReminder, WorkflowStep, Prisma } from "@c
|
||||
import { WorkflowMethods } from "@calcom/prisma/enums";
|
||||
|
||||
type PartialWorkflowStep =
|
||||
| (Partial<WorkflowStep> & { workflow: { userId?: number; teamId?: number } })
|
||||
| (Partial<WorkflowStep> & {
|
||||
workflow: {
|
||||
userId?: number;
|
||||
teamId?: number;
|
||||
};
|
||||
})
|
||||
| null;
|
||||
|
||||
type Booking = Prisma.BookingGetPayload<{
|
||||
@@ -219,3 +224,35 @@ export async function getAllUnscheduledReminders(): Promise<PartialWorkflowRemin
|
||||
|
||||
return unscheduledReminders;
|
||||
}
|
||||
|
||||
export function getWorkflowRecipientEmail({
|
||||
action,
|
||||
organizerEmail,
|
||||
attendeeEmail,
|
||||
sendToEmail,
|
||||
}: {
|
||||
action: string;
|
||||
organizerEmail?: string;
|
||||
attendeeEmail?: string;
|
||||
sendToEmail?: string | null;
|
||||
}): string | null {
|
||||
// const action = reminder.workflowStep.action;
|
||||
|
||||
switch (action) {
|
||||
case "EMAIL_ADDRESS":
|
||||
return sendToEmail || null;
|
||||
case "EMAIL_HOST":
|
||||
return organizerEmail || null;
|
||||
case "EMAIL_ATTENDEE":
|
||||
return attendeeEmail || null;
|
||||
case "SMS_ATTENDEE":
|
||||
return attendeeEmail || null;
|
||||
case "WHATSAPP_ATTENDEE":
|
||||
return attendeeEmail || null;
|
||||
case "SMS_NUMBER":
|
||||
case "WHATSAPP_NUMBER":
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
} from "@calcom/prisma/enums";
|
||||
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { getWorkflowRecipientEmail } from "../getWorkflowReminders";
|
||||
import { sendOrScheduleWorkflowEmails } from "./providers/emailProvider";
|
||||
import { getBatchId, sendSendgridMail } from "./providers/sendgridProvider";
|
||||
import type { AttendeeInBookingInfo, BookingInfo, timeUnitLowerCase } from "./smsReminderManager";
|
||||
@@ -139,6 +140,12 @@ export const scheduleEmailReminder = async (args: scheduleEmailReminderArgs) =>
|
||||
const bookerUrl = evt.bookerUrl ?? WEBSITE_URL;
|
||||
|
||||
if (emailBody) {
|
||||
const recipientEmail = getWorkflowRecipientEmail({
|
||||
action,
|
||||
attendeeEmail: attendeeToBeUsedInMail.email,
|
||||
organizerEmail: evt.organizer.email,
|
||||
sendToEmail: sendTo[0],
|
||||
});
|
||||
const variables: VariablesType = {
|
||||
eventName: evt.title || "",
|
||||
organizerName: evt.organizer.name,
|
||||
@@ -153,9 +160,13 @@ export const scheduleEmailReminder = async (args: scheduleEmailReminderArgs) =>
|
||||
additionalNotes: evt.additionalNotes,
|
||||
responses: evt.responses,
|
||||
meetingUrl: bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl,
|
||||
cancelLink: `${bookerUrl}/booking/${evt.uid}?cancel=true`,
|
||||
cancelLink: `${bookerUrl}/booking/${evt.uid}?cancel=true${
|
||||
recipientEmail ? `&cancelledBy=${encodeURIComponent(recipientEmail)}` : ""
|
||||
}`,
|
||||
cancelReason: evt.cancellationReason,
|
||||
rescheduleLink: `${bookerUrl}/reschedule/${evt.uid}`,
|
||||
rescheduleLink: `${bookerUrl}/reschedule/${evt.uid}${
|
||||
recipientEmail ? `?rescheduledBy=${encodeURIComponent(recipientEmail)}` : ""
|
||||
}`,
|
||||
rescheduleReason: evt.rescheduleReason,
|
||||
ratingUrl: `${bookerUrl}/booking/${evt.uid}?rating`,
|
||||
noShowUrl: `${bookerUrl}/booking/${evt.uid}?noShow=true`,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { WorkflowActions, WorkflowTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { getWorkflowRecipientEmail } from "../getWorkflowReminders";
|
||||
import type { AttendeeInBookingInfo, BookingInfo } from "./smsReminderManager";
|
||||
import type { VariablesType } from "./templates/customTemplate";
|
||||
import customTemplate from "./templates/customTemplate";
|
||||
@@ -40,10 +41,18 @@ export const getSMSMessageWithVariables = async (
|
||||
attendeeToBeUsedInSMS: AttendeeInBookingInfo,
|
||||
action: WorkflowActions
|
||||
) => {
|
||||
const recipientEmail = getWorkflowRecipientEmail({
|
||||
action,
|
||||
attendeeEmail: attendeeToBeUsedInSMS.email,
|
||||
});
|
||||
const urls = {
|
||||
meetingUrl: bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl || "",
|
||||
cancelLink: `${evt.bookerUrl ?? WEBSITE_URL}/booking/${evt.uid}?cancel=true`,
|
||||
rescheduleLink: `${evt.bookerUrl ?? WEBSITE_URL}/reschedule/${evt.uid}`,
|
||||
cancelLink: `${evt.bookerUrl ?? WEBSITE_URL}/booking/${evt.uid}?cancel=true${
|
||||
recipientEmail ? `&cancelledBy=${recipientEmail}` : ""
|
||||
}`,
|
||||
rescheduleLink: `${evt.bookerUrl ?? WEBSITE_URL}/reschedule/${evt.uid}${
|
||||
recipientEmail ? `?rescheduledBy=${recipientEmail}` : ""
|
||||
}`,
|
||||
};
|
||||
|
||||
const [{ shortLink: meetingUrl }, { shortLink: cancelLink }, { shortLink: rescheduleLink }] =
|
||||
|
||||
Reference in new issue
Block a user