page wrapper

This commit is contained in:
2026-01-07 12:40:52 +01:00
parent e589c30bf8
commit 0db80fa98d
128 changed files with 7386 additions and 8096 deletions

View File

@@ -58,18 +58,16 @@ interface LeagueSliderProps {
icon: React.ElementType;
description: string;
leagues: LeagueSummaryViewModel[];
onLeagueClick: (id: string) => void;
autoScroll?: boolean;
iconColor?: string;
scrollSpeedMultiplier?: number;
scrollDirection?: 'left' | 'right';
}
import Link from 'next/link';
interface LeaguesTemplateProps {
leagues: LeagueSummaryViewModel[];
loading?: boolean;
onLeagueClick: (id: string) => void;
onCreateLeagueClick: () => void;
data: LeagueSummaryViewModel[];
}
// ============================================================================
@@ -183,7 +181,6 @@ function LeagueSlider({
icon: Icon,
description,
leagues,
onLeagueClick,
autoScroll = true,
iconColor = 'text-primary-blue',
scrollSpeedMultiplier = 1,
@@ -372,7 +369,9 @@ function LeagueSlider({
`}</style>
{leagues.map((league) => (
<div key={league.id} className="flex-shrink-0 w-[320px] h-full">
<LeagueCard league={league} onClick={() => onLeagueClick(league.id)} />
<Link href={`/leagues/${league.id}`} className="block h-full">
<LeagueCard league={league} />
</Link>
</div>
))}
</div>
@@ -386,17 +385,14 @@ function LeagueSlider({
// ============================================================================
export function LeaguesTemplate({
leagues,
loading = false,
onLeagueClick,
onCreateLeagueClick,
data,
}: LeaguesTemplateProps) {
const [searchQuery, setSearchQuery] = useState('');
const [activeCategory, setActiveCategory] = useState<CategoryId>('all');
const [showFilters, setShowFilters] = useState(false);
// Filter by search query
const searchFilteredLeagues = leagues.filter((league) => {
const searchFilteredLeagues = data.filter((league: LeagueSummaryViewModel) => {
if (!searchQuery) return true;
const query = searchQuery.toLowerCase();
return (
@@ -416,7 +412,7 @@ export function LeaguesTemplate({
const leaguesByCategory = CATEGORIES.reduce(
(acc, category) => {
// First try to use the dedicated category field, fall back to scoring-based filtering
acc[category.id] = searchFilteredLeagues.filter((league) => {
acc[category.id] = searchFilteredLeagues.filter((league: LeagueSummaryViewModel) => {
// If league has a category field, use it directly
if (league.category) {
return league.category === category.id;
@@ -440,19 +436,6 @@ export function LeaguesTemplate({
{ id: 'sprint', speed: 1.2, direction: 'right' },
];
if (loading) {
return (
<div className="max-w-7xl mx-auto px-4">
<div className="flex items-center justify-center min-h-[400px]">
<div className="flex flex-col items-center gap-4">
<div className="w-10 h-10 border-2 border-primary-blue border-t-transparent rounded-full animate-spin" />
<p className="text-gray-400">Loading leagues...</p>
</div>
</div>
</div>
);
}
return (
<div className="max-w-7xl mx-auto px-4 pb-12">
{/* Hero Section */}
@@ -480,7 +463,7 @@ export function LeaguesTemplate({
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-performance-green animate-pulse" />
<span className="text-sm text-gray-400">
<span className="text-white font-semibold">{leagues.length}</span> active leagues
<span className="text-white font-semibold">{data.length}</span> active leagues
</span>
</div>
<div className="flex items-center gap-2">
@@ -500,14 +483,10 @@ export function LeaguesTemplate({
{/* CTA */}
<div className="flex flex-col gap-4">
<Button
variant="primary"
onClick={onCreateLeagueClick}
className="flex items-center gap-2 px-6 py-3"
>
<Link href="/leagues/create" className="flex items-center gap-2 px-6 py-3 bg-primary-blue text-white rounded-lg hover:bg-blue-600 transition-colors">
<Plus className="w-5 h-5" />
<span>Create League</span>
</Button>
</Link>
<p className="text-xs text-gray-500 text-center">Set up your own racing series</p>
</div>
</div>
@@ -574,7 +553,7 @@ export function LeaguesTemplate({
</div>
{/* Content */}
{leagues.length === 0 ? (
{data.length === 0 ? (
/* Empty State */
<Card className="text-center py-16">
<div className="max-w-md mx-auto">
@@ -587,14 +566,10 @@ export function LeaguesTemplate({
<p className="text-gray-400 mb-8">
Be the first to create a racing series. Start your own league and invite drivers to compete for glory.
</p>
<Button
variant="primary"
onClick={onCreateLeagueClick}
className="flex items-center gap-2 mx-auto"
>
<Link href="/leagues/create" className="inline-flex items-center gap-2 px-6 py-3 bg-primary-blue text-white rounded-lg hover:bg-blue-600 transition-colors">
<Sparkles className="w-4 h-4" />
Create Your First League
</Button>
</Link>
</div>
</Card>
) : activeCategory === 'all' && !searchQuery ? (
@@ -613,7 +588,6 @@ export function LeaguesTemplate({
icon={category.icon}
description={category.description}
leagues={leaguesByCategory[category.id]}
onLeagueClick={onLeagueClick}
autoScroll={true}
iconColor={category.color || 'text-primary-blue'}
scrollSpeedMultiplier={speed}
@@ -640,7 +614,9 @@ export function LeaguesTemplate({
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{categoryFilteredLeagues.map((league) => (
<LeagueCard key={league.id} league={league} onClick={() => onLeagueClick(league.id)} />
<Link key={league.id} href={`/leagues/${league.id}`} className="block h-full">
<LeagueCard league={league} />
</Link>
))}
</div>
</>