From f258d7a30430be39b31ea5d5d1e2767dc3f529b3 Mon Sep 17 00:00:00 2001 From: Chris Parsons <438676+chrisparsons83@users.noreply.github.com> Date: Mon, 18 May 2026 08:47:46 -0700 Subject: [PATCH] fix: prevent useBlocker from intercepting same-route form submissions (#443) useBlocker was receiving a boolean, which caused it to block the settings form's own POST submission before the onSubmit state-clear could propagate. Switching to a BlockerFunction that checks nextLocation.pathname lets same-URL form posts through, so the "leave without saving?" dialog only fires on genuine navigation away from the settings page. Co-authored-by: Claude Sonnet 4.6 --- app/routes/leagues/$leagueId.settings.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/routes/leagues/$leagueId.settings.tsx b/app/routes/leagues/$leagueId.settings.tsx index 345096e..3467453 100644 --- a/app/routes/leagues/$leagueId.settings.tsx +++ b/app/routes/leagues/$leagueId.settings.tsx @@ -1,5 +1,5 @@ -import { useState, useEffect } from "react"; -import { Form, useBeforeUnload, useBlocker, useNavigation } from "react-router"; +import { useState, useEffect, useCallback } from "react"; +import { Form, useBeforeUnload, useBlocker, useLocation, useNavigation, type BlockerFunction } from "react-router"; import { format } from "date-fns"; import { AlertTriangle, @@ -119,6 +119,7 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone } = loaderData; const navigation = useNavigation(); + const location = useLocation(); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const [mobileView, setMobileView] = useState<"grid" | "section">("grid"); const [activeSection, setActiveSection] = useState("league-basics"); @@ -202,7 +203,12 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone const isSubmittingSettings = navigation.state === "submitting" && updateIntent === "update"; const isSubmittingDraftOrder = navigation.state === "submitting" && updateIntent === "set-draft-order"; const shouldWarnUnsaved = (hasUnsavedSettingsChanges || hasDraftOrderChanges) && !isSubmittingSettings && !isSubmittingDraftOrder; - const blocker = useBlocker(shouldWarnUnsaved); + const blocker = useBlocker( + useCallback( + ({ nextLocation }) => shouldWarnUnsaved && nextLocation.pathname !== location.pathname, + [shouldWarnUnsaved, location.pathname] + ) + ); const inviteUrl = season?.inviteCode ? `${typeof window !== "undefined" ? window.location.origin : ""}/i/${season.inviteCode}` : "";