perf: SSR - /event-types and /event-types/[type] (#20952)
* add revalidation * ssr for event-types * wip * wip * fix types * fix skeleton * better error component * make skeleton better * no need to export * call revalidations early * remove revalidations if not needed * address comments * address
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
|
||||
export default function Error() {
|
||||
return <Alert severity="error" title="Something went wrong" />;
|
||||
const { t } = useLocale();
|
||||
return <Alert severity="error" title={t("something_went_wrong")} />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
|
||||
export async function revalidateEventTypesList() {
|
||||
revalidatePath("/event-types");
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
|
||||
export default function Error() {
|
||||
const { t } = useLocale();
|
||||
return <Alert severity="error" title={t("something_went_wrong")} />;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { EventTypesSkeleton } from "./skeleton";
|
||||
|
||||
export default function Loading() {
|
||||
return <EventTypesSkeleton />;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { redirect } from "next/navigation";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { getTeamsFiltersFromQuery } from "@calcom/features/filters/lib/getTeamsFiltersFromQuery";
|
||||
import { eventTypesRouter } from "@calcom/trpc/server/routers/viewer/eventTypes/_router";
|
||||
import { meRouter } from "@calcom/trpc/server/routers/viewer/me/_router";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
@@ -32,19 +33,27 @@ const Page = async ({ params, searchParams }: PageProps) => {
|
||||
}
|
||||
|
||||
const t = await getTranslate();
|
||||
|
||||
const caller = await createRouterCaller(eventTypesRouter);
|
||||
const filters = getTeamsFiltersFromQuery(_searchParams);
|
||||
const initialData = await caller.getUserEventGroups({ filters });
|
||||
|
||||
const [meCaller, eventTypesCaller] = await Promise.all([
|
||||
createRouterCaller(meRouter),
|
||||
createRouterCaller(eventTypesRouter),
|
||||
]);
|
||||
|
||||
const [me, userEventGroupsData] = await Promise.all([
|
||||
meCaller.get(),
|
||||
eventTypesCaller.getUserEventGroups({ filters }),
|
||||
]);
|
||||
|
||||
return (
|
||||
<ShellMainAppDir
|
||||
heading={t("event_types_page_title")}
|
||||
subtitle={t("event_types_page_subtitle")}
|
||||
CTA={<EventTypesCTA initialData={initialData} filters={filters} />}>
|
||||
<EventTypes initialData={initialData} filters={filters} />
|
||||
CTA={<EventTypesCTA userEventGroupsData={userEventGroupsData} />}>
|
||||
<EventTypes userEventGroupsData={userEventGroupsData} user={me} />
|
||||
</ShellMainAppDir>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
export const revalidate = 3600; // 1 hour in seconds
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import { ShellMainAppDir } from "app/(use-page-wrapper)/(main-nav)/ShellMainAppDir";
|
||||
|
||||
import { EventTypesSkeletonLoader } from "@calcom/features/eventtypes/components/SkeletonLoader";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
|
||||
export function EventTypesSkeleton() {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<ShellMainAppDir heading={t("event_types_page_title")} subtitle={t("event_types_page_subtitle")}>
|
||||
<EventTypesSkeletonLoader />
|
||||
</ShellMainAppDir>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
|
||||
export async function revalidateEventTypeEditPage(id: number) {
|
||||
revalidatePath(`/event-types/${id}`);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import Shell from "@calcom/features/shell/Shell";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
|
||||
export default function Error() {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<Shell>
|
||||
<Alert severity="error" title={t("something_went_wrong")} />
|
||||
</Shell>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { EventTypeEditPageSkeleton } from "./skeleton";
|
||||
|
||||
export default function Loading() {
|
||||
return <EventTypeEditPageSkeleton />;
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import type { PageProps as _PageProps } from "app/_types";
|
||||
import { createRouterCaller } from "app/_trpc/context";
|
||||
import type { PageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { cookies, headers } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { z } from "zod";
|
||||
|
||||
import { EventTypeRepository } from "@calcom/lib/server/repository/eventType";
|
||||
import { EventTypeWebWrapper } from "@calcom/atoms/event-types/wrappers/EventTypeWebWrapper";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { eventTypesRouter } from "@calcom/trpc/server/routers/viewer/eventTypes/_router";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
import { getServerSideProps } from "@lib/event-types/[type]/getServerSideProps";
|
||||
|
||||
import EventTypePageWrapper from "~/event-types/views/event-types-single-view";
|
||||
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
|
||||
|
||||
const querySchema = z.object({
|
||||
type: z
|
||||
@@ -19,36 +20,34 @@ const querySchema = z.object({
|
||||
.transform((val) => Number(val)),
|
||||
});
|
||||
|
||||
export const generateMetadata = async ({ params }: _PageProps) => {
|
||||
const parsed = querySchema.safeParse(await params);
|
||||
if (!parsed.success) {
|
||||
return await _generateMetadata(
|
||||
(t) => `${t("event_type")}`,
|
||||
() => "",
|
||||
undefined,
|
||||
undefined,
|
||||
"/event-types"
|
||||
);
|
||||
}
|
||||
|
||||
const data = await EventTypeRepository.findTitleById({
|
||||
id: parsed.data.type,
|
||||
});
|
||||
|
||||
export const generateMetadata = async () => {
|
||||
return await _generateMetadata(
|
||||
(t) => (data?.title ? `${data.title} | ${t("event_type")}` : `${t("event_type")}`),
|
||||
(t) => `${t("event_type")}`,
|
||||
() => "",
|
||||
undefined,
|
||||
undefined,
|
||||
`/event-types/${parsed.data.type}`
|
||||
"/event-types"
|
||||
);
|
||||
};
|
||||
|
||||
const ServerPage = async ({ params, searchParams }: _PageProps) => {
|
||||
const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams);
|
||||
const props = await getServerSideProps(legacyCtx);
|
||||
const ServerPage = async ({ params }: PageProps) => {
|
||||
const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
|
||||
if (!session?.user?.id) {
|
||||
return redirect("/auth/login");
|
||||
}
|
||||
|
||||
return <EventTypePageWrapper {...props} />;
|
||||
const parsed = querySchema.safeParse(await params);
|
||||
if (!parsed.success) {
|
||||
throw new Error("Invalid Event Type id");
|
||||
}
|
||||
const eventTypeId = parsed.data.type;
|
||||
const caller = await createRouterCaller(eventTypesRouter);
|
||||
const data = await caller.get({ id: eventTypeId });
|
||||
if (!data?.eventType) {
|
||||
throw new Error("This event type does not exist");
|
||||
}
|
||||
|
||||
return <EventTypeWebWrapper data={data} id={eventTypeId} />;
|
||||
};
|
||||
|
||||
export default ServerPage;
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
"use client";
|
||||
|
||||
import Shell from "@calcom/features/shell/Shell";
|
||||
import {
|
||||
SkeletonButton,
|
||||
SkeletonContainer,
|
||||
SkeletonText,
|
||||
SkeletonAvatar,
|
||||
} from "@calcom/ui/components/skeleton";
|
||||
|
||||
export const EventTypeEditPageSkeleton = () => {
|
||||
const backButtonSkeleton = (
|
||||
<div className="bg-default sticky top-0 z-10 mb-0 flex items-center py-2 md:mb-9 md:mt-0">
|
||||
<div className="rounded-md ltr:mr-2 rtl:ml-2">
|
||||
<SkeletonButton className="h-8 w-8 rounded-md" />
|
||||
</div>
|
||||
<div className="w-full truncate ltr:mr-4 rtl:ml-4 md:block">
|
||||
<SkeletonText className="h-8 w-48" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<SkeletonButton className="h-9 w-9 rounded-md" />
|
||||
<SkeletonButton className="h-9 w-9 rounded-md" />
|
||||
<div className="flex space-x-2 rtl:space-x-reverse">
|
||||
<SkeletonButton className="h-9 w-24 rounded-md" />
|
||||
<SkeletonButton className="h-9 w-24 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Shell subtitle={<SkeletonText className="hidden h-4 w-24" />} afterHeading={backButtonSkeleton}>
|
||||
<div className="flex flex-col xl:flex-row xl:space-x-6">
|
||||
<div className="hidden xl:block">
|
||||
<div className="primary-navigation w-64 flex-shrink-0">
|
||||
<div className="flex flex-col space-y-1">
|
||||
{/* Tab navigation items */}
|
||||
{Array.from({ length: 8 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="group flex w-64 flex-row items-center rounded-md px-3 py-[10px] text-sm font-medium leading-none">
|
||||
<div className="mr-3 h-4 w-4">
|
||||
<SkeletonAvatar className="h-4 w-4" />
|
||||
</div>
|
||||
<div className="flex w-full flex-col">
|
||||
<SkeletonText className="h-4 w-24" />
|
||||
<SkeletonText className="mt-1 h-3 w-16" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full ltr:mr-2 rtl:ml-2">
|
||||
<div className="bg-default border-subtle mt-4 rounded-md sm:mx-0 md:border md:p-6 xl:mt-0">
|
||||
<SkeletonContainer>
|
||||
<div className="mb-8">
|
||||
<SkeletonText className="h-8 w-full max-w-md" />
|
||||
</div>
|
||||
|
||||
<div className="mb-6 space-y-6">
|
||||
{/* Form fields */}
|
||||
<div className="flex flex-col space-y-2">
|
||||
<SkeletonText className="h-4 w-32" />
|
||||
<SkeletonText className="h-10 w-full" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-2">
|
||||
<SkeletonText className="h-4 w-40" />
|
||||
<div className="flex items-center">
|
||||
<SkeletonText className="h-10 w-full" />
|
||||
<SkeletonButton className="ml-2 h-10 w-10 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-2">
|
||||
<SkeletonText className="h-4 w-36" />
|
||||
<SkeletonText className="h-24 w-full" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-2">
|
||||
<SkeletonText className="h-4 w-28" />
|
||||
<div className="flex items-center">
|
||||
<SkeletonText className="h-10 w-full" />
|
||||
<SkeletonButton className="ml-2 h-10 w-10 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-2">
|
||||
<SkeletonText className="h-4 w-32" />
|
||||
<SkeletonText className="h-10 w-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end space-x-2">
|
||||
<SkeletonButton className="h-10 w-24 rounded-md" />
|
||||
<SkeletonButton className="h-10 w-24 rounded-md" />
|
||||
</div>
|
||||
</SkeletonContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Shell>
|
||||
);
|
||||
};
|
||||
+3
-1
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
|
||||
export default function Error() {
|
||||
return <Alert severity="error" title="Something went wrong" />;
|
||||
const { t } = useLocale();
|
||||
return <Alert severity="error" title={t("something_went_wrong")} />;
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
|
||||
export default function Error() {
|
||||
return <Alert severity="error" title="Something went wrong" />;
|
||||
const { t } = useLocale();
|
||||
return <Alert severity="error" title={t("something_went_wrong")} />;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
|
||||
export default function Error() {
|
||||
return <Alert severity="error" title="Something went wrong" />;
|
||||
const { t } = useLocale();
|
||||
return <Alert severity="error" title={t("something_went_wrong")} />;
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { createRouterCaller } from "app/_trpc/context";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { redirect, notFound } from "next/navigation";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import type { RouterOutputs } from "@calcom/trpc";
|
||||
import { eventTypesRouter } from "@calcom/trpc/server/routers/viewer/eventTypes/_router";
|
||||
|
||||
import { asStringOrThrow } from "@lib/asStringOrNull";
|
||||
|
||||
export type PageProps = {
|
||||
type: number;
|
||||
data: RouterOutputs["viewer"]["eventTypes"]["get"];
|
||||
};
|
||||
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const { req, query } = context;
|
||||
|
||||
const session = await getServerSession({ req });
|
||||
|
||||
const typeParam = parseInt(asStringOrThrow(query.type));
|
||||
|
||||
if (Number.isNaN(typeParam)) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return redirect("/auth/login");
|
||||
}
|
||||
const getEventTypeById = async (eventTypeId: number) => {
|
||||
const caller = await createRouterCaller(eventTypesRouter);
|
||||
|
||||
try {
|
||||
return await caller.get({ id: eventTypeId });
|
||||
} catch (e: unknown) {
|
||||
logger.error(safeStringify(e));
|
||||
// reject, user has no access to this event type.
|
||||
return null;
|
||||
}
|
||||
};
|
||||
const data = await getEventTypeById(typeParam);
|
||||
if (!data?.eventType) {
|
||||
return redirect("/event-types");
|
||||
}
|
||||
return {
|
||||
data,
|
||||
type: typeParam,
|
||||
};
|
||||
};
|
||||
@@ -14,10 +14,7 @@ import { EventTypeEmbedButton, EventTypeEmbedDialog } from "@calcom/features/emb
|
||||
import { EventTypeDescription } from "@calcom/features/eventtypes/components";
|
||||
import CreateEventTypeDialog from "@calcom/features/eventtypes/components/CreateEventTypeDialog";
|
||||
import { DuplicateDialog } from "@calcom/features/eventtypes/components/DuplicateDialog";
|
||||
import {
|
||||
InfiniteSkeletonLoader,
|
||||
EventTypesSkeletonLoader,
|
||||
} from "@calcom/features/eventtypes/components/SkeletonLoader";
|
||||
import { InfiniteSkeletonLoader } from "@calcom/features/eventtypes/components/SkeletonLoader";
|
||||
import { parseEventTypeColor } from "@calcom/lib";
|
||||
import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { useCopy } from "@calcom/lib/hooks/useCopy";
|
||||
@@ -32,7 +29,6 @@ import { SchedulingType } from "@calcom/prisma/enums";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
import { ArrowButton } from "@calcom/ui/components/arrow-button";
|
||||
import { UserAvatarGroup } from "@calcom/ui/components/avatar";
|
||||
import { Badge } from "@calcom/ui/components/badge";
|
||||
@@ -58,8 +54,6 @@ import { Skeleton } from "@calcom/ui/components/skeleton";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
|
||||
import useMeQuery from "@lib/hooks/useMeQuery";
|
||||
|
||||
import { TRPCClientError } from "@trpc/client";
|
||||
|
||||
type GetUserEventGroupsResponse = RouterOutputs["viewer"]["eventTypes"]["getUserEventGroups"];
|
||||
@@ -839,7 +833,6 @@ const CreateFirstEventTypeView = ({ slug, searchTerm }: { slug: string; searchTe
|
||||
|
||||
const CTA = ({
|
||||
profileOptions,
|
||||
isOrganization,
|
||||
}: {
|
||||
profileOptions: {
|
||||
teamId: number | null | undefined;
|
||||
@@ -848,7 +841,6 @@ const CTA = ({
|
||||
membershipRole: MembershipRole | null | undefined;
|
||||
slug: string | null;
|
||||
}[];
|
||||
isOrganization: boolean;
|
||||
}) => {
|
||||
const { t } = useLocale();
|
||||
|
||||
@@ -890,28 +882,16 @@ const EmptyEventTypeList = ({
|
||||
};
|
||||
|
||||
const InfiniteScrollMain = ({
|
||||
status,
|
||||
errorMessage,
|
||||
eventTypeGroups,
|
||||
profiles,
|
||||
}: {
|
||||
status: string;
|
||||
errorMessage?: string;
|
||||
eventTypeGroups: GetUserEventGroupsResponse["eventTypeGroups"] | undefined;
|
||||
profiles: GetUserEventGroupsResponse["profiles"] | undefined;
|
||||
eventTypeGroups: GetUserEventGroupsResponse["eventTypeGroups"];
|
||||
profiles: GetUserEventGroupsResponse["profiles"];
|
||||
}) => {
|
||||
const searchParams = useSearchParams();
|
||||
const { data } = useTypedQuery(querySchema);
|
||||
const orgBranding = useOrgBranding();
|
||||
|
||||
if (status === "error") {
|
||||
return <Alert severity="error" title="Something went wrong" message={errorMessage} />;
|
||||
}
|
||||
|
||||
if (!eventTypeGroups || !profiles || status === "pending") {
|
||||
return <EventTypesSkeletonLoader />;
|
||||
}
|
||||
|
||||
const tabs = eventTypeGroups.map((item) => ({
|
||||
name: item.profile.name ?? "",
|
||||
href: item.teamId ? `/event-types?teamId=${item.teamId}` : "/event-types",
|
||||
@@ -947,25 +927,13 @@ const InfiniteScrollMain = ({
|
||||
};
|
||||
|
||||
type Props = {
|
||||
initialData: RouterOutputs["viewer"]["eventTypes"]["getUserEventGroups"];
|
||||
filters?: { teamIds?: number[] | undefined; userIds?: number[] | undefined; upIds?: string[] | undefined };
|
||||
userEventGroupsData: GetUserEventGroupsResponse;
|
||||
user: RouterOutputs["viewer"]["me"]["get"];
|
||||
};
|
||||
|
||||
export const EventTypesCTA = ({ initialData, filters }: Props) => {
|
||||
const { data: user } = useMeQuery();
|
||||
const { data: userEventGroupsQuery } = trpc.viewer.eventTypes.getUserEventGroups.useQuery(
|
||||
filters && { filters },
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
gcTime: 1 * 60 * 60 * 1000,
|
||||
staleTime: 1 * 60 * 60 * 1000,
|
||||
}
|
||||
);
|
||||
|
||||
const getUserEventGroupsData = userEventGroupsQuery ?? initialData;
|
||||
|
||||
export const EventTypesCTA = ({ userEventGroupsData }: Omit<Props, "user">) => {
|
||||
const profileOptions =
|
||||
getUserEventGroupsData?.profiles
|
||||
userEventGroupsData?.profiles
|
||||
?.filter((profile) => !profile.readOnly)
|
||||
?.filter((profile) => !profile.eventTypesLockedByOrg)
|
||||
?.map((profile) => {
|
||||
@@ -978,28 +946,14 @@ export const EventTypesCTA = ({ initialData, filters }: Props) => {
|
||||
};
|
||||
}) ?? [];
|
||||
|
||||
return <CTA profileOptions={profileOptions} isOrganization={!!user?.organizationId} />;
|
||||
return <CTA profileOptions={profileOptions} />;
|
||||
};
|
||||
|
||||
const EventTypesPage = ({ initialData, filters }: Props) => {
|
||||
const { data: user } = useMeQuery();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const EventTypesPage = ({ userEventGroupsData, user }: Props) => {
|
||||
const [_showProfileBanner, setShowProfileBanner] = useState(false);
|
||||
const orgBranding = useOrgBranding();
|
||||
const router = useRouter();
|
||||
|
||||
// TODO: Maybe useSuspenseQuery to focus on success case only? Remember that it would crash the page when there is an error in query. Also, it won't support skeleton
|
||||
const {
|
||||
data: getUserEventGroupsData,
|
||||
status: getUserEventGroupsStatus,
|
||||
error: getUserEventGroupsStatusError,
|
||||
} = trpc.viewer.eventTypes.getUserEventGroups.useQuery(filters && { filters }, {
|
||||
refetchOnWindowFocus: false,
|
||||
gcTime: 1 * 60 * 60 * 1000,
|
||||
staleTime: 1 * 60 * 60 * 1000,
|
||||
initialData,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
* During signup, if the account already exists, we redirect the user to /event-types instead of onboarding.
|
||||
@@ -1019,10 +973,8 @@ const EventTypesPage = ({ initialData, filters }: Props) => {
|
||||
|
||||
return (
|
||||
<InfiniteScrollMain
|
||||
profiles={getUserEventGroupsData?.profiles}
|
||||
eventTypeGroups={getUserEventGroupsData?.eventTypeGroups}
|
||||
status={getUserEventGroupsStatus}
|
||||
errorMessage={getUserEventGroupsStatusError?.message}
|
||||
profiles={userEventGroupsData.profiles}
|
||||
eventTypeGroups={userEventGroupsData.eventTypeGroups}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { EventTypeWebWrapper as EventType } from "@calcom/atoms/event-types/wrappers/EventTypeWebWrapper";
|
||||
|
||||
import type { PageProps } from "@lib/event-types/[type]/getServerSideProps";
|
||||
|
||||
const EventTypePageWrapper = ({ type, data }: PageProps) => {
|
||||
return <EventType data={data} id={type} />;
|
||||
};
|
||||
|
||||
export default EventTypePageWrapper;
|
||||
@@ -123,8 +123,8 @@ const ProfileView = () => {
|
||||
|
||||
const deleteTeamMutation = trpc.viewer.teams.delete.useMutation({
|
||||
async onSuccess() {
|
||||
await utils.viewer.teams.list.invalidate();
|
||||
revalidateTeamsList();
|
||||
await utils.viewer.teams.list.invalidate();
|
||||
await utils.viewer.eventTypes.getUserEventGroups.invalidate();
|
||||
await utils.viewer.eventTypes.getByViewer.invalidate();
|
||||
showToast(t("your_team_disbanded_successfully"), "success");
|
||||
|
||||
@@ -34,11 +34,11 @@ export function InfiniteSkeletonLoader() {
|
||||
);
|
||||
}
|
||||
|
||||
export function TabsSkeletonLoader() {
|
||||
function TabsSkeletonLoader() {
|
||||
return (
|
||||
<div className="mb-4 max-w-full lg:mb-5">
|
||||
<div className="mb-2.5 max-w-full">
|
||||
<nav className="no-scrollbar flex space-x-0.5 overflow-x-scroll rounded-md">
|
||||
<div className="bg-subtle inline-flex h-fit items-center justify-center whitespace-nowrap rounded-md p-2">
|
||||
<div className="bg-subtle inline-flex h-fit items-center justify-center whitespace-nowrap rounded-md p-1">
|
||||
<SkeletonAvatar className="mb-1 mr-1 h-4 w-4 rounded-full" />
|
||||
<SkeletonText className="h-4 w-16" />
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,7 @@ import { Button } from "@calcom/ui/components/button";
|
||||
import { DialogContent } from "@calcom/ui/components/dialog";
|
||||
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { revalidateEventTypeEditPage } from "@calcom/web/app/(use-page-wrapper)/event-types/[type]/actions";
|
||||
|
||||
export const EventWebhooksTab = ({ eventType }: Pick<EventTypeSetupProps, "eventType">) => {
|
||||
const { t } = useLocale();
|
||||
@@ -40,6 +41,7 @@ export const EventWebhooksTab = ({ eventType }: Pick<EventTypeSetupProps, "event
|
||||
const editWebhookMutation = trpc.viewer.webhook.edit.useMutation({
|
||||
async onSuccess() {
|
||||
setEditModalOpen(false);
|
||||
revalidateEventTypeEditPage(eventType.id);
|
||||
showToast(t("webhook_updated_successfully"), "success");
|
||||
await utils.viewer.webhook.list.invalidate();
|
||||
await utils.viewer.eventTypes.get.invalidate();
|
||||
@@ -52,6 +54,7 @@ export const EventWebhooksTab = ({ eventType }: Pick<EventTypeSetupProps, "event
|
||||
const createWebhookMutation = trpc.viewer.webhook.create.useMutation({
|
||||
async onSuccess() {
|
||||
setCreateModalOpen(false);
|
||||
revalidateEventTypeEditPage(eventType.id);
|
||||
showToast(t("webhook_created_successfully"), "success");
|
||||
await utils.viewer.webhook.list.invalidate();
|
||||
await utils.viewer.eventTypes.get.invalidate();
|
||||
|
||||
@@ -23,6 +23,7 @@ import { Switch } from "@calcom/ui/components/form";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
import { revalidateEventTypeEditPage } from "@calcom/web/app/(use-page-wrapper)/event-types/[type]/actions";
|
||||
|
||||
type PartialWorkflowType = Pick<WorkflowType, "name" | "activeOn" | "isOrg" | "steps" | "id" | "readOnly">;
|
||||
|
||||
@@ -54,6 +55,7 @@ const WorkflowListItem = (props: ItemProps) => {
|
||||
const activateEventTypeMutation = trpc.viewer.workflows.activateEventType.useMutation({
|
||||
onSuccess: async () => {
|
||||
const offOn = isActive ? "off" : "on";
|
||||
revalidateEventTypeEditPage(eventType.id);
|
||||
await utils.viewer.workflows.getAllActiveWorkflows.invalidate();
|
||||
|
||||
await utils.viewer.eventTypes.get.invalidate({ id: eventType.id });
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { Switch } from "@calcom/ui/components/form";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
import { revalidateEventTypeEditPage } from "@calcom/web/app/(use-page-wrapper)/event-types/[type]/actions";
|
||||
|
||||
type WebhookProps = {
|
||||
id: string;
|
||||
@@ -41,6 +42,7 @@ export default function EventTypeWebhookListItem(props: {
|
||||
|
||||
const deleteWebhook = trpc.viewer.webhook.delete.useMutation({
|
||||
async onSuccess() {
|
||||
if (webhook.eventTypeId) revalidateEventTypeEditPage(webhook.eventTypeId);
|
||||
showToast(t("webhook_removed_successfully"), "success");
|
||||
await utils.viewer.webhook.getByViewer.invalidate();
|
||||
await utils.viewer.webhook.list.invalidate();
|
||||
@@ -49,6 +51,7 @@ export default function EventTypeWebhookListItem(props: {
|
||||
});
|
||||
const toggleWebhook = trpc.viewer.webhook.edit.useMutation({
|
||||
async onSuccess(data) {
|
||||
if (webhook.eventTypeId) revalidateEventTypeEditPage(webhook.eventTypeId);
|
||||
// TODO: Better success message
|
||||
showToast(t(data?.active ? "enabled" : "disabled"), "success");
|
||||
await utils.viewer.webhook.getByViewer.invalidate();
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { Switch } from "@calcom/ui/components/form";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
import { revalidateEventTypeEditPage } from "@calcom/web/app/(use-page-wrapper)/event-types/[type]/actions";
|
||||
import { revalidateWebhooksList } from "@calcom/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/webhooks/(with-loader)/actions";
|
||||
|
||||
type WebhookProps = {
|
||||
@@ -44,21 +45,23 @@ export default function WebhookListItem(props: {
|
||||
|
||||
const deleteWebhook = trpc.viewer.webhook.delete.useMutation({
|
||||
async onSuccess() {
|
||||
if (webhook.eventTypeId) revalidateEventTypeEditPage(webhook.eventTypeId);
|
||||
revalidateWebhooksList();
|
||||
showToast(t("webhook_removed_successfully"), "success");
|
||||
await utils.viewer.webhook.getByViewer.invalidate();
|
||||
await utils.viewer.webhook.list.invalidate();
|
||||
await utils.viewer.eventTypes.get.invalidate();
|
||||
revalidateWebhooksList();
|
||||
},
|
||||
});
|
||||
const toggleWebhook = trpc.viewer.webhook.edit.useMutation({
|
||||
async onSuccess(data) {
|
||||
if (webhook.eventTypeId) revalidateEventTypeEditPage(webhook.eventTypeId);
|
||||
revalidateWebhooksList();
|
||||
// TODO: Better success message
|
||||
showToast(t(data?.active ? "enabled" : "disabled"), "success");
|
||||
await utils.viewer.webhook.getByViewer.invalidate();
|
||||
await utils.viewer.webhook.list.invalidate();
|
||||
await utils.viewer.eventTypes.get.invalidate();
|
||||
revalidateWebhooksList();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import { trpc } from "@calcom/trpc/react";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { revalidateEventTypeEditPage } from "@calcom/web/app/(use-page-wrapper)/event-types/[type]/actions";
|
||||
|
||||
import { TRPCClientError } from "@trpc/react-query";
|
||||
|
||||
@@ -91,8 +92,15 @@ export type EventTypeWebWrapperProps = {
|
||||
data: RouterOutputs["viewer"]["eventTypes"]["get"];
|
||||
};
|
||||
|
||||
export const EventTypeWebWrapper = ({ id, data }: EventTypeWebWrapperProps) => {
|
||||
const { data: eventTypeQueryData } = trpc.viewer.eventTypes.get.useQuery({ id }, { initialData: data });
|
||||
export const EventTypeWebWrapper = ({ id, data: serverFetchedData }: EventTypeWebWrapperProps) => {
|
||||
const { data: eventTypeQueryData } = trpc.viewer.eventTypes.get.useQuery(
|
||||
{ id },
|
||||
{ enabled: !serverFetchedData }
|
||||
);
|
||||
|
||||
if (serverFetchedData) {
|
||||
return <EventTypeWeb {...serverFetchedData} id={id} />;
|
||||
}
|
||||
|
||||
if (!eventTypeQueryData) return null;
|
||||
|
||||
@@ -129,7 +137,7 @@ const EventTypeWeb = ({ id, ...rest }: EventTypeSetupProps & { id: number }) =>
|
||||
|
||||
// Reset the form with these values as new default values to ensure the correct comparison for dirtyFields eval
|
||||
form.reset(currentValues);
|
||||
|
||||
revalidateEventTypeEditPage(eventType.id);
|
||||
showToast(t("event_type_updated_successfully", { eventTypeTitle: eventType.title }), "success");
|
||||
},
|
||||
async onSettled() {
|
||||
|
||||
Reference in New Issue
Block a user