Spaces:
Running
Running
MichaelEdou
feat: add Email Senders page, replace Reports with Coming Soon, remove AI references
efc415a | import { useLocation, Link, useNavigate } from 'react-router'; | |
| import { useTranslation } from 'react-i18next'; | |
| import { | |
| LayoutDashboard, | |
| ArrowLeftRight, | |
| BarChart3, | |
| Store, | |
| ScrollText, | |
| Settings, | |
| LogOut, | |
| Wallet, | |
| Mail, | |
| } from 'lucide-react'; | |
| import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; | |
| import { cn } from '@/lib/utils'; | |
| import { useAuthStore } from '@/stores/authStore'; | |
| interface NavItem { | |
| icon: React.ElementType; | |
| labelKey: string; | |
| href: string; | |
| } | |
| const navItems: NavItem[] = [ | |
| { icon: LayoutDashboard, labelKey: 'nav.dashboard', href: '/dashboard' }, | |
| { icon: ArrowLeftRight, labelKey: 'nav.transactions', href: '/transactions' }, | |
| { icon: BarChart3, labelKey: 'nav.reports', href: '/reports' }, | |
| { icon: Store, labelKey: 'nav.branches', href: '/branches' }, | |
| { icon: ScrollText, labelKey: 'nav.journal', href: '/journal' }, | |
| { icon: Mail, labelKey: 'nav.emailSenders', href: '/email-senders' }, | |
| { icon: Settings, labelKey: 'nav.settings', href: '/settings' }, | |
| ]; | |
| function getInitials(name?: string | null): string { | |
| if (!name) return '?'; | |
| const parts = name.trim().split(/\s+/); | |
| if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); | |
| return name.slice(0, 2).toUpperCase(); | |
| } | |
| function getDisplayName(name?: string | null): string { | |
| if (!name) return 'Utilisateur'; | |
| const parts = name.trim().split(/\s+/); | |
| if (parts.length >= 2) return `${parts[0]} ${parts[parts.length - 1][0]}.`; | |
| return name; | |
| } | |
| const ROLE_LABELS: Record<string, string> = { | |
| admin: 'Administrateur', | |
| editor: 'Éditeur', | |
| viewer: 'Lecteur', | |
| }; | |
| export default function Sidebar() { | |
| const { t } = useTranslation(); | |
| const location = useLocation(); | |
| const navigate = useNavigate(); | |
| const user = useAuthStore((s) => s.user); | |
| const handleLogout = async () => { | |
| try { | |
| await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }); | |
| } catch { | |
| // Ignore errors — clear cookies and redirect regardless | |
| } | |
| useAuthStore.getState().logout(); | |
| navigate('/login'); | |
| }; | |
| return ( | |
| <aside className="flex w-72 flex-col border-r border-border bg-card transition-all duration-300"> | |
| {/* Logo */} | |
| <div className="flex items-center gap-3 px-6 py-8"> | |
| <div className="flex h-10 w-10 items-center justify-center rounded-xl bg-primary text-white shadow-sm"> | |
| <Wallet className="h-5 w-5" /> | |
| </div> | |
| <div className="flex flex-col"> | |
| <h1 className="text-slate-900 text-base font-bold leading-tight tracking-tight"> | |
| ICC Interac | |
| </h1> | |
| <p className="text-slate-400 text-xs font-medium">Manager v2.4</p> | |
| </div> | |
| </div> | |
| {/* Navigation */} | |
| <nav className="flex flex-1 flex-col gap-1 px-4 py-4"> | |
| {navItems.map((item) => { | |
| const isActive = location.pathname === item.href; | |
| return ( | |
| <Link | |
| key={item.href} | |
| to={item.href} | |
| className={cn( | |
| 'flex items-center gap-3 rounded-lg px-4 py-3 transition-colors', | |
| isActive | |
| ? 'bg-blue-50 text-primary font-semibold' | |
| : 'text-slate-500 hover:bg-slate-50 hover:text-slate-900' | |
| )} | |
| > | |
| <item.icon className="h-5 w-5" /> | |
| <span className={cn('text-sm', isActive ? 'font-semibold' : 'font-medium')}> | |
| {t(item.labelKey)} | |
| </span> | |
| </Link> | |
| ); | |
| })} | |
| </nav> | |
| {/* Footer */} | |
| <div className="p-4 border-t border-border/50"> | |
| <button | |
| onClick={handleLogout} | |
| className="flex w-full items-center gap-3 rounded-lg px-4 py-2.5 text-slate-500 hover:text-slate-900 transition-colors group mb-4" | |
| > | |
| <LogOut className="h-5 w-5 group-hover:text-red-500 transition-colors" /> | |
| <span className="text-sm font-medium">{t('nav.logout')}</span> | |
| </button> | |
| <div className="flex items-center gap-3 rounded-xl border border-border p-3 bg-white"> | |
| <Avatar className="h-10 w-10"> | |
| <AvatarImage src={user?.avatarUrl ?? ''} alt={user?.name ?? 'User'} /> | |
| <AvatarFallback className="bg-slate-100 text-sm font-semibold text-slate-600"> | |
| {getInitials(user?.name)} | |
| </AvatarFallback> | |
| </Avatar> | |
| <div className="flex flex-col min-w-0"> | |
| <span className="text-sm font-semibold text-slate-900">{getDisplayName(user?.name)}</span> | |
| <span className="text-xs text-slate-500 truncate">{user?.email ?? ROLE_LABELS[user?.role ?? ''] ?? ''}</span> | |
| </div> | |
| </div> | |
| </div> | |
| </aside> | |
| ); | |
| } | |