diff --git a/packages/trpc/server/routers/viewer/slots/util.test.ts b/packages/trpc/server/routers/viewer/slots/util.test.ts new file mode 100644 index 0000000000..1112a02f51 --- /dev/null +++ b/packages/trpc/server/routers/viewer/slots/util.test.ts @@ -0,0 +1,45 @@ +import { describe, it, expect } from "vitest"; + +import { BookingDateInPastError, isTimeOutOfBounds } from "@calcom/lib/isOutOfBounds"; + +import { TRPCError } from "@trpc/server"; + +describe("BookingDateInPastError handling", () => { + it("should convert BookingDateInPastError to TRPCError with BAD_REQUEST code", () => { + const testFilteringLogic = () => { + const mockSlot = { + time: "2024-05-20T12:30:00.000Z", // Past date + attendees: 1, + }; + + const mockEventType = { + minimumBookingNotice: 0, + }; + + const isFutureLimitViolationForTheSlot = false; // Mock this to false + + let isOutOfBounds = false; + try { + // This will throw BookingDateInPastError for past dates + isOutOfBounds = isTimeOutOfBounds({ + time: mockSlot.time, + minimumBookingNotice: mockEventType.minimumBookingNotice, + }); + } catch (error) { + if (error instanceof BookingDateInPastError) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: error.message, + }); + } + throw error; + } + + return !isFutureLimitViolationForTheSlot && !isOutOfBounds; + }; + + // This should throw a TRPCError with BAD_REQUEST code + expect(() => testFilteringLogic()).toThrow(TRPCError); + expect(() => testFilteringLogic()).toThrow("Attempting to book a meeting in the past."); + }); +}); diff --git a/packages/trpc/server/routers/viewer/slots/util.ts b/packages/trpc/server/routers/viewer/slots/util.ts index a7f83b2540..b5b393827c 100644 --- a/packages/trpc/server/routers/viewer/slots/util.ts +++ b/packages/trpc/server/routers/viewer/slots/util.ts @@ -35,6 +35,7 @@ import { calculatePeriodLimits, isTimeOutOfBounds, isTimeViolatingFutureLimit, + BookingDateInPastError, } from "@calcom/lib/isOutOfBounds"; import logger from "@calcom/lib/logger"; import { isRestrictionScheduleEnabled } from "@calcom/lib/restrictionSchedule"; @@ -1313,6 +1314,22 @@ export class AvailableSlotsService { periodLimits, }); + let isOutOfBounds = false; + try { + isOutOfBounds = isTimeOutOfBounds({ + time: slot.time, + minimumBookingNotice: eventType.minimumBookingNotice, + }); + } catch (error) { + if (error instanceof BookingDateInPastError) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: error.message, + }); + } + throw error; + } + if (isFutureLimitViolationForTheSlot) { foundAFutureLimitViolation = true; } @@ -1320,7 +1337,7 @@ export class AvailableSlotsService { return ( !isFutureLimitViolationForTheSlot && // TODO: Perf Optimization: Slots calculation logic already seems to consider the minimum booking notice and past booking time and thus there shouldn't be need to filter out slots here. - !isTimeOutOfBounds({ time: slot.time, minimumBookingNotice: eventType.minimumBookingNotice }) + !isOutOfBounds ); });