diff --git a/app/routes/__tests__/settings.test.ts b/app/routes/__tests__/settings.test.ts index da286d2..660dcca 100644 --- a/app/routes/__tests__/settings.test.ts +++ b/app/routes/__tests__/settings.test.ts @@ -22,9 +22,21 @@ vi.mock("~/models/account", () => ({ findLinkedAccountsByUserId: vi.fn() })); vi.mock("~/models/team", () => ({ findTeamsByOwnerId: vi.fn(), removeTeamOwner: vi.fn() })); vi.mock("~/models/commissioner", () => ({ removeAllCommissionersByUserId: vi.fn() })); -import { loader } from "../settings"; +import { loader, shouldRevalidate } from "../settings"; import { auth } from "~/lib/auth.server"; +type RevalidateArgs = Parameters[0]; + +function revalidateArgs(overrides: Partial): RevalidateArgs { + return { + currentParams: {}, + nextParams: {}, + formMethod: undefined, + defaultShouldRevalidate: true, + ...overrides, + } as unknown as RevalidateArgs; +} + type LoaderArgs = Parameters[0]; function loaderArgs(section?: string): LoaderArgs { @@ -54,3 +66,37 @@ describe("/settings loader section handling", () => { expect(auth.api.getSession).toHaveBeenCalled(); }); }); + +describe("/settings shouldRevalidate", () => { + it("skips revalidation when only the section param changes", () => { + expect( + shouldRevalidate( + revalidateArgs({ currentParams: { section: "profile" }, nextParams: { section: "account" } }) + ) + ).toBe(false); + }); + + it("revalidates after a mutation regardless of section", () => { + expect( + shouldRevalidate( + revalidateArgs({ + currentParams: { section: "profile" }, + nextParams: { section: "account" }, + formMethod: "POST", + }) + ) + ).toBe(true); + }); + + it("defers to the default when the section is unchanged", () => { + expect( + shouldRevalidate( + revalidateArgs({ + currentParams: { section: "account" }, + nextParams: { section: "account" }, + defaultShouldRevalidate: true, + }) + ) + ).toBe(true); + }); +}); diff --git a/app/routes/settings.tsx b/app/routes/settings.tsx index d680b65..99cebd1 100644 --- a/app/routes/settings.tsx +++ b/app/routes/settings.tsx @@ -1,4 +1,4 @@ -import { redirect } from "react-router"; +import { redirect, type ShouldRevalidateFunctionArgs } from "react-router"; import { Bell, Key, Lock, Shield, User } from "lucide-react"; import { auth } from "~/lib/auth.server"; import { findUserById, findUserByUsername, isUserInActiveDraft, updateUser, anonymizeUserAccount, USERNAME_RE } from "~/models/user"; @@ -56,6 +56,20 @@ export function meta(): Route.MetaDescriptors { return [{ title: "Settings - Brackt" }]; } +export function shouldRevalidate({ + currentParams, + nextParams, + formMethod, + defaultShouldRevalidate, +}: ShouldRevalidateFunctionArgs) { + // Mutations (profile/avatar/notification updates) must refresh loader data. + if (formMethod && formMethod !== "GET") return true; + // Switching sections only changes the path param, and the loader payload is the + // same for every section, so don't refetch user/draft status/linked accounts. + if (currentParams.section !== nextParams.section) return false; + return defaultShouldRevalidate; +} + export async function loader(args: Route.LoaderArgs) { const section = args.params.section; if (section && !(VALID_SECTION_IDS as Set).has(section)) {