'use client'; import React, { useState, useMemo } from 'react'; import Link from 'next/link'; import { Search, Filter, X, Calendar, Clock, Package, Lock, Unlock, Ghost, FlaskConical, AlertCircle, Trash2, AlertTriangle, PlusCircle } from 'lucide-react'; import { getStorageUrl } from '@/lib/supabase'; import { useSearchParams } from 'next/navigation'; import { validateSession } from '@/services/validate-session'; interface Bottle { id: string; name: string; distillery: string; category: string; abv: number; age: number; image_url: string; purchase_price?: number | null; status: 'sealed' | 'open' | 'sampled' | 'empty'; created_at: string; last_tasted?: string | null; is_whisky?: boolean; confidence?: number; } interface BottleCardProps { bottle: Bottle; sessionId?: string | null; } function BottleCard({ bottle, sessionId }: BottleCardProps) { const statusConfig = { open: { icon: Unlock, color: 'bg-amber-500/80 border-amber-400/50', label: 'Offen' }, sampled: { icon: FlaskConical, color: 'bg-purple-500/80 border-purple-400/50', label: 'Sample' }, empty: { icon: Ghost, color: 'bg-zinc-500/80 border-zinc-400/50', label: 'Leer' }, sealed: { icon: Lock, color: 'bg-blue-600/80 border-blue-400/50', label: 'Versiegelt' }, }; const StatusIcon = statusConfig[bottle.status as keyof typeof statusConfig]?.icon || Lock; const statusStyle = statusConfig[bottle.status as keyof typeof statusConfig] || statusConfig.sealed; return (
{bottle.name}
{sessionId && (
ZU SESSION HINZUFÜGEN
)} {bottle.last_tasted && (
{new Date(bottle.last_tasted).toLocaleDateString('de-DE')}
)}
{statusStyle.label}

{bottle.distillery}

{(bottle.is_whisky === false || (bottle.confidence && bottle.confidence < 70)) && (
REVIEW
)}

{bottle.name || 'Unbekannte Flasche'}

{bottle.category} {bottle.abv}% VOL
Hinzugefügt am {new Date(bottle.created_at).toLocaleDateString('de-DE')}
); } interface BottleGridProps { bottles: any[]; } export default function BottleGrid({ bottles }: BottleGridProps) { const searchParams = useSearchParams(); const sessionId = searchParams.get('session_id'); const [validatedSessionId, setValidatedSessionId] = useState(null); React.useEffect(() => { const checkSession = async () => { if (sessionId) { const isValid = await validateSession(sessionId); setValidatedSessionId(isValid ? sessionId : null); } else { setValidatedSessionId(null); } }; checkSession(); }, [sessionId]); const [searchQuery, setSearchQuery] = useState(''); const [selectedCategory, setSelectedCategory] = useState(null); const [selectedDistillery, setSelectedDistillery] = useState(null); const [selectedStatus, setSelectedStatus] = useState(null); const [sortBy, setSortBy] = useState<'name' | 'last_tasted' | 'created_at'>('created_at'); const categories = useMemo(() => { const cats = new Set(bottles.map(b => b.category).filter(Boolean)); return Array.from(cats).sort() as string[]; }, [bottles]); const distilleries = useMemo(() => { const dists = new Set(bottles.map(b => b.distillery).filter(Boolean)); return Array.from(dists).sort() as string[]; }, [bottles]); const filteredBottles = useMemo(() => { const result = bottles.filter((bottle) => { const searchLower = searchQuery.toLowerCase(); const tastingNotesMatch = bottle.tastings?.some((t: any) => (t.nose_notes?.toLowerCase().includes(searchLower)) || (t.palate_notes?.toLowerCase().includes(searchLower)) || (t.finish_notes?.toLowerCase().includes(searchLower)) ); const matchesSearch = bottle.name.toLowerCase().includes(searchLower) || bottle.distillery?.toLowerCase().includes(searchLower) || bottle.category?.toLowerCase().includes(searchLower) || tastingNotesMatch; const matchesCategory = !selectedCategory || bottle.category === selectedCategory; const matchesDistillery = !selectedDistillery || bottle.distillery === selectedDistillery; const matchesStatus = !selectedStatus || bottle.status === selectedStatus; return matchesSearch && matchesCategory && matchesDistillery && matchesStatus; }); // Sorting logic return result.sort((a, b) => { if (sortBy === 'name') { return (a.name || '').localeCompare(b.name || ''); } else if (sortBy === 'last_tasted') { const dateA = a.last_tasted ? new Date(a.last_tasted).getTime() : 0; const dateB = b.last_tasted ? new Date(b.last_tasted).getTime() : 0; return dateB - dateA; } else { // sortBy === 'created_at' return new Date(b.created_at).getTime() - new Date(a.created_at).getTime(); } }); }, [bottles, searchQuery, selectedCategory, selectedDistillery, selectedStatus, sortBy]); if (!bottles || bottles.length === 0) { return (

Noch keine Flaschen im Vault. Zeit für den ersten Scan! 🥃

); } return (
{/* Search and Filters */}
setSearchQuery(e.target.value)} className="w-full pl-10 pr-4 py-3 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl focus:ring-2 focus:ring-amber-500 outline-none transition-all" /> {searchQuery && ( )}
{/* Category Filter */}
Kategorie
{categories.map((cat) => ( ))}
{/* Distillery Filter */}
Distillery
{distilleries.map((dist) => ( ))}
{/* Status Filter */}
Status
{['sealed', 'open', 'sampled', 'empty'].map((status) => ( ))}
{/* Grid */} {filteredBottles.length > 0 ? (
{filteredBottles.map((bottle) => ( ))}
) : (

Keine Flaschen gefunden, die deinen Filtern entsprechen. 🔎

)}
); }