fediversion/frontend/components/shows/date-grouped-list.tsx
fullsizemalt 60456c4737
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
feat(frontend): Enforce strict mode and refactor pages
2025-12-30 22:29:16 -08:00

107 lines
5 KiB
TypeScript

"use client"
import Link from "next/link"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Calendar, MapPin, Youtube, Music2 } from "lucide-react"
import { Show } from "@/types/models"
interface DateGroupedListProps {
shows: Show[]
}
export function DateGroupedList({ shows }: DateGroupedListProps) {
if (shows.length === 0) {
return (
<div className="text-center py-12 text-muted-foreground">
No shows found matching your filters.
</div>
)
}
// Group shows by date
const groupedShows: Record<string, Show[]> = {}
shows.forEach(show => {
// Use local date string to avoid timezone shifts if possible, or usually just split T
const dateKey = new Date(show.date).toLocaleDateString(undefined, {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})
if (!groupedShows[dateKey]) {
groupedShows[dateKey] = []
}
groupedShows[dateKey].push(show)
})
// Sort dates (descending) - assuming API returned sorted, but safe to re-sort keys if list order isn't guaranteed
// Actually relying on input order is safer if we trust the API to sort by date desc.
// Let's just iterate over the unique keys in the order they appear (which will be desc if input is desc)
const uniqueDates = Array.from(new Set(shows.map(s =>
new Date(s.date).toLocaleDateString(undefined, {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})
)))
return (
<div className="space-y-8">
{uniqueDates.map(dateStr => (
<div key={dateStr} className="space-y-4">
<div className="sticky top-14 z-10 bg-background/95 backdrop-blur py-2 border-b">
<h2 className="text-xl font-bold flex items-center gap-2">
<Calendar className="h-5 w-5 text-primary" />
{dateStr}
</h2>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{groupedShows[dateStr].map(show => (
<Link key={show.id} href={`/shows/${show.slug}`} className="block group">
<Card className="h-full transition-all duration-300 hover:scale-[1.02] hover:shadow-lg group-hover:border-primary/50 relative overflow-hidden">
{/* Vertical Stripe/Badge */}
{show.vertical && (
<div className="absolute top-0 left-0 w-1 h-full bg-primary/50 group-hover:bg-primary transition-colors" />
)}
{show.youtube_link && (
<div className="absolute top-2 right-2 bg-red-500/10 text-red-500 p-1.5 rounded-full" title="Full show video available">
<Youtube className="h-4 w-4" />
</div>
)}
<CardHeader className="pl-5 pb-2"> {/* Added padding-left for stripe */}
<CardTitle className="text-lg flex flex-col gap-1">
{show.vertical && (
<span className="text-xs font-medium text-primary uppercase tracking-wider flex items-center gap-1">
<Music2 className="h-3 w-3" />
{show.vertical.name}
</span>
)}
<span className="group-hover:text-primary transition-colors">
{show.venue?.name}
</span>
</CardTitle>
</CardHeader>
<CardContent className="pl-5 pt-0">
<div className="flex items-center gap-2 text-sm text-muted-foreground group-hover:text-foreground transition-colors">
<MapPin className="h-3.5 w-3.5" />
<span>
{show.venue?.city}, {show.venue?.state}
</span>
</div>
</CardContent>
</Card>
</Link>
))}
</div>
</div>
))}
</div>
)
}