initialisation on the doormile express console with astryx
This commit is contained in:
176
src/layout/MainLayout/AppSideNav.js
Normal file
176
src/layout/MainLayout/AppSideNav.js
Normal file
@@ -0,0 +1,176 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { SideNav, SideNavSection, SideNavItem } from '@astryxdesign/core/SideNav';
|
||||
import { Icon } from '@astryxdesign/core/Icon';
|
||||
|
||||
import nearle from 'menu-items/nearle';
|
||||
import { DT } from 'themes/dt/tokens';
|
||||
|
||||
// Thin wrapper around Astryx's SideNav, driven by menu-items/nearle.js.
|
||||
// Pattern (controlled collapse from the parent, section grouping, the CSS
|
||||
// override block for row spacing/selected-state styling) mirrors
|
||||
// doormile_crm/src/layout/MainLayout/Sidebar.jsx — that sibling app's
|
||||
// Astryx sidebar is the validated reference; only the accent colour changes
|
||||
// (brand red DT.brand instead of their navy) and items come from the
|
||||
// existing nearle.js menu config instead of a flat navItems array.
|
||||
// react-router routing works via the app-root LinkProvider (see
|
||||
// src/index.js) — no per-item Link bridging needed.
|
||||
|
||||
const AppSideNav = ({ isCollapsed, onCollapsedChange }) => {
|
||||
const { pathname } = useLocation();
|
||||
const intl = useIntl();
|
||||
|
||||
const renderMenuItem = (item) => {
|
||||
const label = intl.formatMessage({ id: item.id });
|
||||
// Wrap explicitly in Astryx's own <Icon> rather than passing the bare
|
||||
// component and letting SideNavItem's renderIconSlot auto-detect it:
|
||||
// that detection only matches plain functions/forwardRef objects, not
|
||||
// React.memo-wrapped ones (which several @ant-design/icons v5 icons
|
||||
// are) — those fell through and got returned as a raw, uninstantiated
|
||||
// element, crashing with "Objects are not valid as a React child".
|
||||
// Wrapping here always renders through Icon's own component-mode path,
|
||||
// which handles any component type and gives every icon the same
|
||||
// normalised size/colour regardless of source library.
|
||||
const icon = item.icon ? <Icon icon={item.icon} /> : undefined;
|
||||
|
||||
if (item.type === 'collapse') {
|
||||
const isChildSelected = item.children.some((child) => pathname.startsWith(child.url));
|
||||
return (
|
||||
<SideNavItem key={item.id} label={label} icon={icon} collapsible={{ defaultIsCollapsed: !isChildSelected }} isSelected={isChildSelected}>
|
||||
{item.children.map(renderMenuItem)}
|
||||
</SideNavItem>
|
||||
);
|
||||
}
|
||||
|
||||
return <SideNavItem key={item.id} label={label} icon={icon} href={item.url} isSelected={pathname.startsWith(item.url)} />;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SideNav
|
||||
className="doormile-side-nav"
|
||||
collapsible={{ isCollapsed, onCollapsedChange, buttonLabel: 'Collapse navigation' }}
|
||||
style={{
|
||||
backgroundColor: DT.surface,
|
||||
borderRight: `1px solid ${DT.borderSubtle}`,
|
||||
boxShadow: '1px 0 3px rgba(15, 23, 42, 0.03)',
|
||||
paddingBlock: '12px',
|
||||
paddingInline: '8px',
|
||||
boxSizing: 'border-box',
|
||||
'--spacing-12': '72px',
|
||||
// Pages with tall/independently-scrolling content (e.g. deliveries'
|
||||
// internal TableContainer scroll region) still let the document
|
||||
// scroll past the header, so pin the nav explicitly rather than
|
||||
// relying only on AppShell's own auto-mode sticky wrapper.
|
||||
position: 'sticky',
|
||||
top: 'var(--appshell-header-height, 0px)',
|
||||
height: 'calc(100dvh - var(--appshell-header-height, 0px))',
|
||||
overflowY: 'auto'
|
||||
}}
|
||||
>
|
||||
<SideNavSection title="Doormile">{nearle.children.map(renderMenuItem)}</SideNavSection>
|
||||
</SideNav>
|
||||
<style>{`
|
||||
.doormile-side-nav .astryx-side-nav-section > div:last-child {
|
||||
gap: 6px !important;
|
||||
}
|
||||
|
||||
.doormile-side-nav .astryx-side-nav-item[aria-label] {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-inline: auto;
|
||||
padding: 0 !important;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item[aria-label] > * {
|
||||
margin: 0 !important;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item[aria-label] .astryx-icon {
|
||||
width: 18px !important;
|
||||
height: 18px !important;
|
||||
margin: 0 !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item[aria-label]:hover {
|
||||
background-color: ${DT.brand}14 !important;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item[aria-label]:focus-visible {
|
||||
outline: 2px solid ${DT.brand}66;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item[aria-label][data-selected='selected'] {
|
||||
background-color: ${DT.brand}1f !important;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item[aria-label][data-selected='selected'] .astryx-icon {
|
||||
color: ${DT.brand} !important;
|
||||
}
|
||||
|
||||
.doormile-side-nav .astryx-side-nav-item:not([aria-label]) {
|
||||
position: relative;
|
||||
margin-inline: 2px;
|
||||
height: auto;
|
||||
padding-block: 12px !important;
|
||||
transition: background-color 0.15s ease, transform 0.15s ease;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item:not([aria-label])::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -2px;
|
||||
top: 12px;
|
||||
bottom: 12px;
|
||||
width: 3px;
|
||||
border-radius: 3px;
|
||||
background-color: ${DT.brand};
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item:not([aria-label]):hover {
|
||||
background-color: ${DT.brand}0d !important;
|
||||
transform: translateX(2px);
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item:not([aria-label]):focus-visible {
|
||||
outline: 2px solid ${DT.brand}66;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item:not([aria-label])[data-selected='selected'] {
|
||||
background-color: ${DT.brand}14 !important;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item:not([aria-label])[data-selected='selected']::before {
|
||||
opacity: 1;
|
||||
}
|
||||
.doormile-side-nav .astryx-side-nav-item:not([aria-label])[data-selected='selected'] .astryx-icon {
|
||||
color: ${DT.brand} !important;
|
||||
}
|
||||
|
||||
.doormile-side-nav > div:last-child {
|
||||
padding-block: 8px !important;
|
||||
}
|
||||
|
||||
.doormile-side-nav button[aria-label*="sidebar"],
|
||||
.doormile-side-nav button[aria-label*="navigation"] {
|
||||
border-radius: 50% !important;
|
||||
transition: background-color 0.15s ease !important;
|
||||
}
|
||||
.doormile-side-nav button[aria-label*="sidebar"]:hover,
|
||||
.doormile-side-nav button[aria-label*="navigation"]:hover {
|
||||
background-color: ${DT.brand}14 !important;
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
AppSideNav.propTypes = {
|
||||
isCollapsed: PropTypes.bool.isRequired,
|
||||
onCollapsedChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AppSideNav;
|
||||
199
src/layout/MainLayout/AppTopNav.js
Normal file
199
src/layout/MainLayout/AppTopNav.js
Normal file
@@ -0,0 +1,199 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { TopNav } from '@astryxdesign/core/TopNav';
|
||||
import { TopNavHeading } from '@astryxdesign/core/TopNav';
|
||||
import { DropdownMenu } from '@astryxdesign/core/DropdownMenu';
|
||||
import { Popover } from '@astryxdesign/core/Popover';
|
||||
import { IconButton } from '@astryxdesign/core/IconButton';
|
||||
import { Avatar } from '@astryxdesign/core/Avatar';
|
||||
import { HStack } from '@astryxdesign/core/HStack';
|
||||
import { VStack } from '@astryxdesign/core/VStack';
|
||||
import { Text } from '@astryxdesign/core/Text';
|
||||
import { Heading } from '@astryxdesign/core/Heading';
|
||||
import { Divider } from '@astryxdesign/core/Divider';
|
||||
|
||||
import { TbBoxMultiple1 } from 'react-icons/tb';
|
||||
import { GrMultiple } from 'react-icons/gr';
|
||||
import { BellOutlined, WindowsOutlined, EditOutlined, CommentOutlined, LogoutOutlined, GiftOutlined, MessageOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
|
||||
import avatar1 from 'assets/images/users/avatar-1.png';
|
||||
import logo from 'assets/images/doormile-logo.png';
|
||||
import navbarMark from 'assets/images/doormile-mark.png';
|
||||
import { clearFcmToken } from 'store/reducers/fcmSlice';
|
||||
import { logoutUser } from 'store/reducers/loginUserSlice';
|
||||
import { performSessionLogout } from 'utils/session';
|
||||
import { DT } from 'themes/dt/tokens';
|
||||
|
||||
// doormile-logo.png is a white asset; recolour to brand red for this
|
||||
// light TopNav surface (same trick login.js uses for its white-card logo).
|
||||
const logoStyle = {
|
||||
height: 24,
|
||||
width: 'auto',
|
||||
filter: 'brightness(0) saturate(100%) invert(15%) sepia(93%) saturate(5437%) hue-rotate(346deg) brightness(81%) contrast(92%)'
|
||||
};
|
||||
|
||||
// Collapsed rail: doormile-mark.png (red-on-white disc) needs a white
|
||||
// backing + scale(1.4) crop to fill its circle cleanly — same composition
|
||||
// the old DrawerHeader used, just sized for the nav-bar row instead of the
|
||||
// full-height sidebar rail.
|
||||
const markWrapperStyle = {
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: '50%',
|
||||
background: '#fff',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
overflow: 'hidden',
|
||||
flexShrink: 0
|
||||
};
|
||||
|
||||
const markStyle = {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
transform: 'scale(1.4)',
|
||||
display: 'block'
|
||||
};
|
||||
|
||||
const NotificationPanel = () => (
|
||||
<VStack gap={0} padding={0} width={320}>
|
||||
<HStack justify="between" vAlign="center" padding={2}>
|
||||
<Heading level={5}>Notifications</Heading>
|
||||
</HStack>
|
||||
<Divider />
|
||||
<VStack gap={0} padding={0}>
|
||||
{[
|
||||
{ icon: <GiftOutlined />, text: "It's Cristina danny's birthday today.", time: '2 min ago' },
|
||||
{ icon: <MessageOutlined />, text: 'Aida Burg commented your post.', time: '5 August' },
|
||||
{ icon: <SettingOutlined />, text: 'Your profile is 60% complete.', time: '7 hours ago' }
|
||||
].map((n) => (
|
||||
<HStack key={n.text} gap={1.5} vAlign="center" padding={2}>
|
||||
<Avatar name={n.text} size="sm" />
|
||||
<VStack gap={0} padding={0}>
|
||||
<Text type="body">{n.text}</Text>
|
||||
<Text type="supporting">{n.time}</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
))}
|
||||
</VStack>
|
||||
<Divider />
|
||||
<HStack justify="center" padding={1.5}>
|
||||
<Text type="label" color="accent">
|
||||
View all
|
||||
</Text>
|
||||
</HStack>
|
||||
</VStack>
|
||||
);
|
||||
|
||||
// ==============================|| MAIN LAYOUT - TOP NAV ||============================== //
|
||||
|
||||
const AppTopNav = ({ isSidebarCollapsed }) => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
const topNavRef = useRef(null);
|
||||
const [headerHeight, setHeaderHeight] = useState(null);
|
||||
|
||||
const firstname = localStorage.getItem('firstname') || '';
|
||||
|
||||
const handleLogout = () => {
|
||||
performSessionLogout({ queryClient, dispatch, clearFcmToken, logoutUser });
|
||||
};
|
||||
|
||||
// AppShell (height="auto") pins the sticky side nav below the header using
|
||||
// a --appshell-header-height CSS var it measures itself via ResizeObserver
|
||||
// (AppShell.tsx). On some routes that measurement lags/settles wrong, so
|
||||
// the side nav's sticky offset is off and its bottom-anchored collapse
|
||||
// button visibly jumps on scroll. Re-measure the header independently here
|
||||
// and force the same variable with !important on the shell root — an
|
||||
// author-stylesheet !important rule beats AppShell's own non-important
|
||||
// inline style.setProperty() call on that same element, so this always
|
||||
// wins regardless of what the internal measurement produced.
|
||||
useEffect(() => {
|
||||
const el = topNavRef.current;
|
||||
if (!el) return undefined;
|
||||
|
||||
const updateHeight = () => setHeaderHeight(el.getBoundingClientRect().height);
|
||||
updateHeight();
|
||||
|
||||
const observer = new ResizeObserver(updateHeight);
|
||||
observer.observe(el);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TopNav
|
||||
ref={topNavRef}
|
||||
label="Doormile Express"
|
||||
style={{
|
||||
backgroundColor: DT.surface,
|
||||
borderBottom: `1px solid ${DT.borderSubtle}`,
|
||||
boxShadow: DT.shadowMd
|
||||
}}
|
||||
heading={
|
||||
<TopNavHeading
|
||||
logo={
|
||||
isSidebarCollapsed ? (
|
||||
<HStack gap={1} vAlign="center" padding={0}>
|
||||
<span style={markWrapperStyle}>
|
||||
<img src={navbarMark} alt="" style={markStyle} />
|
||||
</span>
|
||||
<img src={logo} alt="Doormile Express" style={logoStyle} />
|
||||
</HStack>
|
||||
) : (
|
||||
<img src={logo} alt="Doormile Express" style={logoStyle} />
|
||||
)
|
||||
}
|
||||
headingHref="/doormile/dispatch"
|
||||
/>
|
||||
}
|
||||
endContent={
|
||||
<HStack gap={1} vAlign="center" padding={0}>
|
||||
<DropdownMenu
|
||||
hasChevron={false}
|
||||
button={{ label: 'Quick create', icon: <WindowsOutlined />, isIconOnly: true, variant: 'ghost' }}
|
||||
items={[
|
||||
{ label: 'Create Order', icon: <TbBoxMultiple1 />, onClick: () => navigate('/doormile/orders/create') },
|
||||
{ label: 'Create Multiple Order', icon: <GrMultiple />, onClick: () => navigate('/doormile/orders/createorders') }
|
||||
]}
|
||||
/>
|
||||
|
||||
<Popover placement="below" alignment="end" content={<NotificationPanel />} label="Notifications">
|
||||
<IconButton label="Notifications" tooltip="Notifications" variant="ghost" icon={<BellOutlined />} />
|
||||
</Popover>
|
||||
|
||||
<DropdownMenu
|
||||
hasChevron={false}
|
||||
button={{ label: firstname || 'Profile', icon: <Avatar src={avatar1} name={firstname} size="xsm" tooltip={false} />, variant: 'ghost' }}
|
||||
items={[
|
||||
{ label: 'View Profile', icon: <EditOutlined />, onClick: () => navigate('/viewprofile') },
|
||||
{ label: 'Support Ticket', icon: <CommentOutlined /> },
|
||||
{ type: 'divider' },
|
||||
{ label: 'Logout', icon: <LogoutOutlined />, onClick: handleLogout }
|
||||
]}
|
||||
/>
|
||||
</HStack>
|
||||
}
|
||||
/>
|
||||
{headerHeight != null && (
|
||||
<style>{`
|
||||
.astryx-app-shell {
|
||||
--appshell-header-height: ${headerHeight}px !important;
|
||||
}
|
||||
`}</style>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
AppTopNav.propTypes = {
|
||||
isSidebarCollapsed: PropTypes.bool
|
||||
};
|
||||
|
||||
export default AppTopNav;
|
||||
@@ -1,32 +0,0 @@
|
||||
// material-ui
|
||||
import { Button, Link, CardMedia, Stack, Typography } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
|
||||
// assets
|
||||
import avatar from 'assets/images/users/avatar-group.png';
|
||||
import AnimateButton from 'components/@extended/AnimateButton';
|
||||
|
||||
// ==============================|| DRAWER CONTENT - NAVIGATION CARD ||============================== //
|
||||
|
||||
const NavCard = () => (
|
||||
<MainCard sx={{ bgcolor: 'grey.50', m: 3 }}>
|
||||
<Stack alignItems="center" spacing={2.5}>
|
||||
<CardMedia component="img" image={avatar} />
|
||||
<Stack alignItems="center">
|
||||
<Typography variant="h5">Help?</Typography>
|
||||
<Typography variant="h6" color="secondary">
|
||||
Get to resolve query
|
||||
</Typography>
|
||||
</Stack>
|
||||
<AnimateButton>
|
||||
<Button variant="shadow" size="small" component={Link} href="https://codedthemes.support-hub.io/" target="_blank">
|
||||
Support
|
||||
</Button>
|
||||
</AnimateButton>
|
||||
</Stack>
|
||||
</MainCard>
|
||||
);
|
||||
|
||||
export default NavCard;
|
||||
@@ -1,503 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Box,
|
||||
Collapse,
|
||||
ClickAwayListener,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Popper,
|
||||
Typography,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
|
||||
// project import
|
||||
import NavItem from './NavItem';
|
||||
import Dot from 'components/@extended/Dot';
|
||||
import SimpleBar from 'components/third-party/SimpleBar';
|
||||
import Transitions from 'components/@extended/Transitions';
|
||||
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import { dispatch, useSelector } from 'store';
|
||||
import { activeItem } from 'store/reducers/menu';
|
||||
import { MenuOrientation, ThemeMode } from 'config';
|
||||
|
||||
// assets
|
||||
import { BorderOutlined, DownOutlined, UpOutlined, RightOutlined } from '@ant-design/icons';
|
||||
|
||||
// mini-menu - wrapper
|
||||
const PopperStyled = styled(Popper)(({ theme }) => ({
|
||||
overflow: 'visible',
|
||||
zIndex: 1202,
|
||||
minWidth: 180,
|
||||
'&:before': {
|
||||
content: '""',
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
top: 38,
|
||||
left: -5,
|
||||
width: 10,
|
||||
height: 10,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
transform: 'translateY(-50%) rotate(45deg)',
|
||||
zIndex: 120,
|
||||
borderLeft: `1px solid ${theme.palette.grey.A800}`,
|
||||
borderBottom: `1px solid ${theme.palette.grey.A800}`
|
||||
}
|
||||
}));
|
||||
|
||||
// ==============================|| NAVIGATION - LIST COLLAPSE ||============================== //
|
||||
|
||||
const NavCollapse = ({ menu, level, parentId, setSelectedItems, selectedItems, setSelectedLevel, selectedLevel }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const downLG = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
const menuState = useSelector((state) => state.menu);
|
||||
|
||||
const { drawerOpen } = menuState;
|
||||
const { menuOrientation } = useConfig();
|
||||
const navigation = useNavigate();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selected, setSelected] = useState(null);
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(null);
|
||||
setSelectedLevel(level);
|
||||
if (drawerOpen) {
|
||||
setOpen(!open);
|
||||
setSelected(!selected ? menu.id : null);
|
||||
setSelectedItems(!selected ? menu.id : '');
|
||||
if (menu.url) navigation(`${menu.url}`);
|
||||
} else {
|
||||
setAnchorEl(event?.currentTarget);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerIconLink = () => {
|
||||
if (!drawerOpen) {
|
||||
if (menu.url) navigation(`${menu.url}`);
|
||||
setSelected(menu.id);
|
||||
}
|
||||
};
|
||||
|
||||
const handleHover = (event) => {
|
||||
setAnchorEl(event?.currentTarget);
|
||||
if (!drawerOpen) {
|
||||
setSelected(menu.id);
|
||||
}
|
||||
};
|
||||
|
||||
const miniMenuOpened = Boolean(anchorEl);
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
if (!miniMenuOpened) {
|
||||
if (!menu.url) {
|
||||
setSelected(null);
|
||||
}
|
||||
}
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
useMemo(() => {
|
||||
if (selected === selectedItems) {
|
||||
if (level === 1) {
|
||||
setOpen(true);
|
||||
}
|
||||
} else {
|
||||
if (level === selectedLevel) {
|
||||
setOpen(false);
|
||||
if (!miniMenuOpened && !drawerOpen && !selected) {
|
||||
setSelected(null);
|
||||
}
|
||||
if (drawerOpen) {
|
||||
setSelected(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [selectedItems, level, selected, miniMenuOpened, drawerOpen, selectedLevel]);
|
||||
|
||||
const { pathname } = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
if (pathname === menu.url) {
|
||||
setSelected(menu.id);
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [pathname]);
|
||||
|
||||
const checkOpenForParent = (child, id) => {
|
||||
child.forEach((item) => {
|
||||
if (item.url === pathname) {
|
||||
setOpen(true);
|
||||
setSelected(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setOpen(false);
|
||||
if (!miniMenuOpened) {
|
||||
setSelected(null);
|
||||
}
|
||||
if (miniMenuOpened) setAnchorEl(null);
|
||||
if (menu.children) {
|
||||
menu.children.forEach((item) => {
|
||||
if (item.children?.length) {
|
||||
checkOpenForParent(item.children, menu.id);
|
||||
}
|
||||
if (pathname && pathname.includes('product-details')) {
|
||||
if (item.url && item.url.includes('product-details')) {
|
||||
setSelected(menu.id);
|
||||
setOpen(true);
|
||||
}
|
||||
}
|
||||
if (item.url === pathname) {
|
||||
setSelected(menu.id);
|
||||
setOpen(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname, menu.children]);
|
||||
|
||||
useEffect(() => {
|
||||
if (menu.url === pathname) {
|
||||
dispatch(activeItem({ openItem: [menu.id] }));
|
||||
setSelected(menu.id);
|
||||
setAnchorEl(null);
|
||||
setOpen(true);
|
||||
}
|
||||
}, [pathname, menu]);
|
||||
|
||||
const navCollapse = menu.children?.map((item) => {
|
||||
switch (item.type) {
|
||||
case 'collapse':
|
||||
return (
|
||||
<NavCollapse
|
||||
key={item.id}
|
||||
setSelectedItems={setSelectedItems}
|
||||
setSelectedLevel={setSelectedLevel}
|
||||
selectedLevel={selectedLevel}
|
||||
selectedItems={selectedItems}
|
||||
menu={item}
|
||||
level={level + 1}
|
||||
parentId={parentId}
|
||||
/>
|
||||
);
|
||||
case 'item':
|
||||
return <NavItem key={item.id} item={item} level={level + 1} />;
|
||||
default:
|
||||
return (
|
||||
<Typography key={item.id} variant="h6" color="error" align="center">
|
||||
Fix - Collapse or Item
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const isSelected = selected === menu.id;
|
||||
const borderIcon = level === 1 ? <BorderOutlined style={{ fontSize: '1rem' }} /> : false;
|
||||
const Icon = menu.icon;
|
||||
const menuIcon = menu.icon ? <Icon style={{ fontSize: drawerOpen ? '1rem' : '1.25rem', color: 'white' }} /> : borderIcon;
|
||||
// const textColor = theme.palette.mode === ThemeMode.DARK ? 'grey.400' : 'text.primary';
|
||||
// const iconSelectedColor = theme.palette.mode === ThemeMode.DARK && drawerOpen ? theme.palette.text.primary : theme.palette.primary.main;
|
||||
const popperId = miniMenuOpened ? `collapse-pop-${menu.id}` : undefined;
|
||||
const FlexBox = { display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' };
|
||||
const textColor = 'white';
|
||||
const iconSelectedColor = 'white';
|
||||
// const isSelected = true;
|
||||
|
||||
return (
|
||||
<>
|
||||
{menuOrientation === MenuOrientation.VERTICAL || downLG ? (
|
||||
<>
|
||||
<ListItemButton
|
||||
disableRipple
|
||||
selected={selected === menu.id}
|
||||
{...(!drawerOpen && { onMouseEnter: handleClick, onMouseLeave: handleClose })}
|
||||
onClick={handleClick}
|
||||
sx={{
|
||||
pl: drawerOpen ? `${level * 28}px` : 1.5,
|
||||
py: !drawerOpen && level === 1 ? 1.25 : 1,
|
||||
|
||||
...(drawerOpen && {
|
||||
'&:hover': {
|
||||
// bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'primary.lighter'
|
||||
bgcolor: '#7b1fa2'
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
bgcolor: 'transparent',
|
||||
color: iconSelectedColor,
|
||||
'&:hover': { color: iconSelectedColor, bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'transparent' }
|
||||
}
|
||||
}),
|
||||
...(!drawerOpen && {
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
// bgcolor:'#7b1fa2'
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
},
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
{menuIcon && (
|
||||
<ListItemIcon
|
||||
onClick={handlerIconLink}
|
||||
sx={{
|
||||
minWidth: 28,
|
||||
// color: selected === menu.id ? 'primary.main' : textColor,
|
||||
// color: selected === menu.id ? textColor : textColor,
|
||||
// bgcolor:'white',
|
||||
// color:'white',
|
||||
...(!drawerOpen && {
|
||||
borderRadius: 1.5,
|
||||
width: 36,
|
||||
height: 36,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
'&:hover': {
|
||||
// bgcolor: theme.palette.mode === ThemeMode.DARK ? 'secondary.light' : 'secondary.lighter'
|
||||
bgcolor: '#7b1fa2',
|
||||
color: 'white'
|
||||
}
|
||||
}),
|
||||
...(!drawerOpen &&
|
||||
selected === menu.id && {
|
||||
bgcolor: 'primary.light',
|
||||
color: 'primary.main',
|
||||
'&:hover': {
|
||||
bgcolor: '#7b1fa2',
|
||||
color: 'primary.main'
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
{menuIcon}
|
||||
</ListItemIcon>
|
||||
)}
|
||||
{(drawerOpen || (!drawerOpen && level !== 1)) && (
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography
|
||||
variant="h6"
|
||||
// color={selected === menu.id ? 'primary' : textColor}
|
||||
// color={'white'}
|
||||
color={selected === menu.id ? textColor : textColor}
|
||||
>
|
||||
{menu.title}
|
||||
</Typography>
|
||||
}
|
||||
secondary={
|
||||
menu.caption && (
|
||||
<Typography variant="caption" color="secondary">
|
||||
{menu.caption}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{(drawerOpen || (!drawerOpen && level !== 1)) &&
|
||||
(miniMenuOpened || open ? (
|
||||
<UpOutlined
|
||||
style={{
|
||||
fontSize: '0.625rem',
|
||||
marginLeft: 1,
|
||||
// color: theme.palette.primary.main
|
||||
color: 'white'
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<DownOutlined
|
||||
style={{
|
||||
fontSize: '0.625rem',
|
||||
marginLeft: 1,
|
||||
color: 'white'
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{!drawerOpen && (
|
||||
<PopperStyled
|
||||
open={miniMenuOpened}
|
||||
anchorEl={anchorEl}
|
||||
placement="right-start"
|
||||
style={{
|
||||
zIndex: 2001
|
||||
}}
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [-12, 1]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Transitions in={miniMenuOpened} {...TransitionProps}>
|
||||
<Paper
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
mt: 1.5,
|
||||
boxShadow: theme.customShadows.z1,
|
||||
backgroundImage: 'none',
|
||||
border: `2px solid ${theme.palette.primary.main}`,
|
||||
width: 'auto'
|
||||
}}
|
||||
>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<SimpleBar
|
||||
sx={{
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'auto',
|
||||
maxHeight: 'calc(100vh - 170px)'
|
||||
}}
|
||||
>
|
||||
{navCollapse}
|
||||
</SimpleBar>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Transitions>
|
||||
)}
|
||||
</PopperStyled>
|
||||
)}
|
||||
</ListItemButton>
|
||||
{drawerOpen && (
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<List sx={{ p: 0 }}>{navCollapse}</List>
|
||||
</Collapse>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ListItemButton
|
||||
id={`boundary-${popperId}`}
|
||||
disableRipple
|
||||
selected={isSelected}
|
||||
onMouseEnter={handleHover}
|
||||
onMouseLeave={handleClose}
|
||||
onClick={handleHover}
|
||||
aria-describedby={popperId}
|
||||
sx={{
|
||||
'&.Mui-selected': {
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box onClick={handlerIconLink} sx={FlexBox}>
|
||||
{menuIcon && (
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
my: 'auto',
|
||||
minWidth: !menu.icon ? 18 : 36
|
||||
// color: theme.palette.secondary.dark
|
||||
// color:'white'
|
||||
}}
|
||||
>
|
||||
{menuIcon}
|
||||
</ListItemIcon>
|
||||
)}
|
||||
{!menuIcon && level !== 1 && (
|
||||
<ListItemIcon
|
||||
sx={{ my: 'auto', minWidth: !menu.icon ? 18 : 36, bgcolor: 'transparent', '&:hover': { bgcolor: 'transparent' } }}
|
||||
>
|
||||
<Dot size={4} color={isSelected ? 'primary' : 'secondary'} />
|
||||
</ListItemIcon>
|
||||
)}
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography
|
||||
variant="body1"
|
||||
// color="inherit"
|
||||
// color="white"
|
||||
sx={{ my: 'auto' }}
|
||||
>
|
||||
{menu.title}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{miniMenuOpened ? <RightOutlined /> : <DownOutlined />}
|
||||
</Box>
|
||||
|
||||
{anchorEl && (
|
||||
<PopperStyled
|
||||
id={popperId}
|
||||
open={miniMenuOpened}
|
||||
anchorEl={anchorEl}
|
||||
placement="right-start"
|
||||
style={{
|
||||
zIndex: 2001
|
||||
}}
|
||||
modifiers={[
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [-10, 0]
|
||||
}
|
||||
}
|
||||
]}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Transitions in={miniMenuOpened} {...TransitionProps}>
|
||||
<Paper
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
mt: 1.5,
|
||||
py: 0.5,
|
||||
boxShadow: theme.shadows[8],
|
||||
backgroundImage: 'none'
|
||||
}}
|
||||
>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<SimpleBar
|
||||
sx={{
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'auto',
|
||||
maxHeight: 'calc(100vh - 170px)'
|
||||
}}
|
||||
>
|
||||
{navCollapse}
|
||||
</SimpleBar>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Transitions>
|
||||
)}
|
||||
</PopperStyled>
|
||||
)}
|
||||
</ListItemButton>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
NavCollapse.propTypes = {
|
||||
menu: PropTypes.object,
|
||||
level: PropTypes.number,
|
||||
parentId: PropTypes.string,
|
||||
setSelectedItems: PropTypes.func,
|
||||
selectedItems: PropTypes.string,
|
||||
setSelectedLevel: PropTypes.func,
|
||||
selectedLevel: PropTypes.number
|
||||
};
|
||||
|
||||
export default NavCollapse;
|
||||
@@ -1,343 +0,0 @@
|
||||
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 } 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"
|
||||
sx={{ color: '#fff' }}
|
||||
>
|
||||
{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;
|
||||
@@ -1,294 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { forwardRef, useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Avatar, Chip, ListItemButton, ListItemIcon, ListItemText, Tooltip, Typography, useMediaQuery } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import Dot from 'components/@extended/Dot';
|
||||
|
||||
import { MenuOrientation, ThemeMode } from 'config';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
// import { dispatch, useSelector } from 'store';
|
||||
import { activeItem, openDrawer, setSelectedMenu } from 'store/reducers/menu';
|
||||
|
||||
// ==============================|| NAVIGATION - LIST ITEM ||============================== //
|
||||
|
||||
const NavItem = ({ item, level }) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { menuOrientation } = useConfig();
|
||||
const { drawerOpen, openItem } = useSelector((state) => state.menu);
|
||||
|
||||
const downLG = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
let itemTarget = '_self';
|
||||
if (item.target) {
|
||||
itemTarget = '_blank';
|
||||
}
|
||||
|
||||
let listItemProps = { component: forwardRef((props, ref) => <Link {...props} to={item.url} target={itemTarget} ref={ref} />) };
|
||||
if (item?.external) {
|
||||
listItemProps = { component: 'a', href: item.url, target: itemTarget };
|
||||
}
|
||||
|
||||
const Icon = item.icon;
|
||||
|
||||
const isSelected = openItem.findIndex((id) => id === item.id) > -1;
|
||||
|
||||
const itemIcon = item.icon ? (
|
||||
<Icon style={{ fontSize: drawerOpen ? '1rem' : '1.25rem', color: isSelected ? '#662582' : '#fff' }} />
|
||||
) : (
|
||||
false
|
||||
);
|
||||
|
||||
// const { pathname } = useLocation();
|
||||
const pathname = document.location.pathname;
|
||||
|
||||
// active menu item on page load
|
||||
useEffect(() => {
|
||||
if (pathname && pathname.includes('product-details')) {
|
||||
if (item.url && item.url.includes('product-details')) {
|
||||
dispatch(activeItem({ openItem: [item.id] }));
|
||||
}
|
||||
}
|
||||
|
||||
if (pathname && pathname.includes('kanban')) {
|
||||
if (item.url && item.url.includes('kanban')) {
|
||||
dispatch(activeItem({ openItem: [item.id] }));
|
||||
}
|
||||
}
|
||||
|
||||
if (pathname.includes(item.url)) {
|
||||
dispatch(activeItem({ openItem: [item.id] }));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
}, [pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setSelectedMenu(pathname));
|
||||
}, [pathname]);
|
||||
|
||||
const textColor = theme.palette.mode === ThemeMode.DARK ? 'grey.400' : '#fff';
|
||||
const iconSelectedColor = theme.palette.mode === ThemeMode.DARK && drawerOpen ? 'text.primary' : 'primary.main';
|
||||
|
||||
return (
|
||||
<>
|
||||
{menuOrientation === MenuOrientation.VERTICAL || downLG ? (
|
||||
<Tooltip
|
||||
title={!drawerOpen && level === 1 ? item.title : ''}
|
||||
placement="right"
|
||||
arrow
|
||||
disableInteractive
|
||||
componentsProps={{
|
||||
tooltip: { sx: { bgcolor: '#0f172a', fontSize: 12, fontWeight: 600, px: 1.25, py: 0.75, borderRadius: 1.5 } },
|
||||
arrow: { sx: { color: '#0f172a' } }
|
||||
}}
|
||||
>
|
||||
<ListItemButton
|
||||
{...listItemProps}
|
||||
disabled={item.disabled}
|
||||
selected={isSelected}
|
||||
onClick={() => {
|
||||
// dispatch(setSelectedMenu(item));
|
||||
}}
|
||||
sx={{
|
||||
zIndex: 1201,
|
||||
pl: drawerOpen ? `${level * 28}px` : 1.5,
|
||||
py: !drawerOpen && level === 1 ? 1.25 : 1,
|
||||
...(drawerOpen && {
|
||||
'&:hover': {
|
||||
bgcolor: '#7b1fa2'
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'primary.lighter',
|
||||
borderRight: `2px solid ${theme.palette.primary.main}`,
|
||||
color: iconSelectedColor,
|
||||
'&:hover': {
|
||||
color: iconSelectedColor,
|
||||
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'primary.lighter'
|
||||
}
|
||||
}
|
||||
}),
|
||||
...(!drawerOpen && {
|
||||
bgcolor: '#662582',
|
||||
'&:hover': {
|
||||
bgcolor: '#662582'
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
},
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
})
|
||||
}}
|
||||
{...(downLG && {
|
||||
onClick: () => {
|
||||
dispatch(openDrawer(false));
|
||||
}
|
||||
})}
|
||||
>
|
||||
{itemIcon && (
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
minWidth: 28,
|
||||
...(!drawerOpen && {
|
||||
borderRadius: 1.5,
|
||||
width: 36,
|
||||
height: 36,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
'&:hover': {
|
||||
bgcolor: '#7b1fa2'
|
||||
}
|
||||
}),
|
||||
...(!drawerOpen &&
|
||||
isSelected && {
|
||||
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'primary.900' : 'primary.lighter',
|
||||
'&:hover': {
|
||||
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'primary.darker' : 'primary.lighter'
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
{itemIcon}
|
||||
</ListItemIcon>
|
||||
)}
|
||||
{(drawerOpen || (!drawerOpen && level !== 1)) && (
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6" sx={{ color: isSelected ? iconSelectedColor : textColor, whiteSpace: 'nowrap' }}>
|
||||
{item.title}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{(drawerOpen || (!drawerOpen && level !== 1)) && item.chip && (
|
||||
<Chip
|
||||
color={item.chip.color}
|
||||
variant={item.chip.variant}
|
||||
size={item.chip.size}
|
||||
label={item.chip.label}
|
||||
avatar={item.chip.avatar && <Avatar>{item.chip.avatar}</Avatar>}
|
||||
/>
|
||||
)}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<ListItemButton
|
||||
{...listItemProps}
|
||||
disabled={item.disabled}
|
||||
selected={isSelected}
|
||||
sx={{
|
||||
zIndex: 1201,
|
||||
...(drawerOpen && {
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
bgcolor: 'transparent',
|
||||
color: iconSelectedColor,
|
||||
'&:hover': {
|
||||
color: iconSelectedColor,
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
}
|
||||
}),
|
||||
...(!drawerOpen && {
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
},
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
{itemIcon && (
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
minWidth: 36,
|
||||
...(!drawerOpen && {
|
||||
borderRadius: 1.5,
|
||||
width: 36,
|
||||
height: 36,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
}),
|
||||
...(!drawerOpen &&
|
||||
isSelected && {
|
||||
bgcolor: 'transparent',
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
{itemIcon}
|
||||
</ListItemIcon>
|
||||
)}
|
||||
|
||||
{!itemIcon && (
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
color: isSelected ? 'primary.main' : 'secondary.main',
|
||||
...(!drawerOpen && {
|
||||
borderRadius: 1.5,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
}),
|
||||
...(!drawerOpen &&
|
||||
isSelected && {
|
||||
bgcolor: 'transparent',
|
||||
'&:hover': {
|
||||
bgcolor: 'transparent'
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Dot size={4} color={isSelected ? 'primary' : 'secondary'} />
|
||||
</ListItemIcon>
|
||||
)}
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6" color="inherit">
|
||||
{item.title}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{(drawerOpen || (!drawerOpen && level !== 1)) && item.chip && (
|
||||
<Chip
|
||||
color={item.chip.color}
|
||||
variant={item.chip.variant}
|
||||
size={item.chip.size}
|
||||
label={item.chip.label}
|
||||
avatar={item.chip.avatar && <Avatar>{item.chip.avatar}</Avatar>}
|
||||
/>
|
||||
)}
|
||||
</ListItemButton>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
NavItem.propTypes = {
|
||||
item: PropTypes.object,
|
||||
level: PropTypes.number
|
||||
};
|
||||
|
||||
export default NavItem;
|
||||
@@ -1,111 +0,0 @@
|
||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Box, Typography, useMediaQuery } from '@mui/material';
|
||||
import { Menu } from 'menu-items/dashboard';
|
||||
|
||||
import { useSelector } from 'store';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import { HORIZONTAL_MAX_ITEM, MenuOrientation } from 'config';
|
||||
|
||||
// project import
|
||||
import NavGroup from './NavGroup';
|
||||
import menuItem from 'menu-items';
|
||||
|
||||
// ==============================|| DRAWER CONTENT - NAVIGATION ||============================== //
|
||||
|
||||
const Navigation = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const downLG = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
const { menuOrientation } = useConfig();
|
||||
const { drawerOpen } = useSelector((state) => state.menu);
|
||||
const [selectedItems, setSelectedItems] = useState('');
|
||||
const [selectedLevel, setSelectedLevel] = useState(0);
|
||||
const [menuItems, setMenuItems] = useState({ items: [] });
|
||||
|
||||
useEffect(() => {
|
||||
handlerMenuItem();
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
let getMenu = Menu();
|
||||
const handlerMenuItem = () => {
|
||||
const isFound = menuItem.items.some((element) => {
|
||||
if (element.id === 'group-dashboard') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (getMenu?.id !== undefined && !isFound) {
|
||||
menuItem.items.splice(0, 0, getMenu);
|
||||
setMenuItems(menuItem);
|
||||
}
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
setMenuItems(menuItem);
|
||||
// eslint-disable-next-line
|
||||
}, [menuItem]);
|
||||
|
||||
const isHorizontal = menuOrientation === MenuOrientation.HORIZONTAL && !downLG;
|
||||
|
||||
const lastItem = isHorizontal ? HORIZONTAL_MAX_ITEM : null;
|
||||
let lastItemIndex = menuItems.items.length - 1;
|
||||
let remItems = [];
|
||||
let lastItemId;
|
||||
|
||||
// first it checks menu item is more than giving HORIZONTAL_MAX_ITEM after that get lastItemid by giving horizontal max
|
||||
// item and it sets horizontal menu by giving horizontal max item lastly slice menuItem from array and set into remItems
|
||||
|
||||
if (lastItem && lastItem < menuItems.items.length) {
|
||||
lastItemId = menuItems.items[lastItem - 1].id;
|
||||
lastItemIndex = lastItem - 1;
|
||||
remItems = menuItems.items.slice(lastItem - 1, menuItems.items.length).map((item) => ({
|
||||
title: item.title,
|
||||
elements: item.children,
|
||||
icon: item.icon
|
||||
}));
|
||||
}
|
||||
|
||||
const navGroups = menuItems.items.slice(0, lastItemIndex + 1).map((item) => {
|
||||
switch (item.type) {
|
||||
case 'group':
|
||||
return (
|
||||
<NavGroup
|
||||
key={item.id}
|
||||
setSelectedItems={setSelectedItems}
|
||||
setSelectedLevel={setSelectedLevel}
|
||||
selectedLevel={selectedLevel}
|
||||
selectedItems={selectedItems}
|
||||
lastItem={lastItem}
|
||||
remItems={remItems}
|
||||
lastItemId={lastItemId}
|
||||
item={item}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<Typography key={item.id} variant="h6" color="error" align="center">
|
||||
Fix - Navigation Group
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
});
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
pt: drawerOpen ? (isHorizontal ? 0 : 2) : 0,
|
||||
'& > ul:first-of-type': { mt: 0 },
|
||||
display: isHorizontal ? { xs: 'block', lg: 'flex' } : 'block'
|
||||
}}
|
||||
>
|
||||
{navGroups}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navigation;
|
||||
@@ -1,99 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { forwardRef, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { useMediaQuery, Avatar, Chip, ListItemButton, ListItemText, Typography } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import { ThemeMode } from 'config';
|
||||
import { dispatch, useSelector } from 'store';
|
||||
import { activeComponent, openComponentDrawer } from 'store/reducers/menu';
|
||||
|
||||
// ==============================|| NAVIGATION - LIST ITEM ||============================== //
|
||||
|
||||
const NavItem = ({ item }) => {
|
||||
const theme = useTheme();
|
||||
const matchesMD = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
const menu = useSelector((state) => state.menu);
|
||||
const { openComponent } = menu;
|
||||
|
||||
let itemTarget = '_self';
|
||||
if (item.target) {
|
||||
itemTarget = '_blank';
|
||||
}
|
||||
|
||||
let listItemProps = { component: forwardRef((props, ref) => <Link {...props} to={item.url} target={itemTarget} ref={ref} />) };
|
||||
if (item?.external) {
|
||||
listItemProps = { component: 'a', href: item.url, target: itemTarget };
|
||||
}
|
||||
|
||||
const itemHandler = (id) => {
|
||||
dispatch(activeComponent({ openComponent: id }));
|
||||
if (matchesMD) dispatch(openComponentDrawer({ componentDrawerOpen: false }));
|
||||
};
|
||||
|
||||
// active menu item on page load
|
||||
useEffect(() => {
|
||||
const currentIndex = document.location.pathname
|
||||
.toString()
|
||||
.split('/')
|
||||
.findIndex((id) => id === item.id);
|
||||
if (currentIndex > -1) {
|
||||
dispatch(activeComponent({ openComponent: item.id }));
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
const textColor = theme.palette.mode === ThemeMode.DARK ? 'grey.400' : 'text.primary';
|
||||
const iconSelectedColor = theme.palette.mode === ThemeMode.DARK ? 'text.primary' : 'primary.main';
|
||||
|
||||
return (
|
||||
<ListItemButton
|
||||
{...listItemProps}
|
||||
disabled={item.disabled}
|
||||
onClick={() => itemHandler(item.id)}
|
||||
selected={openComponent === item.id}
|
||||
sx={{
|
||||
pl: 4,
|
||||
py: 1,
|
||||
mb: 0.5,
|
||||
'&:hover': {
|
||||
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'primary.lighter'
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'primary.lighter',
|
||||
borderRight: `2px solid ${theme.palette.primary.main}`,
|
||||
'&:hover': {
|
||||
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'divider' : 'primary.lighter'
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6" sx={{ color: openComponent === item.id ? iconSelectedColor : textColor }}>
|
||||
{item.title}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{item.chip && (
|
||||
<Chip
|
||||
color={item.chip.color}
|
||||
variant={item.chip.variant}
|
||||
size={item.chip.size}
|
||||
label={item.chip.label}
|
||||
avatar={item.chip.avatar && <Avatar>{item.chip.avatar}</Avatar>}
|
||||
/>
|
||||
)}
|
||||
</ListItemButton>
|
||||
);
|
||||
};
|
||||
|
||||
NavItem.propTypes = {
|
||||
item: PropTypes.object
|
||||
};
|
||||
|
||||
export default NavItem;
|
||||
@@ -1,37 +0,0 @@
|
||||
// material-ui
|
||||
import // useMediaQuery,
|
||||
// useTheme
|
||||
'@mui/material';
|
||||
|
||||
// project import
|
||||
// import NavCard from './NavCard';
|
||||
import Navigation from './Navigation';
|
||||
// import { useSelector } from 'store';
|
||||
import SimpleBar from 'components/third-party/SimpleBar';
|
||||
|
||||
// ==============================|| DRAWER CONTENT ||============================== //
|
||||
|
||||
const DrawerContent = () => {
|
||||
// const theme = useTheme();
|
||||
// const matchDownMD = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
// const menu = useSelector((state) => state.menu);
|
||||
// const { drawerOpen } = menu;
|
||||
|
||||
return (
|
||||
<SimpleBar
|
||||
sx={{
|
||||
'& .simplebar-content': {
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Navigation />
|
||||
{/* no need navCrd just hided */}
|
||||
{/* {drawerOpen && !matchDownMD && <NavCard />} */}
|
||||
</SimpleBar>
|
||||
);
|
||||
};
|
||||
|
||||
export default DrawerContent;
|
||||
@@ -1,22 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { Box } from '@mui/material';
|
||||
|
||||
// ==============================|| DRAWER HEADER - STYLED ||============================== //
|
||||
|
||||
const DrawerHeaderStyled = styled(Box, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({
|
||||
...theme.mixins.toolbar,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: open ? 'flex-start' : 'center',
|
||||
paddingLeft: theme.spacing(open ? 3 : 0)
|
||||
}));
|
||||
|
||||
DrawerHeaderStyled.propTypes = {
|
||||
theme: PropTypes.object,
|
||||
open: PropTypes.bool
|
||||
};
|
||||
|
||||
export default DrawerHeaderStyled;
|
||||
@@ -1,58 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import DrawerHeaderStyled from './DrawerHeaderStyled';
|
||||
|
||||
import { MenuOrientation } from 'config';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
|
||||
import logo from 'assets/images/logo-nearle9.png'
|
||||
import logo1 from 'assets/images/logo-sm1.png'
|
||||
// ==============================|| DRAWER HEADER ||============================== //
|
||||
|
||||
const DrawerHeader = ({ open }) => {
|
||||
const theme = useTheme();
|
||||
const downLG = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
const { menuOrientation } = useConfig();
|
||||
const isHorizontal = menuOrientation === MenuOrientation.HORIZONTAL && !downLG;
|
||||
|
||||
return (
|
||||
<DrawerHeaderStyled
|
||||
theme={theme}
|
||||
open={open}
|
||||
sx={{
|
||||
minHeight: isHorizontal ? 'unset' : '60px',
|
||||
width: isHorizontal ? { xs: '100%', lg: '424px' } : 'inherit',
|
||||
paddingTop: isHorizontal ? { xs: '10px', lg: '0' } : '8px',
|
||||
paddingBottom: isHorizontal ? { xs: '18px', lg: '0' } : '8px',
|
||||
paddingLeft: isHorizontal ? { xs: '24px', lg: '0' } : open ? '24px' : 0
|
||||
}}
|
||||
>
|
||||
{/* <Logo isIcon={!open} sx={{ width: open ? 'auto' : 35, height: 35 }} /> */}
|
||||
|
||||
{(open) &&
|
||||
<img src={logo}
|
||||
// width='160px'
|
||||
// height='45px'
|
||||
// width='170px'
|
||||
alt='logo'/>
|
||||
}
|
||||
{(!open) &&
|
||||
<img src={logo1}
|
||||
width='40px'
|
||||
alt='logo'/>
|
||||
}
|
||||
</DrawerHeaderStyled>
|
||||
);
|
||||
};
|
||||
|
||||
DrawerHeader.propTypes = {
|
||||
open: PropTypes.bool
|
||||
};
|
||||
|
||||
export default DrawerHeader;
|
||||
@@ -1,62 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { AppBar, Box, Container, useScrollTrigger } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import Navigation from './DrawerContent/Navigation';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
|
||||
// ==============================|| HORIZONTAL MENU LIST ||============================== //
|
||||
|
||||
function ElevationScroll({ children, window }) {
|
||||
const theme = useTheme();
|
||||
// Note that you normally won't need to set the window ref as useScrollTrigger
|
||||
// will default to window.
|
||||
// This is only being set here because the demo is in an iframe.
|
||||
const trigger = useScrollTrigger({
|
||||
disableHysteresis: true,
|
||||
threshold: 0,
|
||||
target: window
|
||||
});
|
||||
|
||||
theme.shadows[4] = theme.customShadows.z1;
|
||||
|
||||
return React.cloneElement(children, {
|
||||
elevation: trigger ? 4 : 0
|
||||
});
|
||||
}
|
||||
|
||||
// ==============================|| HORIZONTAL MENU LIST ||============================== //
|
||||
|
||||
const CustomAppBar = () => {
|
||||
const theme = useTheme();
|
||||
const { container } = useConfig();
|
||||
|
||||
return (
|
||||
<ElevationScroll>
|
||||
<AppBar
|
||||
sx={{
|
||||
top: 60,
|
||||
bgcolor: theme.palette.background.paper,
|
||||
width: '100%',
|
||||
height: 62,
|
||||
justifyContent: 'center',
|
||||
borderTop: `1px solid ${theme.palette.divider}`,
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
zIndex: 1098,
|
||||
color: theme.palette.grey[500]
|
||||
}}
|
||||
>
|
||||
<Container maxWidth={container ? 'xl' : false}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Navigation />
|
||||
</Box>
|
||||
</Container>
|
||||
</AppBar>
|
||||
</ElevationScroll>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomAppBar;
|
||||
@@ -1,51 +0,0 @@
|
||||
// material-ui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Drawer from '@mui/material/Drawer';
|
||||
|
||||
// project import
|
||||
import { DRAWER_WIDTH, ThemeMode } from 'config';
|
||||
|
||||
const openedMixin = (theme) => ({
|
||||
width: DRAWER_WIDTH,
|
||||
// borderRight: `1px solid ${theme.palette.divider}`,
|
||||
borderRight: 'none',
|
||||
transition: theme.transitions.create('width', {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen
|
||||
}),
|
||||
overflowX: 'hidden',
|
||||
boxShadow: theme.palette.mode === ThemeMode.DARK ? theme.customShadows.z1 : 'none',
|
||||
backgroundColor:'#662582',
|
||||
});
|
||||
|
||||
const closedMixin = (theme) => ({
|
||||
transition: theme.transitions.create('width', {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen
|
||||
}),
|
||||
// overflowX: 'hidden',
|
||||
width: theme.spacing(7.5),
|
||||
borderRight: 'none',
|
||||
boxShadow: theme.customShadows.z1,
|
||||
backgroundColor:'#662582',
|
||||
});
|
||||
|
||||
// ==============================|| DRAWER - MINI STYLED ||============================== //
|
||||
|
||||
const MiniDrawerStyled = styled(Drawer, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({
|
||||
width: DRAWER_WIDTH,
|
||||
flexShrink: 0,
|
||||
whiteSpace: 'nowrap',
|
||||
boxSizing: 'border-box',
|
||||
|
||||
...(open && {
|
||||
...openedMixin(theme),
|
||||
'& .MuiDrawer-paper': openedMixin(theme)
|
||||
}),
|
||||
...(!open && {
|
||||
...closedMixin(theme),
|
||||
'& .MuiDrawer-paper': closedMixin(theme)
|
||||
})
|
||||
}));
|
||||
|
||||
export default MiniDrawerStyled;
|
||||
@@ -1,74 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Box, Drawer, useMediaQuery } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import DrawerHeader from './DrawerHeader';
|
||||
import DrawerContent from './DrawerContent';
|
||||
import MiniDrawerStyled from './MiniDrawerStyled';
|
||||
|
||||
import { DRAWER_WIDTH } from 'config';
|
||||
import { dispatch, useSelector } from 'store';
|
||||
import { openDrawer } from 'store/reducers/menu';
|
||||
|
||||
// ==============================|| MAIN LAYOUT - DRAWER ||============================== //
|
||||
|
||||
const MainDrawer = ({ window }) => {
|
||||
const theme = useTheme();
|
||||
const matchDownMD = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
const menu = useSelector((state) => state.menu);
|
||||
const { drawerOpen } = menu;
|
||||
|
||||
// responsive drawer container
|
||||
const container = window !== undefined ? () => window().document.body : undefined;
|
||||
|
||||
// header content
|
||||
const drawerContent = useMemo(() => <DrawerContent />, []);
|
||||
const drawerHeader = useMemo(() => <DrawerHeader open={drawerOpen} />, [drawerOpen]);
|
||||
|
||||
return (
|
||||
<Box component="nav" sx={{ flexShrink: { md: 0 }, zIndex: 1200 }} aria-label="mailbox folders">
|
||||
{!matchDownMD ? (
|
||||
<MiniDrawerStyled
|
||||
variant="permanent"
|
||||
open={drawerOpen}
|
||||
>
|
||||
{drawerHeader}
|
||||
{drawerContent}
|
||||
</MiniDrawerStyled>
|
||||
) : (
|
||||
<Drawer
|
||||
container={container}
|
||||
variant="temporary"
|
||||
open={drawerOpen}
|
||||
onClose={() => dispatch(openDrawer(!drawerOpen))}
|
||||
ModalProps={{ keepMounted: true }}
|
||||
sx={{
|
||||
display: { xs: 'block', lg: 'none' },
|
||||
'& .MuiDrawer-paper': {
|
||||
boxSizing: 'border-box',
|
||||
width: DRAWER_WIDTH,
|
||||
borderRight: `1px solid ${theme.palette.divider}`,
|
||||
backgroundImage: 'none',
|
||||
boxShadow: 'inherit',
|
||||
bgcolor:'#662582'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{drawerHeader}
|
||||
{drawerContent}
|
||||
</Drawer>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
MainDrawer.propTypes = {
|
||||
window: PropTypes.object
|
||||
};
|
||||
|
||||
export default MainDrawer;
|
||||
@@ -1,35 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
|
||||
// project import
|
||||
import { DRAWER_WIDTH } from 'config';
|
||||
|
||||
// ==============================|| HEADER - APP BAR STYLED ||============================== //
|
||||
|
||||
const AppBarStyled = styled(AppBar, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
transition: theme.transitions.create(['width', 'margin'], {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen
|
||||
}),
|
||||
...(!open && {
|
||||
width: `calc(100% - ${theme.spacing(7.5)})`
|
||||
}),
|
||||
...(open && {
|
||||
marginLeft: DRAWER_WIDTH,
|
||||
width: `calc(100% - ${DRAWER_WIDTH}px)`,
|
||||
transition: theme.transitions.create(['width', 'margin'], {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen
|
||||
})
|
||||
})
|
||||
}));
|
||||
|
||||
AppBarStyled.propTypes = {
|
||||
open: PropTypes.bool
|
||||
};
|
||||
|
||||
export default AppBarStyled;
|
||||
@@ -1,298 +0,0 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Button,
|
||||
Box,
|
||||
CardMedia,
|
||||
ClickAwayListener,
|
||||
Grid,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
ListSubheader,
|
||||
Paper,
|
||||
Popper,
|
||||
Stack,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
import Dot from 'components/@extended/Dot';
|
||||
import IconButton from 'components/@extended/IconButton';
|
||||
import Transitions from 'components/@extended/Transitions';
|
||||
import { DRAWER_WIDTH, ThemeMode } from 'config';
|
||||
|
||||
// assets
|
||||
import { ArrowRightOutlined, WindowsOutlined } from '@ant-design/icons';
|
||||
import backgroundVector from 'assets/images/mega-menu/back.svg';
|
||||
import imageChart from 'assets/images/mega-menu/chart.svg';
|
||||
import AnimateButton from 'components/@extended/AnimateButton';
|
||||
|
||||
// ==============================|| HEADER CONTENT - MEGA MENU SECTION ||============================== //
|
||||
|
||||
const MegaMenuSection = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const anchorRef = useRef(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const iconBackColorOpen = theme.palette.mode === ThemeMode.DARK ? 'grey.200' : 'grey.300';
|
||||
const iconBackColor = theme.palette.mode === ThemeMode.DARK ? 'background.default' : 'grey.100';
|
||||
|
||||
return (
|
||||
<Box sx={{ flexShrink: 0, ml: 0.75 }}>
|
||||
<IconButton
|
||||
color="secondary"
|
||||
variant="light"
|
||||
sx={{ color: 'text.primary', bgcolor: open ? iconBackColorOpen : iconBackColor }}
|
||||
aria-label="open profile"
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'profile-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
// onClick={handleToggle}
|
||||
>
|
||||
<WindowsOutlined />
|
||||
</IconButton>
|
||||
<Popper
|
||||
placement="bottom"
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [-180, 9]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Transitions type="grow" position="top" in={open} {...TransitionProps}>
|
||||
<Paper
|
||||
sx={{
|
||||
boxShadow: theme.customShadows.z1,
|
||||
minWidth: 750,
|
||||
width: {
|
||||
md: `calc(100vw - 100px)`,
|
||||
lg: `calc(100vw - ${DRAWER_WIDTH + 100}px)`,
|
||||
xl: `calc(100vw - ${DRAWER_WIDTH + 140}px)`
|
||||
},
|
||||
maxWidth: 1024
|
||||
}}
|
||||
>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<MainCard elevation={0} border={false} content={false}>
|
||||
<Grid container>
|
||||
<Grid
|
||||
item
|
||||
md={4}
|
||||
sx={{
|
||||
background: `url(${backgroundVector}), linear-gradient(183.77deg, ${theme.palette.primary.main} 11.46%, ${theme.palette.primary[700]} 100.33%)`
|
||||
}}
|
||||
>
|
||||
<Box sx={{ p: 4.5, pb: 3 }}>
|
||||
<Stack sx={{ color: 'background.paper' }}>
|
||||
<Typography variant="h2" sx={{ fontSize: '1.875rem', mb: 1 }}>
|
||||
Explore Components
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
Try our pre made component pages to check how it feels and suits as per your need.
|
||||
</Typography>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="flex-end" sx={{ mt: -1 }}>
|
||||
<AnimateButton>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
sx={{
|
||||
bgcolor: 'background.paper',
|
||||
color: 'text.primary',
|
||||
'&:hover': { bgcolor: 'background.paper', color: 'text.primary' }
|
||||
}}
|
||||
endIcon={<ArrowRightOutlined />}
|
||||
component={Link}
|
||||
to="/components-overview/buttons"
|
||||
target="_blank"
|
||||
>
|
||||
View All
|
||||
</Button>
|
||||
</AnimateButton>
|
||||
<CardMedia component="img" src={imageChart} alt="Chart" sx={{ mr: -2.5, mb: -2.5, width: 124 }} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item md={8}>
|
||||
<Box
|
||||
sx={{
|
||||
p: 4,
|
||||
'& .MuiList-root': {
|
||||
pb: 0
|
||||
},
|
||||
'& .MuiListSubheader-root': {
|
||||
p: 0,
|
||||
pb: 1.5
|
||||
},
|
||||
'& .MuiListItemButton-root': {
|
||||
p: 0.5,
|
||||
'&:hover': {
|
||||
background: 'transparent',
|
||||
'& .MuiTypography-root': {
|
||||
color: 'primary.main'
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Grid container spacing={6}>
|
||||
<Grid item xs={4}>
|
||||
<List
|
||||
component="nav"
|
||||
aria-labelledby="nested-list-user"
|
||||
subheader={
|
||||
<ListSubheader id="nested-list-user">
|
||||
<Typography variant="subtitle1" color="textPrimary">
|
||||
Authentication
|
||||
</Typography>
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/auth/login">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Login" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/auth/register">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Register" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/auth/reset-password">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Reset Password" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/auth/forgot-password">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Forgot Password" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/auth/code-verification">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Verification Code" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<List
|
||||
component="nav"
|
||||
aria-labelledby="nested-list-user"
|
||||
subheader={
|
||||
<ListSubheader id="nested-list-user">
|
||||
<Typography variant="subtitle1" color="textPrimary">
|
||||
Other Pages
|
||||
</Typography>
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="About us" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/contact-us">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Contact us" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} to="/pricing">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Pricing" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} to="/apps/profiles/user/payment">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Payment" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/maintenance/under-construction">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Construction" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/maintenance/coming-soon">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Coming Soon" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<List
|
||||
component="nav"
|
||||
aria-labelledby="nested-list-user"
|
||||
subheader={
|
||||
<ListSubheader id="nested-list-user">
|
||||
<Typography variant="subtitle1" color="textPrimary">
|
||||
SAAS Pages
|
||||
</Typography>
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/maintenance/404">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="404 Error" />
|
||||
</ListItemButton>
|
||||
<ListItemButton disableRipple component={Link} target="_blank" to="/">
|
||||
<ListItemIcon>
|
||||
<Dot size={7} color="secondary" variant="outlined" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Landing" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</MainCard>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Transitions>
|
||||
)}
|
||||
</Popper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MegaMenuSection;
|
||||
@@ -1,252 +0,0 @@
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
ClickAwayListener,
|
||||
Divider,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
ListItemSecondaryAction,
|
||||
Paper,
|
||||
Popper,
|
||||
Typography,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
import IconButton from 'components/@extended/IconButton';
|
||||
import Transitions from 'components/@extended/Transitions';
|
||||
import { ThemeMode } from 'config';
|
||||
|
||||
// assets
|
||||
import avatar2 from 'assets/images/users/avatar-2.png';
|
||||
import avatar3 from 'assets/images/users/avatar-3.png';
|
||||
import avatar4 from 'assets/images/users/avatar-4.png';
|
||||
import avatar5 from 'assets/images/users/avatar-5.png';
|
||||
import { MailOutlined, CloseOutlined } from '@ant-design/icons';
|
||||
|
||||
// sx styles
|
||||
const avatarSX = {
|
||||
width: 48,
|
||||
height: 48
|
||||
};
|
||||
|
||||
const actionSX = {
|
||||
mt: '6px',
|
||||
ml: 1,
|
||||
top: 'auto',
|
||||
right: 'auto',
|
||||
alignSelf: 'flex-start',
|
||||
transform: 'none'
|
||||
};
|
||||
|
||||
// ==============================|| HEADER CONTENT - MESSAGES ||============================== //
|
||||
|
||||
const Message = () => {
|
||||
const theme = useTheme();
|
||||
const matchesXs = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
const anchorRef = useRef(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
const handleToggle = () => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const iconBackColorOpen = theme.palette.mode === ThemeMode.DARK ? 'grey.200' : 'grey.300';
|
||||
const iconBackColor = theme.palette.mode === ThemeMode.DARK ? 'background.default' : 'grey.100';
|
||||
|
||||
return (
|
||||
<Box sx={{ flexShrink: 0, ml: 0.75 }}>
|
||||
<IconButton
|
||||
color="secondary"
|
||||
variant="light"
|
||||
sx={{ color: 'text.primary', bgcolor: open ? iconBackColorOpen : iconBackColor }}
|
||||
aria-label="open profile"
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'profile-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<MailOutlined />
|
||||
</IconButton>
|
||||
<Popper
|
||||
placement={matchesXs ? 'bottom' : 'bottom-end'}
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
sx={{
|
||||
maxHeight: 'calc(100vh - 250px)',
|
||||
overflow: 'auto'
|
||||
}}
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [matchesXs ? -60 : 0, 9]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Transitions type="grow" position={matchesXs ? 'top' : 'top-right'} in={open} {...TransitionProps}>
|
||||
<Paper
|
||||
sx={{
|
||||
boxShadow: theme.customShadows.z1,
|
||||
width: '100%',
|
||||
minWidth: 285,
|
||||
maxWidth: 420,
|
||||
[theme.breakpoints.down('md')]: {
|
||||
maxWidth: 285
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<MainCard
|
||||
title="Message"
|
||||
elevation={0}
|
||||
border={false}
|
||||
content={false}
|
||||
secondary={
|
||||
<IconButton size="small" onClick={handleToggle}>
|
||||
<CloseOutlined />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<List
|
||||
component="nav"
|
||||
sx={{
|
||||
p: 0,
|
||||
'& .MuiListItemButton-root': {
|
||||
py: 1.5,
|
||||
'& .MuiAvatar-root': avatarSX,
|
||||
'& .MuiListItemSecondaryAction-root': { ...actionSX, position: 'relative' }
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemButton>
|
||||
<ListItemAvatar>
|
||||
<Avatar alt="profile user" src={avatar2} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6">
|
||||
It's{' '}
|
||||
<Typography component="span" variant="subtitle1">
|
||||
Cristina danny's
|
||||
</Typography>{' '}
|
||||
birthday today.
|
||||
</Typography>
|
||||
}
|
||||
secondary="2 min ago"
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Typography variant="caption" noWrap>
|
||||
3:00 AM
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItemButton>
|
||||
<Divider />
|
||||
<ListItemButton>
|
||||
<ListItemAvatar>
|
||||
<Avatar alt="profile user" src={avatar3} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6">
|
||||
<Typography component="span" variant="subtitle1">
|
||||
Aida Burg
|
||||
</Typography>{' '}
|
||||
commented your post.
|
||||
</Typography>
|
||||
}
|
||||
secondary="5 August"
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Typography variant="caption" noWrap>
|
||||
6:00 PM
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItemButton>
|
||||
<Divider />
|
||||
<ListItemButton>
|
||||
<ListItemAvatar>
|
||||
<Avatar alt="profile user" src={avatar4} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography component="span" variant="subtitle1">
|
||||
There was a failure to your setup.
|
||||
</Typography>
|
||||
}
|
||||
secondary="7 hours ago"
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Typography variant="caption" noWrap>
|
||||
2:45 PM
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItemButton>
|
||||
<Divider />
|
||||
<ListItemButton>
|
||||
<ListItemAvatar>
|
||||
<Avatar alt="profile user" src={avatar5} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6">
|
||||
<Typography component="span" variant="subtitle1">
|
||||
Cristina Danny
|
||||
</Typography>{' '}
|
||||
invited to join{' '}
|
||||
<Typography component="span" variant="subtitle1">
|
||||
Meeting.
|
||||
</Typography>
|
||||
</Typography>
|
||||
}
|
||||
secondary="Daily scrum meeting time"
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Typography variant="caption" noWrap>
|
||||
9:10 PM
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItemButton>
|
||||
<Divider />
|
||||
<ListItemButton sx={{ textAlign: 'center' }}>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6" color="primary">
|
||||
View All
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</MainCard>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Transitions>
|
||||
)}
|
||||
</Popper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Message;
|
||||
@@ -1,104 +0,0 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { AppBar, Box, ClickAwayListener, Paper, Popper, Toolbar } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import Profile from './Profile';
|
||||
import IconButton from 'components/@extended/IconButton';
|
||||
import Transitions from 'components/@extended/Transitions';
|
||||
import { ThemeMode } from 'config';
|
||||
|
||||
// assets
|
||||
import { MoreOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| HEADER CONTENT - MOBILE ||============================== //
|
||||
|
||||
const MobileSection = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const anchorRef = useRef(null);
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const prevOpen = useRef(open);
|
||||
useEffect(() => {
|
||||
if (prevOpen.current === true && open === false) {
|
||||
anchorRef.current.focus();
|
||||
}
|
||||
|
||||
prevOpen.current = open;
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ flexShrink: 0, ml: 0.75 }}>
|
||||
<IconButton
|
||||
// sx={{ color: 'text.primary', bgcolor: open ? iconBackColorOpen : iconBackColor }}
|
||||
sx={{ color: '#fff', bgcolor: 'transparent', ml: { xs: 0, lg: -2 },
|
||||
fontSize:'25px',
|
||||
':hover':{
|
||||
color: '#fff', bgcolor: 'transparent'
|
||||
} }}
|
||||
aria-label="open more menu"
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'menu-list-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={handleToggle}
|
||||
color="secondary"
|
||||
variant="light"
|
||||
>
|
||||
<MoreOutlined />
|
||||
</IconButton>
|
||||
</Box>
|
||||
<Popper
|
||||
placement="bottom-end"
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
style={{ width: '100%' }}
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, 9]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Transitions type="fade" in={open} {...TransitionProps}>
|
||||
<Paper sx={{ boxShadow: theme.customShadows.z1 }}>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<AppBar color="inherit">
|
||||
<Toolbar>
|
||||
{/* <Search /> */}
|
||||
<Profile />
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Transitions>
|
||||
)}
|
||||
</Popper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MobileSection;
|
||||
@@ -1,303 +0,0 @@
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
Box,
|
||||
ClickAwayListener,
|
||||
Divider,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
ListItemSecondaryAction,
|
||||
Paper,
|
||||
Popper,
|
||||
Tooltip,
|
||||
Typography,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
import IconButton from 'components/@extended/IconButton';
|
||||
import Transitions from 'components/@extended/Transitions';
|
||||
import { ThemeMode } from 'config';
|
||||
|
||||
// assets
|
||||
import { BellOutlined, CheckCircleOutlined, GiftOutlined, MessageOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
|
||||
// sx styles
|
||||
const avatarSX = {
|
||||
width: 36,
|
||||
height: 36,
|
||||
fontSize: '1rem'
|
||||
};
|
||||
|
||||
const actionSX = {
|
||||
mt: '6px',
|
||||
ml: 1,
|
||||
top: 'auto',
|
||||
right: 'auto',
|
||||
alignSelf: 'flex-start',
|
||||
|
||||
transform: 'none'
|
||||
};
|
||||
|
||||
// ==============================|| HEADER CONTENT - NOTIFICATION ||============================== //
|
||||
|
||||
const Notification = () => {
|
||||
const theme = useTheme();
|
||||
const matchesXs = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
const anchorRef = useRef(null);
|
||||
const [read, setRead] = useState(0);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ flexShrink: 0, ml: 0.75 }}>
|
||||
<Tooltip title='Notifications'>
|
||||
<IconButton
|
||||
// color="secondary"
|
||||
// variant="light"
|
||||
// sx={{ color: 'text.primary', bgcolor: open ? iconBackColorOpen : iconBackColor }}
|
||||
sx={{ color: '#fff',
|
||||
fontSize:'20px',
|
||||
// bgcolor: open ? iconBackColorOpen : iconBackColor
|
||||
':hover':{
|
||||
bgcolor:'transparent',
|
||||
color: '#fff',
|
||||
},
|
||||
// bgcolor:'transparent'
|
||||
}}
|
||||
|
||||
aria-label="open profile"
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'profile-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
// onClick={handleToggle}
|
||||
>
|
||||
<Badge badgeContent={read}
|
||||
// color="primary"
|
||||
sx={{
|
||||
"& .MuiBadge-badge": {
|
||||
color: "#662582",
|
||||
backgroundColor: "white"
|
||||
}
|
||||
}}
|
||||
>
|
||||
<BellOutlined />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Popper
|
||||
placement={matchesXs ? 'bottom' : 'bottom-end'}
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [matchesXs ? -5 : 0, 9]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Transitions type="grow" position={matchesXs ? 'top' : 'top-right'} sx={{ overflow: 'hidden' }} in={open} {...TransitionProps}>
|
||||
<Paper
|
||||
sx={{
|
||||
boxShadow: theme.customShadows.z1,
|
||||
width: '100%',
|
||||
minWidth: 285,
|
||||
maxWidth: 420,
|
||||
[theme.breakpoints.down('md')]: {
|
||||
maxWidth: 285
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<MainCard
|
||||
title="Notification"
|
||||
elevation={0}
|
||||
border={false}
|
||||
content={false}
|
||||
secondary={
|
||||
<>
|
||||
{read > 0 && (
|
||||
<Tooltip title="Mark as all read">
|
||||
<IconButton color="success" size="small" onClick={() => setRead(0)}>
|
||||
<CheckCircleOutlined style={{ fontSize: '1.15rem' }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<List
|
||||
component="nav"
|
||||
sx={{
|
||||
p: 0,
|
||||
'& .MuiListItemButton-root': {
|
||||
py: 0.5,
|
||||
'&.Mui-selected': { bgcolor: 'grey.50', color: 'text.primary' },
|
||||
'& .MuiAvatar-root': avatarSX,
|
||||
'& .MuiListItemSecondaryAction-root': { ...actionSX, position: 'relative' }
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemButton selected={read > 0}>
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
sx={{
|
||||
color: 'success.main',
|
||||
bgcolor: 'success.lighter'
|
||||
}}
|
||||
>
|
||||
<GiftOutlined />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6">
|
||||
It's{' '}
|
||||
<Typography component="span" variant="subtitle1">
|
||||
Cristina danny's
|
||||
</Typography>{' '}
|
||||
birthday today.
|
||||
</Typography>
|
||||
}
|
||||
secondary="2 min ago"
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Typography variant="caption" noWrap>
|
||||
3:00 AM
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItemButton>
|
||||
<Divider />
|
||||
<ListItemButton selected={read > 0}>
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
sx={{
|
||||
color: 'primary.main',
|
||||
bgcolor: 'primary.lighter'
|
||||
}}
|
||||
>
|
||||
<MessageOutlined />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6">
|
||||
<Typography component="span" variant="subtitle1">
|
||||
Aida Burg
|
||||
</Typography>{' '}
|
||||
commented your post.
|
||||
</Typography>
|
||||
}
|
||||
secondary="5 August"
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Typography variant="caption" noWrap>
|
||||
6:00 PM
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItemButton>
|
||||
<Divider />
|
||||
<ListItemButton>
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
sx={{
|
||||
color: 'error.main',
|
||||
bgcolor: 'error.lighter'
|
||||
}}
|
||||
>
|
||||
<SettingOutlined />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6">
|
||||
Your Profile is Complete
|
||||
<Typography component="span" variant="subtitle1">
|
||||
60%
|
||||
</Typography>{' '}
|
||||
</Typography>
|
||||
}
|
||||
secondary="7 hours ago"
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Typography variant="caption" noWrap>
|
||||
2:45 PM
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItemButton>
|
||||
<Divider />
|
||||
<ListItemButton>
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
sx={{
|
||||
color: 'primary.main',
|
||||
bgcolor: 'primary.lighter'
|
||||
}}
|
||||
>
|
||||
C
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6">
|
||||
<Typography component="span" variant="subtitle1">
|
||||
Cristina Danny
|
||||
</Typography>{' '}
|
||||
invited to join{' '}
|
||||
<Typography component="span" variant="subtitle1">
|
||||
Meeting.
|
||||
</Typography>
|
||||
</Typography>
|
||||
}
|
||||
secondary="Daily scrum meeting time"
|
||||
/>
|
||||
<ListItemSecondaryAction>
|
||||
<Typography variant="caption" noWrap>
|
||||
9:10 PM
|
||||
</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItemButton>
|
||||
<Divider />
|
||||
<ListItemButton sx={{ textAlign: 'center', py: `${12}px !important` }}>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="h6" color="primary">
|
||||
View All
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</MainCard>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Transitions>
|
||||
)}
|
||||
</Popper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Notification;
|
||||
@@ -1,61 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { List, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||
|
||||
// assets
|
||||
import { EditOutlined, LogoutOutlined, CommentOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router';
|
||||
|
||||
// ==============================|| HEADER PROFILE - PROFILE TAB ||============================== //
|
||||
|
||||
const ProfileTab = ({ handleLogout }) => {
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
const navigate = useNavigate();
|
||||
const handleListItemClick = (event, index) => {
|
||||
setSelectedIndex(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<List component="nav" sx={{ p: 0, '& .MuiListItemIcon-root': { minWidth: 32 } }}>
|
||||
<ListItemButton
|
||||
selected={selectedIndex === 0}
|
||||
onClick={(event) => {
|
||||
handleListItemClick(event, 0);
|
||||
navigate('/viewprofile');
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<EditOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="View Profile" />
|
||||
</ListItemButton>
|
||||
|
||||
<ListItemButton selected={selectedIndex === 2} onClick={(event) => handleListItemClick(event, 1)}>
|
||||
<ListItemIcon>
|
||||
<CommentOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Support Ticket" />
|
||||
</ListItemButton>
|
||||
{/* <ListItemButton selected={selectedIndex === 4} onClick={(event) => handleListItemClick(event, 4)}>
|
||||
<ListItemIcon>
|
||||
<WalletOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Billing" />
|
||||
</ListItemButton> */}
|
||||
<ListItemButton selected={selectedIndex === 3} onClick={handleLogout}>
|
||||
<ListItemIcon>
|
||||
<LogoutOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Logout" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
ProfileTab.propTypes = {
|
||||
handleLogout: PropTypes.func
|
||||
};
|
||||
|
||||
export default ProfileTab;
|
||||
@@ -1,53 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { List, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||
|
||||
// assets
|
||||
import { CommentOutlined, LockOutlined, QuestionCircleOutlined, UserOutlined, UnorderedListOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| HEADER PROFILE - SETTING TAB ||============================== //
|
||||
|
||||
const SettingTab = () => {
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
const handleListItemClick = (event, index) => {
|
||||
setSelectedIndex(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<List component="nav" sx={{ p: 0, '& .MuiListItemIcon-root': { minWidth: 32 } }}>
|
||||
<ListItemButton selected={selectedIndex === 0} onClick={(event) => handleListItemClick(event, 0)}>
|
||||
<ListItemIcon>
|
||||
<QuestionCircleOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Support" />
|
||||
</ListItemButton>
|
||||
<ListItemButton selected={selectedIndex === 1} onClick={(event) => handleListItemClick(event, 1)}>
|
||||
<ListItemIcon>
|
||||
<UserOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Account Settings" />
|
||||
</ListItemButton>
|
||||
<ListItemButton selected={selectedIndex === 2} onClick={(event) => handleListItemClick(event, 2)}>
|
||||
<ListItemIcon>
|
||||
<LockOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Privacy Center" />
|
||||
</ListItemButton>
|
||||
<ListItemButton selected={selectedIndex === 3} onClick={(event) => handleListItemClick(event, 3)}>
|
||||
<ListItemIcon>
|
||||
<CommentOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Feedback" />
|
||||
</ListItemButton>
|
||||
<ListItemButton selected={selectedIndex === 4} onClick={(event) => handleListItemClick(event, 4)}>
|
||||
<ListItemIcon>
|
||||
<UnorderedListOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="History" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingTab;
|
||||
@@ -1,211 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useRef, useState } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Box, ButtonBase, CardContent, ClickAwayListener, Grid, Paper, Popper, Stack, Tab, Tabs, Tooltip, Typography } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import ProfileTab from './ProfileTab';
|
||||
import SettingTab from './SettingTab';
|
||||
import Avatar from 'components/@extended/Avatar';
|
||||
import MainCard from 'components/MainCard';
|
||||
import Transitions from 'components/@extended/Transitions';
|
||||
import IconButton from 'components/@extended/IconButton';
|
||||
|
||||
import { ThemeMode } from 'config';
|
||||
// import useAuth from 'hooks/useAuth';
|
||||
|
||||
// assets
|
||||
import avatar1 from 'assets/images/users/avatar-1.png';
|
||||
import { LogoutOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import { clearFcmToken } from 'store/reducers/fcmSlice';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { logoutUser } from 'store/reducers/loginUserSlice';
|
||||
import { performSessionLogout } from 'utils/session';
|
||||
|
||||
// tab panel wrapper
|
||||
function TabPanel({ children, value, index, ...other }) {
|
||||
return (
|
||||
<div role="tabpanel" hidden={value !== index} id={`profile-tabpanel-${index}`} aria-labelledby={`profile-tab-${index}`} {...other}>
|
||||
{value === index && children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
TabPanel.propTypes = {
|
||||
children: PropTypes.node,
|
||||
index: PropTypes.any.isRequired,
|
||||
value: PropTypes.any.isRequired
|
||||
};
|
||||
|
||||
function a11yProps(index) {
|
||||
return {
|
||||
id: `profile-tab-${index}`,
|
||||
'aria-controls': `profile-tabpanel-${index}`
|
||||
};
|
||||
}
|
||||
|
||||
// ==============================|| HEADER CONTENT - PROFILE ||============================== //
|
||||
|
||||
const Profile = () => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const handleLogout = () => {
|
||||
performSessionLogout({ queryClient, dispatch, clearFcmToken, logoutUser });
|
||||
};
|
||||
|
||||
const anchorRef = useRef(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
const handleToggle = () => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const [value, setValue] = useState(0);
|
||||
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ flexShrink: 0, ml: 0.75 }}>
|
||||
<Tooltip title="Profile">
|
||||
<ButtonBase
|
||||
sx={{
|
||||
p: 0.25,
|
||||
// bgcolor: open ? iconBackColorOpen : 'transparent',
|
||||
borderRadius: 1
|
||||
// '&:hover': { bgcolor: theme.palette.mode === ThemeMode.DARK ? 'secondary.light' : 'secondary.lighter' },
|
||||
// '&:focus-visible': {
|
||||
// outline: `2px solid ${theme.palette.secondary.dark}`,
|
||||
// outlineOffset: 2
|
||||
// }
|
||||
}}
|
||||
aria-label="open profile"
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'profile-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<Stack direction="row" spacing={2} alignItems="center" sx={{ p: 0.5 }}>
|
||||
<Avatar alt="profile user" src={avatar1} size="xs" />
|
||||
<Typography variant="subtitle1">{/* {user?.name} */}</Typography>
|
||||
</Stack>
|
||||
</ButtonBase>
|
||||
</Tooltip>
|
||||
<Popper
|
||||
placement="bottom-end"
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, 9]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Transitions type="grow" position="top-right" in={open} {...TransitionProps}>
|
||||
<Paper
|
||||
sx={{
|
||||
boxShadow: theme.customShadows.z1,
|
||||
width: 290,
|
||||
minWidth: 240,
|
||||
maxWidth: 290,
|
||||
[theme.breakpoints.down('md')]: {
|
||||
maxWidth: 250
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<MainCard elevation={0} border={false} content={false}>
|
||||
<CardContent sx={{ px: 2.5, pt: 3 }}>
|
||||
<Grid container justifyContent="space-between" alignItems="center">
|
||||
<Grid item>
|
||||
<Stack direction="row" spacing={1.25} alignItems="center">
|
||||
<Avatar alt="profile user" src={avatar1} sx={{ width: 32, height: 32 }} />
|
||||
<Stack>
|
||||
<Typography variant="h6">
|
||||
{/* {user?.name} */}
|
||||
{localStorage.getItem('firstname') || ''}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
{/* UI/UX Designer */}
|
||||
Partner
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Tooltip title="Logout">
|
||||
<IconButton size="large" sx={{ color: 'text.primary' }} onClick={handleLogout}>
|
||||
<LogoutOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Tabs variant="fullWidth" value={value} onChange={handleChange} aria-label="profile tabs">
|
||||
<Tab
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
// justifyContent: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
textTransform: 'capitalize'
|
||||
}}
|
||||
icon={<UserOutlined style={{ marginBottom: 0, marginRight: '10px' }} />}
|
||||
label="Profile"
|
||||
{...a11yProps(0)}
|
||||
/>
|
||||
{/* <Tab
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
textTransform: 'capitalize'
|
||||
}}
|
||||
icon={<SettingOutlined style={{ marginBottom: 0, marginRight: '10px' }} />}
|
||||
label="Setting"
|
||||
{...a11yProps(1)}
|
||||
/> */}
|
||||
</Tabs>
|
||||
</Box>
|
||||
<TabPanel value={value} index={0} dir={theme.direction}>
|
||||
<ProfileTab handleLogout={handleLogout} />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1} dir={theme.direction}>
|
||||
<SettingTab />
|
||||
</TabPanel>
|
||||
</MainCard>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Transitions>
|
||||
)}
|
||||
</Popper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Profile;
|
||||
@@ -1,30 +0,0 @@
|
||||
// material-ui
|
||||
import { Box, FormControl, InputAdornment, OutlinedInput } from '@mui/material';
|
||||
|
||||
// assets
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| HEADER CONTENT - SEARCH ||============================== //
|
||||
|
||||
const Search = () => (
|
||||
<Box sx={{ width: '100%', ml: { xs: 0, md: 1 } }}>
|
||||
<FormControl sx={{ width: { xs: '100%', md: 224 } }}>
|
||||
<OutlinedInput
|
||||
size="small"
|
||||
id="header-search"
|
||||
startAdornment={
|
||||
<InputAdornment position="start" sx={{ mr: -0.5 }}>
|
||||
<SearchOutlined />
|
||||
</InputAdornment>
|
||||
}
|
||||
aria-describedby="header-search-text"
|
||||
inputProps={{
|
||||
'aria-label': 'weight'
|
||||
}}
|
||||
placeholder="Ctrl + K"
|
||||
/>
|
||||
</FormControl>
|
||||
</Box>
|
||||
);
|
||||
|
||||
export default Search;
|
||||
@@ -1,292 +0,0 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import {
|
||||
Box,
|
||||
useMediaQuery,
|
||||
Stack,
|
||||
Tooltip,
|
||||
IconButton,
|
||||
Popper,
|
||||
ClickAwayListener,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemText,
|
||||
Grid,
|
||||
ListItemIcon,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
import { TbBoxMultiple1 } from 'react-icons/tb';
|
||||
import { GrMultiple } from 'react-icons/gr';
|
||||
import { TbUserEdit } from 'react-icons/tb';
|
||||
|
||||
import Transitions from 'components/@extended/Transitions';
|
||||
|
||||
// project import
|
||||
import Profile from './Profile';
|
||||
import Notification from './Notification';
|
||||
import { useNavigate } from 'react-router';
|
||||
import {
|
||||
WindowsOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
// ==============================|| HEADER - CONTENT ||============================== //
|
||||
|
||||
const HeaderContent = () => {
|
||||
const matchesXs = useMediaQuery((theme) => theme.breakpoints.down('md'));
|
||||
|
||||
const navigate = useNavigate();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const theme = useTheme();
|
||||
|
||||
const handleToggle = (e) => {
|
||||
setOpen(!open);
|
||||
setAnchorEl(e.currentTarget);
|
||||
};
|
||||
const handleClickAway = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* {!matchesXs && <Search />} */}
|
||||
<Stack width="100%" direction="row" justifyContent="space-between" spacing={2} alignItems="center">
|
||||
{/* {!matchesXs && megaMenu} */}
|
||||
<Typography variant="h5" sx={{ ml: 2, color: '#fff' }} noWrap>
|
||||
{localStorage.getItem('firstname') || ''}
|
||||
</Typography>
|
||||
{matchesXs && <Box sx={{ ml: 1 }} />}
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<Box sx={{ flexShrink: 0, ml: 0.75 }}>
|
||||
<Tooltip title="Quick Menu" placement="left-start">
|
||||
<IconButton
|
||||
// color="secondary"
|
||||
// variant="light"
|
||||
// sx={{
|
||||
// color: 'text.primary',
|
||||
// bgcolor: open ? iconBackColorOpen : iconBackColor
|
||||
// }}
|
||||
sx={{
|
||||
color: '#fff',
|
||||
fontSize: '20px',
|
||||
// bgcolor: open ? iconBackColorOpen : iconBackColor
|
||||
bgcolor: 'transparent'
|
||||
// border:'1px solid #fff'
|
||||
}}
|
||||
aria-label="open profile"
|
||||
// ref={anchorRef}
|
||||
// aria-controls={open ? 'profile-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<WindowsOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Popper
|
||||
open={open}
|
||||
placement="bottom"
|
||||
anchorEl={anchorEl}
|
||||
role={undefined}
|
||||
// transition
|
||||
disablePortal
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
sx={{
|
||||
// backgroundColor:'white',
|
||||
// border:1,
|
||||
p: 0,
|
||||
zIndex: 5000,
|
||||
boxShadow: theme.customShadows.z1
|
||||
}}
|
||||
>
|
||||
<Transitions type="grow" position="top" sx={{ overflow: 'hidden' }} in={open}>
|
||||
{/* <Box sx={{
|
||||
backgroundColor: 'white',
|
||||
border: '1px solid #e0e0e0 !important',
|
||||
borderRadius: 1,
|
||||
}}> */}
|
||||
<Box
|
||||
sx={
|
||||
{
|
||||
// boxShadow: theme.customShadows.z1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<ClickAwayListener onClickAway={handleClickAway}>
|
||||
{/* <List disablePadding> */}
|
||||
<List
|
||||
component="nav"
|
||||
sx={{
|
||||
mt: 1.5,
|
||||
p: 0,
|
||||
width: '100%',
|
||||
minWidth: 200,
|
||||
maxWidth: 290,
|
||||
bgcolor: theme.palette.background.paper,
|
||||
borderRadius: 0.5,
|
||||
[theme.breakpoints.down('md')]: {
|
||||
maxWidth: 250
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemButton
|
||||
selected={location.pathname === '/nearle/orders/create'}
|
||||
onClick={() => {
|
||||
// console.log(const location = useLocation();)
|
||||
navigate('/nearle/orders/create');
|
||||
handleClickAway();
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
|
||||
<TbBoxMultiple1 />
|
||||
</ListItemIcon>
|
||||
<Typography color="textPrimary">Create Order</Typography>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemButton
|
||||
selected={location.pathname === '/nearle/orders/createorders'}
|
||||
onClick={() => {
|
||||
// console.log(const location = useLocation();)
|
||||
navigate('/nearle/orders/createorders');
|
||||
handleClickAway();
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
|
||||
<GrMultiple />
|
||||
</ListItemIcon>
|
||||
<Typography color="textPrimary">Create Multiple Order</Typography>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemButton
|
||||
selected={location.pathname === '/nearle/customer/create'}
|
||||
onClick={() => {
|
||||
navigate('/nearle/customer/create');
|
||||
handleClickAway();
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
|
||||
<TbUserEdit />
|
||||
</ListItemIcon>
|
||||
<Typography color="textPrimary">Create Customer</Typography>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
{/* <ListItemButton
|
||||
selected={location.pathname === '/clients/create'}
|
||||
onClick={() => {
|
||||
navigate('/clients/create')
|
||||
handleClickAway()
|
||||
}} >
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
|
||||
<CustomerServiceOutlined />
|
||||
</ListItemIcon>
|
||||
<Typography color="textPrimary">Create Client</Typography>
|
||||
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton> */}
|
||||
{/* <ListItemButton
|
||||
selected={location.pathname === '/riders/create'}
|
||||
onClick={() => {
|
||||
navigate('/riders/create')
|
||||
handleClickAway()
|
||||
}} >
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
|
||||
<SportsMotorsportsOutlinedIcon />
|
||||
</ListItemIcon>
|
||||
<Typography color="textPrimary">Create Rider</Typography>
|
||||
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton> */}
|
||||
|
||||
{/* <ListItem disablePadding>
|
||||
<ListItemButton sx={{ p: 2 }} onClick={() => {
|
||||
navigate('/create_order')
|
||||
handleClickAway()
|
||||
}}>
|
||||
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
|
||||
<MailOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Create Order" />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton sx={{ p: 2 }} onClick={() => {
|
||||
navigate('/create_client')
|
||||
handleClickAway()
|
||||
}}>
|
||||
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
|
||||
<CustomerServiceOutlined />
|
||||
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Create Client" />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton sx={{ p: 2 }} onClick={() => {
|
||||
navigate('/create_staff')
|
||||
handleClickAway()
|
||||
}}>
|
||||
<ListItemIcon sx={{ mr: 1, fontSize: '20px' }}>
|
||||
<UserOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Create Staff" />
|
||||
</ListItemButton>
|
||||
</ListItem> */}
|
||||
</List>
|
||||
</ClickAwayListener>
|
||||
{/* </Box> */}
|
||||
</Box>
|
||||
</Transitions>
|
||||
</Popper>
|
||||
</Box>
|
||||
|
||||
<Notification />
|
||||
|
||||
{/* <Message /> */}
|
||||
{/* {!matchesXs && <Profile />}
|
||||
{matchesXs && <MobileSection />} */}
|
||||
<Tooltip title="Notifications">
|
||||
<Profile />
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderContent;
|
||||
@@ -1,86 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { AppBar, Toolbar, useMediaQuery } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import AppBarStyled from './AppBarStyled';
|
||||
import HeaderContent from './HeaderContent';
|
||||
import IconButton from 'components/@extended/IconButton';
|
||||
|
||||
import { MenuOrientation, ThemeMode } from 'config';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import { dispatch, useSelector } from 'store';
|
||||
import { openDrawer } from 'store/reducers/menu';
|
||||
|
||||
// assets
|
||||
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| MAIN LAYOUT - HEADER ||============================== //
|
||||
|
||||
const Header = () => {
|
||||
const theme = useTheme();
|
||||
const downLG = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
const { menuOrientation } = useConfig();
|
||||
|
||||
const menu = useSelector((state) => state.menu);
|
||||
const { drawerOpen } = menu;
|
||||
|
||||
const isHorizontal = menuOrientation === MenuOrientation.HORIZONTAL && !downLG;
|
||||
|
||||
// header content
|
||||
const headerContent = useMemo(() => <HeaderContent />, []);
|
||||
|
||||
// common header
|
||||
const mainHeader = (
|
||||
<Toolbar>
|
||||
{!isHorizontal ? (
|
||||
<IconButton
|
||||
aria-label="open drawer"
|
||||
onClick={() => dispatch(openDrawer(!drawerOpen))}
|
||||
edge="start"
|
||||
// color="secondary"
|
||||
// variant="light"
|
||||
// sx={{ color: 'text.primary', bgcolor: drawerOpen ? iconBackColorOpen : iconBackColor, ml: { xs: 0, lg: -2 } }}
|
||||
sx={{ color: '#fff', bgcolor: 'transparent', ml: { xs: 0, lg: -2 },
|
||||
fontSize:'25px',
|
||||
':hover':{
|
||||
color: '#fff', bgcolor: 'transparent'
|
||||
} }}
|
||||
>
|
||||
{!drawerOpen ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
||||
</IconButton>
|
||||
) : null}
|
||||
{headerContent}
|
||||
</Toolbar>
|
||||
);
|
||||
|
||||
// app-bar params
|
||||
const appBar = {
|
||||
position: 'fixed',
|
||||
color: 'inherit',
|
||||
elevation: 0,
|
||||
sx: {
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
zIndex: 1200,
|
||||
width: isHorizontal ? '100%' : drawerOpen ? 'calc(100% - 260px)' : { xs: '100%', lg: 'calc(100% - 60px)' },
|
||||
// boxShadow: theme.customShadows.z1
|
||||
bgcolor:'#662582'
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{!downLG ? (
|
||||
<AppBarStyled open={drawerOpen} {...appBar}>
|
||||
{mainHeader}
|
||||
</AppBarStyled>
|
||||
) : (
|
||||
<AppBar {...appBar}>{mainHeader}</AppBar>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -1,72 +1,58 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useState } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { useMediaQuery, Box, Container, Toolbar } from '@mui/material';
|
||||
// Astryx design system — see themes/astryx.js and CLAUDE.md's Astryx CLI
|
||||
// section. This replaces the old MUI Drawer/Header/HorizontalBar shell;
|
||||
// horizontal menu orientation (config.menuOrientation) was dropped since it
|
||||
// was never exposed as a user-facing toggle in this app — see AppSideNav.js.
|
||||
// AppShell config (variant/height/contentPadding/mobileNav breakpoint) and
|
||||
// the lifted collapse state mirror doormile_crm/src/layout/MainLayout/index.jsx
|
||||
// — that sibling Doormile app's validated Astryx shell.
|
||||
import { AppShell } from '@astryxdesign/core/AppShell';
|
||||
import { Theme } from '@astryxdesign/core/theme';
|
||||
import { doormileTheme } from 'themes/astryx';
|
||||
|
||||
// project import
|
||||
import Drawer from './Drawer';
|
||||
import Header from './Header';
|
||||
import HorizontalBar from './Drawer/HorizontalBar';
|
||||
|
||||
import { MenuOrientation } from 'config';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import { dispatch } from 'store';
|
||||
import { openDrawer } from 'store/reducers/menu';
|
||||
import AppTopNav from './AppTopNav';
|
||||
import AppSideNav from './AppSideNav';
|
||||
|
||||
// ==============================|| MAIN LAYOUT ||============================== //
|
||||
|
||||
const MainLayout = () => {
|
||||
const theme = useTheme();
|
||||
const matchDownXL = useMediaQuery(theme.breakpoints.down('xl'));
|
||||
const downLG = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
const { drawerOpen } = useSelector((state) => state.menu);
|
||||
const { container, miniDrawer, menuOrientation } = useConfig();
|
||||
|
||||
const isHorizontal = menuOrientation === MenuOrientation.HORIZONTAL && !downLG;
|
||||
|
||||
// set media wise responsive drawer
|
||||
useEffect(() => {
|
||||
if (!miniDrawer) {
|
||||
// dispatch(openDrawer(!matchDownXL));
|
||||
dispatch(openDrawer(false));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [matchDownXL]);
|
||||
// Lifted here (rather than left as SideNav's own uncontrolled state) so the
|
||||
// TopNav logo can track the sidebar's collapse state. Defaults to collapsed
|
||||
// on every load/reload (not persisted).
|
||||
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(true);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', width: '100%' }}>
|
||||
<Header />
|
||||
{!isHorizontal ? <Drawer /> : <HorizontalBar />}
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
width: isHorizontal ? '100%' : drawerOpen ? 'calc(100% - 260px)' : { xs: '100%', lg: 'calc(100% - 60px)' },
|
||||
flexGrow: 1,
|
||||
p: { xs: 2, sm: 3 }
|
||||
}}
|
||||
<Theme theme={doormileTheme} mode="light">
|
||||
{/* height="auto" (not doormile_crm's "fill"): "fill" scrolls the
|
||||
content area in its own container, and CLAUDE.md's canonical
|
||||
useInfiniteQuery pattern observes a sentinel against the window's
|
||||
viewport (IntersectionObserver root=null), which only fires
|
||||
correctly with normal document-level scroll. */}
|
||||
<AppShell
|
||||
variant="section"
|
||||
height="auto"
|
||||
contentPadding={0}
|
||||
topNav={<AppTopNav isSidebarCollapsed={isSidebarCollapsed} />}
|
||||
sideNav={<AppSideNav isCollapsed={isSidebarCollapsed} onCollapsedChange={setIsSidebarCollapsed} />}
|
||||
mobileNav={{ breakpoint: 'lg' }}
|
||||
>
|
||||
<Toolbar sx={{ mt: isHorizontal ? 8 : 'inherit' }} />
|
||||
<Container
|
||||
// maxWidth={container ? 'xl' : false}
|
||||
maxWidth
|
||||
sx={{
|
||||
...(container && { px: { xs: 0, sm: 2 } }),
|
||||
position: 'relative',
|
||||
minHeight: 'calc(100vh - 110px)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}
|
||||
>
|
||||
{/* <Breadcrumbs navigation={navigation} title titleBottom card={false} divider={false} /> */}
|
||||
<div className="main-content-area" style={{ minHeight: '100%', boxSizing: 'border-box' }}>
|
||||
<Outlet />
|
||||
{/* <Footer /> */}
|
||||
</Container>
|
||||
</Box>
|
||||
</Box>
|
||||
</div>
|
||||
<style>{`
|
||||
.main-content-area {
|
||||
padding: 24px;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.main-content-area {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</AppShell>
|
||||
</Theme>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user