From 6ac4f7c5f94af9c7a456629a6dd86dc71a5dd0e7 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Sat, 2 Mar 2024 15:55:45 +0330 Subject: [PATCH] selected nested sidebar --- src/app/page.js | 4 +- .../dashboard/headerWithSidebar/index.jsx | 2 + src/core/components/SidebarListItem.jsx | 29 --- src/core/components/SidebarListItems.jsx | 46 ++++ src/core/components/SidebarMenu.jsx | 201 ++++++++++++++++++ src/core/components/SidebarSubitem.jsx | 33 --- src/core/components/SidebarSubitems.jsx | 74 +++++++ src/core/components/SidebarTest.jsx | 56 ----- 8 files changed, 325 insertions(+), 120 deletions(-) delete mode 100644 src/core/components/SidebarListItem.jsx create mode 100644 src/core/components/SidebarListItems.jsx create mode 100644 src/core/components/SidebarMenu.jsx delete mode 100644 src/core/components/SidebarSubitem.jsx create mode 100644 src/core/components/SidebarSubitems.jsx delete mode 100644 src/core/components/SidebarTest.jsx diff --git a/src/app/page.js b/src/app/page.js index 98f623d..ad66be2 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,8 +1,8 @@ -import SidebarTest from "@/core/components/SidebarTest"; +import SidebarMenu from "@/core/components/SidebarMenu"; function page() { return ( - + ); } diff --git a/src/components/layouts/dashboard/headerWithSidebar/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/index.jsx index 7591951..eeb88a3 100644 --- a/src/components/layouts/dashboard/headerWithSidebar/index.jsx +++ b/src/components/layouts/dashboard/headerWithSidebar/index.jsx @@ -4,6 +4,7 @@ import {Box, Drawer, IconButton, Paper, styled, Toolbar, Typography} from "@mui/ import MuiAppBar from '@mui/material/AppBar'; import MenuIcon from '@mui/icons-material/Menu'; import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import SidebarMenu from "@/core/components/SidebarMenu"; const drawerWidth = 260; @@ -82,6 +83,7 @@ const HeaderWithSidebar = ({children}) => { +
diff --git a/src/core/components/SidebarListItem.jsx b/src/core/components/SidebarListItem.jsx deleted file mode 100644 index 3776e8f..0000000 --- a/src/core/components/SidebarListItem.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import {Collapse, ListItem, ListItemButton, ListItemText} from "@mui/material"; -import SidebarSubitem from "@/core/components/SidebarSubitem"; -import {useState} from "react"; - -const SidebarListItem = ({menuItem, dispatch}) => { - const [open, setOpen] = useState(false) - return( - <> - - - { - dispatch({type: "COLLAPSE_MENU", id: menuItem.id}) - setOpen(!open) - }}>click - - - { - menuItem.hasSubitems ? (menuItem.Subitems.map((subitem,index)=>{ - return( - - ) - })) : null - } - - - - ) -} -export default SidebarListItem \ No newline at end of file diff --git a/src/core/components/SidebarListItems.jsx b/src/core/components/SidebarListItems.jsx new file mode 100644 index 0000000..9ffcac2 --- /dev/null +++ b/src/core/components/SidebarListItems.jsx @@ -0,0 +1,46 @@ +import {Collapse, ListItem, ListItemButton, ListItemIcon, ListItemText} from "@mui/material"; +import { ExpandLess, ExpandMore } from '@mui/icons-material'; +import WifiIcon from '@mui/icons-material/Wifi'; +import SidebarSubitems from "@/core/components/SidebarSubitems"; + +const SidebarListItems = ({menuItem, dispatch}) => { + return( + <> + + { + dispatch({type: "COLLAPSE_MENU", id: menuItem.id}) + }}> + + {menuItem.icon} + + + {menuItem.hasSubitems ? (menuItem.showSubitems ? : ) : null } + + + + { + menuItem.hasSubitems ? (menuItem.Subitems.map((subitem,index)=>{ + return( + + ) + })) : null + } + + + + ) +} +export default SidebarListItems \ No newline at end of file diff --git a/src/core/components/SidebarMenu.jsx b/src/core/components/SidebarMenu.jsx new file mode 100644 index 0000000..f7589c3 --- /dev/null +++ b/src/core/components/SidebarMenu.jsx @@ -0,0 +1,201 @@ +"use client" +import {List} from "@mui/material"; +import SidebarListItems from "@/core/components/SidebarListItems"; +import {useEffect, useReducer, useState} from "react"; +import {usePathname} from 'next/navigation' +import SecurityIcon from '@mui/icons-material/Security'; +import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard"; +import AssessmentIcon from '@mui/icons-material/Assessment'; +import AirlineSeatReclineNormalIcon from "@mui/icons-material/AirlineSeatReclineNormal"; +import RepartitionIcon from '@mui/icons-material/Repartition'; + +const data = [ + { + id: "hello", + type: "menu", + route: "/hello", + icon: , + selected: false, + Subitems: [ + { + id: "amin", + route: "/s", + icon: , + firstName: "amin", + lastName: "ali", + Subitems: [ + { + id: "shahrokh", shahrokh: "shahrokh", type: "page", selected: false, route: "/dashbssoard", icon: + }, + { + id: "shasdasdsahrokh", shahrokh: "shahroasdasdkh", type: "page", selected: false, route: "/dashboardsd", icon: + } + ], + hasSubitems: true, + showSubitems: false, + type: "menu", + selected: false, + }, + { + id: "amir", + route: "/dashboarsad", + icon: , + firstName: "amir", + lastName: "akbar", + hasSubitems: false, + showSubitems: false, + selected: false, + type: "page", + }, + ], + hasSubitems: true, + showSubitems: false + }, + { + id: "hi", + type: "menu", + icon: , + route: "/hi", + selected: false, + Subitems: [ + { + id: "ali", + route: "/dashboardss", + firstName: "ali", + lastName: "ali", + icon: , + hasSubitems: false, + showSubitems: false, + type: "page", + selected: false, + }, + { + id: "akbar", + route: "/akbar", + firstName: "akbar", + icon: , + lastName: "akbar", + hasSubitems: false, + showSubitems: false, + type: "page", + selected: false, + }, + ], + hasSubitems: true, + showSubitems: false + }, + { + id: "hoo", + type: "page", + route: "/dashboard", + icon: , + selected: false, + hasSubitems: false, + showSubitems: false + } +] + +function reducer(state, action) { + switch (action.type) { + case "COLLAPSE_MENU": + return state.map((item) => action.id == item.id ? { + ...item, showSubitems: !item.showSubitems + } : item) + case "COLLAPSE_SUB_ITEMS" : + return state.map((item) => { + return item.hasSubitems ? { + ...item, Subitems: item.Subitems.map((subitem) => action.id === subitem.id ? { + ...subitem, showSubitems: !subitem.showSubitems + } : subitem) + } : item + }) + case "COLLAPSE_SUB_SECOND_ITEMS" : + return state.map((item) => { + return item.hasSubitems ? { + ...item, Subitems: item.Subitems.map((subitem) => { + return subitem.hasSubitems ? { + ...subitem, + Subitems: subitem.Subitems.map((secondSubitem) => action.id === secondSubitem.id ? { + ...secondSubitem, showSubitems: !secondSubitem.showSubitems + } : secondSubitem) + } : subitem + }) + } : item + }) + case "SELECTED": + return state.map((item) => { + return item.type === "page" ? { + ...item, selected: action.route === item.route,showSubitems: item.route === action.route + } : item.Subitems && Array.isArray(item.Subitems) ? { + ...item, Subitems: item.Subitems.map((subitem) => { + return subitem.type === "page" ? { + ...subitem, selected: action.route === subitem.route,showSubitems: subitem.route === action.route + } : subitem.Subitems && Array.isArray(subitem.Subitems) ? { + ...subitem, Subitems: subitem.Subitems.map((secondSubItem) => ({ + ...secondSubItem, selected: secondSubItem.route === action.route + })),showSubitems: subitem.Subitems.some((secondSubItem) => secondSubItem.route === action.route), + } : subitem + }),showSubitems: item.Subitems.some((subitem) => subitem.showSubitems), + } : item + }); + // case "SELECTED": + // return state.map((item) => { + // return item.type === "page" ? { + // ...item, + // selected: action.route === item.route + // } : item.Subitems && Array.isArray(item.Subitems) ? { + // ...item, + // Subitems: item.Subitems.map((subitem) => { + // const updatedSubitem = subitem.type === "page" ? { + // ...subitem, + // selected: action.route === subitem.route + // } : subitem.Subitems && Array.isArray(subitem.Subitems) ? { + // ...subitem, + // Subitems: subitem.Subitems.map((secondSubItem) => ({ + // ...secondSubItem, + // selected: secondSubItem.route === action.route + // })), + // showSubitems: subitem.Subitems.some((secondSubItem) => secondSubItem.route === action.route), + // } : subitem; + // + // console.log("Updated subitem:", updatedSubitem); // Log the updated subitem + // return updatedSubitem; + // }), + // showSubitems: item.Subitems.some((subitem) => subitem.showSubitems), + // } : item + // }); + + + default: + throw new Error(); + } +} + +const SidebarMenu = () => { + const [menuItems, dispatch] = useReducer(reducer, data); + const pathname = usePathname() + const [selectedKey, setSelectedKey] = useState(null); + useEffect(() => { + dispatch({type: "SELECTED", route: pathname}); + setSelectedKey(pathname); + }, [pathname]); + + useEffect(() => { + selectedKey && document.querySelector(`[data-route="${selectedKey}"]`)?.scrollIntoView({ + behavior: "smooth", block: "center" + }); + }, [selectedKey]); + + return ( + + { + menuItems.map((menuItem) => { + return ( + + ) + }) + } + + ) +} +export default SidebarMenu \ No newline at end of file diff --git a/src/core/components/SidebarSubitem.jsx b/src/core/components/SidebarSubitem.jsx deleted file mode 100644 index 2e0afc0..0000000 --- a/src/core/components/SidebarSubitem.jsx +++ /dev/null @@ -1,33 +0,0 @@ -import {Collapse, List, ListItem, ListItemButton, ListItemText} from "@mui/material"; -import {useState} from "react"; - -const SidebarSubitem = ({subitem, dispatch}) => { - const [subOpen, setSubOpen] = useState(false) - return( - <> - - - - {subitem.hasSubitems ? ( { - dispatch({type: "Subitem1", id: subitem.id}) - setSubOpen(!subOpen) - }}>click) : null} - - - { - subitem.hasSubitems ? (subitem.Subitems.map((subSubitem,index) => { - return( - - - - - - - - ) - })) : null - } - - ) -} -export default SidebarSubitem \ No newline at end of file diff --git a/src/core/components/SidebarSubitems.jsx b/src/core/components/SidebarSubitems.jsx new file mode 100644 index 0000000..275befb --- /dev/null +++ b/src/core/components/SidebarSubitems.jsx @@ -0,0 +1,74 @@ +import {Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText} from "@mui/material"; +import {ExpandLess, ExpandMore} from "@mui/icons-material"; + +const SidebarSubitems = ({subitem, dispatch}) => { + return ( + <> + + + { + dispatch({type: "COLLAPSE_SUB_ITEMS", id: subitem.id}) + }}> + + {subitem.icon} + + + {subitem.hasSubitems ? (subitem.showSubitems ? : ) : null + } + + + + { + subitem.hasSubitems ? (subitem.Subitems.map((subSubitem, index) => { + return ( + + + + { + dispatch({type: "COLLAPSE_SUB_SECOND_ITEMS", id: subSubitem.id}) + }} + selected={subSubitem.selected} + sx={{ + '&.Mui-selected': { + backgroundColor: 'rgba(0, 0, 0, 0.05)', + }, + }} + > + + {subSubitem.icon} + + + + + + + ) + })) : null + } + + ) +} +export default SidebarSubitems \ No newline at end of file diff --git a/src/core/components/SidebarTest.jsx b/src/core/components/SidebarTest.jsx deleted file mode 100644 index f7c9b9e..0000000 --- a/src/core/components/SidebarTest.jsx +++ /dev/null @@ -1,56 +0,0 @@ -"use client" -import {List} from "@mui/material"; -import SidebarListItem from "@/core/components/SidebarListItem"; -import {useReducer} from "react"; -const data = [ - { - id : "hello", - Subitems : [ - {id : "amin",firstName : "amin", lastName:"ali",Subitems : [{id : "shahrokh",shahrokh : "shahrokh"}], hasSubitems : true, showSubitems : false}, - {id : "amir",firstName : "amir", lastName:"akbar", hasSubitems : false, showSubitems : false}, - ], - hasSubitems : true, - showSubitems : false - }, - { - id : "hi", - Subitems : [ - {id : "ali",firstName : "ali", lastName:"ali", hasSubitems : false, showSubitems : false}, - {id : "akbar",firstName : "akbar", lastName:"akbar", hasSubitems : false, showSubitems : false}, - ], - hasSubitems : true, - showSubitems : false - } -] -function reducer(state, action) { - switch (action.type) { - case "COLLAPSE_MENU": - return state.map((item) => action.id == item.id ? { - ...item, showSubitems: !item.showSubitems - } : item) - case "Subitem1" : - return state.map((item) => { - return item.hasSubitems ? {...item, Subitems: item.Subitems.map((subitem) => action.id === subitem.id ? { - ...subitem, showSubitems: !subitem.showSubitems - } : subitem)} : item - }) - default: - throw new Error(); - } -} - -const SidebarTest = () => { - const [itemMenu, dispatch] = useReducer(reducer, data); - return( - - { - itemMenu.map((menuItem) => { - return( - - ) - }) - } - - ) -} -export default SidebarTest \ No newline at end of file