From 198bd3b00ffd6460372d845b2fed4735e8c8d5a7 Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Mon, 23 Mar 2026 15:15:28 +0100 Subject: [PATCH] feat(sidebar): extract SidebarContent to proper React component Convert the sidebarContent(isMobile) closure function to a proper SidebarContent component with explicit props, enabling correct React reconciliation for both desktop and mobile sidebar instances. --- components/dashboard/Sidebar.tsx | 257 +++++++++++++++++++------------ 1 file changed, 159 insertions(+), 98 deletions(-) diff --git a/components/dashboard/Sidebar.tsx b/components/dashboard/Sidebar.tsx index b5d514b..41a35e5 100644 --- a/components/dashboard/Sidebar.tsx +++ b/components/dashboard/Sidebar.tsx @@ -269,6 +269,129 @@ function NavLink({ ) } +// ─── Sidebar Content ──────────────────────────────────────── + +interface SidebarContentProps { + isMobile: boolean + collapsed: boolean + siteId: string + sites: Site[] + canEdit: boolean + pendingHref: string | null + onNavigate: (href: string) => void + onMobileClose: () => void + onExpand: () => void + onCollapse: () => void + onToggle: () => void + wasCollapsed: React.MutableRefObject + auth: ReturnType + orgs: OrganizationMember[] + onSwitchOrganization: (orgId: string | null) => Promise + openSettings: () => void +} + +function SidebarContent({ + isMobile, collapsed, siteId, sites, canEdit, pendingHref, + onNavigate, onMobileClose, onExpand, onCollapse, onToggle, + wasCollapsed, auth, orgs, onSwitchOrganization, openSettings, +}: SidebarContentProps) { + const router = useRouter() + const c = isMobile ? false : collapsed + const { user } = auth + + return ( +
+ {/* App Switcher — top of sidebar (scope-level switch) */} +
+ + + + +
+ + {/* Logo — fixed layout, text fades */} + + + Pulse + + + Pulse + + + + {/* Site Picker */} + + + {/* Nav Groups */} + + + {/* Bottom — utility items */} +
+ {/* Notifications, Profile — same layout as nav items */} +
+ + + + + + + router.push('/onboarding')} + allowPersonalOrganization={false} + onOpenSettings={openSettings} + compact + anchor="right" + > + + + +
+ + {/* Settings + Collapse */} +
+ {!isMobile && ( + + )} +
+
+
+ ) +} + // ─── Main Sidebar ─────────────────────────────────────────── export default function Sidebar({ @@ -339,102 +462,6 @@ export default function Sidebar({ const handleNavigate = useCallback((href: string) => { setPendingHref(href) }, []) - const sidebarContent = (isMobile: boolean) => { - const c = isMobile ? false : collapsed - - return ( -
- {/* App Switcher — top of sidebar (scope-level switch) */} -
- - - - -
- - {/* Logo — fixed layout, text fades */} - - - Pulse - - - Pulse - - - - {/* Site Picker */} - - - {/* Nav Groups */} - - - {/* Bottom — utility items */} -
- {/* Notifications, Profile — same layout as nav items */} -
- - - - - - - router.push('/onboarding')} - allowPersonalOrganization={false} - onOpenSettings={openSettings} - compact - anchor="right" - > - - - -
- - {/* Settings + Collapse */} -
- {!isMobile && ( - - )} -
-
-
- ) - } - return ( <> {/* Desktop — ssr:false means this only renders on client, no hydration flash */} @@ -442,7 +469,24 @@ export default function Sidebar({ className="hidden md:flex flex-col shrink-0 border-r border-neutral-800/60 bg-neutral-900/90 backdrop-blur-xl overflow-hidden relative z-10" style={{ width: collapsed ? COLLAPSED : EXPANDED, transition: 'width 200ms cubic-bezier(0.4, 0, 0.2, 1)' }} > - {sidebarContent(false)} + {/* Mobile overlay */} @@ -456,7 +500,24 @@ export default function Sidebar({ - {sidebarContent(true)} + )}