Files
Dramlog-Prod/src/hooks/useBottleData.ts

84 lines
2.7 KiB
TypeScript

'use client';
import { useState, useEffect, useCallback } from 'react';
import { createClient } from '@/lib/supabase/client';
import { db, type CachedBottle, type CachedTasting } from '@/lib/db';
import { useLiveQuery } from 'dexie-react-hooks';
export function useBottleData(bottleId: string) {
const supabase = createClient();
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Live queries from Dexie
const cachedBottle = useLiveQuery(() => db.cache_bottles.get(bottleId), [bottleId]);
const cachedTastings = useLiveQuery(() =>
db.cache_tastings.where('bottle_id').equals(bottleId).sortBy('created_at'),
[bottleId]
);
const refreshData = useCallback(async () => {
if (!navigator.onLine) {
setLoading(false);
return;
}
try {
// 1. Fetch Bottle
const { data: bottle, error: bottleError } = await supabase
.from('bottles')
.select('*')
.eq('id', bottleId)
.single();
if (bottleError) throw bottleError;
// 2. Fetch Tastings
const { data: tastings, error: tastingsError } = await supabase
.from('tastings')
.select(`
*,
tasting_sessions (id, name),
tasting_tags (
tags (id, name, category)
)
`)
.eq('bottle_id', bottleId)
.order('created_at', { ascending: false });
if (tastingsError) throw tastingsError;
// 3. Update Dexie Cache
await db.cache_bottles.put({
...bottle,
last_updated: Date.now()
});
// Clear old cache for this bottle and put new
await db.cache_tastings.where('bottle_id').equals(bottleId).delete();
if (tastings && tastings.length > 0) {
await db.cache_tastings.bulkAdd(tastings as any);
}
} catch (err: any) {
console.error('Error refreshing bottle data:', err);
setError(err.message);
} finally {
setLoading(false);
}
}, [bottleId, supabase]);
useEffect(() => {
refreshData();
}, [refreshData]);
return {
bottle: cachedBottle,
tastings: cachedTastings ? [...cachedTastings].reverse() : [], // Dexie sorted asc, we want desc
loading: loading && !cachedBottle, // Only show loading if we have nothing at all
error,
refresh: refreshData,
isOffline: !navigator.onLine
};
}