Add checkbox that defines if SMS reminder phone number should be required (#5047)

* add phone number required checkbox

* make input required only if numberRequired is true

* fix error that smsReminderNumber is null

* code clean up

* fix typo

* save no input as null

* fix code change

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
This commit is contained in:
Carina Wollendorfer 2022-10-18 14:47:15 +02:00 committed by GitHub
parent 431e4224fe
commit 95e3f55f26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 62 additions and 14 deletions

View File

@ -266,7 +266,8 @@ const BookingPage = ({
smsReminderNumber: z
.string()
.refine((val) => isValidPhoneNumber(val))
.optional(),
.optional()
.nullable(),
})
.passthrough();
@ -358,7 +359,9 @@ const BookingPage = ({
hasHashedBookingLink,
hashedLink,
smsReminderNumber:
selectedLocationType === LocationType.Phone ? booking.phone : booking.smsReminderNumber,
selectedLocationType === LocationType.Phone
? booking.phone
: booking.smsReminderNumber || undefined,
ethSignature: gateState.rainbowToken,
}));
recurringMutation.mutate(recurringBookings);
@ -386,7 +389,9 @@ const BookingPage = ({
hasHashedBookingLink,
hashedLink,
smsReminderNumber:
selectedLocationType === LocationType.Phone ? booking.phone : booking.smsReminderNumber,
selectedLocationType === LocationType.Phone
? booking.phone
: booking.smsReminderNumber || undefined,
ethSignature: gateState.rainbowToken,
});
}
@ -400,6 +405,7 @@ const BookingPage = ({
"dark:placeholder:text-darkgray-600 focus:border-brand dark:border-darkgray-300 dark:text-darkgray-900 block w-full rounded-md border-gray-300 text-sm focus:ring-black disabled:bg-gray-200 disabled:hover:cursor-not-allowed dark:bg-transparent dark:selection:bg-green-500 disabled:dark:text-gray-500";
let isSmsReminderNumberNeeded = false;
let isSmsReminderNumberRequired = false;
if (eventType.workflows.length > 0) {
eventType.workflows.forEach((workflowReference) => {
@ -407,6 +413,7 @@ const BookingPage = ({
workflowReference.workflow.steps.forEach((step) => {
if (step.action === WorkflowActions.SMS_ATTENDEE) {
isSmsReminderNumberNeeded = true;
isSmsReminderNumberRequired = step.numberRequired || false;
return;
}
});
@ -786,7 +793,7 @@ const BookingPage = ({
name="smsReminderNumber"
placeholder={t("enter_phone_number")}
id="smsReminderNumber"
required
required={isSmsReminderNumberRequired}
/>
</div>
{bookingForm.formState.errors.smsReminderNumber && (

View File

@ -1191,7 +1191,6 @@
"additional_notes_info": "The Additional notes of booking",
"attendee_name_info": "The person booking's name",
"to": "To",
"attendee_required_enter_number": "This will require the attendee to enter a phone number when booking",
"workflow_turned_on_successfully": "{{workflowName}} workflow turned {{offOn}} successfully",
"download_responses": "Download Responses",
"create_your_first_form": "Create your first form",
@ -1314,5 +1313,6 @@
"how_long_after": "How long after event ends?",
"no_available_slots": "No Available slots",
"time_available": "Time available",
"install_new_calendar_app": "Install new calendar app"
"install_new_calendar_app": "Install new calendar app",
"make_phone_number_required": "Make phone number required for booking event"
}

View File

@ -18,6 +18,7 @@ import {
Label,
Select,
} from "@calcom/ui/v2";
import CheckboxField from "@calcom/ui/v2/core/form/Checkbox";
import { WORKFLOW_ACTIONS } from "../../lib/constants";
import { getWorkflowActionOptions } from "../../lib/getOptions";
@ -25,12 +26,13 @@ import { getWorkflowActionOptions } from "../../lib/getOptions";
interface IAddActionDialog {
isOpenDialog: boolean;
setIsOpenDialog: Dispatch<SetStateAction<boolean>>;
addAction: (action: WorkflowActions, sendTo?: string) => void;
addAction: (action: WorkflowActions, sendTo?: string, numberRequired?: boolean) => void;
}
type AddActionFormValues = {
action: WorkflowActions;
sendTo?: string;
numberRequired?: boolean;
};
export const AddActionDialog = (props: IAddActionDialog) => {
@ -46,6 +48,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
.string()
.refine((val) => isValidPhoneNumber(val) || val.includes("@"))
.optional(),
numberRequired: z.boolean().optional(),
});
const form = useForm<AddActionFormValues>({
@ -64,9 +67,10 @@ export const AddActionDialog = (props: IAddActionDialog) => {
<Form
form={form}
handleSubmit={(values) => {
addAction(values.action, values.sendTo);
addAction(values.action, values.sendTo, values.numberRequired);
form.unregister("sendTo");
form.unregister("action");
form.unregister("numberRequired");
setIsOpenDialog(false);
setIsPhoneNumberNeeded(false);
setIsEmailAddressNeeded(false);
@ -96,6 +100,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
setIsPhoneNumberNeeded(false);
}
form.unregister("sendTo");
form.unregister("numberRequired");
form.clearErrors("action");
form.clearErrors("sendTo");
}
@ -109,6 +114,21 @@ 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={() => (
<CheckboxField
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>
@ -140,6 +160,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
setIsOpenDialog(false);
form.unregister("sendTo");
form.unregister("action");
form.unregister("numberRequired");
setIsPhoneNumberNeeded(false);
setIsEmailAddressNeeded(false);
}}>

View File

@ -49,7 +49,7 @@ export default function WorkflowDetailsPage(props: Props) {
[data]
);
const addAction = (action: WorkflowActions, sendTo?: string) => {
const addAction = (action: WorkflowActions, sendTo?: string, numberRequired?: boolean) => {
const steps = form.getValues("steps");
const id =
steps?.length > 0
@ -72,6 +72,7 @@ export default function WorkflowDetailsPage(props: Props) {
reminderBody: null,
emailSubject: null,
template: WorkflowTemplates.CUSTOM,
numberRequired: numberRequired || false,
};
steps?.push(step);
form.setValue("steps", steps);

View File

@ -19,6 +19,7 @@ import { Icon } from "@calcom/ui/Icon";
import PhoneInput from "@calcom/ui/form/PhoneInputLazy";
import { Button, DialogClose, DialogContent } from "@calcom/ui/v2";
import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent";
import CheckboxField from "@calcom/ui/v2/core/form/Checkbox";
import { EmailField, Label, TextArea } from "@calcom/ui/v2/core/form/fields";
import Select from "@calcom/ui/v2/core/form/select";
@ -305,9 +306,22 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
}}
/>
{form.getValues(`steps.${step.stepNumber - 1}.action`) === WorkflowActions.SMS_ATTENDEE && (
<div className="mt-2 flex items-center text-sm text-gray-600">
<Icon.FiInfo className="mr-2 h-3 w-3" />
<p>{t("attendee_required_enter_number")}</p>
<div className="mt-5">
<Controller
name={`steps.${step.stepNumber - 1}.numberRequired`}
control={form.control}
render={() => (
<CheckboxField
defaultChecked={
form.getValues(`steps.${step.stepNumber - 1}.numberRequired`) || false
}
description={t("make_phone_number_required")}
onChange={(e) =>
form.setValue(`steps.${step.stepNumber - 1}.numberRequired`, e.target.checked)
}
/>
)}
/>
</div>
)}
</div>

View File

@ -89,7 +89,7 @@ export const scheduleSMSReminder = async (
}
if (message.length > 0 && reminderPhone) {
//send SMS when event is booked/cancelled/Reschdeuled
//send SMS when event is booked/cancelled/rescheduled
if (
triggerEvent === WorkflowTriggerEvents.NEW_EVENT ||
triggerEvent === WorkflowTriggerEvents.EVENT_CANCELLED ||

View File

@ -18,7 +18,6 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HttpError } from "@calcom/lib/http-error";
import { stringOrNumber } from "@calcom/prisma/zod-utils";
import { trpc } from "@calcom/trpc/react";
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
import { Option } from "@calcom/ui/form/MultiSelectCheckboxes";
import { Alert, Button, Form, showToast } from "@calcom/ui/v2";
import Shell from "@calcom/ui/v2/core/Shell";
@ -53,6 +52,7 @@ const formSchema = z.object({
reminderBody: z.string().nullable(),
emailSubject: z.string().nullable(),
template: z.nativeEnum(WorkflowTemplates),
numberRequired: z.boolean().nullable(),
sendTo: z
.string()
.refine((val) => isValidPhoneNumber(val) || val.includes("@"))

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "WorkflowStep" ADD COLUMN "numberRequired" BOOLEAN;

View File

@ -565,6 +565,7 @@ model WorkflowStep {
emailSubject String?
template WorkflowTemplates @default(REMINDER)
workflowReminders WorkflowReminder[]
numberRequired Boolean?
}
model Workflow {

View File

@ -229,6 +229,7 @@ export const workflowsRouter = createProtectedRouter()
reminderBody: z.string().optional().nullable(),
emailSubject: z.string().optional().nullable(),
template: z.enum(WORKFLOW_TEMPLATES),
numberRequired: z.boolean().nullable(),
})
.array(),
trigger: z.enum(WORKFLOW_TRIGGER_EVENTS),
@ -528,6 +529,7 @@ export const workflowsRouter = createProtectedRouter()
reminderBody: newStep.template === WorkflowTemplates.CUSTOM ? newStep.reminderBody : null,
emailSubject: newStep.template === WorkflowTemplates.CUSTOM ? newStep.emailSubject : null,
template: newStep.template,
numberRequired: newStep.numberRequired,
},
});
//cancel all reminders of step and create new ones (not for newEventTypes)