diff --git a/packages/lib/intervalLimits/server/getBusyTimesFromLimits.ts b/packages/lib/intervalLimits/server/getBusyTimesFromLimits.ts index fa7d011c6b..8757041c83 100644 --- a/packages/lib/intervalLimits/server/getBusyTimesFromLimits.ts +++ b/packages/lib/intervalLimits/server/getBusyTimesFromLimits.ts @@ -12,6 +12,7 @@ import type { EventBusyDetails } from "@calcom/types/Calendar"; import { descendingLimitKeys, intervalLimitKeyToUnit } from "../intervalLimit"; import type { IntervalLimit } from "../intervalLimitSchema"; import LimitManager from "../limitManager"; +import { isBookingWithinPeriod } from "../utils"; import { checkBookingLimit } from "./checkBookingLimits"; export const getBusyTimesFromLimits = async ( @@ -64,6 +65,7 @@ const _getBusyTimesFromLimits = async ( duration, eventType, limitManager, + timeZone, rescheduleUid ); performance.mark("durationLimitsEnd"); @@ -147,7 +149,7 @@ const _getBusyTimesFromBookingLimits = async (params: { for (const booking of bookings) { // consider booking part of period independent of end date - if (!dayjs(booking.start).isBetween(periodStart, periodEnd)) { + if (!isBookingWithinPeriod(booking, periodStart, periodEnd, timeZone || "UTC")) { continue; } totalBookings++; @@ -174,6 +176,7 @@ const _getBusyTimesFromDurationLimits = async ( duration: number | undefined, eventType: NonNullable, limitManager: LimitManager, + timeZone: string, rescheduleUid?: string ) => { for (const key of descendingLimitKeys) { @@ -215,7 +218,7 @@ const _getBusyTimesFromDurationLimits = async ( for (const booking of bookings) { // consider booking part of period independent of end date - if (!dayjs(booking.start).isBetween(periodStart, periodEnd)) { + if (!isBookingWithinPeriod(booking, periodStart, periodEnd, timeZone || "UTC")) { continue; } totalDuration += dayjs(booking.end).diff(dayjs(booking.start), "minute"); diff --git a/packages/lib/intervalLimits/utils.ts b/packages/lib/intervalLimits/utils.ts new file mode 100644 index 0000000000..a02ef42ad8 --- /dev/null +++ b/packages/lib/intervalLimits/utils.ts @@ -0,0 +1,74 @@ +import type { Dayjs } from "@calcom/dayjs"; +import dayjs from "@calcom/dayjs"; +import type { EventBusyDetails } from "@calcom/types/Calendar"; + +import type { IntervalLimitUnit } from "./intervalLimitSchema"; + +/** + * Extracts date parameters from a booking and period + * @param booking The booking to extract date parameters from + * @param periodStart The start of the period + * @param periodEnd The end of the period + * @param timeZone The timezone to use + * @returns Object containing extracted date parameters + */ +export function extractDateParameters( + booking: EventBusyDetails, + periodStart: Dayjs, + periodEnd: Dayjs, + timeZone: string +) { + const bookingStart = dayjs(booking.start).tz(timeZone); + const bookingDay = bookingStart.format("YYYY-MM-DD"); + const periodStartDay = periodStart.format("YYYY-MM-DD"); + const periodEndDay = periodEnd.format("YYYY-MM-DD"); + + return { + bookingStart, + bookingDay, + periodStartDay, + periodEndDay, + }; +} + +/** + * Checks if a booking is within a given period + * @param booking The booking to check + * @param periodStart The start of the period + * @param periodEnd The end of the period + * @param timeZone The timezone to use + * @returns Boolean indicating if the booking is within the period + */ +export function isBookingWithinPeriod( + booking: EventBusyDetails, + periodStart: Dayjs, + periodEnd: Dayjs, + timeZone: string +) { + const { bookingDay, periodStartDay, periodEndDay } = extractDateParameters( + booking, + periodStart, + periodEnd, + timeZone + ); + + return !(bookingDay < periodStartDay || bookingDay > periodEndDay); +} + +/** + * Gets unit from a busy time's start and end dates + * @param start The start date + * @param end The end date + * @returns The appropriate interval limit unit + */ +export function getUnitFromBusyTime(start: Dayjs, end: Dayjs): IntervalLimitUnit { + if (end.diff(start, "year") >= 1) { + return "year"; + } else if (end.diff(start, "month") >= 1) { + return "month"; + } else if (end.diff(start, "week") >= 1) { + return "week"; + } else { + return "day"; + } +} diff --git a/packages/trpc/server/routers/viewer/slots/util.ts b/packages/trpc/server/routers/viewer/slots/util.ts index 285964f2ef..1e332b242a 100644 --- a/packages/trpc/server/routers/viewer/slots/util.ts +++ b/packages/trpc/server/routers/viewer/slots/util.ts @@ -30,6 +30,7 @@ import { parseBookingLimit } from "@calcom/lib/intervalLimits/isBookingLimits"; import { parseDurationLimit } from "@calcom/lib/intervalLimits/isDurationLimits"; import LimitManager from "@calcom/lib/intervalLimits/limitManager"; import { checkBookingLimit } from "@calcom/lib/intervalLimits/server/checkBookingLimits"; +import { isBookingWithinPeriod, getUnitFromBusyTime } from "@calcom/lib/intervalLimits/utils"; import { calculatePeriodLimits, isTimeOutOfBounds, @@ -898,12 +899,7 @@ const getBusyTimesFromLimitsForUsers = async ( let totalBookings = 0; for (const booking of busyTimesFromLimitsBookings) { - const bookingStart = dayjs(booking.start).tz(timeZone); - const bookingDay = bookingStart.format("YYYY-MM-DD"); - const periodStartDay = periodStart.format("YYYY-MM-DD"); - const periodEndDay = periodEnd.format("YYYY-MM-DD"); - - if (bookingDay < periodStartDay || bookingDay > periodEndDay) { + if (!isBookingWithinPeriod(booking, periodStart, periodEnd, timeZone)) { continue; } @@ -924,18 +920,7 @@ const getBusyTimesFromLimitsForUsers = async ( for (const busyTime of globalLimitManager.getBusyTimes()) { const start = dayjs(busyTime.start); const end = dayjs(busyTime.end); - - let unit: "year" | "month" | "week" | "day"; - - if (end.diff(start, "year") >= 1) { - unit = "year"; - } else if (end.diff(start, "month") >= 1) { - unit = "month"; - } else if (end.diff(start, "week") >= 1) { - unit = "week"; - } else { - unit = "day"; - } + const unit = getUnitFromBusyTime(start, end); limitManager.addBusyTime(start, unit, timeZone); } @@ -978,12 +963,7 @@ const getBusyTimesFromLimitsForUsers = async ( let totalBookings = 0; for (const booking of userBookings) { - const bookingStart = dayjs(booking.start).tz(timeZone); - const bookingDay = bookingStart.format("YYYY-MM-DD"); - const periodStartDay = periodStart.format("YYYY-MM-DD"); - const periodEndDay = periodEnd.format("YYYY-MM-DD"); - - if (bookingDay < periodStartDay || bookingDay > periodEndDay) { + if (!isBookingWithinPeriod(booking, periodStart, periodEnd, timeZone)) { continue; } @@ -1037,12 +1017,7 @@ const getBusyTimesFromLimitsForUsers = async ( let totalDuration = selectedDuration; for (const booking of userBookings) { - const bookingStart = dayjs(booking.start).tz(timeZone); - const bookingDay = bookingStart.format("YYYY-MM-DD"); - const periodStartDay = periodStart.format("YYYY-MM-DD"); - const periodEndDay = periodEnd.format("YYYY-MM-DD"); - - if (bookingDay < periodStartDay || bookingDay > periodEndDay) { + if (!isBookingWithinPeriod(booking, periodStart, periodEnd, timeZone)) { continue; } @@ -1115,12 +1090,7 @@ const getBusyTimesFromTeamLimitsForUsers = async ( let totalBookings = 0; for (const booking of busyTimes) { - const bookingStart = dayjs(booking.start).tz(timeZone); - const bookingDay = bookingStart.format("YYYY-MM-DD"); - const periodStartDay = periodStart.format("YYYY-MM-DD"); - const periodEndDay = periodEnd.format("YYYY-MM-DD"); - - if (bookingDay < periodStartDay || bookingDay > periodEndDay) { + if (!isBookingWithinPeriod(booking, periodStart, periodEnd, timeZone)) { continue; } @@ -1142,18 +1112,7 @@ const getBusyTimesFromTeamLimitsForUsers = async ( for (const busyTime of globalLimitManager.getBusyTimes()) { const start = dayjs(busyTime.start); const end = dayjs(busyTime.end); - - let unit: "year" | "month" | "week" | "day"; - - if (end.diff(start, "year") >= 1) { - unit = "year"; - } else if (end.diff(start, "month") >= 1) { - unit = "month"; - } else if (end.diff(start, "week") >= 1) { - unit = "week"; - } else { - unit = "day"; - } + const unit = getUnitFromBusyTime(start, end); limitManager.addBusyTime(start, unit, timeZone); } @@ -1209,12 +1168,7 @@ const getBusyTimesFromTeamLimitsForUsers = async ( let totalBookings = 0; for (const booking of userBusyTimes) { - const bookingStart = dayjs(booking.start).tz(timeZone); - const bookingDay = bookingStart.format("YYYY-MM-DD"); - const periodStartDay = periodStart.format("YYYY-MM-DD"); - const periodEndDay = periodEnd.format("YYYY-MM-DD"); - - if (bookingDay < periodStartDay || bookingDay > periodEndDay) { + if (!isBookingWithinPeriod(booking, periodStart, periodEnd, timeZone)) { continue; }