mirror of
https://github.com/multipleof4/lynchmark.git
synced 2026-01-14 08:37:56 +00:00
93 lines
3.0 KiB
JavaScript
93 lines
3.0 KiB
JavaScript
const findAvailableSlots = async (cal1, cal2, constraints) => {
|
|
const { default: dayjs } = await import('https://cdn.skypack.dev/dayjs@1.11.10');
|
|
const { default: utc } = await import('https://cdn.skypack.dev/dayjs@1.11.10/plugin/utc');
|
|
const { default: customParseFormat } = await import('https://cdn.skypack.dev/dayjs@1.11.10/plugin/customParseFormat');
|
|
|
|
dayjs.extend(utc);
|
|
dayjs.extend(customParseFormat);
|
|
|
|
const { durationMinutes, searchRange, workHours } = constraints;
|
|
const duration = durationMinutes * 60000;
|
|
|
|
const merged = [...cal1, ...cal2]
|
|
.map(({ start, end }) => ({ start: new Date(start).getTime(), end: new Date(end).getTime() }))
|
|
.sort((a, b) => a.start - b.start);
|
|
|
|
const busy = merged.reduce((acc, slot) => {
|
|
if (!acc.length) return [slot];
|
|
const last = acc[acc.length - 1];
|
|
if (slot.start <= last.end) {
|
|
last.end = Math.max(last.end, slot.end);
|
|
return acc;
|
|
}
|
|
acc.push(slot);
|
|
return acc;
|
|
}, []);
|
|
|
|
const rangeStart = new Date(searchRange.start).getTime();
|
|
const rangeEnd = new Date(searchRange.end).getTime();
|
|
const [whStart, whEnd] = [workHours.start, workHours.end];
|
|
|
|
const isWithinWorkHours = (ts) => {
|
|
const d = dayjs(ts);
|
|
const time = d.format('HH:mm');
|
|
return time >= whStart && time <= whEnd;
|
|
};
|
|
|
|
const getWorkDayBounds = (ts) => {
|
|
const d = dayjs(ts);
|
|
const [h1, m1] = whStart.split(':').map(Number);
|
|
const [h2, m2] = whEnd.split(':').map(Number);
|
|
return {
|
|
start: d.hour(h1).minute(m1).second(0).millisecond(0).valueOf(),
|
|
end: d.hour(h2).minute(m2).second(0).millisecond(0).valueOf()
|
|
};
|
|
};
|
|
|
|
const slots = [];
|
|
let current = rangeStart;
|
|
|
|
for (let ts = rangeStart; ts < rangeEnd; ts += 86400000) {
|
|
const { start: dayStart, end: dayEnd } = getWorkDayBounds(ts);
|
|
current = Math.max(current, dayStart);
|
|
|
|
busy.forEach(({ start: bStart, end: bEnd }) => {
|
|
if (bStart > current && bStart <= dayEnd) {
|
|
let slotStart = current;
|
|
while (slotStart + duration <= Math.min(bStart, dayEnd)) {
|
|
const slotEnd = slotStart + duration;
|
|
if (isWithinWorkHours(slotStart) && isWithinWorkHours(slotEnd)) {
|
|
slots.push({
|
|
start: new Date(slotStart).toISOString(),
|
|
end: new Date(slotEnd).toISOString()
|
|
});
|
|
}
|
|
slotStart = slotEnd;
|
|
}
|
|
current = Math.max(current, bEnd);
|
|
}
|
|
if (bEnd > current && bEnd <= dayEnd) {
|
|
current = Math.max(current, bEnd);
|
|
}
|
|
});
|
|
|
|
if (current < dayEnd) {
|
|
let slotStart = current;
|
|
while (slotStart + duration <= dayEnd) {
|
|
const slotEnd = slotStart + duration;
|
|
if (isWithinWorkHours(slotStart) && isWithinWorkHours(slotEnd)) {
|
|
slots.push({
|
|
start: new Date(slotStart).toISOString(),
|
|
end: new Date(slotEnd).toISOString()
|
|
});
|
|
}
|
|
slotStart = slotEnd;
|
|
}
|
|
}
|
|
|
|
current = dayStart + 86400000;
|
|
}
|
|
|
|
return slots;
|
|
};
|
|
export default findAvailableSlots; |