import React, { useState } from "react"; import { House, Layers, Zap, Palette, Mic2, Users, FileText, BookOpen, MessageSquare, CreditCard, Shield, ChevronRight, ChevronLeft, Settings, LogOut, Plus, X, Sun, Moon, } from "lucide-react"; import { useBreakpoint } from "../hooks/useBreakpoint"; import { useNavigate } from "react-router-dom"; import { useTheme } from "../contexts/ThemeContext"; import { useAuth } from "../contexts/AuthContext"; import { navItemAllowed, usePermission } from "../contexts/PermissionContext"; /* ───────────────────────────────────── Types ───────────────────────────────────── */ interface SubItem { id: string; label: string; isAction?: boolean; } interface NavItem { id: string; label: string; icon: React.ReactNode; children?: SubItem[]; } /* ───────────────────────────────────── Sidebar events list (accordion data) ───────────────────────────────────── */ interface SidebarEventItem { id: string; name: string; status: "Live" | "Upcoming" | "Completed"; } const SIDEBAR_EVENTS: SidebarEventItem[] = [ { id: "e1", name: "Napcon Jaipur 2026", status: "Live" }, { id: "e2", name: "Napcon Mumbai 2025", status: "Completed" }, { id: "e3", name: "CHEST India 2026", status: "Upcoming" }, { id: "e4", name: "ICS Annual Conf. 2026", status: "Upcoming" }, { id: "e5", name: "COPD Workshop", status: "Completed" }, { id: "e6", name: "Interventional Pulmo.", status: "Completed" }, { id: "e7", name: "Resp. Physiology Lab", status: "Upcoming" }, { id: "e8", name: "IMA Annual Summit 2025", status: "Completed" }, { id: "e9", name: "AIIMS Research Conclave", status: "Upcoming" }, ]; const EVENT_STATUS_DOT: Record<"Live" | "Upcoming" | "Completed", string> = { Live: "#16a34a", Upcoming: "#2563eb", Completed: "var(--muted)", }; /* ───────────────────────────────────── Nav structure — Portfolio / All Events ───────────────────────────────────── */ const PORTFOLIO_NAV: NavItem[] = [ { id: "home", label: "Home", icon: }, { id: "events", label: "All Events", icon: }, { id: "activities", label: "Activities", icon: }, { id: "design", label: "Design", icon: , children: [ { id: "design-brochure", label: "Brochure" }, { id: "design-badges", label: "Badges" }, { id: "design-emailers", label: "Emailers" }, { id: "design-whatsapp-templates", label: "WhatsApp Templates" }, ], }, { id: "faculty", label: "Faculty & Speakers", icon: }, { id: "all-participants", label: "Participants", icon: }, { id: "forms", label: "Forms & Workflow", icon: , children: [ { id: "forms-feedback", label: "Feedback" }, { id: "forms-registration", label: "Registration" }, { id: "forms-other", label: "Other Forms" }, { id: "forms-add", label: "Add New Form", isAction: true }, ], }, { id: "content", label: "Content", icon: , children: [ { id: "content-library", label: "Library" }, { id: "content-collections", label: "Collections" }, ], }, { id: "messaging", label: "Messaging", icon: , children: [ { id: "messaging-email", label: "Email" }, { id: "messaging-whatsapp", label: "WhatsApp" }, { id: "messaging-whatsapp-chatbots", label: "WhatsApp Chatbots" }, ], }, { id: "payment", label: "Payment Settings", icon: }, { id: "user-management", label: "User Management", icon: }, { id: "settings", label: "Settings", icon: }, ]; /* ───────────────────────────────────── Helpers ───────────────────────────────────── */ function isChildActive(item: NavItem, active: string) { return !!item.children?.some(c => c.id === active); } function isItemActive(item: NavItem, active: string) { return active === item.id || isChildActive(item, active); } /* ───────────────────────────────────── Tooltip (collapsed mode) ───────────────────────────────────── */ function Tooltip({ label, children }: { label: string; children: React.ReactNode }) { const [show, setShow] = useState(false); return (
setShow(true)} onMouseLeave={() => setShow(false)}> {children} {show && (
{label}
)}
); } /* ───────────────────────────────────── Inner nav list — shared between drawer and desktop ───────────────────────────────────── */ function NavList({ activeItem, onNavigate, showCollapsed, selectedEventId, onEventSelect, }: { activeItem: string; onNavigate: (id: string) => void; showCollapsed: boolean; selectedEventId?: string | null; onEventSelect?: (id: string) => void; }) { const { canModule } = usePermission(); const visibleNav = PORTFOLIO_NAV.filter((item) => navItemAllowed(item.id, canModule)); const defaultOpen = visibleNav.filter(n => n.children).reduce>((acc, item) => { acc[item.id] = isChildActive(item, activeItem); return acc; }, {}); // Events accordion starts open by default const [openGroups, setOpenGroups] = useState>({ events: true, ...defaultOpen }); const toggle = (id: string) => setOpenGroups(p => ({ ...p, [id]: !p[id] })); const btnStyle = (isActive: boolean): React.CSSProperties => ({ width: "100%", display: "flex", alignItems: "center", gap: showCollapsed ? 0 : "9px", padding: showCollapsed ? "8px 0" : "7px 10px", justifyContent: showCollapsed ? "center" : "flex-start", borderRadius: "var(--radius-button)", background: isActive ? "var(--sidebar-accent)" : "transparent", border: "none", cursor: "pointer", textAlign: "left", fontSize: "var(--text-sm)", fontFamily: "var(--font-noto-sans)", fontWeight: isActive ? "var(--font-weight-medium)" : "var(--font-weight-normal)", color: isActive ? "var(--sidebar-accent-foreground)" : "var(--sidebar-foreground)", transition: "background 0.12s", marginBottom: "1px", whiteSpace: "nowrap", overflow: "hidden", }); const iconStyle = (isActive: boolean): React.CSSProperties => ({ color: isActive ? "var(--sidebar-primary)" : "var(--muted)", flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center", }); return ( <> {visibleNav.map(item => { /* ── Special: All Events accordion ── */ if (item.id === "events") { const isEvtActive = activeItem === "events"; const isOpen = !!openGroups["events"] && !showCollapsed; if (showCollapsed) { return ( ); } return (
{/* Header row: label navigates, chevron toggles */}
); } /* ── Standard accordion items (Design, Forms, Content, Messaging) ── */ const active = isItemActive(item, activeItem); const isOpen = !!openGroups[item.id] && !showCollapsed; if (item.children) { const GroupBtn = ( ); return (
{showCollapsed ? {GroupBtn} : GroupBtn} {isOpen && (
{item.children!.filter((child) => navItemAllowed(child.id, canModule)).map(child => { const cActive = activeItem === child.id; return ( ); })}
)}
); } /* ── Leaf items (Faculty, Participants, Payment, User Mgmt) ── */ const LeafBtn = ( ); return showCollapsed ? {LeafBtn} : LeafBtn; })} ); } /* ───────────────────────────────────── Bottom user row ───────────────────────────────────── */ function sidebarUserDisplayName(user: { firstName?: string; lastName?: string; email: string } | null): string { if (!user) return "User"; if (user.firstName || user.lastName) return [user.firstName, user.lastName].filter(Boolean).join(" ").trim(); return user.email?.split("@")[0] ?? "User"; } function sidebarUserInitials(user: { firstName?: string; lastName?: string; email: string } | null): string { const name = sidebarUserDisplayName(user); return name.slice(0, 2).toUpperCase() || "?"; } function BottomUser({ collapsed, onNavigate }: { collapsed: boolean; onNavigate: (id: string) => void }) { const { theme, setTheme } = useTheme(); const { user, logout } = useAuth(); const navigate = useNavigate(); const isPlatformAdmin = user?.platform_admin === "yes"; const displayName = sidebarUserDisplayName(user ?? null); const initials = sidebarUserInitials(user ?? null); const email = user?.email ?? ""; const handleLogout = () => { logout(); navigate("/login", { replace: true }); }; const btnStyle: React.CSSProperties = { width: "100%", display: "flex", alignItems: "center", gap: collapsed ? 0 : "9px", padding: collapsed ? "8px 0" : "7px 10px", justifyContent: collapsed ? "center" : "flex-start", borderRadius: "var(--radius-button)", background: "transparent", border: "none", cursor: "pointer", transition: "background 0.12s", marginBottom: "1px", whiteSpace: "nowrap", overflow: "hidden", }; return (
{/* ── Appearance toggle ── */} {collapsed ? ( ) : (

Appearance

{(["light", "dark"] as const).map(mode => { const isActive = theme === mode; return ( ); })}
)} {isPlatformAdmin && (collapsed ? ( ) : ( ))} {collapsed ? ( ) : ( )} {collapsed ? ( <> ) : (
)}
); } /* ───────────────────────────────────── Section label ───────────────────────────────────── */ function SectionLabel() { return (

Portfolio

); } /* ───────────────────────────────────── Public Sidebar component ───────────────────────────────────── */ interface SidebarProps { activeItem: string; onItemClick: (id: string) => void; collapsed: boolean; onToggleCollapse: () => void; drawerOpen?: boolean; onDrawerClose?: () => void; selectedEventId?: string | null; onEventSelect?: (id: string) => void; } export function Sidebar({ activeItem, onItemClick, collapsed, onToggleCollapse, drawerOpen, onDrawerClose, selectedEventId, onEventSelect, }: SidebarProps) { const bp = useBreakpoint(); const isSmall = bp === "mobile" || bp === "tablet"; const handleNav = (id: string) => { onItemClick(id); if (isSmall && onDrawerClose) onDrawerClose(); }; const handleEventSelect = (id: string) => { onEventSelect?.(id); if (isSmall && onDrawerClose) onDrawerClose(); }; /* ── Mobile / Tablet: slide-in drawer ── */ if (isSmall) { return ( <> {/* Backdrop */}
{/* Panel */} ); } /* ── Desktop: inline collapsible sidebar ── */ const w = collapsed ? 60 : 240; return ( ); }