* Show season name instead of year/bracket format; add local timezone hint to draft time Replace the raw year number and scoringType string in the league creation sport picker, review step, and league settings sports section with the human-readable season name (e.g. "2025 NBA Season"), matching how the league homepage sports list already displays seasons. Add a client-side local timezone label below the draft date & time fields on both the league creation wizard and the league settings page, so users know that draft times are in their local timezone. https://claude.ai/code/session_01GtJowGruAc1A4jURkSDVjX * Address code review: shared tz hook, short abbrev, sort fix, dead type cleanup, test update - Extract timezone detection into useLocalTimezone hook to avoid duplication across DraftSetupSection and Step3DraftSettings - Use Intl short timezone abbreviation (e.g. "EST") instead of raw IANA name, matching DraftInfoCard's existing pattern - Sort review step sport list by season name instead of sport.name so the visible order matches the displayed text - Remove unused scoringType and year fields from SportsSection's local type - Update SportsSection tests to use realistic season names and the new display format https://claude.ai/code/session_01GtJowGruAc1A4jURkSDVjX --------- Co-authored-by: Claude <noreply@anthropic.com>
194 lines
7.3 KiB
TypeScript
194 lines
7.3 KiB
TypeScript
import { Swords, CalendarIcon } from "lucide-react";
|
|
import { useLocalTimezone } from "~/hooks/useLocalTimezone";
|
|
import { format } from "date-fns";
|
|
import { Label } from "~/components/ui/label";
|
|
import { Input } from "~/components/ui/input";
|
|
import { Button } from "~/components/ui/button";
|
|
import { Badge } from "~/components/ui/badge";
|
|
import { Calendar } from "~/components/ui/calendar";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "~/components/ui/popover";
|
|
import { cn } from "~/lib/utils";
|
|
import { TimerModeSelector } from "~/components/league/TimerModeSelector";
|
|
import { DraftSpeedPicker } from "~/components/league/DraftSpeedPicker";
|
|
import { OvernightPauseSettings } from "~/components/league/OvernightPauseSettings";
|
|
import { StepperInput } from "~/components/league/StepperInput";
|
|
import { SettingsSection, SettingsStatusPill } from "./SettingsSection";
|
|
|
|
export function DraftSetupSection({
|
|
active,
|
|
canEditDraftRounds,
|
|
minRounds,
|
|
recommendedRounds,
|
|
flexSpots,
|
|
draftRounds,
|
|
onDraftRoundsChange,
|
|
draftDate,
|
|
onDraftDateChange,
|
|
draftTime,
|
|
onDraftTimeChange,
|
|
timerMode,
|
|
onTimerModeChange,
|
|
draftSpeed,
|
|
onDraftSpeedChange,
|
|
overnightMode,
|
|
onOvernightModeChange,
|
|
overnightStart,
|
|
onOvernightStartChange,
|
|
overnightEnd,
|
|
onOvernightEndChange,
|
|
overnightTimezone,
|
|
onOvernightTimezoneChange,
|
|
commishTimezone,
|
|
}: {
|
|
active: boolean;
|
|
canEditDraftRounds: boolean;
|
|
minRounds: number;
|
|
recommendedRounds: number;
|
|
flexSpots: number;
|
|
draftRounds: number;
|
|
onDraftRoundsChange: (v: number) => void;
|
|
draftDate: Date | undefined;
|
|
onDraftDateChange: (v: Date | undefined) => void;
|
|
draftTime: string;
|
|
onDraftTimeChange: (v: string) => void;
|
|
timerMode: "chess_clock" | "standard";
|
|
onTimerModeChange: (v: "chess_clock" | "standard") => void;
|
|
draftSpeed: string;
|
|
onDraftSpeedChange: (v: string) => void;
|
|
overnightMode: "none" | "league" | "per_user";
|
|
onOvernightModeChange: (v: "none" | "league" | "per_user") => void;
|
|
overnightStart: string;
|
|
onOvernightStartChange: (v: string) => void;
|
|
overnightEnd: string;
|
|
onOvernightEndChange: (v: string) => void;
|
|
overnightTimezone: string;
|
|
onOvernightTimezoneChange: (v: string) => void;
|
|
commishTimezone: string | null;
|
|
}) {
|
|
const localTz = useLocalTimezone();
|
|
|
|
return (
|
|
<SettingsSection
|
|
id="draft-setup"
|
|
icon={Swords}
|
|
title="Draft Settings"
|
|
description="Configure the draft format, timing, overnight protections, and pick order."
|
|
status={<SettingsStatusPill tone={canEditDraftRounds ? "success" : "locked"}>{canEditDraftRounds ? "Editable" : "Locked"}</SettingsStatusPill>}
|
|
className={active ? undefined : "hidden"}
|
|
>
|
|
<input type="hidden" name="draftRounds" value={draftRounds} />
|
|
<input type="hidden" name="draftTimerMode" value={timerMode} />
|
|
<input type="hidden" name="draftSpeed" value={draftSpeed} />
|
|
<input type="hidden" name="overnightPauseMode" value={overnightMode} />
|
|
<input type="hidden" name="overnightPauseStart" value={overnightStart} />
|
|
<input type="hidden" name="overnightPauseEnd" value={overnightEnd} />
|
|
<input type="hidden" name="overnightPauseTimezone" value={overnightTimezone} />
|
|
{draftDate && draftTime ? (
|
|
<input
|
|
type="hidden"
|
|
name="draftDateTime"
|
|
value={new Date(`${format(draftDate, "yyyy-MM-dd")}T${draftTime}`).toISOString()}
|
|
/>
|
|
) : (
|
|
<input type="hidden" name="draftDateTime" value="" />
|
|
)}
|
|
|
|
<div className="space-y-8">
|
|
<div className="space-y-8">
|
|
<div className="rounded-lg border p-5 sm:p-6">
|
|
<div className="mb-5 flex items-start justify-between gap-3">
|
|
<div>
|
|
<Label>Draft Rounds</Label>
|
|
<p className="text-sm text-muted-foreground">Minimum {minRounds}; recommended {recommendedRounds}.</p>
|
|
</div>
|
|
<Badge variant="outline">{flexSpots} flex</Badge>
|
|
</div>
|
|
<StepperInput
|
|
value={draftRounds}
|
|
min={canEditDraftRounds ? Math.max(1, minRounds) : draftRounds}
|
|
max={canEditDraftRounds ? 50 : draftRounds}
|
|
onChange={onDraftRoundsChange}
|
|
decrementLabel="Decrease draft rounds"
|
|
incrementLabel="Increase draft rounds"
|
|
/>
|
|
{!canEditDraftRounds && (
|
|
<p className="mt-3 text-sm text-muted-foreground">Round count cannot be changed after draft starts.</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="rounded-lg border p-5 sm:p-6">
|
|
<Label htmlFor="draftDate">Draft Date & Time</Label>
|
|
<div className="mt-5 grid gap-3 sm:grid-cols-2">
|
|
<Popover>
|
|
<PopoverTrigger asChild>
|
|
<Button
|
|
variant="outline"
|
|
className={cn("justify-start text-left font-normal", !draftDate && "text-muted-foreground")}
|
|
disabled={!canEditDraftRounds}
|
|
>
|
|
<CalendarIcon className="mr-2 h-4 w-4" />
|
|
{draftDate ? format(draftDate, "PPP") : <span>Pick a date</span>}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-auto p-0">
|
|
<Calendar
|
|
mode="single"
|
|
selected={draftDate}
|
|
onSelect={(date) => onDraftDateChange(date)}
|
|
disabled={(date) => date < new Date(new Date().setHours(0, 0, 0, 0))}
|
|
/>
|
|
</PopoverContent>
|
|
</Popover>
|
|
<Input
|
|
type="time"
|
|
value={draftTime}
|
|
onChange={(e) => onDraftTimeChange(e.target.value)}
|
|
disabled={!canEditDraftRounds}
|
|
/>
|
|
</div>
|
|
<p className="mt-4 text-sm text-muted-foreground">
|
|
Set this before starting the draft room.
|
|
{localTz && <> Times are in your local timezone ({localTz}).</>}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-8 rounded-lg border p-5 sm:p-6">
|
|
<div className="space-y-4">
|
|
<Label>Timer Mode</Label>
|
|
<TimerModeSelector
|
|
value={timerMode}
|
|
onChange={onTimerModeChange}
|
|
disabled={!canEditDraftRounds}
|
|
/>
|
|
</div>
|
|
<div className="border-t pt-8 space-y-4">
|
|
<Label>Draft Speed</Label>
|
|
<DraftSpeedPicker
|
|
timerMode={timerMode}
|
|
value={draftSpeed}
|
|
onChange={onDraftSpeedChange}
|
|
disabled={!canEditDraftRounds}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="rounded-lg border p-5 sm:p-6">
|
|
<OvernightPauseSettings
|
|
show={true}
|
|
mode={overnightMode}
|
|
onModeChange={onOvernightModeChange}
|
|
start={overnightStart}
|
|
onStartChange={onOvernightStartChange}
|
|
end={overnightEnd}
|
|
onEndChange={onOvernightEndChange}
|
|
timezone={overnightTimezone}
|
|
onTimezoneChange={onOvernightTimezoneChange}
|
|
commishTimezone={commishTimezone}
|
|
disabled={!canEditDraftRounds}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</SettingsSection>
|
|
);
|
|
}
|