perf: Fetch data server-side for Webhook Create page (#20675)

* perf: fetch data server-side for create webhooks page

* refactor

* refactor

* refactor

* improve skeleton styling

* fix styling
This commit is contained in:
Benny Joo
2025-04-16 10:59:18 -03:00
committed by GitHub
parent 9bc703a437
commit 5972a6f77f
8 changed files with 100 additions and 91 deletions
@@ -1,14 +1,5 @@
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { SkeletonLoader } from "@calcom/features/webhooks/pages/webhooks-view";
import { SkeletonLoader } from "@calcom/features/webhooks/pages/webhooks-skeleton";
export default function Loading() {
return (
<SettingsHeader
title="Webhooks"
description="Receive meeting data in real-time when something happens in Cal.com"
borderInShellHeader={true}
CTA={null}>
<SkeletonLoader />
</SettingsHeader>
);
return <SkeletonLoader />;
}
@@ -1,11 +1,9 @@
import { createRouterCaller } from "app/_trpc/context";
import { _generateMetadata, getTranslate } from "app/_utils";
import { _generateMetadata } from "app/_utils";
import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { CreateNewWebhookButton } from "@calcom/features/webhooks/components";
import WebhooksView from "@calcom/features/webhooks/pages/webhooks-view";
import { APP_NAME } from "@calcom/lib/constants";
import { UserPermissionRole } from "@calcom/prisma/enums";
@@ -25,20 +23,11 @@ const WebhooksViewServerWrapper = async () => {
redirect("/auth/login");
}
const t = await getTranslate();
const isAdmin = session.user.role === UserPermissionRole.ADMIN;
const caller = await createRouterCaller(webhookRouter);
const data = await caller.getByViewer();
return (
<SettingsHeader
title={t("webhooks")}
description={t("add_webhook_description", { appName: APP_NAME })}
CTA={data && data.webhookGroups.length > 0 ? <CreateNewWebhookButton isAdmin={isAdmin} /> : null}
borderInShellHeader={(data && data.profiles.length === 1) || !data?.webhookGroups?.length}>
<WebhooksView data={data} isAdmin={isAdmin} />
</SettingsHeader>
);
return <WebhooksView data={data} isAdmin={isAdmin} />;
};
export default WebhooksViewServerWrapper;
@@ -0,0 +1,5 @@
import { SkeletonLoader } from "@calcom/features/webhooks/pages/webhook-new-skeleton";
export default function Loading() {
return <SkeletonLoader />;
}
@@ -1,9 +1,10 @@
import { getTranslate, _generateMetadata } from "app/_utils";
import { Suspense } from "react";
import { createRouterCaller } from "app/_trpc/context";
import { _generateMetadata } from "app/_utils";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { NewWebhookView, SkeletonLoader } from "@calcom/features/webhooks/pages/webhook-new-view";
import { NewWebhookView } from "@calcom/features/webhooks/pages/webhook-new-view";
import { APP_NAME } from "@calcom/lib/constants";
import { appsRouter } from "@calcom/trpc/server/routers/viewer/apps/_router";
import { webhookRouter } from "@calcom/trpc/server/routers/viewer/webhook/_router";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -12,19 +13,17 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const t = await getTranslate();
const [appsCaller, webhookCaller] = await Promise.all([
createRouterCaller(appsRouter),
createRouterCaller(webhookRouter),
]);
return (
<SettingsHeader
title={t("add_webhook")}
description={t("add_webhook_description", { appName: APP_NAME })}
borderInShellHeader={true}
backButton>
<Suspense fallback={<SkeletonLoader />}>
<NewWebhookView />
</Suspense>
</SettingsHeader>
);
const [installedApps, webhooks] = await Promise.all([
appsCaller.integrations({ variant: "other", onlyInstalled: true }),
webhookCaller.list(),
]);
return <NewWebhookView webhooks={webhooks} installedApps={installedApps} />;
};
export default Page;
@@ -0,0 +1,24 @@
"use client";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { APP_NAME } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { SkeletonText, SkeletonContainer } from "@calcom/ui/components/skeleton";
export const SkeletonLoader = () => {
const { t } = useLocale();
return (
<SettingsHeader
title={t("add_webhook")}
description={t("add_webhook_description", { appName: APP_NAME })}
borderInShellHeader={true}
backButton={true}>
<SkeletonContainer>
<div className="divide-subtle border-subtle space-y-6 rounded-b-lg border border-t-0 px-6 py-4">
<SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" />
</div>
</SkeletonContainer>
</SettingsHeader>
);
};
@@ -3,10 +3,12 @@
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { APP_NAME } from "@calcom/lib/constants";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { SkeletonText, SkeletonContainer } from "@calcom/ui/components/skeleton";
import type { RouterOutputs } from "@calcom/trpc/react";
import { showToast } from "@calcom/ui/components/toast";
import { revalidateWebhooksList } from "@calcom/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/webhooks/(with-loader)/actions";
@@ -14,18 +16,12 @@ import type { WebhookFormSubmitData } from "../components/WebhookForm";
import WebhookForm from "../components/WebhookForm";
import { subscriberUrlReserved } from "../lib/subscriberUrlReserved";
export const SkeletonLoader = () => {
return (
<SkeletonContainer>
<div className="divide-subtle border-subtle space-y-6 rounded-b-lg border border-t-0 px-6 py-4">
<SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" />
</div>
</SkeletonContainer>
);
type Props = {
webhooks: RouterOutputs["viewer"]["webhook"]["list"];
installedApps: RouterOutputs["viewer"]["apps"]["integrations"];
};
export const NewWebhookView = () => {
export const NewWebhookView = ({ webhooks, installedApps }: Props) => {
const searchParams = useCompatSearchParams();
const { t } = useLocale();
const utils = trpc.useUtils();
@@ -35,18 +31,6 @@ export const NewWebhookView = () => {
const teamId = searchParams?.get("teamId") ? Number(searchParams.get("teamId")) : undefined;
const platform = searchParams?.get("platform") ? Boolean(searchParams.get("platform")) : false;
const { data: installedApps, isPending } = trpc.viewer.apps.integrations.useQuery(
{ variant: "other", onlyInstalled: true },
{
suspense: true,
enabled: session.status === "authenticated",
}
);
const { data: webhooks } = trpc.viewer.webhook.list.useQuery(undefined, {
suspense: true,
enabled: session.status === "authenticated",
});
const createWebhookMutation = trpc.viewer.webhook.create.useMutation({
async onSuccess() {
showToast(t("webhook_created_successfully"), "success");
@@ -91,14 +75,18 @@ export const NewWebhookView = () => {
});
};
if (isPending) return null;
return (
<WebhookForm
noRoutingFormTriggers={false}
onSubmit={onCreateWebhook}
apps={installedApps?.items.map((app) => app.slug)}
/>
<SettingsHeader
title={t("add_webhook")}
description={t("add_webhook_description", { appName: APP_NAME })}
borderInShellHeader={true}
backButton={true}>
<WebhookForm
noRoutingFormTriggers={false}
onSubmit={onCreateWebhook}
apps={installedApps?.items.map((app) => app.slug)}
/>
</SettingsHeader>
);
};
@@ -0,0 +1,24 @@
"use client";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { APP_NAME } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { SkeletonText, SkeletonContainer } from "@calcom/ui/components/skeleton";
export const SkeletonLoader = () => {
const { t } = useLocale();
return (
<SettingsHeader
title={t("webhooks")}
description={t("add_webhook_description", { appName: APP_NAME })}
borderInShellHeader={false}
CTA={null}>
<SkeletonContainer>
<div className="divide-subtle border-subtle mt-6 space-y-6 rounded-lg border px-6 py-4">
<SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" />
</div>
</SkeletonContainer>
</SettingsHeader>
);
};
@@ -2,6 +2,7 @@
import { useRouter } from "next/navigation";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants";
import { useBookerUrl } from "@calcom/lib/hooks/useBookerUrl";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -10,21 +11,9 @@ import type { WebhooksByViewer } from "@calcom/trpc/server/routers/viewer/webhoo
import classNames from "@calcom/ui/classNames";
import { Avatar } from "@calcom/ui/components/avatar";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import { SkeletonText, SkeletonContainer } from "@calcom/ui/components/skeleton";
import { WebhookListItem, CreateNewWebhookButton } from "../components";
export const SkeletonLoader = () => {
return (
<SkeletonContainer>
<div className="divide-subtle border-subtle space-y-6 rounded-b-lg border border-t-0 px-6 py-4">
<SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" />
</div>
</SkeletonContainer>
);
};
type Props = {
data: RouterOutputs["viewer"]["webhook"]["getByViewer"];
isAdmin: boolean;
@@ -53,9 +42,13 @@ const WebhooksList = ({
const hasTeams = profiles && profiles.length > 1;
return (
<>
<SettingsHeader
title={t("webhooks")}
description={t("add_webhook_description", { appName: APP_NAME })}
CTA={webhooksByViewer.webhookGroups.length > 0 ? <CreateNewWebhookButton isAdmin={isAdmin} /> : null}
borderInShellHeader={false}>
{!!webhookGroups.length ? (
<div className={classNames("mt-0", hasTeams && "mt-6")}>
<div className={classNames("mt-6")}>
{webhookGroups.map((group) => (
<div key={group.teamId}>
{hasTeams && (
@@ -72,11 +65,7 @@ const WebhooksList = ({
</div>
)}
<div className="flex flex-col" key={group.profile.slug}>
<div
className={classNames(
"border-subtle rounded-lg rounded-t-none border border-t-0",
hasTeams && "mb-8 mt-3 rounded-t-lg border-t"
)}>
<div className={classNames("border-subtle mb-8 mt-3 rounded-lg border border-t")}>
{group.webhooks.map((webhook, index) => (
<WebhookListItem
key={webhook.id}
@@ -98,12 +87,12 @@ const WebhooksList = ({
Icon="link"
headline={t("create_your_first_webhook")}
description={t("create_your_first_webhook_description", { appName: APP_NAME })}
className="rounded-b-lg rounded-t-none border-t-0"
className="mt-6 rounded-b-lg"
buttonRaw={<CreateNewWebhookButton isAdmin={isAdmin} />}
border={true}
/>
)}
</>
</SettingsHeader>
);
};