LeftMenuSubMenu is not a function compontnet rather than a class

This commit is contained in:
Colin Dawson 2026-01-31 15:08:23 +00:00
parent 9fad05fd6d
commit 92eb37a6c5
2 changed files with 68 additions and 61 deletions

View File

@ -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<typeof Namespaces.Common>();
const [openMenuItem, setOpenMenuItem] = useState<LOCLeftMenuSubMenu>();
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 && (
<LeftMenuSubMenu
openMenu={openMenuItem}
menuId="admin"
openMenuId={openMenuItem?.id}
icon={faCog}
label={t("Admin")}
onClick={handleClick}
onToggle={handleClick}
>
{viewUser && <LeftMenuItem to="/users" label={t("Users")} />}
{viewDomain && (
@ -98,10 +106,11 @@ const LeftMenu: React.FC = () => {
{viewSupport && (
<LeftMenuSubMenu
openMenu={openMenuItem}
menuId="support"
openMenuId={openMenuItem?.id}
icon={faCogs}
label={t("Support")}
onClick={handleClick}
onToggle={handleClick}
>
{viewAuditLog && <LeftMenuItem to="/audit" label={t("AuditLog")} />}
{viewBlockedIPAddresses && (
@ -114,9 +123,7 @@ const LeftMenu: React.FC = () => {
)}
</div>
{openMenuItem && (
<div className="subbar">{openMenuItem.props.children}</div>
)}
{openMenuItem && <div className="subbar">{openMenuItem.children}</div>}
</>
);
};

View File

@ -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<LeftMenuSubMenuProps> = ({
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 (
<div className={className} onClick={this.handleClick}>
<FontAwesomeIcon className="leftMenuItemIcon" icon={icon} />
<div className="leftMenuItemLabel">{label}</div>
</div>
);
if (selected) {
className += " leftMenuSubMenuOpen";
}
}
const LeftMenuSubMenu = withRouter(LOCLeftMenuSubMenu);
return (
<div className={className} onClick={handleClick}>
<FontAwesomeIcon className="leftMenuItemIcon" icon={icon} />
<div className="leftMenuItemLabel">{label}</div>
</div>
);
};
export default LeftMenuSubMenu;
export { LOCLeftMenuSubMenu };