chore: [app-router-migration 15] migrate bookings/* page group (#13038)
* codemod: remove-get-static-props * replace ssrInit * manual: extract getServerSideProps into a file * manual: Export getServerSideProps from legacy page --------- Co-authored-by: Benny Joo <sldisek783@gmail.com>
This commit is contained in:
parent
bc6267e99b
commit
684575d0a4
|
@ -0,0 +1,57 @@
|
||||||
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
import { isNotFoundError } from "next/dist/client/components/not-found";
|
||||||
|
import { getURLFromRedirectError, isRedirectError } from "next/dist/client/components/redirect";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
|
||||||
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
|
||||||
|
export type EmbedProps = {
|
||||||
|
isEmbed?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function withEmbedSsrAppDir<T extends Record<string, any>>(
|
||||||
|
getData: (context: GetServerSidePropsContext) => Promise<T>
|
||||||
|
) {
|
||||||
|
return async (context: GetServerSidePropsContext): Promise<T> => {
|
||||||
|
const { embed, layout } = context.query;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const props = await getData(context);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...props,
|
||||||
|
isEmbed: true,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
if (isRedirectError(e)) {
|
||||||
|
const destinationUrl = getURLFromRedirectError(e);
|
||||||
|
let urlPrefix = "";
|
||||||
|
|
||||||
|
// Get the URL parsed from URL so that we can reliably read pathname and searchParams from it.
|
||||||
|
const destinationUrlObj = new URL(destinationUrl, WEBAPP_URL);
|
||||||
|
|
||||||
|
// If it's a complete URL, use the origin as the prefix to ensure we redirect to the same domain.
|
||||||
|
if (destinationUrl.search(/^(http:|https:).*/) !== -1) {
|
||||||
|
urlPrefix = destinationUrlObj.origin;
|
||||||
|
} else {
|
||||||
|
// Don't use any prefix for relative URLs to ensure we stay on the same domain
|
||||||
|
urlPrefix = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const destinationQueryStr = destinationUrlObj.searchParams.toString();
|
||||||
|
// Make sure that redirect happens to /embed page and pass on embed query param as is for preserving Cal JS API namespace
|
||||||
|
const newDestinationUrl = `${urlPrefix}${destinationUrlObj.pathname}/embed?${
|
||||||
|
destinationQueryStr ? `${destinationQueryStr}&` : ""
|
||||||
|
}layout=${layout}&embed=${embed}`;
|
||||||
|
|
||||||
|
redirect(newDestinationUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNotFoundError(e)) {
|
||||||
|
notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import OldPage from "@pages/booking/[uid]";
|
||||||
|
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getData } from "../page";
|
||||||
|
|
||||||
|
const getEmbedData = withEmbedSsrAppDir(getData);
|
||||||
|
|
||||||
|
// @ts-expect-error Type '(context: GetServerSidePropsContext) => Promise<any>' is not assignable to type '(arg: {
|
||||||
|
export default WithLayout({ getLayout: null, getData: getEmbedData, Page: OldPage });
|
|
@ -0,0 +1,204 @@
|
||||||
|
import OldPage from "@pages/booking/[uid]";
|
||||||
|
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(
|
||||||
|
() => "",
|
||||||
|
() => ""
|
||||||
|
);
|
||||||
|
|
||||||
|
export 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,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-expect-error Argument of type '{ req: { headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }; }' is not assignable to parameter of type 'GetServerSidePropsContext'.
|
||||||
|
export default WithLayout({ getLayout: null, getData, Page: OldPage });
|
|
@ -0,0 +1,170 @@
|
||||||
|
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
|
||||||
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
import { BookingStatus } from "@calcom/prisma/enums";
|
||||||
|
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||||
|
|
||||||
|
export const getEventTypesFromDB = async (id: number) => {
|
||||||
|
const userSelect = {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
username: true,
|
||||||
|
hideBranding: true,
|
||||||
|
theme: true,
|
||||||
|
brandColor: true,
|
||||||
|
darkBrandColor: true,
|
||||||
|
email: true,
|
||||||
|
timeZone: true,
|
||||||
|
};
|
||||||
|
const eventType = await prisma.eventType.findUnique({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
title: true,
|
||||||
|
description: true,
|
||||||
|
length: true,
|
||||||
|
eventName: true,
|
||||||
|
recurringEvent: true,
|
||||||
|
requiresConfirmation: true,
|
||||||
|
userId: true,
|
||||||
|
successRedirectUrl: true,
|
||||||
|
customInputs: true,
|
||||||
|
locations: true,
|
||||||
|
price: true,
|
||||||
|
currency: true,
|
||||||
|
bookingFields: true,
|
||||||
|
disableGuests: true,
|
||||||
|
timeZone: true,
|
||||||
|
owner: {
|
||||||
|
select: userSelect,
|
||||||
|
},
|
||||||
|
users: {
|
||||||
|
select: userSelect,
|
||||||
|
},
|
||||||
|
hosts: {
|
||||||
|
select: {
|
||||||
|
user: {
|
||||||
|
select: userSelect,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
team: {
|
||||||
|
select: {
|
||||||
|
slug: true,
|
||||||
|
name: true,
|
||||||
|
hideBranding: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
workflows: {
|
||||||
|
select: {
|
||||||
|
workflow: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
steps: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
metadata: true,
|
||||||
|
seatsPerTimeSlot: true,
|
||||||
|
seatsShowAttendees: true,
|
||||||
|
seatsShowAvailabilityCount: true,
|
||||||
|
periodStartDate: true,
|
||||||
|
periodEndDate: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!eventType) {
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata = EventTypeMetaDataSchema.parse(eventType.metadata);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isDynamic: false,
|
||||||
|
...eventType,
|
||||||
|
bookingFields: getBookingFieldsWithSystemFields(eventType),
|
||||||
|
metadata,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleSeatsEventTypeOnBooking = async (
|
||||||
|
eventType: {
|
||||||
|
seatsPerTimeSlot?: number | null;
|
||||||
|
seatsShowAttendees: boolean | null;
|
||||||
|
seatsShowAvailabilityCount: boolean | null;
|
||||||
|
[x: string | number | symbol]: unknown;
|
||||||
|
},
|
||||||
|
bookingInfo: Partial<
|
||||||
|
Prisma.BookingGetPayload<{
|
||||||
|
include: {
|
||||||
|
attendees: { select: { name: true; email: true } };
|
||||||
|
seatsReferences: { select: { referenceUid: true } };
|
||||||
|
user: {
|
||||||
|
select: {
|
||||||
|
id: true;
|
||||||
|
name: true;
|
||||||
|
email: true;
|
||||||
|
username: true;
|
||||||
|
timeZone: true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}>
|
||||||
|
>,
|
||||||
|
seatReferenceUid?: string,
|
||||||
|
userId?: number
|
||||||
|
) => {
|
||||||
|
if (eventType?.seatsPerTimeSlot !== null) {
|
||||||
|
// @TODO: right now bookings with seats doesn't save every description that its entered by every user
|
||||||
|
delete bookingInfo.description;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// @TODO: If handling teams, we need to do more check ups for this.
|
||||||
|
if (bookingInfo?.user?.id === userId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eventType.seatsShowAttendees) {
|
||||||
|
const seatAttendee = await prisma.bookingSeat.findFirst({
|
||||||
|
where: {
|
||||||
|
referenceUid: seatReferenceUid,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
attendee: {
|
||||||
|
select: {
|
||||||
|
name: true,
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (seatAttendee) {
|
||||||
|
const attendee = bookingInfo?.attendees?.find((a) => {
|
||||||
|
return a.email === seatAttendee.attendee?.email;
|
||||||
|
});
|
||||||
|
bookingInfo["attendees"] = attendee ? [attendee] : [];
|
||||||
|
} else {
|
||||||
|
bookingInfo["attendees"] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bookingInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getRecurringBookings(recurringEventId: string | null) {
|
||||||
|
if (!recurringEventId) return null;
|
||||||
|
const recurringBookings = await prisma.booking.findMany({
|
||||||
|
where: {
|
||||||
|
recurringEventId,
|
||||||
|
status: BookingStatus.ACCEPTED,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
startTime: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return recurringBookings.map((obj) => obj.startTime.toString());
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
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 { 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 async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
|
// this is needed to prevent bundling of lib/booking to the client bundle
|
||||||
|
// usually functions that are used in getServerSideProps are tree shaken from client bundle
|
||||||
|
// but not in case when they are exported. So we have to dynamically load them, or to copy paste them to the /future/page.
|
||||||
|
|
||||||
|
const { getRecurringBookings, handleSeatsEventTypeOnBooking, getEventTypesFromDB } = await import(
|
||||||
|
"@lib/booking"
|
||||||
|
);
|
||||||
|
|
||||||
|
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) return { notFound: true } as const;
|
||||||
|
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) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventTypeRaw = !bookingInfoRaw.eventTypeId
|
||||||
|
? getDefaultEvent(eventTypeSlug || "")
|
||||||
|
: await getEventTypesFromDB(bookingInfoRaw.eventTypeId);
|
||||||
|
if (!eventTypeRaw) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
} as const;
|
||||||
|
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 {
|
||||||
|
props: {
|
||||||
|
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),
|
||||||
|
trpcState: ssr.dehydrate(),
|
||||||
|
dynamicEventName: bookingInfo?.eventType?.eventName || "",
|
||||||
|
bookingInfo,
|
||||||
|
paymentStatus: payment,
|
||||||
|
...(tz && { tz }),
|
||||||
|
userTimeFormat,
|
||||||
|
requiresLoginToUpdate,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { createEvent } from "ics";
|
import { createEvent } from "ics";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname, useRouter } from "next/navigation";
|
import { usePathname, useRouter } from "next/navigation";
|
||||||
|
@ -22,35 +23,28 @@ import {
|
||||||
useIsBackgroundTransparent,
|
useIsBackgroundTransparent,
|
||||||
useIsEmbed,
|
useIsEmbed,
|
||||||
} from "@calcom/embed-core/embed-iframe";
|
} from "@calcom/embed-core/embed-iframe";
|
||||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
|
||||||
import { Price } from "@calcom/features/bookings/components/event-meta/Price";
|
import { Price } from "@calcom/features/bookings/components/event-meta/Price";
|
||||||
import { SMS_REMINDER_NUMBER_FIELD, SystemField } from "@calcom/features/bookings/lib/SystemField";
|
import { SMS_REMINDER_NUMBER_FIELD, SystemField } from "@calcom/features/bookings/lib/SystemField";
|
||||||
import { getBookingWithResponses } from "@calcom/features/bookings/lib/get-booking";
|
|
||||||
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
|
|
||||||
import { parseRecurringEvent } from "@calcom/lib";
|
|
||||||
import { APP_NAME } from "@calcom/lib/constants";
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
import {
|
import {
|
||||||
formatToLocalizedDate,
|
formatToLocalizedDate,
|
||||||
formatToLocalizedTime,
|
formatToLocalizedTime,
|
||||||
formatToLocalizedTimezone,
|
formatToLocalizedTimezone,
|
||||||
} from "@calcom/lib/date-fns";
|
} from "@calcom/lib/date-fns";
|
||||||
import { getDefaultEvent } from "@calcom/lib/defaultEvents";
|
|
||||||
import useGetBrandingColours from "@calcom/lib/getBrandColours";
|
import useGetBrandingColours from "@calcom/lib/getBrandColours";
|
||||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
||||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||||
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
||||||
import { maybeGetBookingUidFromSeat } from "@calcom/lib/server/maybeGetBookingUidFromSeat";
|
|
||||||
import { getIs24hClockFromLocalStorage, isBrowserLocale24h } from "@calcom/lib/timeFormat";
|
import { getIs24hClockFromLocalStorage, isBrowserLocale24h } from "@calcom/lib/timeFormat";
|
||||||
import { localStorage } from "@calcom/lib/webstorage";
|
import { localStorage } from "@calcom/lib/webstorage";
|
||||||
import prisma from "@calcom/prisma";
|
|
||||||
import type { Prisma } from "@calcom/prisma/client";
|
|
||||||
import { BookingStatus } from "@calcom/prisma/enums";
|
import { BookingStatus } from "@calcom/prisma/enums";
|
||||||
import { bookingMetadataSchema, customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||||
import { Alert, Badge, Button, EmailInput, HeadSeo, useCalcomTheme } from "@calcom/ui";
|
import { Alert, Badge, Button, EmailInput, HeadSeo, useCalcomTheme } from "@calcom/ui";
|
||||||
import { AlertCircle, Calendar, Check, ChevronLeft, ExternalLink, X } from "@calcom/ui/components/icon";
|
import { AlertCircle, Calendar, Check, ChevronLeft, ExternalLink, X } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@lib/booking/[uid]/getServerSideProps";
|
||||||
import { timeZone } from "@lib/clock";
|
import { timeZone } from "@lib/clock";
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
@ -58,23 +52,7 @@ import PageWrapper from "@components/PageWrapper";
|
||||||
import CancelBooking from "@components/booking/CancelBooking";
|
import CancelBooking from "@components/booking/CancelBooking";
|
||||||
import EventReservationSchema from "@components/schemas/EventReservationSchema";
|
import EventReservationSchema from "@components/schemas/EventReservationSchema";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
export { getServerSideProps };
|
||||||
|
|
||||||
const useBrandColors = ({
|
|
||||||
brandColor,
|
|
||||||
darkBrandColor,
|
|
||||||
}: {
|
|
||||||
brandColor?: string | null;
|
|
||||||
darkBrandColor?: string | null;
|
|
||||||
}) => {
|
|
||||||
const brandTheme = useGetBrandingColours({
|
|
||||||
lightVal: brandColor,
|
|
||||||
darkVal: darkBrandColor,
|
|
||||||
});
|
|
||||||
useCalcomTheme(brandTheme);
|
|
||||||
};
|
|
||||||
|
|
||||||
type SuccessProps = inferSSRProps<typeof getServerSideProps>;
|
|
||||||
|
|
||||||
const stringToBoolean = z
|
const stringToBoolean = z
|
||||||
.string()
|
.string()
|
||||||
|
@ -94,6 +72,22 @@ const querySchema = z.object({
|
||||||
seatReferenceUid: z.string().optional(),
|
seatReferenceUid: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const useBrandColors = ({
|
||||||
|
brandColor,
|
||||||
|
darkBrandColor,
|
||||||
|
}: {
|
||||||
|
brandColor?: string | null;
|
||||||
|
darkBrandColor?: string | null;
|
||||||
|
}) => {
|
||||||
|
const brandTheme = useGetBrandingColours({
|
||||||
|
lightVal: brandColor,
|
||||||
|
darkVal: darkBrandColor,
|
||||||
|
});
|
||||||
|
useCalcomTheme(brandTheme);
|
||||||
|
};
|
||||||
|
|
||||||
|
type SuccessProps = inferSSRProps<typeof getServerSideProps>;
|
||||||
|
|
||||||
export default function Success(props: SuccessProps) {
|
export default function Success(props: SuccessProps) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -925,329 +919,3 @@ export function RecurringBookings({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getEventTypesFromDB = async (id: number) => {
|
|
||||||
const userSelect = {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
username: true,
|
|
||||||
hideBranding: true,
|
|
||||||
theme: true,
|
|
||||||
brandColor: true,
|
|
||||||
darkBrandColor: true,
|
|
||||||
email: true,
|
|
||||||
timeZone: true,
|
|
||||||
};
|
|
||||||
const eventType = await prisma.eventType.findUnique({
|
|
||||||
where: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
description: true,
|
|
||||||
length: true,
|
|
||||||
eventName: true,
|
|
||||||
recurringEvent: true,
|
|
||||||
requiresConfirmation: true,
|
|
||||||
userId: true,
|
|
||||||
successRedirectUrl: true,
|
|
||||||
customInputs: true,
|
|
||||||
locations: true,
|
|
||||||
price: true,
|
|
||||||
currency: true,
|
|
||||||
bookingFields: true,
|
|
||||||
disableGuests: true,
|
|
||||||
timeZone: true,
|
|
||||||
owner: {
|
|
||||||
select: userSelect,
|
|
||||||
},
|
|
||||||
users: {
|
|
||||||
select: userSelect,
|
|
||||||
},
|
|
||||||
hosts: {
|
|
||||||
select: {
|
|
||||||
user: {
|
|
||||||
select: userSelect,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
team: {
|
|
||||||
select: {
|
|
||||||
slug: true,
|
|
||||||
name: true,
|
|
||||||
hideBranding: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
workflows: {
|
|
||||||
select: {
|
|
||||||
workflow: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
steps: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
metadata: true,
|
|
||||||
seatsPerTimeSlot: true,
|
|
||||||
seatsShowAttendees: true,
|
|
||||||
seatsShowAvailabilityCount: true,
|
|
||||||
periodStartDate: true,
|
|
||||||
periodEndDate: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!eventType) {
|
|
||||||
return eventType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const metadata = EventTypeMetaDataSchema.parse(eventType.metadata);
|
|
||||||
|
|
||||||
return {
|
|
||||||
isDynamic: false,
|
|
||||||
...eventType,
|
|
||||||
bookingFields: getBookingFieldsWithSystemFields(eventType),
|
|
||||||
metadata,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSeatsEventTypeOnBooking = async (
|
|
||||||
eventType: {
|
|
||||||
seatsPerTimeSlot?: number | null;
|
|
||||||
seatsShowAttendees: boolean | null;
|
|
||||||
seatsShowAvailabilityCount: boolean | null;
|
|
||||||
[x: string | number | symbol]: unknown;
|
|
||||||
},
|
|
||||||
bookingInfo: Partial<
|
|
||||||
Prisma.BookingGetPayload<{
|
|
||||||
include: {
|
|
||||||
attendees: { select: { name: true; email: true } };
|
|
||||||
seatsReferences: { select: { referenceUid: true } };
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
id: true;
|
|
||||||
name: true;
|
|
||||||
email: true;
|
|
||||||
username: true;
|
|
||||||
timeZone: true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}>
|
|
||||||
>,
|
|
||||||
seatReferenceUid?: string,
|
|
||||||
userId?: number
|
|
||||||
) => {
|
|
||||||
if (eventType?.seatsPerTimeSlot !== null) {
|
|
||||||
// @TODO: right now bookings with seats doesn't save every description that its entered by every user
|
|
||||||
delete bookingInfo.description;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// @TODO: If handling teams, we need to do more check ups for this.
|
|
||||||
if (bookingInfo?.user?.id === userId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!eventType.seatsShowAttendees) {
|
|
||||||
const seatAttendee = await prisma.bookingSeat.findFirst({
|
|
||||||
where: {
|
|
||||||
referenceUid: seatReferenceUid,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
attendee: {
|
|
||||||
select: {
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (seatAttendee) {
|
|
||||||
const attendee = bookingInfo?.attendees?.find((a) => {
|
|
||||||
return a.email === seatAttendee.attendee?.email;
|
|
||||||
});
|
|
||||||
bookingInfo["attendees"] = attendee ? [attendee] : [];
|
|
||||||
} else {
|
|
||||||
bookingInfo["attendees"] = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bookingInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function getServerSideProps(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) return { notFound: true } as const;
|
|
||||||
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) {
|
|
||||||
return {
|
|
||||||
notFound: true,
|
|
||||||
} as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
const eventTypeRaw = !bookingInfoRaw.eventTypeId
|
|
||||||
? getDefaultEvent(eventTypeSlug || "")
|
|
||||||
: await getEventTypesFromDB(bookingInfoRaw.eventTypeId);
|
|
||||||
if (!eventTypeRaw) {
|
|
||||||
return {
|
|
||||||
notFound: true,
|
|
||||||
} as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
return {
|
|
||||||
notFound: true,
|
|
||||||
} as const;
|
|
||||||
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 {
|
|
||||||
props: {
|
|
||||||
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),
|
|
||||||
trpcState: ssr.dehydrate(),
|
|
||||||
dynamicEventName: bookingInfo?.eventType?.eventName || "",
|
|
||||||
bookingInfo,
|
|
||||||
paymentStatus: payment,
|
|
||||||
...(tz && { tz }),
|
|
||||||
userTimeFormat,
|
|
||||||
requiresLoginToUpdate,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getRecurringBookings(recurringEventId: string | null) {
|
|
||||||
if (!recurringEventId) return null;
|
|
||||||
const recurringBookings = await prisma.booking.findMany({
|
|
||||||
where: {
|
|
||||||
recurringEventId,
|
|
||||||
status: BookingStatus.ACCEPTED,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
startTime: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return recurringBookings.map((obj) => obj.startTime.toString());
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import withEmbedSsr from "@lib/withEmbedSsr";
|
"use client";
|
||||||
|
|
||||||
import { getServerSideProps as _getServerSideProps } from "../[uid]";
|
import { getServerSideProps as _getServerSideProps } from "@lib/booking/[uid]/getServerSideProps";
|
||||||
|
import withEmbedSsr from "@lib/withEmbedSsr";
|
||||||
|
|
||||||
export { default } from "../[uid]";
|
export { default } from "../[uid]";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user