cal.pub0.org/apps/web/pages/team/[slug]/book.tsx

174 lines
5.4 KiB
TypeScript

import type { GetServerSidePropsContext } from "next";
import { z } from "zod";
import type { LocationObject } from "@calcom/app-store/locations";
import { privacyFilteredLocations } from "@calcom/app-store/locations";
import getBooking from "@calcom/features/bookings/lib/get-booking";
import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking";
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
import { parseRecurringEvent } from "@calcom/lib";
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
import prisma from "@calcom/prisma";
import { customInputSchema, eventTypeBookingFields, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { asStringOrNull, asStringOrThrow } from "@lib/asStringOrNull";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import BookingPage from "@components/booking/pages/BookingPage";
import { ssrInit } from "@server/lib/ssr";
export type TeamBookingPageProps = inferSSRProps<typeof getServerSideProps>;
export default function TeamBookingPage(props: TeamBookingPageProps) {
return <BookingPage {...props} />;
}
TeamBookingPage.isBookingPage = true;
TeamBookingPage.PageWrapper = PageWrapper;
const querySchema = z.object({
rescheduleUid: z.string().optional(),
bookingUid: z.string().optional(),
});
export async function getServerSideProps(context: GetServerSidePropsContext) {
const ssr = await ssrInit(context);
const eventTypeId = parseInt(asStringOrThrow(context.query.type));
const recurringEventCountQuery = asStringOrNull(context.query.count);
if (typeof eventTypeId !== "number" || eventTypeId % 1 !== 0) {
return {
notFound: true,
} as const;
}
const eventTypeRaw = await prisma.eventType.findUnique({
where: {
id: eventTypeId,
},
select: {
id: true,
title: true,
slug: true,
description: true,
length: true,
locations: true,
customInputs: true,
periodType: true,
periodDays: true,
periodStartDate: true,
periodEndDate: true,
periodCountCalendarDays: true,
recurringEvent: true,
requiresConfirmation: true,
disableGuests: true,
price: true,
currency: true,
metadata: true,
seatsPerTimeSlot: true,
schedulingType: true,
bookingFields: true,
successRedirectUrl: true,
workflows: {
include: {
workflow: {
include: {
steps: true,
},
},
},
},
team: {
select: {
slug: true,
name: true,
logo: true,
theme: true,
brandColor: true,
darkBrandColor: true,
parent: {
select: {
logo: true,
name: true,
},
},
},
},
users: {
select: {
id: true,
username: true,
avatar: true,
name: true,
},
},
},
});
if (!eventTypeRaw) return { notFound: true };
const eventType = {
...eventTypeRaw,
//TODO: Use zodSchema to verify it instead of using Type Assertion
locations: privacyFilteredLocations((eventTypeRaw.locations || []) as LocationObject[]),
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
bookingFields: eventTypeBookingFields.parse(eventTypeRaw.bookingFields || []),
};
const eventTypeObject = [eventType].map((e) => {
return {
...e,
metadata: EventTypeMetaDataSchema.parse(e.metadata || {}),
bookingFields: getBookingFieldsWithSystemFields(eventType),
periodStartDate: e.periodStartDate?.toString() ?? null,
periodEndDate: e.periodEndDate?.toString() ?? null,
customInputs: customInputSchema.array().parse(e.customInputs || []),
users: eventType.users.map((u) => ({
id: u.id,
name: u.name,
username: u.username,
avatar: u.avatar,
image: u.avatar,
slug: u.username,
})),
descriptionAsSafeHTML: markdownToSafeHTML(eventType.description),
};
})[0];
let booking: GetBookingType | null = null;
const { rescheduleUid, bookingUid } = querySchema.parse(context.query);
if (rescheduleUid || bookingUid) {
booking = await getBooking(prisma, rescheduleUid || bookingUid || "");
}
// Checking if number of recurring event ocurrances is valid against event type configuration
const recurringEventCount =
(eventType.recurringEvent?.count &&
recurringEventCountQuery &&
(parseInt(recurringEventCountQuery) <= eventType.recurringEvent.count
? parseInt(recurringEventCountQuery)
: eventType.recurringEvent.count)) ||
null;
return {
props: {
trpcState: ssr.dehydrate(),
profile: {
...eventTypeObject.team,
// FIXME: This slug is used as username on success page which is wrong. This is correctly set as username for user booking.
slug: "team/" + eventTypeObject.slug,
image: eventTypeObject.team?.logo || null,
eventName: null,
},
themeBasis: eventTypeObject.team?.slug,
eventType: eventTypeObject,
recurringEventCount,
booking,
currentSlotBooking: null,
isDynamicGroupBooking: false,
hasHashedBookingLink: false,
hashedLink: null,
isEmbed: typeof context.query.embed === "string",
},
};
}