@@ -27,6 +27,8 @@ import { getIconComponent } from "@/lib/icon-map"
2727import navs from "@/config/navs"
2828import type { NavItem } from "@/types/app-config"
2929import { usePermissions } from "@/hooks/use-permissions"
30+ import { useFirstAccessibleDashboardRoute } from "@/hooks/use-first-accessible-dashboard-route"
31+ import { canAccessDashboardRoute } from "@/lib/dashboard-route-meta"
3032import { SidebarVersion } from "@/components/sidebars/version"
3133import { useDirection } from "@/components/ui/direction"
3234import { getThemeManifest } from "@/lib/theme/manifest"
@@ -65,23 +67,29 @@ export function AppSidebar() {
6567 const dir = useDirection ( )
6668 const brandInitial = APP_NAME . charAt ( 0 ) . toUpperCase ( ) ?? "R"
6769
68- const { isAdmin, canAccessPath } = usePermissions ( )
70+ const { isAdmin, canAccessPath, hasResolvedAdmin, hasFetchedPolicy, isLoading } = usePermissions ( )
71+ const { route : homeRoute } = useFirstAccessibleDashboardRoute ( )
72+ const isPermissionsReady = hasResolvedAdmin && ( isAdmin || ( ! isLoading && hasFetchedPolicy ) )
6973
70- const navGroups : NavItem [ ] [ ] = [ ]
71- let current : NavItem [ ] = [ ]
74+ if ( ! isPermissionsReady ) {
75+ return null
76+ }
77+
78+ const visibleNavs = navs . flatMap ( ( nav ) => {
79+ if ( nav . type === "divider" ) {
80+ return [ nav ]
81+ }
7282
73- for ( const nav of navs ) {
7483 let visibleChildren : NavItem [ ] = [ ]
7584 if ( nav . children ?. length ) {
7685 visibleChildren = nav . children . filter ( ( child ) => {
77- if ( child . to && ! canAccessPath ( child . to ) ) return false
78- if ( child . isAdminOnly && ! isAdmin && ! child . to ) return false
86+ if ( ! child . to || isExternal ( child ) ) return true
87+ if ( ! canAccessDashboardRoute ( child . to , { isAdmin, canAccessPath } ) ) return false
7988 return true
8089 } )
81- if ( visibleChildren . length === 0 && ! nav . to ) continue
90+ if ( visibleChildren . length === 0 && ! nav . to ) return [ ]
8291 } else {
83- if ( nav . to && ! canAccessPath ( nav . to ) ) continue
84- if ( ! nav . to && nav . isAdminOnly && ! isAdmin ) continue
92+ if ( nav . to && ! isExternal ( nav ) && ! canAccessDashboardRoute ( nav . to , { isAdmin, canAccessPath } ) ) return [ ]
8593 }
8694
8795 const navItem = { ...nav }
@@ -91,18 +99,30 @@ export function AppSidebar() {
9199 delete navItem . children
92100 }
93101
102+ return [ navItem ]
103+ } )
104+
105+ const navGroups : NavItem [ ] [ ] = [ ]
106+ let current : NavItem [ ] = [ ]
107+
108+ for ( let index = 0 ; index < visibleNavs . length ; index ++ ) {
109+ const nav = visibleNavs [ index ]
110+ if ( ! nav ) continue
111+
94112 if ( nav . type === "divider" ) {
95- if ( current . length ) {
113+ const hasItemsBefore = current . length > 0
114+ const hasItemsAfter = visibleNavs . slice ( index + 1 ) . some ( ( item ) => item . type !== "divider" )
115+ if ( hasItemsBefore && hasItemsAfter ) {
96116 navGroups . push ( current )
97117 current = [ ]
98118 }
99119 continue
100120 }
101121
102- current . push ( navItem )
122+ current . push ( nav )
103123 }
104124
105- if ( current . length ) {
125+ if ( current . length > 0 ) {
106126 navGroups . push ( current )
107127 }
108128
@@ -127,7 +147,7 @@ export function AppSidebar() {
127147 className = "**:data-[sidebar=menu-button]:text-start! **:data-[sidebar=menu-sub-button]:text-start!"
128148 >
129149 < SidebarHeader >
130- < Link href = "/" className = "flex items-center gap-3" >
150+ < Link href = { homeRoute ?? "/" } className = "flex items-center gap-3" >
131151 { isCollapsed ? (
132152 < div className = "flex size-8 items-center justify-center rounded-lg bg-primary text-md font-semibold text-primary-foreground" >
133153 < span > { brandInitial } </ span >
0 commit comments