Files
pragma-stack/frontend/src/components/admin/AdminSidebar.tsx
Felipe Cardoso 96df7edf88 Refactor useAuth hook, settings components, and docs for formatting and readability improvements
- Consolidated multi-line arguments into single lines where appropriate in `useAuth`.
- Improved spacing and readability in data processing across components (`ProfileSettingsForm`, `PasswordChangeForm`, `SessionCard`).
- Applied consistent table and markdown formatting in design system docs (e.g., `README.md`, `08-ai-guidelines.md`, `00-quick-start.md`).
- Updated code snippets to ensure adherence to Prettier rules and streamlined JSX structures.
2025-11-10 11:03:45 +01:00

130 lines
3.9 KiB
TypeScript

/**
* Admin Sidebar Navigation
* Displays navigation links for admin section
*/
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { cn } from '@/lib/utils';
import {
LayoutDashboard,
Users,
Building2,
Settings,
ChevronLeft,
ChevronRight,
} from 'lucide-react';
import { useState } from 'react';
import { useAuth } from '@/lib/auth/AuthContext';
interface NavItem {
name: string;
href: string;
icon: React.ComponentType<{ className?: string }>;
}
const navItems: NavItem[] = [
{
name: 'Dashboard',
href: '/admin',
icon: LayoutDashboard,
},
{
name: 'Users',
href: '/admin/users',
icon: Users,
},
{
name: 'Organizations',
href: '/admin/organizations',
icon: Building2,
},
{
name: 'Settings',
href: '/admin/settings',
icon: Settings,
},
];
export function AdminSidebar() {
const pathname = usePathname();
const { user } = useAuth();
const [collapsed, setCollapsed] = useState(false);
return (
<aside
className={cn(
'border-r bg-muted/40 transition-all duration-300',
collapsed ? 'w-16' : 'w-64'
)}
data-testid="admin-sidebar"
>
<div className="flex h-full flex-col">
{/* Sidebar Header */}
<div className="flex h-16 items-center justify-between border-b px-4">
{!collapsed && <h2 className="text-lg font-semibold">Admin Panel</h2>}
<button
onClick={() => setCollapsed(!collapsed)}
className="rounded-md p-2 hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
data-testid="sidebar-toggle"
>
{collapsed ? (
<ChevronRight className="h-4 w-4" aria-hidden="true" />
) : (
<ChevronLeft className="h-4 w-4" aria-hidden="true" />
)}
</button>
</div>
{/* Navigation Links */}
<nav className="flex-1 space-y-1 p-2">
{navItems.map((item) => {
const isActive =
pathname === item.href || (item.href !== '/admin' && pathname.startsWith(item.href));
const Icon = item.icon;
return (
<Link
key={item.href}
href={item.href}
className={cn(
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
'hover:bg-accent hover:text-accent-foreground',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
isActive ? 'bg-accent text-accent-foreground' : 'text-muted-foreground',
collapsed && 'justify-center'
)}
title={collapsed ? item.name : undefined}
data-testid={`nav-${item.name.toLowerCase()}`}
>
<Icon className="h-5 w-5 flex-shrink-0" aria-hidden="true" />
{!collapsed && <span>{item.name}</span>}
</Link>
);
})}
</nav>
{/* User Info */}
{!collapsed && user && (
<div className="border-t p-4">
<div className="flex items-center gap-3">
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary text-primary-foreground text-sm font-medium">
{user.first_name?.[0] || user.email[0].toUpperCase()}
</div>
<div className="flex-1 overflow-hidden">
<p className="text-sm font-medium truncate">
{user.first_name} {user.last_name}
</p>
<p className="text-xs text-muted-foreground truncate">{user.email}</p>
</div>
</div>
</div>
)}
</div>
</aside>
);
}