Skip to content

Instantly share code, notes, and snippets.

@ishanray
Created June 2, 2024 03:37
Show Gist options
  • Save ishanray/9fe43e603282001cc10ede0489714091 to your computer and use it in GitHub Desktop.
Save ishanray/9fe43e603282001cc10ede0489714091 to your computer and use it in GitHub Desktop.
Elicit
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