feat: add caching for backend objects

This commit is contained in:
2026-04-21 19:38:57 -04:00
parent 5b4955f07e
commit 7f1e82acc2
14 changed files with 637 additions and 62 deletions

View File

@@ -149,6 +149,9 @@ import {
todayToronto, toDateToronto, addDays,
fmtTime, fmtDateLong, fmtDayHeader, weekDates, utcRange,
} from '~/utils/toronto'
import { useAppCache } from '~/composables/useAppCache'
import { useOfflineStatus } from '~/composables/useOfflineStatus'
import { useBookingDraft } from '~/composables/useBookingDraft'
type Boat = Database['public']['Tables']['boats']['Row']
type Interval = Database['public']['Tables']['intervals']['Row']
@@ -167,6 +170,9 @@ definePageMeta({ layout: false, middleware: ['auth'] })
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const supabase = useSupabaseClient() as any
const cache = useAppCache()
const { isOnline } = useOfflineStatus()
const { set: setDraft } = useBookingDraft()
// ── Responsive ──────────────────────────────────────────────
const isMobile = ref(true)
@@ -200,23 +206,42 @@ const intervals = ref<Interval[]>([])
const slotViews = ref<SlotView[]>([])
async function fetchBoats() {
if (!isOnline.value) {
const cached = cache.peek<Boat[]>('boats')
if (cached) boats.value = cached
return
}
const { data } = await supabase.from('boats').select('*').order('name')
boats.value = data ?? []
if (data) cache.set('boats', data)
}
async function fetchSchedule() {
loading.value = true
const dates = visibleDates.value
const { from, to } = utcRange(dates[0]!, dates[dates.length - 1]!)
const wk = cache.weekKey(dates[0]!)
if (!isOnline.value) {
const cachedIntervals = cache.peek<Interval[]>(`intervals:${wk}`)
const cachedSlots = cache.peek<SlotView[]>(`slots:${wk}`)
if (cachedIntervals) intervals.value = cachedIntervals
if (cachedSlots) slotViews.value = cachedSlots
loading.value = false
return
}
const { from, to } = utcRange(dates[0]!, dates[dates.length - 1]!)
const [intRes, slotRes] = await Promise.all([
supabase.from('intervals').select('*').gte('start_time', from).lte('start_time', to),
supabase.from('reservation_slots').select('*').gte('start_time', from).lte('start_time', to),
])
intervals.value = intRes.data ?? []
slotViews.value = slotRes.data ?? []
loading.value = false
intervals.value = intRes.data ?? []
slotViews.value = slotRes.data ?? []
loading.value = false
if (intRes.data) cache.set(`intervals:${wk}`, intRes.data)
if (slotRes.data) cache.set(`slots:${wk}`, slotRes.data)
}
onMounted(async () => {
@@ -284,14 +309,9 @@ function slotLabelShort(slot: SlotBlock): string {
}
function bookSlot(slot: SlotBlock) {
router.push({
path: '/reservations/create',
query: {
boatId: slot.boatId,
startTime: slot.startTime,
endTime: slot.endTime,
},
})
const boat = boats.value.find(b => b.id === slot.boatId)
if (boat) setDraft(boat, slot.startTime, slot.endTime)
router.push('/reservations/create')
}
function slotTitle(slot: SlotBlock): string {