LFFE-17 Merge branch 'feature/LFFE-17_loading_navigation_pages_dashboard' into 'develop'
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
"between": "میان",
|
||||
"online_message": "شما به اینترنت وصل هستید",
|
||||
"offline_message": "اتصال شما به اینترنت قطع شده است",
|
||||
"routing_to": "در حال انتقال به صفحه",
|
||||
"header": {
|
||||
"open_profile": "پروفایل",
|
||||
"edit_profile": " پروفایل",
|
||||
|
||||
@@ -24,6 +24,7 @@ const DeleteForm = ({rowId, mutate}) => {
|
||||
const handleSubmit = () => {
|
||||
setIsSubmitting(true)
|
||||
requestServer(`${DELETE_ROLE_MANAGEMENT}/${rowId}`, 'delete').then((response) => {
|
||||
setOpenConfirmDialog(false)
|
||||
mutate()
|
||||
update_notification()
|
||||
}).catch(() => {
|
||||
|
||||
65
src/components/layouts/Dashboard/Content/index.jsx
Normal file
65
src/components/layouts/Dashboard/Content/index.jsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import LoadingHardPage from "@/core/components/LoadingHardPage";
|
||||
import RolePermissionMiddleware from "@/middlewares/RolePermission";
|
||||
import BreadCrumbs from "@/components/layouts/Dashboard/Breadcrumbs";
|
||||
import FullPageLayout from "@/layouts/FullPageLayout";
|
||||
import {useEffect, useMemo, useState} from "react";
|
||||
import sidebarMenu from "@/core/data/sidebarMenu";
|
||||
import {useRouter} from "next/router";
|
||||
import {useTranslations} from "next-intl";
|
||||
|
||||
const Content = (props) => {
|
||||
const t = useTranslations()
|
||||
const router = useRouter()
|
||||
const [routing, setRouting] = useState(false)
|
||||
const [routingItem, setRoutingItem] = useState({})
|
||||
const pageList = useMemo(() => {
|
||||
const list = []
|
||||
for (const menu of sidebarMenu) {
|
||||
for (const item of menu) {
|
||||
if (item.type === 'menu') {
|
||||
for (const subItem of item.subItem) {
|
||||
list.push(subItem)
|
||||
}
|
||||
} else {
|
||||
list.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const handlerStartRoute = (url) => {
|
||||
setRoutingItem(pageList.find(page => page.route === url))
|
||||
setRouting(true)
|
||||
}
|
||||
const handlerCompleteRoute = () => {
|
||||
setRouting(false)
|
||||
}
|
||||
|
||||
router.events.on('routeChangeStart', handlerStartRoute)
|
||||
router.events.on('routeChangeComplete', handlerCompleteRoute)
|
||||
|
||||
return () => {
|
||||
router.events.off('routeChangeStart', handlerStartRoute)
|
||||
router.events.off('routeChangeComplete', handlerCompleteRoute)
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
return (
|
||||
<FullPageLayout sx={{mt: 3, position: 'relative'}}>
|
||||
<LoadingHardPage icon={routingItem?.icon}
|
||||
label={routingItem?.key ? `${t('routing_to')} ${t(routingItem?.key)}` : ''}
|
||||
loading={routing} width={100} height={100}
|
||||
sx={{position: "absolute", bgcolor: "#fffc"}}>
|
||||
<RolePermissionMiddleware requiredPermissions={props.permissions}>
|
||||
<BreadCrumbs isVisible={true}/>
|
||||
{props.children}
|
||||
</RolePermissionMiddleware>
|
||||
</LoadingHardPage>
|
||||
</FullPageLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default Content
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Divider, List} from "@mui/material";
|
||||
import {Fragment, useEffect, useReducer, useRef, useState} from "react";
|
||||
import {Fragment, useEffect, useReducer, useState} from "react";
|
||||
import SidebarListItem from "./SidebarListItem";
|
||||
import sidebarMenu from "@/core/data/sidebarMenu";
|
||||
import {useRouter} from "next/router";
|
||||
@@ -10,20 +10,41 @@ function reducer(state, action) {
|
||||
case "COLLAPSE_MENU":
|
||||
return state.map((itemsArr) =>
|
||||
itemsArr.map((item) =>
|
||||
action.key === item.key ? { ...item, showSubItem: !item.showSubItem } : item
|
||||
action.key === item.key ? {...item, showSubItem: !item.showSubItem} : item
|
||||
)
|
||||
);
|
||||
case "SELECTED":
|
||||
return state.map((itemsArr) =>
|
||||
itemsArr.map((item) => {
|
||||
return item.type === "page"
|
||||
? { ...item, selected: action.route === item.route }
|
||||
? {...item, selected: action.route === item.route, routing: false}
|
||||
: item.subItem && Array.isArray(item.subItem)
|
||||
? {
|
||||
...item,
|
||||
subItem: item.subItem.map((subitem) => ({
|
||||
...subitem,
|
||||
selected: subitem.route === action.route,
|
||||
routing: false
|
||||
})),
|
||||
showSubItem: item.subItem.some(
|
||||
(subitem) => subitem.selected
|
||||
),
|
||||
}
|
||||
: item;
|
||||
})
|
||||
);
|
||||
case "SELECTING":
|
||||
return state.map((itemsArr) =>
|
||||
itemsArr.map((item) => {
|
||||
return item.type === "page"
|
||||
? {...item, selected: action.route === item.route, routing: action.route === item.route}
|
||||
: item.subItem && Array.isArray(item.subItem)
|
||||
? {
|
||||
...item,
|
||||
subItem: item.subItem.map((subitem) => ({
|
||||
...subitem,
|
||||
selected: subitem.route === action.route,
|
||||
routing: subitem.route === action.route
|
||||
})),
|
||||
showSubItem: item.subItem.some(
|
||||
(subitem) => subitem.selected
|
||||
@@ -46,7 +67,16 @@ export default function SidebarList({handleDrawerToggle}) {
|
||||
useEffect(() => {
|
||||
dispatch({type: "SELECTED", route: router.pathname});
|
||||
setSelectedKey(router.pathname);
|
||||
}, [router.pathname]);
|
||||
const handlerStartRoute = (url) => {
|
||||
dispatch({type: "SELECTING", route: url});
|
||||
}
|
||||
|
||||
router.events.on('routeChangeStart', handlerStartRoute)
|
||||
|
||||
return () => {
|
||||
router.events.off('routeChangeStart', handlerStartRoute)
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
@@ -57,7 +87,7 @@ export default function SidebarList({handleDrawerToggle}) {
|
||||
}, [selectedKey]);
|
||||
|
||||
return (
|
||||
<List sx={{ overflow: "scroll"}}>
|
||||
<List sx={{overflow: "scroll"}}>
|
||||
{itemMenu.map((itemArr, index) => (
|
||||
<Fragment key={index}>
|
||||
{itemArr.map((item) =>
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import {NextLinkComposed} from "@/core/components/LinkRouting";
|
||||
import ExpandLess from "@mui/icons-material/ExpandLess";
|
||||
import ExpandMore from "@mui/icons-material/ExpandMore";
|
||||
import {Badge, IconButton, ListItem, ListItemButton, ListItemIcon, ListItemText, Typography,} from "@mui/material";
|
||||
import {
|
||||
Badge,
|
||||
CircularProgress,
|
||||
IconButton,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {Fragment} from "react";
|
||||
import SidebarListSubItem from "./SidebarListSubItem";
|
||||
@@ -9,7 +18,7 @@ import useNotification from "@/lib/app/hooks/useNotification";
|
||||
|
||||
const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
||||
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 ? (
|
||||
@@ -40,7 +49,7 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
||||
})}
|
||||
onClick={() => {
|
||||
if (hasSubItems) {
|
||||
dispatch({ type: "COLLAPSE_MENU", key: item.key });
|
||||
dispatch({type: "COLLAPSE_MENU", key: item.key});
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
@@ -53,10 +62,13 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
||||
minWidth: 0,
|
||||
justifyContent: "center",
|
||||
color: "primary.main",
|
||||
width: 40,
|
||||
height: 24,
|
||||
pr: 2,
|
||||
}}
|
||||
>
|
||||
{item.icon}
|
||||
{item.routing ?
|
||||
<CircularProgress size={24} color="inherit"/> : item.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t(item.key)}
|
||||
@@ -69,7 +81,7 @@ const SidebarListItem = ({item, dispatch, handleDrawerToggle}) => {
|
||||
}
|
||||
/>
|
||||
|
||||
{hasSubItems && (item.showSubItem ? <ExpandLess /> : <ExpandMore />)}
|
||||
{hasSubItems && (item.showSubItem ? <ExpandLess/> : <ExpandMore/>)}
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
{item.subItem && (
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import {useTranslations} from "next-intl";
|
||||
import useNotification from "@/lib/app/hooks/useNotification";
|
||||
|
||||
const SidebarListSubItem = ({item, handleDrawerToggle }) => {
|
||||
const SidebarListSubItem = ({item, handleDrawerToggle}) => {
|
||||
const t = useTranslations();
|
||||
const {notification_count} = useNotification();
|
||||
const renderBadge = (subitem) => (
|
||||
@@ -50,6 +50,8 @@ const SidebarListSubItem = ({item, handleDrawerToggle }) => {
|
||||
sx={{
|
||||
minWidth: 0,
|
||||
justifyContent: "center",
|
||||
width: 40,
|
||||
height: 24,
|
||||
pr: 2,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,13 +1,31 @@
|
||||
import {Box, Drawer} from "@mui/material";
|
||||
import {Box, Drawer, useMediaQuery} from "@mui/material";
|
||||
import SidebarDrawer from "./SidebarDrawer";
|
||||
import {useTheme} from "@mui/material/styles";
|
||||
|
||||
const Sidebar = (props) => {
|
||||
const theme = useTheme();
|
||||
const isUpSm = useMediaQuery((theme.breakpoints.up('sm')))
|
||||
return (
|
||||
<Box
|
||||
component="nav"
|
||||
sx={{width: {md: props.drawerWidth}, flexShrink: {sm: 0}}}
|
||||
aria-label="mailbox folders"
|
||||
>
|
||||
> {isUpSm ? (
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
display: {xs: "none", md: "block"},
|
||||
"& .MuiDrawer-paper": {
|
||||
boxSizing: "border-box",
|
||||
width: props.drawerWidth,
|
||||
overflow: "hidden",
|
||||
},
|
||||
}}
|
||||
open
|
||||
>
|
||||
<SidebarDrawer handleDrawerToggle={props.handleDrawerToggle}/>
|
||||
</Drawer>
|
||||
) : (
|
||||
<Drawer
|
||||
container={props.container}
|
||||
variant="temporary"
|
||||
@@ -27,20 +45,7 @@ const Sidebar = (props) => {
|
||||
>
|
||||
<SidebarDrawer handleDrawerToggle={props.handleDrawerToggle}/>
|
||||
</Drawer>
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
display: {xs: "none", md: "block"},
|
||||
"& .MuiDrawer-paper": {
|
||||
boxSizing: "border-box",
|
||||
width: props.drawerWidth,
|
||||
overflow: "hidden",
|
||||
},
|
||||
}}
|
||||
open
|
||||
>
|
||||
<SidebarDrawer handleDrawerToggle={props.handleDrawerToggle}/>
|
||||
</Drawer>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import {useState} from "react";
|
||||
import {Toolbar} from "@mui/material";
|
||||
import FullPageLayout from "@/layouts/FullPageLayout";
|
||||
import RolePermissionMiddleware from "@/middlewares/RolePermission";
|
||||
import Header from "@/components/layouts/Dashboard/Header";
|
||||
import Sidebar from "@/components/layouts/Dashboard/Sidebar";
|
||||
import BreadCrumbs from "@/components/layouts/Dashboard/Breadcrumbs";
|
||||
import Content from "@/components/layouts/Dashboard/Content";
|
||||
|
||||
const drawerWidth = 240;
|
||||
|
||||
@@ -17,6 +16,7 @@ const DashboardLayouts = (props) => {
|
||||
const handleDrawerToggle = () => {
|
||||
setMobileOpen(!mobileOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<FullPageLayout direction="row">
|
||||
<Header
|
||||
@@ -34,12 +34,7 @@ const DashboardLayouts = (props) => {
|
||||
sx={{flexGrow: 1, width: {sm: `calc(100% - ${drawerWidth}px)`}}}
|
||||
>
|
||||
<Toolbar/>
|
||||
<FullPageLayout sx={{mt: 3}}>
|
||||
<RolePermissionMiddleware requiredPermissions={props.permissions}>
|
||||
<BreadCrumbs isVisible={true}/>
|
||||
{props.children}
|
||||
</RolePermissionMiddleware>
|
||||
</FullPageLayout>
|
||||
<Content {...props}/>
|
||||
</FullPageLayout>
|
||||
</FullPageLayout>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Backdrop, Box, styled} from "@mui/material";
|
||||
import {Backdrop, Box, Stack, styled, Typography} from "@mui/material";
|
||||
import SvgLoading from "@/core/components/svgs/SvgLoading";
|
||||
|
||||
const LoadingImage = styled(Box)({
|
||||
@@ -9,7 +9,7 @@ const LoadingImage = styled(Box)({
|
||||
},
|
||||
"50%": {
|
||||
// opacity: 1,
|
||||
transform: "scale(2)",
|
||||
transform: "scale(.5)",
|
||||
},
|
||||
"100%": {
|
||||
// opacity: 0,
|
||||
@@ -19,20 +19,29 @@ const LoadingImage = styled(Box)({
|
||||
animation: "load 2s infinite",
|
||||
});
|
||||
|
||||
const LoadingHardPage = ({children, loading}) => {
|
||||
const LoadingHardPage = ({children, loading, sx = {}, icon = null, width = 200, height = 200, label = ''}) => {
|
||||
return (
|
||||
<>
|
||||
<Backdrop
|
||||
sx={{bgcolor: "#fff", zIndex: (theme) => theme.zIndex.drawer + 1}}
|
||||
sx={{bgcolor: "#fff", zIndex: (theme) => theme.zIndex.drawer + 1, ...sx}}
|
||||
open={loading}
|
||||
>
|
||||
<LoadingImage
|
||||
width={100}
|
||||
height={100}
|
||||
>
|
||||
<SvgLoading width={100}
|
||||
height={100}/>
|
||||
</LoadingImage>
|
||||
<Stack alignItems={'center'} spacing={2}>
|
||||
<LoadingImage
|
||||
width={width}
|
||||
height={height}
|
||||
>
|
||||
{icon ? (
|
||||
<Box sx={{color: "primary.main", width: width, height: height}}>
|
||||
{icon}
|
||||
</Box>
|
||||
) : (
|
||||
<SvgLoading width={width}
|
||||
height={height}/>
|
||||
)}
|
||||
</LoadingImage>
|
||||
<Typography variant={'body2'} sx={{color: "primary.main"}}>{label}</Typography>
|
||||
</Stack>
|
||||
</Backdrop>
|
||||
{children}
|
||||
</>
|
||||
|
||||
@@ -20,7 +20,7 @@ const sidebarMenu = [
|
||||
key: "sidebar.dashboard",
|
||||
type: "page",
|
||||
route: "/dashboard",
|
||||
icon: <SpaceDashboardIcon/>,
|
||||
icon: <SpaceDashboardIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "all",
|
||||
},
|
||||
@@ -30,7 +30,7 @@ const sidebarMenu = [
|
||||
name: "passenger_office_chief",
|
||||
type: "page",
|
||||
route: "/dashboard/passenger-office-chief",
|
||||
icon: <AirlineSeatReclineNormalIcon/>,
|
||||
icon: <AirlineSeatReclineNormalIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_passenger_office_navgan",
|
||||
},
|
||||
@@ -39,7 +39,7 @@ const sidebarMenu = [
|
||||
name: "machinery_expert",
|
||||
type: "page",
|
||||
route: "/dashboard/machinery-expert",
|
||||
icon: <DirectionsCarFilledIcon/>,
|
||||
icon: <DirectionsCarFilledIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_machinery_navgan",
|
||||
},
|
||||
@@ -49,7 +49,7 @@ const sidebarMenu = [
|
||||
name: "province_working_group",
|
||||
type: "page",
|
||||
route: "/dashboard/passenger-boss",
|
||||
icon: <AssignmentIndIcon/>,
|
||||
icon: <AssignmentIndIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_province_working_group_navgan",
|
||||
},
|
||||
@@ -59,7 +59,7 @@ const sidebarMenu = [
|
||||
name: "transportation_assistant",
|
||||
type: "page",
|
||||
route: "/dashboard/transportation-assistant",
|
||||
icon: <DirectionsRailwayIcon/>,
|
||||
icon: <DirectionsRailwayIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_transportation_navgan",
|
||||
},
|
||||
@@ -69,7 +69,7 @@ const sidebarMenu = [
|
||||
name: "province_manager_navgan",
|
||||
type: "page",
|
||||
route: "/dashboard/navgan-province-manager",
|
||||
icon: <DesktopWindowsIcon/>,
|
||||
icon: <DesktopWindowsIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_province_affairs_navgan",
|
||||
},
|
||||
@@ -78,7 +78,7 @@ const sidebarMenu = [
|
||||
name: "province_head_expert",
|
||||
type: "page",
|
||||
route: "/dashboard/province-head-expert",
|
||||
icon: <GavelIcon/>,
|
||||
icon: <GavelIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_province_headquarter_refahi",
|
||||
},
|
||||
@@ -87,7 +87,7 @@ const sidebarMenu = [
|
||||
name: "inspector_expert",
|
||||
type: "page",
|
||||
route: "/dashboard/inspector-expert",
|
||||
icon: <GradingIcon/>,
|
||||
icon: <GradingIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_inspector_refahi",
|
||||
},
|
||||
@@ -96,7 +96,7 @@ const sidebarMenu = [
|
||||
name: "commercial_chief",
|
||||
type: "page",
|
||||
route: "/dashboard/commercial-chief",
|
||||
icon: <BusinessCenterIcon/>,
|
||||
icon: <BusinessCenterIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_commercial_refahi",
|
||||
},
|
||||
@@ -105,7 +105,7 @@ const sidebarMenu = [
|
||||
name: "development_assistant",
|
||||
type: "page",
|
||||
route: "/dashboard/development-assistant",
|
||||
icon: <Diversity3Icon/>,
|
||||
icon: <Diversity3Icon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_development_refahi",
|
||||
},
|
||||
@@ -115,7 +115,7 @@ const sidebarMenu = [
|
||||
name: "province_manager_refahi",
|
||||
type: "page",
|
||||
route: "/dashboard/refahi-province-manager",
|
||||
icon: <SupervisedUserCircleIcon/>,
|
||||
icon: <SupervisedUserCircleIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_province_affairs_refahi",
|
||||
},
|
||||
@@ -125,7 +125,7 @@ const sidebarMenu = [
|
||||
name: "refahi_loan_management",
|
||||
type: "page",
|
||||
route: "/dashboard/refahi-loan-management",
|
||||
icon: <PaidIcon/>,
|
||||
icon: <PaidIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_refahi_loan",
|
||||
},
|
||||
@@ -135,7 +135,7 @@ const sidebarMenu = [
|
||||
name: "navgan_loan_management",
|
||||
type: "page",
|
||||
route: "/dashboard/navgan-loan-management",
|
||||
icon: <PaidIcon/>,
|
||||
icon: <PaidIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_navgan_loan",
|
||||
},
|
||||
@@ -144,7 +144,7 @@ const sidebarMenu = [
|
||||
name: "expert_management",
|
||||
type: "page",
|
||||
route: "/dashboard/expert-management",
|
||||
icon: <ManageAccountsIcon/>,
|
||||
icon: <ManageAccountsIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_navgan_loan",
|
||||
},
|
||||
@@ -153,7 +153,7 @@ const sidebarMenu = [
|
||||
name: "user_management",
|
||||
type: "page",
|
||||
route: "/dashboard/user-management",
|
||||
icon: <PersonIcon/>,
|
||||
icon: <PersonIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_users",
|
||||
},
|
||||
@@ -162,7 +162,7 @@ const sidebarMenu = [
|
||||
name: "role_management",
|
||||
type: "page",
|
||||
route: "/dashboard/role-management",
|
||||
icon: <AccessibilityIcon/>,
|
||||
icon: <AccessibilityIcon sx={{width: 'inherit', height: 'inherit'}}/>,
|
||||
selected: false,
|
||||
permission: "manage_roles",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user