160 lines
4.6 KiB
TypeScript
160 lines
4.6 KiB
TypeScript
|
|
import type { NavigationTree } from '@/@types/navigation'
|
||
|
|
import { Direction, NavMode } from '@/@types/theme'
|
||
|
|
import { PermissionCheck } from '@/components/shared'
|
||
|
|
import Menu from '@/components/ui/Menu'
|
||
|
|
import { themeConfig } from '@/configs/theme.config'
|
||
|
|
import {
|
||
|
|
NAV_ITEM_TYPE_COLLAPSE,
|
||
|
|
NAV_ITEM_TYPE_ITEM,
|
||
|
|
NAV_ITEM_TYPE_TITLE,
|
||
|
|
} from '@/constants/navigation.constant'
|
||
|
|
import useMenuActive from '@/utils/hooks/useMenuActive'
|
||
|
|
import { useEffect, useState } from 'react'
|
||
|
|
import { Trans, useTranslation } from 'react-i18next'
|
||
|
|
import { Link, useLocation } from 'react-router-dom'
|
||
|
|
import VerticalCollapsedMenuItem from './VerticalCollapsedMenuItem'
|
||
|
|
import VerticalSingleMenuItem from './VerticalSingleMenuItem'
|
||
|
|
import MenuCollapse from '@/components/ui/Menu/MenuCollapse'
|
||
|
|
import VerticalMenuIcon from './VerticalMenuIcon'
|
||
|
|
import { MenuItem } from '@/components/ui'
|
||
|
|
|
||
|
|
export interface VerticalMenuContentProps {
|
||
|
|
navMode: NavMode
|
||
|
|
collapsed?: boolean
|
||
|
|
routeKey: string
|
||
|
|
navigationTree?: NavigationTree[]
|
||
|
|
userAuthority: string[]
|
||
|
|
onMenuItemClick?: () => void
|
||
|
|
direction?: Direction
|
||
|
|
}
|
||
|
|
|
||
|
|
const { MenuGroup } = Menu
|
||
|
|
|
||
|
|
const VerticalMenuContent = (props: VerticalMenuContentProps) => {
|
||
|
|
const { pathname } = useLocation()
|
||
|
|
|
||
|
|
const {
|
||
|
|
navMode = themeConfig.navMode,
|
||
|
|
collapsed,
|
||
|
|
routeKey,
|
||
|
|
navigationTree = [],
|
||
|
|
userAuthority = [],
|
||
|
|
onMenuItemClick,
|
||
|
|
direction = themeConfig.direction,
|
||
|
|
} = props
|
||
|
|
|
||
|
|
const { t } = useTranslation()
|
||
|
|
|
||
|
|
const [defaultExpandedKeys, setDefaultExpandedKeys] = useState<string[]>([])
|
||
|
|
const [defaultActiveKeys, setDefaultActiveKeys] = useState<string[]>([])
|
||
|
|
|
||
|
|
const { activedRoute } = useMenuActive(navigationTree, routeKey, pathname)
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
const expandedKeys = [
|
||
|
|
activedRoute.route?.parentKey,
|
||
|
|
activedRoute.parentRoute?.parentKey,
|
||
|
|
].filter(Boolean)
|
||
|
|
const activeKeys = [
|
||
|
|
activedRoute.route?.key,
|
||
|
|
activedRoute.route?.parentKey,
|
||
|
|
activedRoute.parentRoute?.parentKey,
|
||
|
|
].filter(Boolean)
|
||
|
|
|
||
|
|
setDefaultActiveKeys(activeKeys as string[])
|
||
|
|
setDefaultExpandedKeys(expandedKeys as string[])
|
||
|
|
}, [activedRoute])
|
||
|
|
|
||
|
|
const handleLinkClick = () => {
|
||
|
|
onMenuItemClick?.()
|
||
|
|
}
|
||
|
|
|
||
|
|
const getNavItem = (nav: NavigationTree) => {
|
||
|
|
if (nav.subMenu.length === 0 && nav.type === NAV_ITEM_TYPE_ITEM) {
|
||
|
|
return (
|
||
|
|
<VerticalSingleMenuItem
|
||
|
|
key={nav.key}
|
||
|
|
nav={nav}
|
||
|
|
sideCollapsed={collapsed}
|
||
|
|
userAuthority={userAuthority}
|
||
|
|
direction={direction}
|
||
|
|
onLinkClick={handleLinkClick}
|
||
|
|
/>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nav.subMenu.length > 0 && nav.type === NAV_ITEM_TYPE_COLLAPSE) {
|
||
|
|
return (
|
||
|
|
<VerticalCollapsedMenuItem
|
||
|
|
key={nav.key}
|
||
|
|
nav={nav}
|
||
|
|
sideCollapsed={collapsed}
|
||
|
|
userAuthority={userAuthority}
|
||
|
|
direction={direction}
|
||
|
|
onLinkClick={onMenuItemClick}
|
||
|
|
/>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nav.type === NAV_ITEM_TYPE_TITLE) {
|
||
|
|
if (nav.subMenu.length > 0) {
|
||
|
|
return (
|
||
|
|
<PermissionCheck key={nav.key} permissions={nav.authority}>
|
||
|
|
<MenuCollapse
|
||
|
|
key={nav.key}
|
||
|
|
label={
|
||
|
|
<>
|
||
|
|
<VerticalMenuIcon icon={nav.icon} />
|
||
|
|
<span>
|
||
|
|
<Trans i18nKey={nav.translateKey} defaults={nav.title} />
|
||
|
|
</span>
|
||
|
|
</>
|
||
|
|
}
|
||
|
|
eventKey={nav.key}
|
||
|
|
expanded={false}
|
||
|
|
>
|
||
|
|
{nav.subMenu.map((subNav) =>
|
||
|
|
subNav.subMenu.length > 0 ? (
|
||
|
|
<VerticalCollapsedMenuItem
|
||
|
|
key={subNav.key}
|
||
|
|
nav={subNav}
|
||
|
|
sideCollapsed={collapsed}
|
||
|
|
userAuthority={userAuthority}
|
||
|
|
direction={direction}
|
||
|
|
onLinkClick={onMenuItemClick}
|
||
|
|
/>
|
||
|
|
) : (
|
||
|
|
<VerticalSingleMenuItem
|
||
|
|
key={subNav.key}
|
||
|
|
nav={subNav}
|
||
|
|
sideCollapsed={collapsed}
|
||
|
|
userAuthority={userAuthority}
|
||
|
|
direction={direction}
|
||
|
|
onLinkClick={onMenuItemClick}
|
||
|
|
/>
|
||
|
|
),
|
||
|
|
)}
|
||
|
|
</MenuCollapse>
|
||
|
|
</PermissionCheck>
|
||
|
|
)
|
||
|
|
} else {
|
||
|
|
return <MenuGroup label={nav.title} />
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Menu
|
||
|
|
className="px-4 pb-4"
|
||
|
|
variant={navMode}
|
||
|
|
sideCollapsed={collapsed}
|
||
|
|
defaultActiveKeys={defaultActiveKeys}
|
||
|
|
defaultExpandedKeys={defaultExpandedKeys}
|
||
|
|
>
|
||
|
|
{navigationTree.map((nav) => getNavItem(nav))}
|
||
|
|
</Menu>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
export default VerticalMenuContent
|