Replace settings redirect with toast notification (#445)

* Show toast instead of redirecting after league settings save

Commishes now stay on the settings page when saving, with a Sonner
toast confirming the save rather than being navigated to the league
homepage.

https://claude.ai/code/session_01PewdKxVfAbqasJbmk2UGw4

* Fix toast firing for unrelated intents after settings save

Tag update responses with intent: "update" so the success useEffect
only fires for the main settings form, not for owner/commissioner/
reset-draft actions which also return { success: true }. Also replaces
the remaining ?updated=true redirect (no-season edge case) with the
same response shape for consistency.

https://claude.ai/code/session_01PewdKxVfAbqasJbmk2UGw4

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Chris Parsons 2026-05-18 16:08:10 -07:00 committed by GitHub
parent 68193e31c5
commit 3c757c1f73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 12 additions and 11 deletions

View file

@ -25,13 +25,6 @@ export function SettingsMessage({ actionData }: { actionData: SettingsActionData
</div>
);
}
if (actionData.success) {
return (
<div className="rounded-md bg-emerald-500/15 px-4 py-3 text-sm text-emerald-700 dark:text-emerald-300">
{actionData.message ?? "Settings updated successfully."}
</div>
);
}
return null;
}

View file

@ -268,7 +268,7 @@ export async function action(args: Route.ActionArgs) {
const season = await findCurrentSeasonWithSports(leagueId);
if (!season) {
if (intent === "update") {
return redirect(`/leagues/${leagueId}?updated=true`);
return { success: true, message: "Settings saved successfully.", intent: "update" as const };
}
return { error: "No active season found" };
}
@ -776,7 +776,7 @@ export async function action(args: Route.ActionArgs) {
}
}
return redirect(`/leagues/${leagueId}?updated=true`);
return { success: true, message: "Settings saved successfully.", intent: "update" as const };
} catch (error) {
logger.error("Error updating season settings:", error);
return { error: "Failed to update season settings. Please try again." };

View file

@ -179,8 +179,8 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone
setHasDraftOrderChanges(false);
}, [draftSlots, teams]);
// Re-mark dirty if the settings save returned an error (success path redirects away, so no cleanup
// needed there). Guard against non-settings errors (e.g. draft-order) which carry a `section` field.
// Re-mark dirty if the settings save returned an error. Guard against non-settings errors
// (e.g. draft-order) which carry a `section` field.
useEffect(() => {
if (navigation.state !== "idle") return;
if (actionData && "error" in actionData && !("section" in actionData)) {
@ -188,6 +188,14 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone
}
}, [actionData, navigation.state]);
useEffect(() => {
if (navigation.state !== "idle") return;
if (actionData && "intent" in actionData && actionData.intent === "update" && actionData.success) {
toast.success(actionData.message ?? "Settings saved!");
setHasUnsavedSettingsChanges(false);
}
}, [actionData, navigation.state]);
const canEditSports = season?.status === "pre_draft";
const canEditTeamCount = season?.status === "pre_draft";
const canEditDraftOrder = season?.status === "pre_draft";