fediversion/frontend/app/page.tsx
fullsizemalt c59c06915b
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
feat(frontend): implement All Bands view as default when no vertical selected
2025-12-29 01:05:09 -08:00

144 lines
4.9 KiB
TypeScript

import Link from "next/link"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { getApiUrl } from "@/lib/api-config"
interface Vertical {
id: number
name: string
slug: string
description: string | null
}
interface Scene {
id: number
name: string
slug: string
description: string | null
}
async function getVerticals(): Promise<Vertical[]> {
try {
const res = await fetch(`${getApiUrl()}/verticals`, { next: { revalidate: 60 } })
if (!res.ok) return []
return res.json()
} catch {
return []
}
}
async function getScenes(): Promise<Scene[]> {
try {
const res = await fetch(`${getApiUrl()}/verticals/scenes`, { next: { revalidate: 60 } })
if (!res.ok) return []
return res.json()
} catch {
return []
}
}
export default async function HomePage() {
const [verticals, scenes] = await Promise.all([getVerticals(), getScenes()])
return (
<div className="space-y-16">
{/* Hero Section */}
<section className="text-center py-16 space-y-6">
<h1 className="text-5xl font-bold tracking-tight">
Fediversion
</h1>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
The unified platform for the entire jam scene.
One account, all your favorite bands.
</p>
<div className="flex justify-center gap-4">
<Button asChild size="lg">
<Link href="/onboarding">Get Started</Link>
</Button>
<Button asChild variant="outline" size="lg">
<Link href="/shows">Explore Shows</Link>
</Button>
</div>
</section>
{/* Scenes Section */}
{scenes.length > 0 && (
<section className="space-y-6">
<h2 className="text-2xl font-bold text-center">Browse by Scene</h2>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 max-w-3xl mx-auto">
{scenes.map((scene) => (
<Link
key={scene.slug}
href={`/?scene=${scene.slug}`}
className="block p-4 rounded-lg border bg-card hover:bg-accent transition-colors text-center"
>
<div className="font-semibold">{scene.name}</div>
{scene.description && (
<div className="text-sm text-muted-foreground mt-1 line-clamp-2">
{scene.description}
</div>
)}
</Link>
))}
</div>
</section>
)}
{/* Bands Grid */}
<section className="space-y-6">
<h2 className="text-2xl font-bold text-center">Featured Bands</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{verticals.map((vertical) => (
<Card key={vertical.slug} className="hover:shadow-lg transition-shadow">
<CardHeader>
<CardTitle>
<Link href={`/${vertical.slug}`} className="hover:underline">
{vertical.name}
</Link>
</CardTitle>
{vertical.description && (
<CardDescription>{vertical.description}</CardDescription>
)}
</CardHeader>
<CardContent>
<div className="flex gap-2">
<Button asChild variant="outline" size="sm">
<Link href={`/${vertical.slug}/shows`}>Shows</Link>
</Button>
<Button asChild variant="outline" size="sm">
<Link href={`/${vertical.slug}/songs`}>Songs</Link>
</Button>
<Button asChild variant="outline" size="sm">
<Link href={`/${vertical.slug}/venues`}>Venues</Link>
</Button>
</div>
</CardContent>
</Card>
))}
</div>
</section>
{/* Stats Section */}
<section className="bg-muted/50 rounded-lg p-8 text-center space-y-4">
<h2 className="text-2xl font-bold">Join the Community</h2>
<p className="text-muted-foreground">
Track shows, rate performances, discover connections across bands.
</p>
<div className="grid grid-cols-3 gap-6 max-w-md mx-auto pt-4">
<div>
<div className="text-3xl font-bold">{verticals.length}</div>
<div className="text-sm text-muted-foreground">Bands</div>
</div>
<div>
<div className="text-3xl font-bold">{scenes.length}</div>
<div className="text-sm text-muted-foreground">Scenes</div>
</div>
<div>
<div className="text-3xl font-bold">1</div>
<div className="text-sm text-muted-foreground">Account</div>
</div>
</div>
</section>
</div>
)
}