From 10bfa0ca855a5295b3623cea858a30bbda627d14 Mon Sep 17 00:00:00 2001 From: waterWang Date: Mon, 3 Aug 2026 05:04:11 +0800 Subject: [PATCH] fix: preserve sidebar collapse state across route changes (Closes #914) --- src/components/Layout.test.tsx | 26 +++++++++++++++++++- src/components/navigation/MobileNav.test.tsx | 1 + src/components/navigation/MobileNav.tsx | 7 ------ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/components/Layout.test.tsx b/src/components/Layout.test.tsx index 9bd18028..9fbd49e7 100644 --- a/src/components/Layout.test.tsx +++ b/src/components/Layout.test.tsx @@ -39,6 +39,7 @@ function renderLayout(initialPath = '/') { describe('Layout Integration', () => { beforeEach(() => { document.body.style.overflow = '' + sessionStorage.clear() }) it('renders skip link and main branding', () => { @@ -148,6 +149,29 @@ describe('Layout Integration', () => { expect(drawer).toHaveAttribute('aria-hidden', 'true') }) + it('preserves sidebar collapse state across route changes', () => { + renderLayout('/dashboard') + const hamburger = screen.getByRole('button', { name: /open navigation menu/i }) + const drawer = document.getElementById('mobile-nav-drawer') as HTMLElement + + // Open the drawer + fireEvent.click(hamburger) + expect(drawer).toHaveAttribute('aria-hidden', 'false') + + // Navigate to a different route via a desktop nav link (not inside the drawer) + // Desktop nav links are outside the drawer and don't trigger onClick={close} + const desktopDashboardLink = screen + .getAllByRole('link', { name: /dashboard/i }) + .find((link) => !drawer.contains(link)) + expect(desktopDashboardLink).toBeDefined() + if (desktopDashboardLink) { + fireEvent.click(desktopDashboardLink) + } + + // The drawer should remain open after route change + expect(drawer).toHaveAttribute('aria-hidden', 'false') + }) + // --- BottomNav integration --- it('renders BottomNav inside the layout', () => { @@ -161,4 +185,4 @@ describe('Layout Integration', () => { const tabs = Array.from(bottomNav.querySelectorAll('a')) expect(tabs).toHaveLength(5) }) -}) +}) \ No newline at end of file diff --git a/src/components/navigation/MobileNav.test.tsx b/src/components/navigation/MobileNav.test.tsx index 1c4a31e6..a7168607 100644 --- a/src/components/navigation/MobileNav.test.tsx +++ b/src/components/navigation/MobileNav.test.tsx @@ -19,6 +19,7 @@ function getDrawer() { describe('MobileNav', () => { beforeEach(() => { document.body.style.overflow = '' + sessionStorage.clear() }) // --- render --- diff --git a/src/components/navigation/MobileNav.tsx b/src/components/navigation/MobileNav.tsx index 58f2cb27..6268b40f 100644 --- a/src/components/navigation/MobileNav.tsx +++ b/src/components/navigation/MobileNav.tsx @@ -25,13 +25,6 @@ export default function MobileNav() { useScrollPreserver({ isActive: isOpen }) - // Close on route change (SPA navigation) — but state survives full page reloads via sessionStorage - const prevPath = useRef(location.pathname) - if (prevPath.current !== location.pathname) { - prevPath.current = location.pathname - if (isOpen) setIsOpen(false) - } - // Persist collapse state across full page reloads useEffect(() => { try {