import React, { useMemo, useState } from 'react'; import { NavLink, useLocation, useNavigate } from 'react-router-dom'; import { LogOut, Zap, ChevronDown, ChevronRight, AlertCircle, MoreVertical } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import { PerspectiveSwitcher } from './PerspectiveSwitcher'; import { NAVIGATION_CONFIG } from '../config/navigation'; import type { NavItem } from '../config/navigation'; import { logout } from '../utils/auth'; export const Sidebar: React.FC = () => { const navigate = useNavigate(); const location = useLocation(); const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); // Safely parse user data const user = useMemo(() => { try { const stored = localStorage.getItem('teleems_user'); if (!stored || stored === 'undefined' || stored === 'null') return { roles: [] }; const parsed = JSON.parse(stored); if (parsed && typeof parsed === 'object') { // Normalise roles to lowercase_underscore so "Fleet Operator" === "FLEET_OPERATOR" parsed.roles = Array.isArray(parsed.roles) ? parsed.roles.map((r: any) => String(r).toLowerCase().replace(/\s+/g, '_')) : []; return parsed; } return { roles: [] }; } catch (err) { console.error('Failed to parse user data from localStorage', err); return { roles: [] }; } }, []); const handleLogout = () => { logout(); }; const handleRoleSwitch = (role: string) => { // Preserve CURESELECT_ADMIN so the admin doesn't lose access to the perspective switcher when switching roles const originalStored = localStorage.getItem('teleems_user'); let originalRoles: string[] = []; try { if (originalStored) { const parsed = JSON.parse(originalStored); originalRoles = Array.isArray(parsed?.roles) ? parsed.roles : []; } } catch (e) { console.error(e); } const hasAdmin = originalRoles.some((r: string) => { const normalized = r.toLowerCase().replace(/\s+/g, '_'); return normalized === 'cureselect_admin' || normalized === 'admin'; }); let newRoles = [role.toUpperCase()]; if (hasAdmin && role.toUpperCase() !== 'CURESELECT_ADMIN') { newRoles.push('CURESELECT_ADMIN'); } const updatedUser = { ...user, roles: newRoles }; localStorage.setItem('teleems_user', JSON.stringify(updatedUser)); window.location.reload(); }; const currentRole = user.roles?.[0] || 'cureselect_admin'; const displayName = String(user.name || user.username || (currentRole === 'cureselect_admin' ? 'CureSelect Admin' : 'Fleet Operator')); const displayId = user.id ? `#${String(user.id).substring(0, 6)}` : '#789022'; const initials = (displayName.split(' ').map((n: string) => n[0]).join('').toUpperCase().substring(0, 2)) || 'FO'; const filteredNavItems = useMemo(() => { // The active perspective role being viewed (e.g. 'hospital_admin', 'fleet_operator', 'cureselect_admin') const activeRole = currentRole.toLowerCase().replace(/\s+/g, '_'); // Check if the active perspective is a platform-wide admin role const isAdminPerspective = ['cureselect_admin', 'admin', 'super_admin', 'superadmin'].includes(activeRole); const filterItems = (items: NavItem[]): NavItem[] => { return items.filter(item => { // If viewing as CureSelect Admin, they can see everything (or we filter as admin) if (isAdminPerspective) return true; // Otherwise, filter items so they must match the active role perspective return item.roles.some(role => role.toLowerCase().replace(/\s+/g, '_') === activeRole ); }).map(item => ({ ...item, subItems: item.subItems ? filterItems(item.subItems) : undefined })); }; return filterItems(NAVIGATION_CONFIG); }, [currentRole]); const renderNavItem = (item: NavItem, isSubItem = false) => { const Icon = item.icon || AlertCircle; const currentUrl = location.pathname + location.search; // Split path into pathname + search to handle query params correctly const [itemPathname, itemSearch] = item.path.split('?'); const itemTo = itemSearch ? { pathname: itemPathname, search: `?${itemSearch}` } : item.path; const isActive = currentUrl === item.path || (itemSearch ? location.pathname === itemPathname && location.search === `?${itemSearch}` : location.pathname === item.path); const hasSubItems = item.subItems && item.subItems.length > 0; const isParentActive = hasSubItems && (isActive || item.subItems?.some(sub => { const [subPath, subSearch] = sub.path.split('?'); return subSearch ? location.pathname === subPath && location.search === `?${subSearch}` : location.pathname === subPath; })); return (
{ const active = linkActive || isActive; return { display: 'flex', alignItems: 'center', justifyContent: isSidebarCollapsed ? 'center' : 'flex-start', gap: isSidebarCollapsed ? '0' : '12px', padding: isSidebarCollapsed ? '12px' : isSubItem ? '10px 20px 10px 48px' : '12px 16px', margin: isSidebarCollapsed ? '4px 12px' : '2px 12px', borderRadius: '12px', textDecoration: 'none', color: active ? '#fff' : '#94A3B8', background: active ? 'linear-gradient(90deg, rgba(6, 182, 212, 0.15), rgba(59, 130, 246, 0.05))' : 'transparent', borderLeft: active && !isSubItem && !isSidebarCollapsed ? '3px solid #06B6D4' : '3px solid transparent', boxShadow: active && isSidebarCollapsed ? '0 0 0 1px rgba(6,182,212,0.4)' : 'none', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', position: 'relative', overflow: 'hidden' }; }} className={(navData) => `nav-item-link ${navData.isActive || isActive ? 'active' : ''}`} > {({ isActive: linkActive }) => { const active = linkActive || isActive; return ( <> {!isSidebarCollapsed && ( {item.label} {hasSubItems && (
)}
)}
); }}
{hasSubItems && isParentActive && !isSidebarCollapsed && (
{item.subItems?.map(sub => renderNavItem(sub, true))}
)}
); }; return ( <> {/* Brand Header */}
{ if (isSidebarCollapsed) setIsSidebarCollapsed(false); }} title={isSidebarCollapsed ? "Expand Menu" : undefined} style={{ width: '36px', height: '36px', background: 'linear-gradient(135deg, #06B6D4, #3B82F6)', borderRadius: '10px', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 0 20px rgba(6,182,212,0.4)', flexShrink: 0, cursor: isSidebarCollapsed ? 'pointer' : 'default' }} >
{!isSidebarCollapsed && (

CureSelect

Platform
)}
{/* Minimize/Collapse button near CureSelect title */} {!isSidebarCollapsed && ( )}
{/* Navigation Area */} {/* User Footer Profile */}
{!isSidebarCollapsed && ( {/* Perspective Switcher */} {(user.roles?.includes('cureselect_admin') || user.roles?.includes('admin') || user.roles?.includes('CURESELECT_ADMIN') || user.roles?.includes('ADMIN')) && (
)} {/* Premium User Card */}
{initials}
{displayName}
{currentRole.replace(/_/g, ' ')}
)}
); };