fix: {ATTENDEE} workflow variable always uses first attendee for for seated event (#10468)

Co-authored-by: rkreddy99 <rreddy@e2clouds.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
pull/10591/head^2
Rama Krishna Reddy 2023-08-04 19:23:58 +05:30 committed by GitHub
parent d22d8095e1
commit 359779cabb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 29 deletions

View File

@ -14,7 +14,7 @@ import {
} from "@calcom/prisma/enums";
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
import type { BookingInfo, timeUnitLowerCase } from "./smsReminderManager";
import type { AttendeeInBookingInfo, BookingInfo, timeUnitLowerCase } from "./smsReminderManager";
import type { VariablesType } from "./templates/customTemplate";
import customTemplate from "./templates/customTemplate";
import emailReminderTemplate from "./templates/emailReminderTemplate";
@ -42,10 +42,15 @@ async function getBatchId() {
return batchIdResponse[1].batch_id as string;
}
type ScheduleEmailReminderAction = Extract<
WorkflowActions,
"EMAIL_HOST" | "EMAIL_ATTENDEE" | "EMAIL_ADDRESS"
>;
export const scheduleEmailReminder = async (
evt: BookingInfo,
triggerEvent: WorkflowTriggerEvents,
action: WorkflowActions,
action: ScheduleEmailReminderAction,
timeSpan: {
time: number | null;
timeUnit: TimeUnit | null;
@ -79,20 +84,49 @@ export const scheduleEmailReminder = async (
const sandboxMode = process.env.NEXT_PUBLIC_IS_E2E ? true : false;
let attendeeEmailToBeUsedInMail: string | null = null;
let attendeeToBeUsedInMail: AttendeeInBookingInfo | null = null;
let name = "";
let attendeeName = "";
let timeZone = "";
switch (action) {
case WorkflowActions.EMAIL_HOST:
attendeeToBeUsedInMail = evt.attendees[0];
name = evt.organizer.name;
attendeeName = evt.attendees[0].name;
attendeeName = attendeeToBeUsedInMail.name;
timeZone = evt.organizer.timeZone;
break;
case WorkflowActions.EMAIL_ATTENDEE:
name = evt.attendees[0].name;
//These type checks are required as sendTo is of type MailData["to"] which in turn is of string | {name?:string, email: string} | string | {name?:string, email: string}[0]
// and the email is being sent to the first attendee of event by default instead of the sendTo
// so check if first attendee can be extracted from sendTo -> attendeeEmailToBeUsedInMail
if (typeof sendTo === "string") {
attendeeEmailToBeUsedInMail = sendTo;
} else if (Array.isArray(sendTo)) {
// If it's an array, take the first entry (if it exists) and extract name and email (if object); otherwise, just put the email (if string)
const emailData = sendTo[0];
if (typeof emailData === "object" && emailData !== null) {
const { name, email } = emailData;
attendeeEmailToBeUsedInMail = email;
} else if (typeof emailData === "string") {
attendeeEmailToBeUsedInMail = emailData;
}
} else if (typeof sendTo === "object" && sendTo !== null) {
const { name, email } = sendTo;
attendeeEmailToBeUsedInMail = email;
}
// 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 === attendeeEmailToBeUsedInMail
);
attendeeToBeUsedInMail = attendeeEmailToBeUsedInMailFromEvt
? attendeeEmailToBeUsedInMailFromEvt
: evt.attendees[0];
name = attendeeToBeUsedInMail.name;
attendeeName = evt.organizer.name;
timeZone = evt.attendees[0].timeZone;
timeZone = attendeeToBeUsedInMail.timeZone;
break;
}
@ -104,10 +138,10 @@ export const scheduleEmailReminder = async (
const variables: VariablesType = {
eventName: evt.title || "",
organizerName: evt.organizer.name,
attendeeName: evt.attendees[0].name,
attendeeFirstName: evt.attendees[0].firstName,
attendeeLastName: evt.attendees[0].lastName,
attendeeEmail: evt.attendees[0].email,
attendeeName: attendeeToBeUsedInMail.name,
attendeeFirstName: attendeeToBeUsedInMail.firstName,
attendeeLastName: attendeeToBeUsedInMail.lastName,
attendeeEmail: attendeeToBeUsedInMail.email,
eventDate: dayjs(startTime).tz(timeZone),
eventEndTime: dayjs(endTime).tz(timeZone),
timeZone: timeZone,
@ -120,8 +154,8 @@ export const scheduleEmailReminder = async (
};
const locale =
action === WorkflowActions.EMAIL_ATTENDEE || action === WorkflowActions.SMS_ATTENDEE
? evt.attendees[0].language?.locale
action === WorkflowActions.EMAIL_ATTENDEE
? attendeeToBeUsedInMail.language?.locale
: evt.organizer.language.locale;
const emailSubjectTemplate = customTemplate(emailSubject, variables, locale, evt.organizer.timeFormat);

View File

@ -22,16 +22,18 @@ export enum timeUnitLowerCase {
}
const log = logger.getChildLogger({ prefix: ["[smsReminderManager]"] });
export type AttendeeInBookingInfo = {
name: string;
firstName?: string;
lastName?: string;
email: string;
timeZone: string;
language: { locale: string };
};
export type BookingInfo = {
uid?: string | null;
attendees: {
name: string;
firstName?: string;
lastName?: string;
email: string;
timeZone: string;
language: { locale: string };
}[];
attendees: AttendeeInBookingInfo[];
organizer: {
language: { locale: string };
name: string;
@ -52,11 +54,13 @@ export type BookingInfo = {
metadata?: Prisma.JsonValue;
};
type ScheduleSMSReminderAction = Extract<WorkflowActions, "SMS_ATTENDEE" | "SMS_NUMBER">;
export const scheduleSMSReminder = async (
evt: BookingInfo,
reminderPhone: string | null,
triggerEvent: WorkflowTriggerEvents,
action: WorkflowActions,
action: ScheduleSMSReminderAction,
timeSpan: {
time: number | null;
timeUnit: TimeUnit | null;
@ -93,30 +97,42 @@ export const scheduleSMSReminder = async (
}
const isNumberVerified = await getIsNumberVerified();
let attendeeToBeUsedInSMS: AttendeeInBookingInfo | null = null;
if (action === WorkflowActions.SMS_ATTENDEE) {
const attendeeWithReminderPhoneAsSMSReminderNumber =
reminderPhone && evt.attendees.find((attendee) => attendee.email === evt.responses?.email?.value);
attendeeToBeUsedInSMS = attendeeWithReminderPhoneAsSMSReminderNumber
? attendeeWithReminderPhoneAsSMSReminderNumber
: evt.attendees[0];
} else {
attendeeToBeUsedInSMS = evt.attendees[0];
}
if (triggerEvent === WorkflowTriggerEvents.BEFORE_EVENT) {
scheduledDate = timeSpan.time && timeUnit ? dayjs(startTime).subtract(timeSpan.time, timeUnit) : null;
} else if (triggerEvent === WorkflowTriggerEvents.AFTER_EVENT) {
scheduledDate = timeSpan.time && timeUnit ? dayjs(endTime).add(timeSpan.time, timeUnit) : null;
}
const name = action === WorkflowActions.SMS_ATTENDEE ? evt.attendees[0].name : "";
const attendeeName = action === WorkflowActions.SMS_ATTENDEE ? evt.organizer.name : evt.attendees[0].name;
const name = action === WorkflowActions.SMS_ATTENDEE ? attendeeToBeUsedInSMS.name : "";
const attendeeName =
action === WorkflowActions.SMS_ATTENDEE ? evt.organizer.name : attendeeToBeUsedInSMS.name;
const timeZone =
action === WorkflowActions.SMS_ATTENDEE ? evt.attendees[0].timeZone : evt.organizer.timeZone;
action === WorkflowActions.SMS_ATTENDEE ? attendeeToBeUsedInSMS.timeZone : evt.organizer.timeZone;
const locale =
action === WorkflowActions.EMAIL_ATTENDEE || action === WorkflowActions.SMS_ATTENDEE
? evt.attendees[0].language?.locale
action === WorkflowActions.SMS_ATTENDEE
? attendeeToBeUsedInSMS.language?.locale
: evt.organizer.language.locale;
if (message) {
const variables: VariablesType = {
eventName: evt.title,
organizerName: evt.organizer.name,
attendeeName: evt.attendees[0].name,
attendeeFirstName: evt.attendees[0].firstName,
attendeeLastName: evt.attendees[0].lastName,
attendeeEmail: evt.attendees[0].email,
attendeeName: attendeeToBeUsedInSMS.name,
attendeeFirstName: attendeeToBeUsedInSMS.firstName,
attendeeLastName: attendeeToBeUsedInSMS.lastName,
attendeeEmail: attendeeToBeUsedInSMS.email,
eventDate: dayjs(evt.startTime).tz(timeZone),
eventEndTime: dayjs(evt.endTime).tz(timeZone),
timeZone: timeZone,