mirror of
https://github.com/multipleof4/lynchmark.git
synced 2026-01-14 16:47:55 +00:00
71 lines
2.3 KiB
JavaScript
71 lines
2.3 KiB
JavaScript
const findAvailableSlots = async (calendar1, calendar2, constraints) => {
|
|
const { DateTime, Interval } = await import('https://cdn.skypack.dev/luxon@3.0.1')
|
|
|
|
const { durationMinutes, searchRange, workHours } = constraints
|
|
const workStart = DateTime.fromISO(`${searchRange.start.split('T')[0]}T${workHours.start}:00Z`)
|
|
const workEnd = DateTime.fromISO(`${searchRange.start.split('T')[0]}T${workHours.end}:00Z`)
|
|
const searchStart = DateTime.fromISO(searchRange.start)
|
|
const searchEnd = DateTime.fromISO(searchRange.end)
|
|
|
|
const mergeCalendars = (cal1, cal2) => {
|
|
const allSlots = [...cal1, ...cal2].map(slot => ({
|
|
start: DateTime.fromISO(slot.start),
|
|
end: DateTime.fromISO(slot.end)
|
|
})).sort((a, b) => a.start - b.start)
|
|
|
|
return allSlots.reduce((merged, current) => {
|
|
if (merged.length === 0) return [current]
|
|
|
|
const last = merged[merged.length - 1]
|
|
if (current.start <= last.end) {
|
|
last.end = current.end > last.end ? current.end : last.end
|
|
return merged
|
|
}
|
|
|
|
return [...merged, current]
|
|
}, [])
|
|
}
|
|
|
|
const mergedBusy = mergeCalendars(calendar1, calendar2)
|
|
const freeIntervals = []
|
|
|
|
let currentStart = searchStart
|
|
for (const busy of mergedBusy) {
|
|
if (busy.start > currentStart) {
|
|
freeIntervals.push(Interval.fromDateTimes(currentStart, busy.start))
|
|
}
|
|
currentStart = busy.end > currentStart ? busy.end : currentStart
|
|
}
|
|
|
|
if (currentStart < searchEnd) {
|
|
freeIntervals.push(Interval.fromDateTimes(currentStart, searchEnd))
|
|
}
|
|
|
|
const availableSlots = freeIntervals.flatMap(interval => {
|
|
const slots = []
|
|
let slotStart = interval.start
|
|
|
|
while (slotStart.plus({ minutes: durationMinutes }) <= interval.end) {
|
|
const slotEnd = slotStart.plus({ minutes: durationMinutes })
|
|
const slotInterval = Interval.fromDateTimes(slotStart, slotEnd)
|
|
|
|
if (slotInterval.engulfs(workStart) && slotInterval.engulfs(workEnd)) {
|
|
slots.push({
|
|
start: slotStart.toISO(),
|
|
end: slotEnd.toISO()
|
|
})
|
|
}
|
|
|
|
slotStart = slotEnd
|
|
}
|
|
|
|
return slots
|
|
})
|
|
|
|
return availableSlots.filter(slot => {
|
|
const slotStart = DateTime.fromISO(slot.start)
|
|
const slotEnd = DateTime.fromISO(slot.end)
|
|
return slotStart >= workStart && slotEnd <= workEnd
|
|
})
|
|
}
|
|
export default findAvailableSlots; |