health-apps-cms/src/layouts/mainLayout/components/Sidebar.jsx

357 lines
14 KiB
JavaScript

/* eslint-disable no-unused-vars */
import CloseIcon from "@mui/icons-material/Close";
import {
Accordion,
AccordionDetails,
AccordionSummary,
Box,
List,
ListItem,
ListItemText,
} from "@mui/material";
import React, { useEffect, useState } from "react";
import { NavLink, useLocation } from "react-router-dom";
/* ------------------- Custom Imports ------------------- */
import { useDispatch, useSelector } from "react-redux";
import arrowDownImg from "../../../assets/images/icon/arrow-down.svg"; // Make sure this path is correct
import companyLogo from "../../../assets/images/logo/app.svg"; // Make sure this path is correct
import { HIDE_FUNCTIONALITY } from "../../../common/envVariables";
import { CLINIC_STATUS, HIDE_MODULES } from "../../../constants";
import { isBSPortal } from "../../../utils/share";
import { hideAndShowFunctionality } from "../../../views/Signup/signupAction";
import { useStyles } from "../mainLayoutStyles";
// Import the configuration from the separate file
import { SIDEBAR_CONFIG } from "./sideBarConfig"; // Adjust path if necessary
import {
selectClinicStatus,
selectUserRole,
} from "../../../redux/userRoleSlice";
// NOTE: Removed the internal SIDEBAR_ITEMS definition.
// We will now use the imported SIDEBAR_CONFIG.
// NOTE: Removed direct icon imports as they should come from SIDEBAR_CONFIG
// Ensure @mui/icons-material is installed and icons are correctly referenced in sideBarConfig.js
const Sidebar = ({ onClose, showCloseIcon }) => {
const classes = useStyles();
const location = useLocation();
const { isSuperAdmin } = isBSPortal();
const [activeLink, setActiveLink] = useState("Dashboard");
const [accordianActiveLink, setAccordianActiveLink] = useState("All Jobs");
const [parentRoute, setParentRoute] = useState("");
const [childRoute, setchildRoute] = useState("");
const [combinedRoute, setcombinedRoute] = useState("");
const dispatch = useDispatch();
const clinicStatus = useSelector(selectClinicStatus);
// Assuming companyStatus is fetched or defined elsewhere correctly
const companyStatus = "APPROVED"; // Example status, replace with actual logic if needed
const handleHideFeatures = (hideFeatures) => {
if (hideFeatures) {
dispatch(hideAndShowFunctionality({ hideFeatures }));
}
};
useEffect(() => {
const { pathname } = location;
// Ensure pathname splitting is safe
const pathParts = pathname?.split?.("/") ?? [];
const activeLinkFromPath = pathParts[1] ?? ""; // Default to empty string if no segment
const accordianActiveLinkFromPath = pathParts[2]; // Can be undefined
if (accordianActiveLinkFromPath) {
setParentRoute(activeLinkFromPath);
setchildRoute(accordianActiveLinkFromPath);
setcombinedRoute(`${activeLinkFromPath}/${accordianActiveLinkFromPath}`);
} else {
setParentRoute(""); // Reset if no child route
setchildRoute("");
setcombinedRoute("");
}
// Set active link based on the first path segment, default to '' which matches Dashboard path
setActiveLink(activeLinkFromPath || ""); // Use '' for Dashboard path
// Set accordion active link based on the full path segment if available
setAccordianActiveLink(activeLinkFromPath ? `${activeLinkFromPath}` : "");
}, [location]);
// Get companyId at the component level
const companyId = useSelector(
(state) => state?.loginAsCompanyAdmin?.companyId // Make sure this selector path is correct
);
// Get current user role from Redux store
const userRole = useSelector((state) => state.userRole.role);
// Function to determine visibility and render a single sidebar item link
// The checkVisibility function with fixed logic
const checkVisibility = (item, i) => {
// Check if the user has the necessary role for this item
const hasRole = !item.roles || item.roles.includes(userRole);
// Only render if user has the required role
if (hasRole) {
// Determine if the link should be disabled
// FIXED LOGIC: If clinic status is rejected, only allow "/" and "/docs" paths
const isDisabled = (clinicStatus === "rejected" || clinicStatus === "under_review" || clinicStatus === "payment_due") && !(item.path == "" || item.path == "docs");
// Set the correct target path
const targetPath = isDisabled ? "#" : `/${item.path}`;
const isActive = activeLink === item.path; // Check if this link is the active one
return (
<Box
className={classes.marginBottom}
onClick={() => handleHideFeatures(isDisabled)} // Pass isDisabled to handleHideFeatures
key={item.path || i} // Use a stable key like item.path
>
<NavLink
className={`${isActive ? classes.activeLink : ""} ${
classes.textDecorationNone
} ${isDisabled ? classes.disabledLink : ""}`}
to={targetPath}
// Prevent navigation for disabled links
onClick={(e) => {
if (isDisabled) e.preventDefault();
handleLinkClick(item.path); // Set active link on click
}}
>
<ListItem
button // Make it clear it's clickable
className={`${classes.listItem} ${
isActive && classes.activeLink
}`}
disabled={isDisabled} // Visually disable the ListItem as well
>
<Box className={classes.sidebarListImg}>
{isActive
? React.createElement(item.activeIcon, {
className: classes.sidebarLinkIcons,
})
: React.createElement(item.icon, {
className: classes.sidebarLinkIcons,
style: { color: "black" },
})}
</Box>
<ListItemText
primary={item.text}
primaryTypographyProps={{
className: isActive
? classes.activeLinkTextColor
: classes.normalLinkTextColor,
}}
/>
</ListItem>
</NavLink>
</Box>
);
}
return null; // Return null if item shouldn't be rendered
};
// Function to render a sidebar item that has children (accordion)
const rendersideMenu = (item, i) => {
// Check if the parent item has the necessary role
const hasParentRole = !item.roles || item.roles.includes(userRole);
// Only proceed if the parent item has the necessary role
if (!hasParentRole) return null;
// Filter visible children first
const visibleChildren = item.children
?.filter((childItem) => {
// Check if child has the necessary role
const hasChildRole =
!childItem.roles || childItem.roles.includes(userRole);
return hasChildRole;
})
.filter(Boolean); // Filter out any null/undefined results
// Only render the accordion if there are visible children
if (!visibleChildren || visibleChildren.length === 0) {
return null;
}
// Check if the current parent route matches this accordion item's path
const isParentActive =
activeLink === parentRoute && item.path === parentRoute;
return (
<React.Fragment key={item.path || i}>
{" "}
{/* Use stable key */}
<Accordion
disableGutters
elevation={0}
className={`${classes.accordionDiv} ${classes.marginBottom}`}
// Control expanded state based on parentRoute matching item.path
expanded={item.path === parentRoute}
// Prevent accordion expansion/collapse if parent link is clicked directly?
// onChange={(event, isExpanded) => {
// // Handle accordion expansion logic if needed, e.g., update parentRoute
// // setParentRoute(isExpanded ? item.path : "");
// }}
>
<AccordionSummary
className={`${classes.listItem} ${
isParentActive ? classes.activeLink : "" // Apply active styles based on parentRoute
} ${classes.accordionSummary}`}
expandIcon={
<Box>
<img src={arrowDownImg} alt="Expand" />
</Box>
}
// Clicking the summary might navigate or just expand/collapse
// Consider if clicking the summary should set the activeLink or parentRoute
onClick={() => {
// Toggle parent route or handle navigation
// If clicking the parent should navigate, handle it here
// If it just expands/collapses, maybe update parentRoute state
setParentRoute(item.path === parentRoute ? "" : item.path); // Basic toggle example
}}
>
<Box className={classes.sidebarListImg}>
{/* Use the helper function to render the icon */}
{activeLink === item.path
? React.createElement(item.activeIcon, {
className: classes.sidebarLinkIcons,
})
: React.createElement(item.icon, {
className: classes.sidebarLinkIcons,
style: { color: "black" },
})}
</Box>
{/* Removed redundant Box wrapping ListItem */}
<ListItemText
primary={item.text}
primaryTypographyProps={{
className: isParentActive
? classes.activeLinkTextColor
: classes.normalLinkTextColor,
}}
/>
</AccordionSummary>
<AccordionDetails>
<List component="div" disablePadding className={classes.listClass}>
{/* Removed unnecessary <ul> */}
{visibleChildren.map((subItem, subIndex) => {
// Determine if the sub-item link should be disabled
const isSubDisabled =
!isSuperAdmin && companyStatus !== CLINIC_STATUS.APPROVED; // Add hideFeature logic if needed for sub-items
const subTargetPath = isSubDisabled ? "#" : `/${subItem.path}`;
const isSubActive = combinedRoute === subItem.path; // Check if this child link is active
return (
<NavLink
key={subItem.path || subIndex} // Use stable key
to={subTargetPath}
className={classes.textDecorationNone}
onClick={(e) => {
if (isSubDisabled) e.preventDefault();
// Set parent and child routes on click
setParentRoute(item.path); // Ensure parent is marked active
setchildRoute(subItem.path.split("/")[1]); // Extract child part
handleAccordianLinkClick(subItem.path); // Update combined route state
}}
>
{/* Use ListItem for better structure and accessibility */}
<ListItem
button
key={subItem.path || subIndex}
disableRipple={true}
className={classes.dotOuterDiv} // Apply styling class to ListItem
disabled={isSubDisabled}
>
<div
className={`${classes.dotInnerDiv} ${
isSubActive
? classes.activeLinkChildrenBackgroundColor
: classes.normalLinkChildrenBackgroundColor
}`}
></div>
<ListItemText
primary={subItem.text}
primaryTypographyProps={{
className: isSubActive
? classes.activeLinkChildrenTextColor
: classes.normalLinkChildrenTextColor,
}}
/>
</ListItem>
</NavLink>
);
})}
{/* Removed unnecessary </ul> */}
</List>
</AccordionDetails>
</Accordion>
</React.Fragment>
);
};
const closeSidebar = () => {
if (onClose) {
// Check if onClose is provided
onClose();
}
};
// Sets the main active link (top-level or parent of accordion)
const handleLinkClick = (linkPath) => {
// If the clicked link is part of an accordion, don't reset parentRoute
const clickedItem = SIDEBAR_CONFIG.find((item) => item.path === linkPath);
if (!clickedItem?.children) {
setParentRoute(""); // Reset parent route if it's a top-level link
setchildRoute(""); // Reset child route
setcombinedRoute(""); // Reset combined route
}
setActiveLink(linkPath);
};
// Sets the active state for accordion children links
const handleAccordianLinkClick = (fullPath) => {
// Accordion link click implies a parent is active
// We already set parentRoute and childRoute in the NavLink onClick
setcombinedRoute(fullPath); // Update the combined route state
// Optionally update activeLink to the parent path if needed for styling
// setActiveLink(fullPath.split('/')[0]);
};
return (
<Box className={classes.sidebarMain}>
{/* Only show close icon if prop is true */}
{showCloseIcon && (
<Box sx={{ textAlign: "right", padding: 1 }}>
{" "}
{/* Added some padding/alignment */}
<CloseIcon
className={classes.blackColor} // Ensure this class provides styling
onClick={closeSidebar}
sx={{ cursor: "pointer" }} // Make it look clickable
/>
</Box>
)}
<Box className={classes.companyImgDiv}>
{/* Ensure companyLogo is imported correctly and alt text is descriptive */}
<img
className={classes.companyImg}
src={companyLogo}
alt="Company Logo"
/>
</Box>
{/* Use the imported SIDEBAR_CONFIG */}
<List className={classes?.listMainDiv}>
{SIDEBAR_CONFIG?.map((item, i) =>
// Render either an accordion menu or a direct link
item.children ? rendersideMenu(item, i) : checkVisibility(item, i)
)}
</List>
</Box>
);
};
export default Sidebar;