"use client" import { useEffect, useState, Suspense, useMemo } from "react" import { getApiUrl } from "@/lib/api-config" import { Loader2, Calendar, Music2, Clock, Heart, Users, X } from "lucide-react" import { Skeleton } from "@/components/ui/skeleton" import { useSearchParams, useRouter, usePathname } from "next/navigation" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import Link from "next/link" import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs" import { DateGroupedList } from "@/components/shows/date-grouped-list" import { VERTICALS } from "@/config/verticals" import { Card, CardContent } from "@/components/ui/card" interface Show { id: number slug?: string date: string youtube_link?: string vertical?: { name: string slug: string } venue: { id: number name: string city: string state: string } } interface VerticalWithCount { slug: string name: string showCount?: number } function ShowsContent() { const searchParams = useSearchParams() const router = useRouter() const pathname = usePathname() // Parse query params const bandsParam = searchParams.get("bands") const viewParam = searchParams.get("view") || "recent" const initialBands = bandsParam ? bandsParam.split(",") : [] const [shows, setShows] = useState([]) const [upcomingShows, setUpcomingShows] = useState([]) const [loading, setLoading] = useState(true) const [selectedBands, setSelectedBands] = useState(initialBands) const [activeView, setActiveView] = useState(viewParam) const [bandCounts, setBandCounts] = useState>({}) // Fetch band counts on mount useEffect(() => { fetch(`${getApiUrl()}/verticals/`) .then(res => res.json()) .then(verticals => { // We'll get counts from the shows data instead }) .catch(console.error) }, []) // Update URL when filters change const updateFilters = (bands: string[], view: string) => { const params = new URLSearchParams() if (bands.length > 0) { params.set("bands", bands.join(",")) } if (view !== "recent") { params.set("view", view) } const queryString = params.toString() router.push(`${pathname}${queryString ? `?${queryString}` : ''}`) } const toggleBand = (slug: string) => { const newBands = selectedBands.includes(slug) ? selectedBands.filter(s => s !== slug) : [...selectedBands, slug] setSelectedBands(newBands) updateFilters(newBands, activeView) } const clearBandFilters = () => { setSelectedBands([]) updateFilters([], activeView) } const handleViewChange = (view: string) => { setActiveView(view) updateFilters(selectedBands, view) } // Fetch shows based on view useEffect(() => { if (activeView === "bands") return // No fetch needed for bands view setLoading(true) const params = new URLSearchParams() params.append("limit", "200") if (activeView === "recent") { params.append("status", "past") } else if (activeView === "upcoming") { params.append("status", "upcoming") } if (selectedBands.length > 0) { selectedBands.forEach(slug => params.append("vertical_slugs", slug)) } const url = `${getApiUrl()}/shows/?${params.toString()}` fetch(url) .then(res => res.json()) .then(data => { const sorted = data.sort((a: Show, b: Show) => activeView === "upcoming" ? new Date(a.date).getTime() - new Date(b.date).getTime() : new Date(b.date).getTime() - new Date(a.date).getTime() ) // Calculate band counts from data const counts: Record = {} data.forEach((show: Show) => { if (show.vertical?.slug) { counts[show.vertical.slug] = (counts[show.vertical.slug] || 0) + 1 } }) setBandCounts(counts) if (activeView === "upcoming") { setUpcomingShows(sorted) } else { setShows(sorted) } }) .catch(console.error) .finally(() => setLoading(false)) }, [activeView, selectedBands]) // Get unique bands from current data for filter pills const activeBandsInData = useMemo(() => { const dataToCheck = activeView === "upcoming" ? upcomingShows : shows const slugs = new Set(dataToCheck.map(s => s.vertical?.slug).filter(Boolean)) return Array.from(slugs) as string[] }, [shows, upcomingShows, activeView]) // Bands available for filtering const availableBands = VERTICALS.filter(v => activeBandsInData.includes(v.slug) || selectedBands.includes(v.slug) ) return (
{/* Header */}

Shows

Browse the complete archive across all bands.

{/* Tabs Navigation */}
Recent By Band Upcoming My Feed
{/* Band Filter Pills - Only show on Recent and Upcoming */} {(activeView === "recent" || activeView === "upcoming") && (
Filter: {selectedBands.length === 0 ? ( All Bands ) : ( <> {selectedBands.map(slug => { const band = VERTICALS.find(v => v.slug === slug) return ( toggleBand(slug)} > {band?.name || slug} ) })} )} {/* Add band buttons */} {selectedBands.length === 0 && availableBands.length > 0 && (
{availableBands.slice(0, 5).map(band => ( toggleBand(band.slug)} > {band.name} {bandCounts[band.slug] && ( ({bandCounts[band.slug]}) )} ))} {availableBands.length > 5 && ( +{availableBands.length - 5} more )}
)}
)} {/* Tab Content */} {loading ? ( ) : ( )} {loading ? ( ) : upcomingShows.length === 0 ? (

No upcoming shows announced

Check back later for new tour dates!

) : ( )}
) } function BandsGrid() { const [verticals, setVerticals] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { fetch(`${getApiUrl()}/verticals/`) .then(res => res.json()) .then(data => setVerticals(data)) .catch(console.error) .finally(() => setLoading(false)) }, []) if (loading) { return (
{Array.from({ length: 8 }).map((_, i) => ( ))}
) } return (
{verticals.map(vertical => (

{vertical.name}

{vertical.description?.slice(0, 50)}...

))}
) } function MyFeedPlaceholder() { return (

Your Personal Feed

Follow your favorite bands to see a customized feed of shows tailored to your preferences.

) } function LoadingSkeleton() { return (
{Array.from({ length: 6 }).map((_, i) => ( ))}
) } function LoadingFallback() { return (
) } export default function ShowsPage() { return ( }> ) }