veza/apps/web/src/components/layout/Sidebar.tsx

183 lines
7.4 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { useNavigate, useLocation, Link } from 'react-router-dom';
import { Home, Library, Users, Disc, Radio, Settings, LogOut, ShoppingBag, GraduationCap, BarChart2, Shield, Box, MessageSquare, Cloud, Layers, Globe, Cpu, Heart, ListMusic, CreditCard, DollarSign, Terminal } from 'lucide-react';
import { NavItem } from '../../types';
import { useAuthStore } from '@/features/auth/store/authStore';
interface SidebarProps {
currentView?: string;
onNavigate?: (viewId: string) => void;
onLogout?: () => void;
}
const navItems: { section: string; items: NavItem[] }[] = [
{
section: 'My Studio',
items: [
{ id: 'dashboard', label: 'Command Center', icon: <Home className="w-4 h-4" /> },
{ id: 'studio', label: 'Cloud Files', icon: <Cloud className="w-4 h-4" /> },
{ id: 'tracks', label: 'Projects', icon: <Layers className="w-4 h-4" /> },
{ id: 'gear', label: 'Gear Locker', icon: <Box className="w-4 h-4" /> },
{ id: 'analytics', label: 'Performance', icon: <BarChart2 className="w-4 h-4" /> },
]
},
{
section: 'Veza Network',
items: [
{ id: 'social', label: 'Community Feed', icon: <Users className="w-4 h-4" /> },
{ id: 'marketplace', label: 'Marketplace', icon: <ShoppingBag className="w-4 h-4" /> },
{ id: 'live', label: 'Live Sessions', icon: <Radio className="w-4 h-4 text-kodo-red" />, badge: 3 },
{ id: 'chat', label: 'Channels', icon: <MessageSquare className="w-4 h-4" />, badge: 12 },
{ id: 'education', label: 'Academy', icon: <GraduationCap className="w-4 h-4" /> },
]
},
{
section: 'Commerce',
items: [
{ id: 'sell', label: 'Seller Dashboard', icon: <DollarSign className="w-4 h-4" /> },
{ id: 'wishlist', label: 'Wishlist', icon: <Heart className="w-4 h-4" /> },
{ id: 'purchases', label: 'Purchases', icon: <CreditCard className="w-4 h-4" /> },
]
},
{
section: 'Library',
items: [
{ id: 'playlists', label: 'Playlists', icon: <ListMusic className="w-4 h-4" /> },
{ id: 'queue', label: 'Play Queue', icon: <Disc className="w-4 h-4" /> },
]
},
{
section: 'System',
items: [
{ id: 'developer', label: 'Developer API', icon: <Terminal className="w-4 h-4" /> },
{ id: 'admin', label: 'Admin Panel', icon: <Shield className="w-4 h-4" /> },
]
}
];
// Mapping des IDs de navigation vers les routes React Router
const routeMap: Record<string, string> = {
dashboard: '/dashboard',
studio: '/dashboard',
tracks: '/library',
gear: '/dashboard',
analytics: '/analytics',
social: '/dashboard',
marketplace: '/marketplace',
live: '/dashboard',
chat: '/chat',
education: '/dashboard',
sell: '/marketplace',
wishlist: '/marketplace',
purchases: '/marketplace',
playlists: '/playlists',
queue: '/dashboard',
developer: '/dashboard',
admin: '/admin',
settings: '/settings',
};
export const Sidebar: React.FC<SidebarProps> = ({ currentView, onNavigate, onLogout }) => {
const navigate = useNavigate();
const location = useLocation();
const { logout } = useAuthStore();
// Déterminer la vue actuelle depuis l'URL
const activeView = currentView || Object.keys(routeMap).find(
key => routeMap[key] === location.pathname
) || 'dashboard';
2026-01-07 18:39:21 +00:00
const handleLogout = () => {
logout();
navigate('/login');
// Appeler onLogout si fourni (pour compatibilité)
if (onLogout) {
onLogout();
}
};
return (
<aside className="fixed left-0 top-16 bottom-0 w-64 bg-kodo-void/95 backdrop-blur-2xl border-r border-kodo-steel/40 hidden lg:flex flex-col z-30">
<div className="flex-1 overflow-y-auto custom-scrollbar p-4">
{navItems.map((group, idx) => (
<div key={idx} className="mb-8">
<h3 className="text-[10px] font-bold text-kodo-secondary uppercase tracking-widest mb-3 px-3 font-display flex items-center gap-2">
{group.section === 'My Studio' && <Cpu className="w-3 h-3 text-kodo-cyan" />}
{group.section === 'Veza Network' && <Globe className="w-3 h-3 text-kodo-magenta" />}
{group.section === 'Commerce' && <DollarSign className="w-3 h-3 text-kodo-gold" />}
{group.section === 'Library' && <Library className="w-3 h-3 text-white" />}
{group.section}
</h3>
<div className="space-y-1">
{group.items.map((item) => {
const route = routeMap[item.id] || '/dashboard';
const isActive = activeView === item.id || location.pathname === route;
2026-01-07 18:39:21 +00:00
return (
<Link
key={item.id}
to={route}
onClick={() => {
// CRITIQUE FIX #36: Ne pas utiliser preventDefault() sur les liens React Router
// Laisser React Router gérer la navigation naturellement
// Appeler onNavigate si fourni pour compatibilité, mais sans bloquer la navigation
if (onNavigate) {
onNavigate(item.id);
}
}}
className={`
w-full flex items-center justify-between px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 group relative overflow-hidden
${isActive
2026-01-07 18:39:21 +00:00
? 'bg-white/5 text-kodo-primary shadow-[inset_0_0_20px_rgba(102,252,241,0.05)] border-l-2 border-kodo-cyan'
: 'text-kodo-secondary hover:text-kodo-primary hover:bg-white/5 border-l-2 border-transparent'}
`}
>
<div className="flex items-center gap-3 relative z-10">
<span className={`transition-colors duration-300 ${isActive ? 'text-kodo-cyan' : 'text-kodo-secondary group-hover:text-kodo-primary'}`}>
{item.icon}
</span>
{item.label}
</div>
{item.badge && (
<span className="bg-kodo-magenta/20 text-kodo-magenta text-[9px] px-1.5 py-0.5 rounded font-mono font-bold shadow-neon-magenta">
{item.badge}
</span>
)}
</Link>
);
})}
</div>
</div>
))}
</div>
<div className="p-4 border-t border-kodo-steel/30 bg-kodo-graphite/20">
2026-01-07 18:39:21 +00:00
<Link
to="/settings"
onClick={() => {
// CRITIQUE FIX #36: Ne pas utiliser preventDefault() sur les liens React Router
// Laisser React Router gérer la navigation naturellement
if (onNavigate) {
onNavigate('settings');
}
}}
className={`w-full flex items-center gap-3 px-3 py-2.5 text-sm mb-1 rounded-lg transition-colors ${activeView === 'settings' || location.pathname === '/settings' ? 'bg-white/5 text-kodo-primary' : 'text-kodo-secondary hover:text-kodo-primary hover:bg-white/5'}`}
>
<Settings className="w-4 h-4" />
Settings
</Link>
<button
onClick={handleLogout}
className="w-full flex items-center gap-3 px-3 py-2.5 text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded-lg transition-colors text-sm"
>
<LogOut className="w-4 h-4" />
Sign Out
</button>
</div>
</aside>
);
};