/*
* 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;