sideMenu for mobile and desktop

main
alex 2023-10-22 12:11:23 +02:00
parent f06265008c
commit 1ca13395e5
5 changed files with 170 additions and 109 deletions

View File

@ -1,20 +1,70 @@
import { Layout } from "antd"; import { Grid, Layout } from "antd";
import SideMenu from "../SideMenu"; import { SideMenuContent } from "../SideMenu";
import PageContent from "../PageContent"; import PageContent from "../PageContent";
import { useState } from "react"; import { useRef, useState } from "react";
import SideMenuMobile from "../SideMenu/Mobile";
import SideMenuDesktop from "../SideMenu/Desktop";
const { useBreakpoint } = Grid;
const Content = ({
isSideMenuCollapsed,
setIsSideMenuCollapsed,
setUserSession,
userSession,
contentFirstRender,
}) => {
return (
<SideMenuContent
isSideMenuCollapsed={isSideMenuCollapsed}
setIsSideMenuCollapsed={setIsSideMenuCollapsed}
setUserSession={setUserSession}
userSession={userSession}
contentFirstRender={contentFirstRender}
/>
);
};
export default function DashboardLayout({ userSession, setUserSession }) { export default function DashboardLayout({ userSession, setUserSession }) {
const [isSideMenuCollapsed, setIsSideMenuCollapsed] = useState(false); const screenBreakpoint = useBreakpoint();
// open on desktop, closed on mobile on page open
const [isSideMenuCollapsed, setIsSideMenuCollapsed] = useState(
!screenBreakpoint.lg
);
// used to prevent auto close the sideMenu on mobile on first render as the the useEffect on the content component will be called after the first render
const contentFirstRender = useRef(true);
return ( return (
<Layout style={{ minHeight: "100vh" }}> <Layout style={{ minHeight: "100vh" }}>
<Layout> <Layout>
<SideMenu {screenBreakpoint.lg ? (
userSession={userSession} <SideMenuDesktop
setUserSession={setUserSession} isSideMenuCollapsed={
isSideMenuCollapsed={isSideMenuCollapsed} screenBreakpoint.lg ? isSideMenuCollapsed : true
setIsSideMenuCollapsed={setIsSideMenuCollapsed} }
/> setIsSideMenuCollapsed={setIsSideMenuCollapsed}
>
<Content
setIsSideMenuCollapsed={setIsSideMenuCollapsed}
userSession={userSession}
setUserSession={setUserSession}
contentFirstRender={contentFirstRender}
/>
</SideMenuDesktop>
) : (
<SideMenuMobile
isSideMenuCollapsed={isSideMenuCollapsed}
setIsSideMenuCollapsed={setIsSideMenuCollapsed}
>
<Content
setIsSideMenuCollapsed={setIsSideMenuCollapsed}
userSession={userSession}
setUserSession={setUserSession}
contentFirstRender={contentFirstRender}
/>
</SideMenuMobile>
)}
<PageContent <PageContent
isSideMenuCollapsed={isSideMenuCollapsed} isSideMenuCollapsed={isSideMenuCollapsed}

View File

@ -2,13 +2,22 @@ import { Content } from "antd/es/layout/layout";
import AppRoutes from "../AppRoutes"; import AppRoutes from "../AppRoutes";
import { Layout } from "antd"; import { Layout } from "antd";
import HeaderMenu from "../Header"; import HeaderMenu from "../Header";
import { BreakpointLgWidth } from "../../utils";
export default function PageContent({ export default function PageContent({
isSideMenuCollapsed, isSideMenuCollapsed,
setIsSideMenuCollapsed, setIsSideMenuCollapsed,
}) { }) {
return ( return (
<Layout style={{ marginLeft: isSideMenuCollapsed ? 0 : 200 }}> <Layout
style={{
marginLeft:
isSideMenuCollapsed ||
window.document.body.clientWidth < BreakpointLgWidth
? 0
: 200,
}}
>
<HeaderMenu <HeaderMenu
isSideMenuCollapsed={isSideMenuCollapsed} isSideMenuCollapsed={isSideMenuCollapsed}
setIsSideMenuCollapsed={setIsSideMenuCollapsed} setIsSideMenuCollapsed={setIsSideMenuCollapsed}

View File

@ -0,0 +1,27 @@
import Sider from "antd/es/layout/Sider";
export default function SideMenuDesktop({
children,
isSideMenuCollapsed,
setIsSideMenuCollapsed,
}) {
return (
<Sider
theme="light"
style={{
overflow: "auto",
height: "100vh",
position: "fixed",
left: 0,
top: 0,
bottom: 0,
}}
breakpoint="lg"
collapsedWidth={1}
collapsed={isSideMenuCollapsed}
onCollapse={(collapsed) => setIsSideMenuCollapsed(collapsed)}
>
{children}
</Sider>
);
}

View File

@ -0,0 +1,18 @@
import { Drawer } from "antd";
export default function SideMenuMobile({
children,
isSideMenuCollapsed,
setIsSideMenuCollapsed,
}) {
return (
<Drawer
open={!isSideMenuCollapsed}
onClose={() => setIsSideMenuCollapsed(true)}
placement="left"
styles={{ body: { padding: 0 } }}
>
{children}
</Drawer>
);
}

View File

@ -13,11 +13,10 @@ import {
UsergroupAddOutlined, UsergroupAddOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Badge, Divider, Menu } from "antd"; import { Badge, Divider, Menu } from "antd";
import Sider from "antd/es/layout/Sider";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import PropTypes from "prop-types";
import { import {
BreakpointLgWidth,
BrowserTabSession, BrowserTabSession,
Constants, Constants,
hasOnePermission, hasOnePermission,
@ -31,11 +30,11 @@ import { useAppContext } from "../../Contexts/AppContext";
import { useWebSocketContext } from "../../Contexts/WebSocketContext"; import { useWebSocketContext } from "../../Contexts/WebSocketContext";
import { SentMessagesCommands } from "../../Handlers/WebSocketMessageHandler"; import { SentMessagesCommands } from "../../Handlers/WebSocketMessageHandler";
export default function SideMenu({ export function SideMenuContent({
userSession, userSession,
setUserSession, setUserSession,
isSideMenuCollapsed,
setIsSideMenuCollapsed, setIsSideMenuCollapsed,
contentFirstRender,
}) { }) {
const appContext = useAppContext(); const appContext = useAppContext();
const webSocketContext = useWebSocketContext(); const webSocketContext = useWebSocketContext();
@ -45,22 +44,10 @@ export default function SideMenu({
const { t } = useTranslation(); const { t } = useTranslation();
const lastSubscribedTopic = useRef(""); const lastSubscribedTopic = useRef("");
console.log("SideMenuContent");
const navigate = useNavigate(); const navigate = useNavigate();
const getCurrentUsedScannerName = () => {
/*const scannerName = webSocketContext.Scanners.find(
(scanner) => scanner.UsedByUserId === getUserId()
)?.Name;
return scannerName === undefined
? t("sideMenu.adminArea.noScannerSelected")
: scannerName; */
// TODO: handle scanner name
return Constants.LOADING;
};
const getFirstMenuItems = () => { const getFirstMenuItems = () => {
// dashboard // dashboard
let items = [ let items = [
@ -256,18 +243,11 @@ export default function SideMenu({
let items = []; let items = [];
// scanner // scanner
if ( items.push({
hasPermission( icon: <ScanOutlined />,
appContext.userPermissions, label: "Scanner",
Constants.PERMISSIONS.SCANNER.USE_SCANNERS key: Constants.ROUTE_PATHS.SCANNERS,
) });
) {
items.push({
icon: <ScanOutlined />,
label: getCurrentUsedScannerName(),
key: Constants.ROUTE_PATHS.SCANNERS,
});
}
// connection status, userprofile, logout // connection status, userprofile, logout
items.push( items.push(
@ -324,89 +304,66 @@ export default function SideMenu({
}); });
// auto close sideMenu on mobile // auto close sideMenu on mobile
// this will prevent to auto close sideMenu on first render as the useEffects will be called after the first render
if (contentFirstRender.current) {
contentFirstRender.current = false;
return;
}
if ( if (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent navigator.userAgent
) ) ||
document.body.clientWidth < BreakpointLgWidth
) { ) {
console.log("close");
setIsSideMenuCollapsed(true); setIsSideMenuCollapsed(true);
} }
}, [location.pathname]); }, [location.pathname]);
return ( return (
<Sider <div
theme="light"
style={{ style={{
overflow: "auto", display: "flex",
height: "100vh", justifyContent: "space-between",
position: "fixed", flexDirection: "column",
left: 0, height: "100%",
top: 0,
bottom: 0,
}} }}
breakpoint="lg"
collapsedWidth={1}
collapsed={isSideMenuCollapsed}
onCollapse={(collapsed) => setIsSideMenuCollapsed(collapsed)}
> >
<div <div>
style={{ <div className="CompanyNameContainer">
display: "flex", <span>C</span>
justifyContent: "space-between", <span>O</span>
flexDirection: "column", <span>M</span>
height: "100%", <span>P</span>
}} <span>A</span>
> <span>N</span>
<div> <span>Y</span>
<div className="CompanyNameContainer">
<span>C</span>
<span>O</span>
<span>M</span>
<span>P</span>
<span>A</span>
<span>N</span>
<span>Y</span>
</div>
<div className="Subtitle">Admin Dashboard</div>
<Menu
mode="inline"
onClick={(item) => navigate(item.key)}
theme="light"
selectedKeys={[selectedKeys]}
items={getFirstMenuItems()}
defaultOpenKeys={["/admin-area", "/group-tasks"]}
/>
</div> </div>
<div> <div className="Subtitle">Admin Dashboard</div>
<Divider />
<Menu <Menu
selectable={true} mode="inline"
selectedKeys={[selectedKeys]} onClick={(item) => navigate(item.key)}
mode="vertical" theme="light"
onClick={(item) => navigate(item.key)} selectedKeys={[selectedKeys]}
items={getSecondMenuItems()} items={getFirstMenuItems()}
/> defaultOpenKeys={["/admin-area", "/group-tasks"]}
</div> />
</div> </div>
</Sider>
<div>
<Divider />
<Menu
selectable={true}
selectedKeys={[selectedKeys]}
mode="vertical"
onClick={(item) => navigate(item.key)}
items={getSecondMenuItems()}
/>
</div>
</div>
); );
} }
/*
<div className="CompanyNameContainer">
<span>J</span>
<span>A</span>
<span>N</span>
<span>N</span>
<span>E</span>
<span>X</span>
</div>
*/
SideMenu.propTypes = {
setUserSession: PropTypes.func.isRequired,
};