Files
Dramlog-Prod/src/components/SessionBottomSheet.tsx
robin b57f5dc2ad feat: refine Scan & Taste UI, fix desktop scrolling, and resolve production login fetch error
- Reverted theme from gold to amber and restored legacy typography.
- Refactored ScanAndTasteFlow and TastingEditor for robust desktop scrolling.
- Hotfixed sw.js to completely bypass Supabase Auth/API requests to fix 'Failed to fetch' in production.
- Integrated full tasting note persistence (tags, buddies, sessions).
2025-12-21 22:29:16 +01:00

145 lines
6.2 KiB
TypeScript

'use client';
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Plus, Check, ChevronRight, Loader2 } from 'lucide-react';
import { useSession } from '@/context/SessionContext';
import { createClient } from '@/lib/supabase/client';
interface Session {
id: string;
name: string;
}
interface SessionBottomSheetProps {
isOpen: boolean;
onClose: () => void;
}
export default function SessionBottomSheet({ isOpen, onClose }: SessionBottomSheetProps) {
const { activeSession, setActiveSession } = useSession();
const [sessions, setSessions] = useState<Session[]>([]);
const [newSessionName, setNewSessionName] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [isCreating, setIsCreating] = useState(false);
const supabase = createClient();
useEffect(() => {
if (isOpen) {
fetchSessions();
}
}, [isOpen]);
const fetchSessions = async () => {
setIsLoading(true);
const { data, error } = await supabase
.from('tasting_sessions')
.select('id, name')
.order('scheduled_at', { ascending: false })
.limit(10);
if (!error && data) {
setSessions(data);
}
setIsLoading(false);
};
const handleCreateSession = async () => {
if (!newSessionName.trim()) return;
setIsCreating(true);
const { data: { user } } = await supabase.auth.getUser();
if (!user) return;
const { data, error } = await supabase
.from('tasting_sessions')
.insert([{ name: newSessionName.trim(), user_id: user.id }])
.select()
.single();
if (!error && data) {
setSessions(prev => [data, ...prev]);
setNewSessionName('');
setActiveSession({ id: data.id, name: data.name });
onClose();
}
setIsCreating(false);
};
return (
<AnimatePresence>
{isOpen && (
<>
{/* Backdrop */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[80]"
/>
{/* Sheet */}
<motion.div
initial={{ y: '100%' }}
animate={{ y: 0 }}
exit={{ y: '100%' }}
transition={{ type: 'spring', damping: 25, stiffness: 200 }}
className="fixed bottom-0 left-0 right-0 bg-[#1A1B20] border-t border-white/10 rounded-t-[32px] z-[90] p-8 pb-12 max-h-[80vh] overflow-y-auto shadow-[0_-10px_40px_rgba(0,0,0,0.5)]"
>
{/* Drag Handle */}
<div className="w-12 h-1.5 bg-white/10 rounded-full mx-auto mb-8" />
<h2 className="text-2xl font-bold mb-6 font-display text-white">Tasting Session</h2>
{/* New Session Input */}
<div className="relative mb-8">
<input
type="text"
value={newSessionName}
onChange={(e) => setNewSessionName(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleCreateSession()}
placeholder="Neue Session erstellen..."
className="w-full bg-white/5 border border-white/10 rounded-2xl py-4 px-6 text-white focus:outline-none focus:border-[#C89D46] transition-colors"
/>
<button
onClick={handleCreateSession}
disabled={isCreating || !newSessionName.trim()}
className="absolute right-3 top-1/2 -translate-y-1/2 p-2 bg-[#C89D46] text-black rounded-xl disabled:opacity-50"
>
{isCreating ? <Loader2 size={20} className="animate-spin" /> : <Plus size={20} />}
</button>
</div>
{/* Session List */}
<div className="space-y-4">
<p className="text-xs font-black uppercase tracking-widest text-white/40 mb-2">Aktuelle Sessions</p>
{isLoading ? (
<div className="flex justify-center py-8">
<Loader2 size={24} className="animate-spin text-white/20" />
</div>
) : sessions.length > 0 ? (
sessions.map((s) => (
<button
key={s.id}
onClick={() => {
setActiveSession({ id: s.id, name: s.name });
onClose();
}}
className={`w-full flex items-center justify-between p-4 rounded-2xl border transition-all ${activeSession?.id === s.id ? 'bg-[#C89D46]/10 border-[#C89D46] text-[#C89D46]' : 'bg-white/5 border-white/5 hover:border-white/20 text-white'}`}
>
<span className="font-bold">{s.name}</span>
{activeSession?.id === s.id ? <Check size={20} /> : <ChevronRight size={20} className="text-white/20" />}
</button>
))
) : (
<div className="text-center py-8 text-white/30 italic">Keine aktiven Sessions gefunden</div>
)}
</div>
</motion.div>
</>
)}
</AnimatePresence>
);
}