// frontend/src/components/layout/Sidebar.jsx
// Primary navigation sidebar — 224px wide, fixed, full height.
import { useState } from 'react'
import { NavLink, useLocation } from 'react-router-dom'
import { useAuth } from '@/hooks/useAuth'
import logoDark from '@/assets/logos/bell_systems_horizontal_darkMode.png'
// ─── SVG file icons (vite-plugin-svgr v4 — ?react query) ─────────────────────
import IcoDevices from '@/assets/side-menu-icons/devices.svg?react'
import IcoDeviceOverview from '@/assets/side-menu-icons/device-overview.svg?react'
import IcoFleet from '@/assets/side-menu-icons/fleet.svg?react'
import IcoBlackbox from '@/assets/side-menu-icons/blackbox.svg?react'
import IcoMelodies from '@/assets/side-menu-icons/melodies.svg?react'
import IcoMelodiesEditor from '@/assets/side-menu-icons/melodies-editor.svg?react'
import IcoComposer from '@/assets/side-menu-icons/composer.svg?react'
import IcoArchetypes from '@/assets/side-menu-icons/archetypes.svg?react'
import IcoMelodySettings from '@/assets/side-menu-icons/melody-settings.svg?react'
import IcoCommunications from '@/assets/side-menu-icons/communications.svg?react'
import IcoWhatsapp from '@/assets/side-menu-icons/whatsapp.svg?react'
import IcoSms from '@/assets/side-menu-icons/sms.svg?react'
import IcoHelpdesk from '@/assets/side-menu-icons/helpdesk.svg?react'
import IcoCommsLog from '@/assets/side-menu-icons/communications-log.svg?react'
import IcoCustomers from '@/assets/side-menu-icons/customers.svg?react'
import IcoCustomerOverview from '@/assets/side-menu-icons/customer-overview.svg?react'
import IcoOrders from '@/assets/side-menu-icons/orders.svg?react'
import IcoProducts from '@/assets/side-menu-icons/products.svg?react'
import IcoCatalog from '@/assets/side-menu-icons/product-catalog.svg?react'
import IcoSnManager from '@/assets/side-menu-icons/sn-manager.svg?react'
import IcoManufacturing from '@/assets/side-menu-icons/manufacturing.svg?react'
import IcoInventory from '@/assets/side-menu-icons/inventory.svg?react'
import IcoProvisioning from '@/assets/side-menu-icons/provision.svg?react'
import IcoFirmware from '@/assets/side-menu-icons/firmware.svg?react'
import IcoApi from '@/assets/side-menu-icons/api.svg?react'
// ─── Inline-only icons (no SVG file equivalent) ───────────────────────────────
const S = ({ children, ...p }) => (
)
// Wrapper to normalise imported SVG file components to 16×16
function SvgIcon({ Component }) {
return (
)
}
const Icons = {
dashboard: () => ,
devices: () => ,
blackBox: () => ,
melodies: () => ,
whatsapp: () => ,
products: () => ,
manufacturing: () => ,
staff: () => ,
publicFeatures: () => ,
logViewer: () => ,
placeholder: () => ,
chevronRight: () => (
),
lock: () => (
),
}
// ─── Nav structure ────────────────────────────────────────────────────────────
const navSections = [
{ type: 'separator', label: 'General' },
{ to: '/', label: 'Dashboard', icon: 'dashboard' },
{ type: 'separator', label: 'Bell Cloud' },
{
label: 'Devices', icon: 'devices', permission: 'devices',
children: [
{ to: '/devices/overview', label: 'Overview', icon: 'deviceOverview', placeholder: true },
{ to: '/devices', label: 'Fleet', icon: 'fleet', exact: true },
{ to: '/mqtt/commands', label: 'Command Center', icon: 'commandCenter' },
{ to: '/equipment/notes', label: 'BlackBox', icon: 'blackBox' },
{ to: '/devices/settings', label: 'Device Settings', icon: 'deviceSettings', placeholder: true },
],
},
{ to: '/users', label: 'App Users', icon: 'appUsers', permission: 'app_users' },
{
label: 'Melodies', icon: 'melodies', permission: 'melodies',
children: [
{ to: '/melodies', label: 'Library', icon: 'library', exact: true },
{ to: '/melodies/composer', label: 'Composer', icon: 'composer' },
{ to: '/melodies/archetypes', label: 'Archetypes', icon: 'archetypes' },
{ to: '/melodies/settings', label: 'Melody Settings', icon: 'melodySettings' },
],
},
{ type: 'separator', label: 'Headquarters' },
{
label: 'Communications', icon: 'communications', permission: 'crm',
children: [
{ to: '/mail', label: 'Mailbox', icon: 'mail' },
{ to: '/comms/whatsapp', label: 'WhatsApp', icon: 'whatsapp', placeholder: true },
{ to: '/comms/sms', label: 'SMS', icon: 'sms', placeholder: true },
{ to: '/crm/comms/helpdesk', label: 'Helpdesk', icon: 'helpdesk', exact: true },
{ to: '/crm/comms', label: 'Comms Log', icon: 'commsLog', exact: true },
],
},
{
label: 'Customers', icon: 'customers', permission: 'crm',
children: [
{ to: '/crm/customers', label: 'Overview', icon: 'customerOverview' },
{ to: '/crm/orders', label: 'Orders', icon: 'orders' },
{ to: '/crm/quotations', label: 'Quotations', icon: 'quotations' },
],
},
{
label: 'Products', icon: 'products', permission: 'crm',
children: [
{ to: '/crm/products', label: 'Catalog', icon: 'catalog' },
{ to: '/crm/products/sn', label: 'S/N Manager', icon: 'snManager', placeholder: true },
],
},
{ to: '/staff-log', label: 'Staff Log', icon: 'staffLog', placeholder: true },
{ type: 'separator', label: 'Engineering' },
{
label: 'Manufacturing', icon: 'manufacturing', permission: 'manufacturing',
children: [
{ to: '/manufacturing', label: 'Inventory', icon: 'inventory', exact: true },
{ to: '/manufacturing/provision', label: 'Provisioning', icon: 'provisioning' },
],
},
{ to: '/firmware', label: 'Firmware Manager', icon: 'firmware', permission: 'manufacturing' },
{ to: '/developer/api', label: 'API Reference', icon: 'api', roleRequired: ['sysadmin', 'admin'] },
]
// ─── Helpers ──────────────────────────────────────────────────────────────────
function isGroupActive(children, pathname) {
return children.some((child) => {
if (child.exact) return pathname === child.to
return pathname === child.to || pathname.startsWith(child.to + '/')
})
}
// ─── Section separator ────────────────────────────────────────────────────────
function SectionSeparator({ label, first }) {
return (