diff --git a/.prettierrc b/.prettierrc
index 39eed9eea..55ea2b2d1 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,4 +1,4 @@
{
"tabWidth": 4,
- "useTabs": false,
+ "useTabs": false
}
diff --git a/src/App.tsx b/src/App.tsx
index d1e4ed967..5bd54bcb3 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,6 +1,5 @@
import React from "react";
import { APIProvider } from "@vis.gl/react-google-maps";
-import { MenuMainContainer } from "./navigation/MenuMainContainer";
import "./index.css";
import "./App.css";
import CssBaseline from "@mui/material/CssBaseline";
@@ -24,6 +23,7 @@ import SnackNotificationBar from "./components/SnackNotificationBar";
import TenantListProvider from "./scenes/TenantPicker/TenantListProvider";
import { initialiseApp } from "./redux/initialise/initialiseActions";
import * as Sentry from "@sentry/react";
+import { MenuMainContainer } from "./navigation/MenuMainContainer";
const GOOGLE_MAPS_API_KEY = process.env.REACT_APP_GOOGLE_MAPS_API_KEY as string;
@@ -124,41 +124,30 @@ const App = (props: any) => {
});
}
- if (process.env.REACT_APP_DEMO_MODE === "true") {
- return (
-
-
-
-
+ return (
+
+
+
+
+
+ {process.env.REACT_APP_DEMO_MODE === "true" ? (
-
-
-
-
-
- );
- } else {
- return (
-
-
-
-
+ ) : (
-
-
-
-
-
- );
- }
+ )}
+
+
+
+
+ );
};
export default App;
diff --git a/src/navigation/MainWindow.js b/src/navigation/MainWindow.js
index e4275ea82..ab67cf707 100644
--- a/src/navigation/MainWindow.js
+++ b/src/navigation/MainWindow.js
@@ -1,4 +1,3 @@
-import React from "react";
import "../index.css";
import { Route, Switch, useLocation } from "react-router-dom";
import Dashboard from "../scenes/Dashboard/Dashboard";
@@ -31,12 +30,17 @@ import ScheduledTaskOverviewRoute from "../scenes/ScheduledTasks/components/Sche
const useStyles = makeStyles()((theme, { navIndex, guidedSetupOpen }) => ({
root: {
+ [theme.breakpoints.up("sm")]: {
+ display: "flex",
+ flex: 1,
+ },
marginRight: guidedSetupOpen && navIndex === "dashboard" ? 0 : "auto",
marginLeft: navIndex === "dashboard" ? 0 : 20,
- paddingTop: 20,
+ paddingTop: 78,
paddingBottom: 10,
+ minWidth: 0,
[theme.breakpoints.down("md")]: {
- paddingTop: 5,
+ // paddingTop: 5,
marginLeft: 0,
marginRight: 0,
},
@@ -57,7 +61,7 @@ export default function MainWindow(_props) {
// whenever returning an item, set the MenuIndex to update the drawer menu
return (
-
+
{
+const useStyles2 = makeStyles()((theme) => {
return {
appBarComponents: {
margin: "auto",
@@ -40,54 +47,82 @@ const useStyles = makeStyles()((theme) => {
};
});
+interface AppBarProps extends MuiAppBarProps {
+ isXs: boolean;
+ open: boolean;
+}
+
+const AppBar = styled(MuiAppBar, {
+ shouldForwardProp: (prop) => prop !== "open" && prop !== "isXs",
+})(({ theme, open, isXs }) => ({
+ zIndex: theme.zIndex.drawer + 1,
+ background: theme.palette.background.paper,
+ transition: theme.transitions.create(["width", "margin"], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ boxShadow:
+ "0px 2px 0px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12)",
+ ...(open &&
+ !isXs && {
+ // marginLeft: drawerWidth,
+ // width: `calc(100% - ${drawerWidth}px)`,
+ transition: theme.transitions.create(["width", "margin"], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ }),
+}));
+
export function MenuMainContainer() {
- const { classes } = useStyles();
- const [searchMode, setSearchMode] = useState(false);
- const dashboardTabIndex = useSelector(dashboardTabIndexSelector);
const menuIndex = useSelector(menuIndexSelector);
- const currentFilter = useSelector(dashboardFilterTermSelector);
- const toggleIcon = searchMode ? : ;
+ const dashboardTabIndex = useSelector(dashboardTabIndexSelector);
+ const { classes } = useStyles2();
+ const theme = useTheme();
+ const isXs = useMediaQuery(theme.breakpoints.down("sm"));
+ const [open, setOpen] = React.useState(false);
+ const [searchMode, setSearchMode] = React.useState(false);
const dispatch = useDispatch();
-
+ const toggleIcon = searchMode ? : ;
const toggleSearchMode = () => {
if (searchMode) dispatch(clearDashboardFilter());
setSearchMode(!searchMode);
};
- const theme = useTheme();
- const isSm = useMediaQuery(theme.breakpoints.down("md"));
- const isXs = useMediaQuery(theme.breakpoints.down("sm"));
+ useCordovaBackButton(() => {
+ if (isXs) {
+ setOpen(false);
+ }
+ }, open);
- const updateSearchMode = React.useCallback(
- (currentFilter, menuIndex, isSm) => {
- if (menuIndex !== "dashboard") {
- setSearchMode(false);
- dispatch(clearDashboardFilter());
- } else if (currentFilter && isSm) {
- setSearchMode((prevState) => {
- if (!prevState) return true;
- else return prevState;
- });
- }
- },
- [dispatch]
- );
+ const handleDrawerOpen = () => {
+ setOpen(true);
+ };
- useEffect(
- () => updateSearchMode(currentFilter, menuIndex, isSm),
- [currentFilter, isSm, menuIndex, updateSearchMode]
- );
+ const toggleOpen = () => {
+ if (open) {
+ handleDrawerClose();
+ } else {
+ handleDrawerOpen();
+ }
+ };
- useEffect(() => {
- if (!isSm && searchMode) setSearchMode(false);
- }, [isSm, searchMode]);
+ const handleDrawerClose = () => {
+ setOpen(false);
+ };
return (
-
-
+
+
+
-
+
{menuIndex === "dashboard" && (
@@ -153,7 +188,18 @@ export function MenuMainContainer() {
)}
-
-
+
+
+
+
+
);
}
diff --git a/src/navigation/MobileNavigationDrawer.js b/src/navigation/MobileNavigationDrawer.js
deleted file mode 100644
index 46b426e86..000000000
--- a/src/navigation/MobileNavigationDrawer.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import React, { useState } from "react";
-import NavDrawerItems from "./NavDrawerItems";
-import IconButton from "@mui/material/IconButton";
-import MenuIcon from "@mui/icons-material/Menu";
-import { makeStyles } from 'tss-react/mui';
-import ArrowBackIcon from "@mui/icons-material/ArrowBack";
-import { Stack, SwipeableDrawer } from "@mui/material";
-import { useCordovaBackButton } from "../hooks/useCordovaBackButton";
-
-const useStyles = makeStyles()({
- list: {
- width: 250,
- },
-});
-
-export default function MobileNavigationDrawer() {
- const [open, setOpen] = useState(false);
- const { classes } = useStyles();
-
- useCordovaBackButton(() => {
- setOpen(false);
- }, open);
-
- const toggleDrawer = (event) => {
- if (
- event &&
- event.type === "keydown" &&
- (event.key === "Tab" || event.key === "Shift")
- ) {
- return;
- }
- setOpen(!open);
- };
-
- return (
-
-
-
-
-
toggleDrawer(false)}
- onOpen={() => toggleDrawer(true)}
- >
-
- toggleDrawer(false)}>
-
-
- setOpen(false)}
- />
-
-
-
- );
-}
diff --git a/src/navigation/sidebar/Sidebar.tsx b/src/navigation/sidebar/Sidebar.tsx
new file mode 100644
index 000000000..90148d341
--- /dev/null
+++ b/src/navigation/sidebar/Sidebar.tsx
@@ -0,0 +1,130 @@
+import {
+ Stack,
+ useMediaQuery,
+ useTheme,
+ styled,
+ CSSObject,
+ Theme,
+ Drawer as MuiDrawer,
+} from "@mui/material";
+import { makeStyles } from "tss-react/mui";
+import { SidebarDrawerItems } from "./SidebarDrawerItems";
+
+export const drawerWidth = 250;
+
+const useStyles = makeStyles()({
+ list: {
+ width: drawerWidth,
+ },
+ closedList: {
+ width: "100%",
+ },
+ // topBox: {
+ // height: 58,
+ // alignContent: "center",
+ // },
+ stack: {
+ paddingTop: 58,
+ },
+});
+
+const openedMixin = (theme: Theme): CSSObject => ({
+ width: drawerWidth,
+ transition: theme.transitions.create("width", {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ overflowX: "hidden",
+});
+
+const closedMixin = (theme: Theme): CSSObject => ({
+ transition: theme.transitions.create("width", {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ overflowX: "hidden",
+ width: `calc(${theme.spacing(7)} + 1px)`,
+ [theme.breakpoints.up("sm")]: {
+ width: `calc(${theme.spacing(8)} + 1px)`,
+ },
+});
+
+const Drawer = styled(MuiDrawer, {
+ shouldForwardProp: (prop) => prop !== "isXs",
+})<{
+ open: boolean;
+ isXs: boolean;
+}>(({ theme, open, isXs }) => {
+ if (isXs) {
+ // Do not override styles for temporary drawer (mobile)
+ return {};
+ }
+ // Only apply mini-variant styles for permanent drawer
+ return {
+ display: "flex",
+ width: drawerWidth,
+ flexShrink: 0,
+ whiteSpace: "nowrap",
+ boxSizing: "border-box",
+ background: theme.palette.background.paper,
+ borderRight: 0,
+ ...(open
+ ? {
+ ...openedMixin(theme),
+ "& .MuiDrawer-paper": openedMixin(theme),
+ }
+ : {
+ ...closedMixin(theme),
+ "& .MuiDrawer-paper": closedMixin(theme),
+ }),
+ };
+});
+
+export interface SidebarProps {
+ onClose: () => void;
+ open: boolean; // Optional prop to control the open state
+}
+
+export const Sidebar: React.FC = ({ onClose, open }) => {
+ const theme = useTheme();
+ const isXs = useMediaQuery(theme.breakpoints.down("sm"));
+ const { classes } = useStyles();
+
+ // For temporary drawer, pass onClose prop so it can close on backdrop click
+ return (
+
+
+ {/*
+
+
+
+ */}
+
+
+
+ );
+};
diff --git a/src/navigation/NavDrawerItems.js b/src/navigation/sidebar/SidebarDrawerItems.tsx
similarity index 50%
rename from src/navigation/NavDrawerItems.js
rename to src/navigation/sidebar/SidebarDrawerItems.tsx
index 0af6c0811..a5a34e8a3 100644
--- a/src/navigation/NavDrawerItems.js
+++ b/src/navigation/sidebar/SidebarDrawerItems.tsx
@@ -1,25 +1,35 @@
-import React from "react";
+import { FC } from "react";
import { useSelector } from "react-redux";
-import { ListItem, ListItemIcon, ListItemText } from "@mui/material";
-import TwoWheelerIcon from "@mui/icons-material/TwoWheeler";
-import PeopleAltIcon from "@mui/icons-material/PeopleAlt";
-import SupervisorAccountIcon from "@mui/icons-material/SupervisorAccount";
+import { getWhoami } from "../../redux/Selectors";
+import {
+ ListItemIcon,
+ ListItemText,
+ List,
+ ListItemButton,
+} from "@mui/material";
import { Link } from "react-router-dom";
-import Divider from "@mui/material/Divider";
-import * as models from "../models";
-import List from "@mui/material/List";
-import PropTypes from "prop-types";
-import DashboardIcon from "@mui/icons-material/Dashboard";
-import LocationCityIcon from "@mui/icons-material/LocationCity";
-import BarChartIcon from "@mui/icons-material/BarChart";
-import DescriptionIcon from "@mui/icons-material/Description";
-import { getWhoami } from "../redux/Selectors";
-import HistoryIcon from "@mui/icons-material/History";
-import CalendarMonthIcon from "@mui/icons-material/CalendarMonth";
+import {
+ SupervisorAccount,
+ Dashboard,
+ LocationCity,
+ BarChart,
+ Description,
+ History,
+ CalendarMonth,
+ PeopleAlt,
+ TwoWheeler,
+} from "@mui/icons-material";
+import * as models from "../../models";
-function NavDrawerItems(props) {
+export interface SidebarDrawerItemsProps {
+ open?: boolean;
+ className?: string;
+ onSelect: () => void;
+}
+
+export const SidebarDrawerItems: FC = (props) => {
const whoami = useSelector(getWhoami);
- const menuIndex = useSelector((state) => state.menuIndex);
+ const menuIndex = useSelector((state) => state.menuIndex);
const onSelect = props.onSelect;
let adminLink = <>>;
let historyLink = <>>;
@@ -29,18 +39,17 @@ function NavDrawerItems(props) {
if (whoami.roles) {
if (whoami.roles.includes("ADMIN")) {
adminLink = (
-
-
+
-
-
+ {props.open ? : <>>}
+
);
}
if (
@@ -48,114 +57,105 @@ function NavDrawerItems(props) {
whoami.roles.includes(models.Role.COORDINATOR)
) {
historyLink = (
-
-
+
-
-
+ {props.open ? : <>>}
+
);
statisticsLink = (
-
-
+
-
-
+ {props.open ? : <>>}
+
);
scheduledTasksLink = (
-
-
+
-
-
+ {props.open ? : <>>}
+
);
}
}
return (
-
-
-
+
-
+
-
-
- : <>>}
+
+
-
+
-
-
- : <>>}
+
+
-
+
-
-
- : <>>}
+
+
-
+
-
-
- : <>>}
+
+
-
+
-
-
+ {props.open ? : <>>}
+
{scheduledTasksLink}
{statisticsLink}
{historyLink}
@@ -163,15 +163,4 @@ function NavDrawerItems(props) {
);
-}
-
-NavDrawerItems.propTypes = {
- onSelect: PropTypes.func,
- className: PropTypes.string,
};
-
-NavDrawerItems.defaultProps = {
- onSelect: () => {},
-};
-
-export default NavDrawerItems;
diff --git a/src/navigation/sidebar/TopbarButton.tsx b/src/navigation/sidebar/TopbarButton.tsx
new file mode 100644
index 000000000..088c7e2cb
--- /dev/null
+++ b/src/navigation/sidebar/TopbarButton.tsx
@@ -0,0 +1,14 @@
+import { IconButton } from "@mui/material";
+import MenuIcon from "@mui/icons-material/Menu";
+
+export interface TopbarButtonProps {
+ onClick: () => void;
+}
+
+export const TopbarButton: React.FC = ({ onClick }) => {
+ return (
+
+
+
+ );
+};