// vibe_erp main app shell. // // Top bar (logo + version + user + logout) and a permanent left // sidebar grouped by Packaged Business Capability (PBC). The // `` renders whichever child route the router matched. // // **Why a static nav array.** The framework already exposes // menu metadata at /api/v1/_meta/metadata, but plumbing that into // the SPA is a Phase 3 (Tier 1 customization) concern. v1 SPA // hard-codes a sensible default that mirrors the implemented PBCs; // a future chunk replaces this with a metadata-driven sidebar so // plug-ins can contribute new menus through their YAML. import { NavLink, Outlet } from 'react-router-dom' import { useEffect, useState } from 'react' import { useAuth } from '@/auth/AuthContext' import { meta } from '@/api/client' import type { MetaInfo } from '@/types/api' interface NavItem { to: string label: string } interface NavGroup { heading: string items: NavItem[] } const NAV: NavGroup[] = [ { heading: 'Overview', items: [{ to: '/', label: 'Dashboard' }], }, { heading: 'Catalog & Partners', items: [ { to: '/items', label: 'Items' }, { to: '/uoms', label: 'Units of Measure' }, { to: '/partners', label: 'Partners' }, ], }, { heading: 'Inventory', items: [ { to: '/locations', label: 'Locations' }, { to: '/balances', label: 'Stock Balances' }, { to: '/movements', label: 'Stock Movements' }, ], }, { heading: 'Orders', items: [ { to: '/sales-orders', label: 'Sales Orders' }, { to: '/purchase-orders', label: 'Purchase Orders' }, ], }, { heading: 'Production', items: [ { to: '/work-orders', label: 'Work Orders' }, { to: '/shop-floor', label: 'Shop Floor' }, ], }, { heading: 'Finance', items: [{ to: '/journal-entries', label: 'Journal Entries' }], }, ] export function AppLayout() { const { username, logout } = useAuth() const [info, setInfo] = useState(null) useEffect(() => { meta.info().then(setInfo).catch(() => setInfo(null)) }, []) return ( {/* ─── Sidebar ──────────────────────────────────────────── */} {/* ─── Main column ─────────────────────────────────────── */} vibe_erp {username ? ( <> Signed in as {username} > ) : ( 'Signed in' )} Logout ) }