website refactor

This commit is contained in:
2026-01-21 18:40:49 +01:00
parent 69319ce1d4
commit ea58909070
18 changed files with 1051 additions and 267 deletions

View File

@@ -19,6 +19,8 @@ export class LeaguesViewDataBuilder {
createdAt: league.createdAt,
maxDrivers: league.settings.maxDrivers,
usedDriverSlots: league.usedSlots,
activeDriversCount: (league as any).activeDriversCount,
nextRaceAt: (league as any).nextRaceAt,
maxTeams: undefined, // Not provided in DTO
usedTeamSlots: undefined, // Not provided in DTO
structureSummary: league.settings.qualifyingFormat || '',

View File

@@ -0,0 +1,101 @@
import {
Trophy,
Users,
Flag,
Award,
Sparkles,
Zap,
Clock,
Layout,
type LucideIcon
} from 'lucide-react';
export type CategoryId =
| 'all'
| 'driver'
| 'team'
| 'nations'
| 'trophy'
| 'new'
| 'popular'
| 'openSlots'
| 'endurance'
| 'sprint';
export interface LeagueCategory {
id: CategoryId;
label: string;
icon: LucideIcon;
description: string;
color?: string;
filter: (league: any) => boolean;
}
export const LEAGUE_CATEGORIES: LeagueCategory[] = [
{
id: 'all',
label: 'All',
icon: Layout,
description: 'All available competition infrastructure.',
filter: () => true,
},
{
id: 'popular',
label: 'Popular',
icon: Zap,
description: 'High utilization infrastructure.',
filter: (league) => {
const fillRate = (league.usedDriverSlots ?? 0) / (league.maxDrivers ?? 1);
return fillRate > 0.7;
},
},
{
id: 'new',
label: 'New',
icon: Sparkles,
description: 'Recently deployed infrastructure.',
filter: (league) => {
const oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
return new Date(league.createdAt) > oneWeekAgo;
},
},
{
id: 'driver',
label: 'Driver',
icon: Trophy,
description: 'Individual competition format.',
filter: (league) => league.scoring?.primaryChampionshipType === 'driver',
},
{
id: 'team',
label: 'Team',
icon: Users,
description: 'Team-based competition format.',
filter: (league) => league.scoring?.primaryChampionshipType === 'team',
},
{
id: 'nations',
label: 'Nations',
icon: Flag,
description: 'National representation format.',
filter: (league) => league.scoring?.primaryChampionshipType === 'nations',
},
{
id: 'trophy',
label: 'Trophy',
icon: Award,
description: 'Special event infrastructure.',
filter: (league) => league.scoring?.primaryChampionshipType === 'trophy',
},
{
id: 'endurance',
label: 'Endurance',
icon: Clock,
description: 'Long-duration competition.',
filter: (league) =>
league.scoring?.scoringPresetId?.includes('endurance') ??
league.timingSummary?.includes('h Race') ??
false,
},
];

View File

@@ -16,6 +16,8 @@ export interface LeaguesViewData {
createdAt: string; // ISO string
maxDrivers: number;
usedDriverSlots: number;
activeDriversCount?: number;
nextRaceAt?: string;
maxTeams: number | undefined;
usedTeamSlots: number | undefined;
structureSummary: string;

View File

@@ -7,6 +7,8 @@ export interface LeagueSummaryViewModel {
createdAt: string;
maxDrivers: number;
usedDriverSlots: number;
activeDriversCount?: number;
nextRaceAt?: string;
maxTeams?: number;
usedTeamSlots?: number;
structureSummary: string;