diff --git a/packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx b/packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx index e40cf4725f..4b093855cc 100644 --- a/packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx +++ b/packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx @@ -34,6 +34,7 @@ import { Alert, Button, EmptyScreen, Form, showToast } from "@calcom/ui"; import { Calendar } from "@calcom/ui/components/icon"; import { useBookerStore } from "../../store"; +import { useSlotReservationId } from "../../useSlotReservationId"; import { useEvent } from "../../utils/event"; import { BookingFields } from "./BookingFields"; import { FormSkeleton } from "./Skeleton"; @@ -45,8 +46,16 @@ type BookEventFormProps = { type DefaultValues = Record; export const BookEventForm = ({ onCancel }: BookEventFormProps) => { + const [slotReservationId, setSlotReservationId] = useSlotReservationId(); const reserveSlotMutation = trpc.viewer.public.slots.reserveSlot.useMutation({ - trpc: { context: { skipBatch: true } }, + trpc: { + context: { + skipBatch: true, + }, + }, + onSuccess: (data) => { + setSlotReservationId(data.uid); + }, }); const removeSelectedSlot = trpc.viewer.public.slots.removeSelectedSlotMark.useMutation({ trpc: { context: { skipBatch: true } }, @@ -82,7 +91,7 @@ export const BookEventForm = ({ onCancel }: BookEventFormProps) => { return () => { if (eventType) { - removeSelectedSlot.mutate(); + removeSelectedSlot.mutate({ uid: slotReservationId }); } clearInterval(interval); }; diff --git a/packages/features/bookings/Booker/useSlotReservationId.ts b/packages/features/bookings/Booker/useSlotReservationId.ts new file mode 100644 index 0000000000..3639543dbf --- /dev/null +++ b/packages/features/bookings/Booker/useSlotReservationId.ts @@ -0,0 +1,15 @@ +// TODO: It would be lost on refresh, so we need to persist it. +// Though, we are persisting it in a cookie(`uid` cookie is set through reserveSlot call) +// but that becomes a third party cookie in context of embed and thus isn't accessible inside embed +// So, we need to persist it in top window as first party cookie in that case. +let slotReservationId: null | string = null; + +export const useSlotReservationId = () => { + function set(uid: string) { + slotReservationId = uid; + } + function get() { + return slotReservationId; + } + return [get(), set] as const; +}; diff --git a/packages/trpc/server/routers/viewer/slots/_router.tsx b/packages/trpc/server/routers/viewer/slots/_router.tsx index c38b4e4441..2d37ad3eab 100644 --- a/packages/trpc/server/routers/viewer/slots/_router.tsx +++ b/packages/trpc/server/routers/viewer/slots/_router.tsx @@ -3,6 +3,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import publicProcedure from "../../../procedures/publicProcedure"; import { router } from "../../../trpc"; import { ZGetScheduleInputSchema } from "./getSchedule.schema"; +import { ZRemoveSelectedSlotInputSchema } from "./removeSelectedSlot.schema"; import { ZReserveSlotInputSchema } from "./reserveSlot.schema"; type SlotsRouterHandlerCache = { @@ -49,12 +50,14 @@ export const slotsRouter = router({ }); }), // This endpoint has no dependencies, it doesn't need its own file - removeSelectedSlotMark: publicProcedure.mutation(async ({ ctx }) => { - const { req, prisma } = ctx; - const uid = req?.cookies?.uid; - if (uid) { - await prisma.selectedSlots.deleteMany({ where: { uid: { equals: uid } } }); - } - return; - }), + removeSelectedSlotMark: publicProcedure + .input(ZRemoveSelectedSlotInputSchema) + .mutation(async ({ input, ctx }) => { + const { req, prisma } = ctx; + const uid = req?.cookies?.uid || input.uid; + if (uid) { + await prisma.selectedSlots.deleteMany({ where: { uid: { equals: uid } } }); + } + return; + }), }); diff --git a/packages/trpc/server/routers/viewer/slots/removeSelectedSlot.schema.ts b/packages/trpc/server/routers/viewer/slots/removeSelectedSlot.schema.ts new file mode 100644 index 0000000000..afdfab987c --- /dev/null +++ b/packages/trpc/server/routers/viewer/slots/removeSelectedSlot.schema.ts @@ -0,0 +1,7 @@ +import type { z } from "zod"; + +import { removeSelectedSlotSchema } from "./types"; + +export const ZRemoveSelectedSlotInputSchema = removeSelectedSlotSchema; + +export type TRemoveSelectedSlotInputSchema = z.infer; diff --git a/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts b/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts index 330789f975..62e3a263ba 100644 --- a/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts +++ b/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts @@ -86,5 +86,7 @@ export const reserveSlotHandler = async ({ ctx, input }: ReserveSlotOptions) => } } res?.setHeader("Set-Cookie", serialize("uid", uid, { path: "/", sameSite: "lax" })); - return; + return { + uid: uid, + }; }; diff --git a/packages/trpc/server/routers/viewer/slots/types.ts b/packages/trpc/server/routers/viewer/slots/types.ts index aed8403143..aca1834f62 100644 --- a/packages/trpc/server/routers/viewer/slots/types.ts +++ b/packages/trpc/server/routers/viewer/slots/types.ts @@ -57,3 +57,7 @@ export type Slot = { bookingUid?: string; users?: string[]; }; + +export const removeSelectedSlotSchema = z.object({ + uid: z.string().nullable(), +});