Created
June 2, 2024 03:37
-
-
Save ishanray/9fe43e603282001cc10ede0489714091 to your computer and use it in GitHub Desktop.
Elicit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { serverSupabaseClient } from '#supabase/server' | |
import { DateTime, Duration, Interval } from 'luxon' | |
export class Slotter { | |
from: DateTime | |
to: DateTime | |
timeblocks: { | |
dow: number | |
}[] | |
group: Object | |
intervals: Interval[] | |
bookings: Object[] | |
constructor({ from, to, timeblocks, group, bookings }) { | |
this.from = from | |
this.to = to | |
this.timeblocks = timeblocks | |
this.group = group | |
this.bookings = bookings | |
this.intervals = [] | |
} | |
get availableDates() { | |
let interval = Interval.fromDateTimes(this.from, this.to).splitBy( | |
Duration.fromObject({ day: 1 }), | |
) | |
interval = interval | |
.filter(i => this.timeblocks.some(t => t.dow == i.start.weekday)) | |
.map(interval => { | |
if (!interval) return null | |
let matchingTimeblock = this.timeblocks.find( | |
t => t.dow == interval.start.weekday, | |
) | |
const startHour = matchingTimeblock.start_time | |
? DateTime.fromISO(matchingTimeblock.start_time).hour | |
: interval.start?.startOf('day').hour | |
const startMinute = matchingTimeblock.start_time | |
? DateTime.fromISO(matchingTimeblock.start_time).minute | |
: interval.start?.startOf('day').minute | |
const endHour = matchingTimeblock.end_time | |
? DateTime.fromISO(matchingTimeblock.end_time).hour | |
: interval.start?.endOf('day').hour | |
const endMinute = matchingTimeblock.end_time | |
? DateTime.fromISO(matchingTimeblock.end_time).minute | |
: interval.start?.endOf('day').minute | |
interval = interval.set({ | |
start: DateTime.fromObject({ | |
day: interval.start?.day, | |
month: interval.start?.month, | |
year: interval.start?.year, | |
hour: startHour, | |
minute: startMinute, | |
}), | |
end: DateTime.fromObject({ | |
day: interval.start?.day, | |
month: interval.start?.month, | |
year: interval.start?.year, | |
hour: endHour, | |
minute: endMinute, | |
}), | |
}) | |
return interval | |
}) | |
this.intervals = interval | |
interval = interval.map(i => i.start) | |
return interval | |
} | |
get availableSlots() { | |
if (!this.availableDates || !this.availableDates.length > 0) return [] | |
const slots = this.intervals[0] | |
.splitBy(Duration.fromMillis(this.group.duration * 1000 * 60)) | |
.filter(this.alreadyBooked) | |
console.log(this.group.duration) | |
return slots | |
} | |
alreadyBooked = (interval: Interval) => { | |
if ( | |
this.bookings | |
.map(b => Interval.fromISO(b.interval)) | |
.some(b => b.intersection(interval)) | |
) | |
return false | |
return true | |
} | |
} | |
export default defineEventHandler(async event => { | |
const { groupId, from, to } = getQuery(event) | |
const client = serverSupabaseClient(event) | |
const { data: timeblocks } = await client | |
.from('timeblocks') | |
.select('*, groups(*)') | |
.eq('group_id', groupId) | |
const { data: bookings } = await client | |
.from('bookings') | |
.select('*') | |
.eq('group_id', groupId) | |
const slotter = new Slotter({ | |
timeblocks, | |
bookings, | |
group: timeblocks[0].groups, | |
from: DateTime.fromISO(from), | |
to: DateTime.fromISO(to), | |
}) | |
return { | |
availableDates: slotter.availableDates, | |
availableSlots: slotter.availableSlots, | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment