mirror of
https://github.com/multipleof4/lynchmark.git
synced 2026-01-14 16:47:55 +00:00
69 lines
2.2 KiB
JavaScript
69 lines
2.2 KiB
JavaScript
const findAvailableSlots = async (calendar1, calendar2, constraints) => {
|
|
const { startOfDay, addMinutes, parseISO, formatISO } = await import('https://cdn.jsdelivr.net/npm/date-fns@3.0.0/+esm');
|
|
|
|
const { durationMinutes, searchRange, workHours } = constraints;
|
|
const searchStart = parseISO(searchRange.start);
|
|
const searchEnd = parseISO(searchRange.end);
|
|
|
|
const [workStartHour, workStartMin] = workHours.start.split(':').map(Number);
|
|
const [workEndHour, workEndMin] = workHours.end.split(':').map(Number);
|
|
const workStartMs = (workStartHour * 60 + workStartMin) * 60000;
|
|
const workEndMs = (workEndHour * 60 + workEndMin) * 60000;
|
|
|
|
const allBusy = [...calendar1, ...calendar2]
|
|
.map(({ start, end }) => ({ start: parseISO(start), end: parseISO(end) }))
|
|
.sort((a, b) => a.start - b.start);
|
|
|
|
const merged = [];
|
|
for (const slot of allBusy) {
|
|
if (merged.length && slot.start <= merged[merged.length - 1].end) {
|
|
merged[merged.length - 1].end = new Date(Math.max(merged[merged.length - 1].end, slot.end));
|
|
} else {
|
|
merged.push({ start: slot.start, end: slot.end });
|
|
}
|
|
}
|
|
|
|
const free = [];
|
|
let current = searchStart;
|
|
for (const busy of merged) {
|
|
if (current < busy.start) {
|
|
free.push({ start: current, end: busy.start });
|
|
}
|
|
current = new Date(Math.max(current, busy.end));
|
|
}
|
|
if (current < searchEnd) {
|
|
free.push({ start: current, end: searchEnd });
|
|
}
|
|
|
|
const slots = [];
|
|
for (const period of free) {
|
|
let slotStart = period.start;
|
|
|
|
while (slotStart < period.end) {
|
|
const dayStart = startOfDay(slotStart);
|
|
const slotStartMs = slotStart - dayStart;
|
|
const slotEnd = addMinutes(slotStart, durationMinutes);
|
|
const slotEndMs = slotEnd - dayStart;
|
|
|
|
if (slotEnd > period.end) break;
|
|
|
|
const endsNextDay = slotEnd - startOfDay(slotEnd) < slotEndMs % 86400000;
|
|
|
|
if (!endsNextDay &&
|
|
slotStartMs >= workStartMs &&
|
|
slotEndMs <= workEndMs &&
|
|
slotStart >= searchStart &&
|
|
slotEnd <= searchEnd) {
|
|
slots.push({
|
|
start: formatISO(slotStart),
|
|
end: formatISO(slotEnd)
|
|
});
|
|
}
|
|
|
|
slotStart = slotEnd;
|
|
}
|
|
}
|
|
|
|
return slots;
|
|
};
|
|
export default findAvailableSlots; |