Merge branch 'main' into minimum-booking-notice-will-allow-hours-and-days

This commit is contained in:
Jeroen Reumkens 2022-11-03 10:09:12 +01:00 committed by GitHub
commit ab42cfd4bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 25 deletions

View File

@ -27,6 +27,12 @@ interface IAddActionDialog {
isOpenDialog: boolean;
setIsOpenDialog: Dispatch<SetStateAction<boolean>>;
addAction: (action: WorkflowActions, sendTo?: string, numberRequired?: boolean) => void;
isFreeUser: boolean;
}
interface ISelectActionOption {
label: string;
value: WorkflowActions;
}
type AddActionFormValues = {
@ -35,12 +41,19 @@ type AddActionFormValues = {
numberRequired?: boolean;
};
const cleanUpActionsForFreeUser = (actions: ISelectActionOption[]) => {
return actions.filter(
(item) => item.value !== WorkflowActions.SMS_ATTENDEE && item.value !== WorkflowActions.SMS_NUMBER
);
};
export const AddActionDialog = (props: IAddActionDialog) => {
const { t } = useLocale();
const { isOpenDialog, setIsOpenDialog, addAction } = props;
const { isOpenDialog, setIsOpenDialog, addAction, isFreeUser } = props;
const [isPhoneNumberNeeded, setIsPhoneNumberNeeded] = useState(false);
const [isEmailAddressNeeded, setIsEmailAddressNeeded] = useState(false);
const actionOptions = getWorkflowActionOptions(t);
const workflowActions = getWorkflowActionOptions(t);
const actionOptions = isFreeUser ? cleanUpActionsForFreeUser(workflowActions) : workflowActions;
const formSchema = z.object({
action: z.enum(WORKFLOW_ACTIONS),
@ -59,6 +72,26 @@ export const AddActionDialog = (props: IAddActionDialog) => {
resolver: zodResolver(formSchema),
});
const handleSelectAction = (newValue: ISelectActionOption | null) => {
if (newValue) {
form.setValue("action", newValue.value);
if (newValue.value === WorkflowActions.SMS_NUMBER) {
setIsPhoneNumberNeeded(true);
setIsEmailAddressNeeded(false);
} else if (newValue.value === WorkflowActions.EMAIL_ADDRESS) {
setIsEmailAddressNeeded(true);
setIsPhoneNumberNeeded(false);
} else {
setIsEmailAddressNeeded(false);
setIsPhoneNumberNeeded(false);
}
form.unregister("sendTo");
form.unregister("numberRequired");
form.clearErrors("action");
form.clearErrors("sendTo");
}
};
return (
<Dialog open={isOpenDialog} onOpenChange={setIsOpenDialog}>
<DialogContent type="creation" useOwnActionButtons={true} title={t("add_action")}>
@ -86,25 +119,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
isSearchable={false}
className="text-sm"
defaultValue={actionOptions[0]}
onChange={(val) => {
if (val) {
form.setValue("action", val.value);
if (val.value === WorkflowActions.SMS_NUMBER) {
setIsPhoneNumberNeeded(true);
setIsEmailAddressNeeded(false);
} else if (val.value === WorkflowActions.EMAIL_ADDRESS) {
setIsEmailAddressNeeded(true);
setIsPhoneNumberNeeded(false);
} else {
setIsEmailAddressNeeded(false);
setIsPhoneNumberNeeded(false);
}
form.unregister("sendTo");
form.unregister("numberRequired");
form.clearErrors("action");
form.clearErrors("sendTo");
}
}}
onChange={handleSelectAction}
options={actionOptions}
/>
);

View File

@ -6,6 +6,7 @@ import { Controller, UseFormReturn } from "react-hook-form";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
import { Icon } from "@calcom/ui/Icon";
import { Button } from "@calcom/ui/v2";
import { Label, TextField } from "@calcom/ui/v2";
@ -28,6 +29,9 @@ export default function WorkflowDetailsPage(props: Props) {
const { t } = useLocale();
const router = useRouter();
const me = useMeQuery();
const isFreeUser = me.data?.plan === "FREE";
const [isAddActionDialogOpen, setIsAddActionDialogOpen] = useState(false);
const [reload, setReload] = useState(false);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
@ -120,7 +124,7 @@ export default function WorkflowDetailsPage(props: Props) {
<div className="w-full rounded-md border border-gray-200 bg-gray-50 p-3 py-5 md:ml-3 md:p-8">
{form.getValues("trigger") && (
<div>
<WorkflowStepContainer form={form} />
<WorkflowStepContainer form={form} isFreeUser={isFreeUser} />
</div>
)}
{form.getValues("steps") && (
@ -133,6 +137,7 @@ export default function WorkflowDetailsPage(props: Props) {
step={step}
reload={reload}
setReload={setReload}
isFreeUser={isFreeUser}
/>
);
})}
@ -152,6 +157,7 @@ export default function WorkflowDetailsPage(props: Props) {
isOpenDialog={isAddActionDialogOpen}
setIsOpenDialog={setIsAddActionDialogOpen}
addAction={addAction}
isFreeUser={isFreeUser}
/>
<DeleteDialog
isOpenDialog={deleteDialogOpen}

View File

@ -38,11 +38,12 @@ type WorkflowStepProps = {
form: UseFormReturn<FormValues>;
reload?: boolean;
setReload?: Dispatch<SetStateAction<boolean>>;
isFreeUser: boolean;
};
export default function WorkflowStepContainer(props: WorkflowStepProps) {
const { t, i18n } = useLocale();
const { step, form, reload, setReload } = props;
const { step, form, reload, setReload, isFreeUser } = props;
const [isAdditionalInputsDialogOpen, setIsAdditionalInputsDialogOpen] = useState(false);
const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);
@ -300,7 +301,15 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
}
}}
defaultValue={selectedAction}
options={actionOptions}
options={
isFreeUser
? actionOptions.filter(
(actionOption) =>
actionOption.value !== WorkflowActions.SMS_ATTENDEE &&
actionOption.value !== WorkflowActions.SMS_NUMBER
)
: actionOptions
}
/>
);
}}

View File

@ -27,12 +27,17 @@ import {
scheduleSMSReminder,
} from "@calcom/features/ee/workflows/lib/reminders/smsReminderManager";
import { getErrorFromUnknown } from "@calcom/lib/errors";
import { getTranslation } from "@calcom/lib/server/i18n";
import { TRPCError } from "@trpc/server";
import { createProtectedRouter } from "../../createRouter";
function isSMSAction(action: WorkflowActions) {
if (action === WorkflowActions.SMS_ATTENDEE || action === WorkflowActions.SMS_NUMBER) {
return true;
}
}
export const workflowsRouter = createProtectedRouter()
.query("list", {
async resolve({ ctx }) {
@ -515,6 +520,9 @@ export const workflowsRouter = createProtectedRouter()
});
//step was edited
} else if (JSON.stringify(oldStep) !== JSON.stringify(newStep)) {
if (user.plan === "FREE" && !isSMSAction(oldStep.action) && isSMSAction(newStep.action)) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
await ctx.prisma.workflowStep.update({
where: {
id: oldStep.id,
@ -652,6 +660,9 @@ export const workflowsRouter = createProtectedRouter()
//added steps
const addedSteps = steps.map((s) => {
if (s.id <= 0) {
if (user.plan === "FREE" && isSMSAction(s.action)) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
const { id: stepId, ...stepToAdd } = s;
return stepToAdd;
}