feat: Redirect when event type does not match booking type (#14460)
* feat: Redirect when event type does not match booking type * Favour early return * If multiple bookingUid/rescheduleUid given, use first * rescheduleUid/bookingUid behaviour is required
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
import type { DehydratedState } from "@tanstack/react-query";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import type { Session } from "next-auth";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { getBookingForReschedule, getBookingForSeatedEvent } from "@calcom/features/bookings/lib/get-booking";
|
||||
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 { 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 { getTemporaryOrgRedirect } from "@lib/getTemporaryOrgRedirect";
|
||||
@@ -16,6 +20,74 @@ import { type EmbedProps } from "@lib/withEmbedSsr";
|
||||
|
||||
export type PageProps = inferSSRProps<typeof getServerSideProps> & EmbedProps;
|
||||
|
||||
type Props = {
|
||||
eventData: Pick<
|
||||
NonNullable<Awaited<ReturnType<typeof getPublicEvent>>>,
|
||||
"id" | "length" | "metadata" | "entity"
|
||||
>;
|
||||
booking?: GetBookingType;
|
||||
rescheduleUid: string | null;
|
||||
bookingUid: string | null;
|
||||
user: string;
|
||||
slug: string;
|
||||
trpcState: DehydratedState;
|
||||
isBrandingHidden: boolean;
|
||||
isSEOIndexable: boolean | null;
|
||||
themeBasis: null | string;
|
||||
orgBannerUrl: null;
|
||||
};
|
||||
|
||||
async function processReschedule({
|
||||
props,
|
||||
rescheduleUid,
|
||||
session,
|
||||
}: {
|
||||
props: Props;
|
||||
session: Session | null;
|
||||
rescheduleUid: string | string[] | undefined;
|
||||
}) {
|
||||
if (!rescheduleUid) return;
|
||||
const booking = await getBookingForReschedule(`${rescheduleUid}`, session?.user?.id);
|
||||
// if no booking found, no eventTypeId (dynamic) or it matches this eventData - return void (success).
|
||||
if (booking === null || !booking.eventTypeId || booking?.eventTypeId === props.eventData?.id) {
|
||||
props.booking = booking;
|
||||
props.rescheduleUid = Array.isArray(rescheduleUid) ? rescheduleUid[0] : rescheduleUid;
|
||||
return;
|
||||
}
|
||||
// handle redirect response
|
||||
const redirectEventTypeTarget = await prisma.eventType.findUnique({
|
||||
where: {
|
||||
id: booking.eventTypeId,
|
||||
},
|
||||
select: {
|
||||
slug: true,
|
||||
},
|
||||
});
|
||||
if (!redirectEventTypeTarget) {
|
||||
return {
|
||||
notFound: true,
|
||||
} as const;
|
||||
}
|
||||
return {
|
||||
redirect: {
|
||||
permanent: false,
|
||||
destination: redirectEventTypeTarget.slug,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function processSeatedEvent({
|
||||
props,
|
||||
bookingUid,
|
||||
}: {
|
||||
props: Props;
|
||||
bookingUid: string | string[] | undefined;
|
||||
}) {
|
||||
if (!bookingUid) return;
|
||||
props.booking = await getBookingForSeatedEvent(`${bookingUid}`);
|
||||
props.bookingUid = Array.isArray(bookingUid) ? bookingUid[0] : bookingUid;
|
||||
}
|
||||
|
||||
async function getDynamicGroupPageProps(context: GetServerSidePropsContext) {
|
||||
const session = await getServerSession(context);
|
||||
const { user: usernames, type: slug } = paramsSchema.parse(context.params);
|
||||
@@ -51,13 +123,6 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) {
|
||||
} as const;
|
||||
}
|
||||
|
||||
let booking: GetBookingType | null = null;
|
||||
if (rescheduleUid) {
|
||||
booking = await getBookingForReschedule(`${rescheduleUid}`, session?.user?.id);
|
||||
} else if (bookingUid) {
|
||||
booking = await getBookingForSeatedEvent(`${bookingUid}`);
|
||||
}
|
||||
|
||||
// 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 eventData = await ssr.viewer.public.event.fetch({
|
||||
@@ -73,27 +138,38 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) {
|
||||
} as const;
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
eventData: {
|
||||
entity: eventData.entity,
|
||||
length: eventData.length,
|
||||
metadata: {
|
||||
...eventData.metadata,
|
||||
multipleDuration: [15, 30, 60],
|
||||
},
|
||||
const props: Props = {
|
||||
eventData: {
|
||||
id: eventData.id,
|
||||
entity: eventData.entity,
|
||||
length: eventData.length,
|
||||
metadata: {
|
||||
...eventData.metadata,
|
||||
multipleDuration: [15, 30, 60],
|
||||
},
|
||||
booking,
|
||||
user: usernames.join("+"),
|
||||
slug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
isBrandingHidden: false,
|
||||
isSEOIndexable: true,
|
||||
themeBasis: null,
|
||||
bookingUid: bookingUid ? `${bookingUid}` : null,
|
||||
rescheduleUid: rescheduleUid ? `${rescheduleUid}` : null,
|
||||
orgBannerUrl: null,
|
||||
},
|
||||
user: usernames.join("+"),
|
||||
slug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
isBrandingHidden: false,
|
||||
isSEOIndexable: true,
|
||||
themeBasis: null,
|
||||
bookingUid: bookingUid ? `${bookingUid}` : null,
|
||||
rescheduleUid: null,
|
||||
orgBannerUrl: null,
|
||||
};
|
||||
|
||||
if (rescheduleUid) {
|
||||
const processRescheduleResult = await processReschedule({ props, rescheduleUid, session });
|
||||
if (processRescheduleResult) {
|
||||
return processRescheduleResult;
|
||||
}
|
||||
} else if (bookingUid) {
|
||||
await processSeatedEvent({ props, bookingUid });
|
||||
}
|
||||
|
||||
return {
|
||||
props,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -131,13 +207,6 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
|
||||
} as const;
|
||||
}
|
||||
|
||||
let booking: GetBookingType | null = null;
|
||||
if (rescheduleUid) {
|
||||
booking = await getBookingForReschedule(`${rescheduleUid}`, session?.user?.id);
|
||||
} else if (bookingUid) {
|
||||
booking = await getBookingForSeatedEvent(`${bookingUid}`);
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -154,24 +223,35 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
|
||||
} as const;
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
booking,
|
||||
eventData: {
|
||||
entity: eventData.entity,
|
||||
length: eventData.length,
|
||||
metadata: eventData.metadata,
|
||||
},
|
||||
user: username,
|
||||
slug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
isBrandingHidden: user?.hideBranding,
|
||||
isSEOIndexable: user?.allowSEOIndexing,
|
||||
themeBasis: username,
|
||||
bookingUid: bookingUid ? `${bookingUid}` : null,
|
||||
rescheduleUid: rescheduleUid ? `${rescheduleUid}` : null,
|
||||
orgBannerUrl: eventData?.owner?.profile?.organization?.bannerUrl ?? null,
|
||||
const props: Props = {
|
||||
eventData: {
|
||||
id: eventData.id,
|
||||
entity: eventData.entity,
|
||||
length: eventData.length,
|
||||
metadata: eventData.metadata,
|
||||
},
|
||||
user: username,
|
||||
slug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
isBrandingHidden: user?.hideBranding,
|
||||
isSEOIndexable: user?.allowSEOIndexing,
|
||||
themeBasis: username,
|
||||
bookingUid: bookingUid ? `${bookingUid}` : null,
|
||||
rescheduleUid: null,
|
||||
orgBannerUrl: eventData?.owner?.profile?.organization?.bannerUrl ?? null,
|
||||
};
|
||||
|
||||
if (rescheduleUid) {
|
||||
const processRescheduleResult = await processReschedule({ props, rescheduleUid, session });
|
||||
if (processRescheduleResult) {
|
||||
return processRescheduleResult;
|
||||
}
|
||||
} else if (bookingUid) {
|
||||
await processSeatedEvent({ props, bookingUid });
|
||||
}
|
||||
|
||||
return {
|
||||
props,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user