180 lines
6.2 KiB
JavaScript
180 lines
6.2 KiB
JavaScript
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||
import { useState, useEffect } from "react";
|
||
import LogoDM from "../../../assets/icons/LogoDM.svg";
|
||
import LogoLM from "../../../assets/icons/Logo-LM.svg";
|
||
import { BiBarChartAlt2 } from "react-icons/bi";
|
||
import { AiOutlinePieChart } from "react-icons/ai";
|
||
import { PiCoffee } from "react-icons/pi";
|
||
import { HiOutlineLogout } from "react-icons/hi";
|
||
import { FiMenu, FiX } from "react-icons/fi";
|
||
|
||
|
||
const SIDEBAR = {
|
||
navigation: [
|
||
{
|
||
id: 'dashboard',
|
||
path: '/dashboard',
|
||
icon: BiBarChartAlt2,
|
||
label: 'داشبورد',
|
||
},
|
||
{
|
||
id: 'cafe-management',
|
||
path: '/cafe-management',
|
||
icon: PiCoffee,
|
||
label: 'مدیریت کافه ها',
|
||
},
|
||
{
|
||
id: 'stats',
|
||
path: '/stats',
|
||
icon: AiOutlinePieChart,
|
||
label: 'آمار و تحلیل',
|
||
},
|
||
],
|
||
logout: {
|
||
icon: HiOutlineLogout,
|
||
label: 'خروج',
|
||
},
|
||
styles: {
|
||
activeColor: 'primary',
|
||
inactiveColor: '#402E32',
|
||
borderColor: '#D9CAB3',
|
||
padding: 'p-2.5',
|
||
gap: 'gap-2.5',
|
||
rounded: 'rounded-lg',
|
||
},
|
||
};
|
||
|
||
export default function Sidebar({ className, isOpen, setIsOpen }) {
|
||
const location = useLocation();
|
||
const navigate = useNavigate();
|
||
const [currentLogo, setCurrentLogo] = useState(localStorage.getItem('theme') === 'light' ? LogoDM : LogoLM);
|
||
|
||
useEffect(() => {
|
||
const observer = new MutationObserver(() => {
|
||
setCurrentLogo(localStorage.getItem('theme') === 'light' ? LogoDM : LogoLM);
|
||
});
|
||
|
||
observer.observe(document.documentElement, {
|
||
attributes: true,
|
||
attributeFilter: ['class']
|
||
});
|
||
|
||
return () => observer.disconnect();
|
||
}, []);
|
||
|
||
const isActive = (path) => location.pathname === path;
|
||
|
||
const handleLogout = () => {
|
||
try {
|
||
localStorage.removeItem('accessToken');
|
||
localStorage.removeItem('refreshToken');
|
||
localStorage.removeItem('token');
|
||
localStorage.removeItem('adminInfo');
|
||
|
||
navigate('/login');
|
||
} catch (error) {
|
||
console.error('Logout error:', error);
|
||
navigate('/login');
|
||
}
|
||
};
|
||
|
||
const closeSidebar = () => setIsOpen(false);
|
||
|
||
const renderNavItem = (item) => {
|
||
const Icon = item.icon;
|
||
const active = isActive(item.path);
|
||
|
||
return (
|
||
<Link
|
||
key={item.id}
|
||
to={item.path}
|
||
onClick={closeSidebar}
|
||
className={`group flex items-center ${SIDEBAR.styles.gap} ${SIDEBAR.styles.rounded} ${SIDEBAR.styles.padding} transition-all duration-200 ${active
|
||
? `bg-primary shadow-md`
|
||
: `hover:bg-primary hover:text-text2`
|
||
}`}
|
||
>
|
||
<Icon
|
||
className={`w-5 h-5 flex-shrink-0 text-text1 transition-colors ${active
|
||
? "text-white"
|
||
: `text-[${SIDEBAR.styles.inactiveColor}] group-hover:text-white`
|
||
}`}
|
||
/>
|
||
<span
|
||
className={`text-sm font-medium transition-colors ${active
|
||
? "text-text2"
|
||
: ` text-text1 group-hover:text-white`
|
||
}`}
|
||
>
|
||
{item.label}
|
||
</span>
|
||
</Link>
|
||
);
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<div className="lg:hidden fixed top-0 px-6 bg-header right-0 left-0 z-[70] flex justify-between p-3">
|
||
<button
|
||
onClick={() => setIsOpen(true)}
|
||
className=" text-primary"
|
||
aria-label="Toggle menu"
|
||
>
|
||
<FiMenu className="w-6 h-6" />
|
||
</button>
|
||
|
||
<img src={currentLogo} className="h-12 w-12 " alt="Logo" />
|
||
|
||
</div>
|
||
|
||
{isOpen && (
|
||
<div
|
||
className="lg:hidden fixed inset-0 bg-black/50 z-[60]"
|
||
onClick={closeSidebar}
|
||
/>
|
||
)}
|
||
<aside
|
||
dir="rtl"
|
||
className={`${className}
|
||
transition-transform duration-300 ease-in-out
|
||
${isOpen ? 'translate-x-0' : 'translate-x-full'}
|
||
lg:translate-x-0 lg:w-[220px] bg-header
|
||
`}
|
||
>
|
||
<button
|
||
onClick={() => setIsOpen(false)}
|
||
className="lg:hidden absolute top-4 right-4 z-[70] text-primary p-2.5"
|
||
aria-label="Toggle menu"
|
||
>
|
||
<FiX className="w-6 h-6" />
|
||
</button>
|
||
<div className="flex justify-center mt-5 mb-2">
|
||
<img src={currentLogo} className="h-10 w-10 lg:h-16 lg:w-16" alt="Logo" />
|
||
</div>
|
||
|
||
<nav className="flex-1 px-3 mt-6 space-y-3 overflow-y-auto">
|
||
{SIDEBAR.navigation.map(renderNavItem)}
|
||
</nav>
|
||
|
||
<div className={`p-3 border-t border-[${SIDEBAR.styles.borderColor}]`}>
|
||
<button
|
||
onClick={() => {
|
||
handleLogout();
|
||
closeSidebar();
|
||
}}
|
||
className={`group flex items-center ${SIDEBAR.styles.gap} ${SIDEBAR.styles.rounded} ${SIDEBAR.styles.padding} transition-all duration-200 hover:bg-button1 w-full`}
|
||
>
|
||
{(() => {
|
||
const LogoutIcon = SIDEBAR.logout.icon;
|
||
return <LogoutIcon className="w-5 h-5 flex-shrink-0 text-[#402E32] transition-colors group-hover:text-white" />;
|
||
})()}
|
||
<span className="text-sm text-[#402E32] font-medium transition-colors group-hover:text-white">
|
||
{SIDEBAR.logout.label}
|
||
</span>
|
||
</button>
|
||
</div>
|
||
</aside>
|
||
</>
|
||
);
|
||
};
|