261 lines
8.3 KiB
TypeScript
261 lines
8.3 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import * as React from "react";
|
||
|
|
import { Home, Map } from "lucide-react";
|
||
|
|
|
||
|
|
import { NavUser } from "@/components/nav-user";
|
||
|
|
import { Label } from "@/components/ui/label";
|
||
|
|
import {
|
||
|
|
Sidebar,
|
||
|
|
SidebarContent,
|
||
|
|
SidebarFooter,
|
||
|
|
SidebarGroup,
|
||
|
|
SidebarGroupContent,
|
||
|
|
SidebarHeader,
|
||
|
|
SidebarInput,
|
||
|
|
SidebarMenu,
|
||
|
|
SidebarMenuButton,
|
||
|
|
SidebarMenuItem,
|
||
|
|
useSidebar,
|
||
|
|
} from "@/components/ui/sidebar";
|
||
|
|
import { Switch } from "@/components/ui/switch";
|
||
|
|
import { Avatar, AvatarImage } from "./ui/avatar";
|
||
|
|
|
||
|
|
import { useState, useEffect } from "react";
|
||
|
|
import { usePathname, useRouter } from "next/navigation";
|
||
|
|
|
||
|
|
const data = {
|
||
|
|
user: {
|
||
|
|
name: "shadcn",
|
||
|
|
email: "m@example.com",
|
||
|
|
avatar: "/avatars/shadcn.jpg",
|
||
|
|
},
|
||
|
|
navMain: [
|
||
|
|
{
|
||
|
|
title: "Dashboard",
|
||
|
|
url: "/dashboard",
|
||
|
|
icon: Home,
|
||
|
|
isActive: true,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: "Map",
|
||
|
|
url: "/map",
|
||
|
|
icon: Map,
|
||
|
|
isActive: false,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
clienti: [
|
||
|
|
{
|
||
|
|
name: "Savoldi Ettore",
|
||
|
|
email: "savoldi.ettore@gmail.com",
|
||
|
|
ragione_sociale: "Acconciature Uomo",
|
||
|
|
p_iva: "13407520172",
|
||
|
|
telefono: "0301547854",
|
||
|
|
sede: "Via Umberto I 60/T, Flero (BS)",
|
||
|
|
sede_url: "https://maps.app.goo.gl/9uNbw2a62ZCCjkQc7",
|
||
|
|
contratto: "https://google.com",
|
||
|
|
registratori: [
|
||
|
|
{
|
||
|
|
seriale: "80E100548745",
|
||
|
|
acquisto: "15/10/2019",
|
||
|
|
ultima_verifica: "15/10/2025",
|
||
|
|
prossima_verifica: "15/10/2026",
|
||
|
|
interventi: [
|
||
|
|
{
|
||
|
|
data: "15/10/2025",
|
||
|
|
lavoro: "VERIFICA FISCALE - AGGIORNAMENTO FIRMWARE",
|
||
|
|
fattura: true,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
data: "28/05/2025",
|
||
|
|
lavoro: "SOSTITUZIONE DGFE",
|
||
|
|
fattura: false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
data: "08/10/2024",
|
||
|
|
lavoro: "VERIFICA FISCALE",
|
||
|
|
fattura: true,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "Forno Tagliaferri",
|
||
|
|
email: "info@tagliaferri.it",
|
||
|
|
ragione_sociale: "Forno Tagliaferri",
|
||
|
|
p_iva: "12901475639",
|
||
|
|
telefono: "0309183573",
|
||
|
|
sede: "Via Corso dei Martiri 11, Brescia (BS)",
|
||
|
|
sede_url: "https://maps.app.goo.gl/9uNbw2a62ZCCjkQc7",
|
||
|
|
contratto: "https://google.com",
|
||
|
|
registratori: [
|
||
|
|
{
|
||
|
|
seriale: "80E1002587545",
|
||
|
|
acquisto: "24/02/2020",
|
||
|
|
ultima_verifica: "24/02/2025",
|
||
|
|
prossima_verifica: "24/02/2026",
|
||
|
|
interventi: [
|
||
|
|
{
|
||
|
|
data: "24/02/2025",
|
||
|
|
lavoro: "VERIFICA FISCALE",
|
||
|
|
fattura: true,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
data: "06/04/2025",
|
||
|
|
lavoro: "SOSTITUZIONE DGFE",
|
||
|
|
fattura: false,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
data: "24/02/2025",
|
||
|
|
lavoro: "VERIFICA FISCALE - AGGIORNAMENTO FIRMWARE",
|
||
|
|
fattura: true,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
};
|
||
|
|
|
||
|
|
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||
|
|
const pathname = usePathname();
|
||
|
|
const router = useRouter();
|
||
|
|
const [clientPathname, setClientPathname] = useState("");
|
||
|
|
const [clienti, setClienti] = React.useState(data.clienti);
|
||
|
|
const { setOpen } = useSidebar();
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
setClientPathname(pathname);
|
||
|
|
}, [pathname]);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Sidebar
|
||
|
|
collapsible="icon"
|
||
|
|
className="overflow-hidden *:data-[sidebar=sidebar]:flex-row"
|
||
|
|
variant="inset"
|
||
|
|
{...props}
|
||
|
|
>
|
||
|
|
{/* This is the first sidebar */}
|
||
|
|
{/* We disable collapsible and adjust width to icon. */}
|
||
|
|
{/* This will make the sidebar appear as icons. */}
|
||
|
|
<Sidebar
|
||
|
|
collapsible="none"
|
||
|
|
className="w-[calc(var(--sidebar-width-icon)+1px)]! border-r"
|
||
|
|
>
|
||
|
|
<SidebarHeader>
|
||
|
|
<SidebarMenu>
|
||
|
|
<SidebarMenuItem>
|
||
|
|
<SidebarMenuButton
|
||
|
|
size="lg"
|
||
|
|
asChild
|
||
|
|
className="lg:h-16 md:h-8 md:p-0"
|
||
|
|
>
|
||
|
|
<a href="#">
|
||
|
|
<div className="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
|
||
|
|
<Avatar className="h-16 w-8 rounded-lg">
|
||
|
|
<AvatarImage
|
||
|
|
src={
|
||
|
|
"https://www.pcsbrescia.com/images/definitivo-colori.png"
|
||
|
|
}
|
||
|
|
alt={"icon"}
|
||
|
|
/>
|
||
|
|
</Avatar>
|
||
|
|
</div>
|
||
|
|
<div className="grid flex-1 text-left text-sm leading-tight">
|
||
|
|
<span className="truncate font-medium">PC SHOP</span>
|
||
|
|
<span className="truncate text-xs">Brescia</span>
|
||
|
|
</div>
|
||
|
|
</a>
|
||
|
|
</SidebarMenuButton>
|
||
|
|
</SidebarMenuItem>
|
||
|
|
</SidebarMenu>
|
||
|
|
</SidebarHeader>
|
||
|
|
<SidebarContent>
|
||
|
|
<SidebarGroup>
|
||
|
|
<SidebarGroupContent className="px-1.5 md:px-0">
|
||
|
|
<SidebarMenu>
|
||
|
|
{data.navMain.map((item) => (
|
||
|
|
<SidebarMenuItem key={item.title}>
|
||
|
|
<SidebarMenuButton
|
||
|
|
tooltip={{
|
||
|
|
children: item.title,
|
||
|
|
hidden: false,
|
||
|
|
}}
|
||
|
|
onClick={() => {
|
||
|
|
const clienti = data.clienti.sort(
|
||
|
|
() => Math.random() - 0.5,
|
||
|
|
);
|
||
|
|
setClienti(
|
||
|
|
clienti.slice(
|
||
|
|
0,
|
||
|
|
Math.max(5, Math.floor(Math.random() * 10) + 1),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
setOpen(true);
|
||
|
|
if (clientPathname != item.url) {
|
||
|
|
router.push(item.url);
|
||
|
|
}
|
||
|
|
}}
|
||
|
|
isActive={clientPathname === item.url}
|
||
|
|
className="px-2.5 md:px-2"
|
||
|
|
>
|
||
|
|
<item.icon />
|
||
|
|
<span>{item.title}</span>
|
||
|
|
</SidebarMenuButton>
|
||
|
|
</SidebarMenuItem>
|
||
|
|
))}
|
||
|
|
</SidebarMenu>
|
||
|
|
</SidebarGroupContent>
|
||
|
|
</SidebarGroup>
|
||
|
|
</SidebarContent>
|
||
|
|
<SidebarFooter>
|
||
|
|
<NavUser user={data.user} />
|
||
|
|
</SidebarFooter>
|
||
|
|
</Sidebar>
|
||
|
|
|
||
|
|
{/* This is the second sidebar */}
|
||
|
|
{/* We disable collapsible and let it fill remaining space */}
|
||
|
|
<Sidebar collapsible="none" className="hidden flex-1 md:flex">
|
||
|
|
<SidebarHeader className="gap-3.5 border-b p-4">
|
||
|
|
<div className="flex w-full items-center justify-between">
|
||
|
|
<div className="text-foreground text-base font-medium">
|
||
|
|
{clientPathname.startsWith("/client")
|
||
|
|
? "Dettaglio cliente"
|
||
|
|
: data.navMain.find((entry) => entry.url == clientPathname)
|
||
|
|
?.title}
|
||
|
|
</div>
|
||
|
|
{/*<Label className="flex items-center gap-2 text-sm">
|
||
|
|
<span>Unreads</span>
|
||
|
|
<Switch className="shadow-none" />
|
||
|
|
</Label>*/}
|
||
|
|
</div>
|
||
|
|
<SidebarInput placeholder="Type to search..." />
|
||
|
|
</SidebarHeader>
|
||
|
|
<SidebarContent>
|
||
|
|
<SidebarGroup className="px-0">
|
||
|
|
<SidebarGroupContent className="">
|
||
|
|
{clienti.map((cliente) => (
|
||
|
|
<a
|
||
|
|
href="#"
|
||
|
|
onClick={() => router.push(`/client/${cliente.name}`)}
|
||
|
|
key={cliente.name}
|
||
|
|
className="w-11/12 mx-auto rounded-md hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex flex-col items-start gap-2 border-b p-4 text-sm leading-tight whitespace-nowrap last:border-b-0"
|
||
|
|
>
|
||
|
|
<span className="font-medium">{cliente.name}</span>
|
||
|
|
<div className="flex w-full items-center gap-2">
|
||
|
|
<span className="text-xs">{cliente.sede}</span>
|
||
|
|
</div>
|
||
|
|
<span className="line-clamp-2 w-[260px] text-xs whitespace-break-spaces">
|
||
|
|
{cliente.registratori[0].prossima_verifica}
|
||
|
|
</span>
|
||
|
|
</a>
|
||
|
|
))}
|
||
|
|
</SidebarGroupContent>
|
||
|
|
</SidebarGroup>
|
||
|
|
</SidebarContent>
|
||
|
|
</Sidebar>
|
||
|
|
</Sidebar>
|
||
|
|
);
|
||
|
|
}
|