LFFE-6 sidebar improvement
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import {Divider, List} from "@mui/material";
|
import {Divider, List} from "@mui/material";
|
||||||
import {useEffect, useReducer} from "react";
|
import {Fragment, useEffect, useReducer, useRef, useState} from "react";
|
||||||
import SidebarListItem from "./SidebarListItem";
|
import SidebarListItem from "./SidebarListItem";
|
||||||
import sidebarMenu from "@/core/data/sidebarMenu";
|
import sidebarMenu from "@/core/data/sidebarMenu";
|
||||||
import {useRouter} from "next/router";
|
import {useRouter} from "next/router";
|
||||||
@@ -10,18 +10,27 @@ function reducer(state, action) {
|
|||||||
case "COLLAPSE_MENU":
|
case "COLLAPSE_MENU":
|
||||||
return state.map((itemsArr) =>
|
return state.map((itemsArr) =>
|
||||||
itemsArr.map((item) =>
|
itemsArr.map((item) =>
|
||||||
action.key == item.key
|
action.key === item.key ? { ...item, showSubItem: !item.showSubItem } : item
|
||||||
? {...item, showSubItem: !item.showSubItem}
|
|
||||||
: item
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
case "SELECTED":
|
case "SELECTED":
|
||||||
return state.map((itemsArr) =>
|
return state.map((itemsArr) =>
|
||||||
itemsArr.map((item) =>
|
itemsArr.map((item) => {
|
||||||
action.route == item.route
|
return item.type === "page"
|
||||||
? {...item, selected: true}
|
? { ...item, selected: action.route === item.route }
|
||||||
: {...item, selected: false}
|
: item.subItem && Array.isArray(item.subItem)
|
||||||
)
|
? {
|
||||||
|
...item,
|
||||||
|
subItem: item.subItem.map((subitem) => ({
|
||||||
|
...subitem,
|
||||||
|
selected: subitem.route === action.route,
|
||||||
|
})),
|
||||||
|
showSubItem: item.subItem.some(
|
||||||
|
(subitem) => subitem.selected
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: item;
|
||||||
|
})
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
throw new Error();
|
throw new Error();
|
||||||
@@ -32,26 +41,39 @@ export default function SidebarList({handleDrawerToggle}) {
|
|||||||
const [itemMenu, dispatch] = useReducer(reducer, sidebarMenu);
|
const [itemMenu, dispatch] = useReducer(reducer, sidebarMenu);
|
||||||
const {user} = useUser();
|
const {user} = useUser();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [selectedKey, setSelectedKey] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch({type: "SELECTED", route: router.pathname});
|
dispatch({type: "SELECTED", route: router.pathname});
|
||||||
|
setSelectedKey(router.pathname);
|
||||||
}, [router.pathname]);
|
}, [router.pathname]);
|
||||||
|
|
||||||
const filteredItemMenu = itemMenu[0].filter(
|
|
||||||
(item) => user.permissions.includes(item.permission) || item.permission === "all"
|
useEffect(() => {
|
||||||
);
|
selectedKey && document.querySelector(`[data-route="${selectedKey}"]`)?.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "center"
|
||||||
|
});
|
||||||
|
}, [selectedKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List>
|
<List sx={{ overflow: "scroll"}}>
|
||||||
{filteredItemMenu.map((item, index) => (
|
{itemMenu.map((itemArr, index) => (
|
||||||
<SidebarListItem
|
<Fragment key={index}>
|
||||||
item={item}
|
{itemArr.map((item) =>
|
||||||
dispatch={dispatch}
|
<Fragment key={item.key}>
|
||||||
key={item.key}
|
{(user?.permissions?.includes(item.permission) || item.permission === "all") &&
|
||||||
handleDrawerToggle={handleDrawerToggle}
|
<SidebarListItem
|
||||||
/>
|
item={item}
|
||||||
|
dispatch={dispatch}
|
||||||
|
handleDrawerToggle={handleDrawerToggle}
|
||||||
|
/>}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
<Divider/>
|
||||||
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
{filteredItemMenu.length > 0 && <Divider/>}
|
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,23 +9,27 @@ import useNotification from "@/lib/app/hooks/useNotification";
|
|||||||
|
|
||||||
const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const {notification_count} = useNotification()
|
const { notification_count } = useNotification();
|
||||||
|
const hasSubItems = item.type === "menu" && item.subItem && item.subItem.length > 0;
|
||||||
|
const renderBadge = () => {
|
||||||
|
return !hasSubItems ? (
|
||||||
|
<IconButton>
|
||||||
|
<Badge
|
||||||
|
badgeContent={notification_count && notification_count.length>0 ? notification_count[item.name] : 0}
|
||||||
|
color="error"
|
||||||
|
variant="standard"
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: "top",
|
||||||
|
horizontal: "right",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment key={item.key}>
|
<>
|
||||||
<ListItem disablePadding secondaryAction={
|
<ListItem data-route={item.route} disablePadding secondaryAction={renderBadge()}>
|
||||||
<IconButton>
|
|
||||||
<Badge
|
|
||||||
badgeContent={notification_count ? notification_count[item.name] : 0}
|
|
||||||
color="error"
|
|
||||||
variant="standard"
|
|
||||||
anchorOrigin={{
|
|
||||||
vertical: "top",
|
|
||||||
horizontal: "right",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
}>
|
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
selected={item.selected}
|
selected={item.selected}
|
||||||
{...(item.type == "page" && {
|
{...(item.type == "page" && {
|
||||||
@@ -35,10 +39,9 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (item.type == "menu") {
|
if (hasSubItems) {
|
||||||
dispatch({type: "COLLAPSE_MENU", key: item.key});
|
dispatch({ type: "COLLAPSE_MENU", key: item.key });
|
||||||
}
|
}
|
||||||
handleDrawerToggle();
|
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
minHeight: 48,
|
minHeight: 48,
|
||||||
@@ -66,9 +69,7 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{hasSubItems && (item.showSubItem ? <ExpandLess /> : <ExpandMore />)}
|
||||||
{item.type == "menu" &&
|
|
||||||
(item.showSubItem ? <ExpandLess/> : <ExpandMore/>)}
|
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{item.subItem && (
|
{item.subItem && (
|
||||||
@@ -77,7 +78,7 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
|||||||
handleDrawerToggle={handleDrawerToggle}
|
handleDrawerToggle={handleDrawerToggle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,43 @@
|
|||||||
import {NextLinkComposed} from "@/core/components/LinkRouting";
|
import {NextLinkComposed} from "@/core/components/LinkRouting";
|
||||||
import InboxIcon from "@mui/icons-material/MoveToInbox";
|
import {
|
||||||
import {Collapse, List, ListItemButton, ListItemIcon, ListItemText,} from "@mui/material";
|
Badge,
|
||||||
|
Collapse,
|
||||||
|
IconButton,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
ListItemButton,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemText,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
import {useTranslations} from "next-intl";
|
import {useTranslations} from "next-intl";
|
||||||
import {Fragment} from "react";
|
import useNotification from "@/lib/app/hooks/useNotification";
|
||||||
|
|
||||||
const SidebarListSubItem = ({item, handleDrawerToggle}) => {
|
const SidebarListSubItem = ({item, handleDrawerToggle }) => {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
const {notification_count} = useNotification();
|
||||||
|
const renderBadge = (subitem) => (
|
||||||
|
<IconButton>
|
||||||
|
<Badge
|
||||||
|
badgeContent={notification_count && notification_count.length>0 ? notification_count[subitem.name] : 0}
|
||||||
|
color="error"
|
||||||
|
variant="standard"
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: "top",
|
||||||
|
horizontal: "right",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapse in={item.showSubItem} timeout="auto" unmountOnExit>
|
|
||||||
<List component="div" disablePadding sx={{bgcolor: "#f6f6f6"}}>
|
<Collapse in={item.showSubItem} timeout="auto" mountOnEnter={true} unmountOnExit={true}>
|
||||||
{item.subItem.map((subitem, index) => (
|
<List component="div" disablePadding sx={{bgcolor: "#f6f6f6", pr: 0}}>
|
||||||
<Fragment key={subitem.key}>
|
{item.subItem.map((subitem) => (
|
||||||
|
<ListItem key={subitem.key} disablePadding secondaryAction={renderBadge(subitem)}>
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
|
selected={subitem.selected}
|
||||||
component={NextLinkComposed}
|
component={NextLinkComposed}
|
||||||
to={{
|
to={{
|
||||||
pathname: subitem.route,
|
pathname: subitem.route,
|
||||||
@@ -20,12 +45,6 @@ const SidebarListSubItem = ({item, handleDrawerToggle}) => {
|
|||||||
sx={{
|
sx={{
|
||||||
minHeight: 48,
|
minHeight: 48,
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
|
||||||
if (item.type == "menu") {
|
|
||||||
dispatch({type: "COLLAPSE_MENU", key: item.key});
|
|
||||||
}
|
|
||||||
handleDrawerToggle();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<ListItemIcon
|
<ListItemIcon
|
||||||
sx={{
|
sx={{
|
||||||
@@ -34,14 +53,21 @@ const SidebarListSubItem = ({item, handleDrawerToggle}) => {
|
|||||||
pr: 2,
|
pr: 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<InboxIcon/>
|
{subitem.icon}
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={t(subitem.key)}/>
|
<ListItemText primary={t(subitem.key)} secondary={
|
||||||
|
subitem.secondary !== undefined ? (
|
||||||
|
<Typography variant="caption" color="textSecondary">
|
||||||
|
{t(subitem.secondary)}
|
||||||
|
</Typography>
|
||||||
|
) : null
|
||||||
|
}/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Fragment>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const Sidebar = (props) => {
|
|||||||
"& .MuiDrawer-paper": {
|
"& .MuiDrawer-paper": {
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
width: props.drawerWidth,
|
width: props.drawerWidth,
|
||||||
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -33,6 +34,7 @@ const Sidebar = (props) => {
|
|||||||
"& .MuiDrawer-paper": {
|
"& .MuiDrawer-paper": {
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
width: props.drawerWidth,
|
width: props.drawerWidth,
|
||||||
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
open
|
open
|
||||||
|
|||||||
Reference in New Issue
Block a user