92 lines
3.1 KiB
TypeScript
92 lines
3.1 KiB
TypeScript
|
|
import { Link, useLocation } from 'react-router-dom';
|
||
|
|
import { useUIStore } from '@/stores/ui';
|
||
|
|
import { useAuthStore } from '@/stores/auth';
|
||
|
|
import { useTranslation } from '@/hooks/useTranslation';
|
||
|
|
import { cn } from '@/lib/utils';
|
||
|
|
import { Home, MessageSquare, Library, Users, Settings, Shield } from 'lucide-react';
|
||
|
|
|
||
|
|
export function Sidebar() {
|
||
|
|
const { sidebarOpen } = useUIStore();
|
||
|
|
const { user } = useAuthStore();
|
||
|
|
const { t } = useTranslation();
|
||
|
|
const location = useLocation();
|
||
|
|
|
||
|
|
// Vérifier si l'utilisateur est admin
|
||
|
|
const isAdmin = user?.role === 'admin' || user?.role === 'super_admin';
|
||
|
|
|
||
|
|
const navigation = [
|
||
|
|
{ name: t('navigation.dashboard'), href: '/dashboard', icon: Home },
|
||
|
|
{ name: t('navigation.chat'), href: '/chat', icon: MessageSquare },
|
||
|
|
{ name: t('navigation.library'), href: '/library', icon: Library },
|
||
|
|
{ name: t('navigation.profile'), href: '/profile', icon: Users },
|
||
|
|
{ name: t('navigation.settings'), href: '/settings', icon: Settings },
|
||
|
|
];
|
||
|
|
|
||
|
|
// Ajouter les liens admin si l'utilisateur est admin
|
||
|
|
if (isAdmin) {
|
||
|
|
navigation.push({
|
||
|
|
name: 'Roles',
|
||
|
|
href: '/admin/roles',
|
||
|
|
icon: Shield,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<aside
|
||
|
|
className={cn(
|
||
|
|
'fixed inset-y-0 left-0 z-40 w-64 bg-background border-r transform transition-transform duration-200 ease-in-out',
|
||
|
|
sidebarOpen ? 'translate-x-0' : '-translate-x-full',
|
||
|
|
'md:translate-x-0'
|
||
|
|
)}
|
||
|
|
role='navigation'
|
||
|
|
aria-label={t('navigation.menu')}
|
||
|
|
>
|
||
|
|
<div className='flex flex-col h-full'>
|
||
|
|
{/* Logo */}
|
||
|
|
<div className='flex items-center h-16 px-6 border-b'>
|
||
|
|
<div
|
||
|
|
className='h-8 w-8 rounded-lg bg-primary flex items-center justify-center'
|
||
|
|
aria-hidden='true'
|
||
|
|
>
|
||
|
|
<span className='text-primary-foreground font-bold text-lg'>V</span>
|
||
|
|
</div>
|
||
|
|
<span className='ml-2 font-bold text-xl'>Veza</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Navigation */}
|
||
|
|
<nav className='flex-1 px-4 py-6 space-y-2' role='menubar'>
|
||
|
|
{navigation.map(item => {
|
||
|
|
const isActive = location.pathname === item.href;
|
||
|
|
return (
|
||
|
|
<Link
|
||
|
|
key={item.name}
|
||
|
|
to={item.href}
|
||
|
|
role='menuitem'
|
||
|
|
tabIndex={0}
|
||
|
|
aria-current={isActive ? 'page' : undefined}
|
||
|
|
className={cn(
|
||
|
|
'flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||
|
|
isActive
|
||
|
|
? 'bg-primary text-primary-foreground'
|
||
|
|
: 'text-muted-foreground hover:text-foreground hover:bg-accent'
|
||
|
|
)}
|
||
|
|
>
|
||
|
|
<item.icon className='mr-3 h-5 w-5' aria-hidden='true' />
|
||
|
|
{item.name}
|
||
|
|
</Link>
|
||
|
|
);
|
||
|
|
})}
|
||
|
|
</nav>
|
||
|
|
|
||
|
|
{/* Footer */}
|
||
|
|
<footer className='p-4 border-t'>
|
||
|
|
<div className='text-xs text-muted-foreground'>
|
||
|
|
<p>Veza v1.0.0</p>
|
||
|
|
<p>© 2024 Veza Team</p>
|
||
|
|
</div>
|
||
|
|
</footer>
|
||
|
|
</div>
|
||
|
|
</aside>
|
||
|
|
);
|
||
|
|
}
|