Files
Client_Fe/src/hooks/use-nav-items.ts
T
Dhananjaya99 a1b870fa8a first commit
2026-09-28 11:48:14 +05:30

98 lines
2.3 KiB
TypeScript

"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 }