feat: restore the destination workspace mailbox tag filter before saving route state when switching organizations, preserve other query parameters, and cover the mounted Accounts transition without clearing either workspace selection

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Matthew Meszaros
2026-10-08 07:06:25 +00:00
co-authored by Devin AI
parent b4ef37fe82
commit c7144c1502
2 changed files with 29 additions and 5 deletions
+22 -3
View File
@@ -1,13 +1,20 @@
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { createMemoryHistory, createRootRoute, createRoute, createRouter, Outlet, RouterProvider } from "@tanstack/react-router";
import { createMemoryHistory, createRootRoute, createRoute, createRouter, Outlet, RouterProvider, type AnyRouter } from "@tanstack/react-router";
import { createContext, useContext } from "react";
import { beforeEach, describe, expect, it } from "vitest";
import { parseSearch, stringifySearch } from "@/lib/routerSearch";
import useMailboxTagFilter from "./useMailboxTagFilter";
let workspace = "workspace";
let tags: readonly { id: string }[] | undefined;
const FilterConfig = createContext({ workspace, tags });
function TestRouter({ router }: { router: AnyRouter }) {
return <FilterConfig.Provider value={{ workspace, tags }}><RouterProvider router={router} /></FilterConfig.Provider>;
}
function Filters() {
const { workspace, tags } = useContext(FilterConfig);
const [tag, setTag] = useMailboxTagFilter(`user:${workspace}`, tags);
return <><output aria-label="Tag">{tag || "All accounts"}</output>
<button onClick={() => setTag("sending")}>Sending</button>
@@ -20,7 +27,7 @@ async function open(href = "/app/emails") {
const tasks = createRoute({ getParentRoute: () => root, path: "/app/tasks", component: () => <div>Tasks</div> });
const router = createRouter({ routeTree: root.addChildren([emails, tasks]), history: createMemoryHistory({ initialEntries: [href] }), parseSearch, stringifySearch });
await act(() => router.load());
return { router, ...render(<RouterProvider router={router} />) };
return { router, ...render(<TestRouter router={router} />) };
}
describe("remembered mailbox tag", () => {
@@ -35,7 +42,7 @@ describe("remembered mailbox tag", () => {
const page = await open();
expect(screen.getByLabelText("Tag")).toHaveTextContent("sending");
tags = [{ id: "sending" }];
page.rerender(<RouterProvider router={page.router} />);
page.rerender(<TestRouter router={page.router} />);
expect(screen.getByLabelText("Tag")).toHaveTextContent("sending");
page.unmount();
workspace = "another-workspace";
@@ -57,6 +64,18 @@ describe("remembered mailbox tag", () => {
await open(href);
expect(screen.getByLabelText("Tag")).toHaveTextContent("sending");
});
it("restores the new workspace's remembered filter instead of saving the previous URL tag", async () => {
sessionStorage.setItem("warmbly:mailbox-tag:user:another-workspace", "receiving");
const page = await open("/app/emails?tag=sending&tab=settings");
workspace = "another-workspace";
tags = [{ id: "receiving" }];
page.rerender(<TestRouter router={page.router} />);
await waitFor(() => expect(page.router.state.location.searchStr).toContain("tag=receiving"));
expect(screen.getByLabelText("Tag")).toHaveTextContent("receiving");
expect(page.router.state.location.searchStr).toContain("tab=settings");
expect(sessionStorage.getItem("warmbly:mailbox-tag:user:another-workspace")).toBe("receiving");
expect(sessionStorage.getItem("warmbly:mailbox-tag:user:workspace")).toBe("sending");
});
it("keeps All accounts after clearing and falls back for deleted or other-workspace tags", async () => {
sessionStorage.setItem("warmbly:mailbox-tag:other:workspace", "sending");
const page = await open("/app/emails?tag=sending");
+7 -2
View File
@@ -10,7 +10,8 @@ export default function useMailboxTagFilter(owner: string, validTags: readonly {
}, [key]);
const [memory, setMemory] = useState(() => ({ key, value: read() }));
const remembered = memory.key === key ? memory.value : read();
const selected = params.has("tag") ? urlTag : remembered;
const restoringOwner = memory.key !== key;
const selected = !restoringOwner && params.has("tag") ? urlTag : remembered;
const tag = validTags === undefined || validTags.some((candidate) => candidate.id === selected) ? selected : "";
const remember = useCallback((value: string) => {
setMemory({ key, value });
@@ -18,9 +19,13 @@ export default function useMailboxTagFilter(owner: string, validTags: readonly {
}, [key]);
useEffect(() => {
if (restoringOwner && tag !== urlTag) {
setURLTag(tag);
return;
}
remember(tag);
if (tag !== urlTag) setURLTag(tag);
}, [tag, urlTag, remember, setURLTag]);
}, [restoringOwner, tag, urlTag, remember, setURLTag]);
const setTag = useCallback((value: string) => {
remember(value);