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
This commit is contained in:
Claude 2026-05-15 22:25:28 +00:00
parent 9f2eb57e7a
commit 1831898001
No known key found for this signature in database
5 changed files with 20 additions and 23 deletions

View file

@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
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";
@ -65,10 +65,7 @@ export function DraftSetupSection({
onOvernightTimezoneChange: (v: string) => void;
commishTimezone: string | null;
}) {
const [localTz, setLocalTz] = useState("");
useEffect(() => {
setLocalTz(Intl.DateTimeFormat().resolvedOptions().timeZone);
}, []);
const localTz = useLocalTimezone();
return (
<SettingsSection

View file

@ -8,8 +8,6 @@ import { SettingsSection, SettingsStatusPill } from "./SettingsSection";
type SportsSeason = {
id: string;
name: string;
year: number;
scoringType: string;
sport: { id: string; name: string; slug: string; type: string; iconUrl: string | null };
};

View file

@ -7,24 +7,18 @@ import { SportsSection } from "../SportsSection";
type SportsSeason = {
id: string;
name: string;
year: number;
scoringType: string;
sport: { id: string; name: string; slug: string; type: string; iconUrl: string | null };
};
const displaySportsSeasons: SportsSeason[] = [
{
id: "nba-2025",
name: "2025 Season",
year: 2025,
scoringType: "standings",
name: "2025 NBA Season",
sport: { id: "sport-1", name: "NBA", slug: "nba", type: "team", iconUrl: "/sports-icons/nba.svg" },
},
{
id: "mlb-2025",
name: "2025 Season",
year: 2025,
scoringType: "playoffs",
name: "2025 MLB Season",
sport: { id: "sport-2", name: "MLB", slug: "mlb", type: "team", iconUrl: "/sports-icons/mlb.svg" },
},
];
@ -82,10 +76,10 @@ describe("SportsSection", () => {
const user = userEvent.setup();
render(<SportsSectionHarness />);
const mlbCheckbox = screen.getByRole("checkbox", { name: /mlb - 2025 season \(2025\)/i });
const mlbCheckbox = screen.getByRole("checkbox", { name: /2025 mlb season/i });
expect(mlbCheckbox).not.toBeChecked();
await user.click(screen.getByText("MLB - 2025 Season (2025)"));
await user.click(screen.getByText("2025 MLB Season"));
expect(mlbCheckbox).toBeChecked();
});
@ -95,7 +89,7 @@ describe("SportsSection", () => {
const handleSubmit = vi.fn();
render(<SportsSectionHarness onSubmit={handleSubmit} />);
await user.click(screen.getByText("MLB - 2025 Season (2025)"));
await user.click(screen.getByText("2025 MLB Season"));
await user.click(screen.getByRole("button", { name: "Save" }));
expect(handleSubmit).toHaveBeenCalledWith(["nba-2025", "mlb-2025"]);

View file

@ -0,0 +1,10 @@
import { useState, useEffect } from "react";
export function useLocalTimezone() {
const [tz, setTz] = useState("");
useEffect(() => {
const parts = Intl.DateTimeFormat(undefined, { timeZoneName: "short" }).formatToParts(new Date());
setTz(parts.find((p) => p.type === "timeZoneName")?.value ?? "");
}, []);
return tz;
}

View file

@ -25,6 +25,7 @@ import { Checkbox } from "~/components/ui/checkbox";
import { cn } from "~/lib/utils";
import { parseDraftSpeed, formatTime12h } from "~/lib/draft-timer";
import { TIMEZONE_OPTIONS } from "~/components/league/TimezoneSelect";
import { useLocalTimezone } from "~/hooks/useLocalTimezone";
import { saveWizardState, buildFormDataFromSnapshot } from "~/lib/wizard-state";
import { type ScoringRules, DEFAULT_SCORING_RULES } from "~/lib/scoring-types";
import { SportIcon } from "~/components/league/SportIcon";
@ -659,10 +660,7 @@ function Step3DraftSettings({
const { draftInitialTime, draftIncrementTime } = parseDraftSpeed(draftSpeed, timerMode);
const showOvernightPause = draftInitialTime >= 3600 || draftIncrementTime >= 600;
const [localTz, setLocalTz] = useState("");
useEffect(() => {
setLocalTz(Intl.DateTimeFormat().resolvedOptions().timeZone);
}, []);
const localTz = useLocalTimezone();
useEffect(() => {
if (!showOvernightPause) setOvernightMode("none");
@ -917,7 +915,7 @@ function StepReview({
<span className="text-primary font-semibold">{uniqueSportsCount} sport{uniqueSportsCount !== 1 ? "s" : ""}</span>
</p>
<ul className="mt-1 space-y-1">
{selectedSeasons.toSorted((a, b) => a.sport.name.localeCompare(b.sport.name)).map((s) => (
{selectedSeasons.toSorted((a, b) => a.name.localeCompare(b.name)).map((s) => (
<li key={s.id} className="flex items-center gap-2 text-sm text-foreground">
<SportIcon sport={s.sport} />
{s.name}