fix: Navigation active state redesign + Wishlist in all themes
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!
This commit is contained in:
@@ -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<string, any> = {
|
||||
@@ -153,19 +154,16 @@ function Sidebar() {
|
||||
<nav className="flex flex-col gap-1">
|
||||
{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 (
|
||||
<ActiveNavLink
|
||||
key={item.key}
|
||||
to={item.path}
|
||||
startsWith={item.path}
|
||||
childPaths={childPaths}
|
||||
className={({ isActive }: any) => `${link} ${isActive ? active : ''}`}
|
||||
<Link
|
||||
key={item.key}
|
||||
to={item.path}
|
||||
className={`${link} ${isActive ? active : ''}`}
|
||||
>
|
||||
<IconComponent className="w-4 h-4" />
|
||||
<span>{item.label}</span>
|
||||
</ActiveNavLink>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
@@ -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<string, any> = {
|
||||
@@ -198,19 +197,16 @@ function TopNav({ fullscreen = false }: { fullscreen?: boolean }) {
|
||||
<div className="px-4 h-12 flex flex-nowrap overflow-auto items-center gap-2">
|
||||
{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 (
|
||||
<ActiveNavLink
|
||||
<Link
|
||||
key={item.key}
|
||||
to={item.path}
|
||||
startsWith={item.path}
|
||||
childPaths={childPaths}
|
||||
className={({ isActive }: any) => `${link} ${isActive ? active : ''}`}
|
||||
to={item.path}
|
||||
className={`${link} ${isActive ? active : ''}`}
|
||||
>
|
||||
<IconComponent className="w-4 h-4" />
|
||||
<span className="text-sm font-medium">{item.label}</span>
|
||||
</ActiveNavLink>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -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) {
|
||||
</a>
|
||||
)
|
||||
)}
|
||||
{headerSettings.elements.wishlist && isEnabled('wishlist') && (wishlistSettings.show_in_header ?? true) && (
|
||||
<Link to="/my-account/wishlist" className="flex items-center gap-1 text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors no-underline">
|
||||
<Heart className="h-4 w-4" /> Wishlist
|
||||
</Link>
|
||||
)}
|
||||
{headerSettings.elements.cart && (
|
||||
<Link to="/cart" className="flex items-center gap-1 text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors no-underline">
|
||||
<ShoppingCart className="h-4 w-4" /> 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) {
|
||||
<User className="h-4 w-4" /> Account
|
||||
</a>
|
||||
))}
|
||||
{headerSettings.elements.wishlist && isEnabled('wishlist') && (wishlistSettings.show_in_header ?? true) && (
|
||||
<Link to="/my-account/wishlist" className="flex items-center gap-1 text-sm uppercase tracking-wider text-gray-700 hover:text-gray-900 transition-colors no-underline">
|
||||
<Heart className="h-4 w-4" /> Wishlist
|
||||
</Link>
|
||||
)}
|
||||
{headerSettings.elements.cart && (
|
||||
<Link to="/cart" className="flex items-center gap-1 text-sm uppercase tracking-wider text-gray-700 hover:text-gray-900 transition-colors no-underline">
|
||||
<ShoppingCart className="h-4 w-4" /> Cart ({itemCount})
|
||||
|
||||
Reference in New Issue
Block a user