+ {/* Filters */}
+
+
+
+ setSearch(e.target.value)}
+ placeholder="Search sessions or hosts..."
+ className="w-full pl-12 pr-4 py-3 bg-zinc-900 border border-zinc-800 rounded-xl text-white placeholder-zinc-600 focus:outline-none focus:border-orange-600"
+ />
+
+
+
+
+
+
+
+
+
+ {/* Results */}
+
+ Showing {filteredSessions.length} of {sessions.length} sessions
+
+
+ {/* Sessions List */}
+
+ {filteredSessions.map(session => (
+
+
+ {/* Icon */}
+
+
+
+
+ {/* Info */}
+
+
+
{session.name}
+ {!session.ended_at ? (
+
+
+ Live
+
+ ) : (
+
+
+ Ended
+
+ )}
+
+
+
+
+
+ {session.user.display_name || session.user.username}
+
+
+
+ {formatDate(session.scheduled_at)}
+
+
+
+ {getSessionDuration(session.scheduled_at, session.ended_at)}
+
+
+
+
+ {/* Stats */}
+
+
+
{session.participantCount}
+
Buddies
+
+
+
{session.tastingCount}
+
Tastings
+
+
+
+ {/* Link */}
+
+
+
+
+
+ ))}
+
+
+ {/* Empty State */}
+ {filteredSessions.length === 0 && (
+
+
+
+
+
No Sessions Found
+
No tasting sessions match your filters.
+
+ )}
+
+ );
+}
diff --git a/src/app/admin/sessions/page.tsx b/src/app/admin/sessions/page.tsx
new file mode 100644
index 0000000..53f7d74
--- /dev/null
+++ b/src/app/admin/sessions/page.tsx
@@ -0,0 +1,133 @@
+export const dynamic = 'force-dynamic';
+
+import { createClient } from '@/lib/supabase/server';
+import { redirect } from 'next/navigation';
+import { checkIsAdmin } from '@/services/track-api-usage';
+import Link from 'next/link';
+import { ArrowLeft, Calendar, User, Users, GlassWater, Clock, CheckCircle } from 'lucide-react';
+import AdminSessionsList from './AdminSessionsList';
+
+export default async function AdminSessionsPage() {
+ const supabase = await createClient();
+ const { data: { user } } = await supabase.auth.getUser();
+
+ if (!user) {
+ redirect('/');
+ }
+
+ const isAdmin = await checkIsAdmin(user.id);
+ if (!isAdmin) {
+ redirect('/');
+ }
+
+ // Fetch all sessions from all users
+ const { data: sessionsRaw, error } = await supabase
+ .from('tasting_sessions')
+ .select(`
+ id,
+ name,
+ user_id,
+ scheduled_at,
+ ended_at,
+ created_at,
+ session_participants (id),
+ tastings (id)
+ `)
+ .order('created_at', { ascending: false })
+ .limit(500);
+
+ // Get unique user IDs
+ const userIds = Array.from(new Set(sessionsRaw?.map(s => s.user_id) || []));
+
+ // Fetch profiles for users
+ const { data: profiles } = userIds.length > 0
+ ? await supabase.from('profiles').select('id, username, display_name').in('id', userIds)
+ : { data: [] };
+
+ // Combine sessions with user info
+ const sessions = sessionsRaw?.map(session => ({
+ ...session,
+ user: profiles?.find(p => p.id === session.user_id) || { username: 'Unknown', display_name: null },
+ participantCount: (session.session_participants as any[])?.length || 0,
+ tastingCount: (session.tastings as any[])?.length || 0,
+ })) || [];
+
+ // Calculate stats
+ const stats = {
+ totalSessions: sessions.length,
+ activeSessions: sessions.filter(s => !s.ended_at).length,
+ totalHosts: userIds.length,
+ totalParticipants: sessions.reduce((sum, s) => sum + s.participantCount, 0),
+ totalTastings: sessions.reduce((sum, s) => sum + s.tastingCount, 0),
+ };
+
+ return (
+