import { Webhook } from "@prisma/client"; import { useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import showToast from "@calcom/lib/notification"; import { trpc } from "@calcom/trpc/react"; import Button from "@calcom/ui/Button"; import { DialogFooter } from "@calcom/ui/Dialog"; import Switch from "@calcom/ui/Switch"; import { FieldsetLegend, Form, InputGroupBox, TextArea, TextField } from "@calcom/ui/form/fields"; import { WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP } from "@lib/webhooks/constants"; import customTemplate, { hasTemplateIntegration } from "@lib/webhooks/integrationTemplate"; import { TWebhook } from "@components/webhook/WebhookListItem"; import WebhookTestDisclosure from "@components/webhook/WebhookTestDisclosure"; export default function WebhookDialogForm(props: { eventTypeId?: number; defaultValues?: TWebhook; app?: string; handleClose: () => void; webhooks: Webhook[]; }) { const { t } = useLocale(); const utils = trpc.useContext(); const appId = props.app; const webhooks = props.webhooks; const triggers = !appId ? WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP["core"] : WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP[appId as keyof typeof WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP]; const { defaultValues = { id: "", eventTriggers: triggers, subscriberUrl: "", active: true, payloadTemplate: null, secret: null, } as Omit, } = props; const [useCustomPayloadTemplate, setUseCustomPayloadTemplate] = useState(!!defaultValues.payloadTemplate); const [changeSecret, setChangeSecret] = useState(false); const [newSecret, setNewSecret] = useState(""); const hasSecretKey = !!defaultValues.secret; const currentSecret = defaultValues.secret; const subscriberUrlReserved = (subscriberUrl: string, id: string): boolean => { return !!webhooks.find((webhook) => webhook.subscriberUrl === subscriberUrl && webhook.id !== id); }; const form = useForm({ defaultValues, }); const handleInput = (event: React.FormEvent) => { setNewSecret(event.currentTarget.value); }; useEffect(() => { if (changeSecret) { form.unregister("secret", { keepDefaultValue: false }); } }, [changeSecret]); return (
{ if (subscriberUrlReserved(event.subscriberUrl, event.id)) { showToast(t("webhook_subscriber_url_reserved"), "error"); return; } const e = changeSecret ? { ...event, eventTypeId: props.eventTypeId, appId } : { ...event, secret: currentSecret, eventTypeId: props.eventTypeId, appId }; if (!useCustomPayloadTemplate && event.payloadTemplate) { event.payloadTemplate = null; } if (event.id) { await utils.client.mutation("viewer.webhook.edit", e); await utils.invalidateQueries(["viewer.webhook.list"]); showToast(t("webhook_updated_successfully"), "success"); } else { await utils.client.mutation("viewer.webhook.create", e); await utils.invalidateQueries(["viewer.webhook.list"]); showToast(t("webhook_created_successfully"), "success"); } props.handleClose(); }} className="space-y-4">
( { form.setValue("active", isChecked); }} /> )} />
{ form.setValue("subscriberUrl", e.target.value); if (hasTemplateIntegration({ url: e.target.value })) { setUseCustomPayloadTemplate(true); form.setValue("payloadTemplate", customTemplate({ url: e.target.value })); } }} />
{t("event_triggers")} {triggers.map((key) => ( ( { const value = field.value; const newValue = isChecked ? [...value, key] : value.filter((v) => v !== key); form.setValue("eventTriggers", newValue, { shouldDirty: true, }); }} /> )} /> ))}
{!!hasSecretKey && !changeSecret && ( <> {t("secret")}
{t("forgotten_secret_description")}
)} {!!hasSecretKey && changeSecret && ( <> )} {!hasSecretKey && ( )}
{t("payload_template")}
{useCustomPayloadTemplate && (