mirror of
https://github.com/multipleof4/lynchmark.git
synced 2026-01-13 16:17:54 +00:00
43 lines
1.6 KiB
JavaScript
43 lines
1.6 KiB
JavaScript
export const findAvailableSlots = async (calA, calB, { durationMinutes, searchRange, workHours }) => {
|
|
const { DateTime, Interval } = await import('https://cdn.jsdelivr.net/npm/luxon@3.4.4/+esm');
|
|
const zone = 'utc';
|
|
const toDt = (iso) => DateTime.fromISO(iso, { zone });
|
|
const totalRange = Interval.fromDateTimes(toDt(searchRange.start), toDt(searchRange.end));
|
|
const busy = Interval.merge([...calA, ...calB].map(({ start, end }) => Interval.fromDateTimes(toDt(start), toDt(end))));
|
|
|
|
const results = [];
|
|
let cursor = totalRange.start.startOf('day');
|
|
|
|
while (cursor < totalRange.end) {
|
|
const [startH, startM] = workHours.start.split(':');
|
|
const [endH, endM] = workHours.end.split(':');
|
|
|
|
const dailyWork = Interval.fromDateTimes(
|
|
cursor.set({ hour: +startH, minute: +startM }),
|
|
cursor.set({ hour: +endH, minute: +endM })
|
|
);
|
|
|
|
const effective = dailyWork.intersection(totalRange);
|
|
|
|
if (effective?.isValid && !effective.isEmpty()) {
|
|
let available = [effective];
|
|
for (const b of busy) {
|
|
if (b.overlaps(effective)) {
|
|
available = available.flatMap(a => a.difference(b));
|
|
}
|
|
}
|
|
|
|
for (const period of available) {
|
|
period.splitBy({ minutes: durationMinutes }).forEach(slot => {
|
|
if (slot.isValid && slot.toDuration('minutes').minutes === durationMinutes) {
|
|
results.push({ start: slot.start.toISO(), end: slot.end.toISO() });
|
|
}
|
|
});
|
|
}
|
|
}
|
|
cursor = cursor.plus({ days: 1 });
|
|
}
|
|
|
|
return results;
|
|
};
|
|
export default findAvailableSlots; |