/**
* Constains the menu that is opened by the burguer icon in the navbar
*
* @module
*/
import React from "react";
import Link from "../../../components/navigation/Link";
import { ModuleProvider } from "../../../providers/module";
import AppLanguageRetriever from "../../../components/localization/AppLanguageRetriever";
import UserDataRetriever from "../../../components/user/UserDataRetriever";
import I18nRead, { II18nReadProps } from "../../../components/localization/I18nRead";
import LocationReader from "../../../components/navigation/LocationReader";
import { NoStateItemProvider } from "../../../providers/item";
import ListItemIcon from "@mui/material/ListItemIcon";
import Badge from "@mui/material/Badge";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
import List from "@mui/material/List";
import Divider from "@mui/material/Divider";
import SwipeableDrawer from "@mui/material/SwipeableDrawer";
import { styled } from "@mui/material/styles";
/**
* The menu styles
*/
const menuStyles = {
list: {
width: "250px",
},
listLink: {
textDecoration: "none",
color: "inherit",
},
};
type PathRetriever = (path: string) => React.ReactNode;
type PathRetrieverFn = (ele: PathRetriever) => React.ReactNode;
/**
* The menu entry itself that specifies
* how a menu is to be built
*/
export interface IMenuEntry {
/**
* The path it will take to, aka, the navigation
* location
*/
path: string | PathRetrieverFn;
/**
* The icon to use
*/
icon: React.ReactNode,
/**
* A badge to display
*/
badgeContent?: React.ReactNode;
/**
* The module to load in the module provider (optional)
*/
module?: string;
/**
* The item definition to load in the item definition provider (optional)
* will need the module specified if this one specified
*/
idef?: string;
/**
* The arguments to pass to the i18nRead element in order to display some text
*/
i18nProps: II18nReadProps;
/**
* The role that has access to this
*/
role?: string;
/**
* Many roles, a list of roles, role (Single) has priority over this
*/
roles?: string[];
/**
* A wrapper to wrap the content
*/
wrapper?: (entry: React.ReactNode) => React.ReactNode;
/**
* A wrapper key to use, normally it'd use the path as the wrapper key
* but if path is a function you rather specify this
*/
wrapperKey?: string;
}
/**
* The menu properties with the styles attached
*/
interface IMenuProps {
/**
* Whether the menu is open
*/
isOpen: boolean;
/**
* A callback for when it has opened
*/
onOpen: () => void;
/**
* A callback for when it closes
*/
onClose: () => void;
/**
* The admin entries that appear on top
*/
adminEntries: IMenuEntry[];
/**
* The standard entries
*/
entries: IMenuEntry[];
}
const StyledLink = styled(Link)(menuStyles.listLink);
/**
* Given entries, will build an entry list so that it is displayed in the menu
* list
* @param entries the entries to use
* @param role the role that the current user is logged as
*/
function buildEntryFromList(entries: IMenuEntry[], role: string) {
// so we start looping
return entries.map((entry) => {
// first we check if the role is there and if it doesn't match
// do the same with the many roles
if (entry.role && role !== entry.role) {
return null;
} else if (entry.roles && !entry.roles.includes(role)) {
return null;
}
// now we need to see how we are going to approach this, this
// will be the display text
let i18nNodeInfo: React.ReactNode = null;
// with both idef and module specified
if (entry.idef && entry.module) {
// it's done like this, with a no state as we don't need the state
i18nNodeInfo =
(
);
// with only the module itself
} else if (entry.module) {
// we use only the module context
i18nNodeInfo =
(
);
} else {
// otherwise it's just plain like this
i18nNodeInfo = ;
}
let icon: React.ReactNode = (
{entry.icon}
);
if (entry.badgeContent) {
icon = {entry.icon}
}
const elementPathFn = (path: string) => (
{(arg) => (
{icon}
{i18nNodeInfo}
)}
);
const element = typeof entry.path === "string" ? elementPathFn(entry.path) : entry.path(elementPathFn);
if (entry.wrapper) {
return (
{entry.wrapper(element)}
);
}
// now we can return this
return element;
})
}
const StyledDivList = styled("div")(menuStyles.list);
/**
* Provides a menu for the navbar
* @param props the menu props
* @returns a react element
*/
export function Menu(props: IMenuProps) {
// so we render in here, first we need our language retriever to do the rtl thing
return (
{(retriever) => (
{(userData) => (
<>
{
props.adminEntries.length ?
<>
{buildEntryFromList(props.adminEntries, userData.role)}
> :
null
}
{buildEntryFromList(props.entries, userData.role)}
>
)}
)}
)
};