import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { useFormContext } from "react-hook-form"; import { Trans } from "react-i18next"; import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager"; import type { FormValues } from "@calcom/features/eventtypes/lib/types"; 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 { Alert, Button, EmptyScreen, Icon, showToast, Switch, Tooltip } from "@calcom/ui"; import LicenseRequired from "../../common/components/LicenseRequired"; import { getActionIcon } from "../lib/getActionIcon"; import SkeletonLoader from "./SkeletonLoaderEventWorkflowsTab"; import type { WorkflowType } from "./WorkflowListPage"; type PartialWorkflowType = Pick; type ItemProps = { workflow: PartialWorkflowType; eventType: { id: number; title: string; requiresConfirmation: boolean; }; isChildrenManagedEventType: boolean; isActive: boolean; }; const WorkflowListItem = (props: ItemProps) => { const { workflow, eventType, isActive } = props; const { t } = useLocale(); const [activeEventTypeIds, setActiveEventTypeIds] = useState( workflow.activeOn?.map((active) => { if (active.eventType) { return active.eventType.id; } }) ?? [] ); const utils = trpc.useUtils(); const activateEventTypeMutation = trpc.viewer.workflows.activateEventType.useMutation({ onSuccess: async () => { const offOn = isActive ? "off" : "on"; await utils.viewer.workflows.getAllActiveWorkflows.invalidate(); 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") { showToast( t("unauthorized_workflow_error_message", { errorCode: err.data.code, }), "error" ); } }, }); const sendTo: Set = new Set(); workflow.steps.forEach((step) => { switch (step.action) { case WorkflowActions.EMAIL_HOST: sendTo.add(t("organizer")); break; case WorkflowActions.EMAIL_ATTENDEE: case WorkflowActions.SMS_ATTENDEE: case WorkflowActions.WHATSAPP_ATTENDEE: sendTo.add(t("attendee_name_variable")); break; case WorkflowActions.SMS_NUMBER: case WorkflowActions.WHATSAPP_NUMBER: 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: PartialWorkflowType[]; }; function EventWorkflowsTab(props: Props) { const { workflows, eventType } = props; const { t } = useLocale(); const formMethods = useFormContext(); const { shouldLockDisableProps, isManagedEventType, isChildrenManagedEventType } = useLockedFieldsManager({ eventType, translate: t, formMethods, }); const workflowsDisableProps = shouldLockDisableProps("workflows", { simple: true }); const lockedText = workflowsDisableProps.isLocked ? "locked" : "unlocked"; const { data, isPending } = 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 allActiveWorkflows = 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) => (!workflow.teamId || eventType.teamId === workflow.teamId) && !workflows .map((workflow) => { return workflow.id; }) .includes(workflow.id) ); const allSortedWorkflows = workflowsDisableProps.isLocked && !isManagedEventType ? allActiveWorkflows : allActiveWorkflows.concat(disabledWorkflows); setSortedWorkflows(allSortedWorkflows); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isPending]); const createMutation = trpc.viewer.workflows.create.useMutation({ onSuccess: async ({ workflow }) => { await router.replace(`/workflows/${workflow.id}?eventTypeId=${eventType.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}: ${t("error_workflow_unauthorized_create")}`; showToast(message, "error"); } }, }); return ( {!isPending ? ( <> {(isManagedEventType || isChildrenManagedEventType) && ( {lockedText[0].toUpperCase()} {lockedText.slice(1)} {isManagedEventType ? "for members" : "by team admins"} } actions={
{workflowsDisableProps.LockedIcon}
} message={ {isManagedEventType ? "Members" : "You"}{" "} {workflowsDisableProps.isLocked ? "will be able to see the active workflows but will not be able to edit any workflow settings" : "will be able to see the active workflow and will be able to edit any workflow settings"} } /> )} {data?.workflows && sortedWorkflows.length > 0 ? (
{sortedWorkflows.map((workflow) => { return ( activeWorkflow.id === workflow.id)} /> ); })}
) : (
createMutation.mutate({ teamId: eventType.team?.id })} loading={createMutation.isPending}> {t("create_workflow")} } />
)} ) : ( )}
); } export default EventWorkflowsTab;