307 lines
10 KiB
TypeScript
307 lines
10 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
|
import { useTheme } from '../contexts/ThemeContext';
|
|
import {
|
|
LayoutDashboard,
|
|
Package,
|
|
Wrench,
|
|
Menu,
|
|
X,
|
|
Moon,
|
|
Sun,
|
|
LogOut,
|
|
ClipboardList,
|
|
Calendar
|
|
} from 'lucide-react';
|
|
|
|
interface SidebarLink {
|
|
id: string;
|
|
title: string;
|
|
icon: React.ReactNode;
|
|
path: string;
|
|
visible: boolean;
|
|
}
|
|
|
|
interface SidebarProps {
|
|
userEmail?: string;
|
|
}
|
|
|
|
const Sidebar: React.FC<SidebarProps> = ({ userEmail }) => {
|
|
const [isCollapsed, setIsCollapsed] = useState(false);
|
|
const location = useLocation();
|
|
const navigate = useNavigate();
|
|
const { theme, toggleTheme } = useTheme();
|
|
|
|
const handleLogout = () => {
|
|
localStorage.removeItem('user');
|
|
localStorage.removeItem('sid');
|
|
navigate('/login');
|
|
};
|
|
|
|
// Role-based visibility logic
|
|
// const isMaintenanceManagerKASH = userEmail === 'maintenancemanager-kash@gmail.com';
|
|
// const isMaintenanceManagerTH = userEmail === 'maintenancemanager-th@gmail.com';
|
|
// const isMaintenanceManagerDAJH = userEmail === 'maintenancemanager-dajh@gmail.com';
|
|
const isFinanceManager = userEmail === 'financemanager@gmail.com';
|
|
const isEndUser = userEmail && (
|
|
userEmail.startsWith('enduser1-kash') ||
|
|
userEmail.startsWith('enduser1-dajh') ||
|
|
userEmail.startsWith('enduser1-th')
|
|
);
|
|
// const isTechnician = userEmail && (
|
|
// userEmail.startsWith('technician1-kash') ||
|
|
// userEmail.startsWith('technician1-dajh') ||
|
|
// userEmail.startsWith('technician1-th')
|
|
// );
|
|
|
|
const showAsset = !isFinanceManager && !isEndUser;
|
|
// const showInventory = !isFinanceManager && !isEndUser;
|
|
const showPreventiveMaintenance = !isFinanceManager && !isEndUser;
|
|
const showGeneralWO = !isFinanceManager && !isEndUser;
|
|
// const showAMTeam = !isFinanceManager && !isEndUser;
|
|
// const showProjectDashboard = !isMaintenanceManagerKASH && !isMaintenanceManagerTH && !isMaintenanceManagerDAJH && !isFinanceManager && !isEndUser && !isTechnician;
|
|
// const showSiteDashboards = !isFinanceManager && !isEndUser;
|
|
// const showSupplierDashboard = !isFinanceManager && !isEndUser;
|
|
// const showSLA = !isFinanceManager && !isEndUser && !isTechnician;
|
|
// const showSiteInfo = !isFinanceManager && !isEndUser;
|
|
|
|
const links: SidebarLink[] = [
|
|
{
|
|
id: 'dashboard',
|
|
title: 'Dashboard',
|
|
icon: <LayoutDashboard size={20} />,
|
|
path: '/dashboard',
|
|
visible: true
|
|
},
|
|
{
|
|
id: 'assets',
|
|
title: 'Assets',
|
|
icon: <Package size={20} />,
|
|
path: '/assets',
|
|
visible: showAsset
|
|
},
|
|
{
|
|
id: 'work-orders',
|
|
title: 'Work Orders',
|
|
icon: <ClipboardList size={20} />,
|
|
path: '/work-orders',
|
|
visible: showGeneralWO
|
|
},
|
|
{
|
|
id: 'maintenance',
|
|
title: 'Asset Maintenance',
|
|
icon: <Wrench size={20} />,
|
|
path: '/maintenance',
|
|
visible: showPreventiveMaintenance
|
|
},
|
|
{
|
|
id: 'ppm',
|
|
title: 'PPM',
|
|
icon: <Calendar size={20} />,
|
|
path: '/ppm',
|
|
visible: showPreventiveMaintenance
|
|
},
|
|
// {
|
|
// id: 'inventory',
|
|
// title: 'Inventory',
|
|
// icon: <Package size={20} />,
|
|
// path: '/inventory',
|
|
// visible: showInventory
|
|
// },
|
|
// {
|
|
// id: 'vendors',
|
|
// title: 'Vendors',
|
|
// icon: <Truck size={20} />,
|
|
// path: '/vendors',
|
|
// visible: showSupplierDashboard
|
|
// },
|
|
// {
|
|
// id: 'dashboard-view',
|
|
// title: 'Dashboard',
|
|
// icon: <BarChart3 size={20} />,
|
|
// path: '/dashboard-view',
|
|
// visible: showProjectDashboard
|
|
// },
|
|
// {
|
|
// id: 'sites',
|
|
// title: 'Sites',
|
|
// icon: <Building2 size={20} />,
|
|
// path: '/sites',
|
|
// visible: showSiteDashboards
|
|
// },
|
|
// {
|
|
// id: 'active-map',
|
|
// title: 'Active Map',
|
|
// icon: <MapPin size={20} />,
|
|
// path: '/active-map',
|
|
// visible: showSiteInfo
|
|
// },
|
|
// {
|
|
// id: 'users',
|
|
// title: 'Users',
|
|
// icon: <Users size={20} />,
|
|
// path: '/users',
|
|
// visible: showAMTeam
|
|
// },
|
|
// {
|
|
// id: 'account',
|
|
// title: 'Account',
|
|
// icon: <FileText size={20} />,
|
|
// path: '/account',
|
|
// visible: showSLA
|
|
// }
|
|
];
|
|
|
|
const visibleLinks = links.filter(link => link.visible);
|
|
|
|
const isActive = (path: string) => {
|
|
return location.pathname === path;
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className={`
|
|
bg-white dark:bg-gray-800
|
|
h-screen
|
|
transition-all
|
|
duration-300
|
|
ease-in-out
|
|
flex
|
|
flex-col
|
|
shadow-xl
|
|
border-r border-gray-200 dark:border-gray-700
|
|
${isCollapsed ? 'w-16' : 'w-64'}
|
|
`}
|
|
>
|
|
{/* Sidebar Header */}
|
|
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
|
{!isCollapsed && (
|
|
<div className="flex items-center space-x-3">
|
|
<div className="w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-700 rounded-lg p-1">
|
|
{/* Seera Arabia Logo */}
|
|
<img
|
|
src="/seera-logo.png"
|
|
alt="Seera Arabia"
|
|
className="w-full h-full object-contain"
|
|
onError={(e) => {
|
|
// Fallback to SVG if image not found
|
|
e.currentTarget.style.display = 'none';
|
|
e.currentTarget.nextElementSibling?.classList.remove('hidden');
|
|
}}
|
|
/>
|
|
<svg className="w-6 h-6 hidden" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M12 2L2 7L12 12L22 7L12 2Z" fill="#6366F1" fillOpacity="0.9"/>
|
|
<path d="M2 17L12 22L22 17V12L12 17L2 12V17Z" fill="#8B5CF6" fillOpacity="0.7"/>
|
|
<path d="M12 12V17" stroke="#A855F7" strokeWidth="2" strokeLinecap="round"/>
|
|
</svg>
|
|
</div>
|
|
<h1 className="text-gray-900 dark:text-white text-lg font-semibold">Seera Arabia</h1>
|
|
</div>
|
|
)}
|
|
{isCollapsed && (
|
|
<div className="w-8 h-8 flex items-center justify-center bg-white dark:bg-gray-700 rounded-lg p-1">
|
|
<img
|
|
src="/seera-logo.png"
|
|
alt="Seera Arabia"
|
|
className="w-full h-full object-contain"
|
|
onError={(e) => {
|
|
e.currentTarget.style.display = 'none';
|
|
e.currentTarget.nextElementSibling?.classList.remove('hidden');
|
|
}}
|
|
/>
|
|
<svg className="w-5 h-5 hidden" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M12 2L2 7L12 12L22 7L12 2Z" fill="#6366F1" fillOpacity="0.9"/>
|
|
<path d="M2 17L12 22L22 17V12L12 17L2 12V17Z" fill="#8B5CF6" fillOpacity="0.7"/>
|
|
<path d="M12 12V17" stroke="#A855F7" strokeWidth="2" strokeLinecap="round"/>
|
|
</svg>
|
|
</div>
|
|
)}
|
|
<button
|
|
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
className="text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 p-2 rounded-lg transition-colors"
|
|
>
|
|
{isCollapsed ? <Menu size={20} /> : <X size={20} />}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Navigation Links */}
|
|
<nav className="flex-1 overflow-y-auto py-4">
|
|
{visibleLinks.map((link) => (
|
|
<Link
|
|
key={link.id}
|
|
to={link.path}
|
|
className={`
|
|
flex
|
|
items-center
|
|
px-4
|
|
py-3
|
|
text-gray-700 dark:text-gray-300
|
|
hover:bg-gray-100 dark:hover:bg-gray-700
|
|
hover:text-gray-900 dark:hover:text-white
|
|
transition-all
|
|
duration-200
|
|
${isActive(link.path) ? 'bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 border-l-4 border-indigo-600' : ''}
|
|
${isCollapsed ? 'justify-center' : ''}
|
|
`}
|
|
title={isCollapsed ? link.title : ''}
|
|
>
|
|
<span>{link.icon}</span>
|
|
{!isCollapsed && (
|
|
<span className="ml-4 font-medium">{link.title}</span>
|
|
)}
|
|
</Link>
|
|
))}
|
|
</nav>
|
|
|
|
{/* Theme Toggle, Logout & User Info (Bottom) */}
|
|
<div className="p-4 border-t border-gray-200 dark:border-gray-700 space-y-3">
|
|
{/* Theme Toggle Button */}
|
|
<button
|
|
onClick={toggleTheme}
|
|
className="w-full flex items-center justify-center px-4 py-2 rounded-lg bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors text-gray-700 dark:text-gray-300"
|
|
title={isCollapsed ? (theme === 'light' ? 'Dark Mode' : 'Light Mode') : ''}
|
|
>
|
|
{theme === 'light' ? <Moon size={18} /> : <Sun size={18} />}
|
|
{!isCollapsed && (
|
|
<span className="ml-2 text-sm font-medium">
|
|
{theme === 'light' ? 'Dark Mode' : 'Light Mode'}
|
|
</span>
|
|
)}
|
|
</button>
|
|
|
|
{/* Logout Button */}
|
|
<button
|
|
onClick={handleLogout}
|
|
className="w-full flex items-center justify-center px-4 py-2 rounded-lg bg-red-50 dark:bg-red-900/20 hover:bg-red-100 dark:hover:bg-red-900/30 transition-colors text-red-600 dark:text-red-400"
|
|
title={isCollapsed ? 'Logout' : ''}
|
|
>
|
|
<LogOut size={18} />
|
|
{!isCollapsed && (
|
|
<span className="ml-2 text-sm font-medium">Logout</span>
|
|
)}
|
|
</button>
|
|
|
|
{!isCollapsed && userEmail && (
|
|
<div className="pt-2">
|
|
<div className="text-gray-500 dark:text-gray-400 text-xs truncate">
|
|
Logged in as:
|
|
</div>
|
|
<div className="text-gray-900 dark:text-white text-sm font-medium truncate">
|
|
{userEmail}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{!isCollapsed && (
|
|
<div className="text-xs text-gray-400 dark:text-gray-500 text-center">
|
|
Seera Arabia AMS v1.0
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Sidebar;
|
|
|