perf: Remove me.get call in event-types / availability (#22336)

* perf: Event types page remove me.get call

* Update ts definition listing view

* fix type check

* get rid of me call from availability page

---------

Co-authored-by: hbjORbj <sldisek783@gmail.com>
This commit is contained in:
Alex van Andel
2025-07-12 06:49:29 +00:00
committed by GitHub
co-authored by hbjORbj
parent 8cd16ee3dc
commit bd5e14b488
7 changed files with 35 additions and 46 deletions
@@ -3,11 +3,15 @@ import type { PageProps, ReadonlyHeaders, ReadonlyRequestCookies } from "app/_ty
import { _generateMetadata, getTranslate } from "app/_utils";
import { unstable_cache } from "next/cache";
import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation";
import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { AvailabilitySliderTable } from "@calcom/features/timezone-buddy/components/AvailabilitySliderTable";
import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
import { availabilityRouter } from "@calcom/trpc/server/routers/viewer/availability/_router";
import { meRouter } from "@calcom/trpc/server/routers/viewer/me/_router";
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
import { AvailabilityList, AvailabilityCTA } from "~/availability/availability-view";
@@ -23,15 +27,6 @@ export const generateMetadata = async () => {
);
};
const getCachedMe = unstable_cache(
async (headers: ReadonlyHeaders, cookies: ReadonlyRequestCookies) => {
const meCaller = await createRouterCaller(meRouter, await getTRPCContext(headers, cookies));
return await meCaller.get();
},
["viewer.me.get"],
{ revalidate: 3600 } // Cache for 1 hour
);
const getCachedAvailabilities = unstable_cache(
async (headers: ReadonlyHeaders, cookies: ReadonlyRequestCookies) => {
const availabilityCaller = await createRouterCaller(
@@ -49,11 +44,12 @@ const Page = async ({ searchParams: _searchParams }: PageProps) => {
const t = await getTranslate();
const _headers = await headers();
const _cookies = await cookies();
const session = await getServerSession({ req: buildLegacyRequest(_headers, _cookies) });
if (!session?.user?.id) {
return redirect("/auth/login");
}
const [me, cachedAvailabilities] = await Promise.all([
getCachedMe(_headers, _cookies),
getCachedAvailabilities(_headers, _cookies),
]);
const cachedAvailabilities = await getCachedAvailabilities(_headers, _cookies);
// Transform the data to ensure startTime, endTime, and date are Date objects
// This is because the data is cached and as a result the data is converted to a string
@@ -70,13 +66,14 @@ const Page = async ({ searchParams: _searchParams }: PageProps) => {
})),
};
const organizationId = me.organization?.id ?? me.profiles[0]?.organizationId;
const organizationId = session?.user?.profile?.organizationId ?? session?.user.org?.id;
const isOrgPrivate = organizationId
? await OrganizationRepository.checkIfPrivate({
orgId: organizationId,
})
: false;
const canViewTeamAvailability = me.organization?.isOrgAdmin || !isOrgPrivate;
const isOrgAdminOrOwner = checkAdminOrOwner(session?.user?.org?.role);
const canViewTeamAvailability = isOrgAdminOrOwner || !isOrgPrivate;
return (
<ShellMainAppDir
@@ -91,9 +88,9 @@ const Page = async ({ searchParams: _searchParams }: PageProps) => {
/>
}>
{searchParams?.type === "team" && canViewTeamAvailability ? (
<AvailabilitySliderTable userTimeFormat={me?.timeFormat ?? null} isOrg={!!organizationId} />
<AvailabilitySliderTable isOrg={!!organizationId} />
) : (
<AvailabilityList availabilities={availabilities ?? { schedules: [] }} me={me} />
<AvailabilityList availabilities={availabilities ?? { schedules: [] }} />
)}
</ShellMainAppDir>
);
@@ -9,9 +9,8 @@ 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";
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
import EventTypes, { EventTypesCTA } from "~/event-types/views/event-types-listing-view";
@@ -24,15 +23,6 @@ export const generateMetadata = async () =>
"/event-types"
);
const getCachedMe = unstable_cache(
async (headers: ReadonlyHeaders, cookies: ReadonlyRequestCookies) => {
const meCaller = await createRouterCaller(meRouter, await getTRPCContext(headers, cookies));
return await meCaller.get();
},
["viewer.me.get"],
{ revalidate: 3600 } // seconds
);
const getCachedEventGroups = unstable_cache(
async (
headers: ReadonlyHeaders,
@@ -53,30 +43,26 @@ const getCachedEventGroups = unstable_cache(
{ revalidate: 3600 } // seconds
);
const Page = async ({ params, searchParams }: PageProps) => {
const Page = async ({ searchParams }: PageProps) => {
const _searchParams = await searchParams;
const _headers = await headers();
const _cookies = await cookies();
const context = buildLegacyCtx(_headers, _cookies, await params, _searchParams);
const session = await getServerSession({ req: context.req });
const session = await getServerSession({ req: buildLegacyRequest(_headers, _cookies) });
if (!session?.user?.id) {
redirect("/auth/login");
return redirect("/auth/login");
}
const t = await getTranslate();
const filters = getTeamsFiltersFromQuery(_searchParams);
const [me, userEventGroupsData] = await Promise.all([
getCachedMe(_headers, _cookies),
getCachedEventGroups(_headers, _cookies, filters),
]);
const userEventGroupsData = await getCachedEventGroups(_headers, _cookies, filters);
return (
<ShellMainAppDir
heading={t("event_types_page_title")}
subtitle={t("event_types_page_subtitle")}
CTA={<EventTypesCTA userEventGroupsData={userEventGroupsData} />}>
<EventTypes userEventGroupsData={userEventGroupsData} user={me} />
<EventTypes userEventGroupsData={userEventGroupsData} user={session.user} />
</ShellMainAppDir>
);
};
@@ -15,19 +15,20 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HttpError } from "@calcom/lib/http-error";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import { ToggleGroup } from "@calcom/ui/components/form";
import { showToast } from "@calcom/ui/components/toast";
type AvailabilityListProps = {
me: RouterOutputs["viewer"]["me"]["get"];
availabilities: RouterOutputs["viewer"]["availability"]["list"];
};
export function AvailabilityList({ availabilities, me }: AvailabilityListProps) {
export function AvailabilityList({ availabilities }: AvailabilityListProps) {
const { t } = useLocale();
const [bulkUpdateModal, setBulkUpdateModal] = useState(false);
const utils = trpc.useUtils();
const router = useRouter();
const { data: user } = useMeQuery();
const deleteMutation = trpc.viewer.availability.schedule.delete.useMutation({
onMutate: async ({ scheduleId }) => {
@@ -141,9 +142,9 @@ export function AvailabilityList({ availabilities, me }: AvailabilityListProps)
{availabilities.schedules.map((schedule) => (
<ScheduleListItem
displayOptions={{
hour12: me?.timeFormat ? me.timeFormat === 12 : undefined,
timeZone: me?.timeZone,
weekStart: me?.weekStart || "Sunday",
hour12: user?.timeFormat ? user.timeFormat === 12 : undefined,
timeZone: user?.timeZone,
weekStart: user?.weekStart || "Sunday",
}}
key={schedule.id}
schedule={schedule}
@@ -928,7 +928,10 @@ const InfiniteScrollMain = ({
type Props = {
userEventGroupsData: GetUserEventGroupsResponse;
user: RouterOutputs["viewer"]["me"]["get"];
user: {
id: number;
completedOnboarding?: boolean;
} | null;
};
export const EventTypesCTA = ({ userEventGroupsData }: Omit<Props, "user">) => {
@@ -96,6 +96,7 @@ export async function getServerSession(options: {
email: user.email,
emailVerified: user.emailVerified,
email_verified: user.emailVerified !== null,
completedOnboarding: user.completedOnboarding,
role: user.role,
image: getUserAvatarUrl({
avatarUrl: user.avatarUrl,
@@ -67,7 +67,7 @@ function UpgradeTeamTip() {
);
}
export function AvailabilitySliderTable(props: { userTimeFormat: number | null; isOrg: boolean }) {
export function AvailabilitySliderTable(props: { isOrg: boolean }) {
return (
<DataTableProvider>
<AvailabilitySliderTableContent {...props} />
@@ -75,7 +75,7 @@ export function AvailabilitySliderTable(props: { userTimeFormat: number | null;
);
}
function AvailabilitySliderTableContent(props: { userTimeFormat: number | null; isOrg: boolean }) {
function AvailabilitySliderTableContent(props: { isOrg: boolean }) {
const tableContainerRef = useRef<HTMLDivElement>(null);
const [browsingDate, setBrowsingDate] = useState(dayjs());
const [editSheetOpen, setEditSheetOpen] = useState(false);
+1
View File
@@ -20,6 +20,7 @@ declare module "next-auth" {
id: PrismaUser["id"];
emailVerified?: PrismaUser["emailVerified"];
email_verified?: boolean;
completedOnboarding?: boolean;
impersonatedBy?: {
id: number;
role: PrismaUser["role"];