'use client'
import Link from 'next/link'
import { useMemo, useState } from 'react'
import type { SidebarRoute } from '@/types'
import Button from '@/components/formElements/Button'
import AngleDownIcon from '@/components/icons/AngleDownIcon'
import { isSidebarGroupOpen, isSidebarRouteActive } from '@/helpers/sidebarRoute'
interface SidebarNavProps {
items: SidebarRoute[]
pathname: string
onLinkClick?: () => void
compact?: boolean
}
const iconClass = (active: boolean, size: 'md' | 'sm' = 'md') =>
`${size === 'sm' ? 'size-4' : 'size-5'} ${active ? 'text-white' : 'text-secondary-30'}`
const SidebarNavIcon = ({ active, item, size = 'md' }: { item: SidebarRoute; active: boolean; size?: 'md' | 'sm' }) => {
const boxClass = size === 'sm' ? 'size-6' : 'size-8'
if (!item.icon) {
return (
)
}
return (
{item.icon(iconClass(active, size))}
)
}
const SidebarNavLink = ({
active,
href,
item,
onLinkClick,
size = 'md',
compact = false,
}: {
item: SidebarRoute
href: string
active: boolean
onLinkClick?: () => void
size?: 'md' | 'sm'
compact?: boolean
}) => {
const isChild = size === 'sm'
return (
{!isChild &&
(compact && item.icon ? (
item.icon(`size-6 ${active ? 'text-primary-700' : 'text-secondary-20'}`)
) : (
))}
{isChild &&
(item.icon ? (
) : null)}
{item.title}
)
}
const SidebarNavGroup = ({
groupKey,
isOpen,
item,
onLinkClick,
onToggle,
pathname,
}: {
item: SidebarRoute
groupKey: string
pathname: string
isOpen: boolean
onToggle: (key: string) => void
onLinkClick?: () => void
}) => {
const active = isSidebarRouteActive(pathname, item)
return (
{isOpen && item.children ? (
{item.children.map((child, childIndex) => {
if (!child.link) {
return null
}
const childActive = isSidebarRouteActive(pathname, child)
return (
)
})}
) : null}
)
}
const SidebarNav = ({ compact = false, items, onLinkClick, pathname }: SidebarNavProps) => {
const autoOpenKeys = useMemo(() => {
const keys = new Set()
items.forEach((item, index) => {
if (item.children && isSidebarGroupOpen(pathname, item)) {
keys.add(String(index))
}
})
return keys
}, [pathname, items])
const [prevPathname, setPrevPathname] = useState(pathname)
const [manualClosed, setManualClosed] = useState>(() => new Set())
const [manualOpen, setManualOpen] = useState>(() => new Set())
if (pathname !== prevPathname) {
setPrevPathname(pathname)
setManualClosed(new Set())
setManualOpen(new Set())
}
const isGroupOpen = (key: string) => {
if (manualClosed.has(key)) {
return false
}
if (manualOpen.has(key)) {
return true
}
return autoOpenKeys.has(key)
}
const toggleGroup = (key: string) => {
if (isGroupOpen(key)) {
setManualClosed((prev) => new Set(prev).add(key))
setManualOpen((prev) => {
const next = new Set(prev)
next.delete(key)
return next
})
} else {
setManualOpen((prev) => new Set(prev).add(key))
setManualClosed((prev) => {
const next = new Set(prev)
next.delete(key)
return next
})
}
}
return (
)
}
export default SidebarNav