Files
Dramlog-Prod/src/app/page.tsx

174 lines
7.0 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
import CameraCapture from "@/components/CameraCapture";
import BottleGrid from "@/components/BottleGrid";
import AuthForm from "@/components/AuthForm";
import BuddyList from "@/components/BuddyList";
import SessionList from "@/components/SessionList";
export default function Home() {
const supabase = createClientComponentClient();
const [bottles, setBottles] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [user, setUser] = useState<any>(null);
const [fetchError, setFetchError] = useState<string | null>(null);
useEffect(() => {
// Check session
const checkUser = async () => {
try {
const { data: { session }, error } = await supabase.auth.getSession();
console.log('Initial session check:', session ? 'User logged in' : 'No session');
if (error) {
console.error('Session retrieval error:', error);
}
setUser(session?.user ?? null);
if (session?.user) {
fetchCollection();
}
} catch (err) {
console.error('Fatal error checking user:', err);
setUser(null);
} finally {
setIsLoading(false);
}
};
checkUser();
// Listen for auth changes
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
console.log('Auth state change:', event, session?.user ? 'User logged in' : 'No user');
setUser(session?.user ?? null);
if (session?.user) {
fetchCollection();
} else {
setBottles([]);
}
});
return () => subscription.unsubscribe();
}, []);
const fetchCollection = async () => {
setIsLoading(true);
try {
// Fetch bottles with their latest tasting date
const { data, error } = await supabase
.from('bottles')
.select(`
*,
tastings (
created_at
)
`)
.order('created_at', { ascending: false });
if (error) {
console.error('Supabase fetch error:', error);
throw error;
}
console.log(`Fetched ${data?.length || 0} bottles from Supabase`);
// Process data to get the absolute latest tasting date for each bottle
const processedBottles = (data || []).map(bottle => {
const lastTasted = bottle.tastings && bottle.tastings.length > 0
? bottle.tastings.reduce((latest: string, current: any) =>
new Date(current.created_at) > new Date(latest) ? current.created_at : latest,
bottle.tastings[0].created_at
)
: null;
return {
...bottle,
last_tasted: lastTasted
};
});
setBottles(processedBottles);
} catch (err: any) {
console.error('Detailed fetch error:', err);
setFetchError(err.message || JSON.stringify(err));
} finally {
setIsLoading(false);
}
};
const handleLogout = async () => {
await supabase.auth.signOut();
};
if (!user) {
return (
<main className="flex min-h-screen flex-col items-center justify-center p-6 bg-zinc-50 dark:bg-black">
<div className="mb-12 text-center">
<h1 className="text-5xl font-black text-zinc-900 dark:text-white tracking-tighter mb-4">
WHISKY<span className="text-amber-600">VAULT</span>
</h1>
<p className="text-zinc-500 max-w-sm mx-auto">Scanne deine Flaschen, tracke deine Tastings und verwalte deinen Keller.</p>
</div>
<AuthForm />
</main>
);
}
return (
<main className="flex min-h-screen flex-col items-center gap-6 md:gap-12 p-4 md:p-24 bg-zinc-50 dark:bg-black">
<div className="z-10 max-w-5xl w-full flex flex-col items-center gap-8">
<header className="w-full flex justify-between items-center">
<h1 className="text-4xl font-black text-zinc-900 dark:text-white tracking-tighter">
WHISKY<span className="text-amber-600">VAULT</span>
</h1>
<button
onClick={handleLogout}
className="text-sm font-medium text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-300 transition-colors"
>
Abmelden
</button>
</header>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 w-full max-w-5xl">
<div className="flex flex-col gap-8">
<CameraCapture onSaveComplete={fetchCollection} />
<SessionList />
</div>
<div>
<BuddyList />
</div>
</div>
<div className="w-full mt-12">
<h2 className="text-2xl font-bold mb-6 text-zinc-800 dark:text-zinc-100 flex items-center gap-3">
Deine Sammlung
<span className="text-sm font-normal text-zinc-500 bg-zinc-100 dark:bg-zinc-800 px-3 py-1 rounded-full">
{bottles.length}
</span>
</h2>
{isLoading ? (
<div className="flex justify-center py-12">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-amber-600"></div>
</div>
) : fetchError ? (
<div className="p-8 bg-zinc-100 dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 rounded-3xl text-center">
<p className="text-zinc-800 dark:text-zinc-200 font-bold mb-2">Sammlung konnte nicht geladen werden</p>
<p className="text-zinc-500 text-sm italic mb-4">Möglicherweise müssen die Datenbank-Regeln aktualisiert werden.</p>
<button
onClick={fetchCollection}
className="px-6 py-2 bg-amber-600 hover:bg-amber-700 text-white rounded-xl text-xs font-bold uppercase tracking-widest transition-all"
>
Erneut versuchen
</button>
</div>
) : (
<BottleGrid bottles={bottles} />
)}
</div>
</div>
</main>
);
}