Add alphanumeric sender ID to SMS workflow actions (#5471)
* add sender id * add sender to twilio from * added missing sender * add migration * fix design of add action dialog * add cal as sender when creating new workflow * fix type errors Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: Alex van Andel <me@alexvanandel.com>pr/5217
parent
ef3e7fae20
commit
54f4e665a3
|
@ -1361,6 +1361,8 @@
|
|||
"invalid_credential": "Oh no! Looks like permission expired or was revoked. Please reinstall again.",
|
||||
"choose_common_schedule_team_event": "Choose a common schedule",
|
||||
"choose_common_schedule_team_event_description": "Enable this if you want to use a common schedule between hosts. When disabled, each host will be booked based on their default schedule.",
|
||||
"sender_id": "Sender ID",
|
||||
"sender_id_error_message":"Only letters, numbers and spaces allowed (max. 11 characters)",
|
||||
"test_routing_form": "Test Routing Form",
|
||||
"test_preview": "Test Preview",
|
||||
"route_to": "Route to",
|
||||
|
|
|
@ -105,7 +105,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
break;
|
||||
}
|
||||
if (message?.length && message?.length > 0 && sendTo) {
|
||||
const scheduledSMS = await twilio.scheduleSMS(sendTo, message, reminder.scheduledDate);
|
||||
const scheduledSMS = await twilio.scheduleSMS(
|
||||
sendTo,
|
||||
message,
|
||||
reminder.scheduledDate,
|
||||
reminder.workflowStep.sender || "Cal"
|
||||
);
|
||||
|
||||
await prisma.workflowReminder.update({
|
||||
where: {
|
||||
|
|
|
@ -6,17 +6,18 @@ import { Controller, useForm } from "react-hook-form";
|
|||
import { z } from "zod";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, Checkbox, EmailField, Form, Label } from "@calcom/ui/components";
|
||||
import { Button, Checkbox, EmailField, Form, Label, TextField } from "@calcom/ui/components";
|
||||
import PhoneInput from "@calcom/ui/form/PhoneInputLazy";
|
||||
import { Dialog, DialogClose, DialogContent, DialogFooter, Select } from "@calcom/ui/v2";
|
||||
|
||||
import { WORKFLOW_ACTIONS } from "../../lib/constants";
|
||||
import { getWorkflowActionOptions } from "../../lib/getOptions";
|
||||
import { onlyLettersNumbersSpaces } from "../../pages/v2/workflow";
|
||||
|
||||
interface IAddActionDialog {
|
||||
isOpenDialog: boolean;
|
||||
setIsOpenDialog: Dispatch<SetStateAction<boolean>>;
|
||||
addAction: (action: WorkflowActions, sendTo?: string, numberRequired?: boolean) => void;
|
||||
addAction: (action: WorkflowActions, sendTo?: string, numberRequired?: boolean, sender?: string) => void;
|
||||
isFreeUser: boolean;
|
||||
}
|
||||
|
||||
|
@ -29,6 +30,7 @@ type AddActionFormValues = {
|
|||
action: WorkflowActions;
|
||||
sendTo?: string;
|
||||
numberRequired?: boolean;
|
||||
sender?: string;
|
||||
};
|
||||
|
||||
const cleanUpActionsForFreeUser = (actions: ISelectActionOption[]) => {
|
||||
|
@ -41,6 +43,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
const { t } = useLocale();
|
||||
const { isOpenDialog, setIsOpenDialog, addAction, isFreeUser } = props;
|
||||
const [isPhoneNumberNeeded, setIsPhoneNumberNeeded] = useState(false);
|
||||
const [isSenderIdNeeded, setIsSenderIdNeeded] = useState(false);
|
||||
const [isEmailAddressNeeded, setIsEmailAddressNeeded] = useState(false);
|
||||
const workflowActions = getWorkflowActionOptions(t);
|
||||
const actionOptions = isFreeUser ? cleanUpActionsForFreeUser(workflowActions) : workflowActions;
|
||||
|
@ -52,12 +55,17 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
.refine((val) => isValidPhoneNumber(val) || val.includes("@"))
|
||||
.optional(),
|
||||
numberRequired: z.boolean().optional(),
|
||||
sender: z
|
||||
.string()
|
||||
.refine((val) => onlyLettersNumbersSpaces(val))
|
||||
.nullable(),
|
||||
});
|
||||
|
||||
const form = useForm<AddActionFormValues>({
|
||||
mode: "onSubmit",
|
||||
defaultValues: {
|
||||
action: WorkflowActions.EMAIL_HOST,
|
||||
sender: "Cal",
|
||||
},
|
||||
resolver: zodResolver(formSchema),
|
||||
});
|
||||
|
@ -67,11 +75,18 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
form.setValue("action", newValue.value);
|
||||
if (newValue.value === WorkflowActions.SMS_NUMBER) {
|
||||
setIsPhoneNumberNeeded(true);
|
||||
setIsSenderIdNeeded(true);
|
||||
setIsEmailAddressNeeded(false);
|
||||
} else if (newValue.value === WorkflowActions.EMAIL_ADDRESS) {
|
||||
setIsEmailAddressNeeded(true);
|
||||
setIsSenderIdNeeded(false);
|
||||
setIsPhoneNumberNeeded(false);
|
||||
} else if (newValue.value === WorkflowActions.SMS_ATTENDEE) {
|
||||
setIsSenderIdNeeded(true);
|
||||
setIsEmailAddressNeeded(false);
|
||||
setIsPhoneNumberNeeded(false);
|
||||
} else {
|
||||
setIsSenderIdNeeded(false);
|
||||
setIsEmailAddressNeeded(false);
|
||||
setIsPhoneNumberNeeded(false);
|
||||
}
|
||||
|
@ -90,13 +105,14 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
<Form
|
||||
form={form}
|
||||
handleSubmit={(values) => {
|
||||
addAction(values.action, values.sendTo, values.numberRequired);
|
||||
addAction(values.action, values.sendTo, values.numberRequired, values.sender);
|
||||
form.unregister("sendTo");
|
||||
form.unregister("action");
|
||||
form.unregister("numberRequired");
|
||||
setIsOpenDialog(false);
|
||||
setIsPhoneNumberNeeded(false);
|
||||
setIsEmailAddressNeeded(false);
|
||||
setIsSenderIdNeeded(false);
|
||||
}}>
|
||||
<div className="mt-5 space-y-1">
|
||||
<Label htmlFor="label">{t("action")}:</Label>
|
||||
|
@ -119,25 +135,10 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
<p className="mt-1 text-sm text-red-500">{form.formState.errors.action.message}</p>
|
||||
)}
|
||||
</div>
|
||||
{form.getValues("action") === WorkflowActions.SMS_ATTENDEE && (
|
||||
<div className="mt-5">
|
||||
<Controller
|
||||
name="numberRequired"
|
||||
control={form.control}
|
||||
render={() => (
|
||||
<Checkbox
|
||||
defaultChecked={form.getValues("numberRequired") || false}
|
||||
description={t("make_phone_number_required")}
|
||||
onChange={(e) => form.setValue("numberRequired", e.target.checked)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{isPhoneNumberNeeded && (
|
||||
<div className="mt-5 space-y-1">
|
||||
<Label htmlFor="sendTo">{t("phone_number")}</Label>
|
||||
<div className="mt-1">
|
||||
<div className="mt-1 mb-5">
|
||||
<PhoneInput<AddActionFormValues>
|
||||
control={form.control}
|
||||
name="sendTo"
|
||||
|
@ -157,6 +158,32 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
<EmailField required label={t("email_address")} {...form.register("sendTo")} />
|
||||
</div>
|
||||
)}
|
||||
{isSenderIdNeeded && (
|
||||
<div className="mt-5">
|
||||
<TextField
|
||||
label={t("sender_id")}
|
||||
type="text"
|
||||
placeholder="Cal"
|
||||
maxLength={11}
|
||||
{...form.register(`sender`)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{form.getValues("action") === WorkflowActions.SMS_ATTENDEE && (
|
||||
<div className="mt-5">
|
||||
<Controller
|
||||
name="numberRequired"
|
||||
control={form.control}
|
||||
render={() => (
|
||||
<Checkbox
|
||||
defaultChecked={form.getValues("numberRequired") || false}
|
||||
description={t("make_phone_number_required")}
|
||||
onChange={(e) => form.setValue("numberRequired", e.target.checked)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
|
@ -168,6 +195,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
form.unregister("numberRequired");
|
||||
setIsPhoneNumberNeeded(false);
|
||||
setIsEmailAddressNeeded(false);
|
||||
setIsSenderIdNeeded(false);
|
||||
}}>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
|
|
|
@ -51,7 +51,7 @@ export default function WorkflowDetailsPage(props: Props) {
|
|||
[data]
|
||||
);
|
||||
|
||||
const addAction = (action: WorkflowActions, sendTo?: string, numberRequired?: boolean) => {
|
||||
const addAction = (action: WorkflowActions, sendTo?: string, numberRequired?: boolean, sender?: string) => {
|
||||
const steps = form.getValues("steps");
|
||||
const id =
|
||||
steps?.length > 0
|
||||
|
@ -75,6 +75,7 @@ export default function WorkflowDetailsPage(props: Props) {
|
|||
emailSubject: null,
|
||||
template: WorkflowTemplates.CUSTOM,
|
||||
numberRequired: numberRequired || false,
|
||||
sender: sender || "Cal",
|
||||
};
|
||||
steps?.push(step);
|
||||
form.setValue("steps", steps);
|
||||
|
|
|
@ -17,7 +17,7 @@ import Dropdown, { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger }
|
|||
import { Icon } from "@calcom/ui/Icon";
|
||||
import { Button } from "@calcom/ui/components";
|
||||
import { Checkbox } from "@calcom/ui/components";
|
||||
import { EmailField, Label, TextArea } from "@calcom/ui/components/form";
|
||||
import { EmailField, Label, TextArea, TextField } from "@calcom/ui/components/form";
|
||||
import PhoneInput from "@calcom/ui/form/PhoneInputLazy";
|
||||
import { DialogClose, DialogContent } from "@calcom/ui/v2";
|
||||
import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent";
|
||||
|
@ -52,6 +52,12 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
step?.action === WorkflowActions.SMS_NUMBER ? true : false
|
||||
);
|
||||
|
||||
const [isSenderIdNeeded, setIsSenderIdNeeded] = useState(
|
||||
step?.action === WorkflowActions.SMS_NUMBER || step?.action === WorkflowActions.SMS_ATTENDEE
|
||||
? true
|
||||
: false
|
||||
);
|
||||
|
||||
const [isEmailAddressNeeded, setIsEmailAddressNeeded] = useState(
|
||||
step?.action === WorkflowActions.EMAIL_ADDRESS ? true : false
|
||||
);
|
||||
|
@ -279,13 +285,20 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
if (val) {
|
||||
if (val.value === WorkflowActions.SMS_NUMBER) {
|
||||
setIsPhoneNumberNeeded(true);
|
||||
setIsSenderIdNeeded(true);
|
||||
setIsEmailAddressNeeded(false);
|
||||
} else if (val.value === WorkflowActions.EMAIL_ADDRESS) {
|
||||
setIsEmailAddressNeeded(true);
|
||||
setIsPhoneNumberNeeded(false);
|
||||
setIsSenderIdNeeded(false);
|
||||
} else if (val.value === WorkflowActions.SMS_ATTENDEE) {
|
||||
setIsSenderIdNeeded(true);
|
||||
setIsEmailAddressNeeded(false);
|
||||
setIsPhoneNumberNeeded(false);
|
||||
} else {
|
||||
setIsEmailAddressNeeded(false);
|
||||
setIsPhoneNumberNeeded(false);
|
||||
setIsSenderIdNeeded(false);
|
||||
}
|
||||
form.unregister(`steps.${step.stepNumber - 1}.sendTo`);
|
||||
form.clearErrors(`steps.${step.stepNumber - 1}.sendTo`);
|
||||
|
@ -315,8 +328,49 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{(isPhoneNumberNeeded || isSenderIdNeeded) && (
|
||||
<div className="mt-2 rounded-md bg-gray-50 p-4 pt-0">
|
||||
{isPhoneNumberNeeded && (
|
||||
<>
|
||||
<Label className="pt-4">{t("custom_phone_number")}</Label>
|
||||
<PhoneInput<FormValues>
|
||||
control={form.control}
|
||||
name={`steps.${step.stepNumber - 1}.sendTo`}
|
||||
placeholder={t("phone_number")}
|
||||
id={`steps.${step.stepNumber - 1}.sendTo`}
|
||||
className="w-full rounded-md"
|
||||
required
|
||||
/>
|
||||
{form.formState.errors.steps &&
|
||||
form.formState?.errors?.steps[step.stepNumber - 1]?.sendTo && (
|
||||
<p className="mt-1 text-xs text-red-500">
|
||||
{form.formState?.errors?.steps[step.stepNumber - 1]?.sendTo?.message || ""}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{isSenderIdNeeded && (
|
||||
<>
|
||||
<div className="pt-4">
|
||||
<TextField
|
||||
label={t("sender_id")}
|
||||
type="text"
|
||||
placeholder="Cal"
|
||||
maxLength={11}
|
||||
{...form.register(`steps.${step.stepNumber - 1}.sender`)}
|
||||
/>
|
||||
</div>
|
||||
{form.formState.errors.steps &&
|
||||
form.formState?.errors?.steps[step.stepNumber - 1]?.sender && (
|
||||
<p className="mt-1 text-xs text-red-500">{t("sender_id_error_message")}</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{form.getValues(`steps.${step.stepNumber - 1}.action`) === WorkflowActions.SMS_ATTENDEE && (
|
||||
<div className="mt-5">
|
||||
<div className="mt-2">
|
||||
<Controller
|
||||
name={`steps.${step.stepNumber - 1}.numberRequired`}
|
||||
control={form.control}
|
||||
|
@ -334,26 +388,6 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isPhoneNumberNeeded && (
|
||||
<div className="mt-5 rounded-md bg-gray-50 p-4">
|
||||
<Label>{t("custom_phone_number")}</Label>
|
||||
<PhoneInput<FormValues>
|
||||
control={form.control}
|
||||
name={`steps.${step.stepNumber - 1}.sendTo`}
|
||||
placeholder={t("phone_number")}
|
||||
id={`steps.${step.stepNumber - 1}.sendTo`}
|
||||
className="w-full rounded-md"
|
||||
required
|
||||
/>
|
||||
{form.formState.errors.steps &&
|
||||
form.formState?.errors?.steps[step.stepNumber - 1]?.sendTo && (
|
||||
<p className="mt-1 text-sm text-red-500">
|
||||
{form.formState?.errors?.steps[step.stepNumber - 1]?.sendTo?.message || ""}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isEmailAddressNeeded && (
|
||||
<div className="mt-5 rounded-md bg-gray-50 p-4">
|
||||
<EmailField
|
||||
|
@ -408,7 +442,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
/>
|
||||
{form.formState.errors.steps &&
|
||||
form.formState?.errors?.steps[step.stepNumber - 1]?.emailSubject && (
|
||||
<p className="mt-1 text-sm text-red-500">
|
||||
<p className="mt-1 text-xs text-red-500">
|
||||
{form.formState?.errors?.steps[step.stepNumber - 1]?.emailSubject?.message || ""}
|
||||
</p>
|
||||
)}
|
||||
|
@ -433,7 +467,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
/>
|
||||
{form.formState.errors.steps &&
|
||||
form.formState?.errors?.steps[step.stepNumber - 1]?.reminderBody && (
|
||||
<p className="mt-1 text-sm text-red-500">
|
||||
<p className="mt-1 text-xs text-red-500">
|
||||
{form.formState?.errors?.steps[step.stepNumber - 1]?.reminderBody?.message || ""}
|
||||
</p>
|
||||
)}
|
||||
|
@ -497,6 +531,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
emailSubject,
|
||||
reminderBody,
|
||||
template: step.template,
|
||||
sender: step.sender || "Cal",
|
||||
});
|
||||
} else {
|
||||
const isNumberValid =
|
||||
|
|
|
@ -47,7 +47,8 @@ export const scheduleWorkflowReminders = async (
|
|||
},
|
||||
step.reminderBody || "",
|
||||
step.id,
|
||||
step.template
|
||||
step.template,
|
||||
step.sender || "Cal"
|
||||
);
|
||||
} else if (
|
||||
step.action === WorkflowActions.EMAIL_ATTENDEE ||
|
||||
|
@ -115,7 +116,8 @@ export const sendCancelledReminders = async (
|
|||
},
|
||||
step.reminderBody || "",
|
||||
step.id,
|
||||
step.template
|
||||
step.template,
|
||||
step.sender || "Cal"
|
||||
);
|
||||
} else if (
|
||||
step.action === WorkflowActions.EMAIL_ATTENDEE ||
|
||||
|
|
|
@ -19,18 +19,19 @@ function assertTwilio(twilio: TwilioClient.Twilio | undefined): asserts twilio i
|
|||
if (!twilio) throw new Error("Twilio credentials are missing from the .env file");
|
||||
}
|
||||
|
||||
export const sendSMS = async (phoneNumber: string, body: string) => {
|
||||
export const sendSMS = async (phoneNumber: string, body: string, sender: string) => {
|
||||
assertTwilio(twilio);
|
||||
const response = await twilio.messages.create({
|
||||
body: body,
|
||||
messagingServiceSid: process.env.TWILIO_MESSAGING_SID,
|
||||
to: phoneNumber,
|
||||
from: sender,
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
export const scheduleSMS = async (phoneNumber: string, body: string, scheduledDate: Date) => {
|
||||
export const scheduleSMS = async (phoneNumber: string, body: string, scheduledDate: Date, sender: string) => {
|
||||
assertTwilio(twilio);
|
||||
const response = await twilio.messages.create({
|
||||
body: body,
|
||||
|
@ -38,6 +39,7 @@ export const scheduleSMS = async (phoneNumber: string, body: string, scheduledDa
|
|||
to: phoneNumber,
|
||||
scheduleType: "fixed",
|
||||
sendAt: scheduledDate,
|
||||
from: sender,
|
||||
});
|
||||
|
||||
return response;
|
||||
|
|
|
@ -48,7 +48,8 @@ export const scheduleSMSReminder = async (
|
|||
},
|
||||
message: string,
|
||||
workflowStepId: number,
|
||||
template: WorkflowTemplates
|
||||
template: WorkflowTemplates,
|
||||
sender: string
|
||||
) => {
|
||||
const { startTime, endTime } = evt;
|
||||
const uid = evt.uid as string;
|
||||
|
@ -97,7 +98,7 @@ export const scheduleSMSReminder = async (
|
|||
triggerEvent === WorkflowTriggerEvents.RESCHEDULE_EVENT
|
||||
) {
|
||||
try {
|
||||
await twilio.sendSMS(reminderPhone, message);
|
||||
await twilio.sendSMS(reminderPhone, message, sender);
|
||||
} catch (error) {
|
||||
console.log(`Error sending SMS with error ${error}`);
|
||||
}
|
||||
|
@ -112,7 +113,12 @@ export const scheduleSMSReminder = async (
|
|||
!scheduledDate.isAfter(currentDate.add(7, "day"))
|
||||
) {
|
||||
try {
|
||||
const scheduledSMS = await twilio.scheduleSMS(reminderPhone, message, scheduledDate.toDate());
|
||||
const scheduledSMS = await twilio.scheduleSMS(
|
||||
reminderPhone,
|
||||
message,
|
||||
scheduledDate.toDate(),
|
||||
sender
|
||||
);
|
||||
|
||||
await prisma.workflowReminder.create({
|
||||
data: {
|
||||
|
|
|
@ -38,6 +38,13 @@ export type FormValues = {
|
|||
timeUnit?: TimeUnit;
|
||||
};
|
||||
|
||||
export function onlyLettersNumbersSpaces(str: string) {
|
||||
if (str.length <= 11 && /^[A-Za-z0-9\s]*$/.test(str)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z.string(),
|
||||
activeOn: z.object({ value: z.string(), label: z.string() }).array(),
|
||||
|
@ -58,6 +65,11 @@ const formSchema = z.object({
|
|||
.string()
|
||||
.refine((val) => isValidPhoneNumber(val) || val.includes("@"))
|
||||
.nullable(),
|
||||
sender: z
|
||||
.string()
|
||||
.refine((val) => onlyLettersNumbersSpaces(val))
|
||||
.optional()
|
||||
.nullable(),
|
||||
})
|
||||
.array(),
|
||||
});
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "WorkflowStep" ADD COLUMN "sender" TEXT;
|
|
@ -573,6 +573,7 @@ model WorkflowStep {
|
|||
template WorkflowTemplates @default(REMINDER)
|
||||
workflowReminders WorkflowReminder[]
|
||||
numberRequired Boolean?
|
||||
sender String?
|
||||
}
|
||||
|
||||
model Workflow {
|
||||
|
|
|
@ -160,6 +160,7 @@ export const workflowsRouter = router({
|
|||
action: WorkflowActions.EMAIL_HOST,
|
||||
template: WorkflowTemplates.REMINDER,
|
||||
workflowId: workflow.id,
|
||||
sender: "Cal",
|
||||
},
|
||||
});
|
||||
return { workflow };
|
||||
|
@ -235,6 +236,7 @@ export const workflowsRouter = router({
|
|||
emailSubject: z.string().optional().nullable(),
|
||||
template: z.enum(WORKFLOW_TEMPLATES),
|
||||
numberRequired: z.boolean().nullable(),
|
||||
sender: z.string().optional().nullable(),
|
||||
})
|
||||
.array(),
|
||||
trigger: z.enum(WORKFLOW_TRIGGER_EVENTS),
|
||||
|
@ -472,7 +474,8 @@ export const workflowsRouter = router({
|
|||
},
|
||||
step.reminderBody || "",
|
||||
step.id,
|
||||
step.template
|
||||
step.template,
|
||||
step.sender || "Cal"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -541,6 +544,7 @@ export const workflowsRouter = router({
|
|||
emailSubject: newStep.template === WorkflowTemplates.CUSTOM ? newStep.emailSubject : null,
|
||||
template: newStep.template,
|
||||
numberRequired: newStep.numberRequired,
|
||||
sender: newStep.sender || "Cal",
|
||||
},
|
||||
});
|
||||
//cancel all reminders of step and create new ones (not for newEventTypes)
|
||||
|
@ -651,7 +655,8 @@ export const workflowsRouter = router({
|
|||
},
|
||||
newStep.reminderBody || "",
|
||||
newStep.id || 0,
|
||||
newStep.template
|
||||
newStep.template,
|
||||
newStep.sender || "Cal"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -677,6 +682,8 @@ export const workflowsRouter = router({
|
|||
});
|
||||
addedSteps.forEach(async (step) => {
|
||||
if (step) {
|
||||
const newStep = step;
|
||||
newStep.sender = step.sender || "Cal";
|
||||
const createdStep = await ctx.prisma.workflowStep.create({
|
||||
data: step,
|
||||
});
|
||||
|
@ -764,7 +771,8 @@ export const workflowsRouter = router({
|
|||
},
|
||||
step.reminderBody || "",
|
||||
createdStep.id,
|
||||
step.template
|
||||
step.template,
|
||||
step.sender || "Cal"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -812,10 +820,11 @@ export const workflowsRouter = router({
|
|||
reminderBody: z.string(),
|
||||
template: z.enum(WORKFLOW_TEMPLATES),
|
||||
sendTo: z.string().optional(),
|
||||
sender: z.string().optional(),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const { action, emailSubject, reminderBody, template, sendTo } = input;
|
||||
const { action, emailSubject, reminderBody, template, sendTo, sender } = input;
|
||||
try {
|
||||
const booking = await ctx.prisma.booking.findFirst({
|
||||
orderBy: {
|
||||
|
@ -899,7 +908,8 @@ export const workflowsRouter = router({
|
|||
{ time: null, timeUnit: null },
|
||||
reminderBody,
|
||||
0,
|
||||
template
|
||||
template,
|
||||
sender || "Cal"
|
||||
);
|
||||
return { message: "Notification sent" };
|
||||
}
|
||||
|
|
|
@ -183,6 +183,9 @@
|
|||
"$CLOSECOM_API_KEY",
|
||||
"$SENDGRID_API_KEY",
|
||||
"$SENDGRID_EMAIL",
|
||||
"$TWILIO_TOKEN",
|
||||
"$TWILIO_SID",
|
||||
"$TWILIO_MESSAGING_SID",
|
||||
"$CRON_API_KEY",
|
||||
"$DAILY_API_KEY",
|
||||
"$DAILY_SCALE_PLAN",
|
||||
|
|
Loading…
Reference in New Issue