* perf: optimize slot conflict checking from O(n²) to O(n log n) - Replace nested mapping with pre-sorted busy slots for faster lookups - Use early termination when busy slots are sorted by start time - Maintain exact same interface and behavior as original checkForConflicts - All existing tests pass, preserving edge case handling - Reduces complexity from O(available slots × busy slots) to O(n log n) Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * refactor: move O(n log n) optimization to checkForConflicts function - Replace inline optimization with optimized checkForConflicts function - Maintain same performance while improving code architecture - Avoid duplication of conflict checking logic - Keep all existing interfaces and behavior unchanged Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * test: add comprehensive unit tests for checkForConflicts function - Add 20 additional test cases covering edge cases and boundary conditions - Test multiple busy periods scenarios and complex overlaps - Comprehensive currentSeats handling scenarios - Timezone and cross-day boundary testing - Performance testing with large datasets - Fix invalid date generation in test data that was causing NaN conflicts - Achieve near 100% coverage of all conflict scenarios documented in function comments - Verify behavioral equivalence between original O(n²) and optimized O(n log n) implementations Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * Simple, safe performance tweak * Explicitly define the input of busy to be either Date or Dayjs, not string * EventBusyDate must ALWAYS be a type that supports valueOf * Revert "EventBusyDate must ALWAYS be a type that supports valueOf" This reverts commit 35b572266219d64c22db3c3e24b0cb6ca7a901a6. * Revert "Explicitly define the input of busy to be either Date or Dayjs, not string" This reverts commit 902f29708e4b7990a4e5e2865cab2f18ab3e44f0. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Alex van Andel <me@alexvanandel.com>
51 lines
1.3 KiB
TypeScript
51 lines
1.3 KiB
TypeScript
import type { Dayjs } from "dayjs";
|
|
|
|
import dayjs from "@calcom/dayjs";
|
|
import type { CurrentSeats } from "@calcom/lib/getUserAvailability";
|
|
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 slotStart = time.valueOf();
|
|
const slotEnd = slotStart + eventLength * 60 * 1000;
|
|
|
|
const sortedBusyTimes = busy
|
|
.map((busyTime) => ({
|
|
start: dayjs.utc(busyTime.start).valueOf(),
|
|
end: dayjs.utc(busyTime.end).valueOf(),
|
|
}))
|
|
.sort((a, b) => a.start - b.start);
|
|
|
|
for (const busyTime of sortedBusyTimes) {
|
|
if (busyTime.start >= slotEnd) {
|
|
break;
|
|
}
|
|
if (busyTime.end <= slotStart) {
|
|
continue;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|