diff --git a/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx index deb6762d32..d9a727318b 100644 --- a/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx @@ -25,7 +25,7 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { title, profile: { name: profileName, image: profileImage }, users: [ - ...(eventData?.users || []).map((user) => ({ + ...(eventData?.subsetOfUsers || []).map((user) => ({ name: `${user.name}`, username: `${user.username}`, })), diff --git a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx index c07628f4cc..7125f1a1d2 100644 --- a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx @@ -30,7 +30,11 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { title, profile: { name: profileName, image: profileImage }, users: [ - ...(eventData?.users || []).map((user) => ({ + ...( + (eventData as UserTypePageProps["eventData"])?.subsetOfUsers ?? + (eventData as TeamTypePageProps["eventData"])?.users ?? + [] + ).map((user) => ({ name: `${user.name}`, username: `${user.username}`, })), diff --git a/apps/web/modules/users/views/users-type-public-view.tsx b/apps/web/modules/users/views/users-type-public-view.tsx index 7104580858..197ae7be9e 100644 --- a/apps/web/modules/users/views/users-type-public-view.tsx +++ b/apps/web/modules/users/views/users-type-public-view.tsx @@ -35,6 +35,7 @@ function Type({ slug, user, isEmbed, booking, isBrandingHidden, eventData, orgBa eventSlug={slug} bookingData={booking} hideBranding={isBrandingHidden} + eventData={eventData} entity={{ ...eventData.entity, eventTypeId: eventData?.id }} durationConfig={eventData.metadata?.multipleDuration} orgBannerUrl={orgBannerUrl} diff --git a/apps/web/server/lib/[user]/[type]/getServerSideProps.ts b/apps/web/server/lib/[user]/[type]/getServerSideProps.ts index 18ee46682e..448a1be492 100644 --- a/apps/web/server/lib/[user]/[type]/getServerSideProps.ts +++ b/apps/web/server/lib/[user]/[type]/getServerSideProps.ts @@ -1,4 +1,3 @@ -import { createRouterCaller } from "app/_trpc/context"; import { type GetServerSidePropsContext } from "next"; import type { Session } from "next-auth"; import { z } from "zod"; @@ -9,33 +8,16 @@ import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking"; import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; import type { getPublicEvent } from "@calcom/features/eventtypes/lib/getPublicEvent"; import { getUsernameList } from "@calcom/lib/defaultEvents"; +import { EventRepository } from "@calcom/lib/server/repository/event"; import { UserRepository } from "@calcom/lib/server/repository/user"; import slugify from "@calcom/lib/slugify"; import prisma from "@calcom/prisma"; import { RedirectType } from "@calcom/prisma/client"; -import { publicViewerRouter } from "@calcom/trpc/server/routers/publicViewer/_router"; import { getTemporaryOrgRedirect } from "@lib/getTemporaryOrgRedirect"; type Props = { - eventData: Omit< - Pick< - NonNullable>>, - "id" | "length" | "metadata" | "entity" | "profile" | "title" | "subsetOfUsers" | "hidden" - >, - "profile" | "subsetOfUsers" - > & { - profile: { - image: string | undefined; - name: string | null; - username: string | null; - }; - users: { - username: string; - name: string; - }[]; - }; - + eventData: NonNullable>>; booking?: GetBookingType; rescheduleUid: string | null; bookingUid: string | null; @@ -144,13 +126,16 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { // We use this to both prefetch the query on the server, // as well as to check if the event exist, so we c an show a 404 otherwise. - const caller = await createRouterCaller(publicViewerRouter); - const eventData = await caller.event({ - username: usernames.join("+"), - eventSlug: slug, - org, - fromRedirectOfNonOrgLink: context.query.orgRedirection === "true", - }); + + const eventData = await EventRepository.getPublicEvent( + { + username: usernames.join("+"), + eventSlug: slug, + org, + fromRedirectOfNonOrgLink: context.query.orgRedirection === "true", + }, + session?.user?.id + ); if (!eventData) { return { @@ -160,24 +145,11 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { const props: Props = { eventData: { - id: eventData.id, - entity: eventData.entity, - length: eventData.length, + ...eventData, metadata: { ...eventData.metadata, multipleDuration: [15, 30, 45, 60, 90], }, - profile: { - image: eventData.profile.image, - name: eventData.profile.name ?? null, - username: eventData.profile.username ?? null, - }, - title: eventData.title, - users: eventData.subsetOfUsers.map((user) => ({ - username: user.username ?? "", - name: user.name ?? "", - })), - hidden: eventData.hidden, }, user: usernames.join("+"), slug, @@ -238,13 +210,15 @@ async function getUserPageProps(context: GetServerSidePropsContext) { const org = isValidOrgDomain ? currentOrgDomain : null; // We use this to both prefetch the query on the server, // as well as to check if the event exist, so we can show a 404 otherwise. - const caller = await createRouterCaller(publicViewerRouter); - const eventData = await caller.event({ - username, - eventSlug: slug, - org, - fromRedirectOfNonOrgLink: context.query.orgRedirection === "true", - }); + const eventData = await EventRepository.getPublicEvent( + { + username, + eventSlug: slug, + org, + fromRedirectOfNonOrgLink: context.query.orgRedirection === "true", + }, + session?.user?.id + ); if (!eventData) { return { @@ -259,23 +233,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) { : user?.allowSEOIndexing; const props: Props = { - eventData: { - id: eventData.id, - entity: eventData.entity, - length: eventData.length, - metadata: eventData.metadata, - profile: { - image: eventData.profile.image, - name: eventData.profile.name ?? null, - username: eventData.profile.username ?? null, - }, - title: eventData.title, - users: eventData.subsetOfUsers.map((user) => ({ - username: user.username ?? "", - name: user.name ?? "", - })), - hidden: eventData.hidden, - }, + eventData: eventData, user: username, slug, isBrandingHidden: user?.hideBranding, diff --git a/packages/features/bookings/Booker/components/hooks/useSlots.ts b/packages/features/bookings/Booker/components/hooks/useSlots.ts index aebb77c3bd..fa055aabba 100644 --- a/packages/features/bookings/Booker/components/hooks/useSlots.ts +++ b/packages/features/bookings/Booker/components/hooks/useSlots.ts @@ -5,7 +5,6 @@ import dayjs from "@calcom/dayjs"; import { useBookerStore } from "@calcom/features/bookings/Booker/store"; import { useSlotReservationId } from "@calcom/features/bookings/Booker/useSlotReservationId"; import { isBookingDryRun } from "@calcom/features/bookings/Booker/utils/isBookingDryRun"; -import type { BookerEvent } from "@calcom/features/bookings/types"; import { MINUTES_TO_BOOK, PUBLIC_QUERY_RESERVATION_INTERVAL_SECONDS, @@ -78,7 +77,7 @@ const useQuickAvailabilityChecks = ({ export type UseSlotsReturnType = ReturnType; -export const useSlots = (event: { data?: Pick | null }) => { +export const useSlots = (event: { id: number; length: number } | null) => { const selectedDuration = useBookerStore((state) => state.selectedDuration); const searchParams = useCompatSearchParams(); const [selectedTimeslot, setSelectedTimeslot, tentativeSelectedTimeslots, setTentativeSelectedTimeslots] = @@ -107,13 +106,13 @@ export const useSlots = (event: { data?: Pick | nu }); const handleRemoveSlot = () => { - if (event?.data) { + if (event?.id && slotReservationId) { removeSelectedSlot.mutate({ uid: slotReservationId }); } }; - const eventTypeId = event.data?.id; - const eventDuration = selectedDuration || event.data?.length || 0; + const eventTypeId = event?.id; + const eventDuration = selectedDuration || event?.length || 0; const allSelectedTimeslots = [...tentativeSelectedTimeslots, selectedTimeslot].filter( (slot): slot is string => slot !== null ); @@ -153,7 +152,7 @@ export const useSlots = (event: { data?: Pick | nu clearInterval(interval); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [event?.data?.id, timeSlotToBeBooked]); + }, [event?.id, timeSlotToBeBooked]); return { setSelectedTimeslot, diff --git a/packages/features/bookings/Booker/utils/event.ts b/packages/features/bookings/Booker/utils/event.ts index eea28b3b7b..97dd1e48d3 100644 --- a/packages/features/bookings/Booker/utils/event.ts +++ b/packages/features/bookings/Booker/utils/event.ts @@ -18,7 +18,7 @@ export type useScheduleForEventReturnType = ReturnType { +export const useEvent = (props?: { fromRedirectOfNonOrgLink?: boolean; disabled?: boolean }) => { const [username, eventSlug, isTeamEvent, org] = useBookerStore( (state) => [state.username, state.eventSlug, state.isTeamEvent, state.org], shallow @@ -34,7 +34,7 @@ export const useEvent = (props?: { fromRedirectOfNonOrgLink?: boolean }) => { }, { refetchOnWindowFocus: false, - enabled: Boolean(username) && Boolean(eventSlug), + enabled: !props?.disabled && Boolean(username) && Boolean(eventSlug), } ); diff --git a/packages/platform/atoms/booker/BookerWebWrapper.tsx b/packages/platform/atoms/booker/BookerWebWrapper.tsx index b70781b117..62b6b97d61 100644 --- a/packages/platform/atoms/booker/BookerWebWrapper.tsx +++ b/packages/platform/atoms/booker/BookerWebWrapper.tsx @@ -22,19 +22,32 @@ import { useBookerStore, useInitializeBookerStore } from "@calcom/features/booki import { useEvent, useScheduleForEvent } from "@calcom/features/bookings/Booker/utils/event"; import { getLastBookingResponse } from "@calcom/features/bookings/Booker/utils/lastBookingResponse"; import { useBrandColors } from "@calcom/features/bookings/Booker/utils/use-brand-colors"; +import type { getPublicEvent } from "@calcom/features/eventtypes/lib/getPublicEvent"; import { DEFAULT_LIGHT_BRAND_COLOR, DEFAULT_DARK_BRAND_COLOR, WEBAPP_URL } from "@calcom/lib/constants"; import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; import { BookerLayouts } from "@calcom/prisma/zod-utils"; -type BookerWebWrapperAtomProps = BookerProps; +type BookerWebWrapperAtomProps = BookerProps & { + eventData?: NonNullable>>; +}; export const BookerWebWrapper = (props: BookerWebWrapperAtomProps) => { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); - const event = useEvent({ + const clientFetchedEvent = useEvent({ + disabled: !!props.eventData, fromRedirectOfNonOrgLink: props.entity.fromRedirectOfNonOrgLink, }); + const event = props.eventData + ? { + data: props.eventData, + isSuccess: true, + isError: false, + isPending: false, + } + : clientFetchedEvent; + const bookerLayout = useBookerLayout(event.data); const selectedDate = searchParams?.get("date"); @@ -110,7 +123,7 @@ export const BookerWebWrapper = (props: BookerWebWrapperAtomProps) => { requiresBookerEmailVerification: event?.data?.requiresBookerEmailVerification, onVerifyEmail: bookerForm.beforeVerifyEmail, }); - const slots = useSlots(event); + const slots = useSlots(event?.data ? { id: event.data.id, length: event.data.length } : null); const isEmbed = useIsEmbed();