diff --git a/packages/features/bookings/lib/handleConfirmation.ts b/packages/features/bookings/lib/handleConfirmation.ts index 289e6f7148..debc12ec32 100644 --- a/packages/features/bookings/lib/handleConfirmation.ts +++ b/packages/features/bookings/lib/handleConfirmation.ts @@ -2,6 +2,7 @@ import type { Prisma, Workflow, WorkflowsOnEventTypes, WorkflowStep } from "@pri import type { EventManagerUser } from "@calcom/core/EventManager"; import EventManager from "@calcom/core/EventManager"; +import { scheduleMandatoryReminder } from "@calcom/ee/workflows/lib/reminders/scheduleMandatoryReminder"; import { sendScheduledEmails } from "@calcom/emails"; import { scheduleWorkflowReminders } from "@calcom/features/ee/workflows/lib/reminders/reminderScheduler"; import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; @@ -256,27 +257,27 @@ export async function handleConfirmation(args: { //Workflows - set reminders for confirmed events try { for (let index = 0; index < updatedBookings.length; index++) { - if (updatedBookings[index].eventType?.workflows) { - const evtOfBooking = evt; - evtOfBooking.startTime = updatedBookings[index].startTime.toISOString(); - evtOfBooking.endTime = updatedBookings[index].endTime.toISOString(); - evtOfBooking.uid = updatedBookings[index].uid; - const eventTypeSlug = updatedBookings[index].eventType?.slug || ""; - - const isFirstBooking = index === 0; - - await scheduleWorkflowReminders({ - workflows: updatedBookings[index]?.eventType?.workflows || [], - smsReminderNumber: updatedBookings[index].smsReminderNumber, - calendarEvent: { - ...evtOfBooking, - ...{ metadata: { videoCallUrl }, eventType: { slug: eventTypeSlug } }, - }, - isFirstRecurringEvent: isFirstBooking, - hideBranding: !!updatedBookings[index].eventType?.owner?.hideBranding, - eventTypeRequiresConfirmation: true, - }); - } + const eventTypeSlug = updatedBookings[index].eventType?.slug || ""; + const evtOfBooking = { ...evt, metadata: { videoCallUrl }, eventType: { slug: eventTypeSlug } }; + evtOfBooking.startTime = updatedBookings[index].startTime.toISOString(); + evtOfBooking.endTime = updatedBookings[index].endTime.toISOString(); + evtOfBooking.uid = updatedBookings[index].uid; + const isFirstBooking = index === 0; + await scheduleMandatoryReminder( + evtOfBooking, + updatedBookings[index]?.eventType?.workflows || [], + false, + !!updatedBookings[index].eventType?.owner?.hideBranding, + evt.attendeeSeatId + ); + await scheduleWorkflowReminders({ + workflows: updatedBookings[index]?.eventType?.workflows || [], + smsReminderNumber: updatedBookings[index].smsReminderNumber, + calendarEvent: evtOfBooking, + isFirstRecurringEvent: isFirstBooking, + hideBranding: !!updatedBookings[index].eventType?.owner?.hideBranding, + eventTypeRequiresConfirmation: true, + }); } } catch (error) { // Silently fail diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index b3a4f5643c..bab66377a4 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -25,6 +25,7 @@ import { getEventName } from "@calcom/core/event"; import { getUserAvailability } from "@calcom/core/getUserAvailability"; import { deleteMeeting } from "@calcom/core/videoClient"; import dayjs from "@calcom/dayjs"; +import { scheduleMandatoryReminder } from "@calcom/ee/workflows/lib/reminders/scheduleMandatoryReminder"; import { sendAttendeeRequestEmail, sendOrganizerRequestEmail, @@ -2718,15 +2719,21 @@ async function handler( } const metadataFromEvent = videoCallUrl ? { videoCallUrl } : undefined; + const evtWithMetadata = { ...evt, metadata: metadataFromEvent, eventType: { slug: eventType.slug } }; + + await scheduleMandatoryReminder( + evtWithMetadata, + eventType.workflows || [], + !isConfirmedByDefault, + !!eventType.owner?.hideBranding, + evt.attendeeSeatId + ); try { await scheduleWorkflowReminders({ workflows: eventType.workflows, smsReminderNumber: smsReminderNumber || null, - calendarEvent: { - ...evt, - ...{ metadata: metadataFromEvent, eventType: { slug: eventType.slug } }, - }, + calendarEvent: evtWithMetadata, isNotConfirmed: !isConfirmedByDefault, isRescheduleEvent: !!rescheduleUid, isFirstRecurringEvent: true, diff --git a/packages/features/ee/workflows/api/scheduleEmailReminders.ts b/packages/features/ee/workflows/api/scheduleEmailReminders.ts index fa03762ad1..0ad746735e 100644 --- a/packages/features/ee/workflows/api/scheduleEmailReminders.ts +++ b/packages/features/ee/workflows/api/scheduleEmailReminders.ts @@ -6,6 +6,7 @@ import { v4 as uuidv4 } from "uuid"; import dayjs from "@calcom/dayjs"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; +import { SENDER_NAME } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import { defaultHandler } from "@calcom/lib/server"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; @@ -121,100 +122,185 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { } for (const reminder of unscheduledReminders) { - if (!reminder.workflowStep || !reminder.booking) { + if (!reminder.booking) { continue; } - try { - let sendTo; + if (!reminder.isMandatoryReminder && reminder.workflowStep) { + try { + let sendTo; - switch (reminder.workflowStep.action) { - case WorkflowActions.EMAIL_HOST: - sendTo = reminder.booking.user?.email; - break; - case WorkflowActions.EMAIL_ATTENDEE: - sendTo = reminder.booking.attendees[0].email; - break; - case WorkflowActions.EMAIL_ADDRESS: - sendTo = reminder.workflowStep.sendTo; - } + switch (reminder.workflowStep.action) { + case WorkflowActions.EMAIL_HOST: + sendTo = reminder.booking.user?.email; + break; + case WorkflowActions.EMAIL_ATTENDEE: + sendTo = reminder.booking.attendees[0].email; + break; + case WorkflowActions.EMAIL_ADDRESS: + sendTo = reminder.workflowStep.sendTo; + } - const name = - reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE - ? reminder.booking.attendees[0].name - : reminder.booking.user?.name; + const name = + reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE + ? reminder.booking.attendees[0].name + : reminder.booking.user?.name; - const attendeeName = - reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE - ? reminder.booking.user?.name - : reminder.booking.attendees[0].name; + const attendeeName = + reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE + ? reminder.booking.user?.name + : reminder.booking.attendees[0].name; - const timeZone = - reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE - ? reminder.booking.attendees[0].timeZone - : reminder.booking.user?.timeZone; + const timeZone = + reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE + ? reminder.booking.attendees[0].timeZone + : reminder.booking.user?.timeZone; - const locale = - reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE || - reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE - ? reminder.booking.attendees[0].locale - : reminder.booking.user?.locale; + const locale = + reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE || + reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE + ? reminder.booking.attendees[0].locale + : reminder.booking.user?.locale; - let emailContent = { - emailSubject: reminder.workflowStep.emailSubject || "", - emailBody: `${reminder.workflowStep.reminderBody || ""}`, - }; - - let emailBodyEmpty = false; - - if (reminder.workflowStep.reminderBody) { - const { responses } = getCalEventResponses({ - bookingFields: reminder.booking.eventType?.bookingFields ?? null, - booking: reminder.booking, - }); - - 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, - eventDate: dayjs(reminder.booking.startTime).tz(timeZone), - eventEndTime: dayjs(reminder.booking?.endTime).tz(timeZone), - timeZone: timeZone, - location: reminder.booking.location || "", - additionalNotes: reminder.booking.description, - responses: responses, - meetingUrl: bookingMetadataSchema.parse(reminder.booking.metadata || {})?.videoCallUrl, - cancelLink: `/booking/${reminder.booking.uid}?cancel=true`, - rescheduleLink: `/${reminder.booking.user?.username}/${reminder.booking.eventType?.slug}?rescheduleUid=${reminder.booking.uid}`, + let emailContent = { + emailSubject: reminder.workflowStep.emailSubject || "", + emailBody: `${ + reminder.workflowStep.reminderBody || "" + }`, }; - const emailLocale = locale || "en"; - const emailSubject = customTemplate( - reminder.workflowStep.emailSubject || "", - variables, - emailLocale, - getTimeFormatStringFromUserTimeFormat(reminder.booking.user?.timeFormat), - !!reminder.booking.user?.hideBranding - ).text; - emailContent.emailSubject = emailSubject; - emailContent.emailBody = customTemplate( - reminder.workflowStep.reminderBody || "", - variables, - emailLocale, - getTimeFormatStringFromUserTimeFormat(reminder.booking.user?.timeFormat), - !!reminder.booking.user?.hideBranding - ).html; - emailBodyEmpty = - customTemplate( + let emailBodyEmpty = false; + + if (reminder.workflowStep.reminderBody) { + const { responses } = getCalEventResponses({ + bookingFields: reminder.booking.eventType?.bookingFields ?? null, + booking: reminder.booking, + }); + + 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, + eventDate: dayjs(reminder.booking.startTime).tz(timeZone), + eventEndTime: dayjs(reminder.booking?.endTime).tz(timeZone), + timeZone: timeZone, + location: reminder.booking.location || "", + additionalNotes: reminder.booking.description, + responses: responses, + meetingUrl: bookingMetadataSchema.parse(reminder.booking.metadata || {})?.videoCallUrl, + cancelLink: `/booking/${reminder.booking.uid}?cancel=true`, + rescheduleLink: `/${reminder.booking.user?.username}/${reminder.booking.eventType?.slug}?rescheduleUid=${reminder.booking.uid}`, + }; + const emailLocale = locale || "en"; + const emailSubject = customTemplate( + reminder.workflowStep.emailSubject || "", + variables, + emailLocale, + getTimeFormatStringFromUserTimeFormat(reminder.booking.user?.timeFormat), + !!reminder.booking.user?.hideBranding + ).text; + emailContent.emailSubject = emailSubject; + emailContent.emailBody = customTemplate( reminder.workflowStep.reminderBody || "", variables, emailLocale, - getTimeFormatStringFromUserTimeFormat(reminder.booking.user?.timeFormat) - ).text.length === 0; - } else if (reminder.workflowStep.template === WorkflowTemplates.REMINDER) { + getTimeFormatStringFromUserTimeFormat(reminder.booking.user?.timeFormat), + !!reminder.booking.user?.hideBranding + ).html; + + emailBodyEmpty = + customTemplate( + reminder.workflowStep.reminderBody || "", + variables, + emailLocale, + getTimeFormatStringFromUserTimeFormat(reminder.booking.user?.timeFormat) + ).text.length === 0; + } else if (reminder.workflowStep.template === WorkflowTemplates.REMINDER) { + emailContent = emailReminderTemplate( + false, + reminder.workflowStep.action, + getTimeFormatStringFromUserTimeFormat(reminder.booking.user?.timeFormat), + reminder.booking.startTime.toISOString() || "", + reminder.booking.endTime.toISOString() || "", + reminder.booking.eventType?.title || "", + timeZone || "", + attendeeName || "", + name || "", + !!reminder.booking.user?.hideBranding + ); + } + + if (emailContent.emailSubject.length > 0 && !emailBodyEmpty && sendTo) { + const batchIdResponse = await client.request({ + url: "/v3/mail/batch", + method: "POST", + }); + + const batchId = batchIdResponse[1].batch_id; + + if (reminder.workflowStep.action !== WorkflowActions.EMAIL_ADDRESS) { + sendEmailPromises.push( + sgMail.send({ + to: sendTo, + from: { + email: senderEmail, + name: reminder.workflowStep.sender || SENDER_NAME, + }, + subject: emailContent.emailSubject, + html: emailContent.emailBody, + batchId: batchId, + sendAt: dayjs(reminder.scheduledDate).unix(), + replyTo: reminder.booking.user?.email || senderEmail, + mailSettings: { + sandboxMode: { + enable: sandboxMode, + }, + }, + attachments: reminder.workflowStep.includeCalendarEvent + ? [ + { + content: Buffer.from(getiCalEventAsString(reminder.booking) || "").toString("base64"), + filename: "event.ics", + type: "text/calendar; method=REQUEST", + disposition: "attachment", + contentId: uuidv4(), + }, + ] + : undefined, + }) + ); + } + + await prisma.workflowReminder.update({ + where: { + id: reminder.id, + }, + data: { + scheduled: true, + referenceId: batchId, + }, + }); + } + } catch (error) { + logger.error(`Error scheduling Email with error ${error}`); + } + } else if (reminder.isMandatoryReminder) { + try { + const sendTo = reminder.booking.attendees[0].email; + const name = reminder.booking.attendees[0].name; + const attendeeName = reminder.booking.user?.name; + const timeZone = reminder.booking.attendees[0].timeZone; + + let emailContent = { + emailSubject: "", + emailBody: "", + }; + + const emailBodyEmpty = false; + emailContent = emailReminderTemplate( false, - reminder.workflowStep.action, + WorkflowActions.EMAIL_ATTENDEE, getTimeFormatStringFromUserTimeFormat(reminder.booking.user?.timeFormat), reminder.booking.startTime.toISOString() || "", reminder.booking.endTime.toISOString() || "", @@ -224,23 +310,20 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { name || "", !!reminder.booking.user?.hideBranding ); - } + if (emailContent.emailSubject.length > 0 && !emailBodyEmpty && sendTo) { + const batchIdResponse = await client.request({ + url: "/v3/mail/batch", + method: "POST", + }); - if (emailContent.emailSubject.length > 0 && !emailBodyEmpty && sendTo) { - const batchIdResponse = await client.request({ - url: "/v3/mail/batch", - method: "POST", - }); + const batchId = batchIdResponse[1].batch_id; - const batchId = batchIdResponse[1].batch_id; - - if (reminder.workflowStep.action !== WorkflowActions.EMAIL_ADDRESS) { sendEmailPromises.push( sgMail.send({ to: sendTo, from: { email: senderEmail, - name: reminder.workflowStep.sender || "Cal.com", + name: reminder.workflowStep?.sender || SENDER_NAME, }, subject: emailContent.emailSubject, html: emailContent.emailBody, @@ -252,33 +335,23 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { enable: sandboxMode, }, }, - attachments: reminder.workflowStep.includeCalendarEvent - ? [ - { - content: Buffer.from(getiCalEventAsString(reminder.booking) || "").toString("base64"), - filename: "event.ics", - type: "text/calendar; method=REQUEST", - disposition: "attachment", - contentId: uuidv4(), - }, - ] - : undefined, + attachments: undefined, }) ); - } - await prisma.workflowReminder.update({ - where: { - id: reminder.id, - }, - data: { - scheduled: true, - referenceId: batchId, - }, - }); + await prisma.workflowReminder.update({ + where: { + id: reminder.id, + }, + data: { + scheduled: true, + referenceId: batchId, + }, + }); + } + } catch (error) { + logger.error(`Error scheduling Email with error ${error}`); } - } catch (error) { - logger.error(`Error scheduling Email with error ${error}`); } } diff --git a/packages/features/ee/workflows/lib/getWorkflowReminders.ts b/packages/features/ee/workflows/lib/getWorkflowReminders.ts index fe16bead7c..e251397aa4 100644 --- a/packages/features/ee/workflows/lib/getWorkflowReminders.ts +++ b/packages/features/ee/workflows/lib/getWorkflowReminders.ts @@ -26,7 +26,10 @@ type PartialBooking = > & { eventType: Partial | null } & { user: Partial | null }) | null; -export type PartialWorkflowReminder = Pick & { +export type PartialWorkflowReminder = Pick< + WorkflowReminder, + "id" | "isMandatoryReminder" | "scheduledDate" +> & { booking: PartialBooking | null; } & { workflowStep: PartialWorkflowStep }; @@ -113,6 +116,7 @@ export async function getAllUnscheduledReminders(): Promise; -export const scheduleEmailReminder = async ( - evt: BookingInfo, - triggerEvent: WorkflowTriggerEvents, - action: ScheduleEmailReminderAction, +export interface ScheduleReminderArgs { + evt: BookingInfo; + triggerEvent: WorkflowTriggerEvents; timeSpan: { time: number | null; timeUnit: TimeUnit | null; - }, - sendTo: MailData["to"], - emailSubject: string, - emailBody: string, - workflowStepId: number, - template: WorkflowTemplates, - sender: string, - hideBranding?: boolean, - seatReferenceUid?: string, - includeCalendarEvent?: boolean -) => { + }; + template: WorkflowTemplates; + sender?: string | null; + workflowStepId?: number; + seatReferenceUid?: string; +} + +interface scheduleEmailReminderArgs extends ScheduleReminderArgs { + sendTo: MailData["to"]; + action: ScheduleEmailReminderAction; + emailSubject?: string; + emailBody?: string; + hideBranding?: boolean; + includeCalendarEvent?: boolean; + isMandatoryReminder?: boolean; +} + +export const scheduleEmailReminder = async (args: scheduleEmailReminderArgs) => { + const { + evt, + triggerEvent, + timeSpan, + template, + sender, + workflowStepId, + seatReferenceUid, + sendTo, + emailSubject = "", + emailBody = "", + hideBranding, + includeCalendarEvent, + isMandatoryReminder, + action, + } = args; if (action === WorkflowActions.EMAIL_ADDRESS) return; const { startTime, endTime } = evt; const uid = evt.uid as string; @@ -251,7 +274,7 @@ export const scheduleEmailReminder = async ( to: data.to, from: { email: senderEmail, - name: sender, + name: sender || SENDER_NAME, }, subject: emailContent.emailSubject, html: emailContent.emailBody, @@ -289,7 +312,7 @@ export const scheduleEmailReminder = async ( // TODO: Maybe don't await for this? await Promise.all(promises); } catch (error) { - console.log("Error sending Email"); + log.error("Error sending Email"); } } else if ( (triggerEvent === WorkflowTriggerEvents.BEFORE_EVENT || @@ -311,32 +334,59 @@ export const scheduleEmailReminder = async ( }, triggerEvent ); + if (!isMandatoryReminder) { + await prisma.workflowReminder.create({ + data: { + bookingUid: uid, + workflowStepId: workflowStepId, + method: WorkflowMethods.EMAIL, + scheduledDate: scheduledDate.toDate(), + scheduled: true, + referenceId: batchId, + seatReferenceId: seatReferenceUid, + }, + }); + } else { + await prisma.workflowReminder.create({ + data: { + bookingUid: uid, + method: WorkflowMethods.EMAIL, + scheduledDate: scheduledDate.toDate(), + scheduled: true, + referenceId: batchId, + seatReferenceId: seatReferenceUid, + isMandatoryReminder: true, + }, + }); + } + } catch (error) { + log.error(`Error scheduling email with error ${error}`); + } + } else if (scheduledDate.isAfter(currentDate.add(72, "hour"))) { + // Write to DB and send to CRON if scheduled reminder date is past 72 hours + if (!isMandatoryReminder) { await prisma.workflowReminder.create({ data: { bookingUid: uid, workflowStepId: workflowStepId, method: WorkflowMethods.EMAIL, scheduledDate: scheduledDate.toDate(), - scheduled: true, - referenceId: batchId, + scheduled: false, seatReferenceId: seatReferenceUid, }, }); - } catch (error) { - console.log(`Error scheduling email with error ${error}`); + } else { + await prisma.workflowReminder.create({ + data: { + bookingUid: uid, + method: WorkflowMethods.EMAIL, + scheduledDate: scheduledDate.toDate(), + scheduled: false, + seatReferenceId: seatReferenceUid, + isMandatoryReminder: true, + }, + }); } - } else if (scheduledDate.isAfter(currentDate.add(72, "hour"))) { - // Write to DB and send to CRON if scheduled reminder date is past 72 hours - await prisma.workflowReminder.create({ - data: { - bookingUid: uid, - workflowStepId: workflowStepId, - method: WorkflowMethods.EMAIL, - scheduledDate: scheduledDate.toDate(), - scheduled: false, - seatReferenceId: seatReferenceUid, - }, - }); } } }; @@ -362,6 +412,6 @@ export const deleteScheduledEmailReminder = async (reminderId: number, reference }, }); } catch (error) { - console.log(`Error canceling reminder with error ${error}`); + log.error(`Error canceling reminder with error ${error}`); } }; diff --git a/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts b/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts index 7104fa1830..c23291ab94 100644 --- a/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts +++ b/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts @@ -1,14 +1,16 @@ import type { Workflow, WorkflowsOnEventTypes, WorkflowStep } from "@prisma/client"; import { + isSMSAction, isTextMessageToAttendeeAction, isWhatsappAction, } from "@calcom/features/ee/workflows/lib/actionHelperFunctions"; -import { SENDER_ID, SENDER_NAME } from "@calcom/lib/constants"; +import { SENDER_NAME } from "@calcom/lib/constants"; import { WorkflowActions, WorkflowMethods, WorkflowTriggerEvents } from "@calcom/prisma/enums"; import type { CalendarEvent } from "@calcom/types/Calendar"; import { deleteScheduledEmailReminder, scheduleEmailReminder } from "./emailReminderManager"; +import type { ScheduleTextReminderAction } from "./smsReminderManager"; import { deleteScheduledSMSReminder, scheduleSMSReminder } from "./smsReminderManager"; import { deleteScheduledWhatsappReminder, scheduleWhatsappReminder } from "./whatsappReminderManager"; @@ -51,26 +53,26 @@ const processWorkflowStep = async ( ) => { if (isTextMessageToAttendeeAction(step.action) && !eventTypeRequiresConfirmation) return; - if (step.action === WorkflowActions.SMS_ATTENDEE || step.action === WorkflowActions.SMS_NUMBER) { + if (isSMSAction(step.action)) { const sendTo = step.action === WorkflowActions.SMS_ATTENDEE ? smsReminderNumber : step.sendTo; - await scheduleSMSReminder( + await scheduleSMSReminder({ evt, - sendTo, - workflow.trigger, - step.action, - { + reminderPhone: sendTo, + triggerEvent: workflow.trigger, + action: step.action as ScheduleTextReminderAction, + timeSpan: { time: workflow.time, timeUnit: workflow.timeUnit, }, - step.reminderBody || "", - step.id, - step.template, - step.sender || SENDER_ID, - workflow.userId, - workflow.teamId, - step.numberVerificationPending, - seatReferenceUid - ); + message: step.reminderBody || "", + workflowStepId: step.id, + template: step.template, + sender: step.sender, + userId: workflow.userId, + teamId: workflow.teamId, + isVerificationPending: step.numberVerificationPending, + seatReferenceUid, + }); } else if (step.action === WorkflowActions.EMAIL_ATTENDEE || step.action === WorkflowActions.EMAIL_HOST) { let sendTo: string[] = []; @@ -88,43 +90,43 @@ const processWorkflowStep = async ( break; } - await scheduleEmailReminder( + await scheduleEmailReminder({ evt, - workflow.trigger, - step.action, - { + triggerEvent: workflow.trigger, + action: step.action, + timeSpan: { time: workflow.time, timeUnit: workflow.timeUnit, }, sendTo, - step.emailSubject || "", - step.reminderBody || "", - step.id, - step.template, - step.sender || SENDER_NAME, + emailSubject: step.emailSubject || "", + emailBody: step.reminderBody || "", + template: step.template, + sender: step.sender || SENDER_NAME, + workflowStepId: step.id, hideBranding, seatReferenceUid, - step.includeCalendarEvent - ); + includeCalendarEvent: step.includeCalendarEvent, + }); } else if (isWhatsappAction(step.action)) { const sendTo = step.action === WorkflowActions.WHATSAPP_ATTENDEE ? smsReminderNumber : step.sendTo; - await scheduleWhatsappReminder( + await scheduleWhatsappReminder({ evt, - sendTo, - workflow.trigger, - step.action, - { + reminderPhone: sendTo, + triggerEvent: workflow.trigger, + action: step.action as ScheduleTextReminderAction, + timeSpan: { time: workflow.time, timeUnit: workflow.timeUnit, }, - step.reminderBody || "", - step.id, - step.template, - workflow.userId, - workflow.teamId, - step.numberVerificationPending, - seatReferenceUid - ); + message: step.reminderBody || "", + workflowStepId: step.id, + template: step.template, + userId: workflow.userId, + teamId: workflow.teamId, + isVerificationPending: step.numberVerificationPending, + seatReferenceUid, + }); } }; @@ -164,7 +166,6 @@ export const scheduleWorkflowReminders = async (args: ScheduleWorkflowRemindersA ) { continue; } - for (const step of workflow.steps) { await processWorkflowStep(workflow, step, { calendarEvent: evt, diff --git a/packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts b/packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts new file mode 100644 index 0000000000..3512e9f9f1 --- /dev/null +++ b/packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts @@ -0,0 +1,72 @@ +import type { Workflow, WorkflowsOnEventTypes, WorkflowStep } from "@prisma/client"; + +import type { getEventTypesFromDB } from "@calcom/features/bookings/lib/handleNewBooking"; +import { scheduleEmailReminder } from "@calcom/features/ee/workflows/lib/reminders/emailReminderManager"; +import type { BookingInfo } from "@calcom/features/ee/workflows/lib/reminders/smsReminderManager"; +import type { getDefaultEvent } from "@calcom/lib/defaultEvents"; +import logger from "@calcom/lib/logger"; +import { WorkflowTriggerEvents, TimeUnit, WorkflowActions, WorkflowTemplates } from "@calcom/prisma/enums"; + +const log = logger.getSubLogger({ prefix: ["[scheduleMandatoryReminder]"] }); + +export type NewBookingEventType = + | Awaited> + | Awaited>; + +export async function scheduleMandatoryReminder( + evt: BookingInfo, + workflows: (WorkflowsOnEventTypes & { + workflow: Workflow & { + steps: WorkflowStep[]; + }; + })[], + requiresConfirmation: boolean, + hideBranding: boolean, + seatReferenceUid: string | undefined +) { + try { + const hasExistingWorkflow = workflows.some((workflow) => { + return ( + workflow.workflow?.trigger === WorkflowTriggerEvents.BEFORE_EVENT && + ((workflow.workflow.time !== null && + workflow.workflow.time <= 12 && + workflow.workflow?.timeUnit === TimeUnit.HOUR) || + (workflow.workflow.time !== null && + workflow.workflow.time <= 720 && + workflow.workflow?.timeUnit === TimeUnit.MINUTE)) && + workflow.workflow?.steps.some((step) => step?.action === WorkflowActions.EMAIL_ATTENDEE) + ); + }); + + if ( + !hasExistingWorkflow && + evt.attendees.some((attendee) => attendee.email.includes("@gmail.com")) && + !requiresConfirmation + ) { + try { + const filteredAttendees = + evt.attendees?.filter((attendee) => attendee.email.includes("@gmail.com")) || []; + + await scheduleEmailReminder({ + evt, + triggerEvent: WorkflowTriggerEvents.BEFORE_EVENT, + action: WorkflowActions.EMAIL_ATTENDEE, + timeSpan: { + time: 1, + timeUnit: TimeUnit.HOUR, + }, + sendTo: filteredAttendees, + template: WorkflowTemplates.REMINDER, + hideBranding, + seatReferenceUid, + includeCalendarEvent: false, + isMandatoryReminder: true, + }); + } catch (error) { + log.error("Error while scheduling mandatory reminders", JSON.stringify({ error })); + } + } + } catch (error) { + log.error("Error while scheduling mandatory reminders", JSON.stringify({ error })); + } +} diff --git a/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts b/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts index 10fb2166d1..71a24f1345 100644 --- a/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts +++ b/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts @@ -1,15 +1,16 @@ import dayjs from "@calcom/dayjs"; +import { SENDER_ID } from "@calcom/lib/constants"; import logger from "@calcom/lib/logger"; import type { TimeFormat } from "@calcom/lib/timeFormat"; import prisma from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; -import type { TimeUnit } from "@calcom/prisma/enums"; import { WorkflowTemplates, WorkflowActions, WorkflowMethods } from "@calcom/prisma/enums"; import { WorkflowTriggerEvents } from "@calcom/prisma/enums"; import { bookingMetadataSchema } from "@calcom/prisma/zod-utils"; import type { CalEventResponses, RecurringEvent } from "@calcom/types/Calendar"; import { getSenderId } from "../alphanumericSenderIdSupport"; +import type { ScheduleReminderArgs } from "./emailReminderManager"; import * as twilio from "./smsProviders/twilioProvider"; import type { VariablesType } from "./templates/customTemplate"; import customTemplate from "./templates/customTemplate"; @@ -55,33 +56,42 @@ export type BookingInfo = { metadata?: Prisma.JsonValue; }; -type ScheduleSMSReminderAction = Extract; +export type ScheduleTextReminderAction = Extract< + WorkflowActions, + "SMS_ATTENDEE" | "SMS_NUMBER" | "WHATSAPP_ATTENDEE" | "WHATSAPP_NUMBER" +>; +export interface ScheduleTextReminderArgs extends ScheduleReminderArgs { + reminderPhone: string | null; + message: string; + action: ScheduleTextReminderAction; + userId?: number | null; + teamId?: number | null; + isVerificationPending?: boolean; +} -export const scheduleSMSReminder = async ( - evt: BookingInfo, - reminderPhone: string | null, - triggerEvent: WorkflowTriggerEvents, - action: ScheduleSMSReminderAction, - timeSpan: { - time: number | null; - timeUnit: TimeUnit | null; - }, - message: string, - workflowStepId: number, - template: WorkflowTemplates, - sender: string, - userId?: number | null, - teamId?: number | null, - isVerificationPending = false, - seatReferenceUid?: string -) => { +export const scheduleSMSReminder = async (args: ScheduleTextReminderArgs) => { + const { + evt, + reminderPhone, + triggerEvent, + action, + timeSpan, + message = "", + workflowStepId, + template, + sender, + userId, + teamId, + isVerificationPending = false, + seatReferenceUid, + } = args; const { startTime, endTime } = evt; const uid = evt.uid as string; const currentDate = dayjs(); const timeUnit: timeUnitLowerCase | undefined = timeSpan.timeUnit?.toLocaleLowerCase() as timeUnitLowerCase; let scheduledDate = null; - const senderID = getSenderId(reminderPhone, sender); + const senderID = getSenderId(reminderPhone, sender || SENDER_ID); //SMS_ATTENDEE action does not need to be verified //isVerificationPending is from all already existing workflows (once they edit their workflow, they will also have to verify the number) @@ -126,7 +136,9 @@ export const scheduleSMSReminder = async ( ? attendeeToBeUsedInSMS.language?.locale : evt.organizer.language.locale; - if (message) { + let smsMessage = message; + + if (smsMessage) { const variables: VariablesType = { eventName: evt.title, organizerName: evt.organizer.name, @@ -144,10 +156,10 @@ export const scheduleSMSReminder = async ( cancelLink: `/booking/${evt.uid}?cancel=true`, rescheduleLink: `/${evt.organizer.username}/${evt.eventType.slug}?rescheduleUid=${evt.uid}`, }; - const customMessage = customTemplate(message, variables, locale, evt.organizer.timeFormat); - message = customMessage.text; + const customMessage = customTemplate(smsMessage, variables, locale, evt.organizer.timeFormat); + smsMessage = customMessage.text; } else if (template === WorkflowTemplates.REMINDER) { - message = + smsMessage = smsReminderTemplate( false, action, @@ -161,9 +173,9 @@ export const scheduleSMSReminder = async ( } // Allows debugging generated email content without waiting for sendgrid to send emails - log.debug(`Sending sms for trigger ${triggerEvent}`, message); + log.debug(`Sending sms for trigger ${triggerEvent}`, smsMessage); - if (message.length > 0 && reminderPhone && isNumberVerified) { + if (smsMessage.length > 0 && reminderPhone && isNumberVerified) { //send SMS when event is booked/cancelled/rescheduled if ( triggerEvent === WorkflowTriggerEvents.NEW_EVENT || @@ -171,9 +183,9 @@ export const scheduleSMSReminder = async ( triggerEvent === WorkflowTriggerEvents.RESCHEDULE_EVENT ) { try { - await twilio.sendSMS(reminderPhone, message, senderID); + await twilio.sendSMS(reminderPhone, smsMessage, senderID); } catch (error) { - console.log(`Error sending SMS with error ${error}`); + log.error(`Error sending SMS with error ${error}`); } } else if ( (triggerEvent === WorkflowTriggerEvents.BEFORE_EVENT || @@ -188,7 +200,7 @@ export const scheduleSMSReminder = async ( try { const scheduledSMS = await twilio.scheduleSMS( reminderPhone, - message, + smsMessage, scheduledDate.toDate(), senderID ); @@ -205,7 +217,7 @@ export const scheduleSMSReminder = async ( }, }); } catch (error) { - console.log(`Error scheduling SMS with error ${error}`); + log.error(`Error scheduling SMS with error ${error}`); } } else if (scheduledDate.isAfter(currentDate.add(7, "day"))) { // Write to DB and send to CRON if scheduled reminder date is past 7 days @@ -236,6 +248,6 @@ export const deleteScheduledSMSReminder = async (reminderId: number, referenceId }, }); } catch (error) { - console.log(`Error canceling reminder with error ${error}`); + log.error(`Error canceling reminder with error ${error}`); } }; diff --git a/packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts b/packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts index 2945f0e55e..07a774aa9b 100644 --- a/packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts +++ b/packages/features/ee/workflows/lib/reminders/whatsappReminderManager.ts @@ -1,5 +1,3 @@ -import type { TimeUnit } from "@prisma/client"; - import dayjs from "@calcom/dayjs"; import logger from "@calcom/lib/logger"; import prisma from "@calcom/prisma"; @@ -11,7 +9,7 @@ import { } from "@calcom/prisma/enums"; import * as twilio from "./smsProviders/twilioProvider"; -import type { BookingInfo, timeUnitLowerCase } from "./smsReminderManager"; +import type { ScheduleTextReminderArgs, timeUnitLowerCase } from "./smsReminderManager"; import { deleteScheduledSMSReminder } from "./smsReminderManager"; import { whatsappEventCancelledTemplate, @@ -22,23 +20,21 @@ import { const log = logger.getSubLogger({ prefix: ["[whatsappReminderManager]"] }); -export const scheduleWhatsappReminder = async ( - evt: BookingInfo, - reminderPhone: string | null, - triggerEvent: WorkflowTriggerEvents, - action: WorkflowActions, - timeSpan: { - time: number | null; - timeUnit: TimeUnit | null; - }, - message: string, - workflowStepId: number, - template: WorkflowTemplates, - userId?: number | null, - teamId?: number | null, - isVerificationPending = false, - seatReferenceUid?: string -) => { +export const scheduleWhatsappReminder = async (args: ScheduleTextReminderArgs) => { + const { + evt, + reminderPhone, + triggerEvent, + action, + timeSpan, + message = "", + workflowStepId, + template, + userId, + teamId, + isVerificationPending = false, + seatReferenceUid, + } = args; const { startTime, endTime } = evt; const uid = evt.uid as string; const currentDate = dayjs(); @@ -72,9 +68,11 @@ export const scheduleWhatsappReminder = async ( const timeZone = action === WorkflowActions.WHATSAPP_ATTENDEE ? evt.attendees[0].timeZone : evt.organizer.timeZone; + let textMessage = message; + switch (template) { case WorkflowTemplates.REMINDER: - message = + textMessage = whatsappReminderTemplate( false, action, @@ -87,7 +85,7 @@ export const scheduleWhatsappReminder = async ( ) || message; break; case WorkflowTemplates.CANCELLED: - message = + textMessage = whatsappEventCancelledTemplate( false, action, @@ -100,7 +98,7 @@ export const scheduleWhatsappReminder = async ( ) || message; break; case WorkflowTemplates.RESCHEDULED: - message = + textMessage = whatsappEventRescheduledTemplate( false, action, @@ -113,7 +111,7 @@ export const scheduleWhatsappReminder = async ( ) || message; break; case WorkflowTemplates.COMPLETED: - message = + textMessage = whatsappEventCompletedTemplate( false, action, @@ -126,7 +124,7 @@ export const scheduleWhatsappReminder = async ( ) || message; break; default: - message = + textMessage = whatsappReminderTemplate( false, action, @@ -140,8 +138,8 @@ export const scheduleWhatsappReminder = async ( } // Allows debugging generated whatsapp content without waiting for twilio to send whatsapp messages - log.debug(`Sending Whatsapp for trigger ${triggerEvent}`, message); - if (message.length > 0 && reminderPhone && isNumberVerified) { + log.debug(`Sending Whatsapp for trigger ${triggerEvent}`, textMessage); + if (textMessage.length > 0 && reminderPhone && isNumberVerified) { //send WHATSAPP when event is booked/cancelled/rescheduled if ( triggerEvent === WorkflowTriggerEvents.NEW_EVENT || @@ -149,7 +147,7 @@ export const scheduleWhatsappReminder = async ( triggerEvent === WorkflowTriggerEvents.RESCHEDULE_EVENT ) { try { - await twilio.sendSMS(reminderPhone, message, "", true); + await twilio.sendSMS(reminderPhone, textMessage, "", true); } catch (error) { console.log(`Error sending WHATSAPP with error ${error}`); } @@ -166,7 +164,7 @@ export const scheduleWhatsappReminder = async ( try { const scheduledWHATSAPP = await twilio.scheduleSMS( reminderPhone, - message, + textMessage, scheduledDate.toDate(), "", true diff --git a/packages/prisma/migrations/20231203154633_adding_is_mandatory_reminder_field_for_mandatory_reminders/migration.sql b/packages/prisma/migrations/20231203154633_adding_is_mandatory_reminder_field_for_mandatory_reminders/migration.sql new file mode 100644 index 0000000000..c9da8290d3 --- /dev/null +++ b/packages/prisma/migrations/20231203154633_adding_is_mandatory_reminder_field_for_mandatory_reminders/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "WorkflowReminder" ADD COLUMN "isMandatoryReminder" BOOLEAN DEFAULT false; diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index b65a687acb..70b3821e63 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -823,17 +823,18 @@ enum TimeUnit { } model WorkflowReminder { - id Int @id @default(autoincrement()) - bookingUid String? - booking Booking? @relation(fields: [bookingUid], references: [uid]) - method WorkflowMethods - scheduledDate DateTime - referenceId String? @unique - scheduled Boolean - workflowStepId Int? - workflowStep WorkflowStep? @relation(fields: [workflowStepId], references: [id]) - cancelled Boolean? - seatReferenceId String? + id Int @id @default(autoincrement()) + bookingUid String? + booking Booking? @relation(fields: [bookingUid], references: [uid]) + method WorkflowMethods + scheduledDate DateTime + referenceId String? @unique + scheduled Boolean + workflowStepId Int? + workflowStep WorkflowStep? @relation(fields: [workflowStepId], references: [id]) + cancelled Boolean? + seatReferenceId String? + isMandatoryReminder Boolean? @default(false) @@index([bookingUid]) @@index([workflowStepId]) diff --git a/packages/trpc/server/routers/viewer/workflows/activateEventType.handler.ts b/packages/trpc/server/routers/viewer/workflows/activateEventType.handler.ts index a8f8c0e861..1068ab3fb4 100644 --- a/packages/trpc/server/routers/viewer/workflows/activateEventType.handler.ts +++ b/packages/trpc/server/routers/viewer/workflows/activateEventType.handler.ts @@ -10,7 +10,6 @@ import { deleteScheduledWhatsappReminder, scheduleWhatsappReminder, } from "@calcom/features/ee/workflows/lib/reminders/whatsappReminderManager"; -import { SENDER_ID, SENDER_NAME } from "@calcom/lib/constants"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import { prisma } from "@calcom/prisma"; import { BookingStatus } from "@calcom/prisma/client"; @@ -197,54 +196,54 @@ export const activateEventTypeHandler = async ({ ctx, input }: ActivateEventType break; } - await scheduleEmailReminder( - bookingInfo, - eventTypeWorkflow.trigger, - step.action, - { + await scheduleEmailReminder({ + evt: bookingInfo, + triggerEvent: eventTypeWorkflow.trigger, + action: step.action, + timeSpan: { time: eventTypeWorkflow.time, timeUnit: eventTypeWorkflow.timeUnit, }, sendTo, - step.emailSubject || "", - step.reminderBody || "", - step.id, - step.template, - step.sender || SENDER_NAME - ); + emailSubject: step.emailSubject || "", + emailBody: step.reminderBody || "", + template: step.template, + sender: step.sender, + workflowStepId: step.id, + }); } else if (step.action === WorkflowActions.SMS_NUMBER && step.sendTo) { - await scheduleSMSReminder( - bookingInfo, - step.sendTo, - eventTypeWorkflow.trigger, - step.action, - { + await scheduleSMSReminder({ + evt: bookingInfo, + reminderPhone: step.sendTo, + triggerEvent: eventTypeWorkflow.trigger, + action: step.action, + timeSpan: { time: eventTypeWorkflow.time, timeUnit: eventTypeWorkflow.timeUnit, }, - step.reminderBody || "", - step.id, - step.template, - step.sender || SENDER_ID, - booking.userId, - eventTypeWorkflow.teamId - ); + message: step.reminderBody || "", + workflowStepId: step.id, + template: step.template, + sender: step.sender, + userId: booking.userId, + teamId: eventTypeWorkflow.teamId, + }); } else if (step.action === WorkflowActions.WHATSAPP_NUMBER && step.sendTo) { - await scheduleWhatsappReminder( - bookingInfo, - step.sendTo, - eventTypeWorkflow.trigger, - step.action, - { + await scheduleWhatsappReminder({ + evt: bookingInfo, + reminderPhone: step.sendTo, + triggerEvent: eventTypeWorkflow.trigger, + action: step.action, + timeSpan: { time: eventTypeWorkflow.time, timeUnit: eventTypeWorkflow.timeUnit, }, - step.reminderBody || "", - step.id, - step.template, - booking.userId, - eventTypeWorkflow.teamId - ); + message: step.reminderBody || "", + workflowStepId: step.id, + template: step.template, + userId: booking.userId, + teamId: eventTypeWorkflow.teamId, + }); } } } diff --git a/packages/trpc/server/routers/viewer/workflows/update.handler.ts b/packages/trpc/server/routers/viewer/workflows/update.handler.ts index 5799f96756..567dbedce8 100644 --- a/packages/trpc/server/routers/viewer/workflows/update.handler.ts +++ b/packages/trpc/server/routers/viewer/workflows/update.handler.ts @@ -17,7 +17,7 @@ import { deleteScheduledWhatsappReminder, scheduleWhatsappReminder, } from "@calcom/features/ee/workflows/lib/reminders/whatsappReminderManager"; -import { IS_SELF_HOSTED, SENDER_ID, SENDER_NAME } from "@calcom/lib/constants"; +import { IS_SELF_HOSTED } from "@calcom/lib/constants"; import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import type { PrismaClient } from "@calcom/prisma"; @@ -315,54 +315,54 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => { sendTo = step.sendTo || "";*/ } - await scheduleEmailReminder( - bookingInfo, - trigger, - step.action, - { + await scheduleEmailReminder({ + evt: bookingInfo, + triggerEvent: trigger, + action: step.action, + timeSpan: { time, timeUnit, }, sendTo, - step.emailSubject || "", - step.reminderBody || "", - step.id, - step.template, - step.senderName || SENDER_NAME - ); + emailSubject: step.emailSubject || "", + emailBody: step.reminderBody || "", + template: step.template, + sender: step.senderName, + workflowStepId: step.id, + }); } else if (step.action === WorkflowActions.SMS_NUMBER) { - await scheduleSMSReminder( - bookingInfo, - step.sendTo || "", - trigger, - step.action, - { + await scheduleSMSReminder({ + evt: bookingInfo, + reminderPhone: step.sendTo || "", + triggerEvent: trigger, + action: step.action, + timeSpan: { time, timeUnit, }, - step.reminderBody || "", - step.id, - step.template, - step.sender || SENDER_ID, - user.id, - userWorkflow.teamId - ); + message: step.reminderBody || "", + workflowStepId: step.id, + template: step.template, + sender: step.sender, + userId: user.id, + teamId: userWorkflow.teamId, + }); } else if (step.action === WorkflowActions.WHATSAPP_NUMBER) { - await scheduleWhatsappReminder( - bookingInfo, - step.sendTo || "", - trigger, - step.action, - { + await scheduleWhatsappReminder({ + evt: bookingInfo, + reminderPhone: step.sendTo || "", + triggerEvent: trigger, + action: step.action, + timeSpan: { time, timeUnit, }, - step.reminderBody || "", - step.id || 0, - step.template, - user.id, - userWorkflow.teamId - ); + message: step.reminderBody || "", + workflowStepId: step.id || 0, + template: step.template, + userId: user.id, + teamId: userWorkflow.teamId, + }); } }); await Promise.all(promiseScheduleReminders); @@ -552,54 +552,54 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => { sendTo = newStep.sendTo || "";*/ } - await scheduleEmailReminder( - bookingInfo, - trigger, - newStep.action, - { + await scheduleEmailReminder({ + evt: bookingInfo, + triggerEvent: trigger, + action: newStep.action, + timeSpan: { time, timeUnit, }, sendTo, - newStep.emailSubject || "", - newStep.reminderBody || "", - newStep.id, - newStep.template, - newStep.senderName || SENDER_NAME - ); + emailSubject: newStep.emailSubject || "", + emailBody: newStep.reminderBody || "", + template: newStep.template, + sender: newStep.senderName, + workflowStepId: newStep.id, + }); } else if (newStep.action === WorkflowActions.SMS_NUMBER) { - await scheduleSMSReminder( - bookingInfo, - newStep.sendTo || "", - trigger, - newStep.action, - { + await scheduleSMSReminder({ + evt: bookingInfo, + reminderPhone: newStep.sendTo || "", + triggerEvent: trigger, + action: newStep.action, + timeSpan: { time, timeUnit, }, - newStep.reminderBody || "", - newStep.id || 0, - newStep.template, - newStep.sender || SENDER_ID, - user.id, - userWorkflow.teamId - ); + message: newStep.reminderBody || "", + workflowStepId: newStep.id || 0, + template: newStep.template, + sender: newStep.sender, + userId: user.id, + teamId: userWorkflow.teamId, + }); } else if (newStep.action === WorkflowActions.WHATSAPP_NUMBER) { - await scheduleWhatsappReminder( - bookingInfo, - newStep.sendTo || "", - trigger, - newStep.action, - { + await scheduleWhatsappReminder({ + evt: bookingInfo, + reminderPhone: newStep.sendTo || "", + triggerEvent: trigger, + action: newStep.action, + timeSpan: { time, timeUnit, }, - newStep.reminderBody || "", - newStep.id || 0, - newStep.template, - user.id, - userWorkflow.teamId - ); + message: newStep.reminderBody || "", + workflowStepId: newStep.id || 0, + template: newStep.template, + userId: user.id, + teamId: userWorkflow.teamId, + }); } }); await Promise.all(promiseScheduleReminders); @@ -703,54 +703,54 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => { sendTo = step.sendTo || "";*/ } - await scheduleEmailReminder( - bookingInfo, - trigger, - step.action, - { + await scheduleEmailReminder({ + evt: bookingInfo, + triggerEvent: trigger, + action: step.action, + timeSpan: { time, timeUnit, }, sendTo, - step.emailSubject || "", - step.reminderBody || "", - createdStep.id, - step.template, - step.senderName || SENDER_NAME - ); + emailSubject: step.emailSubject || "", + emailBody: step.reminderBody || "", + template: step.template, + sender: step.senderName, + workflowStepId: createdStep.id, + }); } else if (step.action === WorkflowActions.SMS_NUMBER && step.sendTo) { - await scheduleSMSReminder( - bookingInfo, - step.sendTo, - trigger, - step.action, - { + await scheduleSMSReminder({ + evt: bookingInfo, + reminderPhone: step.sendTo, + triggerEvent: trigger, + action: step.action, + timeSpan: { time, timeUnit, }, - step.reminderBody || "", - createdStep.id, - step.template, - step.sender || SENDER_ID, - user.id, - userWorkflow.teamId - ); + message: step.reminderBody || "", + workflowStepId: createdStep.id, + template: step.template, + sender: step.sender, + userId: user.id, + teamId: userWorkflow.teamId, + }); } else if (step.action === WorkflowActions.WHATSAPP_NUMBER && step.sendTo) { - await scheduleWhatsappReminder( - bookingInfo, - step.sendTo, - trigger, - step.action, - { + await scheduleWhatsappReminder({ + evt: bookingInfo, + reminderPhone: step.sendTo, + triggerEvent: trigger, + action: step.action, + timeSpan: { time, timeUnit, }, - step.reminderBody || "", - createdStep.id, - step.template, - user.id, - userWorkflow.teamId - ); + message: step.reminderBody || "", + workflowStepId: createdStep.id, + template: step.template, + userId: user.id, + teamId: userWorkflow.teamId, + }); } } }