From d575e12bf3bd4d4d81291f97064ab7017ee1bc08 Mon Sep 17 00:00:00 2001 From: Dwindi Ramadhana Date: Fri, 26 Dec 2025 22:42:41 +0700 Subject: [PATCH] fix: Navigation active state redesign + Wishlist in all themes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue 1 - Dashboard Still Always Active (Final Fix): Problem: Despite multiple attempts, dashboard remained active on all routes Root Cause: Path-based matching with startsWith() was fundamentally flawed Solution: Complete redesign - use useActiveSection hook state instead - Replaced ActiveNavLink component with simple Link - Active state determined by: main.key === item.key - No more path matching, childPaths, or complex logic - Single source of truth: useActiveSection hook Result: Navigation now works correctly - only one menu active at a time ✅ Changes: - Sidebar: Uses useActiveSection().main.key for active state - TopNav: Uses useActiveSection().main.key for active state - Removed all path-based matching logic - Simplified navigation rendering Issue 2 - Wishlist Only in Classic Theme: Problem: Only ClassicLayout had wishlist icon, other themes missing Root Cause: Wishlist feature was only implemented in one layout Solution: Added wishlist icon to all applicable layout themes - ModernLayout: Added wishlist with module + settings checks - BoutiqueLayout: Added wishlist with module + settings checks - LaunchLayout: Skipped (minimal checkout-only layout) Result: All themes now support wishlist feature ✅ Files Modified (2): - admin-spa/src/App.tsx (navigation redesign) - customer-spa/src/layouts/BaseLayout.tsx (wishlist in all themes) - admin-spa/dist/app.js + customer-spa/dist/app.js (rebuilt) Both issues finally resolved with proper architectural approach! --- admin-spa/src/App.tsx | 30 +++++++++++-------------- customer-spa/src/layouts/BaseLayout.tsx | 14 ++++++++++++ 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/admin-spa/src/App.tsx b/admin-spa/src/App.tsx index 574a791..3a164e0 100644 --- a/admin-spa/src/App.tsx +++ b/admin-spa/src/App.tsx @@ -132,6 +132,7 @@ function ActiveNavLink({ to, startsWith, end, className, children, childPaths }: function Sidebar() { const link = "flex items-center gap-2 rounded-md px-3 py-2 hover:bg-accent hover:text-accent-foreground shadow-none hover:shadow-none focus:shadow-none focus:outline-none focus:ring-0"; const active = "bg-secondary"; + const { main } = useActiveSection(); // Icon mapping const iconMap: Record = { @@ -153,19 +154,16 @@ function Sidebar() { @@ -177,6 +175,7 @@ function TopNav({ fullscreen = false }: { fullscreen?: boolean }) { const link = "inline-flex items-center gap-2 rounded-md px-3 py-2 hover:bg-accent hover:text-accent-foreground shadow-none hover:shadow-none focus:shadow-none focus:outline-none focus:ring-0"; const active = "bg-secondary"; const topClass = fullscreen ? 'top-16' : 'top-[calc(4rem+32px)]'; + const { main } = useActiveSection(); // Icon mapping (same as Sidebar) const iconMap: Record = { @@ -198,19 +197,16 @@ function TopNav({ fullscreen = false }: { fullscreen?: boolean }) {
{navTree.map((item: any) => { const IconComponent = iconMap[item.icon] || Package; - // Extract child paths for matching - const childPaths = item.children?.map((child: any) => child.path).filter(Boolean) || []; + const isActive = main.key === item.key; return ( - `${link} ${isActive ? active : ''}`} + to={item.path} + className={`${link} ${isActive ? active : ''}`} > {item.label} - + ); })}
diff --git a/customer-spa/src/layouts/BaseLayout.tsx b/customer-spa/src/layouts/BaseLayout.tsx index 39dd037..8c11669 100644 --- a/customer-spa/src/layouts/BaseLayout.tsx +++ b/customer-spa/src/layouts/BaseLayout.tsx @@ -365,6 +365,8 @@ function ModernLayout({ children }: BaseLayoutProps) { const storeName = (window as any).woonoowCustomer?.storeName || (window as any).woonoowCustomer?.siteTitle || 'Store Title'; const user = (window as any).woonoowCustomer?.user; const headerSettings = useHeaderSettings(); + const { isEnabled } = useModules(); + const { settings: wishlistSettings } = useModuleSettings('wishlist'); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [searchOpen, setSearchOpen] = useState(false); @@ -426,6 +428,11 @@ function ModernLayout({ children }: BaseLayoutProps) { ) )} + {headerSettings.elements.wishlist && isEnabled('wishlist') && (wishlistSettings.show_in_header ?? true) && ( + + Wishlist + + )} {headerSettings.elements.cart && ( Cart ({itemCount}) @@ -493,6 +500,8 @@ function BoutiqueLayout({ children }: BaseLayoutProps) { const storeName = (window as any).woonoowCustomer?.storeName || (window as any).woonoowCustomer?.siteTitle || 'BOUTIQUE'; const user = (window as any).woonoowCustomer?.user; const headerSettings = useHeaderSettings(); + const { isEnabled } = useModules(); + const { settings: wishlistSettings } = useModuleSettings('wishlist'); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [searchOpen, setSearchOpen] = useState(false); @@ -552,6 +561,11 @@ function BoutiqueLayout({ children }: BaseLayoutProps) { Account ))} + {headerSettings.elements.wishlist && isEnabled('wishlist') && (wishlistSettings.show_in_header ?? true) && ( + + Wishlist + + )} {headerSettings.elements.cart && ( Cart ({itemCount})