first
This commit is contained in:
@@ -0,0 +1,340 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
import { useLocation } from 'react-router';
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Box,
|
||||
ClickAwayListener,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Popper,
|
||||
Typography,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
|
||||
// third-party
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
// project import
|
||||
import NavItem from './NavItem';
|
||||
import NavCollapse from './NavCollapse';
|
||||
import SimpleBar from 'components/third-party/SimpleBar';
|
||||
import Transitions from 'components/@extended/Transitions';
|
||||
|
||||
import { MenuOrientation, ThemeMode } from 'config';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import { dispatch, useSelector } from 'store';
|
||||
import { activeID } from 'store/reducers/menu';
|
||||
|
||||
// assets
|
||||
import { DownOutlined, RightOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| NAVIGATION - LIST GROUP ||============================== //
|
||||
|
||||
const PopperStyled = styled(Popper)(({ theme }) => ({
|
||||
overflow: 'visible',
|
||||
zIndex: 1202,
|
||||
minWidth: 180,
|
||||
'&:before': {
|
||||
content: '""',
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
top: 5,
|
||||
left: 32,
|
||||
width: 12,
|
||||
height: 12,
|
||||
transform: 'translateY(-50%) rotate(45deg)',
|
||||
zIndex: 120,
|
||||
borderWidth: '6px',
|
||||
borderStyle: 'solid',
|
||||
borderColor: `${theme.palette.background.paper} transparent transparent ${theme.palette.background.paper}`
|
||||
}
|
||||
}));
|
||||
|
||||
const NavGroup = ({ item, lastItem, remItems, lastItemId, setSelectedItems, selectedItems, setSelectedLevel, selectedLevel }) => {
|
||||
const theme = useTheme();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const { menuOrientation } = useConfig();
|
||||
const menu = useSelector((state) => state.menu);
|
||||
const { drawerOpen, selectedID } = menu;
|
||||
|
||||
const downLG = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const [currentItem, setCurrentItem] = useState(item);
|
||||
|
||||
const openMini = Boolean(anchorEl);
|
||||
|
||||
useEffect(() => {
|
||||
if (lastItem) {
|
||||
if (item.id === lastItemId) {
|
||||
const localItem = { ...item };
|
||||
const elements = remItems.map((ele) => ele.elements);
|
||||
localItem.children = elements.flat(1);
|
||||
setCurrentItem(localItem);
|
||||
} else {
|
||||
setCurrentItem(item);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [item, lastItem, downLG]);
|
||||
|
||||
const checkOpenForParent = (child, id) => {
|
||||
child.forEach((ele) => {
|
||||
if (ele.children?.length) {
|
||||
checkOpenForParent(ele.children, currentItem.id);
|
||||
}
|
||||
if (ele.url === pathname) {
|
||||
dispatch(activeID(id));
|
||||
}
|
||||
});
|
||||
};
|
||||
const checkSelectedOnload = (data) => {
|
||||
const childrens = data.children ? data.children : [];
|
||||
childrens.forEach((itemCheck) => {
|
||||
if (itemCheck.children?.length) {
|
||||
checkOpenForParent(itemCheck.children, currentItem.id);
|
||||
}
|
||||
if (itemCheck.url === pathname) {
|
||||
dispatch(activeID(currentItem.id));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
checkSelectedOnload(currentItem);
|
||||
if (openMini) setAnchorEl(null);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname, currentItem]);
|
||||
|
||||
const handleClick = (event) => {
|
||||
if (!openMini) {
|
||||
setAnchorEl(event?.currentTarget);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const Icon = currentItem?.icon;
|
||||
const itemIcon = currentItem?.icon ? (
|
||||
<Icon
|
||||
style={{
|
||||
fontSize: 20,
|
||||
stroke: '1.5',
|
||||
color: selectedID === currentItem.id ? theme.palette.primary.main : theme.palette.secondary.dark
|
||||
}}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
const navCollapse = item.children?.map((menuItem) => {
|
||||
switch (menuItem.type) {
|
||||
case 'collapse':
|
||||
return (
|
||||
<NavCollapse
|
||||
key={menuItem.id}
|
||||
menu={menuItem}
|
||||
setSelectedItems={setSelectedItems}
|
||||
setSelectedLevel={setSelectedLevel}
|
||||
selectedLevel={selectedLevel}
|
||||
selectedItems={selectedItems}
|
||||
level={1}
|
||||
parentId={currentItem.id}
|
||||
/>
|
||||
);
|
||||
case 'item':
|
||||
return <NavItem key={menuItem.id} item={menuItem} level={1} />;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
const moreItems = remItems.map((itemRem, i) => (
|
||||
<Fragment key={i}>
|
||||
{itemRem.title && (
|
||||
<Typography variant="caption" sx={{ pl: 2 }}>
|
||||
{itemRem.title}
|
||||
</Typography>
|
||||
)}
|
||||
{itemRem?.elements?.map((menu) => {
|
||||
switch (menu.type) {
|
||||
case 'collapse':
|
||||
return (
|
||||
<NavCollapse
|
||||
key={menu.id}
|
||||
menu={menu}
|
||||
level={1}
|
||||
parentId={currentItem.id}
|
||||
setSelectedItems={setSelectedItems}
|
||||
setSelectedLevel={setSelectedLevel}
|
||||
selectedLevel={selectedLevel}
|
||||
selectedItems={selectedItems}
|
||||
/>
|
||||
);
|
||||
case 'item':
|
||||
return <NavItem key={menu.id} item={menu} level={1} />;
|
||||
default:
|
||||
return (
|
||||
<Typography key={menu.id} variant="h6" color="error" align="center">
|
||||
Menu Items Error
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</Fragment>
|
||||
));
|
||||
|
||||
// menu list collapse & items
|
||||
const items = currentItem.children?.map((menu) => {
|
||||
switch (menu.type) {
|
||||
case 'collapse':
|
||||
return (
|
||||
<NavCollapse
|
||||
key={menu.id}
|
||||
menu={menu}
|
||||
level={1}
|
||||
parentId={currentItem.id}
|
||||
setSelectedItems={setSelectedItems}
|
||||
setSelectedLevel={setSelectedLevel}
|
||||
selectedLevel={selectedLevel}
|
||||
selectedItems={selectedItems}
|
||||
/>
|
||||
);
|
||||
case 'item':
|
||||
return <NavItem key={menu.id} item={menu} level={1} />;
|
||||
default:
|
||||
return (
|
||||
<Typography key={menu.id} variant="h6" color="error" align="center">
|
||||
Menu Items Error
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const popperId = openMini ? `group-pop-${item.id}` : undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
{menuOrientation === MenuOrientation.VERTICAL || downLG ? (
|
||||
<List
|
||||
subheader={
|
||||
item.title &&
|
||||
drawerOpen && (
|
||||
<Box sx={{ pl: 3, mb: 1.5 }}>
|
||||
<Typography variant="subtitle2" color={theme.palette.mode === ThemeMode.DARK ? 'textSecondary' : 'text.secondary'}>
|
||||
{item.title}
|
||||
</Typography>
|
||||
{item.caption && (
|
||||
<Typography variant="caption" color="secondary">
|
||||
{item.caption}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
sx={{ mt: drawerOpen && item.title ? 1.5 : 0, py: 0, zIndex: 0 }}
|
||||
>
|
||||
{navCollapse}
|
||||
</List>
|
||||
) : (
|
||||
<List>
|
||||
<ListItemButton
|
||||
selected={selectedID === currentItem.id}
|
||||
sx={{
|
||||
p: 1,
|
||||
my: 0.5,
|
||||
mr: 1,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'inherit',
|
||||
'&.Mui-selected': {
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
}}
|
||||
onMouseEnter={handleClick}
|
||||
onClick={handleClick}
|
||||
onMouseLeave={handleClose}
|
||||
aria-describedby={popperId}
|
||||
>
|
||||
{itemIcon && (
|
||||
<ListItemIcon sx={{ minWidth: 28 }}>
|
||||
{currentItem.id === lastItemId ? <DownOutlined style={{ fontSize: 20, stroke: '1.5' }} /> : itemIcon}
|
||||
</ListItemIcon>
|
||||
)}
|
||||
<ListItemText
|
||||
sx={{ mr: 1 }}
|
||||
primary={
|
||||
<Typography
|
||||
variant="body1"
|
||||
color={selectedID === currentItem.id ? theme.palette.primary.main : theme.palette.secondary.dark}
|
||||
>
|
||||
{currentItem.id === lastItemId ? <FormattedMessage id="More Items" /> : currentItem.title}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{openMini ? (
|
||||
<DownOutlined style={{ fontSize: 16, stroke: '1.5' }} />
|
||||
) : (
|
||||
<RightOutlined style={{ fontSize: 16, stroke: '1.5' }} />
|
||||
)}
|
||||
{anchorEl && (
|
||||
<PopperStyled
|
||||
id={popperId}
|
||||
open={openMini}
|
||||
anchorEl={anchorEl}
|
||||
placement="bottom-start"
|
||||
style={{
|
||||
zIndex: 2001
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Transitions in={openMini} {...TransitionProps}>
|
||||
<Paper
|
||||
sx={{
|
||||
mt: 0.5,
|
||||
py: 1.25,
|
||||
boxShadow: theme.shadows[8],
|
||||
backgroundImage: 'none'
|
||||
}}
|
||||
>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<SimpleBar
|
||||
sx={{
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'auto',
|
||||
maxHeight: 'calc(100vh - 170px)'
|
||||
}}
|
||||
>
|
||||
{currentItem.id !== lastItemId ? items : moreItems}
|
||||
</SimpleBar>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Transitions>
|
||||
)}
|
||||
</PopperStyled>
|
||||
)}
|
||||
</ListItemButton>
|
||||
</List>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
NavGroup.propTypes = {
|
||||
item: PropTypes.object,
|
||||
lastItem: PropTypes.number,
|
||||
remItems: PropTypes.array,
|
||||
lastItemId: PropTypes.string,
|
||||
setSelectedItems: PropTypes.func,
|
||||
selectedItems: PropTypes.string,
|
||||
setSelectedLevel: PropTypes.func,
|
||||
selectedLevel: PropTypes.number
|
||||
};
|
||||
|
||||
export default NavGroup;
|
||||
Reference in New Issue
Block a user