import React, { useMemo, useState, useEffect } from 'react'; import { useLocation, Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Home, Users, Disc, Radio, Settings, LogOut, ShoppingBag, BarChart2, Shield, Box, MessageSquare, Layers, Cpu, Heart, ListMusic, CreditCard, DollarSign, Terminal, ChevronLeft, ChevronRight, } from 'lucide-react'; import { NavItem } from '../../types'; import { useUIStore } from '@/stores/ui'; import { useSidebarNavigation } from '@/hooks/useSidebarNavigation'; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Tooltip } from '@/components/ui/tooltip'; import { FocusTrap } from '@/components/ui/focus-trap'; interface SidebarProps { currentView?: string; } // Section key mapping for i18n const sectionKeys: Record = { myStudio: 'nav.sections.myStudio', vezaNetwork: 'nav.sections.vezaNetwork', commerce: 'nav.sections.commerce', library: 'nav.sections.library', system: 'nav.sections.system', }; // Icon map — static, does not need translation const iconMap: Record = { dashboard: , tracks: , gear: , analytics: , social: , marketplace: , live: , chat: , sell: , wishlist: , purchases: , playlists: , queue: , developer: , admin: , }; // Badge data — static const badgeMap: Record = { live: 3, chat: 12 }; // Navigation structure definition (ids only, labels resolved via t()) const navStructure: { sectionKey: string; itemIds: string[] }[] = [ { sectionKey: 'myStudio', itemIds: ['dashboard', 'tracks', 'gear', 'analytics'] }, { sectionKey: 'vezaNetwork', itemIds: ['social', 'marketplace', 'live', 'chat'] }, { sectionKey: 'commerce', itemIds: ['sell', 'wishlist', 'purchases'] }, { sectionKey: 'library', itemIds: ['playlists', 'queue'] }, { sectionKey: 'system', itemIds: ['developer', 'admin'] }, ]; function buildNavItems(t: (key: string) => string): { section: string; items: NavItem[] }[] { return navStructure.map(({ sectionKey, itemIds }) => ({ section: t(sectionKeys[sectionKey] ?? sectionKey), items: itemIds.map((id) => ({ id, label: t(`nav.items.${id}`), icon: iconMap[id], ...(badgeMap[id] != null ? { badge: badgeMap[id] } : {}), })), })); } const routeMap: Record = { dashboard: '/dashboard', tracks: '/library', gear: '/gear', analytics: '/analytics', social: '/social', marketplace: '/marketplace', live: '/live', chat: '/chat', sell: '/sell', wishlist: '/wishlist', purchases: '/purchases', playlists: '/playlists', queue: '/queue', developer: '/developer', admin: '/admin', settings: '/settings', }; const navItemBaseClasses = cn( 'w-full flex items-center px-3 py-2 rounded-lg text-sm font-medium transition-all duration-[var(--duration-fast)] group relative', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background' ); const navItemInactiveClasses = 'text-muted-foreground hover:text-foreground hover:bg-sidebar-accent active:bg-sidebar-accent/80'; const navItemActiveClasses = 'bg-primary/10 text-primary sidebar-active-indicator'; const LG_BREAKPOINT = 1024; export const Sidebar: React.FC = ({ currentView }) => { const { t } = useTranslation(); const location = useLocation(); const { sidebarOpen, setSidebarOpen } = useUIStore(); const { handleMobileNav, handleLogout } = useSidebarNavigation(); const navItems = useMemo(() => buildNavItems(t), [t]); const [isMobile, setIsMobile] = useState(() => typeof window !== 'undefined' ? window.innerWidth < LG_BREAKPOINT : false, ); useEffect(() => { const mq = window.matchMedia(`(max-width: ${LG_BREAKPOINT - 1}px)`); const handler = () => setIsMobile(mq.matches); handler(); mq.addEventListener('change', handler); return () => mq.removeEventListener('change', handler); }, []); const activeView = currentView || Object.keys(routeMap).find((key) => routeMap[key] === location.pathname) || 'dashboard'; return ( <> {sidebarOpen && (
setSidebarOpen(false)} aria-hidden="true" role="presentation" /> )} setSidebarOpen(false)} > ); };