/* * Copyright © 2024 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). */ import { faBars } from "@fortawesome/free-solid-svg-icons"; import AddIcon from "@mui/icons-material/Add"; import { Box, Button, debounce, Grid, Paper } from "@mui/material"; import { useRef, useState } from "react"; import { ConfirmDialogBody } from "@/app-components/dialogs"; import { NoDataOverlay } from "@/app-components/tables/NoDataOverlay"; import { useDelete } from "@/hooks/crud/useDelete"; import { useFind } from "@/hooks/crud/useFind"; import { useDialogs } from "@/hooks/useDialogs"; import { useHasPermission } from "@/hooks/useHasPermission"; import { useTranslate } from "@/hooks/useTranslate"; import { PageHeader } from "@/layout/content/PageHeader"; import { EntityType } from "@/services/types"; import { PermissionAction } from "@/types/permission.types"; import MenuAccordion from "./MenuAccordion"; import { MenuFormDialog } from "./MenuFormDialog"; export const Menu = () => { const { t } = useTranslate(); const dialogs = useDialogs(); const hasPermission = useHasPermission(); const { data: menus, refetch } = useFind( { entity: EntityType.MENUTREE }, { hasCount: false, }, ); const { mutate: deleteMenu } = useDelete(EntityType.MENU, { onSuccess: () => { refetch(); }, }); const [position, setPosition] = useState(0); const ref = useRef(null); const [shadowVisible, setShadowVisible] = useState(false); return ( {hasPermission(EntityType.MENU, PermissionAction.CREATE) ? ( ) : null} { if (!ref.current) return; const padding = 16; const boxHeight = 56; const mousePositionInsideElement = e.clientY - ref.current?.getBoundingClientRect().top - padding; const currentBlock = Math.floor( mousePositionInsideElement / boxHeight, ); const maxBlock = Math.floor( (ref.current.getBoundingClientRect().height - padding - 1) / boxHeight, ); const step = Math.max(0, Math.min(currentBlock, maxBlock - 1)); if (maxBlock <= 0) { setShadowVisible(false); return; } setPosition(step * boxHeight + padding); }, 0)} sx={{ padding: 2, position: "relative", overFlow: "hidden" }} onMouseLeave={() => setShadowVisible(false)} onMouseEnter={() => setShadowVisible(true)} > {menus?.length > 0 && ( )} {menus?.length === 0 && } {menus?.map((menu) => ( dialogs.open(MenuFormDialog, { parentId })} onUpdate={(row) => dialogs.open(MenuFormDialog, { row })} onDelete={async (row) => { const isConfirmed = await dialogs.confirm(ConfirmDialogBody); if (isConfirmed) { deleteMenu(row.id); } }} /> ))} ); };