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:
parent
9f2eb57e7a
commit
1831898001
5 changed files with 20 additions and 23 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]);
|
||||
|
|
|
|||
10
app/hooks/useLocalTimezone.ts
Normal file
10
app/hooks/useLocalTimezone.ts
Normal 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;
|
||||
}
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue