fix: Booker fix for team + user with same event + event slug (#9654)
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
This commit is contained in:
parent
b070cfb227
commit
ab6781cd72
|
@ -14,7 +14,7 @@ import PageWrapper from "@components/PageWrapper";
|
|||
|
||||
type PageProps = inferSSRProps<typeof getServerSideProps>;
|
||||
|
||||
export default function Type({ slug, user, booking, away, isBrandingHidden }: PageProps) {
|
||||
export default function Type({ slug, user, booking, away, isBrandingHidden, isTeamEvent }: PageProps) {
|
||||
return (
|
||||
<main className="flex h-full min-h-[100dvh] items-center justify-center">
|
||||
<BookerSeo
|
||||
|
@ -29,6 +29,7 @@ export default function Type({ slug, user, booking, away, isBrandingHidden }: Pa
|
|||
rescheduleBooking={booking}
|
||||
isAway={away}
|
||||
hideBranding={isBrandingHidden}
|
||||
isTeamEvent={isTeamEvent}
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
|
@ -57,6 +58,11 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
|
|||
username: true,
|
||||
},
|
||||
},
|
||||
team: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -96,9 +102,11 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
|
|||
booking = await getBookingByUidOrRescheduleUid(`${rescheduleUid}`);
|
||||
}
|
||||
|
||||
const isTeamEvent = !!hashedLink.eventType?.team?.id;
|
||||
|
||||
// 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({ username, eventSlug: slug });
|
||||
const eventData = await ssr.viewer.public.event.fetch({ username, eventSlug: slug, isTeamEvent });
|
||||
|
||||
if (!eventData) {
|
||||
return {
|
||||
|
@ -114,6 +122,9 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
|
|||
slug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
isBrandingHidden: user?.hideBranding,
|
||||
// Sending the team event from the server, because this template file
|
||||
// is reused for both team and user events.
|
||||
isTeamEvent,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ export default function Type({ slug, user, booking, away, isBrandingHidden }: Pa
|
|||
rescheduleBooking={booking}
|
||||
isAway={away}
|
||||
hideBranding={isBrandingHidden}
|
||||
isTeamEvent
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
|
@ -71,7 +72,11 @@ export const getServerSideProps = async (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 eventData = await ssr.viewer.public.event.fetch({ username: teamSlug, eventSlug: meetingSlug });
|
||||
const eventData = await ssr.viewer.public.event.fetch({
|
||||
username: teamSlug,
|
||||
eventSlug: meetingSlug,
|
||||
isTeamEvent: true,
|
||||
});
|
||||
|
||||
if (!eventData) {
|
||||
return {
|
||||
|
|
|
@ -36,6 +36,7 @@ const BookerComponent = ({
|
|||
month,
|
||||
rescheduleBooking,
|
||||
hideBranding = false,
|
||||
isTeamEvent,
|
||||
}: BookerProps) => {
|
||||
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||
const isTablet = useMediaQuery("(max-width: 1024px)");
|
||||
|
@ -81,6 +82,7 @@ const BookerComponent = ({
|
|||
rescheduleUid,
|
||||
rescheduleBooking,
|
||||
layout: defaultLayout,
|
||||
isTeamEvent,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -22,6 +22,7 @@ type StoreInitializeType = {
|
|||
rescheduleUid: string | null;
|
||||
rescheduleBooking: GetBookingType | null | undefined;
|
||||
layout: BookerLayout;
|
||||
isTeamEvent?: boolean;
|
||||
};
|
||||
|
||||
export type BookerStore = {
|
||||
|
@ -89,6 +90,12 @@ export type BookerStore = {
|
|||
*/
|
||||
formValues: Record<string, any>;
|
||||
setFormValues: (values: Record<string, any>) => void;
|
||||
/**
|
||||
* Force event being a team event, so we only query for team events instead
|
||||
* of also include 'user' events and return the first event that matches with
|
||||
* both the slug and the event slug.
|
||||
*/
|
||||
isTeamEvent: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -137,6 +144,7 @@ export const useBookerStore = create<BookerStore>((set, get) => ({
|
|||
updateQueryParam("month", month ?? "");
|
||||
get().setSelectedDate(null);
|
||||
},
|
||||
isTeamEvent: false,
|
||||
initialize: ({
|
||||
username,
|
||||
eventSlug,
|
||||
|
@ -145,6 +153,7 @@ export const useBookerStore = create<BookerStore>((set, get) => ({
|
|||
rescheduleUid = null,
|
||||
rescheduleBooking = null,
|
||||
layout,
|
||||
isTeamEvent,
|
||||
}: StoreInitializeType) => {
|
||||
const selectedDateInStore = get().selectedDate;
|
||||
|
||||
|
@ -165,6 +174,7 @@ export const useBookerStore = create<BookerStore>((set, get) => ({
|
|||
rescheduleUid,
|
||||
rescheduleBooking,
|
||||
layout: layout || BookerLayouts.MONTH_VIEW,
|
||||
isTeamEvent: isTeamEvent || false,
|
||||
// Preselect today's date in week / column view, since they use this to show the week title.
|
||||
selectedDate:
|
||||
selectedDateInStore ||
|
||||
|
@ -207,9 +217,29 @@ export const useInitializeBookerStore = ({
|
|||
rescheduleUid = null,
|
||||
rescheduleBooking = null,
|
||||
layout,
|
||||
isTeamEvent,
|
||||
}: StoreInitializeType) => {
|
||||
const initializeStore = useBookerStore((state) => state.initialize);
|
||||
useEffect(() => {
|
||||
initializeStore({ username, eventSlug, month, eventId, rescheduleUid, rescheduleBooking, layout });
|
||||
}, [initializeStore, username, eventSlug, month, eventId, rescheduleUid, rescheduleBooking, layout]);
|
||||
initializeStore({
|
||||
username,
|
||||
eventSlug,
|
||||
month,
|
||||
eventId,
|
||||
rescheduleUid,
|
||||
rescheduleBooking,
|
||||
layout,
|
||||
isTeamEvent,
|
||||
});
|
||||
}, [
|
||||
initializeStore,
|
||||
username,
|
||||
eventSlug,
|
||||
month,
|
||||
eventId,
|
||||
rescheduleUid,
|
||||
rescheduleBooking,
|
||||
layout,
|
||||
isTeamEvent,
|
||||
]);
|
||||
};
|
||||
|
|
|
@ -41,6 +41,13 @@ export interface BookerProps {
|
|||
* within the atom (i.e. without a server side component).
|
||||
*/
|
||||
rescheduleBooking?: GetBookingType;
|
||||
/**
|
||||
* If this boolean is passed, we will only check team events with this slug and event slug.
|
||||
* If it's not passed, we will first query a generic user event, and only if that doesn't exist
|
||||
* fetch the team event. In case there's both a team + user with the same slug AND same event slug,
|
||||
* that will always result in the user event being returned.
|
||||
*/
|
||||
isTeamEvent?: boolean;
|
||||
}
|
||||
|
||||
export type BookerState = "loading" | "selecting_date" | "selecting_time" | "booking";
|
||||
|
|
|
@ -16,9 +16,10 @@ import { useBookerStore } from "../store";
|
|||
*/
|
||||
export const useEvent = () => {
|
||||
const [username, eventSlug] = useBookerStore((state) => [state.username, state.eventSlug], shallow);
|
||||
const isTeamEvent = useBookerStore((state) => state.isTeamEvent);
|
||||
|
||||
return trpc.viewer.public.event.useQuery(
|
||||
{ username: username ?? "", eventSlug: eventSlug ?? "" },
|
||||
{ username: username ?? "", eventSlug: eventSlug ?? "", isTeamEvent },
|
||||
{ refetchOnWindowFocus: false, enabled: Boolean(username) && Boolean(eventSlug) }
|
||||
);
|
||||
};
|
||||
|
|
|
@ -76,7 +76,12 @@ const publicEventSelect = Prisma.validator<Prisma.EventTypeSelect>()({
|
|||
hidden: true,
|
||||
});
|
||||
|
||||
export const getPublicEvent = async (username: string, eventSlug: string, prisma: PrismaClient) => {
|
||||
export const getPublicEvent = async (
|
||||
username: string,
|
||||
eventSlug: string,
|
||||
isTeamEvent: boolean | undefined,
|
||||
prisma: PrismaClient
|
||||
) => {
|
||||
const usernameList = username.split("+");
|
||||
|
||||
// In case of dynamic group event, we fetch user's data and use the default event.
|
||||
|
@ -141,24 +146,26 @@ export const getPublicEvent = async (username: string, eventSlug: string, prisma
|
|||
};
|
||||
}
|
||||
|
||||
const usersOrTeamQuery = isTeamEvent
|
||||
? {
|
||||
team: {
|
||||
slug: username,
|
||||
},
|
||||
}
|
||||
: {
|
||||
users: {
|
||||
some: {
|
||||
username,
|
||||
},
|
||||
},
|
||||
team: null,
|
||||
};
|
||||
|
||||
// In case it's not a group event, it's either a single user or a team, and we query that data.
|
||||
const event = await prisma.eventType.findFirst({
|
||||
where: {
|
||||
slug: eventSlug,
|
||||
OR: [
|
||||
{
|
||||
users: {
|
||||
some: {
|
||||
username,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
team: {
|
||||
slug: username,
|
||||
},
|
||||
},
|
||||
],
|
||||
...usersOrTeamQuery,
|
||||
},
|
||||
select: publicEventSelect,
|
||||
});
|
||||
|
|
|
@ -10,6 +10,6 @@ interface EventHandlerOptions {
|
|||
}
|
||||
|
||||
export const eventHandler = async ({ ctx, input }: EventHandlerOptions) => {
|
||||
const event = await getPublicEvent(input.username, input.eventSlug, ctx.prisma);
|
||||
const event = await getPublicEvent(input.username, input.eventSlug, input.isTeamEvent, ctx.prisma);
|
||||
return event;
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ import z from "zod";
|
|||
export const ZEventInputSchema = z.object({
|
||||
username: z.string(),
|
||||
eventSlug: z.string(),
|
||||
isTeamEvent: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type TEventInputSchema = z.infer<typeof ZEventInputSchema>;
|
||||
|
|
Loading…
Reference in New Issue
Block a user