diff --git a/frontend/app/[vertical]/page.tsx b/frontend/app/[vertical]/page.tsx index 1b8d9cb..2270c2d 100644 --- a/frontend/app/[vertical]/page.tsx +++ b/frontend/app/[vertical]/page.tsx @@ -1,5 +1,10 @@ import { notFound } from "next/navigation" import { VERTICALS } from "@/config/verticals" +import { getApiUrl } from "@/lib/api-config" +import Link from "next/link" +import { Calendar, MapPin, Music, Trophy, Video, Ticket, Building, ChevronRight, Play } from "lucide-react" +import { Card, CardContent } from "@/components/ui/card" +import { Button } from "@/components/ui/button" interface Props { params: Promise<{ vertical: string }> @@ -11,6 +16,30 @@ export function generateStaticParams() { })) } +async function getRecentShows(verticalSlug: string) { + try { + const res = await fetch(`${getApiUrl()}/shows?vertical=${verticalSlug}&limit=8&status=past`, { + next: { revalidate: 60 } + }) + if (!res.ok) return [] + return res.json() + } catch { + return [] + } +} + +async function getTopSongs(verticalSlug: string) { + try { + const res = await fetch(`${getApiUrl()}/songs?vertical=${verticalSlug}&limit=5&sort=times_played`, { + next: { revalidate: 60 } + }) + if (!res.ok) return [] + return res.json() + } catch { + return [] + } +} + export default async function VerticalPage({ params }: Props) { const { vertical: verticalSlug } = await params const vertical = VERTICALS.find((v) => v.slug === verticalSlug) @@ -19,39 +48,156 @@ export default async function VerticalPage({ params }: Props) { notFound() } + const [recentShows, topSongs] = await Promise.all([ + getRecentShows(verticalSlug), + getTopSongs(verticalSlug) + ]) + + const navCards = [ + { href: `/${verticalSlug}/shows`, icon: Calendar, title: "Shows", desc: "Browse the complete archive" }, + { href: `/${verticalSlug}/venues`, icon: Building, title: "Venues", desc: "Find your favorite spots" }, + { href: `/${verticalSlug}/songs`, icon: Music, title: "Songs", desc: "Explore the catalog" }, + { href: `/${verticalSlug}/performances`, icon: Trophy, title: "Top Performances", desc: "Highest rated jams" }, + { href: `/leaderboards?band=${verticalSlug}`, icon: Trophy, title: "Leaderboards", desc: "Top rated everything" }, + { href: `/${verticalSlug}/tours`, icon: Ticket, title: "Tours", desc: "Browse by tour" }, + { href: `/videos?band=${verticalSlug}`, icon: Video, title: "Videos", desc: "Watch full shows and songs" }, + ] + return ( -
-
-

{vertical.name}

-

- Explore setlists, rate performances, and connect with the {vertical.name} community. +

+ {/* Hero Section */} +
+

+ {vertical.name} +

+

+ A comprehensive community-driven archive for {vertical.name} history. +
+ Discover shows, share ratings, and explore the music together.

-
+
+ + + + + + +
+ -
- -

Shows

-

Browse all concerts and setlists

-
+
+ {/* Recent Shows */} + {recentShows.length > 0 && ( +
+
+

Recent Shows

+ + View all shows + +
+
+ {recentShows.slice(0, 8).map((show: any) => ( + + + +
+ {new Date(show.date).toLocaleDateString('en-US', { + weekday: 'short', + month: 'short', + day: 'numeric', + year: 'numeric' + })} +
+
+ {show.venue?.name || "Unknown Venue"} +
+
+ + {show.venue?.city}, {show.venue?.state || show.venue?.country} +
+ {show.tour?.name && ( +
+ {show.tour.name} +
+ )} +
+
+ + ))} +
+
+ )} - -

Songs

-

Explore the catalog and stats

-
+ {/* Top Songs */} + {topSongs.length > 0 && ( +
+
+

Top Songs

+ + All songs + +
+
+ {topSongs.slice(0, 5).map((song: any, index: number) => ( + +
+
+ {index + 1} +
+
+
+ {song.title} +
+
+
+ {song.times_played || song.performance_count || 0} performances +
+
+ + ))} +
+
+ )} - -

Venues

-

See where they've played

-
+ {/* Navigation Cards */} +
+

Explore

+
+ {navCards.map((card) => ( + + + +
+ +
+
+

+ {card.title} +

+

+ {card.desc} +

+
+
+
+ + ))} +
+
)