full project: admin panel, backend modules, docs
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { useAuth } from '@/lib/auth';
|
||||
import {
|
||||
LayoutDashboard,
|
||||
Users,
|
||||
Briefcase,
|
||||
ClipboardList,
|
||||
MapPin,
|
||||
Wrench,
|
||||
Settings,
|
||||
LogOut,
|
||||
ChevronLeft,
|
||||
Menu,
|
||||
} from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useState } from 'react';
|
||||
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
||||
|
||||
const menu = [
|
||||
{ href: '/', label: 'Dashboard', icon: LayoutDashboard },
|
||||
{ href: '/users', label: 'Usuarios', icon: Users },
|
||||
{ href: '/professionals', label: 'Profesionales', icon: Briefcase },
|
||||
{ href: '/services', label: 'Servicios', icon: ClipboardList },
|
||||
{ href: '/cities', label: 'Ciudades', icon: MapPin },
|
||||
{ href: '/professions', label: 'Profesiones', icon: Wrench },
|
||||
{ href: '/settings', label: 'Configuración', icon: Settings },
|
||||
];
|
||||
|
||||
export default function Sidebar({ children }: { children: React.ReactNode }) {
|
||||
const path = usePathname();
|
||||
const { user, logout } = useAuth();
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
if (path === '/login') return <>{children}</>;
|
||||
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<aside
|
||||
className={cn(
|
||||
'flex flex-col border-r bg-card transition-all duration-200',
|
||||
collapsed ? 'w-16' : 'w-56',
|
||||
)}
|
||||
>
|
||||
<div className="flex h-14 items-center justify-between border-b px-3">
|
||||
{!collapsed && <span className="font-semibold">ProsApp Admin</span>}
|
||||
<Button variant="ghost" size="icon" onClick={() => setCollapsed(!collapsed)}>
|
||||
{collapsed ? <Menu size={18} /> : <ChevronLeft size={18} />}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<nav className="flex-1 space-y-1 p-2">
|
||||
{menu.map((item) => (
|
||||
<Link key={item.href} href={item.href}>
|
||||
<Button
|
||||
variant={path === item.href ? 'secondary' : 'ghost'}
|
||||
className={cn('w-full justify-start', collapsed ? 'px-2' : 'px-3')}
|
||||
>
|
||||
<item.icon size={18} className={collapsed ? 'mx-auto' : 'mr-2'} />
|
||||
{!collapsed && item.label}
|
||||
</Button>
|
||||
</Link>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<div className="border-t p-2">
|
||||
{collapsed ? (
|
||||
<Button variant="ghost" size="icon" className="w-full" onClick={logout}>
|
||||
<LogOut size={18} />
|
||||
</Button>
|
||||
) : (
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar className="h-8 w-8">
|
||||
<AvatarFallback>{user?.name?.charAt(0) || 'A'}</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium truncate">{user?.name}</p>
|
||||
</div>
|
||||
<Button variant="ghost" size="icon" onClick={logout}>
|
||||
<LogOut size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main className="flex-1 overflow-auto bg-muted/20">
|
||||
<div className="mx-auto max-w-7xl p-6">{children}</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user