/* * QQQ - Low-code Application Framework for Engineers. * Copyright (C) 2021-2022. Kingsrook, LLC * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States * contact@kingsrook.com * https://github.com/Kingsrook/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import {QBrandingMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QBrandingMetaData"; import Box from "@mui/material/Box"; import Divider from "@mui/material/Divider"; import Icon from "@mui/material/Icon"; import Link from "@mui/material/Link"; import List from "@mui/material/List"; import {ReactNode, useEffect, useReducer, useState} from "react"; import {NavLink, useLocation} from "react-router-dom"; import AuthenticationButton from "qqq/components/buttons/AuthenticationButton"; import SideNavCollapse from "qqq/components/horseshoe/sidenav/SideNavCollapse"; import SideNavItem from "qqq/components/horseshoe/sidenav/SideNavItem"; import SideNavList from "qqq/components/horseshoe/sidenav/SideNavList"; import SidenavRoot from "qqq/components/horseshoe/sidenav/SideNavRoot"; import sidenavLogoLabel from "qqq/components/horseshoe/sidenav/styles/SideNav"; import MDTypography from "qqq/components/legacy/MDTypography"; import {setMiniSidenav, setTransparentSidenav, setWhiteSidenav, useMaterialUIController,} from "qqq/context"; interface Props { color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark"; icon?: string; logo?: string; appName?: string; branding?: QBrandingMetaData; routes: { [key: string]: | ReactNode | string | { [key: string]: | ReactNode | string | { [key: string]: | ReactNode | string | { [key: string]: ReactNode | string; }[]; }[]; }[]; }[]; [key: string]: any; } function Sidenav({color, icon, logo, appName, branding, routes, ...rest}: Props): JSX.Element { const [openCollapse, setOpenCollapse] = useState(false); const [openNestedCollapse, setOpenNestedCollapse] = useState(false); const [controller, dispatch] = useMaterialUIController(); const {miniSidenav, transparentSidenav, whiteSidenav, darkMode} = controller; const location = useLocation(); const {pathname} = location; const collapseName = pathname.split("/").slice(1)[0]; const items = pathname.split("/").slice(1); const itemParentName = items[1]; const itemName = items[items.length - 1]; const [, forceUpdate] = useReducer((x) => x + 1, 0); let textColor: | "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark" | "white" | "inherit" | "text" | "light" = "white"; if (transparentSidenav || (whiteSidenav && !darkMode)) { textColor = "dark"; } else if (whiteSidenav && darkMode) { textColor = "inherit"; } const closeSidenav = () => setMiniSidenav(dispatch, true); useEffect(() => { setOpenCollapse(collapseName); setOpenNestedCollapse(itemParentName); }, []); useEffect(() => { // A function that sets the mini state of the sidenav. function handleMiniSidenav() { setMiniSidenav(dispatch, window.innerWidth < 1200); setTransparentSidenav(dispatch, window.innerWidth < 1200 ? false : transparentSidenav); setWhiteSidenav(dispatch, window.innerWidth < 1200 ? false : whiteSidenav); } /** The event listener that's calling the handleMiniSidenav function when resizing the window. */ window.addEventListener("resize", handleMiniSidenav); window.onload = () => { forceUpdate(); }; // Call the handleMiniSidenav function to set the state with the initial value. handleMiniSidenav(); // Remove event listener on cleanup return () => window.removeEventListener("resize", handleMiniSidenav); }, [dispatch, location]); // Render all the nested collapse items from the routes.js const renderNestedCollapse = (collapse: any) => { const template = collapse.map(({name, route, key, href}: any) => href ? ( ) : ( ) ); return template; }; // Render the all the collpases from the routes.js const renderCollapse = (collapses: any) => collapses.map(({name, collapse, route, href, key}: any) => { let returnValue; if (collapse) { returnValue = ( openNestedCollapse === key && currentTarget.classList.contains("MuiListItem-root") ? setOpenNestedCollapse(false) : setOpenNestedCollapse(key) } > {renderNestedCollapse(collapse)} ); } else { returnValue = href ? ( ) : ( ); } return {returnValue}; }); // Render all the routes from the routes.js (All the visible items on the Sidenav) const renderRoutes = routes.map( ({type, name, icon, title, collapse, noCollapse, key, href, route}: any) => { let returnValue; if (type === "collapse") { if (href) { returnValue = ( ); } else if (noCollapse && route) { returnValue = ( {collapse ? renderCollapse(collapse) : null} ); } else { returnValue = ( (! noCollapse ? (openCollapse === key ? setOpenCollapse(false) : setOpenCollapse(key)) : null) } > {collapse ? renderCollapse(collapse) : null} ); } } else if (type === "title") { returnValue = ( {title} ); } else if (type === "divider") { returnValue = ( ); } return returnValue; } ); return ( close {!miniSidenav && logo && } {miniSidenav && icon && } {!miniSidenav && !logo && appName && sidenavLogoLabel(theme, {miniSidenav})}> {appName} } { branding && branding.environmentBannerText && {branding.environmentBannerText} } {renderRoutes} ); } // Declaring default props for Sidenav Sidenav.defaultProps = { color: "info", icon: "", logo: "", appName: "", }; export default Sidenav;