From 5e668fc914c62a246d4f930e9cdb3ce1294e8f77 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 15 May 2026 20:19:12 +0000 Subject: [PATCH] Fix custom chess-clock timer detection and save settings blocker - Extract getInitialDraftSpeed() helper so both useState init and resetSettingsFormState use the same logic; unrecognized presets now produce a "custom:{bank}:{incr}" string instead of falling back to "standard", so the custom section auto-expands correctly (e.g. 8 hr bank + 30 min increment is no longer shown as Standard) - resetSettingsFormState was not resetting draftSpeed at all; fixed - Clear hasUnsavedSettingsChanges in the Form's onSubmit so the useBlocker check is false at the moment the save navigation starts, preventing the "Leave without saving?" dialog from firing on save - Replace the cleared-on-success useEffect with one that re-marks dirty when the action returns an error, so the warning reappears after a failed save https://claude.ai/code/session_01DgHNkvJXGizx41CE2tkVS1 --- app/routes/leagues/$leagueId.settings.tsx | 36 +++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/app/routes/leagues/$leagueId.settings.tsx b/app/routes/leagues/$leagueId.settings.tsx index cdc82da..579d96a 100644 --- a/app/routes/leagues/$leagueId.settings.tsx +++ b/app/routes/leagues/$leagueId.settings.tsx @@ -48,6 +48,19 @@ type LoaderSportsSeason = Route.ComponentProps["loaderData"]["allSportsSeasons"] fantasySeasonId?: string | null; }; +function getInitialDraftSpeed(season: LoaderSeason): string { + const mode = season?.draftTimerMode ?? "chess_clock"; + if (mode === "standard") return season?.draftIncrementTime?.toString() ?? "90"; + if (season?.draftInitialTime === 60 && season?.draftIncrementTime === 10) return "fast"; + if (season?.draftInitialTime === 120 && season?.draftIncrementTime === 15) return "standard"; + if (season?.draftInitialTime === 28800 && season?.draftIncrementTime === 3600) return "slow"; + if (season?.draftInitialTime === 43200 && season?.draftIncrementTime === 3600) return "very-slow"; + if (season?.draftInitialTime != null && season?.draftIncrementTime != null) { + return `custom:${season.draftInitialTime}:${season.draftIncrementTime}`; + } + return "standard"; +} + function getInitialScoringPreset(season: LoaderSeason) { const rules: ScoringRules = { pointsFor1st: season?.pointsFor1st ?? DEFAULT_SCORING_RULES.pointsFor1st, @@ -148,15 +161,7 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone pointsFor7th: season?.pointsFor7th ?? DEFAULT_SCORING_RULES.pointsFor7th, pointsFor8th: season?.pointsFor8th ?? DEFAULT_SCORING_RULES.pointsFor8th, }); - const initTimerMode = season?.draftTimerMode ?? "chess_clock"; - const [draftSpeed, setDraftSpeed] = useState(() => { - if (initTimerMode === "standard") return season?.draftIncrementTime?.toString() ?? "90"; - if (season?.draftInitialTime === 60 && season?.draftIncrementTime === 10) return "fast"; - if (season?.draftInitialTime === 120 && season?.draftIncrementTime === 15) return "standard"; - if (season?.draftInitialTime === 28800 && season?.draftIncrementTime === 3600) return "slow"; - if (season?.draftInitialTime === 43200 && season?.draftIncrementTime === 3600) return "very-slow"; - return "standard"; - }); + const [draftSpeed, setDraftSpeed] = useState(() => getInitialDraftSpeed(season)); const [selectedSports, setSelectedSports] = useState>( () => getInitialSelectedSports({ season, allSportsSeasons }) ); @@ -184,13 +189,13 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone setHasDraftOrderChanges(false); }, [draftSlots, teams]); - // Clear settings dirty flag after a successful (non-error) submission + // Re-mark dirty if the save returned an error (success path redirects away, so no cleanup needed there) useEffect(() => { - if (!hasUnsavedSettingsChanges || navigation.state !== "idle") return; - if (actionData && !("error" in actionData)) { - setHasUnsavedSettingsChanges(false); + if (navigation.state !== "idle") return; + if (actionData && "error" in actionData) { + setHasUnsavedSettingsChanges(true); } - }, [actionData, hasUnsavedSettingsChanges, navigation.state]); + }, [actionData, navigation.state]); const canEditSports = season?.status === "pre_draft"; const canEditTeamCount = season?.status === "pre_draft"; @@ -235,6 +240,7 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone setDiscordWebhookUrl(league.discordWebhookUrl ?? ""); setTeamCountValue(teamCount); setTimerMode(season?.draftTimerMode ?? "chess_clock"); + setDraftSpeed(getInitialDraftSpeed(season)); setOvernightMode(season?.overnightPauseMode ?? "none"); setOvernightStart(season?.overnightPauseStart ?? "23:00"); setOvernightEnd(season?.overnightPauseEnd ?? "07:00"); @@ -345,7 +351,7 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone
{showUpdateForm && ( -
+ setHasUnsavedSettingsChanges(false)}>