moved embed and webhooks from settings into /integrations (#978)
This commit is contained in:
parent
c146231b31
commit
656d58b94f
6 changed files with 292 additions and 288 deletions
|
@ -1,4 +1,4 @@
|
||||||
import { CodeIcon, CreditCardIcon, KeyIcon, UserGroupIcon, UserIcon } from "@heroicons/react/solid";
|
import { CreditCardIcon, KeyIcon, UserGroupIcon, UserIcon } from "@heroicons/react/solid";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { useLocale } from "@lib/hooks/useLocale";
|
import { useLocale } from "@lib/hooks/useLocale";
|
||||||
|
@ -19,7 +19,6 @@ export default function SettingsShell({ children }: { children: React.ReactNode
|
||||||
href: "/settings/security",
|
href: "/settings/security",
|
||||||
icon: KeyIcon,
|
icon: KeyIcon,
|
||||||
},
|
},
|
||||||
{ name: t("embed_and_webhooks"), href: "/settings/embed", icon: CodeIcon },
|
|
||||||
{
|
{
|
||||||
name: t("teams"),
|
name: t("teams"),
|
||||||
href: "/settings/teams",
|
href: "/settings/teams",
|
||||||
|
|
|
@ -11,7 +11,7 @@ import Button from "@components/ui/Button";
|
||||||
|
|
||||||
export default function WebhookListItem(props: {
|
export default function WebhookListItem(props: {
|
||||||
onChange: () => void;
|
onChange: () => void;
|
||||||
key: number;
|
key: string;
|
||||||
webhook: Webhook;
|
webhook: Webhook;
|
||||||
onEditWebhook: () => void;
|
onEditWebhook: () => void;
|
||||||
}) {
|
}) {
|
||||||
|
|
285
pages/integrations/embed.tsx
Normal file
285
pages/integrations/embed.tsx
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
import { useSession } from "next-auth/client";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
import classNames from "@lib/classNames";
|
||||||
|
import { useLocale } from "@lib/hooks/useLocale";
|
||||||
|
import { trpc } from "@lib/trpc";
|
||||||
|
import { Webhook } from "@lib/webhook";
|
||||||
|
|
||||||
|
import { Dialog, DialogClose, DialogContent, DialogHeader, DialogTrigger } from "@components/Dialog";
|
||||||
|
import { List, ListItem, ListItemText, ListItemTitle } from "@components/List";
|
||||||
|
import Loader from "@components/Loader";
|
||||||
|
import { ShellSubHeading } from "@components/Shell";
|
||||||
|
import Button from "@components/ui/Button";
|
||||||
|
import Switch from "@components/ui/Switch";
|
||||||
|
import EditWebhook from "@components/webhook/EditWebhook";
|
||||||
|
import WebhookList from "@components/webhook/WebhookList";
|
||||||
|
|
||||||
|
export default function Embed() {
|
||||||
|
const user = trpc.useQuery(["viewer.me"]).data;
|
||||||
|
const [, loading] = useSession();
|
||||||
|
const { t } = useLocale();
|
||||||
|
|
||||||
|
const [isLoading, setLoading] = useState(false);
|
||||||
|
const [bookingCreated, setBookingCreated] = useState(true);
|
||||||
|
const [bookingRescheduled, setBookingRescheduled] = useState(true);
|
||||||
|
const [bookingCancelled, setBookingCancelled] = useState(true);
|
||||||
|
const [editWebhookEnabled, setEditWebhookEnabled] = useState(false);
|
||||||
|
const [webhooks, setWebhooks] = useState([]);
|
||||||
|
const [webhookToEdit, setWebhookToEdit] = useState<Webhook | null>();
|
||||||
|
const [webhookEventTrigger, setWebhookEventTriggers] = useState([
|
||||||
|
"BOOKING_CREATED",
|
||||||
|
"BOOKING_RESCHEDULED",
|
||||||
|
"BOOKING_CANCELLED",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const subUrlRef = useRef<HTMLInputElement>() as React.MutableRefObject<HTMLInputElement>;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const arr = [];
|
||||||
|
bookingCreated && arr.push("BOOKING_CREATED");
|
||||||
|
bookingRescheduled && arr.push("BOOKING_RESCHEDULED");
|
||||||
|
bookingCancelled && arr.push("BOOKING_CANCELLED");
|
||||||
|
setWebhookEventTriggers(arr);
|
||||||
|
}, [bookingCreated, bookingRescheduled, bookingCancelled]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getWebhooks();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const iframeTemplate = `<iframe src="${process.env.NEXT_PUBLIC_BASE_URL}/${user?.username}" frameborder="0" allowfullscreen></iframe>`;
|
||||||
|
const htmlTemplate = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>${t(
|
||||||
|
"schedule_a_meeting"
|
||||||
|
)}</title><style>body {margin: 0;}iframe {height: calc(100vh - 4px);width: calc(100vw - 4px);box-sizing: border-box;}</style></head><body>${iframeTemplate}</body></html>`;
|
||||||
|
const handleErrors = async (resp: Response) => {
|
||||||
|
if (!resp.ok) {
|
||||||
|
const err = await resp.json();
|
||||||
|
throw new Error(err.message);
|
||||||
|
}
|
||||||
|
return resp.json();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getWebhooks = () => {
|
||||||
|
fetch("/api/webhook")
|
||||||
|
.then(handleErrors)
|
||||||
|
.then((data) => {
|
||||||
|
setWebhooks(
|
||||||
|
data.webhooks.map((webhook: Webhook) => {
|
||||||
|
return {
|
||||||
|
...webhook,
|
||||||
|
eventTriggers: webhook.eventTriggers.map((eventTrigger: string) => eventTrigger.toLowerCase()),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
console.log(data.webhooks);
|
||||||
|
})
|
||||||
|
.catch(console.log);
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createWebhook = () => {
|
||||||
|
setLoading(true);
|
||||||
|
fetch("/api/webhook", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
subscriberUrl: subUrlRef.current.value,
|
||||||
|
eventTriggers: webhookEventTrigger,
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(getWebhooks)
|
||||||
|
.catch(console.log);
|
||||||
|
};
|
||||||
|
|
||||||
|
const editWebhook = (webhook: Webhook) => {
|
||||||
|
setEditWebhookEnabled(true);
|
||||||
|
setWebhookToEdit(webhook);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCloseEdit = () => {
|
||||||
|
getWebhooks();
|
||||||
|
setEditWebhookEnabled(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <Loader />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!editWebhookEnabled && (
|
||||||
|
<>
|
||||||
|
<ShellSubHeading className="mt-10" title={t("Webhooks")} subtitle={t("receive_cal_meeting_data")} />
|
||||||
|
<List>
|
||||||
|
<ListItem className={classNames("flex-col")}>
|
||||||
|
<div className={classNames("flex flex-1 space-x-2 w-full p-3 items-center")}>
|
||||||
|
<Image width={40} height={40} src="/integrations/webhooks.svg" alt="Webhooks" />
|
||||||
|
<div className="flex-grow pl-2 truncate">
|
||||||
|
<ListItemTitle component="h3">Webhooks</ListItemTitle>
|
||||||
|
<ListItemText component="p">Automation</ListItemText>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Dialog>
|
||||||
|
<DialogTrigger>
|
||||||
|
<Button color="secondary">{t("new_webhook")}</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader
|
||||||
|
title={t("create_new_webhook")}
|
||||||
|
subtitle={t("create_new_webhook_to_account")}
|
||||||
|
/>
|
||||||
|
<div className="my-4">
|
||||||
|
<div className="mb-4">
|
||||||
|
<label htmlFor="subUrl" className="block text-sm font-medium text-gray-700">
|
||||||
|
{t("subscriber_url")}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
ref={subUrlRef}
|
||||||
|
type="text"
|
||||||
|
name="subUrl"
|
||||||
|
id="subUrl"
|
||||||
|
placeholder="https://example.com/sub"
|
||||||
|
required
|
||||||
|
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-sm shadow-sm focus:outline-none focus:ring-neutral-500 focus:border-neutral-500 sm:text-sm"
|
||||||
|
/>
|
||||||
|
<legend className="block pt-4 mb-2 text-sm font-medium text-gray-700">
|
||||||
|
{" "}
|
||||||
|
{t("event_triggers")}{" "}
|
||||||
|
</legend>
|
||||||
|
<div className="p-2 border border-gray-300 rounded-sm">
|
||||||
|
<div className="flex pb-4">
|
||||||
|
<div className="w-10/12">
|
||||||
|
<h2 className="font-medium text-gray-800">{t("booking_created")}</h2>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-center w-2/12 text-right">
|
||||||
|
<Switch
|
||||||
|
defaultChecked={true}
|
||||||
|
id="booking-created"
|
||||||
|
value={bookingCreated}
|
||||||
|
onCheckedChange={() => {
|
||||||
|
setBookingCreated(!bookingCreated);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex py-1">
|
||||||
|
<div className="w-10/12">
|
||||||
|
<h2 className="font-medium text-gray-800">{t("booking_rescheduled")}</h2>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-center w-2/12 text-right">
|
||||||
|
<Switch
|
||||||
|
defaultChecked={true}
|
||||||
|
id="booking-rescheduled"
|
||||||
|
value={bookingRescheduled}
|
||||||
|
onCheckedChange={() => {
|
||||||
|
setBookingRescheduled(!bookingRescheduled);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex pt-4">
|
||||||
|
<div className="w-10/12">
|
||||||
|
<h2 className="font-medium text-gray-800">{t("booking_cancelled")}</h2>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-center w-2/12 text-right">
|
||||||
|
<Switch
|
||||||
|
defaultChecked={true}
|
||||||
|
id="booking-cancelled"
|
||||||
|
value={bookingCancelled}
|
||||||
|
onCheckedChange={() => {
|
||||||
|
setBookingCancelled(!bookingCancelled);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="gap-2 mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
loading={isLoading}
|
||||||
|
onClick={createWebhook}
|
||||||
|
color="primary"
|
||||||
|
className="ml-2">
|
||||||
|
{t("create_webhook")}
|
||||||
|
</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button color="secondary">{t("cancel")}</Button>
|
||||||
|
</DialogClose>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<div className="divide-y divide-gray-200 lg:col-span-9">
|
||||||
|
<div className="py-6 lg:pb-8">
|
||||||
|
<div>
|
||||||
|
{!!webhooks.length && (
|
||||||
|
<WebhookList
|
||||||
|
webhooks={webhooks}
|
||||||
|
onChange={getWebhooks}
|
||||||
|
onEditWebhook={editWebhook}></WebhookList>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ShellSubHeading className="mt-10" title={t("iframe_embed")} subtitle={t("embed_calcom")} />
|
||||||
|
<div className="py-6 lg:pb-8 lg:col-span-9">
|
||||||
|
<div className="mb-6">
|
||||||
|
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal"></h2>
|
||||||
|
<p className="mt-1 text-sm text-gray-500"></p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 space-x-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="iframe" className="block text-sm font-medium text-gray-700">
|
||||||
|
{t("standard_iframe")}
|
||||||
|
</label>
|
||||||
|
<div className="mt-1">
|
||||||
|
<textarea
|
||||||
|
id="iframe"
|
||||||
|
className="block w-full h-32 border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-black sm:text-sm"
|
||||||
|
placeholder={t("loading")}
|
||||||
|
defaultValue={iframeTemplate}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="fullscreen" className="block text-sm font-medium text-gray-700">
|
||||||
|
{t("responsive_fullscreen_iframe")}
|
||||||
|
</label>
|
||||||
|
<div className="mt-1">
|
||||||
|
<textarea
|
||||||
|
id="fullscreen"
|
||||||
|
className="block w-full h-32 border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-black sm:text-sm"
|
||||||
|
placeholder={t("loading")}
|
||||||
|
defaultValue={htmlTemplate}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ShellSubHeading className="mt-10" title="Cal.com API" subtitle={t("leverage_our_api")} />
|
||||||
|
<a href="https://developer.cal.com/api" className="btn btn-primary">
|
||||||
|
{t("browse_api_documentation")}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{!!editWebhookEnabled && webhookToEdit && (
|
||||||
|
<EditWebhook webhook={webhookToEdit} onCloseEdit={onCloseEdit} />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -18,6 +18,8 @@ import Badge from "@components/ui/Badge";
|
||||||
import Button, { ButtonBaseProps } from "@components/ui/Button";
|
import Button, { ButtonBaseProps } from "@components/ui/Button";
|
||||||
import Switch from "@components/ui/Switch";
|
import Switch from "@components/ui/Switch";
|
||||||
|
|
||||||
|
import Embed from "./embed";
|
||||||
|
|
||||||
function pluralize(opts: { num: number; plural: string; singular: string }) {
|
function pluralize(opts: { num: number; plural: string; singular: string }) {
|
||||||
if (opts.num === 0) {
|
if (opts.num === 0) {
|
||||||
return opts.singular;
|
return opts.singular;
|
||||||
|
@ -425,6 +427,8 @@ export default function IntegrationsPage() {
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Embed />
|
||||||
</Shell>
|
</Shell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,285 +0,0 @@
|
||||||
import { PlusIcon } from "@heroicons/react/outline";
|
|
||||||
import { useSession } from "next-auth/client";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
|
|
||||||
import { useLocale } from "@lib/hooks/useLocale";
|
|
||||||
import { trpc } from "@lib/trpc";
|
|
||||||
import { Webhook } from "@lib/webhook";
|
|
||||||
|
|
||||||
import { Dialog, DialogClose, DialogContent, DialogHeader, DialogTrigger } from "@components/Dialog";
|
|
||||||
import Loader from "@components/Loader";
|
|
||||||
import SettingsShell from "@components/SettingsShell";
|
|
||||||
import Shell from "@components/Shell";
|
|
||||||
import Button from "@components/ui/Button";
|
|
||||||
import Switch from "@components/ui/Switch";
|
|
||||||
import EditWebhook from "@components/webhook/EditWebhook";
|
|
||||||
import WebhookList from "@components/webhook/WebhookList";
|
|
||||||
|
|
||||||
export default function Embed() {
|
|
||||||
const user = trpc.useQuery(["viewer.me"]).data;
|
|
||||||
const [, loading] = useSession();
|
|
||||||
const { t } = useLocale();
|
|
||||||
|
|
||||||
const [isLoading, setLoading] = useState(false);
|
|
||||||
const [bookingCreated, setBookingCreated] = useState(true);
|
|
||||||
const [bookingRescheduled, setBookingRescheduled] = useState(true);
|
|
||||||
const [bookingCancelled, setBookingCancelled] = useState(true);
|
|
||||||
const [editWebhookEnabled, setEditWebhookEnabled] = useState(false);
|
|
||||||
const [webhooks, setWebhooks] = useState([]);
|
|
||||||
const [webhookToEdit, setWebhookToEdit] = useState<Webhook | null>();
|
|
||||||
const [webhookEventTrigger, setWebhookEventTriggers] = useState([
|
|
||||||
"BOOKING_CREATED",
|
|
||||||
"BOOKING_RESCHEDULED",
|
|
||||||
"BOOKING_CANCELLED",
|
|
||||||
]);
|
|
||||||
|
|
||||||
const subUrlRef = useRef<HTMLInputElement>() as React.MutableRefObject<HTMLInputElement>;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const arr = [];
|
|
||||||
bookingCreated && arr.push("BOOKING_CREATED");
|
|
||||||
bookingRescheduled && arr.push("BOOKING_RESCHEDULED");
|
|
||||||
bookingCancelled && arr.push("BOOKING_CANCELLED");
|
|
||||||
setWebhookEventTriggers(arr);
|
|
||||||
}, [bookingCreated, bookingRescheduled, bookingCancelled]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getWebhooks();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const iframeTemplate = `<iframe src="${process.env.NEXT_PUBLIC_BASE_URL}/${user?.username}" frameborder="0" allowfullscreen></iframe>`;
|
|
||||||
const htmlTemplate = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>${t(
|
|
||||||
"schedule_a_meeting"
|
|
||||||
)}</title><style>body {margin: 0;}iframe {height: calc(100vh - 4px);width: calc(100vw - 4px);box-sizing: border-box;}</style></head><body>${iframeTemplate}</body></html>`;
|
|
||||||
const handleErrors = async (resp: Response) => {
|
|
||||||
if (!resp.ok) {
|
|
||||||
const err = await resp.json();
|
|
||||||
throw new Error(err.message);
|
|
||||||
}
|
|
||||||
return resp.json();
|
|
||||||
};
|
|
||||||
|
|
||||||
const getWebhooks = () => {
|
|
||||||
fetch("/api/webhook")
|
|
||||||
.then(handleErrors)
|
|
||||||
.then((data) => {
|
|
||||||
setWebhooks(
|
|
||||||
data.webhooks.map((webhook: Webhook) => {
|
|
||||||
return {
|
|
||||||
...webhook,
|
|
||||||
eventTriggers: webhook.eventTriggers.map((eventTrigger: string) => eventTrigger.toLowerCase()),
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
console.log(data.webhooks);
|
|
||||||
})
|
|
||||||
.catch(console.log);
|
|
||||||
setLoading(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createWebhook = () => {
|
|
||||||
setLoading(true);
|
|
||||||
fetch("/api/webhook", {
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({
|
|
||||||
subscriberUrl: subUrlRef.current.value,
|
|
||||||
eventTriggers: webhookEventTrigger,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(getWebhooks)
|
|
||||||
.catch(console.log);
|
|
||||||
};
|
|
||||||
|
|
||||||
const editWebhook = (webhook: Webhook) => {
|
|
||||||
setEditWebhookEnabled(true);
|
|
||||||
setWebhookToEdit(webhook);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCloseEdit = () => {
|
|
||||||
getWebhooks();
|
|
||||||
setEditWebhookEnabled(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return <Loader />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Shell heading={t("embed_and_webhooks")} subtitle={t("integrate_using_embed_or_webhooks")}>
|
|
||||||
<SettingsShell>
|
|
||||||
{!editWebhookEnabled && (
|
|
||||||
<div className="py-6 lg:pb-8 lg:col-span-9">
|
|
||||||
<div className="mb-6">
|
|
||||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">{t("iframe_embed")}</h2>
|
|
||||||
<p className="mt-1 text-sm text-gray-500">{t("embed_calcom")}</p>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-2 space-x-4">
|
|
||||||
<div>
|
|
||||||
<label htmlFor="iframe" className="block text-sm font-medium text-gray-700">
|
|
||||||
{t("standard_iframe")}
|
|
||||||
</label>
|
|
||||||
<div className="mt-1">
|
|
||||||
<textarea
|
|
||||||
id="iframe"
|
|
||||||
className="block w-full h-32 border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-black sm:text-sm"
|
|
||||||
placeholder={t("loading")}
|
|
||||||
defaultValue={iframeTemplate}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="fullscreen" className="block text-sm font-medium text-gray-700">
|
|
||||||
{t("responsive_fullscreen_iframe")}
|
|
||||||
</label>
|
|
||||||
<div className="mt-1">
|
|
||||||
<textarea
|
|
||||||
id="fullscreen"
|
|
||||||
className="block w-full h-32 border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-black sm:text-sm"
|
|
||||||
placeholder={t("loading")}
|
|
||||||
defaultValue={htmlTemplate}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr className="mt-8" />
|
|
||||||
<div className="flex justify-between my-6">
|
|
||||||
<div>
|
|
||||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">Webhooks</h2>
|
|
||||||
<p className="mt-1 text-sm text-gray-500">{t("receive_cal_meeting_data")} </p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Dialog>
|
|
||||||
<DialogTrigger className="px-4 py-2 my-6 text-sm font-medium text-white border border-transparent rounded-sm shadow-sm bg-neutral-900 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900">
|
|
||||||
<PlusIcon className="inline w-5 h-5 mr-1" />
|
|
||||||
{t("new_webhook")}
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent>
|
|
||||||
<DialogHeader
|
|
||||||
title={t("create_new_webhook")}
|
|
||||||
subtitle={t("create_new_webhook_to_account")}
|
|
||||||
/>
|
|
||||||
<div className="my-4">
|
|
||||||
<div className="mb-4">
|
|
||||||
<label htmlFor="subUrl" className="block text-sm font-medium text-gray-700">
|
|
||||||
{t("subscriber_url")}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
ref={subUrlRef}
|
|
||||||
type="text"
|
|
||||||
name="subUrl"
|
|
||||||
id="subUrl"
|
|
||||||
placeholder="https://example.com/sub"
|
|
||||||
required
|
|
||||||
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-sm shadow-sm focus:outline-none focus:ring-neutral-500 focus:border-neutral-500 sm:text-sm"
|
|
||||||
/>
|
|
||||||
<legend className="block pt-4 mb-2 text-sm font-medium text-gray-700">
|
|
||||||
{" "}
|
|
||||||
{t("event_triggers")}{" "}
|
|
||||||
</legend>
|
|
||||||
<div className="p-2 border border-gray-300 rounded-sm">
|
|
||||||
<div className="flex pb-4">
|
|
||||||
<div className="w-10/12">
|
|
||||||
<h2 className="font-medium text-gray-800">{t("booking_created")}</h2>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center justify-center w-2/12 text-right">
|
|
||||||
<Switch
|
|
||||||
defaultChecked={true}
|
|
||||||
id="booking-created"
|
|
||||||
value={bookingCreated}
|
|
||||||
onCheckedChange={() => {
|
|
||||||
setBookingCreated(!bookingCreated);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex py-1">
|
|
||||||
<div className="w-10/12">
|
|
||||||
<h2 className="font-medium text-gray-800">{t("booking_rescheduled")}</h2>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center justify-center w-2/12 text-right">
|
|
||||||
<Switch
|
|
||||||
defaultChecked={true}
|
|
||||||
id="booking-rescheduled"
|
|
||||||
value={bookingRescheduled}
|
|
||||||
onCheckedChange={() => {
|
|
||||||
setBookingRescheduled(!bookingRescheduled);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex pt-4">
|
|
||||||
<div className="w-10/12">
|
|
||||||
<h2 className="font-medium text-gray-800">{t("booking_cancelled")}</h2>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center justify-center w-2/12 text-right">
|
|
||||||
<Switch
|
|
||||||
defaultChecked={true}
|
|
||||||
id="booking-cancelled"
|
|
||||||
value={bookingCancelled}
|
|
||||||
onCheckedChange={() => {
|
|
||||||
setBookingCancelled(!bookingCancelled);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="gap-2 mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
|
||||||
<DialogClose asChild>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
loading={isLoading}
|
|
||||||
onClick={createWebhook}
|
|
||||||
color="primary"
|
|
||||||
className="ml-2">
|
|
||||||
{t("create_webhook")}
|
|
||||||
</Button>
|
|
||||||
</DialogClose>
|
|
||||||
<DialogClose asChild>
|
|
||||||
<Button color="secondary">{t("cancel")}</Button>
|
|
||||||
</DialogClose>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="divide-y divide-gray-200 lg:col-span-9">
|
|
||||||
<div className="py-6 lg:pb-8">
|
|
||||||
<div className="flex flex-col justify-between md:flex-row">
|
|
||||||
<div></div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{!!webhooks.length && (
|
|
||||||
<WebhookList
|
|
||||||
webhooks={webhooks}
|
|
||||||
onChange={getWebhooks}
|
|
||||||
onEditWebhook={editWebhook}></WebhookList>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr className="mt-8" />
|
|
||||||
<div className="my-6">
|
|
||||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">Cal.com API</h2>
|
|
||||||
<p className="mt-1 text-sm text-gray-500">{t("leverage_our_api")}</p>
|
|
||||||
</div>
|
|
||||||
<a href="https://developer.cal.com/api" className="btn btn-primary">
|
|
||||||
{t("browse_api_documentation")}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!!editWebhookEnabled && webhookToEdit && (
|
|
||||||
<EditWebhook webhook={webhookToEdit} onCloseEdit={onCloseEdit} />
|
|
||||||
)}
|
|
||||||
</SettingsShell>
|
|
||||||
</Shell>
|
|
||||||
);
|
|
||||||
}
|
|
1
public/integrations/webhooks.svg
Normal file
1
public/integrations/webhooks.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg width="2500" height="2334" viewBox="0 0 256 239" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><path d="M119.54 100.503c-10.61 17.836-20.775 35.108-31.152 52.25-2.665 4.401-3.984 7.986-1.855 13.58 5.878 15.454-2.414 30.493-17.998 34.575-14.697 3.851-29.016-5.808-31.932-21.543-2.584-13.927 8.224-27.58 23.58-29.757 1.286-.184 2.6-.205 4.762-.367l23.358-39.168C73.612 95.465 64.868 78.39 66.803 57.23c1.368-14.957 7.25-27.883 18-38.477 20.59-20.288 52.002-23.573 76.246-8.001 23.284 14.958 33.948 44.094 24.858 69.031-6.854-1.858-13.756-3.732-21.343-5.79 2.854-13.865.743-26.315-8.608-36.981-6.178-7.042-14.106-10.733-23.12-12.093-18.072-2.73-35.815 8.88-41.08 26.618-5.976 20.13 3.069 36.575 27.784 48.967z" fill="#C73A63"/><path d="M149.841 79.41c7.475 13.187 15.065 26.573 22.587 39.836 38.02-11.763 66.686 9.284 76.97 31.817 12.422 27.219 3.93 59.457-20.465 76.25-25.04 17.238-56.707 14.293-78.892-7.851 5.654-4.733 11.336-9.487 17.407-14.566 21.912 14.192 41.077 13.524 55.305-3.282 12.133-14.337 11.87-35.714-.615-49.75-14.408-16.197-33.707-16.691-57.035-1.143-9.677-17.168-19.522-34.199-28.893-51.491-3.16-5.828-6.648-9.21-13.77-10.443-11.893-2.062-19.571-12.275-20.032-23.717-.453-11.316 6.214-21.545 16.634-25.53 10.322-3.949 22.435-.762 29.378 8.014 5.674 7.17 7.477 15.24 4.491 24.083-.83 2.466-1.905 4.852-3.07 7.774z" fill="#4B4B4B"/><path d="M167.707 187.21h-45.77c-4.387 18.044-13.863 32.612-30.19 41.876-12.693 7.2-26.373 9.641-40.933 7.29-26.808-4.323-48.728-28.456-50.658-55.63-2.184-30.784 18.975-58.147 47.178-64.293 1.947 7.071 3.915 14.21 5.862 21.264-25.876 13.202-34.832 29.836-27.59 50.636 6.375 18.304 24.484 28.337 44.147 24.457 20.08-3.962 30.204-20.65 28.968-47.432 19.036 0 38.088-.197 57.126.097 7.434.117 13.173-.654 18.773-7.208 9.22-10.784 26.191-9.811 36.121.374 10.148 10.409 9.662 27.157-1.077 37.127-10.361 9.62-26.73 9.106-36.424-1.26-1.992-2.136-3.562-4.673-5.533-7.298z" fill="#4A4A4A"/></svg>
|
After Width: | Height: | Size: 1.9 KiB |
Loading…
Reference in a new issue