import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { HttpError } from "@calcom/lib/http-error"; import { WorkflowActions } from "@calcom/prisma/enums"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; import { Button, EmptyScreen, showToast, Switch, Tooltip, Alert } from "@calcom/ui"; import { ExternalLink, Zap, Lock } from "@calcom/ui/components/icon"; import LicenseRequired from "../../common/components/LicenseRequired"; import { getActionIcon } from "../lib/getActionIcon"; import SkeletonLoader from "./SkeletonLoaderEventWorkflowsTab"; import type { WorkflowType } from "./WorkflowListPage"; type ItemProps = { workflow: WorkflowType; eventType: { id: number; title: string; }; isChildrenManagedEventType: boolean; }; const WorkflowListItem = (props: ItemProps) => { const { workflow, eventType } = props; const { t } = useLocale(); const [activeEventTypeIds, setActiveEventTypeIds] = useState( workflow.activeOn.map((active) => { if (active.eventType) { return active.eventType.id; } }) ); const isActive = activeEventTypeIds.includes(eventType.id); const utils = trpc.useContext(); const activateEventTypeMutation = trpc.viewer.workflows.activateEventType.useMutation({ onSuccess: async () => { let offOn = ""; if (activeEventTypeIds.includes(eventType.id)) { const newActiveEventTypeIds = activeEventTypeIds.filter((id) => { return id !== eventType.id; }); setActiveEventTypeIds(newActiveEventTypeIds); offOn = "off"; } else { const newActiveEventTypeIds = activeEventTypeIds; newActiveEventTypeIds.push(eventType.id); setActiveEventTypeIds(newActiveEventTypeIds); offOn = "on"; } await utils.viewer.eventTypes.get.invalidate({ id: eventType.id }); showToast( t("workflow_turned_on_successfully", { workflowName: workflow.name, offOn, }), "success" ); }, onError: (err) => { if (err instanceof HttpError) { const message = `${err.statusCode}: ${err.message}`; showToast(message, "error"); } if (err.data?.code === "UNAUTHORIZED") { // TODO: Add missing translation const message = `${err.data.code}: You are not authorized to enable or disable this workflow`; showToast(message, "error"); } }, }); const sendTo: Set = new Set(); workflow.steps.forEach((step) => { switch (step.action) { case WorkflowActions.EMAIL_HOST: sendTo.add(t("organizer_name_variable")); break; case WorkflowActions.EMAIL_ATTENDEE: sendTo.add(t("attendee_name_variable")); break; case WorkflowActions.SMS_ATTENDEE: sendTo.add(t("attendee_name_variable")); break; case WorkflowActions.SMS_NUMBER: sendTo.add(step.sendTo || ""); break; case WorkflowActions.EMAIL_ADDRESS: sendTo.add(step.sendTo || ""); break; } }); return (
{getActionIcon( workflow.steps, isActive ? "h-6 w-6 stroke-[1.5px] text-default" : "h-6 w-6 stroke-[1.5px] text-muted" )}
{workflow.name ? workflow.name : "Untitled (" + `${t(`${workflow.steps[0].action.toLowerCase()}_action`)}`.charAt(0).toUpperCase() + `${t(`${workflow.steps[0].action.toLowerCase()}_action`)}`.slice(1) + ")"}
{t("to")}: {Array.from(sendTo).map((sendToPerson, index) => { return {`${index ? ", " : ""}${sendToPerson}`}; })}
{!workflow.readOnly && (
)}
{workflow.readOnly && props.isChildrenManagedEventType && ( )} { activateEventTypeMutation.mutate({ workflowId: workflow.id, eventTypeId: eventType.id }); }} />
); }; type EventTypeSetup = RouterOutputs["viewer"]["eventTypes"]["get"]["eventType"]; type Props = { eventType: EventTypeSetup; workflows: WorkflowType[]; }; function EventWorkflowsTab(props: Props) { const { workflows, eventType } = props; const { t } = useLocale(); const { isManagedEventType, isChildrenManagedEventType } = useLockedFieldsManager( eventType, t("locked_fields_admin_description"), t("locked_fields_member_description") ); const { data, isLoading } = trpc.viewer.workflows.list.useQuery({ teamId: eventType.team?.id, userId: !isChildrenManagedEventType ? eventType.userId || undefined : undefined, }); const router = useRouter(); const [sortedWorkflows, setSortedWorkflows] = useState>([]); useEffect(() => { if (data?.workflows) { const activeWorkflows = workflows.map((workflowOnEventType) => { const dataWf = data.workflows.find((wf) => wf.id === workflowOnEventType.id); return { ...workflowOnEventType, readOnly: isChildrenManagedEventType && dataWf?.teamId ? true : dataWf?.readOnly ?? false, } as WorkflowType; }); const disabledWorkflows = data.workflows.filter( (workflow) => !workflows .map((workflow) => { return workflow.id; }) .includes(workflow.id) ); setSortedWorkflows(activeWorkflows.concat(disabledWorkflows)); } }, [isLoading]); const createMutation = trpc.viewer.workflows.create.useMutation({ onSuccess: async ({ workflow }) => { await router.replace("/workflows/" + workflow.id); }, onError: (err) => { if (err instanceof HttpError) { const message = `${err.statusCode}: ${err.message}`; showToast(message, "error"); } if (err.data?.code === "UNAUTHORIZED") { const message = `${err.data.code}: You are not able to create this workflow`; showToast(message, "error"); } }, }); return ( {!isLoading ? ( <> {isManagedEventType && ( )} {data?.workflows && data?.workflows.length > 0 ? (
{sortedWorkflows.map((workflow) => { return ( ); })}
) : (
createMutation.mutate({ teamId: eventType.team?.id })} loading={createMutation.isLoading}> {t("create_workflow")} } />
)} ) : ( )}
); } export default EventWorkflowsTab;