84 lines
2.7 KiB
TypeScript
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
|
|
};
|
|
}
|