Skip to content

Commit

Permalink
chore: [app-router-migration 37] Fix Build Errors in /bookings and /b…
Browse files Browse the repository at this point in the history
…ooking (calcom#13313)
  • Loading branch information
hbjORbj authored Jan 18, 2024
1 parent 03671e2 commit 1976dd1
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 266 deletions.
4 changes: 3 additions & 1 deletion apps/web/app/future/booking/[uid]/embed/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import OldPage, { type PageProps, getServerSideProps } from "@pages/booking/[uid]";
import { type PageProps, getServerSideProps } from "@pages/booking/[uid]";
import OldPage from "@pages/booking/[uid]/embed";
import { withAppDirSsr } from "app/WithAppDirSsr";
import withEmbedSsrAppDir from "app/WithEmbedSSR";
import { WithLayout } from "app/layoutHOC";

const getData = withAppDirSsr<PageProps>(getServerSideProps);

const getEmbedData = withEmbedSsrAppDir(getData);

export default WithLayout({ getLayout: null, getData: getEmbedData, Page: OldPage });
226 changes: 29 additions & 197 deletions apps/web/app/future/booking/[uid]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,204 +1,36 @@
import OldPage from "@pages/booking/[uid]";
import OldPage, { type PageProps } from "@pages/booking/[uid]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { Params, SearchParams } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import type { GetServerSidePropsContext } from "next";
import { notFound } from "next/navigation";
import { z } from "zod";

import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { getBookingWithResponses } from "@calcom/features/bookings/lib/get-booking";
import { parseRecurringEvent } from "@calcom/lib";
import { getDefaultEvent } from "@calcom/lib/defaultEvents";
import { maybeGetBookingUidFromSeat } from "@calcom/lib/server/maybeGetBookingUidFromSeat";
import prisma from "@calcom/prisma";
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";

import { getRecurringBookings, handleSeatsEventTypeOnBooking, getEventTypesFromDB } from "@lib/booking";

import { ssrInit } from "@server/lib/ssr";

const stringToBoolean = z
.string()
.optional()
.transform((val) => val === "true");

const querySchema = z.object({
uid: z.string(),
email: z.string().optional(),
eventTypeSlug: z.string().optional(),
cancel: stringToBoolean,
allRemainingBookings: stringToBoolean,
changes: stringToBoolean,
reschedule: stringToBoolean,
isSuccessBookingPage: stringToBoolean,
formerTime: z.string().optional(),
seatReferenceUid: z.string().optional(),
});

export const generateMetadata = async () =>
await _generateMetadata(
() => "",
() => ""
import { type GetServerSidePropsContext } from "next";
import { cookies, headers } from "next/headers";

import { BookingStatus } from "@calcom/prisma/enums";

import { getServerSideProps } from "@lib/booking/[uid]/getServerSideProps";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";

export const generateMetadata = async ({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) => {
const { bookingInfo, eventType, recurringBookings } = await getData(
buildLegacyCtx(headers(), cookies(), params, searchParams) as unknown as GetServerSidePropsContext
);
const needsConfirmation = bookingInfo.status === BookingStatus.PENDING && eventType.requiresConfirmation;

const getData = async (context: GetServerSidePropsContext) => {
const ssr = await ssrInit(context);
const session = await getServerSession(context);
let tz: string | null = null;
let userTimeFormat: number | null = null;
let requiresLoginToUpdate = false;
if (session) {
const user = await ssr.viewer.me.fetch();
tz = user.timeZone;
userTimeFormat = user.timeFormat;
}

const parsedQuery = querySchema.safeParse(context.query);

if (!parsedQuery.success) {
notFound();
}

const { uid, eventTypeSlug, seatReferenceUid } = parsedQuery.data;

const { uid: maybeUid } = await maybeGetBookingUidFromSeat(prisma, uid);
const bookingInfoRaw = await prisma.booking.findFirst({
where: {
uid: maybeUid,
},
select: {
title: true,
id: true,
uid: true,
description: true,
customInputs: true,
smsReminderNumber: true,
recurringEventId: true,
startTime: true,
endTime: true,
location: true,
status: true,
metadata: true,
cancellationReason: true,
responses: true,
rejectionReason: true,
user: {
select: {
id: true,
name: true,
email: true,
username: true,
timeZone: true,
},
},
attendees: {
select: {
name: true,
email: true,
timeZone: true,
},
},
eventTypeId: true,
eventType: {
select: {
eventName: true,
slug: true,
timeZone: true,
},
},
seatsReferences: {
select: {
referenceUid: true,
},
},
},
});

if (!bookingInfoRaw) {
notFound();
}

const eventTypeRaw = !bookingInfoRaw.eventTypeId
? getDefaultEvent(eventTypeSlug || "")
: await getEventTypesFromDB(bookingInfoRaw.eventTypeId);
if (!eventTypeRaw) {
notFound();
}

if (eventTypeRaw.seatsPerTimeSlot && !seatReferenceUid && !session) {
requiresLoginToUpdate = true;
}

const bookingInfo = getBookingWithResponses(bookingInfoRaw);
// @NOTE: had to do this because Server side cant return [Object objects]
// probably fixable with json.stringify -> json.parse
bookingInfo["startTime"] = (bookingInfo?.startTime as Date)?.toISOString() as unknown as Date;
bookingInfo["endTime"] = (bookingInfo?.endTime as Date)?.toISOString() as unknown as Date;

eventTypeRaw.users = !!eventTypeRaw.hosts?.length
? eventTypeRaw.hosts.map((host) => host.user)
: eventTypeRaw.users;

if (!eventTypeRaw.users.length) {
if (!eventTypeRaw.owner) {
notFound();
}

eventTypeRaw.users.push({
...eventTypeRaw.owner,
});
}

const eventType = {
...eventTypeRaw,
periodStartDate: eventTypeRaw.periodStartDate?.toString() ?? null,
periodEndDate: eventTypeRaw.periodEndDate?.toString() ?? null,
metadata: EventTypeMetaDataSchema.parse(eventTypeRaw.metadata),
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
customInputs: customInputSchema.array().parse(eventTypeRaw.customInputs),
};

const profile = {
name: eventType.team?.name || eventType.users[0]?.name || null,
email: eventType.team ? null : eventType.users[0].email || null,
theme: (!eventType.team?.name && eventType.users[0]?.theme) || null,
brandColor: eventType.team ? null : eventType.users[0].brandColor || null,
darkBrandColor: eventType.team ? null : eventType.users[0].darkBrandColor || null,
slug: eventType.team?.slug || eventType.users[0]?.username || null,
};

if (bookingInfo !== null && eventType.seatsPerTimeSlot) {
await handleSeatsEventTypeOnBooking(eventType, bookingInfo, seatReferenceUid, session?.user.id);
}

const payment = await prisma.payment.findFirst({
where: {
bookingId: bookingInfo.id,
},
select: {
success: true,
refunded: true,
currency: true,
amount: true,
paymentOption: true,
},
});

return {
themeBasis: eventType.team ? eventType.team.slug : eventType.users[0]?.username,
hideBranding: eventType.team ? eventType.team.hideBranding : eventType.users[0].hideBranding,
profile,
eventType,
recurringBookings: await getRecurringBookings(bookingInfo.recurringEventId),
dehydratedState: ssr.dehydrate(),
dynamicEventName: bookingInfo?.eventType?.eventName || "",
bookingInfo,
paymentStatus: payment,
...(tz && { tz }),
userTimeFormat,
requiresLoginToUpdate,
};
return await _generateMetadata(
(t) =>
t(`booking_${needsConfirmation ? "submitted" : "confirmed"}${recurringBookings ? "_recurring" : ""}`),
(t) =>
t(`booking_${needsConfirmation ? "submitted" : "confirmed"}${recurringBookings ? "_recurring" : ""}`)
);
};

// @ts-expect-error Argument of type '{ req: { headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }; }' is not assignable to parameter of type 'GetServerSidePropsContext'.
const getData = withAppDirSsr<PageProps>(getServerSideProps);

export default WithLayout({ getLayout: null, getData, Page: OldPage });
45 changes: 0 additions & 45 deletions apps/web/app/future/bookings/[status]/layout.tsx

This file was deleted.

30 changes: 29 additions & 1 deletion apps/web/app/future/bookings/[status]/page.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,29 @@
export { default } from "@pages/bookings/[status]";
import Page from "@pages/bookings/[status]";
import { withAppDirSsg } from "app/WithAppDirSsg";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import type { InferGetStaticPropsType } from "next";

import { getLayout } from "@calcom/features/MainLayoutAppDir";
import { APP_NAME } from "@calcom/lib/constants";

import { getStaticProps } from "@lib/bookings/[status]/getStaticProps";

const validStatuses = ["upcoming", "recurring", "past", "cancelled", "unconfirmed"] as const;

type Y = InferGetStaticPropsType<typeof getStaticProps>;
const getData = withAppDirSsg<Y>(getStaticProps);

export const generateMetadata = async () =>
await _generateMetadata(
(t) => `${APP_NAME} | ${t("bookings")}`,
() => ""
);

export const generateStaticParams = async () => {
return validStatuses.map((status) => ({ status }));
};

export default WithLayout({ getLayout, getData, Page })<"P">;

export const dynamic = "force-static";
24 changes: 24 additions & 0 deletions apps/web/lib/bookings/[status]/getStaticProps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { type GetStaticProps } from "next";
import { z } from "zod";

import { ssgInit } from "@server/lib/ssg";

const validStatuses = ["upcoming", "recurring", "past", "cancelled", "unconfirmed"] as const;

const querySchema = z.object({
status: z.enum(validStatuses),
});

export const getStaticProps: GetStaticProps = async (ctx) => {
const params = querySchema.safeParse(ctx.params);
const ssg = await ssgInit(ctx);

if (!params.success) return { notFound: true };

return {
props: {
status: params.data.status,
trpcState: ssg.dehydrate(),
},
};
};
8 changes: 3 additions & 5 deletions apps/web/pages/booking/[uid].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ const useBrandColors = ({
useCalcomTheme(brandTheme);
};

type SuccessProps = inferSSRProps<typeof getServerSideProps>;

export default function Success(props: SuccessProps) {
export default function Success(props: PageProps) {
const { t } = useLocale();
const router = useRouter();
const routerQuery = useRouterQuery();
Expand Down Expand Up @@ -829,8 +827,8 @@ Success.isBookingPage = true;
Success.PageWrapper = PageWrapper;

type RecurringBookingsProps = {
eventType: SuccessProps["eventType"];
recurringBookings: SuccessProps["recurringBookings"];
eventType: PageProps["eventType"];
recurringBookings: PageProps["recurringBookings"];
date: dayjs.Dayjs;
duration: number | undefined;
is24h: boolean;
Expand Down
Loading

0 comments on commit 1976dd1

Please sign in to comment.