149 lines
4.2 KiB
TypeScript
149 lines
4.2 KiB
TypeScript
'use client';
|
|
|
|
import { routes } from '@/lib/routing/RouteConfig';
|
|
import type { LeaguesViewData } from '@/lib/view-data/LeaguesViewData';
|
|
import {
|
|
Award,
|
|
Clock,
|
|
Flag,
|
|
Flame,
|
|
Globe,
|
|
Sparkles,
|
|
Target,
|
|
Timer,
|
|
Trophy,
|
|
Users,
|
|
} from 'lucide-react';
|
|
import { useRouter } from 'next/navigation';
|
|
import React, { useState } from 'react';
|
|
import { LeaguesTemplate, Category, CategoryId } from '@/templates/LeaguesTemplate';
|
|
import { ClientWrapperProps } from '@/lib/contracts/components/ComponentContracts';
|
|
|
|
const CATEGORIES: Category[] = [
|
|
{
|
|
id: 'all',
|
|
label: 'All',
|
|
icon: Globe,
|
|
description: 'Browse all available leagues',
|
|
filter: () => true,
|
|
},
|
|
{
|
|
id: 'popular',
|
|
label: 'Popular',
|
|
icon: Flame,
|
|
description: 'Most active leagues right now',
|
|
filter: (league) => {
|
|
const fillRate = (league.usedDriverSlots ?? 0) / (league.maxDrivers ?? 1);
|
|
return fillRate > 0.7;
|
|
},
|
|
color: 'text-orange-400',
|
|
},
|
|
{
|
|
id: 'new',
|
|
label: 'New',
|
|
icon: Sparkles,
|
|
description: 'Fresh leagues looking for members',
|
|
filter: (league) => {
|
|
const oneWeekAgo = new Date();
|
|
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
|
|
return new Date(league.createdAt) > oneWeekAgo;
|
|
},
|
|
color: 'text-green-500',
|
|
},
|
|
{
|
|
id: 'openSlots',
|
|
label: 'Open Slots',
|
|
icon: Target,
|
|
description: 'Leagues with available spots',
|
|
filter: (league) => {
|
|
if (league.maxTeams && league.maxTeams > 0) {
|
|
const usedTeams = league.usedTeamSlots ?? 0;
|
|
return usedTeams < league.maxTeams;
|
|
}
|
|
const used = league.usedDriverSlots ?? 0;
|
|
const max = league.maxDrivers ?? 0;
|
|
return max > 0 && used < max;
|
|
},
|
|
color: 'text-cyan-400',
|
|
},
|
|
{
|
|
id: 'driver',
|
|
label: 'Driver',
|
|
icon: Trophy,
|
|
description: 'Compete as an individual',
|
|
filter: (league) => league.scoring?.primaryChampionshipType === 'driver',
|
|
},
|
|
{
|
|
id: 'team',
|
|
label: 'Team',
|
|
icon: Users,
|
|
description: 'Race together as a team',
|
|
filter: (league) => league.scoring?.primaryChampionshipType === 'team',
|
|
},
|
|
{
|
|
id: 'nations',
|
|
label: 'Nations',
|
|
icon: Flag,
|
|
description: 'Represent your country',
|
|
filter: (league) => league.scoring?.primaryChampionshipType === 'nations',
|
|
},
|
|
{
|
|
id: 'trophy',
|
|
label: 'Trophy',
|
|
icon: Award,
|
|
description: 'Special championship events',
|
|
filter: (league) => league.scoring?.primaryChampionshipType === 'trophy',
|
|
},
|
|
{
|
|
id: 'endurance',
|
|
label: 'Endurance',
|
|
icon: Timer,
|
|
description: 'Long-distance racing',
|
|
filter: (league) =>
|
|
league.scoring?.scoringPresetId?.includes('endurance') ??
|
|
league.timingSummary?.includes('h Race') ??
|
|
false,
|
|
},
|
|
{
|
|
id: 'sprint',
|
|
label: 'Sprint',
|
|
icon: Clock,
|
|
description: 'Quick, intense races',
|
|
filter: (league) =>
|
|
(league.scoring?.scoringPresetId?.includes('sprint') ?? false) &&
|
|
!(league.scoring?.scoringPresetId?.includes('endurance') ?? false),
|
|
},
|
|
];
|
|
|
|
export function LeaguesPageClient({ viewData }: ClientWrapperProps<LeaguesViewData>) {
|
|
const router = useRouter();
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const [activeCategory, setActiveCategory] = useState<CategoryId>('all');
|
|
|
|
const filteredLeagues = viewData.leagues.filter((league) => {
|
|
const matchesSearch = !searchQuery ||
|
|
league.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
(league.description ?? '').toLowerCase().includes(searchQuery.toLowerCase());
|
|
|
|
const category = CATEGORIES.find(c => c.id === activeCategory);
|
|
const matchesCategory = !category || category.filter(league);
|
|
|
|
return matchesSearch && matchesCategory;
|
|
});
|
|
|
|
return (
|
|
<LeaguesTemplate
|
|
viewData={viewData}
|
|
searchQuery={searchQuery}
|
|
onSearchChange={setSearchQuery}
|
|
activeCategory={activeCategory}
|
|
onCategoryChange={setActiveCategory}
|
|
filteredLeagues={filteredLeagues}
|
|
categories={CATEGORIES}
|
|
onCreateLeague={() => router.push(routes.league.create)}
|
|
onLeagueClick={(id) => router.push(routes.league.detail(id))}
|
|
onClearFilters={() => { setSearchQuery(''); setActiveCategory('all'); }}
|
|
/>
|
|
);
|
|
}
|