first commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type { LucideIcon } from "lucide-react"
|
||||
import {
|
||||
Activity,
|
||||
BarChart3,
|
||||
CalendarCheck,
|
||||
CalendarClock,
|
||||
CreditCard,
|
||||
LayoutDashboard,
|
||||
Receipt,
|
||||
Rss,
|
||||
Settings,
|
||||
TicketIcon,
|
||||
Users,
|
||||
UsersRound,
|
||||
Utensils,
|
||||
} from "lucide-react"
|
||||
import { getNav } from "@/lib/api/nav"
|
||||
import type { DashboardNavItem } from "@/lib/nav"
|
||||
|
||||
const ICON_MAP: Record<string, LucideIcon> = {
|
||||
Activity,
|
||||
BarChart3,
|
||||
CalendarCheck,
|
||||
CalendarClock,
|
||||
CreditCard,
|
||||
LayoutDashboard,
|
||||
Receipt,
|
||||
Rss,
|
||||
Settings,
|
||||
TicketIcon,
|
||||
Users,
|
||||
UsersRound,
|
||||
Utensils,
|
||||
}
|
||||
|
||||
interface NavState {
|
||||
isOwner: boolean
|
||||
items: DashboardNavItem[]
|
||||
}
|
||||
|
||||
// Module-level cache: the nav call happens once per dashboard session — app-sidebar.tsx
|
||||
// and mobile-nav.tsx both mount together and both need this, so a plain cache avoids
|
||||
// wrapping DashboardShell in a second context provider just for this.
|
||||
let cache: NavState | null = null
|
||||
|
||||
/** Clears the per-session nav cache when a user signs in or out. */
|
||||
function resetNavItemsCache() {
|
||||
cache = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Live, permission-filtered sidebar nav for the current caller.
|
||||
*
|
||||
* Sandbox components pass `false` because they use the static demo navigation
|
||||
* and must never make an authenticated permission request.
|
||||
*/
|
||||
function useNavItems(enabled = true) {
|
||||
const [state, setState] = React.useState<NavState>(cache ?? { isOwner: false, items: [] })
|
||||
const [loading, setLoading] = React.useState(enabled && !cache)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!enabled || cache) return
|
||||
let cancelled = false
|
||||
|
||||
getNav()
|
||||
.then((res) => {
|
||||
if (cancelled) return
|
||||
const items = res.items.map((i) => ({
|
||||
key: i.key,
|
||||
label: i.label,
|
||||
shortLabel: i.shortLabel,
|
||||
href: i.href,
|
||||
icon: ICON_MAP[i.icon] ?? LayoutDashboard,
|
||||
}))
|
||||
cache = { isOwner: res.isOwner, items }
|
||||
setState(cache)
|
||||
})
|
||||
.catch(() => {
|
||||
// Leave state empty — the sidebar/mobile-nav will just show nothing until a retry
|
||||
// (e.g. navigating away and back re-mounts the hook, since cache stays null).
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setLoading(false)
|
||||
})
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [enabled])
|
||||
|
||||
return { ...state, loading: enabled && loading }
|
||||
}
|
||||
|
||||
export { resetNavItemsCache, useNavItems }
|
||||
Reference in New Issue
Block a user