help-desk/web/src/components/SidebarSubmenu.jsx

89 lines
4.0 KiB
JavaScript

import ChevronDownIcon from '@heroicons/react/24/outline/ChevronDownIcon';
import { useEffect, useState } from 'react';
import { NavLink, useLocation } from 'react-router-dom';
import { useSelector } from 'react-redux';
function SidebarSubmenu({ submenu, name, icon, closeMobileSidebar }) {
const location = useLocation();
const [isExpanded, setIsExpanded] = useState(false);
// ดึง Role จาก Redux
const userRole = useSelector(state => state.auth.role);
// ฟังก์ชันตรวจสอบสิทธิ์
const canAccess = (requiredRole) => {
// userRole ที่มาจาก Redux ควรเป็นตัวพิมพ์ใหญ่แล้ว
if (!requiredRole) return true;
const allowedRoles = Array.isArray(requiredRole)
? requiredRole
: [requiredRole];
return allowedRoles.includes(userRole);
};
// เปิด Submenu หาก Path ปัจจุบันอยู่ใน Submenu นั้น
useEffect(() => {
// ตรวจสอบว่ามีเมนูย่อยใดที่ผู้ใช้เข้าถึงได้และเป็น Path ปัจจุบันหรือไม่
const isActive = submenu.some(
// ใช้ userRole ใน canAccess
m => canAccess(m.requiredRole) && m.path === location.pathname
);
if (isActive) {
setIsExpanded(true);
}
}, [location.pathname, submenu, userRole]);
return (
<div className='flex flex-col'>
{/** Route header */}
<a
className='w-full block cursor-pointer flex items-center justify-between text-base'
onClick={() => setIsExpanded(!isExpanded)}
>
<div className="flex items-center">
{icon}
<span className="ml-3 whitespace-nowrap">{name}</span>
</div>
<ChevronDownIcon
className={'w-5 h-5 mt-1 float-right delay-400 duration-500 transition-all ' +
(isExpanded ? 'rotate-180' : '')}
/>
</a>
{/** Submenu list */}
<div className={` w-full ` + (isExpanded ? "" : "hidden")}>
<ul className={`menu menu-compact`}>
{submenu.map((m, k) => {
// กรองเมนูย่อยตามสิทธิ์ (RBAC)
if (!canAccess(m.requiredRole)) return null;
return (
<li key={k}>
{/* ใช้ NavLink เพื่อแสดงสถานะ Active และใช้ onClick เพื่อปิด Sidebar (สำหรับ Mobile) */}
<NavLink
to={m.path}
onClick={closeMobileSidebar}
className={({ isActive }) =>
`text-base ${isActive ? 'bg-base-200 text-primary font-semibold' : 'hover:bg-base-400'}`
}
>
{m.icon} {m.name}
{/* แถบสี Primary แสดงสถานะ Active */}
{location.pathname === m.path ? (
<span
className="absolute mt-1 mb-1 inset-y-0 left-0 w-1 rounded-tr-md rounded-br-md bg-primary "
aria-hidden="true"
></span>
) : null}
</NavLink>
</li>
);
})}
</ul>
</div>
</div>
);
}
export default SidebarSubmenu;