fix: formatting
parent
d27ff41682
commit
6b5c8935c5
|
@ -22,18 +22,18 @@ Any other relevant information. For example, why do you consider this a bug and
|
|||
|
||||
### Actual Results
|
||||
|
||||
- What's happening right now that is different from what is expected
|
||||
- What's happening right now that is different from what is expected
|
||||
|
||||
### Expected Results
|
||||
|
||||
- This is an ideal result that the system should get after the tests are performed
|
||||
- This is an ideal result that the system should get after the tests are performed
|
||||
|
||||
### Technical details
|
||||
|
||||
- Browser version, screen recording, console logs, network requests: You can make a recording with [Bird Eats Bug](https://birdeatsbug.com/).
|
||||
- Node.js version
|
||||
- Anything else that you think could be an issue.
|
||||
- Browser version, screen recording, console logs, network requests: You can make a recording with [Bird Eats Bug](https://birdeatsbug.com/).
|
||||
- Node.js version
|
||||
- Anything else that you think could be an issue.
|
||||
|
||||
### Evidence
|
||||
|
||||
- How was this tested? This is quite mandatory in terms of bugs. Providing evidence of your testing with screenshots or/and videos is an amazing way to prove the bug and a troubleshooting chance to find the solution.
|
||||
- How was this tested? This is quite mandatory in terms of bugs. Providing evidence of your testing with screenshots or/and videos is an amazing way to prove the bug and a troubleshooting chance to find the solution.
|
||||
|
|
|
@ -11,31 +11,32 @@ Fixes # (issue)
|
|||
## Requirement/Documentation
|
||||
|
||||
<!-- Please provide all documents that are important to understand the reason of that PR. -->
|
||||
- If there is a requirement document, please, share it here.
|
||||
- If there is ab UI/UX design document, please, share it here.
|
||||
|
||||
- If there is a requirement document, please, share it here.
|
||||
- If there is ab UI/UX design document, please, share it here.
|
||||
|
||||
## Type of change
|
||||
|
||||
<!-- Please delete bullets that are not relevant. -->
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] Chore (refactoring code, technical debt, workflow improvements)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] This change requires a documentation update
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] Chore (refactoring code, technical debt, workflow improvements)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] This change requires a documentation update
|
||||
|
||||
## How should this be tested?
|
||||
|
||||
<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. Write details that help to start the tests -->
|
||||
|
||||
- Are there environment variables that should be set?
|
||||
- What are the minimal test data to have?
|
||||
- What is expected (happy path) to have (input and output)?
|
||||
- Any other important info that could help to test that PR
|
||||
- Are there environment variables that should be set?
|
||||
- What are the minimal test data to have?
|
||||
- What is expected (happy path) to have (input and output)?
|
||||
- Any other important info that could help to test that PR
|
||||
|
||||
## Mandatory Tasks
|
||||
|
||||
- [ ] Make sure you have self-reviewed the code. A decent size PR without self-review might be rejected.
|
||||
- [ ] Make sure you have self-reviewed the code. A decent size PR without self-review might be rejected.
|
||||
|
||||
## Checklist
|
||||
|
||||
|
|
|
@ -90,7 +90,6 @@ That's where Cal.com comes in. Self-hosted or hosted by us. White-label by desig
|
|||
- [Prisma.io](https://prisma.io/?ref=cal.com)
|
||||
- [Daily.co](https://go.cal.com/daily)
|
||||
|
||||
|
||||
## Contact us
|
||||
|
||||
Meet our sales team for any commercial inquiries.
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
allowDisablingHostConfirmationEmails,
|
||||
} from "@calcom/features/ee/workflows/lib/allowDisablingStandardEmails";
|
||||
import { FormBuilder } from "@calcom/features/form-builder/FormBuilder";
|
||||
import { EditableSchema } from "@calcom/features/form-builder/FormBuilderFieldsSchema"
|
||||
import { EditableSchema } from "@calcom/features/form-builder/FormBuilderFieldsSchema";
|
||||
import { BookerLayoutSelector } from "@calcom/features/settings/BookerLayoutSelector";
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { APP_NAME, CAL_URL } from "@calcom/lib/constants";
|
||||
|
@ -87,7 +87,9 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||
return {
|
||||
...field,
|
||||
hidden: !enabled,
|
||||
editable: (!enabled ? "system-but-hidden" : "system-but-optional") as z.infer<typeof EditableSchema>
|
||||
editable: (!enabled ? "system-but-hidden" : "system-but-optional") as z.infer<
|
||||
typeof EditableSchema
|
||||
>,
|
||||
};
|
||||
}
|
||||
return field;
|
||||
|
|
|
@ -12,6 +12,7 @@ items:
|
|||
Skiff is a privacy-first, end-to-end encrypted workspace with Mail, Pages, Drive, and Calendar applications. Skiff Calendar integrates with Cal.com, enabling you to schedule appointments, organize events, and use your preferred video conferencing product.
|
||||
|
||||
## Features
|
||||
|
||||
- **Full workspace** — beyond email and calendar, Skiff enables writing and collaborating on end-to-end encrypted notes or wikis. You can also upload, preview, and share files.
|
||||
- **Native applications** — Skiff has native macOS, Windows, iOS, and Android applications, ensuring you can stay on top of your schedule from any device.
|
||||
- **Multiple accounts** — all Skiff products support multiple accounts, or sharing your entire team to collaborate inside one workspace.
|
||||
|
|
|
@ -23,7 +23,7 @@ import { useBookerStore, useInitializeBookerStore } from "./store";
|
|||
import type { BookerLayout, BookerProps } from "./types";
|
||||
import { useEvent } from "./utils/event";
|
||||
import { validateLayout } from "./utils/layout";
|
||||
import { getQueryParam } from './utils/query-param';
|
||||
import { getQueryParam } from "./utils/query-param";
|
||||
import { useBrandColors } from "./utils/use-brand-colors";
|
||||
|
||||
const PoweredBy = dynamic(() => import("@calcom/ee/components/PoweredBy"));
|
||||
|
@ -120,9 +120,9 @@ const BookerComponent = ({
|
|||
layout !== _layout
|
||||
) {
|
||||
const validLayout = bookerLayouts.enabledLayouts.find((userLayout) => userLayout === layout);
|
||||
validLayout && setLayout(validLayout)
|
||||
validLayout && setLayout(validLayout);
|
||||
}
|
||||
}, [bookerLayouts, validateLayout, setLayout,_layout]);
|
||||
}, [bookerLayouts, validateLayout, setLayout, _layout]);
|
||||
|
||||
useEffect(() => {
|
||||
if (event.isLoading) return setBookerState("loading");
|
||||
|
|
|
@ -128,7 +128,7 @@ export const useBookerStore = create<BookerStore>((set, get) => ({
|
|||
if (["week_view", "column_view"].includes(layout) && !get().selectedDate) {
|
||||
set({ selectedDate: dayjs().format("YYYY-MM-DD") });
|
||||
}
|
||||
updateQueryParam("layout", layout)
|
||||
updateQueryParam("layout", layout);
|
||||
return set({ layout });
|
||||
},
|
||||
selectedDate: getQueryParam("date") || null,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { getEventLocationType, getTranslatedLocation } from "@calcom/app-store/locations";
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Tooltip } from "@calcom/ui";
|
||||
import { MapPin } from "@calcom/ui/components/icon";
|
||||
import { classNames } from "@calcom/lib";
|
||||
|
||||
import type { PublicEvent } from "../../types";
|
||||
import { EventMetaBlock } from "./Details";
|
||||
|
@ -20,7 +20,7 @@ export const EventLocations = ({ event }: { event: PublicEvent }) => {
|
|||
return translatedLocation;
|
||||
};
|
||||
const eventLocationType = getEventLocationType(locations[0].type);
|
||||
const icon = (locations.length > 1 || !eventLocationType?.iconUrl) ? MapPin : eventLocationType.iconUrl;
|
||||
const icon = locations.length > 1 || !eventLocationType?.iconUrl ? MapPin : eventLocationType.iconUrl;
|
||||
|
||||
return (
|
||||
<EventMetaBlock icon={icon} isDark={eventLocationType?.iconUrl?.includes("-dark")}>
|
||||
|
@ -44,13 +44,15 @@ export const EventLocations = ({ event }: { event: PublicEvent }) => {
|
|||
<li key={`${location.type}-${index}`} className="mt-1">
|
||||
<div className="flex flex-row items-center">
|
||||
<img
|
||||
src={getEventLocationType(location.type)?.iconUrl}
|
||||
className={classNames(
|
||||
"h-3 w-3 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 ",
|
||||
!getEventLocationType(location.type)?.iconUrl?.startsWith("/app-store") ? "dark:invert-[.65]" : ""
|
||||
)}
|
||||
alt={`${getEventLocationType(location.type)?.label} icon`}
|
||||
/>
|
||||
src={getEventLocationType(location.type)?.iconUrl}
|
||||
className={classNames(
|
||||
"h-3 w-3 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 ",
|
||||
!getEventLocationType(location.type)?.iconUrl?.startsWith("/app-store")
|
||||
? "dark:invert-[.65]"
|
||||
: ""
|
||||
)}
|
||||
alt={`${getEventLocationType(location.type)?.label} icon`}
|
||||
/>
|
||||
<span>{getLocationToDisplay(location)}</span>
|
||||
</div>
|
||||
</li>
|
||||
|
|
|
@ -116,8 +116,7 @@ const PaymentForm = (props: Props) => {
|
|||
color="minimal"
|
||||
disabled={!holdAcknowledged || ["processing", "error"].includes(state.status)}
|
||||
id="cancel"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
onClick={() => router.back()}>
|
||||
<span id="button-text">{t("cancel")}</span>
|
||||
</Button>
|
||||
<Button
|
||||
|
|
|
@ -207,8 +207,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||
).html;
|
||||
|
||||
emailBodyEmpty =
|
||||
customTemplate(reminder.workflowStep.reminderBody || "", variables, emailLocale).text.length ===
|
||||
0;
|
||||
customTemplate(reminder.workflowStep.reminderBody || "", variables, emailLocale).text.length === 0;
|
||||
} else if (reminder.workflowStep.template === WorkflowTemplates.REMINDER) {
|
||||
emailContent = emailReminderTemplate(
|
||||
false,
|
||||
|
|
|
@ -93,7 +93,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
setIsPhoneNumberNeeded(true);
|
||||
setIsSenderIdNeeded(true);
|
||||
setIsEmailAddressNeeded(false);
|
||||
form.resetField("senderId", { defaultValue: SENDER_ID })
|
||||
form.resetField("senderId", { defaultValue: SENDER_ID });
|
||||
} else if (newValue.value === WorkflowActions.EMAIL_ADDRESS) {
|
||||
setIsEmailAddressNeeded(true);
|
||||
setIsSenderIdNeeded(false);
|
||||
|
@ -102,7 +102,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
setIsSenderIdNeeded(true);
|
||||
setIsEmailAddressNeeded(false);
|
||||
setIsPhoneNumberNeeded(false);
|
||||
form.resetField("senderId", { defaultValue: SENDER_ID })
|
||||
form.resetField("senderId", { defaultValue: SENDER_ID });
|
||||
} else if (newValue.value === WorkflowActions.WHATSAPP_NUMBER) {
|
||||
setIsSenderIdNeeded(false);
|
||||
setIsPhoneNumberNeeded(true);
|
||||
|
@ -123,17 +123,16 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
|
||||
const canRequirePhoneNumber = (workflowStep: string) => {
|
||||
return (
|
||||
WorkflowActions.SMS_ATTENDEE === workflowStep ||
|
||||
WorkflowActions.WHATSAPP_ATTENDEE === workflowStep
|
||||
)
|
||||
}
|
||||
WorkflowActions.SMS_ATTENDEE === workflowStep || WorkflowActions.WHATSAPP_ATTENDEE === workflowStep
|
||||
);
|
||||
};
|
||||
|
||||
const showSender = (action: string) => {
|
||||
return !isSenderIdNeeded && !(
|
||||
WorkflowActions.WHATSAPP_NUMBER === action ||
|
||||
WorkflowActions.WHATSAPP_ATTENDEE === action
|
||||
)
|
||||
}
|
||||
return (
|
||||
!isSenderIdNeeded &&
|
||||
!(WorkflowActions.WHATSAPP_NUMBER === action || WorkflowActions.WHATSAPP_ATTENDEE === action)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={isOpenDialog} onOpenChange={setIsOpenDialog}>
|
||||
|
@ -186,7 +185,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
{isPhoneNumberNeeded && (
|
||||
<div className="mt-5 space-y-1">
|
||||
<Label htmlFor="sendTo">{t("phone_number")}</Label>
|
||||
<div className="mt-1 mb-5">
|
||||
<div className="mb-5 mt-1">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="sendTo"
|
||||
|
@ -228,7 +227,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
)}
|
||||
</>
|
||||
)}
|
||||
{showSender(form.getValues('action')) && (
|
||||
{showSender(form.getValues("action")) && (
|
||||
<div className="mt-5">
|
||||
<Label>{t("sender_name")}</Label>
|
||||
<Input type="text" placeholder={SENDER_NAME} {...form.register(`senderName`)} />
|
||||
|
|
|
@ -39,8 +39,14 @@ import {
|
|||
} from "@calcom/ui";
|
||||
import { ArrowDown, MoreHorizontal, Trash2, HelpCircle, Info } from "@calcom/ui/components/icon";
|
||||
|
||||
import {
|
||||
isAttendeeAction,
|
||||
isSMSAction,
|
||||
isSMSOrWhatsappAction,
|
||||
isWhatsappAction,
|
||||
getWhatsappTemplateForAction,
|
||||
} from "../lib/actionHelperFunctions";
|
||||
import { DYNAMIC_TEXT_VARIABLES } from "../lib/constants";
|
||||
import { isAttendeeAction, isSMSAction, isSMSOrWhatsappAction, isWhatsappAction, getWhatsappTemplateForAction } from "../lib/actionHelperFunctions";
|
||||
import { getWorkflowTemplateOptions, getWorkflowTriggerOptions } from "../lib/getOptions";
|
||||
import emailReminderTemplate from "../lib/reminders/templates/emailReminderTemplate";
|
||||
import smsReminderTemplate from "../lib/reminders/templates/smsReminderTemplate";
|
||||
|
@ -71,14 +77,16 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
|
||||
const [verificationCode, setVerificationCode] = useState("");
|
||||
|
||||
const action = step?.action
|
||||
const requirePhoneNumber = WorkflowActions.SMS_NUMBER === action || WorkflowActions.WHATSAPP_NUMBER === action;
|
||||
const action = step?.action;
|
||||
const requirePhoneNumber =
|
||||
WorkflowActions.SMS_NUMBER === action || WorkflowActions.WHATSAPP_NUMBER === action;
|
||||
const [isPhoneNumberNeeded, setIsPhoneNumberNeeded] = useState(requirePhoneNumber);
|
||||
|
||||
const [updateTemplate, setUpdateTemplate] = useState(false);
|
||||
const [firstRender, setFirstRender] = useState(true);
|
||||
|
||||
const senderNeeded = step?.action === WorkflowActions.SMS_NUMBER || step?.action === WorkflowActions.SMS_ATTENDEE;
|
||||
const senderNeeded =
|
||||
step?.action === WorkflowActions.SMS_NUMBER || step?.action === WorkflowActions.SMS_ATTENDEE;
|
||||
|
||||
const [isSenderIsNeeded, setIsSenderIsNeeded] = useState(senderNeeded);
|
||||
|
||||
|
@ -110,20 +118,11 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
if (!form.getValues(`steps.${step.stepNumber - 1}.reminderBody`)) {
|
||||
const action = form.getValues(`steps.${step.stepNumber - 1}.action`);
|
||||
if (isSMSAction(action)) {
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, smsReminderTemplate(
|
||||
true,
|
||||
action
|
||||
));
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, smsReminderTemplate(true, action));
|
||||
} else if (isWhatsappAction(action)) {
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, whatsappReminderTemplate(
|
||||
true,
|
||||
action
|
||||
))
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, whatsappReminderTemplate(true, action));
|
||||
} else {
|
||||
const reminderBodyTemplate = emailReminderTemplate(
|
||||
true,
|
||||
action
|
||||
).emailBody;
|
||||
const reminderBodyTemplate = emailReminderTemplate(true, action).emailBody;
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, reminderBodyTemplate);
|
||||
}
|
||||
}
|
||||
|
@ -135,8 +134,8 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
form.setValue(`steps.${step.stepNumber - 1}.emailSubject`, subjectTemplate);
|
||||
}
|
||||
} else if (step && isWhatsappAction(step.action)) {
|
||||
const templateBody = getWhatsappTemplateForAction(step.action, step.template)
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, templateBody)
|
||||
const templateBody = getWhatsappTemplateForAction(step.action, step.template);
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, templateBody);
|
||||
}
|
||||
|
||||
const { ref: emailSubjectFormRef, ...restEmailSubjectForm } = step
|
||||
|
@ -151,7 +150,11 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
|
||||
const refReminderBody = useRef<HTMLTextAreaElement | null>(null);
|
||||
|
||||
const getNumberVerificationStatus = () => !!step && !!verifiedNumbers.find((number: string) => number === form.getValues(`steps.${step.stepNumber - 1}.sendTo`))
|
||||
const getNumberVerificationStatus = () =>
|
||||
!!step &&
|
||||
!!verifiedNumbers.find(
|
||||
(number: string) => number === form.getValues(`steps.${step.stepNumber - 1}.sendTo`)
|
||||
);
|
||||
|
||||
const [numberVerified, setNumberVerified] = useState(getNumberVerificationStatus());
|
||||
|
||||
|
@ -236,17 +239,17 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
return (
|
||||
<>
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full border rounded-md min-w-80 bg-default border-subtle p-7">
|
||||
<div className="min-w-80 bg-default border-subtle w-full rounded-md border p-7">
|
||||
<div className="flex">
|
||||
<div className="bg-subtle text-default mt-[3px] flex h-5 w-5 items-center justify-center rounded-full p-1 text-xs font-medium ltr:mr-5 rtl:ml-5">
|
||||
1
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-base font-bold text-emphasis">{t("trigger")}</div>
|
||||
<div className="text-sm text-default">{t("when_something_happens")}</div>
|
||||
<div className="text-emphasis text-base font-bold">{t("trigger")}</div>
|
||||
<div className="text-default text-sm">{t("when_something_happens")}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-t border-subtle my-7" />
|
||||
<div className="border-subtle my-7 border-t" />
|
||||
<Label>{t("when")}</Label>
|
||||
<Controller
|
||||
name="trigger"
|
||||
|
@ -291,7 +294,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
<Label>{showTimeSectionAfter ? t("how_long_after") : t("how_long_before")}</Label>
|
||||
<TimeTimeUnitInput form={form} disabled={props.readOnly} />
|
||||
{!props.readOnly && (
|
||||
<div className="flex mt-1 text-gray-500">
|
||||
<div className="mt-1 flex text-gray-500">
|
||||
<Info className="mr-1 mt-0.5 h-4 w-4" />
|
||||
<p className="text-sm">{t("testing_workflow_info_message")}</p>
|
||||
</div>
|
||||
|
@ -318,18 +321,17 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
|
||||
const canRequirePhoneNumber = (workflowStep: string) => {
|
||||
return (
|
||||
WorkflowActions.SMS_ATTENDEE === workflowStep ||
|
||||
WorkflowActions.WHATSAPP_ATTENDEE === workflowStep
|
||||
)
|
||||
}
|
||||
WorkflowActions.SMS_ATTENDEE === workflowStep || WorkflowActions.WHATSAPP_ATTENDEE === workflowStep
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex justify-center my-3">
|
||||
<div className="my-3 flex justify-center">
|
||||
<ArrowDown className="text-subtle stroke-[1.5px] text-3xl" />
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<div className="flex w-full border rounded-md min-w-80 bg-default border-subtle p-7">
|
||||
<div className="min-w-80 bg-default border-subtle flex w-full rounded-md border p-7">
|
||||
<div className="w-full">
|
||||
<div className="flex">
|
||||
<div className="w-full">
|
||||
|
@ -338,8 +340,8 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
{step.stepNumber + 1}
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-base font-bold text-emphasis">{t("action")}</div>
|
||||
<div className="text-sm text-default">{t("action_is_performed")}</div>
|
||||
<div className="text-emphasis text-base font-bold">{t("action")}</div>
|
||||
<div className="text-default text-sm">{t("action_is_performed")}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -379,7 +381,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="border-t border-subtle my-7" />
|
||||
<div className="border-subtle my-7 border-t" />
|
||||
<div>
|
||||
<Label>{t("do_this")}</Label>
|
||||
<Controller
|
||||
|
@ -395,16 +397,18 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
if (val) {
|
||||
const oldValue = form.getValues(`steps.${step.stepNumber - 1}.action`);
|
||||
|
||||
const setNumberRequiredConfigs = (phoneNumberIsNeeded: boolean, senderNeeded = true) => {
|
||||
const setNumberRequiredConfigs = (
|
||||
phoneNumberIsNeeded: boolean,
|
||||
senderNeeded = true
|
||||
) => {
|
||||
setIsSenderIsNeeded(senderNeeded);
|
||||
setIsEmailAddressNeeded(false);
|
||||
setIsPhoneNumberNeeded(phoneNumberIsNeeded);
|
||||
setNumberVerified(getNumberVerificationStatus());
|
||||
}
|
||||
};
|
||||
|
||||
if (isSMSAction(val.value)) {
|
||||
|
||||
setNumberRequiredConfigs(val.value === WorkflowActions.SMS_NUMBER)
|
||||
setNumberRequiredConfigs(val.value === WorkflowActions.SMS_NUMBER);
|
||||
// email action changes to sms action
|
||||
if (!isSMSAction(oldValue)) {
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, "");
|
||||
|
@ -501,7 +505,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
/>
|
||||
</div>
|
||||
{isPhoneNumberNeeded && (
|
||||
<div className="p-4 pt-0 mt-2 rounded-md bg-muted">
|
||||
<div className="bg-muted mt-2 rounded-md p-4 pt-0">
|
||||
<Label className="pt-4">{t("custom_phone_number")}</Label>
|
||||
<div className="block sm:flex">
|
||||
<Controller
|
||||
|
@ -553,7 +557,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
) : (
|
||||
!props.readOnly && (
|
||||
<>
|
||||
<div className="flex mt-3">
|
||||
<div className="mt-3 flex">
|
||||
<TextField
|
||||
className="rounded-r-none border-r-transparent"
|
||||
placeholder="Verification code"
|
||||
|
@ -589,43 +593,45 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
)}
|
||||
</div>
|
||||
)}
|
||||
{!isWhatsappAction(form.getValues(`steps.${step.stepNumber - 1}.action`)) && (<div className="p-4 pt-0 mt-2 rounded-md bg-muted">
|
||||
{isSenderIsNeeded ? (
|
||||
<>
|
||||
<div className="pt-4">
|
||||
<div className="flex">
|
||||
<Label>{t("sender_id")}</Label>
|
||||
<Tooltip content={t("sender_id_info")}>
|
||||
<Info className="ml-2 mr-1 mt-0.5 h-4 w-4 text-gray-500" />
|
||||
</Tooltip>
|
||||
{!isWhatsappAction(form.getValues(`steps.${step.stepNumber - 1}.action`)) && (
|
||||
<div className="bg-muted mt-2 rounded-md p-4 pt-0">
|
||||
{isSenderIsNeeded ? (
|
||||
<>
|
||||
<div className="pt-4">
|
||||
<div className="flex">
|
||||
<Label>{t("sender_id")}</Label>
|
||||
<Tooltip content={t("sender_id_info")}>
|
||||
<Info className="ml-2 mr-1 mt-0.5 h-4 w-4 text-gray-500" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={SENDER_ID}
|
||||
disabled={props.readOnly}
|
||||
maxLength={11}
|
||||
{...form.register(`steps.${step.stepNumber - 1}.sender`)}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={SENDER_ID}
|
||||
disabled={props.readOnly}
|
||||
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 className="pt-4">
|
||||
<Label>{t("sender_name")}</Label>
|
||||
<Input
|
||||
type="text"
|
||||
disabled={props.readOnly}
|
||||
placeholder={SENDER_NAME}
|
||||
{...form.register(`steps.${step.stepNumber - 1}.senderName`)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</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 className="pt-4">
|
||||
<Label>{t("sender_name")}</Label>
|
||||
<Input
|
||||
type="text"
|
||||
disabled={props.readOnly}
|
||||
placeholder={SENDER_NAME}
|
||||
{...form.register(`steps.${step.stepNumber - 1}.senderName`)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{canRequirePhoneNumber(form.getValues(`steps.${step.stepNumber - 1}.action`)) && (
|
||||
<div className="mt-2">
|
||||
<Controller
|
||||
|
@ -647,7 +653,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
</div>
|
||||
)}
|
||||
{isEmailAddressNeeded && (
|
||||
<div className="p-4 mt-5 rounded-md bg-muted">
|
||||
<div className="bg-muted mt-5 rounded-md p-4">
|
||||
<EmailField
|
||||
required
|
||||
disabled={props.readOnly}
|
||||
|
@ -669,20 +675,17 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
isDisabled={props.readOnly}
|
||||
onChange={(val) => {
|
||||
if (val) {
|
||||
const action = form.getValues(`steps.${step.stepNumber - 1}.action`)
|
||||
const action = form.getValues(`steps.${step.stepNumber - 1}.action`);
|
||||
if (val.value === WorkflowTemplates.REMINDER) {
|
||||
if (isWhatsappAction(action)) {
|
||||
form.setValue(
|
||||
`steps.${step.stepNumber - 1}.reminderBody`,
|
||||
whatsappReminderTemplate(
|
||||
true,
|
||||
action
|
||||
)
|
||||
whatsappReminderTemplate(true, action)
|
||||
);
|
||||
} else if (isSMSAction(action)) {
|
||||
form.setValue(
|
||||
`steps.${step.stepNumber - 1}.reminderBody`,
|
||||
smsReminderTemplate(true,action)
|
||||
smsReminderTemplate(true, action)
|
||||
);
|
||||
} else {
|
||||
form.setValue(
|
||||
|
@ -696,13 +699,16 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
}
|
||||
} else {
|
||||
if (isWhatsappAction(action)) {
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, getWhatsappTemplateForAction(action, val.value))
|
||||
form.setValue(
|
||||
`steps.${step.stepNumber - 1}.reminderBody`,
|
||||
getWhatsappTemplateForAction(action, val.value)
|
||||
);
|
||||
} else {
|
||||
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, "");
|
||||
form.setValue(`steps.${step.stepNumber - 1}.emailSubject`, "");
|
||||
}
|
||||
}
|
||||
field.onChange(val.value)
|
||||
field.onChange(val.value);
|
||||
form.setValue(`steps.${step.stepNumber - 1}.template`, val.value);
|
||||
setUpdateTemplate(!updateTemplate);
|
||||
}
|
||||
|
@ -715,7 +721,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="pt-2 mt-2 rounded-md bg-muted md:p-6 md:pt-4">
|
||||
<div className="bg-muted mt-2 rounded-md pt-2 md:p-6 md:pt-4">
|
||||
{isEmailSubjectNeeded && (
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center">
|
||||
|
@ -755,7 +761,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
step.action !== WorkflowActions.SMS_NUMBER ? (
|
||||
<>
|
||||
<div className="mb-2 flex items-center pb-[1.5px]">
|
||||
<Label className="flex-none mb-0 ">
|
||||
<Label className="mb-0 flex-none ">
|
||||
{isEmailSubjectNeeded ? t("email_body") : t("text_message")}
|
||||
</Label>
|
||||
</div>
|
||||
|
@ -795,7 +801,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
reminderBodyFormRef?.(e);
|
||||
refReminderBody.current = e;
|
||||
}}
|
||||
className="h-24 my-0"
|
||||
className="my-0 h-24"
|
||||
disabled={props.readOnly}
|
||||
required
|
||||
{...restReminderBodyForm}
|
||||
|
@ -811,7 +817,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
{!props.readOnly && (
|
||||
<div className="mt-3 ">
|
||||
<button type="button" onClick={() => setIsAdditionalInputsDialogOpen(true)}>
|
||||
<div className="flex mt-2 text-sm text-default">
|
||||
<div className="text-default mt-2 flex text-sm">
|
||||
<HelpCircle className="mt-[3px] h-3 w-3 ltr:mr-2 rtl:ml-2" />
|
||||
<p className="text-left">{t("using_booking_questions_as_variables")}</p>
|
||||
</div>
|
||||
|
@ -923,23 +929,23 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
<DialogContent type="creation" className="sm:max-w-[610px]">
|
||||
<div className="-m-3 h-[430px] overflow-x-hidden overflow-y-scroll sm:m-0">
|
||||
<h1 className="w-full text-xl font-semibold ">{t("how_booking_questions_as_variables")}</h1>
|
||||
<div className="mb-6 rounded-md bg-muted-3 sm:p-4">
|
||||
<p className="font-medium test-sm">{t("format")}</p>
|
||||
<ul className="mt-2 ml-5 list-disc text-emphasis">
|
||||
<div className="bg-muted-3 mb-6 rounded-md sm:p-4">
|
||||
<p className="test-sm font-medium">{t("format")}</p>
|
||||
<ul className="text-emphasis ml-5 mt-2 list-disc">
|
||||
<li>{t("uppercase_for_letters")}</li>
|
||||
<li>{t("replace_whitespaces_underscores")}</li>
|
||||
<li>{t("ignore_special_characters_booking_questions")}</li>
|
||||
</ul>
|
||||
<div className="mt-4">
|
||||
<p className="w-full font-medium test-sm">{t("example_1")}</p>
|
||||
<div className="grid grid-cols-12 mt-2">
|
||||
<div className="col-span-5 test-sm text-default ltr:mr-2 rtl:ml-2">
|
||||
<p className="test-sm w-full font-medium">{t("example_1")}</p>
|
||||
<div className="mt-2 grid grid-cols-12">
|
||||
<div className="test-sm text-default col-span-5 ltr:mr-2 rtl:ml-2">
|
||||
{t("booking_question_identifier")}
|
||||
</div>
|
||||
<div className="col-span-7 test-sm text-emphasis">{t("company_size")}</div>
|
||||
<div className="w-full col-span-5 test-sm text-default">{t("variable")}</div>
|
||||
<div className="test-sm text-emphasis col-span-7">{t("company_size")}</div>
|
||||
<div className="test-sm text-default col-span-5 w-full">{t("variable")}</div>
|
||||
|
||||
<div className="col-span-7 break-words test-sm text-emphasis">
|
||||
<div className="test-sm text-emphasis col-span-7 break-words">
|
||||
{" "}
|
||||
{`{${t("company_size")
|
||||
.replace(/[^a-zA-Z0-9 ]/g, "")
|
||||
|
@ -950,14 +956,14 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
</div>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<p className="w-full font-medium test-sm">{t("example_2")}</p>
|
||||
<div className="grid grid-cols-12 mt-2">
|
||||
<div className="col-span-5 test-sm text-default ltr:mr-2 rtl:ml-2">
|
||||
<p className="test-sm w-full font-medium">{t("example_2")}</p>
|
||||
<div className="mt-2 grid grid-cols-12">
|
||||
<div className="test-sm text-default col-span-5 ltr:mr-2 rtl:ml-2">
|
||||
{t("booking_question_identifier")}
|
||||
</div>
|
||||
<div className="col-span-7 test-sm text-emphasis">{t("what_help_needed")}</div>
|
||||
<div className="col-span-5 test-sm text-default">{t("variable")}</div>
|
||||
<div className="col-span-7 break-words test-sm text-emphasis">
|
||||
<div className="test-sm text-emphasis col-span-7">{t("what_help_needed")}</div>
|
||||
<div className="test-sm text-default col-span-5">{t("variable")}</div>
|
||||
<div className="test-sm text-emphasis col-span-7 break-words">
|
||||
{" "}
|
||||
{`{${t("what_help_needed")
|
||||
.replace(/[^a-zA-Z0-9 ]/g, "")
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import { WorkflowActions, WorkflowTemplates, WorkflowTriggerEvents } from "@prisma/client";
|
||||
import { whatsappEventCancelledTemplate, whatsappEventCompletedTemplate, whatsappEventRescheduledTemplate, whatsappReminderTemplate } from "../lib/reminders/templates/whatsapp";
|
||||
|
||||
import {
|
||||
whatsappEventCancelledTemplate,
|
||||
whatsappEventCompletedTemplate,
|
||||
whatsappEventRescheduledTemplate,
|
||||
whatsappReminderTemplate,
|
||||
} from "../lib/reminders/templates/whatsapp";
|
||||
|
||||
export function isSMSAction(action: WorkflowActions) {
|
||||
return action === WorkflowActions.SMS_ATTENDEE || action === WorkflowActions.SMS_NUMBER;
|
||||
|
@ -10,46 +16,53 @@ export function isWhatsappAction(action: WorkflowActions) {
|
|||
}
|
||||
|
||||
export function isSMSOrWhatsappAction(action: WorkflowActions) {
|
||||
return isSMSAction(action) || isWhatsappAction(action)
|
||||
return isSMSAction(action) || isWhatsappAction(action);
|
||||
}
|
||||
|
||||
export function isAttendeeAction(action: WorkflowActions) {
|
||||
return action === WorkflowActions.SMS_ATTENDEE || action === WorkflowActions.EMAIL_ATTENDEE || action === WorkflowActions.WHATSAPP_ATTENDEE;
|
||||
return (
|
||||
action === WorkflowActions.SMS_ATTENDEE ||
|
||||
action === WorkflowActions.EMAIL_ATTENDEE ||
|
||||
action === WorkflowActions.WHATSAPP_ATTENDEE
|
||||
);
|
||||
}
|
||||
|
||||
export function getWhatsappTemplateForTrigger(trigger: WorkflowTriggerEvents): WorkflowTemplates {
|
||||
switch(trigger) {
|
||||
switch (trigger) {
|
||||
case "NEW_EVENT":
|
||||
case "BEFORE_EVENT":
|
||||
return WorkflowTemplates.REMINDER
|
||||
return WorkflowTemplates.REMINDER;
|
||||
case "AFTER_EVENT":
|
||||
return WorkflowTemplates.COMPLETED
|
||||
return WorkflowTemplates.COMPLETED;
|
||||
case "EVENT_CANCELLED":
|
||||
return WorkflowTemplates.CANCELLED
|
||||
return WorkflowTemplates.CANCELLED;
|
||||
case "RESCHEDULE_EVENT":
|
||||
return WorkflowTemplates.RESCHEDULED
|
||||
return WorkflowTemplates.RESCHEDULED;
|
||||
default:
|
||||
return WorkflowTemplates.REMINDER
|
||||
return WorkflowTemplates.REMINDER;
|
||||
}
|
||||
}
|
||||
|
||||
export function getWhatsappTemplateFunction(template: WorkflowTemplates): typeof whatsappReminderTemplate {
|
||||
switch(template) {
|
||||
switch (template) {
|
||||
case "CANCELLED":
|
||||
return whatsappEventCancelledTemplate
|
||||
return whatsappEventCancelledTemplate;
|
||||
case "COMPLETED":
|
||||
return whatsappEventCompletedTemplate
|
||||
return whatsappEventCompletedTemplate;
|
||||
case "RESCHEDULED":
|
||||
return whatsappEventRescheduledTemplate
|
||||
return whatsappEventRescheduledTemplate;
|
||||
case "CUSTOM":
|
||||
case "REMINDER":
|
||||
return whatsappReminderTemplate
|
||||
return whatsappReminderTemplate;
|
||||
default:
|
||||
return whatsappReminderTemplate
|
||||
return whatsappReminderTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
export function getWhatsappTemplateForAction(action: WorkflowActions, template: WorkflowTemplates): string | null {
|
||||
const templateFunction = getWhatsappTemplateFunction(template)
|
||||
return templateFunction(true, action)
|
||||
export function getWhatsappTemplateForAction(
|
||||
action: WorkflowActions,
|
||||
template: WorkflowTemplates
|
||||
): string | null {
|
||||
const templateFunction = getWhatsappTemplateFunction(template);
|
||||
return templateFunction(true, action);
|
||||
}
|
||||
|
|
|
@ -25,19 +25,16 @@ export const WORKFLOW_TEMPLATES = [
|
|||
WorkflowTemplates.REMINDER,
|
||||
WorkflowTemplates.CANCELLED,
|
||||
WorkflowTemplates.COMPLETED,
|
||||
WorkflowTemplates.RESCHEDULED
|
||||
WorkflowTemplates.RESCHEDULED,
|
||||
] as const;
|
||||
|
||||
export const BASIC_WORKFLOW_TEMPLATES = [
|
||||
WorkflowTemplates.CUSTOM,
|
||||
WorkflowTemplates.REMINDER,
|
||||
] as const;
|
||||
export const BASIC_WORKFLOW_TEMPLATES = [WorkflowTemplates.CUSTOM, WorkflowTemplates.REMINDER] as const;
|
||||
|
||||
export const WHATSAPP_WORKFLOW_TEMPLATES = [
|
||||
WorkflowTemplates.REMINDER,
|
||||
WorkflowTemplates.COMPLETED,
|
||||
WorkflowTemplates.CANCELLED,
|
||||
WorkflowTemplates.RESCHEDULED
|
||||
WorkflowTemplates.RESCHEDULED,
|
||||
] as const;
|
||||
|
||||
export const DYNAMIC_TEXT_VARIABLES = [
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import type { WorkflowStep } from "@prisma/client";
|
||||
|
||||
import { isSMSOrWhatsappAction } from "@calcom/features/ee/workflows/lib/actionHelperFunctions";
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { WorkflowActions } from "@calcom/prisma/enums";
|
||||
import { Zap, Smartphone, Mail, Bell } from "@calcom/ui/components/icon";
|
||||
import { isSMSOrWhatsappAction } from "@calcom/features/ee/workflows/lib/actionHelperFunctions";
|
||||
|
||||
export function getActionIcon(steps: WorkflowStep[], className?: string): JSX.Element {
|
||||
if (steps.length === 0) {
|
||||
|
|
|
@ -3,7 +3,13 @@ import type { TFunction } from "next-i18next";
|
|||
import { WorkflowActions } from "@calcom/prisma/enums";
|
||||
|
||||
import { isSMSOrWhatsappAction, isWhatsappAction } from "./actionHelperFunctions";
|
||||
import { TIME_UNIT, WHATSAPP_WORKFLOW_TEMPLATES, WORKFLOW_ACTIONS, BASIC_WORKFLOW_TEMPLATES, WORKFLOW_TRIGGER_EVENTS } from "./constants";
|
||||
import {
|
||||
TIME_UNIT,
|
||||
WHATSAPP_WORKFLOW_TEMPLATES,
|
||||
WORKFLOW_ACTIONS,
|
||||
BASIC_WORKFLOW_TEMPLATES,
|
||||
WORKFLOW_TRIGGER_EVENTS,
|
||||
} from "./constants";
|
||||
|
||||
export function getWorkflowActionOptions(t: TFunction, isTeamsPlan?: boolean) {
|
||||
return WORKFLOW_ACTIONS.filter((action) => action !== WorkflowActions.EMAIL_ADDRESS) //removing EMAIL_ADDRESS for now due to abuse episode
|
||||
|
@ -33,7 +39,8 @@ export function getWorkflowTimeUnitOptions(t: TFunction) {
|
|||
}
|
||||
|
||||
export function getWorkflowTemplateOptions(t: TFunction, action: WorkflowActions | undefined) {
|
||||
const TEMPLATES = (action && isWhatsappAction(action)) ? WHATSAPP_WORKFLOW_TEMPLATES : BASIC_WORKFLOW_TEMPLATES;
|
||||
const TEMPLATES =
|
||||
action && isWhatsappAction(action) ? WHATSAPP_WORKFLOW_TEMPLATES : BASIC_WORKFLOW_TEMPLATES;
|
||||
return TEMPLATES.map((template) => {
|
||||
return { label: t(`${template.toLowerCase()}`), value: template };
|
||||
}) as { label: string; value: any }[];
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { Workflow, WorkflowsOnEventTypes, WorkflowStep } from "@prisma/client";
|
||||
import type { MailData } from "@sendgrid/helpers/classes/mail";
|
||||
|
||||
import { isWhatsappAction } from "@calcom/features/ee/workflows/lib/actionHelperFunctions";
|
||||
import { SENDER_ID, SENDER_NAME } from "@calcom/lib/constants";
|
||||
import { WorkflowTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { WorkflowActions } from "@calcom/prisma/enums";
|
||||
|
@ -10,8 +11,6 @@ import { scheduleEmailReminder } from "./emailReminderManager";
|
|||
import { scheduleSMSReminder } from "./smsReminderManager";
|
||||
import { scheduleWhatsappReminder } from "./whatsappReminderManager";
|
||||
|
||||
import { isWhatsappAction } from "@calcom/features/ee/workflows/lib/actionHelperFunctions";
|
||||
|
||||
type ExtendedCalendarEvent = CalendarEvent & {
|
||||
metadata?: { videoCallUrl: string | undefined };
|
||||
eventType: { slug?: string };
|
||||
|
@ -113,7 +112,8 @@ export const scheduleWorkflowReminders = async (args: ScheduleWorkflowRemindersA
|
|||
hideBranding
|
||||
);
|
||||
} else if (isWhatsappAction(step.action)) {
|
||||
const sendTo = step.action === WorkflowActions.WHATSAPP_ATTENDEE ? smsReminderNumber : step.sendTo;
|
||||
const sendTo =
|
||||
step.action === WorkflowActions.WHATSAPP_ATTENDEE ? smsReminderNumber : step.sendTo;
|
||||
await scheduleWhatsappReminder(
|
||||
evt,
|
||||
sendTo,
|
||||
|
@ -208,7 +208,8 @@ export const sendCancelledReminders = async (args: SendCancelledRemindersArgs) =
|
|||
hideBranding
|
||||
);
|
||||
} else if (isWhatsappAction(step.action)) {
|
||||
const sendTo = step.action === WorkflowActions.WHATSAPP_ATTENDEE ? smsReminderNumber : step.sendTo;
|
||||
const sendTo =
|
||||
step.action === WorkflowActions.WHATSAPP_ATTENDEE ? smsReminderNumber : step.sendTo;
|
||||
await scheduleWhatsappReminder(
|
||||
evt,
|
||||
sendTo,
|
||||
|
|
|
@ -20,11 +20,11 @@ function assertTwilio(twilio: TwilioClient.Twilio | undefined): asserts twilio i
|
|||
}
|
||||
|
||||
function getDefaultSender(whatsapp = false) {
|
||||
let defaultSender = process.env.TWILIO_PHONE_NUMBER
|
||||
let defaultSender = process.env.TWILIO_PHONE_NUMBER;
|
||||
if (whatsapp) {
|
||||
defaultSender = `whatsapp:+${process.env.TWILIO_WHATSAPP_PHONE_NUMBER}`
|
||||
defaultSender = `whatsapp:+${process.env.TWILIO_WHATSAPP_PHONE_NUMBER}`;
|
||||
}
|
||||
return defaultSender
|
||||
return defaultSender;
|
||||
}
|
||||
|
||||
function getSMSNumber(phone: string, whatsapp = false) {
|
||||
|
@ -43,7 +43,13 @@ export const sendSMS = async (phoneNumber: string, body: string, sender: string,
|
|||
return response;
|
||||
};
|
||||
|
||||
export const scheduleSMS = async (phoneNumber: string, body: string, scheduledDate: Date, sender: string, whatsapp = false) => {
|
||||
export const scheduleSMS = async (
|
||||
phoneNumber: string,
|
||||
body: string,
|
||||
scheduledDate: Date,
|
||||
sender: string,
|
||||
whatsapp = false
|
||||
) => {
|
||||
assertTwilio(twilio);
|
||||
const response = await twilio.messages.create({
|
||||
body: body,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export * from "./whatsappEventCancelledTemplate"
|
||||
export * from "./whatsappEventCompletedTemplate"
|
||||
export * from "./whatsappEventReminderTemplate"
|
||||
export * from "./whatsappEventRescheduledTemplate"
|
||||
export * from "./whatsappEventCancelledTemplate";
|
||||
export * from "./whatsappEventCompletedTemplate";
|
||||
export * from "./whatsappEventReminderTemplate";
|
||||
export * from "./whatsappEventRescheduledTemplate";
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import dayjs from "@calcom/dayjs";
|
||||
import { WorkflowActions } from "@prisma/client";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
|
||||
export const whatsappEventCancelledTemplate = (
|
||||
isEditingMode: boolean,
|
||||
action?: WorkflowActions,
|
||||
|
@ -26,7 +27,7 @@ export const whatsappEventCancelledTemplate = (
|
|||
|
||||
const templateOne = `Hi${
|
||||
name ? ` ${name}` : ``
|
||||
}, your meeting (*${eventName}*) with ${attendee} on ${eventDate} at ${startTime} ${timeZone} has been canceled.`
|
||||
}, your meeting (*${eventName}*) with ${attendee} on ${eventDate} at ${startTime} ${timeZone} has been canceled.`;
|
||||
|
||||
//Twilio supports up to 1024 characters for whatsapp template messages
|
||||
if (templateOne.length <= 1024) return templateOne;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import dayjs from "@calcom/dayjs";
|
||||
import { WorkflowActions } from "@prisma/client";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
|
||||
export const whatsappEventCompletedTemplate = (
|
||||
isEditingMode: boolean,
|
||||
action?: WorkflowActions,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { WorkflowActions } from "@prisma/client";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
|
||||
export const whatsappEventRescheduledTemplate = (
|
||||
|
@ -28,7 +29,6 @@ export const whatsappEventRescheduledTemplate = (
|
|||
name ? ` ${name}` : ``
|
||||
}, your meeting (*${eventName}*) with ${attendee} on ${eventDate} at ${startTime} ${timeZone} has been rescheduled.`;
|
||||
|
||||
|
||||
//Twilio supports up to 1024 characters for whatsapp template messages
|
||||
if (templateOne.length <= 1024) return templateOne;
|
||||
|
||||
|
|
|
@ -2,12 +2,17 @@ import type { TimeUnit } from "@prisma/client";
|
|||
import { WorkflowTriggerEvents, WorkflowTemplates, WorkflowActions, WorkflowMethods } from "@prisma/client";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import prisma from "@calcom/prisma";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { BookingInfo, deleteScheduledSMSReminder, timeUnitLowerCase } from "./smsReminderManager";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import * as twilio from "./smsProviders/twilioProvider";
|
||||
import { whatsappEventCancelledTemplate, whatsappEventCompletedTemplate, whatsappEventRescheduledTemplate, whatsappReminderTemplate } from "./templates/whatsapp";
|
||||
import { BookingInfo, deleteScheduledSMSReminder, timeUnitLowerCase } from "./smsReminderManager";
|
||||
import {
|
||||
whatsappEventCancelledTemplate,
|
||||
whatsappEventCompletedTemplate,
|
||||
whatsappEventRescheduledTemplate,
|
||||
whatsappReminderTemplate,
|
||||
} from "./templates/whatsapp";
|
||||
|
||||
const log = logger.getChildLogger({ prefix: ["[whatsappReminderManager]"] });
|
||||
|
||||
|
@ -55,25 +60,57 @@ export const scheduleWhatsappReminder = async (
|
|||
}
|
||||
|
||||
const name = action === WorkflowActions.WHATSAPP_ATTENDEE ? evt.attendees[0].name : evt.organizer.name;
|
||||
const attendeeName = action === WorkflowActions.WHATSAPP_ATTENDEE ? evt.organizer.name : evt.attendees[0].name;
|
||||
const attendeeName =
|
||||
action === WorkflowActions.WHATSAPP_ATTENDEE ? evt.organizer.name : evt.attendees[0].name;
|
||||
const timeZone =
|
||||
action === WorkflowActions.WHATSAPP_ATTENDEE ? evt.attendees[0].timeZone : evt.organizer.timeZone;
|
||||
|
||||
switch(template) {
|
||||
switch (template) {
|
||||
case WorkflowTemplates.REMINDER:
|
||||
message = whatsappReminderTemplate(false, action, evt.startTime, evt.title, timeZone, attendeeName, name) || message;
|
||||
message =
|
||||
whatsappReminderTemplate(false, action, evt.startTime, evt.title, timeZone, attendeeName, name) ||
|
||||
message;
|
||||
break;
|
||||
case WorkflowTemplates.CANCELLED:
|
||||
message = whatsappEventCancelledTemplate(false, action, evt.startTime, evt.title, timeZone, attendeeName, name) || message;
|
||||
break
|
||||
message =
|
||||
whatsappEventCancelledTemplate(
|
||||
false,
|
||||
action,
|
||||
evt.startTime,
|
||||
evt.title,
|
||||
timeZone,
|
||||
attendeeName,
|
||||
name
|
||||
) || message;
|
||||
break;
|
||||
case WorkflowTemplates.RESCHEDULED:
|
||||
message = whatsappEventRescheduledTemplate(false, action, evt.startTime, evt.title, timeZone, attendeeName, name) || message;
|
||||
message =
|
||||
whatsappEventRescheduledTemplate(
|
||||
false,
|
||||
action,
|
||||
evt.startTime,
|
||||
evt.title,
|
||||
timeZone,
|
||||
attendeeName,
|
||||
name
|
||||
) || message;
|
||||
break;
|
||||
case WorkflowTemplates.COMPLETED:
|
||||
message = whatsappEventCompletedTemplate(false, action, evt.startTime, evt.title, timeZone, attendeeName, name) || message;
|
||||
break
|
||||
message =
|
||||
whatsappEventCompletedTemplate(
|
||||
false,
|
||||
action,
|
||||
evt.startTime,
|
||||
evt.title,
|
||||
timeZone,
|
||||
attendeeName,
|
||||
name
|
||||
) || message;
|
||||
break;
|
||||
default:
|
||||
message = whatsappReminderTemplate(false, action, evt.startTime, evt.title, timeZone, attendeeName, name) || message;
|
||||
message =
|
||||
whatsappReminderTemplate(false, action, evt.startTime, evt.title, timeZone, attendeeName, name) ||
|
||||
message;
|
||||
}
|
||||
|
||||
// Allows debugging generated whatsapp content without waiting for twilio to send whatsapp messages
|
||||
|
|
|
@ -221,7 +221,7 @@ function WorkflowPage() {
|
|||
|
||||
//check if phone number is verified
|
||||
if (
|
||||
(step.action === WorkflowActions.SMS_NUMBER || step.action === WorkflowActions.WHATSAPP_NUMBER) &&
|
||||
(step.action === WorkflowActions.SMS_NUMBER || step.action === WorkflowActions.WHATSAPP_NUMBER) &&
|
||||
!verifiedNumbers?.find((verifiedNumber) => verifiedNumber.phoneNumber === step.sendTo)
|
||||
) {
|
||||
isVerified = false;
|
||||
|
|
|
@ -71,9 +71,7 @@ const fieldSchema = z.object({
|
|||
|
||||
required: z.boolean().default(false).optional(),
|
||||
hidden: z.boolean().optional(),
|
||||
editable: EditableSchema
|
||||
.default("user")
|
||||
.optional(),
|
||||
editable: EditableSchema.default("user").optional(),
|
||||
sources: z
|
||||
.array(
|
||||
z.object({
|
||||
|
|
Loading…
Reference in New Issue