151 lines
4.5 KiB
TypeScript
151 lines
4.5 KiB
TypeScript
|
|
import type { CommonProps } from '@/proxy/common'
|
||
|
|
import type { NavigationTree } from '@/proxy/menus/navigation'
|
||
|
|
import type { Direction, Mode, NavMode } from '@/proxy/theme/models'
|
||
|
|
import { PermissionCheck } from '@/components/shared'
|
||
|
|
import Logo from '@/components/template/Logo'
|
||
|
|
import Menu from '@/components/ui/Menu'
|
||
|
|
import ScrollBar from '@/components/ui/ScrollBar'
|
||
|
|
import navigationIcon from '@/proxy/menus/navigation-icon.config'
|
||
|
|
import { NAV_ITEM_TYPE_ITEM } from '@/constants/navigation.constant'
|
||
|
|
import {
|
||
|
|
NAV_MODE_DARK,
|
||
|
|
NAV_MODE_THEMED,
|
||
|
|
NAV_MODE_TRANSPARENT,
|
||
|
|
SIDE_NAV_CONTENT_GUTTER,
|
||
|
|
} from '@/constants/theme.constant'
|
||
|
|
import { useStoreState } from '@/store'
|
||
|
|
import useMenuActive from '@/utils/hooks/useMenuActive'
|
||
|
|
import isEmpty from 'lodash/isEmpty'
|
||
|
|
import React from 'react'
|
||
|
|
import { useEffect } from 'react'
|
||
|
|
import { FaQuestionCircle } from 'react-icons/fa'
|
||
|
|
import { Link, useLocation } from 'react-router-dom'
|
||
|
|
|
||
|
|
export type SelectedMenuItem = {
|
||
|
|
key?: string
|
||
|
|
title?: string
|
||
|
|
menu?: NavigationTree[]
|
||
|
|
translateKey?: string
|
||
|
|
}
|
||
|
|
|
||
|
|
interface StackedSideNavMiniProps extends CommonProps {
|
||
|
|
className?: string
|
||
|
|
navMode: NavMode
|
||
|
|
onChange: (item: SelectedMenuItem) => void
|
||
|
|
routeKey: string
|
||
|
|
activeKeys: string[]
|
||
|
|
onSetActiveKey: (activeKey: string[]) => void
|
||
|
|
userAuthority: string[]
|
||
|
|
mode: Mode
|
||
|
|
direction: Direction
|
||
|
|
}
|
||
|
|
|
||
|
|
const StackedSideNavMini = (props: StackedSideNavMiniProps) => {
|
||
|
|
const { pathname } = useLocation()
|
||
|
|
|
||
|
|
const {
|
||
|
|
navMode,
|
||
|
|
onChange,
|
||
|
|
routeKey,
|
||
|
|
activeKeys,
|
||
|
|
onSetActiveKey,
|
||
|
|
|
||
|
|
mode,
|
||
|
|
direction,
|
||
|
|
...rest
|
||
|
|
} = props
|
||
|
|
|
||
|
|
const { mainMenu: navigationConfig } = useStoreState((state) => state.abpConfig.menu)
|
||
|
|
|
||
|
|
const { includedRouteTree } = useMenuActive(navigationConfig, routeKey, pathname)
|
||
|
|
|
||
|
|
const logoMode = () => {
|
||
|
|
if (navMode === NAV_MODE_THEMED) {
|
||
|
|
return NAV_MODE_DARK
|
||
|
|
}
|
||
|
|
|
||
|
|
if (navMode === NAV_MODE_TRANSPARENT) {
|
||
|
|
return mode
|
||
|
|
}
|
||
|
|
|
||
|
|
return navMode
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleMenuItemSelect = ({ key, title, menu, translateKey }: SelectedMenuItem) => {
|
||
|
|
onChange({ title, menu, translateKey })
|
||
|
|
onSetActiveKey([key as string])
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleLinkMenuItemSelect = ({ key }: SelectedMenuItem) => {
|
||
|
|
onChange({})
|
||
|
|
onSetActiveKey([key as string])
|
||
|
|
}
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (includedRouteTree.type !== NAV_ITEM_TYPE_ITEM && !isEmpty(includedRouteTree)) {
|
||
|
|
onChange({
|
||
|
|
key: includedRouteTree.key,
|
||
|
|
title: includedRouteTree.title,
|
||
|
|
menu: includedRouteTree.subMenu,
|
||
|
|
translateKey: includedRouteTree.translateKey,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
|
|
}, [includedRouteTree.key])
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div {...rest}>
|
||
|
|
<Logo mode={logoMode()} type="streamline" className={SIDE_NAV_CONTENT_GUTTER} />
|
||
|
|
<ScrollBar autoHide direction={direction}>
|
||
|
|
<Menu
|
||
|
|
className="px-6 pb-4 py-1"
|
||
|
|
variant={navMode}
|
||
|
|
defaultActiveKeys={activeKeys || [includedRouteTree.key]}
|
||
|
|
>
|
||
|
|
{navigationConfig.map((nav) => (
|
||
|
|
<PermissionCheck key={nav.key} permissions={nav.authority}>
|
||
|
|
{nav.subMenu && nav.subMenu.length > 0 ? (
|
||
|
|
<Menu.MenuItem
|
||
|
|
icon={nav.icon}
|
||
|
|
eventKey={nav.key}
|
||
|
|
className="mb-2"
|
||
|
|
onSelect={() =>
|
||
|
|
handleMenuItemSelect({
|
||
|
|
key: nav.key,
|
||
|
|
title: nav.title,
|
||
|
|
menu: nav.subMenu,
|
||
|
|
translateKey: nav.translateKey,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
>
|
||
|
|
<div className="text-2xl">
|
||
|
|
{React.createElement(navigationIcon[nav.icon] || FaQuestionCircle)}{' '}
|
||
|
|
</div>
|
||
|
|
</Menu.MenuItem>
|
||
|
|
) : (
|
||
|
|
<Link
|
||
|
|
to={nav.path}
|
||
|
|
className="flex items-center h-full w-full"
|
||
|
|
onClick={() =>
|
||
|
|
handleLinkMenuItemSelect({
|
||
|
|
key: nav.key,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
>
|
||
|
|
<Menu.MenuItem icon={nav.icon} eventKey={nav.key} className="mb-2">
|
||
|
|
<div className="text-2xl">
|
||
|
|
{React.createElement(navigationIcon[nav.icon] || FaQuestionCircle)}
|
||
|
|
</div>
|
||
|
|
</Menu.MenuItem>
|
||
|
|
</Link>
|
||
|
|
)}
|
||
|
|
</PermissionCheck>
|
||
|
|
))}
|
||
|
|
</Menu>
|
||
|
|
</ScrollBar>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
export default StackedSideNavMini
|