import * as React from "react"; import { useTheme } from "@mui/material/styles"; import useMediaQuery from "@mui/material/useMediaQuery"; import Box from "@mui/material/Box"; import Drawer from "@mui/material/Drawer"; import List from "@mui/material/List"; import Toolbar from "@mui/material/Toolbar"; import type {} from "@mui/material/themeCssVarsAugmentation"; import PersonIcon from "@mui/icons-material/Person"; import BarChartIcon from "@mui/icons-material/BarChart"; import DescriptionIcon from "@mui/icons-material/Description"; import LayersIcon from "@mui/icons-material/Layers"; import { matchPath, useLocation } from "react-router"; import DashboardSidebarContext from "./DashboardSidebarContext"; import { DRAWER_WIDTH, MINI_DRAWER_WIDTH } from "./constants"; import DashboardSidebarPageItem from "./DashboardSidebarPageItem"; import DashboardSidebarHeaderItem from "./DashboardSidebarHeaderItem"; import DashboardSidebarDividerItem from "./DashboardSidebarDividerItem"; import { getDrawerSxTransitionMixin, getDrawerWidthTransitionMixin, } from "./mixins"; export interface DashboardSidebarProps { expanded?: boolean; setExpanded: (expanded: boolean) => void; disableCollapsibleSidebar?: boolean; container?: Element; } export default function DashboardSidebar({ expanded = true, setExpanded, disableCollapsibleSidebar = false, container, }: DashboardSidebarProps) { const theme = useTheme(); const { pathname } = useLocation(); const [expandedItemIds, setExpandedItemIds] = React.useState([]); const isOverSmViewport = useMediaQuery(theme.breakpoints.up("sm")); const isOverMdViewport = useMediaQuery(theme.breakpoints.up("md")); const [isFullyExpanded, setIsFullyExpanded] = React.useState(expanded); const [isFullyCollapsed, setIsFullyCollapsed] = React.useState(!expanded); React.useEffect(() => { if (expanded) { const drawerWidthTransitionTimeout = setTimeout(() => { setIsFullyExpanded(true); }, theme.transitions.duration.enteringScreen); return () => clearTimeout(drawerWidthTransitionTimeout); } setIsFullyExpanded(false); return () => {}; }, [expanded, theme.transitions.duration.enteringScreen]); React.useEffect(() => { if (!expanded) { const drawerWidthTransitionTimeout = setTimeout(() => { setIsFullyCollapsed(true); }, theme.transitions.duration.leavingScreen); return () => clearTimeout(drawerWidthTransitionTimeout); } setIsFullyCollapsed(false); return () => {}; }, [expanded, theme.transitions.duration.leavingScreen]); const mini = !disableCollapsibleSidebar && !expanded; const handleSetSidebarExpanded = React.useCallback( (newExpanded: boolean) => () => { setExpanded(newExpanded); }, [setExpanded] ); const handlePageItemClick = React.useCallback( (itemId: string, hasNestedNavigation: boolean) => { if (hasNestedNavigation && !mini) { setExpandedItemIds((previousValue) => previousValue.includes(itemId) ? previousValue.filter( (previousValueItemId) => previousValueItemId !== itemId ) : [...previousValue, itemId] ); } else if (!isOverSmViewport && !hasNestedNavigation) { setExpanded(false); } }, [mini, setExpanded, isOverSmViewport] ); const hasDrawerTransitions = isOverSmViewport && (!disableCollapsibleSidebar || isOverMdViewport); const getDrawerContent = React.useCallback( (viewport: "phone" | "tablet" | "desktop") => ( Main items } href="/employees" selected={ !!matchPath("/employees/*", pathname) || pathname === "/" } /> Example items } href="/reports" selected={!!matchPath("/reports", pathname)} defaultExpanded={!!matchPath("/reports", pathname)} expanded={expandedItemIds.includes("reports")} nestedNavigation={ } href="/reports/sales" selected={!!matchPath("/reports/sales", pathname)} /> } href="/reports/traffic" selected={!!matchPath("/reports/traffic", pathname)} /> } /> } href="/integrations" selected={!!matchPath("/integrations", pathname)} /> ), [mini, hasDrawerTransitions, isFullyExpanded, expandedItemIds, pathname] ); const getDrawerSharedSx = React.useCallback( (isTemporary: boolean) => { const drawerWidth = mini ? MINI_DRAWER_WIDTH : DRAWER_WIDTH; return { displayPrint: "none", width: drawerWidth, flexShrink: 0, ...getDrawerWidthTransitionMixin(expanded), ...(isTemporary ? { position: "absolute" } : {}), [`& .MuiDrawer-paper`]: { position: "absolute", width: drawerWidth, boxSizing: "border-box", backgroundImage: "none", ...getDrawerWidthTransitionMixin(expanded), }, }; }, [expanded, mini] ); const sidebarContextValue = React.useMemo(() => { return { onPageItemClick: handlePageItemClick, mini, fullyExpanded: isFullyExpanded, fullyCollapsed: isFullyCollapsed, hasDrawerTransitions, }; }, [ handlePageItemClick, mini, isFullyExpanded, isFullyCollapsed, hasDrawerTransitions, ]); return ( {getDrawerContent("phone")} {getDrawerContent("tablet")} {getDrawerContent("desktop")} ); }