"use client" import { useEffect, useState } from "react" import { getApiUrl } from "@/lib/api-config" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Skeleton } from "@/components/ui/skeleton" import { Youtube, Calendar, MapPin, Music, Film } from "lucide-react" import Link from "next/link" interface PerformanceVideo { type: "performance" id: number youtube_link: string show_id: number song_id: number song_title: string song_slug: string date: string show_slug: string venue_name: string venue_city: string venue_state: string | null performance_slug?: string venue_slug: string } interface ShowVideo { type: "full_show" id: number youtube_link: string date: string show_slug: string venue_name: string venue_city: string venue_state: string | null venue_slug: string } interface VideoStats { performance_videos: number full_show_videos: number total: number } export default function VideosPage() { const [performances, setPerformances] = useState([]) const [shows, setShows] = useState([]) const [stats, setStats] = useState(null) const [loading, setLoading] = useState(true) const [activeTab, setActiveTab] = useState<"all" | "songs" | "shows">("all") const [searchQuery, setSearchQuery] = useState("") const [expandedVideoId, setExpandedVideoId] = useState(null) useEffect(() => { Promise.all([ fetch(`${getApiUrl()}/videos/?limit=500`).then(r => r.json()), fetch(`${getApiUrl()}/videos/stats`).then(r => r.json()) ]) .then(([videoData, statsData]) => { setPerformances(videoData.performances) setShows(videoData.shows) setStats(statsData) }) .catch(console.error) .finally(() => setLoading(false)) }, []) const extractVideoId = (url: string) => { const match = url.match(/[?&]v=([^&]+)/) return match ? match[1] : null } const toggleVideo = (uniqueId: string) => { if (expandedVideoId === uniqueId) { setExpandedVideoId(null) } else { setExpandedVideoId(uniqueId) } } if (loading) { return (
{Array.from({ length: 10 }).map((_, i) => ( ))}
) } // Filter logic const query = searchQuery.toLowerCase() const filterVideo = (v: PerformanceVideo | ShowVideo) => { if (v.type === "full_show") { const show = v as ShowVideo return show.venue_name.toLowerCase().includes(query) || show.venue_city.toLowerCase().includes(query) || show.date.includes(query) } else { const perf = v as PerformanceVideo return perf.song_title.toLowerCase().includes(query) || perf.venue_name.toLowerCase().includes(query) || perf.venue_city.toLowerCase().includes(query) || perf.date.includes(query) } } // Combine and sort by date let allVideos = [ ...performances, ...shows.map(s => ({ ...s, song_title: "Full Show" })) ].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) // Apply Tab Filter if (activeTab === "songs") { allVideos = allVideos.filter(v => v.type === "performance") } else if (activeTab === "shows") { allVideos = allVideos.filter(v => v.type === "full_show") } // Apply Search Filter if (searchQuery) { allVideos = allVideos.filter(filterVideo) } return (

Videos

{stats && (

{stats.total} videos available • {stats.full_show_videos} full shows • {stats.performance_videos} song performances

)}
{/* Special Features Section */}

Special Features

Show Upon Time

Documentary

An intimate look behind the scenes of Goose's journey.

{expandedVideoId === "doc-show-upon-time" && (