import React, { type CSSProperties, useState } from "react"; import Box from "@mui/material/Box"; import Drawer from "@mui/material/Drawer"; import List from "@mui/material/List"; import ListItemButton from "@mui/material/ListItemButton"; import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemText from "@mui/material/ListItemText"; import Collapse from "@mui/material/Collapse"; import Tooltip from "@mui/material/Tooltip"; import IconButton from "@mui/material/IconButton"; import Paper from "@mui/material/Paper"; import ListOutlined from "@mui/icons-material/ListOutlined"; import Logout from "@mui/icons-material/Logout"; import ExpandLess from "@mui/icons-material/ExpandLess"; import ExpandMore from "@mui/icons-material/ExpandMore"; import ChevronLeft from "@mui/icons-material/ChevronLeft"; import Dashboard from "@mui/icons-material/Dashboard"; import { CanAccess, type TreeMenuItem, useIsExistAuthentication, useLogout, useTranslate, useLink, useMenu, useActiveAuthProvider, useWarnAboutChange, } from "@refinedev/core"; import type { RefineThemedLayoutSiderProps } from "../types"; import { ThemedTitle as DefaultTitle } from "@components"; import { useThemedLayoutContext } from "@hooks"; export const ThemedSider: React.FC = ({ Title: TitleFromProps, render, meta, activeItemDisabled = false, siderItemsAreCollapsed = true, }) => { const { siderCollapsed, setSiderCollapsed, mobileSiderOpen, setMobileSiderOpen, } = useThemedLayoutContext(); const drawerWidth = () => { if (siderCollapsed) return 56; return 240; }; const t = useTranslate(); const Link = useLink(); const translate = useTranslate(); const { menuItems, selectedKey, defaultOpenKeys } = useMenu({ meta }); const isExistAuthentication = useIsExistAuthentication(); const authProvider = useActiveAuthProvider(); const { warnWhen, setWarnWhen } = useWarnAboutChange(); const { mutate: mutateLogout } = useLogout(); const defaultExpandMenuItems = (() => { const defaultOpenKeys = {}; if (siderItemsAreCollapsed) return defaultOpenKeys; return menuItems.reduce((prev, curr) => { const { key } = curr; return { ...prev, [key]: true, }; }, {}); })(); const [open, setOpen] = useState<{ [k: string]: any }>( defaultExpandMenuItems, ); React.useEffect(() => { setOpen((previous) => { const previousKeys: string[] = Object.keys(previous); const previousOpenKeys = previousKeys.filter((key) => previous[key]); const uniqueKeys = new Set([...previousOpenKeys, ...defaultOpenKeys]); const uniqueKeysRecord = Object.fromEntries( Array.from(uniqueKeys.values()).map((key) => [key, true]), ); return uniqueKeysRecord; }); }, [defaultOpenKeys]); const RenderToTitle = TitleFromProps ?? DefaultTitle; const handleClick = (key: string) => { setOpen({ ...open, [key]: !open[key] }); }; const renderTreeView = (tree: TreeMenuItem[], selectedKey?: string) => { return tree.map((item: TreeMenuItem) => { const { icon, label, route, name, children, meta } = item; const isOpen = open[item.key || ""] || false; const isSelected = item.key === selectedKey; const isNested = !(meta?.parent === undefined); if (children.length > 0) { return (
{ if (siderCollapsed) { setSiderCollapsed(false); if (!isOpen) { handleClick(item.key || ""); } } else { handleClick(item.key || ""); } }} sx={{ pl: isNested ? 4 : 2, justifyContent: "center", }} > {icon ?? } {isOpen ? ( ) : ( )} {!siderCollapsed && ( {renderTreeView(children, selectedKey)} )}
); } const linkStyle: CSSProperties = activeItemDisabled && isSelected ? { pointerEvents: "none" } : {}; return ( { setMobileSiderOpen(false); }} sx={{ pl: isNested ? 4 : 2, py: isNested ? 1.25 : 1, justifyContent: "center", color: isSelected ? "primary.main" : "text.primary", }} > {icon ?? } ); }); }; const dashboard = ( { setMobileSiderOpen(false); }} > ); const handleLogout = () => { if (warnWhen) { const confirm = window.confirm( t( "warnWhenUnsavedChanges", "Are you sure you want to leave? You have unsaved changes.", ), ); if (confirm) { setWarnWhen(false); mutateLogout(); } } else { mutateLogout(); } }; const logout = isExistAuthentication && ( handleLogout()} sx={{ justifyContent: "center", }} > ); const items = renderTreeView(menuItems, selectedKey); const renderSider = () => { if (render) { return render({ logout, items, collapsed: siderCollapsed, }); } return ( <> {dashboard} {items} {logout} ); }; const drawer = ( {renderSider()} ); return ( <> setMobileSiderOpen(false)} ModalProps={{ keepMounted: true, // Better open performance on mobile. }} sx={{ display: { sm: "block", md: "none", }, }} > {drawer} `1px solid ${theme.palette.action.focus}`, }} > {!siderCollapsed && ( setSiderCollapsed(true)}> {} )} {drawer} ); };