This commit is contained in:
2025-12-05 12:47:20 +01:00
parent 5a9cd28d5b
commit b6c2b4a422
7 changed files with 1093 additions and 713 deletions

View File

@@ -1,5 +1,6 @@
'use client';
import { User, Users2, Info } from 'lucide-react';
import Input from '@/components/ui/Input';
import SegmentedControl from '@/components/ui/SegmentedControl';
import type { LeagueConfigFormModel } from '@gridpilot/racing/application';
@@ -128,71 +129,162 @@ export function LeagueStructureSection({
return (
<div className="space-y-6">
<h2 className="text-lg font-semibold text-white">
Step 2 Structure &amp; capacity
</h2>
{/* League structure selection */}
<div className="space-y-3">
<label className="flex items-center gap-2 text-sm font-medium text-gray-300">
<Users2 className="w-4 h-4 text-primary-blue" />
League structure
</label>
<SegmentedControl
options={[
{
value: 'solo',
label: 'Drivers only (Solo)',
description: 'Individual drivers score points.',
},
{
value: 'fixedTeams',
label: 'Teams',
description: 'Teams with fixed drivers per team.',
},
]}
value={structure.mode}
onChange={
disabled
? undefined
: (mode) => handleModeChange(mode as 'solo' | 'fixedTeams')
}
/>
</div>
<div className="space-y-5">
<div>
<span className="block text-sm font-medium text-gray-300 mb-2">
League structure
</span>
<SegmentedControl
options={[
{
value: 'solo',
label: 'Drivers only (Solo)',
description: 'Individual drivers score points.',
},
{
value: 'fixedTeams',
label: 'Teams',
description: 'Teams with fixed drivers per team.',
},
]}
value={structure.mode}
onChange={
disabled
? undefined
: (mode) => handleModeChange(mode as 'solo' | 'fixedTeams')
}
/>
</div>
{/* Solo mode capacity */}
{structure.mode === 'solo' && (
<div className="rounded-lg border border-charcoal-outline bg-iron-gray/30 p-5 space-y-4">
<div className="flex items-start gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary-blue/10 shrink-0">
<User className="w-5 h-5 text-primary-blue" />
</div>
<div className="flex-1">
<h3 className="text-sm font-semibold text-white mb-1">Driver capacity</h3>
<p className="text-xs text-gray-500">
Set the maximum number of drivers who can join your league
</p>
</div>
</div>
{structure.mode === 'solo' && (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<div className="space-y-4">
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-300">
Max drivers
</label>
<p className="text-xs text-gray-500">
Typical club leagues use 2030
</p>
<div className="mt-2">
<Input
type="number"
value={structure.maxDrivers ?? 24}
onChange={(e) => handleMaxDriversChange(e.target.value)}
disabled={disabled}
min={1}
max={64}
className="w-28"
/>
<Input
type="number"
value={structure.maxDrivers ?? 24}
onChange={(e) => handleMaxDriversChange(e.target.value)}
disabled={disabled}
min={1}
max={64}
className="w-32"
/>
<div className="space-y-2">
<p className="text-xs text-gray-500 flex items-start gap-1.5">
<Info className="w-3 h-3 mt-0.5 shrink-0" />
<span>Typical club leagues use 2030 drivers</span>
</p>
<div className="flex flex-wrap gap-2 text-xs">
<button
type="button"
onClick={() => handleMaxDriversChange('20')}
disabled={disabled}
className="px-2 py-1 rounded bg-iron-gray border border-charcoal-outline text-gray-300 hover:border-primary-blue hover:text-primary-blue transition-colors"
>
Small (20)
</button>
<button
type="button"
onClick={() => handleMaxDriversChange('24')}
disabled={disabled}
className="px-2 py-1 rounded bg-iron-gray border border-charcoal-outline text-gray-300 hover:border-primary-blue hover:text-primary-blue transition-colors"
>
Medium (24)
</button>
<button
type="button"
onClick={() => handleMaxDriversChange('30')}
disabled={disabled}
className="px-2 py-1 rounded bg-iron-gray border border-charcoal-outline text-gray-300 hover:border-primary-blue hover:text-primary-blue transition-colors"
>
Large (30)
</button>
</div>
</div>
</div>
</div>
)}
</div>
)}
{structure.mode === 'fixedTeams' && (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-300">
Max teams
</label>
{/* Teams mode capacity */}
{structure.mode === 'fixedTeams' && (
<div className="rounded-lg border border-charcoal-outline bg-iron-gray/30 p-5 space-y-4">
<div className="flex items-start gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary-blue/10 shrink-0">
<Users2 className="w-5 h-5 text-primary-blue" />
</div>
<div className="flex-1">
<h3 className="text-sm font-semibold text-white mb-1">Team structure</h3>
<p className="text-xs text-gray-500">
Roughly how many teams you expect.
Configure the team composition and maximum grid size
</p>
<div className="mt-2">
</div>
</div>
<div className="space-y-4">
<div className="rounded-lg bg-primary-blue/5 border border-primary-blue/20 p-3">
<p className="text-xs text-gray-300">
<span className="font-medium text-primary-blue">Quick setup:</span> Choose a common configuration
</p>
<div className="flex flex-wrap gap-2 mt-2">
<button
type="button"
onClick={() => {
handleMaxTeamsChange('10');
handleDriversPerTeamChange('2');
}}
disabled={disabled}
className="px-3 py-1.5 rounded bg-iron-gray border border-charcoal-outline text-xs text-gray-300 hover:border-primary-blue hover:text-primary-blue transition-colors"
>
10 teams × 2 drivers (20 grid)
</button>
<button
type="button"
onClick={() => {
handleMaxTeamsChange('12');
handleDriversPerTeamChange('2');
}}
disabled={disabled}
className="px-3 py-1.5 rounded bg-iron-gray border border-charcoal-outline text-xs text-gray-300 hover:border-primary-blue hover:text-primary-blue transition-colors"
>
12 teams × 2 drivers (24 grid)
</button>
<button
type="button"
onClick={() => {
handleMaxTeamsChange('8');
handleDriversPerTeamChange('3');
}}
disabled={disabled}
className="px-3 py-1.5 rounded bg-iron-gray border border-charcoal-outline text-xs text-gray-300 hover:border-primary-blue hover:text-primary-blue transition-colors"
>
8 teams × 3 drivers (24 grid)
</button>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-300">
Max teams
</label>
<Input
type="number"
value={structure.maxTeams ?? 12}
@@ -200,18 +292,18 @@ export function LeagueStructureSection({
disabled={disabled}
min={1}
max={32}
className="w-28"
className="w-32"
/>
<p className="text-xs text-gray-500 flex items-start gap-1.5">
<Info className="w-3 h-3 mt-0.5 shrink-0" />
<span>Total competing teams</span>
</p>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-300">
Drivers per team
</label>
<p className="text-xs text-gray-500">
Common values are 23 drivers.
</p>
<div className="mt-2">
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-300">
Drivers per team
</label>
<Input
type="number"
value={structure.driversPerTeam ?? 2}
@@ -219,28 +311,36 @@ export function LeagueStructureSection({
disabled={disabled}
min={1}
max={6}
className="w-28"
className="w-32"
/>
<p className="text-xs text-gray-500 flex items-start gap-1.5">
<Info className="w-3 h-3 mt-0.5 shrink-0" />
<span>Common: 23 drivers</span>
</p>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-300">
Max drivers (derived)
</label>
<p className="text-xs text-gray-500">
Calculated as teams × drivers per team.
</p>
<div className="mt-2 max-w-[7rem]">
<Input
type="number"
value={structure.maxDrivers ?? 0}
disabled
/>
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-300">
Total grid size
</label>
<div className="flex items-center gap-2">
<Input
type="number"
value={structure.maxDrivers ?? 0}
disabled
className="w-32"
/>
<div className="text-xs text-gray-500">drivers</div>
</div>
<p className="text-xs text-gray-500 flex items-start gap-1.5">
<Info className="w-3 h-3 mt-0.5 shrink-0" />
<span>Auto-calculated from teams × drivers</span>
</p>
</div>
</div>
</div>
)}
</div>
</div>
)}
</div>
);
}