wip
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { TrendingDown, Info } from 'lucide-react';
|
||||
import type { LeagueConfigFormModel } from '@gridpilot/racing/application';
|
||||
import Input from '@/components/ui/Input';
|
||||
import SegmentedControl from '@/components/ui/SegmentedControl';
|
||||
@@ -52,6 +53,22 @@ export function LeagueDropSection({
|
||||
});
|
||||
};
|
||||
|
||||
const getSuggestedN = () => {
|
||||
const rounds = form.timings.roundsPlanned;
|
||||
if (!rounds || rounds <= 0) return null;
|
||||
|
||||
if (dropPolicy.strategy === 'bestNResults') {
|
||||
// Suggest keeping 70-80% of rounds
|
||||
const suggestion = Math.max(1, Math.floor(rounds * 0.75));
|
||||
return { value: suggestion, explanation: `Keep best ${suggestion} of ${rounds} rounds (75%)` };
|
||||
} else if (dropPolicy.strategy === 'dropWorstN') {
|
||||
// Suggest dropping 1-2 rounds for every 8-10 rounds
|
||||
const suggestion = Math.max(1, Math.floor(rounds / 8));
|
||||
return { value: suggestion, explanation: `Drop worst ${suggestion} of ${rounds} rounds` };
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const computeSummary = () => {
|
||||
if (dropPolicy.strategy === 'none') {
|
||||
return 'All results will count towards the championship.';
|
||||
@@ -80,58 +97,104 @@ export function LeagueDropSection({
|
||||
? 'bestN'
|
||||
: 'dropWorstN';
|
||||
|
||||
const suggestedN = getSuggestedN();
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-sm font-semibold text-white">Drop rule</h3>
|
||||
<p className="text-xs text-gray-400">
|
||||
Decide whether to count every round or ignore a few worst results.
|
||||
</p>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<TrendingDown className="w-4 h-4 text-primary-blue" />
|
||||
<h3 className="text-sm font-semibold text-white">Drop rule</h3>
|
||||
</div>
|
||||
<p className="text-xs text-gray-400">
|
||||
Protect drivers from bad races by dropping worst results or counting only the best ones
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<SegmentedControl
|
||||
options={[
|
||||
{ value: 'all', label: 'All count' },
|
||||
{ value: 'bestN', label: 'Best N' },
|
||||
{ value: 'dropWorstN', label: 'Drop worst N' },
|
||||
]}
|
||||
value={currentStrategyValue}
|
||||
onChange={(value) => {
|
||||
if (disabled) return;
|
||||
if (value === 'all') {
|
||||
handleStrategyChange('none');
|
||||
} else if (value === 'bestN') {
|
||||
handleStrategyChange('bestNResults');
|
||||
} else if (value === 'dropWorstN') {
|
||||
handleStrategyChange('dropWorstN');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="space-y-3">
|
||||
<SegmentedControl
|
||||
options={[
|
||||
{ value: 'all', label: 'All count', description: 'Every race matters' },
|
||||
{ value: 'bestN', label: 'Best N', description: 'Keep best results' },
|
||||
{ value: 'dropWorstN', label: 'Drop worst N', description: 'Ignore worst results' },
|
||||
]}
|
||||
value={currentStrategyValue}
|
||||
onChange={(value) => {
|
||||
if (disabled) return;
|
||||
if (value === 'all') {
|
||||
handleStrategyChange('none');
|
||||
} else if (value === 'bestN') {
|
||||
handleStrategyChange('bestNResults');
|
||||
} else if (value === 'dropWorstN') {
|
||||
handleStrategyChange('dropWorstN');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{dropPolicy.strategy === 'none' && (
|
||||
<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">All count:</span> Every race result affects the championship. Best for shorter seasons or when consistency is key.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{(dropPolicy.strategy === 'bestNResults' ||
|
||||
dropPolicy.strategy === 'dropWorstN') && (
|
||||
<div className="mt-2 max-w-[140px]">
|
||||
<label className="mb-1 block text-xs font-medium text-gray-300">
|
||||
N
|
||||
</label>
|
||||
<Input
|
||||
type="number"
|
||||
value={
|
||||
typeof dropPolicy.n === 'number' && dropPolicy.n > 0
|
||||
? String(dropPolicy.n)
|
||||
: ''
|
||||
}
|
||||
onChange={(e) => handleNChange(e.target.value)}
|
||||
disabled={disabled}
|
||||
min={1}
|
||||
/>
|
||||
<p className="mt-1 text-[11px] text-gray-500">
|
||||
{dropPolicy.strategy === 'bestNResults'
|
||||
? 'For example, best 6 of 10 rounds count.'
|
||||
: 'For example, drop the worst 2 results.'}
|
||||
</p>
|
||||
<div className="space-y-3">
|
||||
{suggestedN && (
|
||||
<div className="rounded-lg bg-primary-blue/5 border border-primary-blue/20 p-3">
|
||||
<p className="text-xs text-gray-300 mb-2">
|
||||
<span className="font-medium text-primary-blue">Suggested:</span> {suggestedN.explanation}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleNChange(String(suggestedN.value))}
|
||||
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"
|
||||
>
|
||||
Use suggested value ({suggestedN.value})
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="rounded-lg border border-charcoal-outline bg-iron-gray/30 p-4 space-y-3">
|
||||
<div className="flex items-start gap-2">
|
||||
<Info className="w-4 h-4 text-primary-blue mt-0.5 shrink-0" />
|
||||
<div className="flex-1">
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Number of rounds (N)
|
||||
</label>
|
||||
<Input
|
||||
type="number"
|
||||
value={
|
||||
typeof dropPolicy.n === 'number' && dropPolicy.n > 0
|
||||
? String(dropPolicy.n)
|
||||
: ''
|
||||
}
|
||||
onChange={(e) => handleNChange(e.target.value)}
|
||||
disabled={disabled}
|
||||
min={1}
|
||||
className="max-w-[140px]"
|
||||
/>
|
||||
<p className="mt-2 text-xs text-gray-500">
|
||||
{dropPolicy.strategy === 'bestNResults'
|
||||
? 'Only your best N results will count towards the championship. Great for long seasons.'
|
||||
: 'Your worst N results will be excluded from the championship. Helps forgive bad days.'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="mt-3 text-xs text-gray-400">{computeSummary()}</p>
|
||||
<div className="rounded-lg border border-charcoal-outline/50 bg-iron-gray/30 p-4">
|
||||
<div className="flex items-start gap-2">
|
||||
<Info className="w-4 h-4 text-primary-blue mt-0.5 shrink-0" />
|
||||
<div className="text-xs text-gray-300">{computeSummary()}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user