diff --git a/src/modules/frame/components/LeftMenu.tsx b/src/modules/frame/components/LeftMenu.tsx index f79e4b6..d5e75b1 100644 --- a/src/modules/frame/components/LeftMenu.tsx +++ b/src/modules/frame/components/LeftMenu.tsx @@ -8,14 +8,16 @@ import { faPrint, } from "@fortawesome/pro-thin-svg-icons"; import LeftMenuItem from "./LeftMenuItem"; -import LeftMenuSubMenu, { LOCLeftMenuSubMenu } from "./LeftMenuSubMenu"; +import LeftMenuSubMenu from "./LeftMenuSubMenu"; import { useTranslation } from "react-i18next"; import { Namespaces } from "../../../i18n/i18n"; const LeftMenu: React.FC = () => { const { t } = useTranslation(); - const [openMenuItem, setOpenMenuItem] = useState(); + const [openMenuItem, setOpenMenuItem] = useState< + { id: string; children: React.ReactNode } | undefined + >(); // Close menus when clicking outside useEffect(() => { @@ -24,9 +26,14 @@ const LeftMenu: React.FC = () => { return () => document.body.removeEventListener("click", handleClick, true); }, []); - const handleClick = useCallback((menuItem: LOCLeftMenuSubMenu) => { - setOpenMenuItem((current) => (current === menuItem ? undefined : menuItem)); - }, []); + const handleClick = useCallback( + (menuId: string, children: React.ReactNode) => { + setOpenMenuItem((current) => + current?.id === menuId ? undefined : { id: menuId, children }, + ); + }, + [], + ); // Access checks const viewOrganisation = authentication.hasAccess("ViewOrganisation"); @@ -69,10 +76,11 @@ const LeftMenu: React.FC = () => { {viewAdmin && ( {viewUser && } {viewDomain && ( @@ -98,10 +106,11 @@ const LeftMenu: React.FC = () => { {viewSupport && ( {viewAuditLog && } {viewBlockedIPAddresses && ( @@ -114,9 +123,7 @@ const LeftMenu: React.FC = () => { )} - {openMenuItem && ( -
{openMenuItem.props.children}
- )} + {openMenuItem &&
{openMenuItem.children}
} ); }; diff --git a/src/modules/frame/components/LeftMenuSubMenu.tsx b/src/modules/frame/components/LeftMenuSubMenu.tsx index 575550c..4ae5c62 100644 --- a/src/modules/frame/components/LeftMenuSubMenu.tsx +++ b/src/modules/frame/components/LeftMenuSubMenu.tsx @@ -1,76 +1,76 @@ import { IconDefinition } from "@fortawesome/fontawesome-common-types"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import React from "react"; -import withRouter, { RouterProps } from "../../../utils/withRouter"; +import React, { useCallback, useMemo } from "react"; +import { useLocation } from "react-router-dom"; -interface LeftMenuSubMenuProps extends RouterProps { +interface LeftMenuSubMenuProps { icon: IconDefinition; label: string; - openMenu?: LOCLeftMenuSubMenu; + menuId: string; + openMenuId?: string; children: (false | JSX.Element)[]; - onClick?: (menuItem: LOCLeftMenuSubMenu) => void; + onToggle?: (menuId: string, children: React.ReactNode) => void; } -interface LeftMenuSubMenuState {} +const LeftMenuSubMenu: React.FC = ({ + icon, + label, + menuId, + openMenuId, + children, + onToggle, +}) => { + const { pathname } = useLocation(); -class LOCLeftMenuSubMenu extends React.Component< - LeftMenuSubMenuProps, - LeftMenuSubMenuState -> { - state = {}; + const handleClick = useCallback((): void => { + if (onToggle !== undefined) onToggle(menuId, children); + }, [children, menuId, onToggle]); - handleClick = (): void => { - const { onClick } = this.props; + const isChildSelected = useCallback( + (child: JSX.Element): boolean => { + const { to } = child.props; + let isSelected: boolean = false; + if ( + to === "/" ? pathname === to : pathname.toLowerCase().startsWith(to) + ) { + isSelected = true; + } - if (onClick !== undefined) onClick(this); - }; - - isChildSelected = (child: JSX.Element): boolean => { - const { to } = child.props; - const { pathname } = this.props.router.location; - let isSelected: boolean = false; - if (to === "/" ? pathname === to : pathname.toLowerCase().startsWith(to)) { - isSelected = true; - } - - return isSelected; - }; - - isAnyChildSelected = (): boolean => { - const { children } = this.props; + return isSelected; + }, + [pathname], + ); + const isAnyChildSelected = useCallback((): boolean => { let childIsSelected = false; children.forEach((child) => { if (child === false) { return; } - if (this.isChildSelected(child)) childIsSelected = true; + if (isChildSelected(child)) childIsSelected = true; }); return childIsSelected; - }; + }, [children, isChildSelected]); - render() { - const { icon, label, openMenu } = this.props; + const selected = useMemo( + () => openMenuId === menuId || isAnyChildSelected(), + [isAnyChildSelected, menuId, openMenuId], + ); - const selected = this === openMenu || this.isAnyChildSelected(); + let className = "LeftMenuItem leftMenuSubMenu"; - let className = "LeftMenuItem leftMenuSubMenu"; - - if (selected) { - className += " leftMenuSubMenuOpen"; - } - - return ( -
- -
{label}
-
- ); + if (selected) { + className += " leftMenuSubMenuOpen"; } -} -const LeftMenuSubMenu = withRouter(LOCLeftMenuSubMenu); + return ( +
+ +
{label}
+
+ ); +}; + export default LeftMenuSubMenu; -export { LOCLeftMenuSubMenu };