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 (
);
}
/* ─────────────────────────────────────
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 (
);
}