"use client" import * as React from "react" import { LayoutDashboard, LifeBuoy, Ticket, PlayCircle, BarChart3, TrendingUp, PanelsTopLeft, UserCog, Building2, Waypoints, Clock4, Timer, MonitorCog, UserPlus, ChevronDown, ShieldCheck, Users, } from "lucide-react" import { usePathname } from "next/navigation" import Link from "next/link" import { SearchForm } from "@/components/search-form" import { SidebarBrand } from "@/components/sidebar-brand" import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarRail, } from "@/components/ui/sidebar" import { Skeleton } from "@/components/ui/skeleton" import { NavUser } from "@/components/nav-user" import { useAuth } from "@/lib/auth-client" import { cn } from "@/lib/utils" import type { LucideIcon } from "lucide-react" type NavRoleRequirement = "staff" | "admin" type NavigationItem = { title: string url: string icon?: LucideIcon requiredRole?: NavRoleRequirement exact?: boolean children?: NavigationItem[] } type NavigationGroup = { title: string requiredRole?: NavRoleRequirement items: NavigationItem[] } const navigation: NavigationGroup[] = [ { title: "Operação", items: [ { title: "Dashboard", url: "/dashboard", icon: LayoutDashboard, requiredRole: "staff" }, { title: "Tickets", url: "/tickets", icon: Ticket, requiredRole: "staff", children: [{ title: "Resolvidos", url: "/tickets/resolved", icon: ShieldCheck, requiredRole: "staff" }], }, { title: "Visualizações", url: "/views", icon: PanelsTopLeft, requiredRole: "staff" }, { title: "Modo Play", url: "/play", icon: PlayCircle, requiredRole: "staff" }, ], }, { title: "Relatórios", requiredRole: "staff", items: [ { title: "Produtividade", url: "/reports/sla", icon: TrendingUp, requiredRole: "staff" }, { title: "Qualidade (CSAT)", url: "/reports/csat", icon: LifeBuoy, requiredRole: "staff" }, { title: "Backlog", url: "/reports/backlog", icon: BarChart3, requiredRole: "staff" }, { title: "Empresas", url: "/reports/company", icon: Building2, requiredRole: "staff" }, { title: "Horas", url: "/reports/hours", icon: Clock4, requiredRole: "staff" }, ], }, { title: "Administração", requiredRole: "admin", items: [ { title: "Administração", url: "/admin", icon: UserPlus, requiredRole: "admin", exact: true, }, { title: "Filas", url: "/admin/channels", icon: Waypoints, requiredRole: "admin" }, { title: "Times & papéis", url: "/admin/teams", icon: UserCog, requiredRole: "admin" }, { title: "Empresas", url: "/admin/companies", icon: Building2, requiredRole: "admin", }, { title: "Usuários", url: "/admin/users", icon: Users, requiredRole: "admin" }, { title: "Máquinas", url: "/admin/machines", icon: MonitorCog, requiredRole: "admin" }, { title: "SLAs", url: "/admin/slas", icon: Timer, requiredRole: "admin" }, ], }, // Removido grupo "Conta" (Configurações) para evitar redundância com o menu do usuário no rodapé ] export function AppSidebar({ ...props }: React.ComponentProps) { const pathname = usePathname() const { session, isLoading, isAdmin, isStaff } = useAuth() const [isHydrated, setIsHydrated] = React.useState(false) const canAccess = React.useCallback( (requiredRole?: NavRoleRequirement) => { if (!requiredRole) return true if (requiredRole === "admin") return isAdmin if (requiredRole === "staff") return isStaff return false }, [isAdmin, isStaff] ) const initialExpanded = React.useMemo(() => { const open = new Set() navigation.forEach((group) => { group.items.forEach((item) => { if (!item.children || item.children.length === 0) return const shouldOpen = item.children.some((child) => { if (!canAccess(child.requiredRole)) return false return pathname === child.url || pathname.startsWith(`${child.url}/`) }) if (shouldOpen) { open.add(item.title) } }) }) return open }, [pathname, canAccess]) const [expanded, setExpanded] = React.useState>(initialExpanded) React.useEffect(() => { setExpanded((prev) => { const next = new Set(prev) initialExpanded.forEach((key) => next.add(key)) return next }) }, [initialExpanded]) React.useEffect(() => { setIsHydrated(true) }, []) function isActive(item: NavigationItem) { const { url, exact } = item if (!pathname) return false if (url === "/dashboard" && pathname === "/") { return true } if (exact) { return pathname === url } return pathname === url || pathname.startsWith(`${url}/`) } const toggleExpanded = React.useCallback((title: string) => { setExpanded((prev) => { const next = new Set(prev) if (next.has(title)) { next.delete(title) } else { next.add(title) } return next }) }, []) if (!isHydrated) { return ( {[0, 1, 2].map((group) => (
{[0, 1, 2].map((item) => ( ))}
))}
) } return ( {navigation.map((group) => { if (!canAccess(group.requiredRole)) return null const visibleItems = group.items.filter((item) => canAccess(item.requiredRole)) if (visibleItems.length === 0) return null return ( {group.title} {visibleItems.map((item) => { if (item.children && item.children.length > 0) { const childItems = item.children.filter((child) => canAccess(child.requiredRole)) const isExpanded = expanded.has(item.title) const isChildActive = childItems.some((child) => isActive(child)) const parentActive = isActive(item) || isChildActive return ( {item.icon ? : null} {item.title} { event.preventDefault() event.stopPropagation() toggleExpanded(item.title) }} className={cn( "absolute right-1.5 top-1/2 inline-flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-md text-neutral-500 transition hover:bg-slate-200 hover:text-neutral-700", isExpanded && "rotate-180" )} > {isExpanded ? childItems.map((child) => ( {child.icon ? : null} {child.title} )) : null} ) } return ( {item.icon ? : null} {item.title} ) })} ) })} {isLoading ? (
) : ( )} {/* Dev debug removido */}
) }