@pablo2410/shared-ui 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/layout/SharedSidebar.tsx","../../src/layout/DashboardLayout.tsx","../../src/layout/DashboardLayoutSkeleton.tsx","../../src/layout/SharedPageHeader.tsx","../../src/layout/SharedFooter.tsx","../../src/layout/createServiceLayout.tsx","../../src/layout/serviceConfigs.ts"],"sourcesContent":["/**\n * SharedSidebar — Config-driven sidebar component for all Oplytics subdomains.\n *\n * Replaces per-subdomain DashboardLayout sidebar implementations with a single\n * shared component. Each subdomain provides its own configuration (menu items,\n * service name, feature flags) and gets a consistent sidebar experience.\n *\n * Features:\n * - Resizable sidebar with localStorage persistence\n * - Collapsible icon mode with tooltips\n * - Service branding (icon + name) in header\n * - \"Back to Service Hub/Portal\" link (configurable)\n * - Grouped menu sections with optional section labels\n * - Admin-only menu items (role-gated)\n * - User avatar footer with optional logout dropdown\n * - Mobile-responsive with auto-collapse\n *\n * Usage:\n * import { createServiceLayout } from \"@shared/components/SharedSidebar\";\n * const MyLayout = createServiceLayout({ serviceName: \"SQDCP\", ... });\n * // Then use <MyLayout>{children}</MyLayout> in your routes\n *\n * @module shared/components/SharedSidebar\n */\n\nimport React, { CSSProperties, useEffect, useRef, useState } from \"react\";\n\n/* ── Types ── */\n\nexport interface MenuItem {\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n path: string;\n /** Optional badge text (e.g. count) */\n badge?: string | number;\n}\n\nexport interface MenuSection {\n /** Section label displayed above items */\n label?: string;\n /** Alias for label — used by DashboardLayout */\n title?: string;\n items: MenuItem[];\n adminOnly?: boolean;\n}\n\nexport interface SharedSidebarConfig {\n /** Display name shown in sidebar header */\n serviceName: string;\n /** Icon component rendered next to service name */\n serviceIcon: React.ReactNode;\n /** Primary navigation items */\n menuSections: MenuSection[];\n /** Show \"Back to Service Hub\" / \"Back to Portal\" link at top of nav */\n backLink?: {\n label: string;\n path: string;\n };\n /** localStorage key prefix for sidebar width persistence */\n storageKeyPrefix?: string;\n /** Default sidebar width in pixels (default: 260) */\n defaultWidth?: number;\n /** Minimum sidebar width in pixels (default: 200) */\n minWidth?: number;\n /** Maximum sidebar width in pixels (default: 480) */\n maxWidth?: number;\n}\n\nexport interface SharedSidebarProps {\n config: SharedSidebarConfig;\n /** Current route location */\n location: string;\n /** Navigate to a path */\n setLocation: (path: string) => void;\n /** Current user object (null if not authenticated) */\n user: { name?: string; email?: string; role?: string } | null;\n /** Logout handler */\n onLogout?: () => void;\n /** Whether sidebar is collapsed */\n isCollapsed: boolean;\n /** Toggle sidebar collapsed state */\n toggleSidebar: () => void;\n /** Whether user has admin role */\n isAdmin: boolean;\n /** Children rendered in SidebarInset main area */\n children: React.ReactNode;\n}\n\n/* ── Constants ── */\n\nconst ADMIN_ROLES = [\"enterprise_admin\", \"platform_admin\", \"admin\", \"superuser\"];\n\n/* ── Helpers ── */\n\nexport function isAdminRole(role?: string): boolean {\n return !!role && ADMIN_ROLES.includes(role);\n}\n\nexport function getInitials(name?: string): string {\n if (!name) return \"U\";\n return name\n .split(\" \")\n .map((n) => n[0])\n .join(\"\")\n .toUpperCase()\n .slice(0, 2);\n}\n\n/**\n * Determines if a menu item is active based on current location.\n * Exact match for root paths, startsWith for nested paths.\n */\nexport function isMenuItemActive(itemPath: string, location: string, basePath?: string): boolean {\n if (basePath) {\n // For subdomain routes with a base path (e.g., /app/policy-deployment)\n if (itemPath === basePath) return location === basePath;\n return location.startsWith(itemPath);\n }\n // For root-level routes\n if (itemPath === \"/\") return location === \"/\";\n return location.startsWith(itemPath);\n}\n\n/* ── Resize Hook ── */\n\nexport function useSidebarResize(config: {\n storageKey: string;\n defaultWidth: number;\n minWidth: number;\n maxWidth: number;\n}) {\n const [width, setWidth] = useState(() => {\n if (typeof window === \"undefined\") return config.defaultWidth;\n const saved = localStorage.getItem(config.storageKey);\n return saved ? parseInt(saved, 10) : config.defaultWidth;\n });\n const [isResizing, setIsResizing] = useState(false);\n const startX = useRef(0);\n const startWidth = useRef(config.defaultWidth);\n\n useEffect(() => {\n localStorage.setItem(config.storageKey, String(width));\n }, [width, config.storageKey]);\n\n useEffect(() => {\n if (!isResizing) return;\n const onMove = (e: MouseEvent) => {\n const newWidth = Math.min(\n config.maxWidth,\n Math.max(config.minWidth, startWidth.current + (e.clientX - startX.current))\n );\n setWidth(newWidth);\n };\n const onUp = () => {\n setIsResizing(false);\n };\n document.addEventListener(\"mousemove\", onMove);\n document.addEventListener(\"mouseup\", onUp);\n document.body.style.cursor = \"col-resize\";\n document.body.style.userSelect = \"none\";\n return () => {\n document.removeEventListener(\"mousemove\", onMove);\n document.removeEventListener(\"mouseup\", onUp);\n document.body.style.cursor = \"\";\n document.body.style.userSelect = \"\";\n };\n }, [isResizing, config.minWidth, config.maxWidth]);\n\n const startResize = (e: React.MouseEvent) => {\n setIsResizing(true);\n startX.current = e.clientX;\n startWidth.current = width;\n };\n\n return { width, isResizing, startResize };\n}\n\n/* ── Export config type for subdomain use ── */\nexport type { SharedSidebarConfig as SidebarConfig };\n","/**\n * DashboardLayout — standard sidebar + content layout for all Oplytics subdomains.\n *\n * Config-driven: pass a ServiceLayoutConfig to define menu items, service name,\n * feature flags, and callbacks. The layout handles sidebar state, mobile drawer,\n * user profile section, and content area.\n *\n * Oplytics dark theme: #0A0E1A bg, #0D1220 sidebar, #8C34E9 accent\n */\nimport { cn } from \"../utils/cn\";\nimport {\n type MenuItem,\n type MenuSection,\n type SharedSidebarConfig,\n isAdminRole,\n getInitials,\n isMenuItemActive,\n useSidebarResize,\n} from \"./SharedSidebar\";\nimport {\n ChevronLeft,\n ChevronRight,\n LogOut,\n Menu,\n X,\n ExternalLink,\n} from \"lucide-react\";\nimport {\n useState,\n useCallback,\n useMemo,\n type ReactNode,\n} from \"react\";\n\n/* ── Re-export sidebar types ── */\nexport type { MenuItem, MenuSection, SharedSidebarConfig };\n\n/* ── DashboardLayout config ── */\n\nexport interface DashboardLayoutUser {\n name: string;\n email?: string;\n role?: string;\n avatarUrl?: string;\n}\n\nexport interface DashboardLayoutProps {\n /** Service/module name displayed in the sidebar header */\n serviceName: string;\n /** Optional service icon (ReactNode) */\n serviceIcon?: ReactNode;\n /** Menu sections with items */\n menuSections: MenuSection[];\n /** Currently active path/route */\n activePath: string;\n /** Handler when a menu item is clicked */\n onNavigate: (path: string) => void;\n /** Current user info */\n user?: DashboardLayoutUser | null;\n /** Whether the user is authenticated */\n isAuthenticated?: boolean;\n /** Whether auth state is loading */\n isLoading?: boolean;\n /** Logout handler */\n onLogout?: () => void;\n /** Login handler / redirect */\n onLogin?: () => void;\n /** Show \"Back to Portal\" link (default: false) */\n showBackToPortal?: boolean;\n /** Portal URL for \"Back to Portal\" link */\n portalUrl?: string;\n /** Whether user has admin role */\n isAdmin?: boolean;\n /** Admin menu sections (shown only for admins) */\n adminSections?: MenuSection[];\n /** Optional hierarchy navigator to render in the sidebar */\n hierarchyNavigator?: ReactNode;\n /** Optional reporting toolbar to render in the header */\n reportingToolbar?: ReactNode;\n /** Loading skeleton to show while auth is loading */\n loadingSkeleton?: ReactNode;\n /** Main content */\n children: ReactNode;\n /** Additional CSS class for the outer container */\n className?: string;\n}\n\n/* ── Sidebar item component ── */\n\nfunction SidebarItem({\n item,\n isActive,\n collapsed,\n onNavigate,\n}: {\n item: MenuItem;\n isActive: boolean;\n collapsed: boolean;\n onNavigate: (path: string) => void;\n}) {\n const Icon = item.icon;\n\n return (\n <button\n onClick={() => onNavigate(item.path)}\n className={cn(\n \"w-full flex items-center gap-3 rounded-lg transition-all duration-200\",\n \"text-sm font-medium outline-none\",\n \"focus-visible:ring-1 focus-visible:ring-[#8C34E9]\",\n collapsed ? \"px-3 py-2.5 justify-center\" : \"px-3 py-2\",\n isActive\n ? \"bg-[#8C34E9]/15 text-[#A855F7] border-l-2 border-[#8C34E9]\"\n : \"text-[#8890A0] hover:bg-[#1E2738] hover:text-[#E2E8F0]\"\n )}\n title={collapsed ? item.label : undefined}\n >\n {Icon && <Icon className={cn(\"shrink-0\", collapsed ? \"h-5 w-5\" : \"h-4 w-4\")} />}\n {!collapsed && <span className=\"truncate\">{item.label}</span>}\n {!collapsed && item.badge && (\n <span className=\"ml-auto shrink-0 text-[10px] font-semibold px-1.5 py-0.5 rounded-full bg-[#8C34E9]/20 text-[#A855F7]\">\n {item.badge}\n </span>\n )}\n </button>\n );\n}\n\n/* ── Sidebar section component ── */\n\nfunction SidebarSection({\n section,\n activePath,\n collapsed,\n onNavigate,\n}: {\n section: MenuSection;\n activePath: string;\n collapsed: boolean;\n onNavigate: (path: string) => void;\n}) {\n return (\n <div className=\"space-y-1\">\n {!collapsed && section.title && (\n <p className=\"px-3 py-1 text-[10px] font-semibold uppercase tracking-wider text-[#596475]\">\n {section.title}\n </p>\n )}\n {collapsed && section.title && (\n <div className=\"mx-auto w-6 border-t border-[#1E2738] my-2\" />\n )}\n {section.items.map((item) => (\n <SidebarItem\n key={item.path}\n item={item}\n isActive={isMenuItemActive(item.path, activePath)}\n collapsed={collapsed}\n onNavigate={onNavigate}\n />\n ))}\n </div>\n );\n}\n\n/* ── User profile section ── */\n\nfunction UserProfile({\n user,\n collapsed,\n onLogout,\n}: {\n user: DashboardLayoutUser;\n collapsed: boolean;\n onLogout?: () => void;\n}) {\n const initials = getInitials(user.name);\n\n return (\n <div\n className={cn(\n \"border-t border-[#1E2738] p-3\",\n collapsed ? \"flex flex-col items-center gap-2\" : \"flex items-center gap-3\"\n )}\n >\n {/* Avatar */}\n {user.avatarUrl ? (\n <img\n src={user.avatarUrl}\n alt={user.name}\n className=\"h-8 w-8 rounded-full shrink-0 object-cover\"\n />\n ) : (\n <div className=\"h-8 w-8 rounded-full shrink-0 bg-[#8C34E9]/20 flex items-center justify-center\">\n <span className=\"text-xs font-semibold text-[#A855F7]\">{initials}</span>\n </div>\n )}\n\n {!collapsed && (\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-[#E2E8F0] truncate\">{user.name}</p>\n {user.email && (\n <p className=\"text-[10px] text-[#596475] truncate\">{user.email}</p>\n )}\n {user.role && (\n <p className=\"text-[10px] text-[#8C34E9] capitalize\">{user.role}</p>\n )}\n </div>\n )}\n\n {onLogout && (\n <button\n onClick={onLogout}\n className={cn(\n \"shrink-0 p-1.5 rounded-md\",\n \"text-[#596475] hover:text-[#E2E8F0] hover:bg-[#1E2738]\",\n \"transition-colors cursor-pointer\",\n \"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[#8C34E9]\"\n )}\n title=\"Sign out\"\n >\n <LogOut className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n );\n}\n\n/* ── Main DashboardLayout ── */\n\nexport function DashboardLayout({\n serviceName,\n serviceIcon,\n menuSections,\n activePath,\n onNavigate,\n user,\n isAuthenticated = true,\n isLoading = false,\n onLogout,\n onLogin,\n showBackToPortal = false,\n portalUrl = \"https://portal.oplytics.digital\",\n isAdmin = false,\n adminSections,\n hierarchyNavigator,\n reportingToolbar,\n loadingSkeleton,\n children,\n className,\n}: DashboardLayoutProps) {\n const [collapsed, setCollapsed] = useState(false);\n const [mobileOpen, setMobileOpen] = useState(false);\n\n // Sidebar resize hook\n const { width: sidebarWidth } = useSidebarResize({\n storageKey: `oplytics-sidebar-${serviceName}`,\n defaultWidth: collapsed ? 72 : 260,\n minWidth: 72,\n maxWidth: 480,\n });\n\n const toggleCollapse = useCallback(() => setCollapsed((c) => !c), []);\n const toggleMobile = useCallback(() => setMobileOpen((o) => !o), []);\n const closeMobile = useCallback(() => setMobileOpen(false), []);\n\n const handleNavigate = useCallback(\n (path: string) => {\n onNavigate(path);\n closeMobile();\n },\n [onNavigate, closeMobile]\n );\n\n // Show loading skeleton\n if (isLoading && loadingSkeleton) {\n return <>{loadingSkeleton}</>;\n }\n\n // Redirect to login if not authenticated\n if (!isLoading && !isAuthenticated && onLogin) {\n onLogin();\n return loadingSkeleton ? <>{loadingSkeleton}</> : null;\n }\n\n return (\n <div className={cn(\"min-h-screen flex\", \"bg-[#0A0E1A]\", className)}>\n {/* ── Mobile overlay ── */}\n {mobileOpen && (\n <div\n className=\"fixed inset-0 z-40 bg-black/60 lg:hidden\"\n onClick={closeMobile}\n />\n )}\n\n {/* ── Sidebar ── */}\n <aside\n className={cn(\n \"fixed top-0 left-0 h-full z-50 flex flex-col\",\n \"bg-[#0D1220] border-r border-[#1E2738]\",\n \"transition-all duration-300\",\n // Mobile: slide in/out\n \"lg:relative lg:translate-x-0\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\"\n )}\n style={{ width: sidebarWidth }}\n >\n {/* Sidebar header */}\n <div className={cn(\n \"flex items-center gap-2 p-4 border-b border-[#1E2738]\",\n collapsed && \"justify-center px-2\"\n )}>\n {serviceIcon && (\n <div className=\"shrink-0 text-[#8C34E9]\">{serviceIcon}</div>\n )}\n {!collapsed && (\n <span className=\"text-sm font-semibold text-[#E2E8F0] truncate font-[Montserrat,sans-serif]\">\n {serviceName}\n </span>\n )}\n\n {/* Collapse toggle (desktop) */}\n <button\n onClick={toggleCollapse}\n className={cn(\n \"hidden lg:flex shrink-0 p-1 rounded-md ml-auto\",\n \"text-[#596475] hover:text-[#E2E8F0] hover:bg-[#1E2738]\",\n \"transition-colors cursor-pointer\",\n collapsed && \"ml-0\"\n )}\n >\n {collapsed ? (\n <ChevronRight className=\"h-4 w-4\" />\n ) : (\n <ChevronLeft className=\"h-4 w-4\" />\n )}\n </button>\n\n {/* Close button (mobile) */}\n <button\n onClick={closeMobile}\n className=\"lg:hidden shrink-0 p-1 rounded-md ml-auto text-[#596475] hover:text-[#E2E8F0]\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n\n {/* Hierarchy navigator */}\n {hierarchyNavigator && !collapsed && (\n <div className=\"px-3 py-2 border-b border-[#1E2738]\">\n {hierarchyNavigator}\n </div>\n )}\n\n {/* Back to Portal */}\n {showBackToPortal && (\n <div className={cn(\"px-3 py-2\", collapsed && \"px-2\")}>\n <a\n href={portalUrl}\n className={cn(\n \"flex items-center gap-2 px-3 py-1.5 rounded-md text-xs\",\n \"text-[#596475] hover:text-[#8890A0] hover:bg-[#1E2738]\",\n \"transition-colors\",\n collapsed && \"justify-center px-2\"\n )}\n >\n <ExternalLink className=\"h-3.5 w-3.5 shrink-0\" />\n {!collapsed && <span>Back to Portal</span>}\n </a>\n </div>\n )}\n\n {/* Menu sections */}\n <nav className=\"flex-1 overflow-y-auto px-3 py-3 space-y-4\">\n {menuSections.map((section, idx) => (\n <SidebarSection\n key={section.title || `section-${idx}`}\n section={section}\n activePath={activePath}\n collapsed={collapsed}\n onNavigate={handleNavigate}\n />\n ))}\n\n {/* Admin sections */}\n {isAdmin && adminSections && adminSections.length > 0 && (\n <>\n {!collapsed && (\n <div className=\"mx-3 border-t border-[#1E2738] my-2\" />\n )}\n {adminSections.map((section, idx) => (\n <SidebarSection\n key={section.title || `admin-${idx}`}\n section={section}\n activePath={activePath}\n collapsed={collapsed}\n onNavigate={handleNavigate}\n />\n ))}\n </>\n )}\n </nav>\n\n {/* User profile */}\n {user && (\n <UserProfile\n user={user}\n collapsed={collapsed}\n onLogout={onLogout}\n />\n )}\n </aside>\n\n {/* ── Main content area ── */}\n <div className=\"flex-1 flex flex-col min-w-0\">\n {/* Mobile header */}\n <header className=\"lg:hidden flex items-center gap-3 px-4 py-2.5 border-b border-[#1E2738] bg-[#0D1220]\">\n <button\n onClick={toggleMobile}\n className=\"p-1.5 rounded-md text-[#8890A0] hover:text-[#E2E8F0] hover:bg-[#1E2738]\"\n >\n <Menu className=\"h-5 w-5\" />\n </button>\n <span className=\"text-sm font-semibold text-[#E2E8F0] font-[Montserrat,sans-serif]\">\n {serviceName}\n </span>\n {reportingToolbar && (\n <div className=\"ml-auto\">{reportingToolbar}</div>\n )}\n </header>\n\n {/* Desktop reporting toolbar */}\n {reportingToolbar && (\n <div className=\"hidden lg:flex items-center justify-end px-4 py-1.5 border-b border-[#1E2738] bg-[#0D1220]/50\">\n {reportingToolbar}\n </div>\n )}\n\n {/* Content */}\n <main className=\"flex-1 overflow-y-auto\">\n {children}\n </main>\n </div>\n </div>\n );\n}\n","/**\n * DashboardLayoutSkeleton — loading skeleton for DashboardLayout.\n *\n * Shows a sidebar + content skeleton while auth state is loading.\n * Oplytics dark theme.\n */\nimport { cn } from \"../utils/cn\";\n\nfunction Skeleton({ className }: { className?: string }) {\n return (\n <div\n className={cn(\n \"animate-pulse rounded-md bg-[#1E2738]\",\n className\n )}\n />\n );\n}\n\nexport interface DashboardLayoutSkeletonProps {\n className?: string;\n}\n\nexport function DashboardLayoutSkeleton({ className }: DashboardLayoutSkeletonProps) {\n return (\n <div className={cn(\"flex min-h-screen bg-[#0A0E1A]\", className)}>\n {/* Sidebar skeleton */}\n <div className=\"w-[260px] border-r border-[#1E2738] bg-[#0D1220] p-4 space-y-6\">\n {/* Logo area */}\n <div className=\"flex items-center gap-3 px-2\">\n <Skeleton className=\"h-8 w-8 rounded-md\" />\n <Skeleton className=\"h-4 w-24\" />\n </div>\n\n {/* Menu items */}\n <div className=\"space-y-2 px-2\">\n <Skeleton className=\"h-9 w-full rounded-lg\" />\n <Skeleton className=\"h-9 w-full rounded-lg\" />\n <Skeleton className=\"h-9 w-full rounded-lg\" />\n <Skeleton className=\"h-9 w-full rounded-lg\" />\n </div>\n\n {/* Section divider */}\n <div className=\"px-2\">\n <Skeleton className=\"h-3 w-16 mb-3\" />\n <Skeleton className=\"h-9 w-full rounded-lg\" />\n <Skeleton className=\"h-9 w-full rounded-lg mt-2\" />\n </div>\n\n {/* User profile area at bottom */}\n <div className=\"absolute bottom-4 left-4 right-4\">\n <div className=\"flex items-center gap-3 px-1\">\n <Skeleton className=\"h-8 w-8 rounded-full\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-3 w-20\" />\n <Skeleton className=\"h-2 w-32\" />\n </div>\n </div>\n </div>\n </div>\n\n {/* Main content skeleton */}\n <div className=\"flex-1 p-6 space-y-4\">\n {/* Page header */}\n <div className=\"flex items-center justify-between\">\n <Skeleton className=\"h-8 w-48 rounded-lg\" />\n <Skeleton className=\"h-9 w-24 rounded-lg\" />\n </div>\n\n {/* Stats cards */}\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <Skeleton className=\"h-24 rounded-xl\" />\n <Skeleton className=\"h-24 rounded-xl\" />\n <Skeleton className=\"h-24 rounded-xl\" />\n <Skeleton className=\"h-24 rounded-xl\" />\n </div>\n\n {/* Main content area */}\n <Skeleton className=\"h-64 rounded-xl\" />\n\n {/* Table-like area */}\n <div className=\"space-y-2\">\n <Skeleton className=\"h-10 w-full rounded-lg\" />\n <Skeleton className=\"h-10 w-full rounded-lg\" />\n <Skeleton className=\"h-10 w-full rounded-lg\" />\n </div>\n </div>\n </div>\n );\n}\n","/**\n * SharedPageHeader — standard page header for all Oplytics subdomains.\n *\n * Displays: page title, optional subtitle, optional breadcrumbs,\n * optional action buttons, and optional HierarchyNavigator.\n *\n * Oplytics dark theme: #0A0E1A bg, #8C34E9 accent, #E2E8F0 text, #8890A0 muted\n */\nimport { cn } from \"../utils/cn\";\nimport { ChevronLeft } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\n\nexport interface SharedPageHeaderProps {\n /** Page title */\n title: string;\n /** Optional subtitle / description */\n subtitle?: string;\n /** Optional icon to display before the title */\n icon?: ReactNode;\n /** Optional back button handler — shows a back arrow when provided */\n onBack?: () => void;\n /** Optional action buttons to render on the right side */\n actions?: ReactNode;\n /** Optional breadcrumb trail (e.g. HierarchyNavigator) */\n breadcrumbs?: ReactNode;\n /** Whether to show a bottom border (default: true) */\n showBorder?: boolean;\n /** Compact mode — smaller spacing and text (default: false) */\n compact?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Children rendered below the header row */\n children?: ReactNode;\n}\n\nexport function SharedPageHeader({\n title,\n subtitle,\n icon,\n onBack,\n actions,\n breadcrumbs,\n showBorder = true,\n compact = false,\n className,\n children,\n}: SharedPageHeaderProps) {\n return (\n <div\n className={cn(\n \"w-full\",\n showBorder && \"border-b border-[#1E2738]\",\n compact ? \"px-4 py-3\" : \"px-6 py-4\",\n className\n )}\n >\n {/* Breadcrumbs row */}\n {breadcrumbs && (\n <div className={cn(\"mb-2\", compact && \"mb-1\")}>\n {breadcrumbs}\n </div>\n )}\n\n {/* Main header row */}\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"flex items-center gap-3 min-w-0\">\n {/* Back button */}\n {onBack && (\n <button\n onClick={onBack}\n className={cn(\n \"shrink-0 p-1.5 rounded-md\",\n \"text-[#8890A0] hover:text-[#E2E8F0] hover:bg-[#1E2738]\",\n \"transition-colors cursor-pointer\",\n \"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[#8C34E9]\"\n )}\n aria-label=\"Go back\"\n >\n <ChevronLeft className={compact ? \"h-4 w-4\" : \"h-5 w-5\"} />\n </button>\n )}\n\n {/* Icon */}\n {icon && (\n <div className=\"shrink-0 text-[#8C34E9]\">\n {icon}\n </div>\n )}\n\n {/* Title + subtitle */}\n <div className=\"min-w-0\">\n <h1\n className={cn(\n \"font-semibold text-[#E2E8F0] truncate\",\n \"font-[Montserrat,sans-serif]\",\n compact ? \"text-lg\" : \"text-xl\"\n )}\n >\n {title}\n </h1>\n {subtitle && (\n <p\n className={cn(\n \"text-[#8890A0] truncate mt-0.5\",\n \"font-[Space_Grotesk,sans-serif]\",\n compact ? \"text-xs\" : \"text-sm\"\n )}\n >\n {subtitle}\n </p>\n )}\n </div>\n </div>\n\n {/* Action buttons */}\n {actions && (\n <div className=\"shrink-0 flex items-center gap-2\">\n {actions}\n </div>\n )}\n </div>\n\n {/* Optional children below header */}\n {children && (\n <div className={cn(\"mt-3\", compact && \"mt-2\")}>\n {children}\n </div>\n )}\n </div>\n );\n}\n","/**\n * SharedFooter — standard footer for all Oplytics subdomains.\n *\n * Displays: Oplytics branding, service links, legal links, copyright.\n * Consistent across all subdomains.\n *\n * Oplytics dark theme: #0D1220 bg, #1E2738 border, #8890A0 text, #8C34E9 accent\n */\nimport { cn } from \"../utils/cn\";\nimport type { ReactNode } from \"react\";\n\n/* ── Service definitions ── */\n\nexport interface FooterService {\n name: string;\n slug: string;\n /** Local route within the portal (e.g. /services/sqdcp) */\n localRoute: string;\n /** External URL for the subdomain (e.g. https://sqdcp.oplytics.digital) */\n externalUrl?: string;\n}\n\n/** Standard Oplytics service list */\nexport const FOOTER_SERVICES: FooterService[] = [\n { name: \"SQDCP\", slug: \"sqdcp\", localRoute: \"/services/sqdcp\", externalUrl: \"https://sqdcp.oplytics.digital\" },\n { name: \"OEE Manager\", slug: \"oee-manager\", localRoute: \"/services/oee-manager\", externalUrl: \"https://oee.oplytics.digital\" },\n { name: \"Policy Deployment\", slug: \"policy-deployment\", localRoute: \"/services/policy-deployment\", externalUrl: \"https://policy.oplytics.digital\" },\n { name: \"Action Manager\", slug: \"action-manager\", localRoute: \"/services/action-manager\", externalUrl: \"https://actions.oplytics.digital\" },\n { name: \"Safety Manager\", slug: \"safety-manager\", localRoute: \"/services/safety-manager\" },\n { name: \"Connect\", slug: \"connect\", localRoute: \"/services/connect\", externalUrl: \"https://connect.oplytics.digital\" },\n];\n\n/* ── Footer props ── */\n\nexport interface SharedFooterProps {\n /** Override the default service list */\n services?: FooterService[];\n /** Show pricing link (default: true) */\n showPricing?: boolean;\n /** Show sign-in link (default: true) */\n showSignIn?: boolean;\n /** Handler for service link clicks — receives the service */\n onServiceClick?: (service: FooterService, e: React.MouseEvent) => void;\n /** Handler for pricing link click */\n onPricingClick?: (e: React.MouseEvent) => void;\n /** Handler for sign-in link click */\n onSignInClick?: (e: React.MouseEvent) => void;\n /** Additional content to render in the footer */\n children?: ReactNode;\n /** CSS class for the footer container */\n className?: string;\n /** Whether to use external URLs (subdomain links) or local routes */\n useExternalUrls?: boolean;\n /** Current year override (default: auto) */\n year?: number;\n}\n\n/* ── Component ── */\n\nexport function SharedFooter({\n services = FOOTER_SERVICES,\n showPricing = true,\n showSignIn = true,\n onServiceClick,\n onPricingClick,\n onSignInClick,\n children,\n className,\n useExternalUrls = false,\n year,\n}: SharedFooterProps) {\n const currentYear = year ?? new Date().getFullYear();\n\n return (\n <footer\n className={cn(\n \"w-full border-t border-[#1E2738]\",\n \"bg-[#0D1220] text-[#8890A0]\",\n \"font-[Space_Grotesk,sans-serif]\",\n className\n )}\n >\n <div className=\"max-w-7xl mx-auto px-6 py-10\">\n {/* Top section: Logo + columns */}\n <div className=\"grid grid-cols-1 md:grid-cols-4 gap-8 mb-8\">\n {/* Brand column */}\n <div className=\"md:col-span-1\">\n <div className=\"flex items-center gap-2 mb-3\">\n <div\n className=\"w-7 h-7 rounded-full flex items-center justify-center\"\n style={{ background: \"#8C34E9\" }}\n >\n <span className=\"text-white font-bold text-xs\">O</span>\n </div>\n <span className=\"text-[#E2E8F0] font-semibold text-sm font-[Montserrat,sans-serif]\">\n Oplytics.digital\n </span>\n </div>\n <p className=\"text-xs text-[#596475] leading-relaxed\">\n Operational intelligence platform for manufacturing excellence.\n </p>\n </div>\n\n {/* Services column */}\n <div>\n <h4 className=\"text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]\">\n Services\n </h4>\n <ul className=\"space-y-2\">\n {services.map((service) => (\n <li key={service.slug}>\n <a\n href={useExternalUrls && service.externalUrl ? service.externalUrl : service.localRoute}\n onClick={onServiceClick ? (e) => onServiceClick(service, e) : undefined}\n className=\"text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors\"\n >\n {service.name}\n </a>\n </li>\n ))}\n </ul>\n </div>\n\n {/* Company column */}\n <div>\n <h4 className=\"text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]\">\n Company\n </h4>\n <ul className=\"space-y-2\">\n {showPricing && (\n <li>\n <a\n href=\"/pricing\"\n onClick={onPricingClick}\n className=\"text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors\"\n >\n Pricing\n </a>\n </li>\n )}\n <li>\n <a\n href=\"/about\"\n className=\"text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors\"\n >\n About\n </a>\n </li>\n <li>\n <a\n href=\"/contact\"\n className=\"text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors\"\n >\n Contact\n </a>\n </li>\n </ul>\n </div>\n\n {/* Legal column */}\n <div>\n <h4 className=\"text-[#E2E8F0] font-medium text-xs uppercase tracking-wider mb-3 font-[Montserrat,sans-serif]\">\n Legal\n </h4>\n <ul className=\"space-y-2\">\n <li>\n <a\n href=\"/privacy\"\n className=\"text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors\"\n >\n Privacy Policy\n </a>\n </li>\n <li>\n <a\n href=\"/terms\"\n className=\"text-xs text-[#8890A0] hover:text-[#E2E8F0] transition-colors\"\n >\n Terms of Service\n </a>\n </li>\n </ul>\n {showSignIn && (\n <div className=\"mt-4\">\n <a\n href=\"/login\"\n onClick={onSignInClick}\n className=\"text-xs text-[#8C34E9] hover:text-[#A855F7] transition-colors font-medium\"\n >\n Sign In\n </a>\n </div>\n )}\n </div>\n </div>\n\n {/* Custom content */}\n {children}\n\n {/* Bottom bar */}\n <div className=\"pt-6 border-t border-[#1E2738] flex flex-col sm:flex-row items-center justify-between gap-3\">\n <p className=\"text-xs text-[#596475]\">\n &copy; {currentYear} Oplytics.digital. All rights reserved.\n </p>\n <p className=\"text-xs text-[#3E4A5C]\">\n Built for manufacturing excellence\n </p>\n </div>\n </div>\n </footer>\n );\n}\n","/**\n * createServiceLayout — Factory function that generates a complete DashboardLayout\n * for any Oplytics subdomain from a SharedSidebarConfig.\n *\n * This is the primary API for subdomains. Instead of each subdomain maintaining\n * its own 200-350 line DashboardLayout, they call:\n *\n * const SQDCPLayout = createServiceLayout({ serviceName: \"SQDCP\", ... });\n *\n * And get a fully-featured layout with:\n * - Resizable sidebar with all standard features\n * - SharedPageHeader integration\n * - ReportingToolbar integration (optional)\n * - HierarchyProvider wrapping (optional)\n * - Auth gate with loading skeleton + sign-in fallback (optional)\n * - User footer with logout dropdown\n *\n * @module shared/components/createServiceLayout\n */\n\nimport React from \"react\";\nimport type { SharedSidebarConfig, MenuSection } from \"./SharedSidebar\";\nimport { isAdminRole, getInitials, isMenuItemActive, useSidebarResize } from \"./SharedSidebar\";\n\n/* ── Service Layout Configuration ── */\n\nexport interface ServiceLayoutConfig extends SharedSidebarConfig {\n /** Show SharedPageHeader above content (default: true) */\n showPageHeader?: boolean;\n /** SharedPageHeader props — passed through when showPageHeader is true */\n pageHeaderProps?: {\n showHierarchy?: boolean;\n hierarchyMaxDepth?: number;\n showSidebarTrigger?: boolean;\n };\n /** Show ReportingToolbar in the header (default: false) */\n showReportingToolbar?: boolean;\n /** Module name passed to ReportingToolbar */\n reportingModuleName?: string;\n /** Wrap layout in HierarchyProvider (default: false) */\n wrapHierarchyProvider?: boolean;\n /** Show auth gate — loading skeleton + sign-in fallback (default: true) */\n showAuthGate?: boolean;\n /** Report submit handler */\n onReportSubmit?: (report: any) => Promise<void> | void;\n /** Feedback submit handler */\n onFeedbackSubmit?: (feedback: any) => Promise<void> | void;\n}\n\n/**\n * Creates a service-specific layout component from configuration.\n *\n * NOTE: This is a blueprint/factory specification. The actual React component\n * is assembled by each subdomain using their local UI primitives (Sidebar,\n * SidebarProvider, etc.) since these are not shared across subdomains yet.\n *\n * When subdomain consolidation (#311) is complete, this factory will directly\n * render the shared UI primitives. Until then, subdomains use this config\n * to standardise their DashboardLayout implementations.\n *\n * @example\n * ```tsx\n * // In SQDCP's DashboardLayout.tsx:\n * import { sqdcpLayoutConfig } from \"./sqdcp-config\";\n * // Use sqdcpLayoutConfig.menuSections, .backLink, etc. to build the layout\n * ```\n */\nexport function defineServiceLayout(config: ServiceLayoutConfig): ServiceLayoutConfig {\n return {\n defaultWidth: 260,\n minWidth: 200,\n maxWidth: 480,\n showPageHeader: true,\n showReportingToolbar: false,\n wrapHierarchyProvider: false,\n showAuthGate: true,\n ...config,\n storageKeyPrefix: config.storageKeyPrefix || config.serviceName.toLowerCase().replace(/\\s+/g, \"-\"),\n };\n}\n\n/* ── Pre-built Service Configurations ── */\n\n// These are the canonical configurations for each subdomain.\n// Subdomains should import and use these instead of defining their own.\n\nexport { isAdminRole, getInitials, isMenuItemActive, useSidebarResize };\n","/**\n * Canonical Service Layout Configurations for all Oplytics subdomains.\n *\n * Each subdomain imports its config from here and uses it to build its\n * DashboardLayout. This ensures consistency across all services while\n * allowing per-service customisation (menu items, features, etc.).\n *\n * When subdomain consolidation (#311) is complete, these configs will\n * drive the shared createServiceLayout factory directly.\n *\n * @module shared/components/serviceConfigs\n */\n\nimport type { ServiceLayoutConfig } from \"./createServiceLayout\";\n\n/* ── Icon placeholder types ── */\n// Icons are imported locally by each subdomain from lucide-react.\n// These configs use string identifiers that map to icon components.\n\nexport interface MenuItemConfig {\n iconName: string;\n label: string;\n path: string;\n}\n\nexport interface MenuSectionConfig {\n label?: string;\n items: MenuItemConfig[];\n adminOnly?: boolean;\n}\n\nexport interface ServiceConfig {\n serviceName: string;\n serviceAbbreviation: string;\n serviceIconName: string;\n menuSections: MenuSectionConfig[];\n backLink?: {\n label: string;\n path: string;\n };\n showPageHeader: boolean;\n showReportingToolbar: boolean;\n reportingModuleName?: string;\n wrapHierarchyProvider: boolean;\n showAuthGate: boolean;\n storageKeyPrefix: string;\n defaultWidth: number;\n minWidth: number;\n maxWidth: number;\n}\n\n/* ── SQDCP ── */\n\nexport const sqdcpConfig: ServiceConfig = {\n serviceName: \"SQDCP\",\n serviceAbbreviation: \"S\",\n serviceIconName: \"BarChart3\",\n menuSections: [\n {\n items: [\n { iconName: \"LayoutDashboard\", label: \"Dashboard\", path: \"/\" },\n { iconName: \"PenLine\", label: \"Data Entry\", path: \"/entry\" },\n { iconName: \"ClipboardList\", label: \"Action Tracker\", path: \"/actions\" },\n { iconName: \"FileText\", label: \"Reports\", path: \"/reports\" },\n { iconName: \"Settings\", label: \"Admin\", path: \"/admin\" },\n ],\n },\n ],\n showPageHeader: true,\n showReportingToolbar: true,\n reportingModuleName: \"SQDCP\",\n wrapHierarchyProvider: false,\n showAuthGate: false,\n storageKeyPrefix: \"sqdcp-sidebar\",\n defaultWidth: 260,\n minWidth: 200,\n maxWidth: 480,\n};\n\n/* ── OEE Manager ── */\n\nexport const oeeManagerConfig: ServiceConfig = {\n serviceName: \"OEE Manager\",\n serviceAbbreviation: \"o\",\n serviceIconName: \"BarChart3\",\n menuSections: [\n {\n items: [\n { iconName: \"BarChart3\", label: \"Dashboard\", path: \"/\" },\n { iconName: \"Database\", label: \"Data Input\", path: \"/data-input\" },\n { iconName: \"Clock\", label: \"Downtime\", path: \"/downtime\" },\n { iconName: \"Settings\", label: \"Settings\", path: \"/settings\" },\n ],\n },\n ],\n backLink: {\n label: \"Back to Portal\",\n path: \"https://portal.oplytics.digital\",\n },\n showPageHeader: true,\n showReportingToolbar: true,\n reportingModuleName: \"OEE Enterprise Manager\",\n wrapHierarchyProvider: false,\n showAuthGate: false,\n storageKeyPrefix: \"oee-sidebar\",\n defaultWidth: 240,\n minWidth: 200,\n maxWidth: 400,\n};\n\n/* ── Action Manager ── */\n\nexport const actionManagerConfig: ServiceConfig = {\n serviceName: \"Action Manager\",\n serviceAbbreviation: \"A\",\n serviceIconName: \"LayoutDashboard\",\n menuSections: [\n {\n items: [\n { iconName: \"LayoutDashboard\", label: \"Dashboard\", path: \"/\" },\n { iconName: \"Users\", label: \"Teams\", path: \"/teams\" },\n ],\n },\n ],\n showPageHeader: true,\n showReportingToolbar: false,\n reportingModuleName: \"Action Manager\",\n wrapHierarchyProvider: false,\n showAuthGate: true,\n storageKeyPrefix: \"actionmanager-sidebar\",\n defaultWidth: 280,\n minWidth: 200,\n maxWidth: 480,\n};\n\n/* ── Business Hub ── */\n\nexport const businessHubConfig: ServiceConfig = {\n serviceName: \"Business Hub\",\n serviceAbbreviation: \"B\",\n serviceIconName: \"LayoutDashboard\",\n menuSections: [\n {\n items: [\n { iconName: \"LayoutDashboard\", label: \"Dashboard\", path: \"/\" },\n { iconName: \"Users\", label: \"Analytics\", path: \"/analytics\" },\n ],\n },\n ],\n showPageHeader: true,\n showReportingToolbar: false,\n reportingModuleName: \"Business Hub\",\n wrapHierarchyProvider: false,\n showAuthGate: true,\n storageKeyPrefix: \"businesshub-sidebar\",\n defaultWidth: 280,\n minWidth: 200,\n maxWidth: 480,\n};\n\n/* ── Policy Deployment ── */\n\nexport const policyDeploymentConfig: ServiceConfig = {\n serviceName: \"Policy Deployment\",\n serviceAbbreviation: \"PD\",\n serviceIconName: \"FileStack\",\n menuSections: [\n {\n label: \"Analysis\",\n items: [\n { iconName: \"LayoutGrid\", label: \"Dashboard\", path: \"/app/policy-deployment\" },\n { iconName: \"Grid3X3\", label: \"X-Matrix\", path: \"/app/policy-deployment/xmatrix\" },\n { iconName: \"BarChart3\", label: \"Bowling Chart\", path: \"/app/policy-deployment/bowling\" },\n { iconName: \"FolderKanban\", label: \"Action Plans\", path: \"/app/policy-deployment/actions\" },\n { iconName: \"GitBranchPlus\", label: \"Catchball\", path: \"/app/policy-deployment/catchball\" },\n { iconName: \"Target\", label: \"Deployments\", path: \"/app/policy-deployment/deployments\" },\n ],\n },\n {\n label: \"Administration\",\n adminOnly: true,\n items: [\n { iconName: \"Settings\", label: \"Manage Policy\", path: \"/app/policy-deployment/manage\" },\n { iconName: \"Plug\", label: \"Integrations\", path: \"/app/policy-deployment/integrations\" },\n ],\n },\n ],\n backLink: {\n label: \"Service Hub\",\n path: \"/app\",\n },\n showPageHeader: true,\n showReportingToolbar: true,\n reportingModuleName: \"Policy Deployment\",\n wrapHierarchyProvider: true,\n showAuthGate: true,\n storageKeyPrefix: \"policy-sidebar\",\n defaultWidth: 260,\n minWidth: 200,\n maxWidth: 480,\n};\n\n/* ── All configs indexed by service key ── */\n\nexport const SERVICE_CONFIGS = {\n sqdcp: sqdcpConfig,\n oeeManager: oeeManagerConfig,\n actionManager: actionManagerConfig,\n businessHub: businessHubConfig,\n policyDeployment: policyDeploymentConfig,\n} as const;\n\nexport type ServiceKey = keyof typeof SERVICE_CONFIGS;\n"],"mappings":"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","names":["useState","jsx","jsxs","ChevronLeft","jsx","jsxs","jsx","jsxs"]}