VigilanzaTurni/client/src/components/app-sidebar.tsx
marco370 dcbf059d73 Add advanced planning features with new database schemas and UI
Implement new API endpoints and database schemas for guard constraints, site preferences, training courses, holidays, and absences, alongside a dedicated advanced planning UI.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 99f0fce6-9386-489a-9632-1d81223cab44
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/99f0fce6-9386-489a-9632-1d81223cab44/H8Wilyj
2025-10-11 19:30:16 +00:00

163 lines
4.1 KiB
TypeScript

import {
Calendar,
Shield,
MapPin,
Users,
BarChart3,
Bell,
Settings,
LogOut,
UserCog,
ClipboardList,
} from "lucide-react";
import { Link, useLocation } from "wouter";
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarHeader,
SidebarFooter,
} from "@/components/ui/sidebar";
import { useAuth } from "@/hooks/useAuth";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { ThemeToggle } from "@/components/theme-toggle";
const menuItems = [
{
title: "Dashboard",
url: "/",
icon: Shield,
roles: ["admin", "coordinator", "guard", "client"],
},
{
title: "Turni",
url: "/shifts",
icon: Calendar,
roles: ["admin", "coordinator", "guard"],
},
{
title: "Pianificazione",
url: "/planning",
icon: ClipboardList,
roles: ["admin", "coordinator"],
},
{
title: "Guardie",
url: "/guards",
icon: Users,
roles: ["admin", "coordinator"],
},
{
title: "Siti",
url: "/sites",
icon: MapPin,
roles: ["admin", "coordinator", "client"],
},
{
title: "Report",
url: "/reports",
icon: BarChart3,
roles: ["admin", "coordinator", "client"],
},
{
title: "Notifiche",
url: "/notifications",
icon: Bell,
roles: ["admin", "coordinator", "guard"],
},
{
title: "Utenti",
url: "/users",
icon: UserCog,
roles: ["admin"],
},
];
export function AppSidebar() {
const { user } = useAuth();
const [location] = useLocation();
const filteredItems = menuItems.filter(
(item) => user && item.roles.includes(user.role)
);
return (
<Sidebar>
<SidebarHeader className="p-4 border-b">
<div className="flex items-center gap-3">
<Shield className="h-8 w-8 text-primary" />
<div>
<h1 className="text-lg font-semibold">VigilanzaTurni</h1>
<p className="text-xs text-muted-foreground">Sistema Gestione</p>
</div>
</div>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Menu Principale</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{filteredItems.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton
asChild
isActive={location === item.url}
data-testid={`link-${item.title.toLowerCase()}`}
>
<Link href={item.url}>
<item.icon className="h-4 w-4" />
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter className="p-4 border-t space-y-4">
<div className="flex items-center justify-between gap-3">
<div className="flex items-center gap-3 min-w-0">
<Avatar className="h-8 w-8">
<AvatarImage src={user?.profileImageUrl || undefined} />
<AvatarFallback>
{user?.firstName?.[0]}{user?.lastName?.[0]}
</AvatarFallback>
</Avatar>
<div className="min-w-0">
<p className="text-sm font-medium truncate">
{user?.firstName} {user?.lastName}
</p>
<p className="text-xs text-muted-foreground capitalize">
{user?.role}
</p>
</div>
</div>
<ThemeToggle />
</div>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
className="flex-1"
onClick={() => window.location.href = '/api/logout'}
data-testid="button-logout"
>
<LogOut className="h-4 w-4 mr-2" />
Esci
</Button>
</div>
</SidebarFooter>
</Sidebar>
);
}