Files
ERP_Distribution/distribution_fe/components/layout/app-sidebar.tsx
T
2026-08-25 16:20:50 +05:30

176 lines
6.2 KiB
TypeScript

'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { HugeiconsIcon } from '@hugeicons/react'
import { ChevronRightIcon, UserIcon } from '@hugeicons/core-free-icons'
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarRail,
} from '@/components/ui/sidebar'
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@/components/ui/collapsible'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { useAuth, type Role } from '@/contexts/auth-context'
import { DASHBOARD_ITEM, NAV_GROUPS, type NavGroup, type NavItem } from '@/config/nav'
function canSee(item: NavItem, permissions: string[]): boolean {
if (!item.permission) return true
return permissions.includes('*') || permissions.includes(item.permission)
}
function isGroupVisible(group: NavGroup, permissions: string[]): boolean {
return group.items.some((item) => canSee(item, permissions))
}
export function AppSidebar() {
const { user, setRole, permissions } = useAuth()
const pathname = usePathname()
const dashboardActive = pathname === DASHBOARD_ITEM.href
return (
<Sidebar collapsible="icon">
<SidebarHeader>
<div className="flex items-center gap-2 px-2 py-1">
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground text-sm font-bold">
D
</div>
<span className="truncate font-semibold text-sidebar-foreground group-data-[collapsible=icon]:hidden">
Distribution
</span>
</div>
</SidebarHeader>
<SidebarContent className="gap-0">
{/* Dashboard — standalone, not inside a collapsible group */}
<SidebarGroup className="py-1">
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton
render={<Link href={DASHBOARD_ITEM.href} />}
isActive={dashboardActive}
tooltip={DASHBOARD_ITEM.title}
>
<HugeiconsIcon icon={DASHBOARD_ITEM.icon} size={18} />
<span>{DASHBOARD_ITEM.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroup>
{/* Collapsible groups */}
{NAV_GROUPS.map((group) => {
if (!isGroupVisible(group, permissions)) return null
const visibleItems = group.items.filter((item) =>
canSee(item, permissions),
)
const groupActive = visibleItems.some(
(item) =>
pathname === item.href ||
(item.href !== '/' && pathname.startsWith(item.href)),
)
return (
<Collapsible
key={group.title}
defaultOpen={false}
className="group/collapsible"
>
<SidebarGroup className="py-0">
<SidebarMenu>
{/* Group trigger — looks like a regular nav button */}
<SidebarMenuItem>
<SidebarMenuButton
render={<CollapsibleTrigger />}
isActive={groupActive}
tooltip={group.title}
>
<HugeiconsIcon icon={group.icon} size={18} />
<span>{group.title}</span>
<HugeiconsIcon
icon={ChevronRightIcon}
size={14}
className="ml-auto shrink-0 transition-transform duration-200 group-data-[open]/collapsible:rotate-90 group-data-[collapsible=icon]:hidden"
/>
</SidebarMenuButton>
</SidebarMenuItem>
{/* Sub-items with indent line */}
<CollapsibleContent>
<SidebarMenuSub>
{visibleItems.map((item) => {
const isActive =
pathname === item.href ||
(item.href !== '/' &&
pathname.startsWith(item.href))
return (
<SidebarMenuSubItem key={item.href}>
<SidebarMenuSubButton
render={<Link href={item.href} />}
isActive={isActive}
>
<HugeiconsIcon icon={item.icon} size={15} />
<span>{item.title}</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
)
})}
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenu>
</SidebarGroup>
</Collapsible>
)
})}
</SidebarContent>
<SidebarFooter>
<div className="flex items-center gap-2 px-2 py-1 group-data-[collapsible=icon]:justify-center">
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground">
<HugeiconsIcon icon={UserIcon} size={16} />
</div>
<div className="flex min-w-0 flex-1 flex-col group-data-[collapsible=icon]:hidden">
<span className="truncate text-sm font-medium text-sidebar-foreground">
{user.fullName}
</span>
<Select value={user.role} onValueChange={(v) => setRole(v as Role)}>
<SelectTrigger className="h-5 border-0 p-0 text-xs text-muted-foreground shadow-none focus:ring-0">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="admin">Admin</SelectItem>
<SelectItem value="warehouse">Warehouse</SelectItem>
<SelectItem value="sales">Sales</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</SidebarFooter>
<SidebarRail />
</Sidebar>
)
}