mirror of
https://github.com/multipleof4/lynchmark.git
synced 2026-01-14 16:47:55 +00:00
45 lines
1.6 KiB
JavaScript
45 lines
1.6 KiB
JavaScript
export const findAvailableSlots = async (cal1, cal2, { durationMinutes: dur, searchRange: rng, workHours: wh }) => {
|
|
const { DateTime, Interval } = await import('https://cdn.skypack.dev/luxon');
|
|
const zone = 'utc';
|
|
const fromISO = t => DateTime.fromISO(t, { zone });
|
|
const searchIv = Interval.fromDateTimes(fromISO(rng.start), fromISO(rng.end));
|
|
|
|
const busy = [...cal1, ...cal2]
|
|
.map(s => Interval.fromDateTimes(fromISO(s.start), fromISO(s.end)))
|
|
.filter(i => i.isValid && i.overlaps(searchIv))
|
|
.sort((a, b) => a.start - b.start)
|
|
.reduce((acc, cur) => {
|
|
const last = acc[acc.length - 1];
|
|
return last && (last.overlaps(cur) || last.abutsStart(cur))
|
|
? [...acc.slice(0, -1), last.union(cur)]
|
|
: [...acc, cur];
|
|
}, []);
|
|
|
|
const slots = [];
|
|
let curDate = searchIv.start.startOf('day');
|
|
const [wsH, wsM] = wh.start.split(':');
|
|
const [weH, weM] = wh.end.split(':');
|
|
|
|
while (curDate < searchIv.end) {
|
|
const workStart = curDate.set({ hour: wsH, minute: wsM });
|
|
const workEnd = curDate.set({ hour: weH, minute: weM });
|
|
const workIv = Interval.fromDateTimes(workStart, workEnd).intersection(searchIv);
|
|
|
|
if (workIv && workIv.isValid) {
|
|
let free = [workIv];
|
|
busy.forEach(b => { free = free.flatMap(f => f.difference(b)); });
|
|
|
|
free.forEach(iv => {
|
|
iv.splitBy({ minutes: dur }).forEach(chunk => {
|
|
if (Math.abs(chunk.length('minutes') - dur) < 0.01) {
|
|
slots.push({ start: chunk.start.toISO(), end: chunk.end.toISO() });
|
|
}
|
|
});
|
|
});
|
|
}
|
|
curDate = curDate.plus({ days: 1 });
|
|
}
|
|
|
|
return slots;
|
|
};
|
|
export default findAvailableSlots; |