Organize the main navigation menu with new sub-menus and updated labels
Refactor the `app-sidebar.tsx` component to restructure the navigation menu, introducing collapsible sub-menus for planning and master data, and renaming several menu items. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e0b5b11c-5b75-4389-8ea9-5f3cd9332f88 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e0b5b11c-5b75-4389-8ea9-5f3cd9332f88/EPTvOHB
This commit is contained in:
parent
3e3b9851a8
commit
7961971ad0
4
.replit
4
.replit
@ -19,6 +19,10 @@ externalPort = 80
|
||||
localPort = 33035
|
||||
externalPort = 3001
|
||||
|
||||
[[ports]]
|
||||
localPort = 40417
|
||||
externalPort = 8000
|
||||
|
||||
[[ports]]
|
||||
localPort = 41295
|
||||
externalPort = 5173
|
||||
|
||||
@ -12,6 +12,11 @@ import {
|
||||
Car,
|
||||
Briefcase,
|
||||
Navigation,
|
||||
ChevronDown,
|
||||
FileText,
|
||||
FolderKanban,
|
||||
Building2,
|
||||
Wrench,
|
||||
} from "lucide-react";
|
||||
import { Link, useLocation } from "wouter";
|
||||
import {
|
||||
@ -23,15 +28,31 @@ import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubItem,
|
||||
SidebarMenuSubButton,
|
||||
SidebarHeader,
|
||||
SidebarFooter,
|
||||
} from "@/components/ui/sidebar";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
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 = [
|
||||
interface MenuItem {
|
||||
title: string;
|
||||
url?: string;
|
||||
icon: any;
|
||||
roles: string[];
|
||||
items?: MenuItem[];
|
||||
}
|
||||
|
||||
const menuItems: MenuItem[] = [
|
||||
{
|
||||
title: "Dashboard",
|
||||
url: "/",
|
||||
@ -39,100 +60,117 @@ const menuItems = [
|
||||
roles: ["admin", "coordinator", "guard", "client"],
|
||||
},
|
||||
{
|
||||
title: "Turni",
|
||||
url: "/shifts",
|
||||
icon: Calendar,
|
||||
roles: ["admin", "coordinator", "guard"],
|
||||
},
|
||||
{
|
||||
title: "Pianificazione",
|
||||
url: "/planning",
|
||||
icon: ClipboardList,
|
||||
title: "Planning",
|
||||
icon: FolderKanban,
|
||||
roles: ["admin", "coordinator"],
|
||||
items: [
|
||||
{
|
||||
title: "Fissi",
|
||||
url: "/general-planning",
|
||||
icon: Calendar,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Mobili",
|
||||
url: "/planning-mobile",
|
||||
icon: Navigation,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Vista",
|
||||
url: "/service-planning",
|
||||
icon: ClipboardList,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Pianificazione Operativa",
|
||||
url: "/operational-planning",
|
||||
icon: Calendar,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Planning Fissi",
|
||||
url: "/general-planning",
|
||||
icon: BarChart3,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Planning Mobile",
|
||||
url: "/planning-mobile",
|
||||
icon: Navigation,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Planning di Servizio",
|
||||
url: "/service-planning",
|
||||
icon: ClipboardList,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Gestione Pianificazioni",
|
||||
title: "Scadenziario",
|
||||
url: "/advanced-planning",
|
||||
icon: ClipboardList,
|
||||
icon: Calendar,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Guardie",
|
||||
url: "/guards",
|
||||
icon: Users,
|
||||
title: "Anagrafiche",
|
||||
icon: Building2,
|
||||
roles: ["admin", "coordinator"],
|
||||
items: [
|
||||
{
|
||||
title: "Guardie",
|
||||
url: "/guards",
|
||||
icon: Users,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Siti",
|
||||
url: "/sites",
|
||||
icon: MapPin,
|
||||
roles: ["admin", "coordinator", "client"],
|
||||
},
|
||||
{
|
||||
title: "Clienti",
|
||||
url: "/customers",
|
||||
icon: Briefcase,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Automezzi",
|
||||
url: "/vehicles",
|
||||
icon: Car,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Siti",
|
||||
url: "/sites",
|
||||
icon: MapPin,
|
||||
roles: ["admin", "coordinator", "client"],
|
||||
},
|
||||
{
|
||||
title: "Clienti",
|
||||
url: "/customers",
|
||||
icon: Briefcase,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Servizi",
|
||||
url: "/services",
|
||||
icon: Briefcase,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Parco Automezzi",
|
||||
url: "/vehicles",
|
||||
icon: Car,
|
||||
title: "Tipologia",
|
||||
icon: Wrench,
|
||||
roles: ["admin", "coordinator"],
|
||||
items: [
|
||||
{
|
||||
title: "Servizi",
|
||||
url: "/services",
|
||||
icon: Briefcase,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
{
|
||||
title: "Contratti",
|
||||
url: "/parameters",
|
||||
icon: Settings,
|
||||
roles: ["admin", "coordinator"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Report",
|
||||
url: "/reports",
|
||||
icon: BarChart3,
|
||||
roles: ["admin", "coordinator", "client"],
|
||||
items: [
|
||||
{
|
||||
title: "Report Amministrativo",
|
||||
url: "/reports",
|
||||
icon: FileText,
|
||||
roles: ["admin", "coordinator", "client"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Notifiche",
|
||||
url: "/notifications",
|
||||
icon: Bell,
|
||||
roles: ["admin", "coordinator", "guard"],
|
||||
},
|
||||
{
|
||||
title: "Utenti",
|
||||
url: "/users",
|
||||
icon: UserCog,
|
||||
roles: ["admin"],
|
||||
},
|
||||
{
|
||||
title: "Parametri",
|
||||
url: "/parameters",
|
||||
title: "Utilità",
|
||||
icon: Settings,
|
||||
roles: ["admin", "coordinator"],
|
||||
roles: ["admin", "coordinator", "guard"],
|
||||
items: [
|
||||
{
|
||||
title: "Utenti",
|
||||
url: "/users",
|
||||
icon: UserCog,
|
||||
roles: ["admin"],
|
||||
},
|
||||
{
|
||||
title: "Notifiche",
|
||||
url: "/notifications",
|
||||
icon: Bell,
|
||||
roles: ["admin", "coordinator", "guard"],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@ -140,9 +178,78 @@ export function AppSidebar() {
|
||||
const { user } = useAuth();
|
||||
const [location] = useLocation();
|
||||
|
||||
const filteredItems = menuItems.filter(
|
||||
(item) => user && item.roles.includes(user.role)
|
||||
);
|
||||
const filterMenuItems = (items: MenuItem[]): MenuItem[] => {
|
||||
if (!user) return [];
|
||||
|
||||
return items.filter((item) => {
|
||||
const hasRole = item.roles.includes(user.role);
|
||||
if (!hasRole) return false;
|
||||
|
||||
if (item.items) {
|
||||
item.items = filterMenuItems(item.items);
|
||||
return item.items.length > 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
const filteredItems = filterMenuItems(menuItems);
|
||||
|
||||
const renderMenuItem = (item: MenuItem) => {
|
||||
// Menu item con sottomenu
|
||||
if (item.items && item.items.length > 0) {
|
||||
const isAnySubItemActive = item.items.some((subItem) => location === subItem.url);
|
||||
|
||||
return (
|
||||
<Collapsible key={item.title} defaultOpen={isAnySubItemActive} className="group/collapsible">
|
||||
<SidebarMenuItem>
|
||||
<CollapsibleTrigger asChild>
|
||||
<SidebarMenuButton data-testid={`menu-${item.title.toLowerCase()}`}>
|
||||
<item.icon className="h-4 w-4" />
|
||||
<span>{item.title}</span>
|
||||
<ChevronDown className="ml-auto h-4 w-4 transition-transform group-data-[state=open]/collapsible:rotate-180" />
|
||||
</SidebarMenuButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{item.items.map((subItem) => (
|
||||
<SidebarMenuSubItem key={subItem.title}>
|
||||
<SidebarMenuSubButton
|
||||
asChild
|
||||
isActive={location === subItem.url}
|
||||
data-testid={`link-${subItem.title.toLowerCase()}`}
|
||||
>
|
||||
<Link href={subItem.url!}>
|
||||
<subItem.icon className="h-4 w-4" />
|
||||
<span>{subItem.title}</span>
|
||||
</Link>
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</SidebarMenuItem>
|
||||
</Collapsible>
|
||||
);
|
||||
}
|
||||
|
||||
// Menu item semplice
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Sidebar>
|
||||
@ -161,20 +268,7 @@ export function AppSidebar() {
|
||||
<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>
|
||||
))}
|
||||
{filteredItems.map(renderMenuItem)}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user