SMS workflow actions only for Teams (#6003)
* disable sms actions for users without team * add isTeamsPlan query * disable SMS action if user is not in a team * remove console log * disable SMS actions also in AddActionDialog * throw error is users wants to add sms or edit to sms action * code clean up * Get actions options from backend. cleanup * Typefix Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: zomars <zomars@me.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
parent
cf6efabdbb
commit
7b18272d60
|
@ -7,6 +7,7 @@ import { z } from "zod";
|
|||
|
||||
import { SENDER_ID } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
|
@ -23,7 +24,6 @@ import {
|
|||
} from "@calcom/ui";
|
||||
|
||||
import { WORKFLOW_ACTIONS } from "../lib/constants";
|
||||
import { getWorkflowActionOptions } from "../lib/getOptions";
|
||||
import { onlyLettersNumbersSpaces } from "../pages/workflow";
|
||||
|
||||
interface IAddActionDialog {
|
||||
|
@ -50,7 +50,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
const [isPhoneNumberNeeded, setIsPhoneNumberNeeded] = useState(false);
|
||||
const [isSenderIdNeeded, setIsSenderIdNeeded] = useState(false);
|
||||
const [isEmailAddressNeeded, setIsEmailAddressNeeded] = useState(false);
|
||||
const actionOptions = getWorkflowActionOptions(t);
|
||||
const { data: actionOptions } = trpc.viewer.workflows.getWorkflowActionOptions.useQuery();
|
||||
|
||||
const formSchema = z.object({
|
||||
action: z.enum(WORKFLOW_ACTIONS),
|
||||
|
@ -101,6 +101,8 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
}
|
||||
};
|
||||
|
||||
if (!actionOptions) return null;
|
||||
|
||||
return (
|
||||
<Dialog open={isOpenDialog} onOpenChange={setIsOpenDialog}>
|
||||
<DialogContent type="creation" title={t("add_action")}>
|
||||
|
@ -131,6 +133,11 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
|||
defaultValue={actionOptions[0]}
|
||||
onChange={handleSelectAction}
|
||||
options={actionOptions}
|
||||
isOptionDisabled={(option: {
|
||||
label: string;
|
||||
value: WorkflowActions;
|
||||
disabled: boolean;
|
||||
}) => option.disabled}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
|
|
@ -6,7 +6,6 @@ import { Controller, UseFormReturn } from "react-hook-form";
|
|||
import { SENDER_ID } from "@calcom/lib/constants";
|
||||
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";
|
||||
import { Button, Label, TextField } from "@calcom/ui";
|
||||
import { MultiSelectCheckboxes } from "@calcom/ui";
|
||||
|
|
|
@ -92,8 +92,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
const [showTimeSectionAfter, setShowTimeSectionAfter] = useState(
|
||||
form.getValues("trigger") === WorkflowTriggerEvents.AFTER_EVENT
|
||||
);
|
||||
|
||||
const actionOptions = getWorkflowActionOptions(t);
|
||||
const { data: actionOptions } = trpc.viewer.workflows.getWorkflowActionOptions.useQuery();
|
||||
const triggerOptions = getWorkflowTriggerOptions(t);
|
||||
const templateOptions = getWorkflowTemplateOptions(t);
|
||||
|
||||
|
@ -227,6 +226,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
const selectedAction = {
|
||||
label: actionString.charAt(0).toUpperCase() + actionString.slice(1),
|
||||
value: step.action,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
const selectedTemplate = { label: t(`${step.template.toLowerCase()}`), value: step.template };
|
||||
|
@ -341,6 +341,11 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
|
|||
}}
|
||||
defaultValue={selectedAction}
|
||||
options={actionOptions}
|
||||
isOptionDisabled={(option: {
|
||||
label: string;
|
||||
value: WorkflowActions;
|
||||
disabled: boolean;
|
||||
}) => option.disabled}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import { WorkflowActions } from "@prisma/client";
|
||||
import { TFunction } from "next-i18next";
|
||||
|
||||
import { TIME_UNIT, WORKFLOW_ACTIONS, WORKFLOW_TEMPLATES, WORKFLOW_TRIGGER_EVENTS } from "./constants";
|
||||
|
||||
export function getWorkflowActionOptions(t: TFunction) {
|
||||
export function getWorkflowActionOptions(t: TFunction, isTeamsPlan?: boolean) {
|
||||
return WORKFLOW_ACTIONS.map((action) => {
|
||||
const actionString = t(`${action.toLowerCase()}_action`);
|
||||
|
||||
return { label: actionString.charAt(0).toUpperCase() + actionString.slice(1), value: action };
|
||||
const isSMSAction = action === WorkflowActions.SMS_ATTENDEE || action === WorkflowActions.SMS_NUMBER;
|
||||
|
||||
return {
|
||||
label: actionString.charAt(0).toUpperCase() + actionString.slice(1),
|
||||
value: action,
|
||||
disabled: isSMSAction && !isTeamsPlan,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
WORKFLOW_ACTIONS,
|
||||
TIME_UNIT,
|
||||
} from "@calcom/features/ee/workflows/lib/constants";
|
||||
import { getWorkflowActionOptions } from "@calcom/features/ee/workflows/lib/getOptions";
|
||||
import {
|
||||
deleteScheduledEmailReminder,
|
||||
scheduleEmailReminder,
|
||||
|
@ -28,11 +29,16 @@ import {
|
|||
} from "@calcom/features/ee/workflows/lib/reminders/smsReminderManager";
|
||||
import { SENDER_ID } from "@calcom/lib/constants";
|
||||
import { getErrorFromUnknown } from "@calcom/lib/errors";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
import { router, authedProcedure, authedRateLimitedProcedure } from "../../trpc";
|
||||
|
||||
function isSMSAction(action: WorkflowActions) {
|
||||
return action === WorkflowActions.SMS_ATTENDEE || action === WorkflowActions.SMS_NUMBER;
|
||||
}
|
||||
|
||||
export const workflowsRouter = router({
|
||||
list: authedProcedure.query(async ({ ctx }) => {
|
||||
const workflows = await ctx.prisma.workflow.findMany({
|
||||
|
@ -249,6 +255,11 @@ export const workflowsRouter = router({
|
|||
},
|
||||
select: {
|
||||
userId: true,
|
||||
user: {
|
||||
select: {
|
||||
teams: true,
|
||||
},
|
||||
},
|
||||
steps: true,
|
||||
},
|
||||
});
|
||||
|
@ -519,6 +530,13 @@ export const workflowsRouter = router({
|
|||
});
|
||||
//step was edited
|
||||
} else if (JSON.stringify(oldStep) !== JSON.stringify(newStep)) {
|
||||
if (
|
||||
!userWorkflow.user.teams.length &&
|
||||
!isSMSAction(oldStep.action) &&
|
||||
isSMSAction(newStep.action)
|
||||
) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
await ctx.prisma.workflowStep.update({
|
||||
where: {
|
||||
id: oldStep.id,
|
||||
|
@ -658,6 +676,9 @@ export const workflowsRouter = router({
|
|||
//added steps
|
||||
const addedSteps = steps.map((s) => {
|
||||
if (s.id <= 0) {
|
||||
if (!userWorkflow.user.teams.length && isSMSAction(s.action)) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
const { id: stepId, ...stepToAdd } = s;
|
||||
return stepToAdd;
|
||||
}
|
||||
|
@ -984,4 +1005,10 @@ export const workflowsRouter = router({
|
|||
});
|
||||
}
|
||||
}),
|
||||
getWorkflowActionOptions: authedProcedure.query(async ({ ctx }) => {
|
||||
const userId = ctx.user.id;
|
||||
const hasTeamPlan = (await ctx.prisma.membership.count({ where: { userId } })) > 0;
|
||||
const t = await getTranslation(ctx.user.locale, "common");
|
||||
return getWorkflowActionOptions(t, hasTeamPlan);
|
||||
}),
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user