Files
calendar/packages/features/bookings/lib/conflictChecker/checkForConflicts.ts
T

60 lines
2.0 KiB
TypeScript

import type { Dayjs } from "dayjs";
import type { CurrentSeats } from "@calcom/core/getUserAvailability";
import dayjs from "@calcom/dayjs";
import type { BufferedBusyTime } from "@calcom/types/BufferedBusyTime";
type BufferedBusyTimes = BufferedBusyTime[];
// if true, there are conflicts.
export function checkForConflicts({
busy,
time,
eventLength,
currentSeats,
}: {
busy: BufferedBusyTimes;
time: Dayjs;
eventLength: number;
currentSeats?: CurrentSeats;
}) {
// Early return
if (!Array.isArray(busy) || busy.length < 1) {
return false; // guaranteed no conflicts when there is no busy times.
}
// no conflicts if some seats are found for the current time slot
if (currentSeats?.some((booking) => booking.startTime.toISOString() === time.toISOString())) {
return false;
}
const slotStartDate = time.utc().toDate();
const slotEndDate = time.add(eventLength, "minutes").utc().toDate();
// handle busy times.
return busy.some((busyTime) => {
const busyStartDate = dayjs.utc(busyTime.start).toDate();
const busyEndDate = dayjs.utc(busyTime.end).toDate();
// First check if there's any overlap at all
// If busy period ends before slot starts or starts after slot ends, there's no overlap
if (busyEndDate <= slotStartDate || busyStartDate >= slotEndDate) {
return false;
}
// Now check all possible overlap scenarios:
// 1. Slot start falls within busy period (inclusive start, exclusive end)
if (slotStartDate >= busyStartDate && slotStartDate < busyEndDate) {
return true;
}
// 2. Slot end falls within busy period (exclusive start, inclusive end)
if (slotEndDate > busyStartDate && slotEndDate <= busyEndDate) {
return true;
}
// 3. Busy period completely contained within slot
if (busyStartDate >= slotStartDate && busyEndDate <= slotEndDate) {
return true;
}
// 4. Slot completely contained within busy period
if (busyStartDate <= slotStartDate && busyEndDate >= slotEndDate) {
return true;
}
return false;
});
}