import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { ArrowLeft, MapPin, Music2, Disc, PlayCircle, Youtube } from "lucide-react" import Link from "next/link" import { CommentSection } from "@/components/social/comment-section" import { EntityRating } from "@/components/social/entity-rating" import { ShowAttendance } from "@/components/shows/show-attendance" import { SocialWrapper } from "@/components/social/social-wrapper" import { notFound } from "next/navigation" import { SuggestNicknameDialog } from "@/components/shows/suggest-nickname-dialog" import { EntityReviews } from "@/components/reviews/entity-reviews" import { getApiUrl } from "@/lib/api-config" import { YouTubeEmbed } from "@/components/ui/youtube-embed" import { MarkCaughtButton } from "@/components/chase/mark-caught-button" async function getShow(id: string) { try { const res = await fetch(`${getApiUrl()}/shows/${id}`, { cache: 'no-store' }) if (!res.ok) return null return res.json() } catch (e) { console.error(e) return null } } export default async function ShowDetailPage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params const show = await getShow(slug) if (!show) { notFound() } // Group by set const sets: Record = {}; if (show.performances) { show.performances.forEach((perf: any) => { const setName = perf.set_name || "Set 1"; // Default to Set 1 if missing if (!sets[setName]) sets[setName] = []; sets[setName].push(perf); }); } // Sort keys: Set 1, Set 2, Set 3, Encore, Encore 2... const sortedKeys = Object.keys(sets).sort((a, b) => { const aLower = a.toLowerCase(); const bLower = b.toLowerCase(); // Encore always last if (aLower.includes("encore") && !bLower.includes("encore")) return 1; if (!aLower.includes("encore") && bLower.includes("encore")) return -1; // If both have Set, compare numbers if (aLower.includes("set") && bLower.includes("set")) { const aNum = parseInt(a.replace(/\D/g, "") || "0"); const bNum = parseInt(b.replace(/\D/g, "") || "0"); return aNum - bNum; } return a.localeCompare(b); }); return (

{new Date(show.date).toLocaleDateString()} {show.venue && ( - {show.venue.name}, {show.venue.city}, {show.venue.state} )}

{show.tags && show.tags.length > 0 && (
{show.tags.map((tag: any) => ( #{tag.name} ))}
)}
{show.tour && (

{show.tour.name}

)}
{show.notes && (
Note: {show.notes}
)}
{/* Full Show Video */} {show.youtube_link && ( Full Show Video )} Setlist {show.performances && show.performances.length > 0 ? (
{sortedKeys.map((setName) => (

{setName}

{sets[setName].map((perf: any) => (
{perf.position}.
{perf.song?.title || "Unknown Song"} {perf.track_url && ( )} {perf.youtube_link && ( )} {perf.bandcamp_link && ( )} {perf.nugs_link && ( )} {perf.segue && >}
{/* Nicknames */} {perf.nicknames && perf.nicknames.length > 0 && (
{perf.nicknames.map((nick: any) => ( "{nick.nickname}" ))}
)} {/* Suggest Nickname Button */}
{/* Rating Column */} {/* Mark Caught (for chase songs) */}
{perf.notes && (
{perf.notes}
)}
))}
))}
) : (

No Setlist Documented

This show's setlist hasn't been added yet. Early Goose shows (2014-2016) often weren't documented.

)}
{/* Venue Info Card */} Venue {show.venue ? ( <>
{show.venue.name}

{show.venue.city}, {show.venue.state} {show.venue.country}

) : (

Unknown Venue

)}
{/* Listen On Card */} {(show.nugs_link || show.bandcamp_link) && ( Listen On {show.nugs_link && (

Nugs.net

Stream or download

)} {show.bandcamp_link && (

Bandcamp

Official release

)}
)} {/* Tour Info */} {show.tour && ( Tour
{show.tour.name}
)} {/* Attendance */} I Was There {/* Rate This Show */} Rate This Show
) }