@fluid-app/portal-sdk 0.1.236 → 0.1.237
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.
- package/dist/index.cjs +11 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +11 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -12
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["React","Slot","useScreenHeaderContext","PanelLeft","ICON_MAP","ContactRound","Repeat","Bell","Box","Boxes","Briefcase","Calendar","ShoppingCart","CircleUser","MessageCircle","Compass","Mail","File","FileText","FileVideo","Folder","FolderOpen","Settings","Globe","GraduationCap","Heart","House","Image","ListMusic","Search","MessageSquare","PackageOpen","Star","Store","LayoutGrid","User","UserCog","Users","React","Ellipsis","X","getActiveThemeId","transformThemes","createPersister","useAppDefinitionApi","Collapsible","CollapsibleTrigger","ChevronRight","CollapsibleContent","useRepUser","X","Smartphone","Moon","Sun","LogOut","Moon","Sun","Menu","Building2","cn","Skeleton","useStore","Card","CardHeader","CardTitle","CardDescription","CardFooter","Compass","Button","useRegistry","DataAwareWidget","User","PackageOpen","Repeat","useAppNavigation","ProfileScreen","OrdersScreen","SubscriptionsScreen","MessagingScreen","ContactsScreen","ShopScreen","CustomersScreen","ShareablesScreen","MySiteScreen","useAccount","Suspense","CoreScreenPlaceholder","Component","TriangleAlert","Button","deleteDatabase","LogOut","useAccount","getDefaultThemeDefinition","resolveTheme","ScreenHeaderProvider","RepUserProvider","AppNavigationProvider","Toaster","DEFAULT_SDK_WIDGET_REGISTRY","Component","FluidProvider","StrictMode","useAppDefinitionApi","useAppDefinitionApi","useThemeContext","usePortalTenantClient","deleteDatabase","now","daysFromNow","now","now","hoursAgo","now","daysAgo","z","useAccount","Popover","PopoverTrigger","Button","LayoutGrid","PopoverContent","useAppNavigation"],"sources":["../src/types/page-template.ts","../src/registries/page-template-registry.ts","../src/core/resolve-pages.ts","../src/providers/PageTemplateProvider.tsx","../../react/src/shell/use-mobile.ts","../../react/src/shell/sidebar.tsx","../../react/src/shell/AppShellLayout.tsx","../../react/src/shell/ThemeModeContext.tsx","../../core/src/navigation/system-navigation-items.ts","../../core/src/navigation/default-navigation.ts","../../react/src/shell/ScreenHeader.tsx","../../react/src/components/RepIcon.tsx","../../core/src/navigation/navigation-storage.ts","../../core/src/navigation/navigation-utils.ts","../src/shell/SdkBottomNav.tsx","../src/hooks/query-keys.ts","../src/transforms/screen-transforms.ts","../src/transforms/navigation-transforms.ts","../src/transforms/index.ts","../src/hooks/use-fluid-app.ts","../src/shell/AppShellLoading.tsx","../src/shell/CollapsibleNavItem.tsx","../src/shell/SdkNavigation.tsx","../src/shell/SdkMobileProfileMenu.tsx","../src/shell/SdkHeader.tsx","../../../company-switcher/ui/src/components/CompanyImage.tsx","../../../company-switcher/ui/src/components/CompanyItem.tsx","../../../company-switcher/ui/src/components/CompanySwitcherSkeleton.tsx","../src/shell/SdkCompanySwitcher.tsx","../../core/src/navigation/account-manage.ts","../src/shell/go-back-or-home.ts","../src/screens/FallbackCard.tsx","../src/screens/ScreenNotFound.tsx","../src/screens/AccessDeniedScreen.tsx","../src/shell/BuilderScreenView.tsx","../src/account/account-management-layout.tsx","../src/shell/system-screen-map.ts","../src/shell/PageRouter.tsx","../../core/src/navigation/slug-utils.ts","../src/shell/AppShellErrorBoundary.tsx","../src/hooks/use-logout.ts","../src/shell/SdkLogoutButton.tsx","../src/navigation/filter-nav-items.ts","../src/shell/AppShell.tsx","../src/config/env.ts","../src/config/defaults.ts","../src/utils/build-widget-registry.ts","../src/entry/create-portal.tsx","../src/hooks/use-fluid-profile.ts","../src/hooks/use-app-definition.ts","../src/hooks/use-fluid-theme.ts","../src/hooks/use-company-switch.ts","../src/hooks/demo-data/calendar-events.ts","../src/hooks/use-calendar-events.ts","../src/hooks/demo-data/todos.ts","../src/hooks/use-todos.ts","../src/hooks/hook-types.ts","../src/hooks/demo-data/activities.ts","../src/hooks/use-activities.ts","../src/hooks/demo-data/catchups.ts","../src/hooks/use-catchups.ts","../src/hooks/demo-data/mysite.ts","../src/hooks/use-mysite.ts","../src/hooks/demo-data/conversations.ts","../src/hooks/use-conversations.ts","../src/types/screen-types.ts","../src/hooks/demo-data/contacts.ts","../src/hooks/use-contacts.ts","../../../platform/auth/src/types.ts","../../../platform/auth/src/company-switch.ts","../src/screens/index.ts","../src/shell/QuickLinksDropdown.tsx","../src/shell/AppLink.tsx","../src/scaffold/manifest.ts"],"sourcesContent":["import type { WidgetSchema } from \"./widget-schema\";\n\n/**\n * Category for organizing page templates in the registry\n */\nexport interface PageCategory {\n /** Unique identifier for the category */\n readonly id: string;\n /** Display label */\n label: string;\n /** Icon identifier (e.g., lucide icon name) */\n icon?: string;\n}\n\n/**\n * A reusable page template that can be shared across multiple navigations\n */\nexport interface PageTemplate {\n /** Unique identifier for the template */\n readonly id: string;\n /** URL-friendly slug */\n slug: string;\n /** Display name */\n name: string;\n /** Description of the template's purpose */\n description?: string;\n /** Category ID for organization */\n category: string;\n /** Tags for filtering and search */\n tags?: readonly string[];\n /** The widget tree that defines the page content */\n component_tree: readonly WidgetSchema[];\n /** Semantic version of the template */\n version: string;\n /** Whether this is a core feature that cannot be removed */\n isCore?: boolean;\n /** Default prop values that can be customized */\n defaultProps?: Readonly<Record<string, unknown>>;\n /** Thumbnail image URL for UI display */\n thumbnail?: string;\n}\n\n/**\n * Reference to a shared page template within a navigation\n */\nexport interface PageReference {\n /** ID of the page template being referenced */\n page_template_id: string;\n /** Screen ID to assign to this page in the navigation */\n screen_id: number;\n /** Optional prop overrides (only prop values, not widget structure) */\n overrides?: readonly PageOverride[];\n}\n\n/**\n * Override for a specific widget's props within a page template\n */\nexport interface PageOverride {\n /** ID of the widget to override (must match WidgetSchema.id in the template) */\n readonly widget_id: string;\n /** Props to override (merged with original props) */\n props: Readonly<Record<string, unknown>>;\n}\n\n/**\n * Built-in page category IDs\n */\nexport const PAGE_CATEGORIES = {\n CORE: \"core\",\n COMMERCE: \"commerce\",\n COMMUNICATION: \"communication\",\n DATA: \"data\",\n CUSTOM: \"custom\",\n} as const;\n\nexport type PageCategoryId =\n (typeof PAGE_CATEGORIES)[keyof typeof PAGE_CATEGORIES];\n","import type {\n PageTemplate,\n PageCategory,\n PageCategoryId,\n} from \"../types/page-template\";\nimport { PAGE_CATEGORIES } from \"../types/page-template\";\n\n/**\n * Registry for managing reusable page templates.\n *\n * The registry provides a central store for page templates that can be\n * shared across multiple navigations. Core pages (like Messaging, Contacts)\n * are pre-registered and cannot be removed.\n *\n * @example\n * ```ts\n * // Register a custom page template\n * PageTemplateRegistry.register({\n * id: 'custom-dashboard',\n * slug: 'dashboard',\n * name: 'Custom Dashboard',\n * category: 'custom',\n * version: '1.0.0',\n * component_tree: [{ type: 'TextWidget', props: { text: 'Hello' } }],\n * });\n *\n * // Get a template by ID\n * const template = PageTemplateRegistry.get('custom-dashboard');\n *\n * // List all templates in a category\n * const corePages = PageTemplateRegistry.getByCategory('core');\n * ```\n */\nclass PageTemplateRegistryImpl {\n private templates = new Map<string, PageTemplate>();\n private categories: PageCategory[] = [];\n\n constructor() {\n // Initialize default categories\n this.categories = [\n { id: PAGE_CATEGORIES.CORE, label: \"Core Features\", icon: \"star\" },\n {\n id: PAGE_CATEGORIES.COMMERCE,\n label: \"Commerce\",\n icon: \"shopping-cart\",\n },\n {\n id: PAGE_CATEGORIES.COMMUNICATION,\n label: \"Communication\",\n icon: \"message-circle\",\n },\n {\n id: PAGE_CATEGORIES.DATA,\n label: \"Data & Analytics\",\n icon: \"bar-chart\",\n },\n { id: PAGE_CATEGORIES.CUSTOM, label: \"Custom\", icon: \"puzzle\" },\n ];\n }\n\n /**\n * Register a new page template.\n * @throws Error if a template with the same ID already exists\n */\n register(template: PageTemplate): void {\n if (this.templates.has(template.id)) {\n throw new Error(\n `Page template with ID \"${template.id}\" is already registered`,\n );\n }\n this.templates.set(template.id, template);\n }\n\n /**\n * Unregister a page template by ID.\n * Core templates cannot be unregistered.\n * @returns true if the template was removed, false if it didn't exist or is a core template\n */\n unregister(id: string): boolean {\n const template = this.templates.get(id);\n if (!template) {\n return false;\n }\n if (template.isCore) {\n console.warn(\n `Cannot unregister core page template \"${id}\". Core templates are required.`,\n );\n return false;\n }\n return this.templates.delete(id);\n }\n\n /**\n * Get a page template by ID.\n */\n get(id: string): PageTemplate | undefined {\n return this.templates.get(id);\n }\n\n /**\n * Get all page templates in a specific category.\n */\n getByCategory(category: PageCategoryId | string): PageTemplate[] {\n return Array.from(this.templates.values()).filter(\n (t) => t.category === category,\n );\n }\n\n /**\n * List all registered page templates.\n */\n listAll(): PageTemplate[] {\n return Array.from(this.templates.values());\n }\n\n /**\n * List all core page templates (isCore: true).\n */\n listCore(): PageTemplate[] {\n return Array.from(this.templates.values()).filter((t) => t.isCore);\n }\n\n /**\n * List all non-core page templates.\n */\n listOptional(): PageTemplate[] {\n return Array.from(this.templates.values()).filter((t) => !t.isCore);\n }\n\n /**\n * List all registered categories.\n */\n listCategories(): PageCategory[] {\n return [...this.categories];\n }\n\n /**\n * Add a custom category.\n */\n addCategory(category: PageCategory): void {\n if (this.categories.some((c) => c.id === category.id)) {\n console.warn(`Category with ID \"${category.id}\" already exists`);\n return;\n }\n this.categories.push(category);\n }\n\n /**\n * Check if a template exists by ID.\n */\n has(id: string): boolean {\n return this.templates.has(id);\n }\n\n /**\n * Get the count of registered templates.\n */\n get size(): number {\n return this.templates.size;\n }\n\n /**\n * Clear all non-core templates.\n * Useful for testing or resetting the registry.\n */\n clearNonCore(): void {\n for (const [id, template] of this.templates) {\n if (!template.isCore) {\n this.templates.delete(id);\n }\n }\n }\n}\n\n/**\n * Global page template registry singleton.\n *\n * This registry is automatically populated with core page templates\n * (Messaging, Contacts) when the SDK is imported.\n */\nexport const PageTemplateRegistry: PageTemplateRegistryImpl =\n new PageTemplateRegistryImpl();\n","import type { Navigation, ScreenDefinition, WidgetSchema } from \"../types\";\nimport type {\n PageReference,\n PageOverride,\n PageTemplate,\n} from \"../types/page-template\";\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\n\n/**\n * Apply prop overrides to widgets in a component tree.\n * Recursively walks widget.props.children so overrides targeting\n * nested widgets (inside LayoutWidget, ContainerWidget, etc.) are applied.\n *\n * @param componentTree - The original component tree from the page template\n * @param overrides - Array of widget-specific prop overrides\n * @returns A new component tree with overrides applied\n */\nfunction applyOverrides(\n componentTree: readonly WidgetSchema[],\n overrides: readonly PageOverride[],\n): WidgetSchema[] {\n if (!overrides.length) {\n // Return a mutable copy to satisfy ScreenDefinition.component_tree type\n return [...componentTree];\n }\n\n // Build a map of widget_id -> override for O(1) lookup (built once, shared across recursion)\n const overrideMap = new Map(overrides.map((o) => [o.widget_id, o.props]));\n\n return componentTree.map((widget) =>\n applyWidgetOverrides(widget, overrideMap),\n );\n}\n\n/**\n * Recursively apply overrides to a widget and its children.\n * Only clones widgets that actually change (have an override or contain children that might).\n */\nfunction applyWidgetOverrides(\n widget: WidgetSchema,\n overrideMap: ReadonlyMap<string, Record<string, unknown>>,\n): WidgetSchema {\n const override = widget.id ? overrideMap.get(widget.id) : undefined;\n const children = widget.props.children;\n\n // Recurse into children if they exist (LayoutWidget, ContainerWidget)\n const hasChildren = Array.isArray(children) && children.length > 0;\n\n if (!override && !hasChildren) {\n return widget;\n }\n\n const newProps = override\n ? { ...widget.props, ...override }\n : { ...widget.props };\n\n if (hasChildren) {\n newProps.children = (children as readonly WidgetSchema[]).map((child) =>\n applyWidgetOverrides(child, overrideMap),\n );\n }\n\n return { ...widget, props: newProps };\n}\n\n/**\n * Resolve a page reference to a screen definition.\n *\n * @param ref - The page reference from navigation\n * @returns A ScreenDefinition or undefined if the template doesn't exist\n */\nfunction resolvePageReference(\n ref: Readonly<PageReference>,\n): ScreenDefinition | undefined {\n const template = PageTemplateRegistry.get(ref.page_template_id);\n if (!template) {\n console.warn(\n `Page template \"${ref.page_template_id}\" not found in registry`,\n );\n return undefined;\n }\n\n // Apply any overrides to the component tree\n // Spread to create mutable array for ScreenDefinition.component_tree\n const componentTree = ref.overrides\n ? applyOverrides(template.component_tree, ref.overrides)\n : [...template.component_tree];\n\n return {\n id: ref.screen_id,\n slug: template.slug,\n name: template.name,\n component_tree: componentTree,\n };\n}\n\n/**\n * Resolve all page references and local screens into a unified screen list.\n *\n * This function merges:\n * 1. Screen definitions from page_refs (shared templates)\n * 2. Local screen definitions (for backwards compatibility and custom screens)\n *\n * When a screen_id appears in both page_refs and screens, the local screen\n * takes precedence (allows local overrides of template pages).\n *\n * @param navigation - The navigation configuration\n * @returns A unified array of ScreenDefinition objects\n *\n * @example\n * ```ts\n * const navigation: Navigation = {\n * definition_id: 1,\n * id: 1,\n * name: \"Main Nav\",\n * navigation_items: [...],\n * screens: [\n * // Local custom screen\n * { id: 1, slug: \"home\", name: \"Home\", component_tree: [...] }\n * ],\n * page_refs: [\n * // Reference to shared messaging template\n * { page_template_id: \"core-messaging\", screen_id: 2 }\n * ],\n * };\n *\n * const allScreens = resolveNavigationPages(navigation);\n * // Returns: [home screen, messaging screen from template]\n * ```\n */\nexport function resolveNavigationPages(\n navigation: Readonly<Navigation>,\n): ScreenDefinition[] {\n // Start with local screens (these take precedence)\n const localScreenIds = new Set(navigation.screens.map((s) => s.id));\n const result: ScreenDefinition[] = [...navigation.screens];\n\n // Resolve page references (skip if local screen already exists with same ID)\n if (navigation.page_refs) {\n for (const ref of navigation.page_refs) {\n if (localScreenIds.has(ref.screen_id)) {\n // Local screen takes precedence\n continue;\n }\n\n const screen = resolvePageReference(ref);\n if (screen) {\n result.push(screen);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Get all available page templates for use in navigation.\n *\n * @returns Array of page templates from the registry\n */\nexport function getAvailablePageTemplates(): PageTemplate[] {\n return PageTemplateRegistry.listAll();\n}\n\n/**\n * Get core page templates that are required for basic functionality.\n *\n * @returns Array of core page templates\n */\nexport function getCorePageTemplates(): PageTemplate[] {\n return PageTemplateRegistry.listCore();\n}\n\n/**\n * Get optional page templates that can be added to navigation.\n *\n * @returns Array of optional (non-core) page templates\n */\nexport function getOptionalPageTemplates(): PageTemplate[] {\n return PageTemplateRegistry.listOptional();\n}\n\n/**\n * Check if a navigation has all required core pages.\n *\n * @param navigation - The navigation to check\n * @returns Object with validation result and missing page IDs\n */\nexport function validateNavigationPages(navigation: Readonly<Navigation>): {\n readonly valid: boolean;\n readonly missingCorePages: readonly string[];\n} {\n const corePages = PageTemplateRegistry.listCore();\n const referencedTemplateIds = new Set(\n navigation.page_refs?.map((ref) => ref.page_template_id) ?? [],\n );\n\n // Check which core pages are referenced\n const missingCorePages = corePages\n .filter((page) => !referencedTemplateIds.has(page.id))\n .map((page) => page.id);\n\n return {\n valid: missingCorePages.length === 0,\n missingCorePages,\n };\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport type { PageTemplate } from \"../types/page-template\";\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\nimport { resolveNavigationPages } from \"../core/resolve-pages\";\nimport type { Navigation, ScreenDefinition } from \"../types\";\n\n/** Stable empty array for the default `templates` prop (avoids new reference each render) */\nconst EMPTY_TEMPLATES: readonly PageTemplate[] = [];\n\n/**\n * Context value for page template resolution.\n * All properties are readonly since context values should not be mutated by consumers.\n */\ninterface PageTemplateContextValue {\n /**\n * Resolve a navigation's page_refs and screens into a unified screen list\n */\n readonly resolvePages: (navigation: Navigation) => ScreenDefinition[];\n /**\n * Get all available page templates\n */\n readonly listTemplates: () => PageTemplate[];\n /**\n * Get a specific template by ID\n */\n readonly getTemplate: (id: string) => PageTemplate | undefined;\n /**\n * Check if a template exists\n */\n readonly hasTemplate: (id: string) => boolean;\n}\n\nconst PageTemplateContext = createContext<PageTemplateContextValue | null>(\n null,\n);\n\n/**\n * Props for PageTemplateProvider\n */\ninterface PageTemplateProviderProps {\n children: React.ReactNode;\n /**\n * Additional custom page templates to register.\n * These are registered when the provider mounts and unregistered when it unmounts.\n */\n templates?: readonly PageTemplate[];\n}\n\n/**\n * Provider for page template resolution.\n *\n * This provider:\n * 1. Registers any custom templates passed via props\n * 2. Provides methods for resolving navigation pages\n * 3. Cleans up custom templates on unmount\n *\n * @example\n * ```tsx\n * // With custom templates\n * const customTemplates: PageTemplate[] = [\n * {\n * id: 'custom-dashboard',\n * slug: 'dashboard',\n * name: 'Dashboard',\n * category: 'custom',\n * version: '1.0.0',\n * component_tree: [{ type: 'TextWidget', props: { text: 'Custom Dashboard' } }],\n * },\n * ];\n *\n * <PageTemplateProvider templates={customTemplates}>\n * <App />\n * </PageTemplateProvider>\n *\n * // Without custom templates (uses only core templates)\n * <PageTemplateProvider>\n * <App />\n * </PageTemplateProvider>\n * ```\n */\nexport function PageTemplateProvider({\n children,\n templates = EMPTY_TEMPLATES,\n}: PageTemplateProviderProps): React.JSX.Element {\n // Track which templates we registered so we can clean them up\n const registeredIds = useRef<string[]>([]);\n\n // Derive a stable primitive key from template IDs\n // (rerender-dependencies rule: use primitive dependencies in effects)\n const templateKey = templates.map((t) => t.id).join(\",\");\n\n // Register custom templates when template IDs change\n useEffect(() => {\n const registered: string[] = [];\n\n for (const template of templates) {\n if (!PageTemplateRegistry.has(template.id)) {\n try {\n PageTemplateRegistry.register(template);\n registered.push(template.id);\n } catch (error) {\n console.warn(\n `Failed to register page template \"${template.id}\":`,\n error,\n );\n }\n }\n }\n\n registeredIds.current = registered;\n\n // Cleanup when template IDs change or on unmount\n return () => {\n for (const id of registeredIds.current) {\n PageTemplateRegistry.unregister(id);\n }\n registeredIds.current = [];\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [templateKey]);\n\n // Memoize context value to prevent unnecessary re-renders\n // Use `satisfies` to validate shape at compile time while preserving inference\n const contextValue = useMemo(\n () =>\n ({\n resolvePages: resolveNavigationPages,\n listTemplates: () => PageTemplateRegistry.listAll(),\n getTemplate: (id: string) => PageTemplateRegistry.get(id),\n hasTemplate: (id: string) => PageTemplateRegistry.has(id),\n }) satisfies PageTemplateContextValue,\n [],\n );\n\n return (\n <PageTemplateContext.Provider value={contextValue}>\n {children}\n </PageTemplateContext.Provider>\n );\n}\n\n/**\n * Hook to access page template functionality.\n *\n * @throws Error if used outside of PageTemplateProvider\n *\n * @example\n * ```tsx\n * function NavigationRenderer({ navigation }: { navigation: Navigation }) {\n * const { resolvePages } = usePageTemplates();\n * const screens = resolvePages(navigation);\n *\n * return (\n * <div>\n * {screens.map((screen) => (\n * <Screen key={screen.id} definition={screen} />\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function usePageTemplates(): PageTemplateContextValue {\n const context = useContext(PageTemplateContext);\n if (!context) {\n throw new Error(\n \"usePageTemplates must be used within a PageTemplateProvider\",\n );\n }\n return context;\n}\n\n/**\n * Hook to resolve navigation pages directly.\n * Convenience wrapper around usePageTemplates().resolvePages.\n *\n * @param navigation - The navigation to resolve\n * @returns Array of resolved screen definitions\n */\nexport function useResolvedPages(navigation: Navigation): ScreenDefinition[] {\n const { resolvePages } = usePageTemplates();\n return useMemo(() => resolvePages(navigation), [resolvePages, navigation]);\n}\n","import { useState, useEffect } from \"react\";\n\nconst MOBILE_BREAKPOINT = 768;\nconst TABLET_BREAKPOINT = 1024;\n\nexport function useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState<boolean>(false);\n\n useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return isMobile;\n}\n\nexport function useIsTablet(): boolean {\n const [isTablet, setIsTablet] = useState<boolean>(false);\n\n useEffect(() => {\n const mql = window.matchMedia(\n `(min-width: ${MOBILE_BREAKPOINT}px) and (max-width: ${TABLET_BREAKPOINT - 1}px)`,\n );\n const onChange = () => {\n setIsTablet(\n window.innerWidth >= MOBILE_BREAKPOINT &&\n window.innerWidth < TABLET_BREAKPOINT,\n );\n };\n mql.addEventListener(\"change\", onChange);\n setIsTablet(\n window.innerWidth >= MOBILE_BREAKPOINT &&\n window.innerWidth < TABLET_BREAKPOINT,\n );\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return isTablet;\n}\n\nexport function useIsMobileOrTablet(): boolean {\n const [isMobileOrTablet, setIsMobileOrTablet] = useState<boolean>(false);\n\n useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${TABLET_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobileOrTablet(window.innerWidth < TABLET_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobileOrTablet(window.innerWidth < TABLET_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return isMobileOrTablet;\n}\n","\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport * as React from \"react\";\n\nimport { useIsMobile } from \"./use-mobile\";\n\n// ---------------------------------------------------------------------------\n// Inlined utilities (avoid importing from builder's UI kit)\n// ---------------------------------------------------------------------------\n\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nfunction Separator({\n className,\n orientation = \"horizontal\",\n ...props\n}: React.ComponentPropsWithRef<\"div\"> & {\n orientation?: \"horizontal\" | \"vertical\";\n decorative?: boolean;\n}) {\n return (\n <div\n role=\"separator\"\n aria-orientation={orientation}\n className={cn(\n \"bg-border shrink-0\",\n orientation === \"horizontal\" ? \"h-px w-full\" : \"h-full w-px\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Skeleton({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn(\"bg-muted animate-pulse rounded-md\", className)}\n {...props}\n />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst SIDEBAR_WIDTH = \"13rem\";\nconst SIDEBAR_WIDTH_MOBILE = \"18rem\";\nconst SIDEBAR_WIDTH_ICON = \"3rem\";\nconst SIDEBAR_KEYBOARD_SHORTCUT = \"b\";\n\n// ---------------------------------------------------------------------------\n// Sidebar Context\n// ---------------------------------------------------------------------------\n\ntype SidebarContextValue = {\n state: \"expanded\" | \"collapsed\";\n open: boolean;\n setOpen: (open: boolean) => void;\n openMobile: boolean;\n setOpenMobile: (open: boolean) => void;\n isMobile: boolean;\n toggleSidebar: () => void;\n isPreviewMode: boolean;\n useBottomNav: boolean;\n};\n\nexport const SidebarContext: React.Context<SidebarContextValue | null> =\n React.createContext<SidebarContextValue | null>(null);\n\nfunction useSidebar(): SidebarContextValue {\n const context = React.useContext(SidebarContext);\n if (!context) {\n throw new Error(\"useSidebar must be used within a SidebarProvider.\");\n }\n\n return context;\n}\n\n// ---------------------------------------------------------------------------\n// SidebarProvider\n// ---------------------------------------------------------------------------\n\nconst SidebarProvider: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n viewportWidth?: number;\n previewMode?: boolean;\n useBottomNav?: boolean;\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n viewportWidth?: number;\n previewMode?: boolean;\n useBottomNav?: boolean;\n }\n>(\n (\n {\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n viewportWidth,\n previewMode,\n useBottomNav: useBottomNavProp = false,\n className,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const windowIsMobile = useIsMobile();\n // Use viewportWidth if provided, otherwise use actual window detection\n const isMobile =\n viewportWidth !== undefined ? viewportWidth < 768 : windowIsMobile;\n // Preview mode is active when viewportWidth is provided\n const isPreviewMode = viewportWidth !== undefined || !!previewMode;\n const [openMobile, setOpenMobile] = React.useState(false);\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen);\n const open = openProp ?? _open;\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === \"function\" ? value(open) : value;\n if (setOpenProp) {\n setOpenProp(openState);\n } else {\n _setOpen(openState);\n }\n },\n [setOpenProp, open],\n );\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile\n ? setOpenMobile((open) => !open)\n : setOpen((open) => !open);\n }, [isMobile, setOpen, setOpenMobile]);\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === SIDEBAR_KEYBOARD_SHORTCUT &&\n (event.metaKey || event.ctrlKey)\n ) {\n // check if composer is focused - if so, let the composer handle the shortcut\n const activeElement = document.activeElement;\n const isComposerFocused =\n activeElement?.closest(\".group\\\\/composer\") ||\n activeElement?.closest(\"[data-toolbar]\") ||\n activeElement?.classList.contains(\"ProseMirror\");\n\n if (isComposerFocused) {\n return; // let the composer handle the shortcut\n }\n\n event.preventDefault();\n toggleSidebar();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [toggleSidebar]);\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? \"expanded\" : \"collapsed\";\n\n const contextValue = React.useMemo<SidebarContextValue>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n isPreviewMode,\n useBottomNav: useBottomNavProp,\n }),\n [\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n isPreviewMode,\n useBottomNavProp,\n ],\n );\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <div\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH,\n \"--sidebar-width-icon\": SIDEBAR_WIDTH_ICON,\n ...style,\n } as React.CSSProperties\n }\n className={cn(\n \"group/sidebar-wrapper flex min-h-0 w-full flex-1\",\n className,\n )}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n </SidebarContext.Provider>\n );\n },\n);\nSidebarProvider.displayName = \"SidebarProvider\";\n\n// ---------------------------------------------------------------------------\n// Sidebar\n// ---------------------------------------------------------------------------\n\nconst Sidebar: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n side?: \"left\" | \"right\";\n variant?: \"sidebar\" | \"floating\" | \"inset\";\n collapsible?: \"offcanvas\" | \"icon\" | \"none\";\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n side?: \"left\" | \"right\";\n variant?: \"sidebar\" | \"floating\" | \"inset\";\n collapsible?: \"offcanvas\" | \"icon\" | \"none\";\n }\n>(\n (\n {\n side = \"left\",\n variant = \"sidebar\",\n collapsible = \"offcanvas\",\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const {\n isMobile,\n state,\n openMobile,\n setOpenMobile,\n isPreviewMode,\n useBottomNav,\n } = useSidebar();\n\n // Define CSS variables for expanded and collapsed sidebar widths\n const sidebarWidth =\n state === \"expanded\" ? SIDEBAR_WIDTH : SIDEBAR_WIDTH_ICON;\n\n // When bottom nav is active on mobile, hide the sidebar entirely\n if (useBottomNav && isMobile) {\n return null;\n }\n\n if (collapsible === \"none\") {\n return (\n <div\n className={cn(\n \"bg-sidebar text-sidebar-foreground flex w-(--sidebar-width) flex-col rounded-tl-lg\",\n isPreviewMode ? \"h-full\" : \"h-[97vh]\",\n className,\n )}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n );\n }\n\n if (isMobile) {\n // For mobile, render a slide-out sidebar with overlay\n // Use absolute positioning in preview mode so it stays within the preview container\n const positionClass = isPreviewMode ? \"absolute\" : \"fixed\";\n return (\n <>\n {/* Overlay - only visible when sidebar is open */}\n {openMobile && (\n <div\n className={cn(positionClass, \"inset-0 z-40 bg-black/50\")}\n onClick={() => setOpenMobile(false)}\n aria-hidden=\"true\"\n />\n )}\n\n {/* Sidebar - slides in from left */}\n <div\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n className={cn(\n positionClass,\n \"bg-sidebar text-sidebar-foreground top-0 left-0 z-50 h-full w-[--sidebar-width] p-0 transition-transform duration-300 ease-in-out\",\n openMobile ? \"translate-x-0\" : \"-translate-x-full\",\n className,\n )}\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n ref={ref}\n {...props}\n >\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </div>\n </>\n );\n }\n\n return (\n <div\n ref={ref}\n className=\"group peer bg-sidebar text-sidebar-foreground hidden md:block\"\n data-state={state}\n data-collapsible={state === \"collapsed\" ? collapsible : \"\"}\n data-variant={variant}\n data-side={side}\n style={\n {\n \"--sidebar-width\": sidebarWidth,\n } as React.CSSProperties\n }\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n className={cn(\n \"relative bg-transparent transition-[width] duration-200 ease-linear\",\n \"group-data-[collapsible=offcanvas]:w-0\",\n \"group-data-[side=right]:rotate-180\",\n variant === \"floating\" || variant === \"inset\"\n ? \"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]\"\n : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon)\",\n )}\n />\n <div\n className={cn(\n \"relative inset-y-0 z-[20] hidden w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex\",\n isPreviewMode ? \"h-full\" : \"h-svh\",\n side === \"left\"\n ? \"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]\"\n : \"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]\",\n // Adjust the padding for floating and inset variants.\n variant === \"floating\" || variant === \"inset\"\n ? \"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]\"\n : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=right]:border-l\",\n className,\n )}\n {...props}\n >\n <div\n data-sidebar=\"sidebar\"\n className=\"group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm\"\n >\n {children}\n </div>\n </div>\n </div>\n );\n },\n);\nSidebar.displayName = \"Sidebar\";\n\n// ---------------------------------------------------------------------------\n// SidebarRail\n// ---------------------------------------------------------------------------\n\nconst SidebarRail: React.ForwardRefExoticComponent<\n React.ComponentProps<\"button\"> & React.RefAttributes<HTMLButtonElement>\n> = React.forwardRef<HTMLButtonElement, React.ComponentProps<\"button\">>(\n ({ className, ...props }, ref) => {\n const { toggleSidebar } = useSidebar();\n\n return (\n <button\n ref={ref}\n data-sidebar=\"rail\"\n aria-label=\"Toggle Sidebar\"\n tabIndex={-1}\n onClick={toggleSidebar}\n title=\"Toggle Sidebar\"\n className={cn(\n \"hover:after:bg-sidebar-border absolute inset-y-0 z-[10] hidden w-4 -translate-x-full transition-all ease-linear group-data-[side=left]:-right-[1.375rem] group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex\",\n \"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize\",\n \"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize\",\n \"hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full\",\n \"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2\",\n \"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarRail.displayName = \"SidebarRail\";\n\n// ---------------------------------------------------------------------------\n// SidebarInset\n// ---------------------------------------------------------------------------\n\nconst SidebarInset: React.ForwardRefExoticComponent<\n React.ComponentProps<\"main\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"main\">>(\n ({ className, ...props }, ref) => {\n const { isPreviewMode } = useSidebar();\n return (\n <main\n ref={ref}\n className={cn(\n \"relative flex flex-1 flex-col\",\n isPreviewMode\n ? \"max-h-[calc(100svh-(--spacing(4)))]\"\n : \"min-h-svh peer-data-[variant=inset]:min-h-[calc(100svh-(--spacing(4)))]\",\n \"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarInset.displayName = \"SidebarInset\";\n\n// ---------------------------------------------------------------------------\n// SidebarInput\n// ---------------------------------------------------------------------------\n\nconst SidebarInput: React.ForwardRefExoticComponent<\n React.ComponentProps<\"input\"> & React.RefAttributes<HTMLInputElement>\n> = React.forwardRef<HTMLInputElement, React.ComponentProps<\"input\">>(\n ({ className, ...props }, ref) => {\n return (\n <input\n ref={ref}\n data-sidebar=\"input\"\n className={cn(\n \"bg-background focus-visible:ring-sidebar-ring h-8 w-full rounded-md border px-3 text-sm shadow-none focus-visible:ring-2 focus-visible:outline-none\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarInput.displayName = \"SidebarInput\";\n\n// ---------------------------------------------------------------------------\n// SidebarHeader / Footer\n// ---------------------------------------------------------------------------\n\nconst SidebarHeader: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"header\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n );\n },\n);\nSidebarHeader.displayName = \"SidebarHeader\";\n\nconst SidebarFooter: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"footer\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n );\n },\n);\nSidebarFooter.displayName = \"SidebarFooter\";\n\n// ---------------------------------------------------------------------------\n// SidebarSeparator\n// ---------------------------------------------------------------------------\n\nconst SidebarSeparator: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n orientation?: \"horizontal\" | \"vertical\";\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n orientation?: \"horizontal\" | \"vertical\";\n }\n>(({ className, ...props }, ref) => {\n return (\n <Separator\n ref={ref}\n data-sidebar=\"separator\"\n className={cn(\"bg-sidebar-border mx-2 w-auto\", className)}\n {...props}\n />\n );\n});\nSidebarSeparator.displayName = \"SidebarSeparator\";\n\n// ---------------------------------------------------------------------------\n// SidebarContent\n// ---------------------------------------------------------------------------\n\nconst SidebarContent: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"content\"\n className={cn(\n \"scrollbar-none flex min-h-0 flex-1 flex-col gap-2 overflow-auto rounded group-data-[collapsible=icon]:gap-0 group-data-[collapsible=icon]:overflow-hidden group-data-[collapsible=icon]:pt-3\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarContent.displayName = \"SidebarContent\";\n\n// ---------------------------------------------------------------------------\n// SidebarGroup\n// ---------------------------------------------------------------------------\n\nconst SidebarGroup: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"group\"\n className={cn(\n \"relative flex w-full min-w-0 flex-col p-2 group-data-[collapsible=icon]:py-0 group-data-[collapsible=icon]:pt-4\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarGroup.displayName = \"SidebarGroup\";\n\nconst SidebarGroupLabel: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n asChild?: boolean;\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & { asChild?: boolean }\n>(({ className, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"div\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-label\"\n className={cn(\n \"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n \"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n );\n});\nSidebarGroupLabel.displayName = \"SidebarGroupLabel\";\n\nconst SidebarGroupAction: React.ForwardRefExoticComponent<\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n } & React.RefAttributes<HTMLButtonElement>\n> = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & { asChild?: boolean }\n>(({ className, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-action\"\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n // Increases the hit area of the button on mobile.\n \"after:absolute after:-inset-2 md:after:hidden\",\n \"group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n );\n});\nSidebarGroupAction.displayName = \"SidebarGroupAction\";\n\nconst SidebarGroupContent: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n data-sidebar=\"group-content\"\n className={cn(\"w-full text-sm\", className)}\n {...props}\n />\n ),\n);\nSidebarGroupContent.displayName = \"SidebarGroupContent\";\n\n// ---------------------------------------------------------------------------\n// SidebarMenu\n// ---------------------------------------------------------------------------\n\nconst SidebarMenu: React.ForwardRefExoticComponent<\n React.ComponentProps<\"ul\"> & React.RefAttributes<HTMLUListElement>\n> = React.forwardRef<HTMLUListElement, React.ComponentProps<\"ul\">>(\n ({ className, ...props }, ref) => (\n <ul\n ref={ref}\n data-sidebar=\"menu\"\n className={cn(\"flex w-full min-w-0 flex-col gap-1\", className)}\n {...props}\n />\n ),\n);\nSidebarMenu.displayName = \"SidebarMenu\";\n\nconst SidebarMenuItem: React.ForwardRefExoticComponent<\n React.ComponentProps<\"li\"> & React.RefAttributes<HTMLLIElement>\n> = React.forwardRef<HTMLLIElement, React.ComponentProps<\"li\">>(\n ({ className, ...props }, ref) => (\n <li\n ref={ref}\n data-sidebar=\"menu-item\"\n className={cn(\"group/menu-item relative\", className)}\n {...props}\n />\n ),\n);\nSidebarMenuItem.displayName = \"SidebarMenuItem\";\n\n// ---------------------------------------------------------------------------\n// SidebarMenuButton\n// ---------------------------------------------------------------------------\n\nconst sidebarMenuButtonVariants: (\n props?:\n | ({\n variant?: \"default\" | \"outline\" | null | undefined;\n size?: \"default\" | \"sm\" | \"lg\" | null | undefined;\n } & (\n | {\n class: ClassValue;\n className?: never;\n }\n | {\n class?: never;\n className: ClassValue;\n }\n | {\n class?: never;\n className?: never;\n }\n ))\n | undefined,\n) => string = cva(\n \"peer/menu-button ring-sidebar-ring hover:bg-sidebar-primary hover:text-sidebar-primary-foreground active:bg-sidebar-primary active:text-sidebar-primary-foreground data-[active=true]:bg-sidebar-primary data-[active=true]:text-sidebar-primary-foreground data-[state=open]:hover:bg-sidebar-primary data-[state=open]:hover:text-sidebar-primary-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden transition-[width,height,padding,background-color,color] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n {\n variants: {\n variant: {\n default:\n \"hover:bg-sidebar-primary hover:text-sidebar-primary-foreground\",\n outline:\n \"hover:bg-sidebar-primary hover:text-sidebar-primary-foreground shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:shadow-[0_0_0_1px_hsl(var(--sidebar-primary))]\",\n },\n size: {\n default: \"h-8 text-sm\",\n sm: \"h-7 text-xs\",\n lg: \"h-12 text-sm group-data-[collapsible=icon]:p-0!\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nconst SidebarMenuButton: React.ForwardRefExoticComponent<\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n isActive?: boolean;\n } & VariantProps<typeof sidebarMenuButtonVariants> &\n React.RefAttributes<HTMLButtonElement>\n> = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n isActive?: boolean;\n } & VariantProps<typeof sidebarMenuButtonVariants>\n>(\n (\n {\n asChild = false,\n isActive = false,\n variant = \"default\",\n size = \"default\",\n className,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"button\";\n\n const button = (\n <Comp\n ref={ref}\n data-sidebar=\"menu-button\"\n data-size={size}\n data-active={isActive}\n className={cn(sidebarMenuButtonVariants({ variant, size }), className)}\n {...props}\n />\n );\n\n return button;\n },\n);\nSidebarMenuButton.displayName = \"SidebarMenuButton\";\n\n// ---------------------------------------------------------------------------\n// SidebarMenuAction / Badge / Skeleton\n// ---------------------------------------------------------------------------\n\nconst SidebarMenuAction: React.ForwardRefExoticComponent<\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n showOnHover?: boolean;\n } & React.RefAttributes<HTMLButtonElement>\n> = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n showOnHover?: boolean;\n }\n>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-action\"\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n // Increases the hit area of the button on mobile.\n \"after:absolute after:-inset-2 md:after:hidden\",\n \"peer-data-[size=sm]/menu-button:top-1\",\n \"peer-data-[size=default]/menu-button:top-1.5\",\n \"peer-data-[size=lg]/menu-button:top-2.5\",\n \"group-data-[collapsible=icon]:hidden\",\n showOnHover &&\n \"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n});\nSidebarMenuAction.displayName = \"SidebarMenuAction\";\n\nconst SidebarMenuBadge: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n data-sidebar=\"menu-badge\"\n className={cn(\n \"text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none\",\n \"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground\",\n \"peer-data-[size=sm]/menu-button:top-1\",\n \"peer-data-[size=default]/menu-button:top-1.5\",\n \"peer-data-[size=lg]/menu-button:top-2.5\",\n \"group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n ),\n);\nSidebarMenuBadge.displayName = \"SidebarMenuBadge\";\n\nconst SidebarMenuSkeleton: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n showIcon?: boolean;\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n showIcon?: boolean;\n }\n>(({ className, showIcon = false, ...props }, ref) => {\n // Random width between 50 to 90%.\n const width = React.useMemo(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`;\n }, []);\n\n return (\n <div\n ref={ref}\n data-sidebar=\"menu-skeleton\"\n className={cn(\"flex h-8 items-center gap-2 rounded-md px-2\", className)}\n {...props}\n >\n {showIcon && (\n <Skeleton\n className=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n )}\n <Skeleton\n className=\"h-4 max-w-(--skeleton-width) flex-1\"\n data-sidebar=\"menu-skeleton-text\"\n style={\n {\n \"--skeleton-width\": width,\n } as React.CSSProperties\n }\n />\n </div>\n );\n});\nSidebarMenuSkeleton.displayName = \"SidebarMenuSkeleton\";\n\n// ---------------------------------------------------------------------------\n// SidebarMenuSub\n// ---------------------------------------------------------------------------\n\nconst SidebarMenuSub: React.ForwardRefExoticComponent<\n React.ComponentProps<\"ul\"> & React.RefAttributes<HTMLUListElement>\n> = React.forwardRef<HTMLUListElement, React.ComponentProps<\"ul\">>(\n ({ className, ...props }, ref) => (\n <ul\n ref={ref}\n data-sidebar=\"menu-sub\"\n className={cn(\n \"border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5\",\n \"group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n ),\n);\nSidebarMenuSub.displayName = \"SidebarMenuSub\";\n\nconst SidebarMenuSubItem: React.ForwardRefExoticComponent<\n React.ComponentProps<\"li\"> & React.RefAttributes<HTMLLIElement>\n> = React.forwardRef<HTMLLIElement, React.ComponentProps<\"li\">>(\n ({ ...props }, ref) => <li ref={ref} {...props} />,\n);\nSidebarMenuSubItem.displayName = \"SidebarMenuSubItem\";\n\nconst SidebarMenuSubButton: React.ForwardRefExoticComponent<\n React.ComponentProps<\"a\"> & {\n asChild?: boolean;\n size?: \"sm\" | \"md\";\n isActive?: boolean;\n } & React.RefAttributes<HTMLAnchorElement>\n> = React.forwardRef<\n HTMLAnchorElement,\n React.ComponentProps<\"a\"> & {\n asChild?: boolean;\n size?: \"sm\" | \"md\";\n isActive?: boolean;\n }\n>(({ asChild = false, size = \"md\", isActive, className, ...props }, ref) => {\n const Comp = asChild ? Slot : \"a\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-sub-button\"\n data-size={size}\n data-active={isActive}\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n \"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground\",\n size === \"sm\" && \"text-xs\",\n size === \"md\" && \"text-sm\",\n \"group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n );\n});\nSidebarMenuSubButton.displayName = \"SidebarMenuSubButton\";\n\n// ---------------------------------------------------------------------------\n// Exports\n// ---------------------------------------------------------------------------\n\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n useSidebar,\n};\n","\"use client\";\n\nimport * as React from \"react\";\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarHeader,\n SidebarInset,\n SidebarProvider,\n} from \"./sidebar\";\n\nexport interface AppShellLayoutProps {\n /** Navigation content rendered inside the sidebar's scrollable area */\n sidebarContent: React.ReactNode;\n /** Header content rendered above the main content area */\n headerContent: React.ReactNode;\n /** Main page content */\n children: React.ReactNode;\n /** Optional slot at the top of the sidebar (e.g. logo, search) */\n sidebarHeader?: React.ReactNode;\n /** Optional slot at the bottom of the sidebar (e.g. user info) */\n sidebarFooter?: React.ReactNode;\n /** Content rendered after SidebarInset (e.g. MobileBottomNav) */\n afterContent?: React.ReactNode;\n /** Enable bottom nav mode (hides sidebar on mobile, adds bottom padding) */\n useBottomNav?: boolean;\n}\n\n/**\n * Pure visual frame that replicates the RepApp layout:\n * - 13rem collapsible sidebar\n * - 52px header area\n * - rounded-xl bg-background shadow-lg content area with bg-muted gutters\n *\n * This component handles zero business logic — it simply provides the visual shell.\n */\nexport function AppShellLayout({\n sidebarContent,\n headerContent,\n children,\n sidebarHeader,\n sidebarFooter,\n afterContent,\n useBottomNav = false,\n}: AppShellLayoutProps): React.JSX.Element {\n return (\n <SidebarProvider useBottomNav={useBottomNav}>\n <div className=\"bg-muted relative flex max-h-dvh w-full overflow-hidden\">\n {/* Navigation Sidebar */}\n <Sidebar>\n {sidebarHeader && <SidebarHeader>{sidebarHeader}</SidebarHeader>}\n <SidebarContent className=\"p-4\">{sidebarContent}</SidebarContent>\n {sidebarFooter && <SidebarFooter>{sidebarFooter}</SidebarFooter>}\n </Sidebar>\n\n {/* Main Content Area */}\n <SidebarInset className=\"flex flex-1 flex-col overflow-hidden\">\n {/* Header */}\n {headerContent}\n\n {/* Screen Content */}\n <div\n className={`bg-muted flex-1 overflow-hidden md:pr-4 md:pb-4 ${useBottomNav ? \"max-md:pb-[calc(4rem+env(safe-area-inset-bottom))]\" : \"\"}`}\n >\n <div className=\"scrollbar-none bg-background text-foreground h-full overflow-auto rounded-xl shadow-lg\">\n {children}\n </div>\n </div>\n </SidebarInset>\n\n {/* After content (e.g. MobileBottomNav) */}\n {afterContent}\n </div>\n </SidebarProvider>\n );\n}\n","\"use client\";\n\nimport type React from \"react\";\nimport {\n createContext,\n useContext,\n useCallback,\n useMemo,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\n\nexport type ThemeMode = \"auto\" | \"light\" | \"dark\";\n\nexport type DisplayMode = \"light\" | \"dark\";\n\nexport interface ThemeModeContextValue {\n mode: ThemeMode;\n displayMode: DisplayMode;\n setMode: (mode: ThemeMode) => void;\n autoModeEnabled: boolean;\n cycleMode: () => void;\n dataAttribute: string | undefined;\n}\n\nconst ThemeModeContext = createContext<ThemeModeContextValue | null>(null);\n\nconst darkMediaQuery =\n typeof window !== \"undefined\"\n ? window.matchMedia(\"(prefers-color-scheme: dark)\")\n : null;\n\nfunction subscribeToPrefersColorScheme(callback: () => void) {\n darkMediaQuery?.addEventListener(\"change\", callback);\n return () => darkMediaQuery?.removeEventListener(\"change\", callback);\n}\n\nfunction getSystemPrefersDark(): boolean {\n return darkMediaQuery?.matches ?? false;\n}\n\nfunction getServerSnapshot(): boolean {\n return false;\n}\n\ninterface ThemeModeProviderProps {\n children: ReactNode;\n mode: ThemeMode;\n onModeChange: (mode: ThemeMode) => void;\n /** When false, auto mode is skipped in the cycle (light↔dark only). Default true. */\n autoModeEnabled?: boolean;\n}\n\nexport function ThemeModeProvider({\n children,\n mode,\n onModeChange,\n autoModeEnabled = true,\n}: ThemeModeProviderProps): React.JSX.Element {\n const systemPrefersDark = useSyncExternalStore(\n subscribeToPrefersColorScheme,\n getSystemPrefersDark,\n getServerSnapshot,\n );\n\n const systemMode: DisplayMode = systemPrefersDark ? \"dark\" : \"light\";\n\n const displayMode: DisplayMode = mode === \"auto\" ? systemMode : mode;\n\n const cycleMode = useCallback(() => {\n if (autoModeEnabled) {\n // Toggle displayed mode. If target matches system preference, use \"auto\".\n const target: DisplayMode = displayMode === \"light\" ? \"dark\" : \"light\";\n onModeChange(target === systemMode ? \"auto\" : target);\n } else {\n // light ↔ dark\n onModeChange(mode === \"light\" ? \"dark\" : \"light\");\n }\n }, [mode, displayMode, systemMode, onModeChange, autoModeEnabled]);\n\n const dataAttribute = getThemeModeAttribute(mode);\n\n const value = useMemo(\n () => ({\n mode,\n displayMode,\n setMode: onModeChange,\n autoModeEnabled,\n cycleMode,\n dataAttribute,\n }),\n [\n mode,\n displayMode,\n onModeChange,\n autoModeEnabled,\n cycleMode,\n dataAttribute,\n ],\n );\n\n return (\n <ThemeModeContext.Provider value={value}>\n {children}\n </ThemeModeContext.Provider>\n );\n}\n\n/** Access the current theme mode, setter, and cycle helper. Must be used within a `ThemeModeProvider`. */\nexport function useThemeMode(): ThemeModeContextValue {\n const ctx = useContext(ThemeModeContext);\n if (!ctx) {\n throw new Error(\"useThemeMode must be used within a ThemeModeProvider\");\n }\n return ctx;\n}\n\n/** Maps a ThemeMode to the value for `data-theme-mode`. Returns undefined for \"auto\". */\nexport function getThemeModeAttribute(mode: ThemeMode): string | undefined {\n return mode === \"auto\" ? undefined : mode;\n}\n","/**\n * System navigation items for portal apps\n * These are pre-built screens that cannot be edited or deleted in the builder.\n * They are handled by custom code (slugLibrary) rather than builder screens.\n */\n\nimport type { NavigationItem } from \"../types/navigation\";\n\nexport const SYSTEM_NAVIGATION_SLUGS = [\n \"app-download\",\n \"contacts\",\n \"account\",\n \"messages\",\n \"my-site\",\n \"orders\",\n \"profile\",\n \"subscriptions\",\n // \"share/enrollments\",\n \"share/media\",\n \"share/pages\",\n \"share/playlists\",\n \"share/products\",\n \"shop\",\n // \"upgrade\",\n] as const;\n\nexport type SystemNavigationSlug = (typeof SYSTEM_NAVIGATION_SLUGS)[number];\n\nexport type SystemNavigationItem = Omit<NavigationItem, \"children\">;\n\n/**\n * Slugs hidden from the quicklinks/shortcuts menu.\n * These screens still exist and are navigable, but don't appear in the grid.\n */\nexport const QUICKLINKS_HIDDEN_SLUGS: ReadonlySet<string> =\n new Set<SystemNavigationSlug>([\"app-download\"]);\n\n/**\n * Slugs restricted to rep (non-customer) users.\n * Customers will not see these in navigation and cannot access these routes.\n */\nexport const REP_ONLY_SLUGS: ReadonlySet<string> =\n new Set<SystemNavigationSlug>([\"messages\", \"my-site\"]);\n\n/**\n * Check if a slug is restricted to rep users only.\n * Handles both exact matches and prefix matches (e.g. \"contacts/123\").\n */\nexport function isRepOnlySlug(slug: string | undefined | null): boolean {\n if (!slug) return false;\n const normalized = slug.startsWith(\"/\") ? slug.slice(1) : slug;\n if (REP_ONLY_SLUGS.has(normalized)) return true;\n for (const repSlug of REP_ONLY_SLUGS) {\n if (normalized.startsWith(repSlug + \"/\")) return true;\n }\n return false;\n}\n\nexport const SYSTEM_NAVIGATION_ITEMS: Record<\n SystemNavigationSlug,\n SystemNavigationItem\n> = {\n \"app-download\": {\n slug: \"app-download\",\n label: \"App Download\",\n icon: \"mobile\",\n section: \"User\",\n },\n contacts: {\n slug: \"contacts\",\n label: \"Contacts\",\n icon: \"circle-user\",\n section: \"User\",\n },\n messages: {\n slug: \"messages\",\n label: \"Messaging\",\n icon: \"message\",\n section: \"User\",\n },\n \"my-site\": {\n slug: \"my-site\",\n label: \"My Site\",\n icon: \"globe\",\n section: \"Shareables\",\n },\n orders: {\n slug: \"orders\",\n label: \"Orders\",\n icon: \"package-open\",\n section: \"User\",\n },\n profile: {\n slug: \"profile\",\n label: \"Profile\",\n icon: \"user\",\n section: \"User\",\n },\n account: {\n slug: \"profile\",\n label: \"Account\",\n icon: \"user\",\n section: \"User\",\n },\n // \"share/enrollments\": {\n // slug: \"share/enrollments\",\n // label: \"Enrollments\",\n // icon: \"graduation-cap\",\n // section: \"Shareables\",\n // },\n \"share/media\": {\n slug: \"share/media\",\n label: \"Media\",\n icon: \"file-video\",\n section: \"Shareables\",\n },\n \"share/pages\": {\n slug: \"share/pages\",\n label: \"Pages\",\n icon: \"file-lines\",\n section: \"Shareables\",\n },\n \"share/playlists\": {\n slug: \"share/playlists\",\n label: \"Playlists\",\n icon: \"list-music\",\n section: \"Shareables\",\n },\n \"share/products\": {\n slug: \"share/products\",\n label: \"Products\",\n icon: \"box\",\n section: \"Shareables\",\n },\n shop: {\n slug: \"shop\",\n label: \"Shop\",\n icon: \"store\",\n section: \"User\",\n },\n subscriptions: {\n slug: \"subscriptions\",\n label: \"Subscriptions\",\n icon: \"arrows-repeat\",\n section: \"User\",\n },\n // upgrade: {\n // slug: \"upgrade\",\n // label: \"Upgrade\",\n // icon: \"arrow-up-from-bracket\",\n // section: \"User\",\n // },\n} as const;\n\n/**\n * Get the default system navigation items for a new portal app.\n * These items have no screen_id - they're handled by the slugLibrary.\n */\nexport function getDefaultSystemNavigationItems(): SystemNavigationItem[] {\n return Object.values(SYSTEM_NAVIGATION_ITEMS);\n}\n\n/**\n * Check if a navigation item is a system item that doesn't require a screen_id.\n * Used by RepApp to skip screen validation for these items.\n */\nexport function isSystemNavigationItem(\n slug?: string | null,\n): slug is SystemNavigationSlug {\n if (!slug) return false;\n return SYSTEM_NAVIGATION_SLUGS.includes(slug as SystemNavigationSlug);\n}\n\n/**\n * Get icon name for a navigation item by slug.\n */\nexport function getNavigationItemIcon(slug?: string): string | undefined {\n if (!slug) return undefined;\n const systemItem = SYSTEM_NAVIGATION_ITEMS[slug as SystemNavigationSlug];\n return systemItem?.icon;\n}\n\n/**\n * Get system navigation items grouped by section.\n */\nexport function getSystemNavigationBySection(): Record<\n string,\n SystemNavigationItem[]\n> {\n const sections: Record<string, SystemNavigationItem[]> = {};\n const seenSlugs = new Set<string>();\n for (const item of Object.values(SYSTEM_NAVIGATION_ITEMS)) {\n if (item.slug && seenSlugs.has(item.slug)) continue;\n if (item.slug) seenSlugs.add(item.slug);\n if (item.slug && QUICKLINKS_HIDDEN_SLUGS.has(item.slug)) continue;\n const section = item.section || \"Other\";\n if (!sections[section]) {\n sections[section] = [];\n }\n sections[section].push(item);\n }\n return sections;\n}\n\n/**\n * Normalize a navigation slug by stripping a leading slash.\n */\nexport function normalizeSlug(slug: string | undefined): string {\n if (!slug) return \"\";\n return slug.startsWith(\"/\") ? slug.slice(1) : slug;\n}\n","import {\n SYSTEM_NAVIGATION_ITEMS,\n type SystemNavigationSlug,\n} from \"./system-navigation-items\";\nimport type { NavigationItem } from \"../types/navigation\";\n\n/**\n * Build a NavigationItem from a system navigation slug.\n * Icons and labels come from SYSTEM_NAVIGATION_ITEMS (single source of truth).\n */\nfunction systemNavItem(slug: SystemNavigationSlug): NavigationItem {\n const item = SYSTEM_NAVIGATION_ITEMS[slug];\n return {\n slug: item.slug,\n label: item.label,\n icon: item.icon,\n children: [],\n };\n}\n\nfunction sectionHeader(label: string): NavigationItem {\n return { label, children: [] };\n}\n\n/**\n * Returns the default navigation items for a portal app when no\n * API data is available. All icons/labels derive from\n * SYSTEM_NAVIGATION_ITEMS so they can never drift.\n */\nexport function getDefaultNavigation(): NavigationItem[] {\n return [\n sectionHeader(\"We Commerce\"),\n systemNavItem(\"shop\"),\n systemNavItem(\"messages\"),\n systemNavItem(\"contacts\"),\n systemNavItem(\"account\"),\n sectionHeader(\"Marketing Assets\"),\n systemNavItem(\"share/products\"),\n ];\n}\n","\"use client\";\n\nimport type React from \"react\";\nimport { PanelLeft } from \"lucide-react\";\nimport { useSidebar } from \"./sidebar\";\nimport { useScreenHeaderContext } from \"./ScreenHeaderContext\";\n\nexport interface ScreenHeaderProps {\n title?: string;\n}\n\nexport function ScreenHeader({\n title,\n}: ScreenHeaderProps): React.JSX.Element | null {\n const { toggleSidebar, isMobile } = useSidebar();\n const { actions, breadcrumbs } = useScreenHeaderContext();\n\n if (!title && !breadcrumbs) return null;\n\n return (\n <div className=\"border-border bg-background sticky top-0 z-30 flex flex-row items-center border-b px-4 py-3 md:px-6\">\n {!isMobile && (\n <>\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"text-muted-foreground hover:text-foreground -ml-1 inline-flex items-center justify-center rounded-md p-1\"\n aria-label=\"Toggle Sidebar\"\n >\n <PanelLeft className=\"size-4\" />\n </button>\n <div className=\"bg-border mx-2 h-4 w-px\" />\n </>\n )}\n {breadcrumbs ? (\n <div className=\"min-w-0 flex-1\">{breadcrumbs}</div>\n ) : (\n <h1 className=\"text-foreground text-lg font-semibold\">{title}</h1>\n )}\n {actions && (\n <div className=\"ml-auto flex items-center gap-2\">{actions}</div>\n )}\n </div>\n );\n}\n","import type React from \"react\";\nimport type { LucideIcon } from \"lucide-react\";\nimport {\n Bell,\n Box,\n Boxes,\n Briefcase,\n Calendar,\n CircleUser,\n Compass,\n ContactRound,\n File,\n FileText,\n FileVideo,\n Folder,\n FolderOpen,\n Globe,\n GraduationCap,\n Heart,\n House,\n Image,\n LayoutGrid,\n ListMusic,\n Mail,\n MessageCircle,\n MessageSquare,\n PackageOpen,\n Repeat,\n Search,\n Settings,\n ShoppingCart,\n Star,\n Store,\n User,\n UserCog,\n Users,\n} from \"lucide-react\";\n\nconst ICON_MAP: Record<string, LucideIcon> = {\n \"address-card\": ContactRound,\n \"arrows-repeat\": Repeat,\n bell: Bell,\n box: Box,\n \"boxes-stacked\": Boxes,\n briefcase: Briefcase,\n calendar: Calendar,\n \"cart-shopping\": ShoppingCart,\n \"circle-user\": CircleUser,\n comment: MessageCircle,\n compass: Compass,\n envelope: Mail,\n file: File,\n \"file-lines\": FileText,\n \"file-video\": FileVideo,\n folder: Folder,\n \"folder-open\": FolderOpen,\n gear: Settings,\n globe: Globe,\n \"graduation-cap\": GraduationCap,\n heart: Heart,\n house: House,\n image: Image,\n \"list-music\": ListMusic,\n \"magnifying-glass\": Search,\n message: MessageSquare,\n \"package-open\": PackageOpen,\n star: Star,\n store: Store,\n \"table-cells-large\": LayoutGrid,\n user: User,\n \"user-gear\": UserCog,\n users: Users,\n};\n\ninterface RepIconProps {\n name: string;\n className?: string;\n}\n\nexport function RepIcon({ name, className }: RepIconProps): React.JSX.Element {\n const Icon = ICON_MAP[name] ?? File;\n return <Icon className={className} />;\n}\n","/**\n * Utility functions for managing navigation state in localStorage\n */\n\nconst STORAGE_PREFIX = \"portal-app-last-tab\";\n\n/**\n * Gets the localStorage key for a specific app and top-level section\n */\nfunction getStorageKey(appDefinitionId: number, topLevelSlug: string): string {\n return `${STORAGE_PREFIX}-${appDefinitionId}-${topLevelSlug}`;\n}\n\n/**\n * Retrieves the last visited tab slug for a given section\n */\nexport function getLastVisitedTab(\n appDefinitionId: number,\n topLevelSlug: string,\n): string | null {\n if (typeof window === \"undefined\") return null;\n\n try {\n const key = getStorageKey(appDefinitionId, topLevelSlug);\n return localStorage.getItem(key);\n } catch (error) {\n console.warn(\"Failed to read from localStorage:\", error);\n return null;\n }\n}\n\n/**\n * Stores the last visited tab slug for a given section\n */\nexport function setLastVisitedTab(\n appDefinitionId: number,\n topLevelSlug: string,\n tabSlug: string,\n): void {\n if (typeof window === \"undefined\") return;\n\n try {\n const key = getStorageKey(appDefinitionId, topLevelSlug);\n localStorage.setItem(key, tabSlug);\n } catch (error) {\n console.warn(\"Failed to write to localStorage:\", error);\n }\n}\n\n/**\n * Clears the last visited tab for a given section\n */\nexport function clearLastVisitedTab(\n appDefinitionId: number,\n topLevelSlug: string,\n): void {\n if (typeof window === \"undefined\") return;\n\n try {\n const key = getStorageKey(appDefinitionId, topLevelSlug);\n localStorage.removeItem(key);\n } catch (error) {\n console.warn(\"Failed to remove from localStorage:\", error);\n }\n}\n","import type { NavigationItem } from \"../types/navigation\";\nimport { normalizeSlug } from \"./system-navigation-items\";\nimport { getLastVisitedTab } from \"./navigation-storage\";\n\n/**\n * Helper function to determine if the current route is within a top-level section\n */\nexport function isInSection(\n topLevelItem: NavigationItem,\n currentRoute: string,\n): boolean {\n const normalizedCurrentRoute = normalizeSlug(currentRoute);\n\n if (\n (!topLevelItem.children || topLevelItem.children.length <= 0) &&\n topLevelItem.slug\n ) {\n const normalizedItemSlug = normalizeSlug(topLevelItem.slug);\n if (normalizedItemSlug === normalizedCurrentRoute) {\n return true;\n }\n } else {\n return topLevelItem.children.some((child: NavigationItem) => {\n const normalizedChildSlug = normalizeSlug(child.slug);\n return normalizedChildSlug === normalizedCurrentRoute;\n });\n }\n\n return false;\n}\n\n/**\n * Get the target slug when clicking a top-level navigation item\n */\nexport function getNavigationTarget(\n item: NavigationItem,\n appDefinitionId: number,\n): string | null {\n // If it has children, it's always a section parent — navigate to a child\n if (item.children && item.children.length > 0) {\n // Try to get the last visited tab from localStorage (only if parent has a slug for the key)\n if (item.slug) {\n const lastVisitedSlug = getLastVisitedTab(appDefinitionId, item.slug);\n\n // If we have a last visited tab and it exists in the children, use it\n if (lastVisitedSlug) {\n const normalizedLastVisited = normalizeSlug(lastVisitedSlug);\n const childExists = item.children.some((child: NavigationItem) => {\n const normalizedChildSlug = normalizeSlug(child.slug);\n return normalizedChildSlug === normalizedLastVisited;\n });\n if (childExists) {\n return normalizedLastVisited;\n }\n }\n }\n\n // Default to the first child's slug\n const firstChild = item.children[0];\n if (firstChild?.slug) {\n return normalizeSlug(firstChild.slug);\n }\n\n return null;\n }\n\n // If it's a leaf node with a screen, return its slug directly (normalized)\n if (item.screen_id && item.slug) {\n return normalizeSlug(item.slug);\n }\n\n // If it's a leaf node with just a slug (system nav items like account, messages, etc.)\n if (item.slug) {\n return normalizeSlug(item.slug);\n }\n\n return null;\n}\n","import * as React from \"react\";\nimport { Ellipsis, X } from \"lucide-react\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport {\n isInSection,\n getNavigationTarget,\n} from \"@fluid-app/portal-core/navigation/utils\";\nimport type { NavigationItem } from \"../types/navigation\";\n\ninterface SdkBottomNavProps {\n navItems: NavigationItem[];\n currentSlug: string;\n onNavigate: (slug: string) => void;\n appDefinitionId?: number;\n maxVisibleItems?: number;\n}\n\nexport function SdkBottomNav({\n navItems,\n currentSlug,\n onNavigate,\n appDefinitionId = 0,\n maxVisibleItems = 6,\n}: SdkBottomNavProps): React.JSX.Element | null {\n const { isMobile, useBottomNav } = useSidebar();\n const [moreOpen, setMoreOpen] = React.useState(false);\n\n if (!isMobile || !useBottomNav) return null;\n\n const navigableItems = navItems\n .filter((item) => !item.parent_id)\n .filter((item) => item.slug || (item.children && item.children.length > 0));\n\n const hasOverflow = navigableItems.length > maxVisibleItems;\n const visibleItems = hasOverflow\n ? navigableItems.slice(0, maxVisibleItems - 1)\n : navigableItems;\n const overflowItems = hasOverflow\n ? navigableItems.slice(maxVisibleItems - 1)\n : [];\n\n const handleItemClick = (item: NavigationItem) => {\n const target = getNavigationTarget(item, appDefinitionId);\n if (target) onNavigate(target);\n setMoreOpen(false);\n };\n\n return (\n <>\n <nav className=\"border-border bg-sidebar fixed right-0 bottom-0 left-0 z-40 flex h-16 items-end justify-around border-t pb-[env(safe-area-inset-bottom)]\">\n {visibleItems.map((item) => {\n const isActive = isInSection(item, currentSlug);\n return (\n <button\n key={item.id ?? item.slug ?? item.label}\n type=\"button\"\n onClick={() => handleItemClick(item)}\n className={`flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-[10px] font-medium transition-colors ${\n isActive ? \"text-primary\" : \"text-muted-foreground\"\n }`}\n >\n {item.icon ? (\n <RepIcon name={item.icon} className=\"size-5\" />\n ) : (\n <span className=\"size-5\" />\n )}\n <span className=\"max-w-[72px] truncate\">{item.label}</span>\n </button>\n );\n })}\n\n {hasOverflow && (\n <button\n type=\"button\"\n onClick={() => setMoreOpen(true)}\n className={`flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-[10px] font-medium transition-colors ${\n overflowItems.some((item) => isInSection(item, currentSlug))\n ? \"text-primary\"\n : \"text-muted-foreground\"\n }`}\n >\n <Ellipsis className=\"size-5\" />\n <span>More</span>\n </button>\n )}\n </nav>\n\n {moreOpen && (\n <div className=\"fixed inset-0 z-50 flex flex-col\">\n <div\n className=\"flex-1 bg-black/50\"\n onClick={() => setMoreOpen(false)}\n aria-hidden=\"true\"\n />\n <div className=\"bg-sidebar rounded-t-2xl pb-[env(safe-area-inset-bottom)]\">\n <div className=\"flex items-center justify-between px-4 pt-4 pb-2\">\n <span className=\"text-foreground text-sm font-semibold\">\n More\n </span>\n <button\n type=\"button\"\n onClick={() => setMoreOpen(false)}\n className=\"text-muted-foreground hover:bg-sidebar-accent flex items-center justify-center rounded-full p-1\"\n aria-label=\"Close\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n <div className=\"px-2 pb-4\">\n {overflowItems.map((item) => {\n const isActive = isInSection(item, currentSlug);\n return (\n <button\n key={item.id ?? item.slug ?? item.label}\n type=\"button\"\n onClick={() => handleItemClick(item)}\n className={`flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors ${\n isActive\n ? \"bg-sidebar-primary text-sidebar-primary-foreground\"\n : \"text-sidebar-foreground hover:bg-sidebar-accent\"\n }`}\n >\n {item.icon && (\n <RepIcon name={item.icon} className=\"size-5\" />\n )}\n <span>{item.label}</span>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n","/**\n * Company-scoped query key factory for TanStack Query.\n *\n * In portal-tenant, each tenant is a single company, so query keys are\n * returned unscoped. The `createCompanyQueryKey` utility is preserved for\n * potential future multi-company support.\n */\n\nimport { useCallback } from \"react\";\n\n/**\n * Create a company-scoped query key by prepending [\"company\", companyId].\n *\n * @param companyId - The company ID\n * @param baseKey - The base query key segments (e.g. [\"fluid\", \"profile\"])\n * @returns A tuple like [\"company\", 42, \"fluid\", \"profile\"]\n */\nexport function createCompanyQueryKey(\n companyId: number,\n ...baseKey: readonly string[]\n): readonly [\"company\", number, ...string[]] {\n return [\"company\", companyId, ...baseKey] as const;\n}\n\n/**\n * Hook that returns a `scopeKey` function.\n *\n * In portal-tenant, each tenant is a single company, so keys are\n * returned unscoped (no company prefix).\n */\nexport function useCompanyScopedQueryKey(): {\n readonly companyId: number | undefined;\n readonly scopeKey: <T extends readonly string[]>(\n baseKey: T,\n ) => readonly (string | number)[];\n} {\n const scopeKey = useCallback(\n <T extends readonly string[]>(baseKey: T): readonly (string | number)[] => {\n return baseKey;\n },\n [],\n );\n\n return { companyId: undefined, scopeKey } as const;\n}\n","/**\n * Screen Transforms\n * Convert FluidOS API screen objects to ScreenDefinition format.\n *\n * Extracted from:\n * - apps/fluid-admin/networking/app-builder/app-screens/types.ts\n * - apps/fluid-admin/networking/reps/screens.api.ts\n */\n\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type { ScreenDefinition } from \"@fluid-app/portal-core/types\";\n\n/** Raw screen from the FluidOS API */\nexport interface RawApiScreen {\n id: number | string;\n definition_id?: number | string;\n name?: string | null;\n slug?: string | null;\n component_tree?: unknown;\n}\n\n/**\n * Normalize component_tree to always be an array.\n * The API stores component_tree as a hash (object), but the frontend expects an array.\n */\nexport function normalizeComponentTree(componentTree: unknown): WidgetSchema[] {\n if (!componentTree) return [];\n if (Array.isArray(componentTree)) return componentTree as WidgetSchema[];\n if (typeof componentTree === \"object\") {\n return [componentTree as WidgetSchema];\n }\n return [];\n}\n\n/**\n * Convert a raw FluidOS screen to ScreenDefinition.\n * Normalizes component_tree and converts string IDs to numbers.\n */\nexport function toScreenDefinition(screen: RawApiScreen): ScreenDefinition {\n return {\n id: Number(screen.id),\n slug: screen.slug ?? \"\",\n name: screen.name ?? \"\",\n component_tree: normalizeComponentTree(screen.component_tree),\n };\n}\n","/**\n * Navigation Transforms\n * Convert FluidOS API navigation items to NavigationItem format.\n *\n * Extracted from:\n * - apps/fluid-admin/networking/app-builder/app-navigation-items/types.ts\n * - apps/fluid-admin/networking/reps/screens.api.ts\n */\n\nimport type { NavigationItem } from \"@fluid-app/portal-core/types\";\nimport type { FluidOsApiNavigationItem } from \"@fluid-app/portal-core/fluidos-api\";\n\n/** Raw navigation item from the FluidOS API. */\nexport type RawApiNavigationItem = FluidOsApiNavigationItem;\n\n/**\n * Convert a raw FluidOS navigation item to NavigationItem.\n * Recursively transforms children and sorts by position.\n */\nexport function toNavigationItem(item: RawApiNavigationItem): NavigationItem {\n const children = (item.children ?? [])\n .map(toNavigationItem)\n .sort((a, b) => (a.position ?? 0) - (b.position ?? 0));\n\n return {\n id: Number(item.id),\n label: item.label ?? \"Untitled\",\n // Use conditional spread for optional properties (exactOptionalPropertyTypes)\n ...(item.slug != null ? { slug: String(item.slug) } : {}),\n ...(item.icon != null ? { icon: String(item.icon) } : {}),\n ...(item.screen_id != null ? { screen_id: Number(item.screen_id) } : {}),\n ...(item.parent_id != null ? { parent_id: Number(item.parent_id) } : {}),\n ...(item.source != null ? { source: item.source } : {}),\n position: item.position ?? 0,\n children,\n };\n}\n","/**\n * Data Transforms\n * Convert FluidOS API responses to RepAppData format.\n *\n * This is the main entry point for all transforms used by the SDK client\n * and hooks when fetching from the fluidos API.\n */\n\nexport {\n transformThemes,\n buildThemeDefinition,\n getActiveThemeId,\n type RawApiTheme,\n} from \"@fluid-app/portal-core/theme\";\n\nexport {\n normalizeComponentTree,\n toScreenDefinition,\n type RawApiScreen,\n} from \"./screen-transforms\";\n\nexport {\n toNavigationItem,\n type RawApiNavigationItem,\n} from \"./navigation-transforms\";\n\nimport type { AppManifestResponse } from \"@fluid-app/portal-core/app-definition-types\";\nimport type { RepAppData, RepAppManifest } from \"@fluid-app/portal-core/types\";\nimport {\n transformThemes,\n getActiveThemeId,\n type RawApiTheme,\n} from \"@fluid-app/portal-core/theme\";\nimport { toScreenDefinition, type RawApiScreen } from \"./screen-transforms\";\nimport {\n toNavigationItem,\n type RawApiNavigationItem,\n} from \"./navigation-transforms\";\n\n/**\n * Raw manifest shape consumed by the transform pipeline.\n *\n * A structural superset of `AppManifestResponse` that also accommodates\n * the legacy `RepAppData` fixtures produced by\n * `packages/cli/portal/src/vite-plugin/build-manifest.ts` in dev mode.\n * Fields that are optional here are either (a) never emitted by\n * `/api/app/manifest` or (b) emitted only by the dev-mode fixture. In both\n * cases `transformManifestToRepAppData` supplies `?? fallback` defaults.\n */\nexport interface RawManifestResponse {\n manifest: {\n definition_id?: number;\n published_version?: number;\n screens?: RawApiScreen[];\n profile?: {\n name?: string;\n definition_id?: number;\n themes?: RawApiTheme[];\n navigation?: {\n id?: number;\n name?: string;\n definition_id?: number;\n navigation_items?: RawApiNavigationItem[];\n };\n mobile_navigation?: {\n id?: number;\n name?: string;\n definition_id?: number;\n navigation_items?: RawApiNavigationItem[];\n };\n };\n };\n}\n\n/**\n * Convert an `AppManifestResponse` into the `RawManifestResponse` shape\n * expected by the transform pipeline. `AppManifestResponse` is structurally\n * assignable to `RawManifestResponse`, so this is a runtime-only guard that\n * rejects empty payloads.\n */\nexport function toRawManifest(\n response: AppManifestResponse,\n): RawManifestResponse {\n if (!response.manifest) {\n throw new Error(\"Portal BFF returned empty manifest\");\n }\n return response;\n}\n\n/**\n * Transform a raw FluidOS manifest API response into RepAppData.\n *\n * Handles:\n * - Theme transformation (legacy and new formats)\n * - Screen normalization (component_tree array wrapping)\n * - Navigation item transformation (recursive with position sorting)\n */\nexport function transformManifestToRepAppData(\n response: RawManifestResponse,\n): RepAppData {\n const manifest = response.manifest;\n const rawProfile = manifest.profile;\n\n const rawThemes: RawApiTheme[] = Array.isArray(rawProfile?.themes)\n ? rawProfile.themes\n : [];\n\n const screens = (manifest.screens ?? []).map((screen) =>\n toScreenDefinition(screen),\n );\n\n const navigationItems = (rawProfile?.navigation?.navigation_items ?? []).map(\n toNavigationItem,\n );\n\n const nav = rawProfile?.navigation;\n const mobileNav = rawProfile?.mobile_navigation;\n const mobileNavigationItems = (mobileNav?.navigation_items ?? []).map(\n toNavigationItem,\n );\n const activeThemeId = getActiveThemeId(rawThemes);\n const definitionId = manifest.definition_id ?? 0;\n\n return {\n definition_id: definitionId,\n published_version: manifest.published_version ?? 0,\n screens,\n profile: {\n name: rawProfile?.name ?? \"Default\",\n definition_id: rawProfile?.definition_id ?? definitionId,\n themes: transformThemes(rawThemes),\n // Conditional spread for exactOptionalPropertyTypes compliance\n ...(activeThemeId !== undefined ? { activeThemeId } : {}),\n navigation: {\n definition_id: nav?.definition_id ?? definitionId,\n id: nav?.id ?? 0,\n name: nav?.name ?? \"Main Navigation\",\n navigation_items: navigationItems,\n screens,\n },\n ...(mobileNav\n ? {\n mobile_navigation: {\n definition_id: mobileNav.definition_id ?? definitionId,\n id: mobileNav.id ?? 0,\n name: mobileNav.name ?? \"Mobile Navigation\",\n navigation_items: mobileNavigationItems,\n screens,\n },\n }\n : {}),\n },\n };\n}\n\n/**\n * Transform a raw manifest response, unwrapping the `{ manifest }` envelope.\n * Convenience wrapper matching the `RepAppManifest` type.\n */\nexport function transformRawManifest(\n response: RawManifestResponse,\n): RepAppManifest {\n return {\n manifest: transformManifestToRepAppData(response),\n };\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { createPersister } from \"@fluid-app/query-persister\";\nimport { useAppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api-context\";\nimport type { AppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport { transformManifestToRepAppData, toRawManifest } from \"../transforms\";\nimport type { RawManifestResponse } from \"../transforms\";\nimport type { RepAppData } from \"@fluid-app/portal-core/types\";\n\n/**\n * Base query key for full app data (rendered manifest endpoint).\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const APP_DATA_QUERY_KEY = [\"fluid\", \"app\"] as const;\n\n/**\n * Fetch the raw rendered manifest via the portal-tenant BFF adapter.\n * Shared by `useFluidApp` and `useFluidProfile` to avoid drift.\n */\nexport async function fetchRawManifest(\n api: AppDefinitionApi,\n): Promise<RawManifestResponse> {\n const response = await api.fetchManifest();\n return toRawManifest(response);\n}\n\n/**\n * Module-level persister instance (browser only).\n * Created once when the module loads so all calls to useFluidApp share\n * the same IndexedDB connection. Applied at the query level so it works\n * regardless of which QueryClient the app provides.\n */\nconst appDataPersister =\n typeof window !== \"undefined\" && !import.meta.env?.DEV\n ? createPersister()\n : undefined;\n\n/**\n * Hook to fetch the full portal app data from the rendered-manifest endpoint.\n *\n * Returns a `RepAppData` object containing:\n * - `screens` — all screen definitions with normalized component trees\n * - `profile.themes` — fully-transformed ThemeDefinition[] (handles legacy + new formats)\n * - `profile.activeThemeId` — the currently active theme ID\n * - `profile.navigation.navigation_items` — sorted, recursive navigation tree\n *\n * Uses IndexedDB persistence so subsequent page loads hydrate instantly\n * from cache while revalidating in the background. The raw API response\n * (plain JSON) is cached; Color objects are recreated from cache via\n * `select` on every restore — this is fast (CPU only, no network).\n *\n * @example\n * ```tsx\n * function App() {\n * const { data: appData, isLoading } = useFluidApp();\n *\n * if (isLoading) return <Spinner />;\n *\n * return (\n * <AppShell\n * appData={appData}\n * navigation={appData.profile.navigation.navigation_items}\n * />\n * );\n * }\n * ```\n */\nexport function useFluidApp(options?: {\n enabled?: boolean;\n}): UseQueryResult<RepAppData> {\n const appDefinitionApi = useAppDefinitionApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery<\n RawManifestResponse,\n Error,\n RepAppData,\n readonly (string | number)[]\n >({\n queryKey: scopeKey(APP_DATA_QUERY_KEY),\n queryFn: () => fetchRawManifest(appDefinitionApi),\n select: transformManifestToRepAppData,\n ...(appDataPersister && { persister: appDataPersister.persisterFn }),\n ...(options?.enabled !== undefined && { enabled: options.enabled }),\n });\n}\n","import { useEffect } from \"react\";\n\nconst SPIN_STYLE_ID = \"fluid-app-shell-loading-spin\";\n\n/**\n * Inject the spin keyframes style once into the document head.\n */\nfunction ensureSpinStyle(): void {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(SPIN_STYLE_ID)) return;\n\n const style = document.createElement(\"style\");\n style.id = SPIN_STYLE_ID;\n style.textContent = `@keyframes spin { to { transform: rotate(360deg); } }`;\n document.head.appendChild(style);\n}\n\n/**\n * Full-page loading spinner shown while AppShell is fetching app data\n * for the first time. Uses inline styles (not Tailwind) since the theme\n * hasn't loaded yet.\n */\nexport function AppShellLoading(): React.JSX.Element {\n useEffect(() => {\n ensureSpinStyle();\n }, []);\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n backgroundColor: \"#f9fafb\",\n }}\n >\n <div\n style={{\n width: \"40px\",\n height: \"40px\",\n border: \"3px solid #e5e7eb\",\n borderTopColor: \"#3b82f6\",\n borderRadius: \"50%\",\n animation: \"spin 1s linear infinite\",\n }}\n />\n <p\n style={{\n marginTop: \"1rem\",\n color: \"#6b7280\",\n fontSize: \"0.875rem\",\n }}\n >\n Loading...\n </p>\n </div>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { ChevronRight } from \"lucide-react\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport {\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n} from \"@fluid-app/portal-react/shell/sidebar\";\nimport {\n Collapsible,\n CollapsibleTrigger,\n CollapsibleContent,\n} from \"@fluid-app/ui-primitives\";\nimport type { NavigationItem } from \"../types/navigation\";\n\nexport interface CollapsibleNavItemProps {\n item: NavigationItem;\n isActive: boolean;\n currentSlug: string;\n onNavigate: (slug: string) => void;\n}\n\nexport function CollapsibleNavItem({\n item,\n isActive,\n currentSlug,\n onNavigate,\n}: CollapsibleNavItemProps): React.JSX.Element {\n const [open, setOpen] = useState(isActive);\n\n useEffect(() => {\n if (isActive) setOpen(true);\n }, [isActive]);\n\n return (\n <Collapsible\n open={open}\n onOpenChange={setOpen}\n asChild\n className=\"group/collapsible\"\n >\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton>\n {item.icon && <RepIcon name={item.icon} />}\n <span className=\"truncate\">{item.label}</span>\n <ChevronRight className=\"ml-auto size-3 transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => {\n const childSlug = normalizeSlug(child.slug);\n const childIsActive = normalizeSlug(currentSlug) === childSlug;\n\n return (\n <SidebarMenuItem key={child.slug || child.label}>\n <SidebarMenuButton\n isActive={childIsActive}\n onClick={() => onNavigate(childSlug)}\n >\n <RepIcon name={child.icon || \"file\"} className=\"h-3 w-3\" />\n <span>{child.label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n );\n })}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n );\n}\n","import {\n SidebarGroupLabel,\n SidebarMenu,\n SidebarMenuItem,\n SidebarMenuButton,\n} from \"@fluid-app/portal-react/shell/sidebar\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { isInSection } from \"@fluid-app/portal-core/navigation/utils\";\nimport type { NavigationItem } from \"../types/navigation\";\nimport { CollapsibleNavItem } from \"./CollapsibleNavItem\";\n\nexport interface SdkNavigationProps {\n navItems: NavigationItem[];\n currentSlug: string;\n onNavigate: (slug: string) => void;\n}\n\nexport function SdkNavigation({\n navItems,\n currentSlug,\n onNavigate,\n}: SdkNavigationProps): React.JSX.Element {\n return (\n <SidebarMenu>\n {navItems.map((item, index) => {\n // Skip items without slug AND without label\n if (!item.slug && !item.label) return null;\n\n const isActive = isInSection(item, currentSlug);\n const hasChildren = item.children?.length > 0;\n\n // Items with children — collapsible\n if (hasChildren) {\n return (\n <CollapsibleNavItem\n key={item.slug || item.label}\n item={item}\n isActive={isActive}\n currentSlug={currentSlug}\n onNavigate={onNavigate}\n />\n );\n }\n\n // Items without a slug are section headers\n if (!item.slug) {\n return (\n <SidebarGroupLabel key={item.id ?? `section-${index}`}>\n {item.label}\n </SidebarGroupLabel>\n );\n }\n\n // Leaf item — no children\n const itemSlug = normalizeSlug(item.slug);\n\n return (\n <SidebarMenuItem key={item.id ?? itemSlug}>\n <SidebarMenuButton\n isActive={isActive}\n onClick={() => onNavigate(itemSlug)}\n >\n {item.icon && <RepIcon name={item.icon} />}\n <span className=\"truncate\">{item.label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n );\n })}\n </SidebarMenu>\n );\n}\n","import { useState, useCallback } from \"react\";\nimport { X, Moon, Sun, LogOut, Smartphone } from \"lucide-react\";\nimport { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport { useRepUser } from \"@fluid-app/portal-widgets/contexts\";\nimport { useThemeMode } from \"@fluid-app/portal-react/shell/ThemeModeContext\";\n// import { SdkMobileQuickLinksGrid } from \"./SdkMobileQuickLinksGrid\";\n\nexport interface SdkMobileProfileMenuProps {\n onNavigate: (slug: string) => void;\n onLogout?: () => void;\n}\n\nfunction getInitials(name: string | null | undefined): string {\n if (!name) return \"U\";\n const parts = name.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (\n (parts[0]?.[0] ?? \"\") + (parts[parts.length - 1]?.[0] ?? \"\")\n ).toUpperCase();\n }\n return (name[0] ?? \"U\").toUpperCase();\n}\n\nexport function SdkMobileProfileMenu({\n onNavigate,\n onLogout,\n}: SdkMobileProfileMenuProps): React.JSX.Element | null {\n const { isMobile, useBottomNav } = useSidebar();\n const [isOpen, setIsOpen] = useState(false);\n const user = useRepUser();\n const themeMode = useThemeMode();\n\n const handleNavigate = useCallback(\n (slug: string) => {\n setIsOpen(false);\n onNavigate(slug);\n },\n [onNavigate],\n );\n\n if (!isMobile || !useBottomNav) return null;\n\n const initials = getInitials(user?.name);\n\n return (\n <>\n <button\n type=\"button\"\n onClick={() => setIsOpen(true)}\n className=\"bg-background text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex shrink-0 items-center justify-center rounded-full p-1\"\n aria-label=\"Open profile menu\"\n >\n {user?.imageUrl ? (\n <img\n src={user.imageUrl}\n alt={user.name ?? \"User\"}\n className=\"size-8 rounded-full object-cover\"\n />\n ) : (\n <span className=\"flex size-8 items-center justify-center text-xs font-medium\">\n {initials}\n </span>\n )}\n </button>\n\n {isOpen && (\n <div className=\"animate-in fade-in slide-in-from-bottom-4 bg-background fixed inset-0 z-50 flex flex-col duration-200\">\n <div className=\"flex items-center justify-between px-4 py-3\">\n <span className=\"text-foreground text-lg font-semibold\">\n Profile\n </span>\n <button\n type=\"button\"\n onClick={() => setIsOpen(false)}\n className=\"text-muted-foreground rounded-full p-1\"\n aria-label=\"Close profile menu\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"flex-1 overflow-auto px-4 pb-[env(safe-area-inset-bottom)]\">\n {user && (\n <div className=\"border-border flex items-center gap-3 border-b py-4\">\n {user.imageUrl ? (\n <img\n src={user.imageUrl}\n alt={user.name ?? \"User\"}\n className=\"size-10 rounded-full object-cover\"\n />\n ) : (\n <span className=\"bg-muted flex size-10 items-center justify-center rounded-full text-sm font-medium\">\n {initials}\n </span>\n )}\n <div className=\"min-w-0 flex-1\">\n {user.name && (\n <p className=\"text-foreground truncate text-sm font-semibold\">\n {user.name}\n </p>\n )}\n {user.email && (\n <p className=\"text-muted-foreground truncate text-xs\">\n {user.email}\n </p>\n )}\n </div>\n </div>\n )}\n\n <div className=\"border-border border-b py-4\">\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"app-download\")}\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n >\n <Smartphone className=\"size-5\" />\n <span>App Download</span>\n </button>\n </div>\n\n {/* <div className=\"border-border border-b py-4\">\n <SdkMobileQuickLinksGrid onNavigate={handleNavigate} />\n </div> */}\n\n <div className=\"space-y-4 py-4\">\n <button\n type=\"button\"\n onClick={themeMode.cycleMode}\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n >\n {themeMode.mode === \"dark\" ? (\n <Moon className=\"size-5\" />\n ) : (\n <Sun className=\"size-5\" />\n )}\n <span>\n Theme: {themeMode.mode === \"light\" ? \"Light\" : \"Dark\"}\n </span>\n </button>\n\n {onLogout && (\n <button\n type=\"button\"\n onClick={onLogout}\n className=\"text-destructive hover:bg-sidebar-accent flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n >\n <LogOut className=\"size-5\" />\n <span>Log out</span>\n </button>\n )}\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n","import { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport { useThemeMode } from \"@fluid-app/portal-react/shell/ThemeModeContext\";\nimport { Menu, Moon, Sun } from \"lucide-react\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport type { NavigationItem } from \"../types/navigation\";\n// import { QuickLinksDropdown } from \"./QuickLinksDropdown\";\nimport { SdkMobileProfileMenu } from \"./SdkMobileProfileMenu\";\n\nexport interface SdkHeaderProps {\n mobileTabs?: NavigationItem[];\n currentSlug: string;\n onNavigate: (slug: string) => void;\n onLogout?: () => void;\n}\n\nexport function SdkHeader({\n mobileTabs,\n currentSlug,\n onNavigate,\n onLogout,\n}: SdkHeaderProps): React.JSX.Element {\n const sidebar = useSidebar();\n const themeMode = useThemeMode();\n\n const ThemeIcon = themeMode.mode === \"dark\" ? Moon : Sun;\n const isMobileWithBottomNav = sidebar.isMobile && sidebar.useBottomNav;\n\n return (\n <header className=\"bg-sidebar shrink-0\">\n {isMobileWithBottomNav ? (\n <div className=\"flex h-[52px] items-center px-4\">\n <div className=\"text-muted-foreground ml-auto flex flex-none items-center justify-end\">\n <SdkMobileProfileMenu onNavigate={onNavigate} onLogout={onLogout} />\n </div>\n </div>\n ) : (\n <div className=\"flex h-[52px] items-center gap-2 px-6\">\n {/* Mobile hamburger — only show if NOT using bottom nav */}\n {sidebar.isMobile && !sidebar.useBottomNav && (\n <button\n type=\"button\"\n onClick={sidebar.toggleSidebar}\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground mr-2 flex shrink-0 items-center justify-center rounded-md p-2\"\n aria-label=\"Toggle sidebar\"\n >\n <Menu className=\"size-5\" />\n </button>\n )}\n\n {/* Spacer to push actions to the right */}\n <div className=\"flex-1\" />\n\n {/* Quick Links */}\n {/* <QuickLinksDropdown onNavigate={onNavigate} /> */}\n\n {/* Theme toggle */}\n <button\n type=\"button\"\n onClick={themeMode.cycleMode}\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground ml-2 flex shrink-0 items-center justify-center rounded-md p-2\"\n aria-label={`Switch theme (current: ${themeMode.mode})`}\n >\n <ThemeIcon className=\"size-3\" />\n </button>\n </div>\n )}\n\n {/* Mobile child tabs — shown below header when parent has children */}\n {isMobileWithBottomNav && mobileTabs && mobileTabs.length > 0 && (\n <nav className=\"scrollbar-none flex items-center gap-1 overflow-x-auto px-4\">\n {mobileTabs.map((tab) => {\n const tabSlug = normalizeSlug(tab.slug);\n if (!tabSlug) return null;\n\n const isActive = normalizeSlug(currentSlug) === tabSlug;\n\n return (\n <button\n key={tab.id ?? tabSlug}\n type=\"button\"\n onClick={() => onNavigate(tabSlug)}\n className={`border-b-2 px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors ${\n isActive\n ? \"border-primary text-foreground\"\n : \"text-muted-foreground hover:border-border hover:text-foreground border-transparent\"\n }`}\n >\n {tab.label}\n </button>\n );\n })}\n </nav>\n )}\n </header>\n );\n}\n","import { useState } from \"react\";\nimport { Building2 } from \"lucide-react\";\n\nexport function CompanyImage({\n src,\n alt,\n size,\n}: {\n size: number;\n src: string;\n alt: string;\n}) {\n const [error, setError] = useState(false);\n\n if (!src || error)\n return (\n <Building2\n style={{ height: size, width: size }}\n className=\"text-muted-foreground/25\"\n />\n );\n\n return (\n <img\n className=\"max-h-8 max-w-8 object-contain\"\n alt={alt}\n src={src}\n width={size}\n height={size}\n onError={() => setError(true)}\n />\n );\n}\n","import type { Company } from \"@fluid-app/company-switcher-core\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { CompanyImage } from \"./CompanyImage\";\n\nexport function CompanyItem({\n logo_url,\n icon_url,\n name,\n compact = false,\n}: Omit<Company, \"id\"> & { compact?: boolean }) {\n const resolvedSrc = icon_url || logo_url || \"\";\n return (\n <>\n <div className=\"flex aspect-square size-8 items-center justify-center rounded-lg\">\n <CompanyImage alt={name} src={resolvedSrc} size={32} />\n </div>\n <div\n className={cn(\n \"grid text-left text-sm leading-tight\",\n compact ? \"flex-shrink-0\" : \"flex-1\",\n )}\n >\n <span className=\"truncate font-semibold\">{name}</span>\n </div>\n </>\n );\n}\n","import { Skeleton } from \"@fluid-app/ui-primitives\";\n\nexport function CompanySwitcherSkeleton({ show }: { show: boolean }) {\n if (!show) return null;\n\n return (\n <div className=\"flex items-center gap-4 p-2\">\n <Skeleton className=\"size-5 shrink-0 rounded-sm bg-current\" />\n <Skeleton className=\"h-4 w-36 bg-current\" />\n </div>\n );\n}\n","import { useStore } from \"../hooks/use-store\";\nimport {\n CompanyItem,\n CompanySwitcherSkeleton,\n} from \"@fluid-app/company-switcher-ui\";\n\n/**\n * Static company display for single-tenant portal.\n * Shows logo + name in the sidebar header. No switching — just branding.\n */\nexport function SdkCompanySwitcher(): React.JSX.Element | null {\n const { data: store, isLoading } = useStore();\n\n if (isLoading) {\n return <CompanySwitcherSkeleton show />;\n }\n\n if (!store) {\n return null;\n }\n\n return (\n <div className=\"flex w-full items-center gap-2 rounded-md p-2\">\n <CompanyItem\n logo_url={store.logo_url}\n icon_url={store.icon_url}\n name={store.name || store.subdomain}\n />\n </div>\n );\n}\n","import {\n SYSTEM_NAVIGATION_ITEMS,\n type SystemNavigationSlug,\n} from \"./system-navigation-items\";\n\nexport const ACCOUNT_MANAGE_SLUGS = [\n \"profile\",\n \"orders\",\n \"subscriptions\",\n] as const satisfies readonly SystemNavigationSlug[];\n\nexport type AccountManageSlug = (typeof ACCOUNT_MANAGE_SLUGS)[number];\n\nexport interface AccountManageTab {\n key: AccountManageSlug;\n label: string;\n slug: string;\n}\n\n/** Account manage tabs with labels derived from SYSTEM_NAVIGATION_ITEMS. */\nexport const ACCOUNT_MANAGE_TABS: AccountManageTab[] = ACCOUNT_MANAGE_SLUGS.map(\n (slug) => ({\n key: slug,\n label: SYSTEM_NAVIGATION_ITEMS[slug].label,\n slug,\n }),\n);\n","/**\n * Navigate one step back in the browser history if anything is on the stack;\n * otherwise navigate to the SPA root. Used by fallback screens (error\n * boundary, 404) to give the user a way out without risking a navigation\n * outside the SPA when no prior history exists.\n */\nexport function goBackOrHome(): void {\n if (window.history.length > 1) {\n window.history.back();\n } else {\n window.location.assign(\"/\");\n }\n}\n","import type { ReactNode } from \"react\";\nimport {\n Card,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@fluid-app/ui-primitives\";\n\n/**\n * Internal centered card used for screen-level fallback states (errors,\n * 404s). Shared by `DefaultFallback` and `ScreenNotFound` so the two stay\n * visually consistent. Not exported from the SDK.\n */\nexport function FallbackCard({\n icon,\n title,\n description,\n actions,\n}: {\n readonly icon?: ReactNode;\n readonly title: string;\n readonly description?: ReactNode;\n readonly actions?: ReactNode;\n}): React.JSX.Element {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center p-4\">\n <Card className=\"h-auto w-full max-w-md\">\n <CardHeader className=\"text-center\">\n {icon && (\n <div className=\"text-muted-foreground flex justify-center [&_svg]:size-8\">\n {icon}\n </div>\n )}\n <CardTitle className=\"text-xl\">{title}</CardTitle>\n {description && <CardDescription>{description}</CardDescription>}\n </CardHeader>\n {actions && (\n <CardFooter className=\"justify-center gap-2\">{actions}</CardFooter>\n )}\n </Card>\n </div>\n );\n}\n","import { Button } from \"@fluid-app/ui-primitives\";\nimport { Compass } from \"lucide-react\";\nimport { goBackOrHome } from \"../shell/go-back-or-home\";\nimport { FallbackCard } from \"./FallbackCard\";\n\n/**\n * Rendered by `PageRouter` when the current slug doesn't match any custom\n * page, system screen, or builder screen. This is a true \"not found\" — the\n * portal isn't configured to render anything for this path.\n */\nexport function ScreenNotFound({\n name,\n}: {\n readonly name?: string;\n}): React.JSX.Element {\n return (\n <FallbackCard\n icon={<Compass />}\n title=\"Page not found\"\n description={\n name\n ? `We couldn't find a page for \"${name}\".`\n : \"We couldn't find the page you were looking for.\"\n }\n actions={\n <Button variant=\"default\" onClick={goBackOrHome}>\n Go back\n </Button>\n }\n />\n );\n}\n","import type React from \"react\";\n\n/**\n * Shown when a customer attempts to access a rep-only page via direct URL.\n */\nexport function AccessDeniedScreen(): React.JSX.Element {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"border-border max-w-sm rounded-lg border border-dashed p-8 text-center\">\n <h2 className=\"text-foreground text-xl font-semibold\">Access Denied</h2>\n <p className=\"text-muted-foreground mt-2\">\n You don't have permission to view this page.\n </p>\n <p className=\"text-muted-foreground mt-1 text-sm\">\n This feature is not available for your account type.\n </p>\n </div>\n </div>\n );\n}\n","/**\n * BuilderScreenView — renders a builder screen's component_tree with\n * DataAwareWidget support for data-bound widgets.\n *\n * Uses the shared ScreenRenderer from portal-widgets under the hood,\n * but wraps data-bound widgets with DataAwareWidget from portal-core.\n */\n\nimport React, { memo } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type { ScreenDefinition } from \"@fluid-app/portal-core/types\";\nimport { DataAwareWidget } from \"@fluid-app/portal-react/data-sources/DataAwareWidget\";\nimport { useRegistry } from \"@fluid-app/portal-widgets/contexts\";\n\ninterface WidgetRendererProps {\n widget: WidgetSchema;\n index: number;\n}\n\n/**\n * Renders a single widget, wrapping with DataAwareWidget if it has a dataSource.\n */\nfunction WidgetRenderer({ widget, index }: WidgetRendererProps) {\n const registry = useRegistry();\n const Component = registry[widget.type];\n\n if (!Component) {\n console.warn(\n `[BuilderScreenView] Widget type \"${String(widget.type)}\" not found in registry`,\n );\n return null;\n }\n\n if (widget.dataSource) {\n return (\n <div key={widget.id ?? index} className=\"h-full w-full overflow-x-hidden\">\n <DataAwareWidget widget={widget} Component={Component} />\n </div>\n );\n }\n\n return (\n <div key={widget.id ?? index} className=\"h-full w-full overflow-x-hidden\">\n <Component {...widget.props} />\n </div>\n );\n}\n\nexport interface BuilderScreenViewProps {\n /** The screen definition to render */\n screen: ScreenDefinition;\n /** Additional CSS classes for the wrapper div */\n className?: string;\n}\n\n/**\n * Renders a builder screen's component_tree with full data source support.\n * Widgets with `dataSource` config are automatically wrapped with `DataAwareWidget`\n * which fetches data and merges it with static props before rendering.\n */\nfunction BuilderScreenViewImpl({\n screen,\n className,\n}: BuilderScreenViewProps): React.JSX.Element | null {\n const widgets = screen.component_tree;\n\n if (!widgets || widgets.length === 0) {\n return (\n <div className={className ?? \"h-full w-full\"}>\n <div className=\"text-muted-foreground flex h-full items-center justify-center\">\n <p>This screen has no content yet.</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className={className ?? \"h-full w-full\"}>\n {widgets.map((widget, index) => {\n if (!widget) return null;\n return (\n <WidgetRenderer\n key={widget.id ?? index}\n widget={widget}\n index={index}\n />\n );\n })}\n </div>\n );\n}\n\nexport const BuilderScreenView: React.MemoExoticComponent<\n typeof BuilderScreenViewImpl\n> = memo(BuilderScreenViewImpl);\n","import { PackageOpen, Repeat, User, type LucideIcon } from \"lucide-react\";\nimport {\n ACCOUNT_MANAGE_TABS,\n type AccountManageSlug,\n} from \"@fluid-app/portal-core/navigation/account-manage\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\n\nconst ICON_MAP: Record<AccountManageSlug, LucideIcon> = {\n profile: User,\n orders: PackageOpen,\n subscriptions: Repeat,\n};\n\nconst NAV_ITEMS = ACCOUNT_MANAGE_TABS.map((tab) => ({\n ...tab,\n icon: ICON_MAP[tab.key],\n}));\n\nfunction getActiveTab(slug: string): AccountManageSlug {\n const root = slug.split(\"/\")[0];\n if (root === \"orders\") return \"orders\";\n if (root === \"subscriptions\") return \"subscriptions\";\n return \"profile\";\n}\n\nexport function AccountManageLayout({\n children,\n}: {\n children: React.ReactNode;\n}): React.JSX.Element {\n const { currentSlug, navigate } = useAppNavigation();\n const activeTab = getActiveTab(currentSlug);\n\n return (\n <div className=\"flex flex-col md:flex-row\">\n {/* Mobile: horizontal tab bar */}\n <nav className=\"flex gap-1 overflow-x-auto border-b px-4 py-2 md:hidden\">\n {NAV_ITEMS.map(({ key, slug, label, icon: Icon }) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => navigate(slug)}\n className={`flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium whitespace-nowrap ${\n activeTab === key\n ? \"bg-sidebar-primary text-sidebar-primary-foreground\"\n : \"hover:bg-sidebar-primary hover:text-sidebar-primary-foreground\"\n }`}\n >\n <Icon className=\"h-4 w-4\" />\n {label}\n </button>\n ))}\n </nav>\n\n {/* Desktop: vertical sidebar */}\n <nav className=\"hidden w-48 shrink-0 flex-col gap-1 p-4 md:flex\">\n {NAV_ITEMS.map(({ key, slug, label, icon: Icon }) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => navigate(slug)}\n className={`flex items-center gap-2 rounded-md px-3 py-2 text-left text-sm font-medium ${\n activeTab === key\n ? \"bg-sidebar-primary text-sidebar-primary-foreground\"\n : \"hover:bg-sidebar-primary hover:text-sidebar-primary-foreground\"\n }`}\n >\n <Icon className=\"h-4 w-4\" />\n {label}\n </button>\n ))}\n </nav>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">{children}</div>\n </div>\n );\n}\n","import { lazy, type ComponentType } from \"react\";\n\nconst ProfileScreen = lazy(() =>\n import(\"../screens/ProfileScreen\").then((m) => ({\n default: m.ProfileScreen,\n })),\n);\nconst OrdersScreen = lazy(() =>\n import(\"../screens/OrdersScreen\").then((m) => ({\n default: m.OrdersScreen,\n })),\n);\nconst SubscriptionsScreen = lazy(() =>\n import(\"../screens/SubscriptionsScreen\").then((m) => ({\n default: m.SubscriptionsScreen,\n })),\n);\nconst MessagingScreen = lazy(() =>\n import(\"../screens/MessagingScreen\").then((m) => ({\n default: m.MessagingScreen,\n })),\n);\nconst ContactsScreen = lazy(() =>\n import(\"../screens/ContactsScreen\").then((m) => ({\n default: m.ContactsScreen,\n })),\n);\nconst ShopScreen = lazy(() =>\n import(\"../screens/ShopScreen\").then((m) => ({ default: m.ShopScreen })),\n);\nconst CustomersScreen = lazy(() =>\n import(\"../screens/CustomersScreen\").then((m) => ({\n default: m.CustomersScreen,\n })),\n);\nconst ShareablesScreen = lazy(() =>\n import(\"../screens/ShareablesScreen\").then((m) => ({\n default: m.ShareablesScreen,\n })),\n);\nconst MySiteScreen = lazy(() =>\n import(\"../screens/MySiteScreen\").then((m) => ({\n default: m.MySiteScreen,\n })),\n);\nconst UpgradeScreen = lazy(() =>\n import(\"../screens/UpgradeScreen\").then((m) => ({\n default: m.UpgradeScreen,\n })),\n);\nconst AppDownloadScreen = lazy(() =>\n import(\"../screens/AppDownloadScreen\").then((m) => ({\n default: m.AppDownloadScreen,\n })),\n);\n\nexport const SYSTEM_SLUG_SCREEN_MAP: Record<string, ComponentType> = {\n profile: ProfileScreen,\n orders: OrdersScreen,\n subscriptions: SubscriptionsScreen,\n messages: MessagingScreen,\n contacts: ContactsScreen,\n shop: ShopScreen,\n customers: CustomersScreen,\n \"my-site\": MySiteScreen,\n \"share/products\": ShareablesScreen,\n \"share/product\": ShareablesScreen,\n \"share/media\": ShareablesScreen,\n \"share/playlists\": ShareablesScreen,\n \"share/playlist\": ShareablesScreen,\n \"share/files\": ShareablesScreen,\n \"share/pages\": ShareablesScreen,\n \"share/page\": ShareablesScreen,\n upgrade: UpgradeScreen,\n \"app-download\": AppDownloadScreen,\n};\n\n/** Pre-sorted keys for greedy prefix matching (longest first). */\nconst SORTED_SCREEN_KEYS = Object.keys(SYSTEM_SLUG_SCREEN_MAP).sort(\n (a, b) => b.length - a.length,\n);\n\n/** Prefix-match a slug against screen map keys, longest match first. */\nexport function findScreenByPrefix(slug: string): ComponentType | undefined {\n for (const key of SORTED_SCREEN_KEYS) {\n if (slug === key || slug.startsWith(key + \"/\")) {\n return SYSTEM_SLUG_SCREEN_MAP[key];\n }\n }\n return undefined;\n}\n","import { Suspense, useMemo, type ComponentType } from \"react\";\nimport {\n isSystemNavigationItem,\n isRepOnlySlug,\n} from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { ACCOUNT_MANAGE_SLUGS } from \"@fluid-app/portal-core/navigation/account-manage\";\nimport type { NavigationItem, ScreenDefinition } from \"../types/navigation\";\nimport { CoreScreenPlaceholder } from \"../screens/CoreScreenPlaceholder\";\nimport { ScreenNotFound } from \"../screens/ScreenNotFound\";\nimport { AccessDeniedScreen } from \"../screens/AccessDeniedScreen\";\nimport { BuilderScreenView } from \"./BuilderScreenView\";\nimport { AccountManageLayout } from \"../account/account-management-layout\";\nimport { useAccount } from \"../hooks/use-account\";\nimport {\n SYSTEM_SLUG_SCREEN_MAP,\n findScreenByPrefix,\n} from \"./system-screen-map\";\n\nconst ACCOUNT_SLUGS = new Set<string>(ACCOUNT_MANAGE_SLUGS);\n\n/**\n * Returns true if any nav slug resolves to the given system screen component.\n * Lets detail routes (e.g. `share/product/:id`) render when their listing\n * slug (`share/products`) is in the nav, since both map to the same screen.\n */\nfunction isSystemScreenCoveredByNav(\n target: ComponentType,\n navSlugs: readonly string[],\n): boolean {\n for (const slug of navSlugs) {\n const navScreen = SYSTEM_SLUG_SCREEN_MAP[slug] ?? findScreenByPrefix(slug);\n if (navScreen === target) return true;\n }\n return false;\n}\n\nexport interface PageRouterProps {\n currentSlug: string;\n currentNavItem?: NavigationItem | undefined;\n customPages?:\n | Record<string, ComponentType<{ slug?: string; params?: string }>>\n | undefined;\n /** Builder screen definitions (from fluidos API) */\n screens?: ScreenDefinition[] | undefined;\n baseSlug: string;\n restParams: string;\n /**\n * Slugs from the active navigation. When provided, system screens only\n * render if they're reachable via the nav (matches the implicit gating\n * builder screens get from being sourced via `appData.screens`). Omit to\n * render system screens unconditionally.\n */\n navSlugs?: readonly string[] | undefined;\n}\n\nexport function PageRouter({\n currentSlug,\n currentNavItem,\n customPages,\n screens,\n baseSlug,\n restParams,\n navSlugs,\n}: PageRouterProps): React.JSX.Element {\n const { data: account } = useAccount();\n const isCustomer = account?.member_type === \"customer\";\n\n // Build a screen lookup map by ID for O(1) access\n const screenById = useMemo(() => {\n if (!screens || screens.length === 0) return undefined;\n return new Map(screens.map((s) => [s.id, s]));\n }, [screens]);\n\n // Build a screen lookup map by slug for fallback resolution\n const screenBySlug = useMemo(() => {\n if (!screens || screens.length === 0) return undefined;\n return new Map(screens.filter((s) => s.slug).map((s) => [s.slug, s]));\n }, [screens]);\n\n // Resolve builder screen: screen_id first, then slug fallback\n const builderScreen = useMemo(() => {\n if (currentNavItem?.screen_id && screenById) {\n const byId = screenById.get(currentNavItem.screen_id);\n if (byId) return byId;\n }\n if (screenBySlug) {\n return (\n screenBySlug.get(currentSlug) ?? screenBySlug.get(baseSlug) ?? undefined\n );\n }\n return undefined;\n }, [\n currentNavItem?.screen_id,\n screenById,\n screenBySlug,\n currentSlug,\n baseSlug,\n ]);\n\n // 0. Block customer access to rep-only slugs\n if (isCustomer && isRepOnlySlug(currentSlug)) {\n return <AccessDeniedScreen />;\n }\n\n // 1. Custom page match (takes priority over system defaults)\n const ExactCustomPage = customPages?.[currentSlug];\n if (ExactCustomPage) {\n return <ExactCustomPage slug={currentSlug} params={restParams} />;\n }\n\n // 2. Prefix custom page match (base slug with rest params)\n if (baseSlug !== currentSlug) {\n const PrefixCustomPage = customPages?.[baseSlug];\n if (PrefixCustomPage) {\n return <PrefixCustomPage slug={currentSlug} params={restParams} />;\n }\n }\n\n // 3. System navigation item with a dedicated screen component\n // First try exact match on baseSlug, then prefix-match currentSlug\n // against screen map keys (handles detail routes like \"share/product/123\"\n // matching \"share/product\" when the slug isn't a registered nav item).\n const SystemScreen =\n SYSTEM_SLUG_SCREEN_MAP[baseSlug] ?? findScreenByPrefix(currentSlug);\n const systemScreenInNav =\n navSlugs === undefined ||\n (SystemScreen !== undefined &&\n isSystemScreenCoveredByNav(SystemScreen, navSlugs));\n if (SystemScreen && systemScreenInNav) {\n const content = (\n <Suspense\n fallback={\n <div className=\"flex h-full items-center justify-center\">\n <div className=\"border-primary h-8 w-8 animate-spin rounded-full border-2 border-t-transparent\" />\n </div>\n }\n >\n <SystemScreen />\n </Suspense>\n );\n\n if (ACCOUNT_SLUGS.has(baseSlug)) {\n return <AccountManageLayout>{content}</AccountManageLayout>;\n }\n\n return content;\n }\n\n // 4. System slug without a dedicated screen (account, my-site, share/*)\n if (isSystemNavigationItem(baseSlug)) {\n return <CoreScreenPlaceholder name={currentNavItem?.label ?? baseSlug} />;\n }\n\n // 5. Builder screen (by screen_id or slug match)\n if (builderScreen) {\n return <BuilderScreenView screen={builderScreen} />;\n }\n\n // 6. True \"not found\" — slug didn't match any custom/system/builder screen\n return <ScreenNotFound name={currentNavItem?.label ?? currentSlug} />;\n}\n","import type { NavigationItem } from \"../types/navigation\";\nimport { normalizeSlug } from \"./system-navigation-items\";\n\nexport interface SlugMatch {\n matchedSlug: string;\n rest: string;\n}\n\n/**\n * Extract all slugs from a navigation tree, sorted by segment count descending.\n * Longest slugs first enables greedy prefix matching (e.g. \"share/playlists\"\n * is checked before \"share\").\n */\nexport function collectNavSlugs(items: NavigationItem[]): string[] {\n const slugs: string[] = [];\n\n for (const item of items) {\n if (item.slug) slugs.push(normalizeSlug(item.slug));\n for (const child of item.children ?? []) {\n if (child.slug) slugs.push(normalizeSlug(child.slug));\n }\n }\n\n return [...slugs].sort((a, b) => b.split(\"/\").length - a.split(\"/\").length);\n}\n\n/**\n * Find the longest registered nav slug that is a prefix of `fullSlug`.\n * Uses segment-boundary checking to prevent \"shop\" from matching \"shopping\".\n */\nexport function matchSlugPrefix(\n fullSlug: string,\n navSlugs: string[],\n): SlugMatch | undefined {\n const normalized = normalizeSlug(fullSlug);\n if (!normalized) return undefined;\n\n for (const navSlug of navSlugs) {\n if (normalized === navSlug) {\n return { matchedSlug: navSlug, rest: \"\" };\n }\n if (normalized.startsWith(navSlug + \"/\")) {\n return {\n matchedSlug: navSlug,\n rest: normalized.slice(navSlug.length + 1),\n };\n }\n }\n\n return undefined;\n}\n\n/**\n * Extract the slug portion from a full pathname by stripping the basePath prefix.\n * Returns an empty string when the pathname equals the basePath exactly.\n *\n * Examples:\n * extractSlugFromPathname(\"/contacts/123\", \"/\") → \"contacts/123\"\n * extractSlugFromPathname(\"/portal/contacts\", \"/portal\") → \"contacts\"\n * extractSlugFromPathname(\"/portal\", \"/portal\") → \"\"\n * extractSlugFromPathname(\"/\", \"/\") → \"\"\n */\nexport function extractSlugFromPathname(\n pathname: string,\n basePath: string,\n): string {\n // For root basePath, just strip the leading slash\n if (basePath === \"/\") {\n return pathname.replace(/^\\//, \"\");\n }\n\n // Strip basePath prefix, then strip leading slash from remainder\n if (pathname.startsWith(basePath)) {\n return pathname.slice(basePath.length).replace(/^\\//, \"\");\n }\n\n // Fallback: return pathname without leading slash\n return pathname.replace(/^\\//, \"\");\n}\n\nexport function isSlugInSection(\n item: NavigationItem,\n currentSlug: string,\n navSlugs: string[],\n): boolean {\n const match = matchSlugPrefix(currentSlug, navSlugs);\n const baseSlug = match?.matchedSlug ?? normalizeSlug(currentSlug);\n\n if (normalizeSlug(item.slug) === baseSlug) return true;\n return (\n item.children?.some((child) => normalizeSlug(child.slug) === baseSlug) ??\n false\n );\n}\n","import { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { TriangleAlert } from \"lucide-react\";\nimport { FallbackCard } from \"../screens/FallbackCard\";\nimport { goBackOrHome } from \"./go-back-or-home\";\n\nexport interface AppShellErrorBoundaryProps {\n children: ReactNode;\n /**\n * Invoked every time the boundary catches an error. Fires again on each\n * subsequent crash if `reset()` is called and the underlying issue persists.\n * When provided, the boundary will not log to `console.error` itself —\n * forward to your reporter (e.g. Sentry) inside this callback.\n *\n * @example\n * ```tsx\n * <AppShellErrorBoundary onError={(err, info) => Sentry.captureException(err, { extra: info })}>\n * ```\n */\n onError?: (error: Error, info: ErrorInfo) => void;\n /** Override the default fallback UI. Receives a reset callback. */\n fallback?: (props: { error: Error; reset: () => void }) => ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\n\nexport class AppShellErrorBoundary extends Component<\n AppShellErrorBoundaryProps,\n State\n> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo): void {\n if (this.props.onError) {\n try {\n this.props.onError(error, info);\n } catch (callbackError) {\n // A throwing onError (e.g. misconfigured Sentry transport) must not\n // mask the original crash. Surface both to console as a fallback.\n console.error(\"[portal] onError handler threw:\", callbackError);\n console.error(\"[portal] Original screen crash:\", error, info);\n }\n return;\n }\n console.error(\"[portal] Screen crashed:\", error, info);\n }\n\n reset = (): void => {\n this.setState({ error: null });\n };\n\n override render(): ReactNode {\n const { error } = this.state;\n if (!error) return this.props.children;\n\n if (this.props.fallback) {\n return this.props.fallback({ error, reset: this.reset });\n }\n\n return (\n <FallbackCard\n icon={<TriangleAlert />}\n title=\"Something went wrong\"\n description=\"We hit an unexpected error loading this page.\"\n actions={\n <>\n <Button variant=\"outline\" onClick={this.reset}>\n Try again\n </Button>\n <Button variant=\"default\" onClick={goBackOrHome}>\n Go back\n </Button>\n </>\n }\n />\n );\n }\n}\n","/**\n * useLogout Hook\n *\n * Provides a complete logout function that:\n * 1. Clears all client-side state (query cache, IndexedDB, sessionStorage)\n * 2. Navigates to GET /logout — Rails clears the session and redirects to the Hub\n */\n\nimport { useCallback } from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { deleteDatabase } from \"@fluid-app/query-persister\";\n\nexport interface UseLogoutOptions {\n /** URL to redirect to after logout. Triggers a full page navigation. */\n redirectUrl?: string;\n /** Callback invoked after all state is cleared. Ignored when `redirectUrl` is set. */\n onLogout?: () => void;\n}\n\n/**\n * Hook that returns a `logout` function which clears the server session\n * via `DELETE /logout` and all cached/persisted client state.\n *\n * @example\n * ```tsx\n * const logout = useLogout({ redirectUrl: \"/login\" });\n * <button onClick={logout}>Log out</button>\n * ```\n *\n * @example\n * ```tsx\n * const logout = useLogout({\n * onLogout: () => navigate(\"/signed-out\"),\n * });\n * ```\n */\nexport function useLogout({\n redirectUrl,\n onLogout,\n}: UseLogoutOptions = {}): () => Promise<void> {\n const queryClient = useQueryClient();\n\n const logout = useCallback(async () => {\n // 1. Cancel in-flight requests to prevent cache repopulation\n await queryClient.cancelQueries();\n\n // 2. Clear in-memory TanStack Query cache\n queryClient.clear();\n\n // 3. Clear IndexedDB persisted query cache\n try {\n await deleteDatabase();\n } catch (error) {\n // Non-fatal — continue with logout even if IndexedDB cleanup fails\n console.error(\"[useLogout] Failed to clear IndexedDB cache:\", error);\n }\n\n // 4. Clear sessionStorage — intentionally clears all keys because the\n // portal app owns the full page (not embedded as a micro-frontend).\n try {\n sessionStorage.clear();\n } catch {\n // sessionStorage may be unavailable in some contexts\n }\n\n // 5. Navigate to the server logout endpoint. Rails clears the session\n // cookie and redirects to the Portal Hub company list. A full page\n // navigation lets the browser follow the redirect naturally — no\n // fetch or JSON parsing needed.\n if (redirectUrl) {\n window.location.href = redirectUrl;\n } else if (onLogout) {\n onLogout();\n } else {\n window.location.href = \"/logout\";\n }\n }, [queryClient, redirectUrl, onLogout]);\n\n return logout;\n}\n","import { useCallback, useState } from \"react\";\nimport { LogOut } from \"lucide-react\";\nimport {\n SidebarMenu,\n SidebarMenuItem,\n SidebarMenuButton,\n} from \"@fluid-app/portal-react/shell/sidebar\";\n\nexport interface SdkLogoutButtonProps {\n onLogout: () => Promise<void>;\n}\n\n/**\n * Sidebar footer button that triggers the logout flow.\n * Rendered inside the AppShell sidebar footer slot.\n */\nexport function SdkLogoutButton({\n onLogout,\n}: SdkLogoutButtonProps): React.JSX.Element {\n const [isPending, setIsPending] = useState(false);\n\n const handleClick = useCallback(async () => {\n setIsPending(true);\n try {\n await onLogout();\n } catch (error) {\n console.error(\"[SdkLogoutButton] Logout failed:\", error);\n } finally {\n setIsPending(false);\n }\n }, [onLogout]);\n\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton onClick={handleClick} disabled={isPending}>\n <LogOut className=\"size-4\" />\n <span>{isPending ? \"Logging out\\u2026\" : \"Log out\"}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n );\n}\n","import type { NavigationItem } from \"@fluid-app/portal-core/types\";\nimport {\n isRepOnlySlug,\n type SystemNavigationItem,\n} from \"@fluid-app/portal-core/navigation/system-navigation-items\";\n\n/**\n * Filter navigation items by removing rep-only slugs.\n * Handles nested children: rep-only children are removed, and parents\n * with no remaining children are also removed.\n */\nexport function filterRepOnlyNavItems(\n items: NavigationItem[],\n): NavigationItem[] {\n const result: NavigationItem[] = [];\n\n for (const item of items) {\n // Leaf item with a rep-only slug — skip\n if (!item.children?.length) {\n if (isRepOnlySlug(item.slug)) continue;\n result.push(item);\n continue;\n }\n\n // Parent with a rep-only slug — skip entire group\n if (isRepOnlySlug(item.slug)) continue;\n\n // Recursively filter children\n const filteredChildren = filterRepOnlyNavItems(item.children);\n\n // Drop parent if all children were removed\n if (filteredChildren.length === 0) continue;\n\n result.push({ ...item, children: filteredChildren });\n }\n\n return result;\n}\n\n/**\n * Filter system navigation sections by removing rep-only items.\n * Sections with no remaining items are dropped entirely.\n */\nexport function filterRepOnlySections(\n sections: Record<string, SystemNavigationItem[]>,\n): Record<string, SystemNavigationItem[]> {\n const filtered: Record<string, SystemNavigationItem[]> = {};\n for (const [section, items] of Object.entries(sections)) {\n const allowed = items.filter((item) => !isRepOnlySlug(item.slug));\n if (allowed.length > 0) filtered[section] = allowed;\n }\n return filtered;\n}\n","import {\n useState,\n useEffect,\n useCallback,\n useMemo,\n type ReactNode,\n type ComponentType,\n} from \"react\";\nimport { AppShellLayout } from \"@fluid-app/portal-react/shell/AppShellLayout\";\nimport {\n ThemeModeProvider,\n type ThemeMode,\n} from \"@fluid-app/portal-react/shell/ThemeModeContext\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { getDefaultNavigation } from \"@fluid-app/portal-core/navigation/default-navigation\";\nimport { ScreenHeader } from \"@fluid-app/portal-react/shell/ScreenHeader\";\nimport { ScreenHeaderProvider } from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport { SdkBottomNav } from \"./SdkBottomNav\";\nimport type {\n RepAppData,\n ScreenDefinition,\n} from \"@fluid-app/portal-core/types\";\nimport {\n applyTheme,\n getDefaultThemeDefinition,\n removeAllThemes,\n resolveTheme,\n} from \"@fluid-app/portal-core/theme\";\nimport { useFluidApp } from \"../hooks/use-fluid-app\";\nimport type { NavigationItem } from \"../types/navigation\";\nimport { AppShellLoading } from \"./AppShellLoading\";\nimport { SdkNavigation } from \"./SdkNavigation\";\nimport { SdkHeader } from \"./SdkHeader\";\nimport { SdkCompanySwitcher } from \"./SdkCompanySwitcher\";\nimport { PageRouter } from \"./PageRouter\";\nimport {\n collectNavSlugs,\n matchSlugPrefix,\n extractSlugFromPathname,\n} from \"@fluid-app/portal-core/navigation/slug-utils\";\nimport { AppNavigationProvider } from \"./AppNavigationContext\";\nimport { AppShellErrorBoundary } from \"./AppShellErrorBoundary\";\n\nimport { useLogout } from \"../hooks/use-logout\";\nimport { SdkLogoutButton } from \"./SdkLogoutButton\";\nimport { RepUserProvider } from \"@fluid-app/portal-widgets/contexts\";\nimport { Toaster } from \"@fluid-app/ui-primitives\";\nimport { useAccount } from \"../hooks/use-account\";\nimport { filterRepOnlyNavItems } from \"../navigation/filter-nav-items\";\n\nconst THEME_STORAGE_KEY = \"portal-theme-mode\";\n\nfunction getInitialThemeMode(): ThemeMode {\n if (typeof window === \"undefined\") return \"light\";\n const stored = localStorage.getItem(THEME_STORAGE_KEY);\n if (stored === \"light\" || stored === \"dark\") return stored;\n return \"light\";\n}\n\nfunction findFirstNavigableSlug(items: NavigationItem[]): string {\n for (const item of items) {\n if (item.slug) return normalizeSlug(item.slug);\n for (const child of item.children ?? []) {\n if (child.slug) return normalizeSlug(child.slug);\n }\n }\n return \"\";\n}\n\nfunction findCurrentSection(\n items: NavigationItem[],\n slug: string,\n): NavigationItem | undefined {\n const normalized = normalizeSlug(slug);\n for (const item of items) {\n if (normalizeSlug(item.slug) === normalized) return item;\n if (\n item.children?.some((child) => normalizeSlug(child.slug) === normalized)\n ) {\n return item;\n }\n }\n return undefined;\n}\n\nfunction findNavItem(\n items: NavigationItem[],\n slug: string,\n): NavigationItem | undefined {\n const normalized = normalizeSlug(slug);\n for (const item of items) {\n if (normalizeSlug(item.slug) === normalized) return item;\n for (const child of item.children ?? []) {\n if (normalizeSlug(child.slug) === normalized) return child;\n }\n }\n return undefined;\n}\n\nexport interface AppShellProps {\n /** Pre-fetched app data (skips internal useFluidApp call if provided) */\n appData?: RepAppData;\n /** Override navigation items (otherwise derived from appData/API) */\n navigation?: NavigationItem[];\n /** Custom page components keyed by slug */\n customPages?: Record<\n string,\n ComponentType<{ slug?: string; params?: string }>\n >;\n /** Base path for subpath deployments (e.g. \"/portal\"). Default: \"/\" */\n basePath?: string;\n /** Controlled current slug */\n currentSlug?: string;\n /** Navigation callback */\n onNavigate?: (slug: string) => void;\n /** Custom sidebar header slot */\n sidebarHeader?: ReactNode;\n /** Custom sidebar footer slot. When provided, replaces the default logout button. */\n sidebarFooter?: ReactNode;\n /**\n * Callback invoked after the user logs out and all client state has been cleared.\n * If not provided, a default logout button is still rendered, but no post-logout\n * action is taken (consumers should pair this with `logoutRedirectUrl`\n * or provide their own `sidebarFooter`).\n */\n onLogout?: () => void;\n /** URL to redirect to after logout (e.g. \"/login\"). Takes precedence over `onLogout`. */\n logoutRedirectUrl?: string;\n /** Render prop or static children for the content area */\n children?:\n | ReactNode\n | ((props: {\n currentSlug: string;\n currentNavItem: NavigationItem | undefined;\n }) => ReactNode);\n}\n\nexport function AppShell({\n appData: appDataProp,\n navigation: navigationProp,\n customPages,\n basePath = \"/\",\n currentSlug: controlledSlug,\n onNavigate: onNavigateProp,\n sidebarHeader,\n sidebarFooter,\n onLogout,\n logoutRedirectUrl,\n children,\n}: AppShellProps): React.JSX.Element {\n // Normalize basePath: ensure leading slash, no trailing slash\n const normalizedBasePath = useMemo(() => {\n const stripped = basePath.replace(/^\\/|\\/$/g, \"\");\n return stripped ? `/${stripped}` : \"/\";\n }, [basePath]);\n\n // Fetch full app data from the rendered-manifest endpoint\n // (disabled when appData is provided). The response carries\n // `definition_id` directly, so no separate definition fetch is needed.\n const { data: fetchedAppData, isLoading } = useFluidApp({\n enabled: !appDataProp,\n });\n const appData = appDataProp ?? fetchedAppData;\n\n const { data: account } = useAccount();\n const repUser = useMemo(\n () => ({\n name:\n account?.first_name && account?.last_name\n ? `${account.first_name} ${account.last_name}`\n : null,\n email: account?.email ?? null,\n imageUrl: account?.avatar_url ?? null,\n publicId: account?.slug,\n }),\n [\n account?.first_name,\n account?.last_name,\n account?.email,\n account?.avatar_url,\n account?.slug,\n ],\n );\n\n // Resolve the active theme from app data, falling back to the theme-engine\n // default when the manifest has no themes. This guarantees CSS variables\n // are always emitted so the shell renders with proper styling.\n const activeTheme = useMemo(() => {\n const themes = appData?.profile?.themes;\n const activeId = appData?.profile?.activeThemeId;\n if (themes?.length) {\n const matched = activeId\n ? themes.find((t) => t.id === activeId)\n : undefined;\n const first = themes[0];\n if (matched) return matched;\n if (first) return first;\n }\n return getDefaultThemeDefinition();\n }, [appData?.profile?.themes, appData?.profile?.activeThemeId]);\n\n // Apply theme CSS via the shared theme pipeline\n const resolvedTheme = useMemo(() => resolveTheme(activeTheme), [activeTheme]);\n\n useEffect(() => {\n applyTheme(resolvedTheme);\n return () => {\n removeAllThemes();\n };\n }, [resolvedTheme]);\n\n // Mirror data-theme and data-theme-mode onto <html> so that Radix portals\n // (rendered at document.body) inherit the correct CSS custom properties.\n useEffect(() => {\n const root = document.documentElement;\n root.setAttribute(\"data-theme\", activeTheme.id);\n return () => {\n root.removeAttribute(\"data-theme\");\n };\n }, [activeTheme.id]);\n\n // Resolve navigation items\n const navItems = useMemo(() => {\n if (navigationProp) return navigationProp;\n const profileNav = appData?.profile?.navigation?.navigation_items;\n if (profileNav && profileNav.length > 0) return profileNav;\n return getDefaultNavigation();\n }, [navigationProp, appData?.profile?.navigation?.navigation_items]);\n\n // Resolve mobile navigation items (fall back to desktop nav)\n const mobileNavItems = useMemo(() => {\n const mobileNav = appData?.profile?.mobile_navigation?.navigation_items;\n if (mobileNav && mobileNav.length > 0) return mobileNav;\n return navItems;\n }, [appData?.profile?.mobile_navigation?.navigation_items, navItems]);\n\n const isCustomer = account?.member_type === \"customer\";\n\n const filteredNavItems = useMemo(\n () => (isCustomer ? filterRepOnlyNavItems(navItems) : navItems),\n [navItems, isCustomer],\n );\n\n const filteredMobileNavItems = useMemo(\n () => (isCustomer ? filterRepOnlyNavItems(mobileNavItems) : mobileNavItems),\n [mobileNavItems, isCustomer],\n );\n\n // Resolve builder screen definitions\n const screens: ScreenDefinition[] | undefined = appData?.screens;\n\n // Collect all nav slugs for prefix matching (sorted longest-first)\n const navSlugs = useMemo(\n () => collectNavSlugs(filteredNavItems),\n [filteredNavItems],\n );\n\n // Combined desktop + mobile nav slugs for gating system-screen rendering;\n // a slug present in either nav counts as \"in nav\".\n const allNavSlugs = useMemo(() => {\n const mobileSlugs = collectNavSlugs(filteredMobileNavItems);\n return Array.from(new Set([...navSlugs, ...mobileSlugs]));\n }, [navSlugs, filteredMobileNavItems]);\n\n // Theme mode state with localStorage persistence\n const [themeMode, setThemeMode] = useState<ThemeMode>(getInitialThemeMode);\n\n const handleThemeModeChange = useCallback((mode: ThemeMode) => {\n setThemeMode(mode);\n if (typeof window !== \"undefined\") {\n localStorage.setItem(THEME_STORAGE_KEY, mode);\n }\n }, []);\n\n // Mirror data-theme-mode onto <html> so that Radix portals\n // (rendered at document.body) inherit the correct CSS custom properties.\n useEffect(() => {\n const root = document.documentElement;\n const mode = themeMode === \"auto\" ? undefined : themeMode;\n if (mode) {\n root.setAttribute(\"data-theme-mode\", mode);\n } else {\n root.removeAttribute(\"data-theme-mode\");\n }\n return () => {\n root.removeAttribute(\"data-theme-mode\");\n };\n }, [themeMode]);\n\n // Set <meta name=\"theme-color\"> so mobile browser chrome matches the theme\n useEffect(() => {\n let meta = document.querySelector<HTMLMetaElement>(\n 'meta[name=\"theme-color\"]',\n );\n if (!meta) {\n meta = document.createElement(\"meta\");\n meta.name = \"theme-color\";\n document.head.appendChild(meta);\n }\n const metaEl = meta;\n\n const theme = resolvedTheme;\n function update(prefersDark: boolean) {\n const mode =\n themeMode === \"auto\" ? (prefersDark ? \"dark\" : \"light\") : themeMode;\n const color =\n mode === \"dark\" ? theme.dark.muted.base : theme.light.muted.base;\n const hex = color.toString();\n metaEl.content = hex;\n document.body.style.backgroundColor = hex;\n }\n\n const mql = window.matchMedia(\"(prefers-color-scheme: dark)\");\n update(mql.matches);\n\n if (themeMode === \"auto\") {\n const handler = (e: MediaQueryListEvent) => update(e.matches);\n mql.addEventListener(\"change\", handler);\n return () => {\n mql.removeEventListener(\"change\", handler);\n metaEl.remove();\n document.body.style.backgroundColor = \"\";\n };\n }\n\n return () => {\n metaEl.remove();\n document.body.style.backgroundColor = \"\";\n };\n }, [resolvedTheme, themeMode]);\n\n // Path-based routing for uncontrolled mode\n const [pathSlug, setPathSlug] = useState<string>(() => {\n if (typeof window === \"undefined\") return \"\";\n return extractSlugFromPathname(\n window.location.pathname,\n normalizedBasePath,\n );\n });\n\n // Sync initial path when navItems load — redirect to first nav slug if at root\n useEffect(() => {\n if (controlledSlug !== undefined) return;\n if (typeof window === \"undefined\") return;\n\n const currentPath = extractSlugFromPathname(\n window.location.pathname,\n normalizedBasePath,\n );\n\n if (!currentPath) {\n const firstSlug = findFirstNavigableSlug(filteredNavItems);\n if (firstSlug) {\n const targetPath =\n normalizedBasePath === \"/\"\n ? `/${firstSlug}`\n : `${normalizedBasePath}/${firstSlug}`;\n // replaceState to avoid polluting back-button history\n history.replaceState(null, \"\", targetPath);\n setPathSlug(firstSlug);\n }\n }\n }, [filteredNavItems, controlledSlug, normalizedBasePath]);\n\n // Listen for popstate (browser back/forward)\n useEffect(() => {\n if (controlledSlug !== undefined) return;\n\n const handlePopState = () => {\n const slug = extractSlugFromPathname(\n window.location.pathname,\n normalizedBasePath,\n );\n setPathSlug(slug);\n };\n\n window.addEventListener(\"popstate\", handlePopState);\n return () => window.removeEventListener(\"popstate\", handlePopState);\n }, [controlledSlug, normalizedBasePath]);\n\n // Logout hook — always called (rules of hooks) but only wired to UI below\n const logout = useLogout({\n redirectUrl: logoutRedirectUrl,\n onLogout,\n });\n\n const activeSlug = controlledSlug ?? pathSlug;\n\n const handleNavigate = useCallback(\n (slug: string) => {\n if (onNavigateProp) {\n onNavigateProp(slug);\n return;\n }\n const targetPath =\n normalizedBasePath === \"/\"\n ? `/${slug}`\n : `${normalizedBasePath}/${slug}`;\n history.pushState(null, \"\", targetPath);\n setPathSlug(slug);\n },\n [onNavigateProp, normalizedBasePath],\n );\n\n // Resolve sidebar footer: explicit prop wins, otherwise render default logout button\n const resolvedSidebarFooter = useMemo(\n () =>\n sidebarFooter !== undefined ? (\n sidebarFooter\n ) : (\n <SdkLogoutButton onLogout={logout} />\n ),\n [sidebarFooter, logout],\n );\n\n // Derive base slug and rest params via prefix matching\n const slugMatch = useMemo(\n () => matchSlugPrefix(activeSlug, navSlugs),\n [activeSlug, navSlugs],\n );\n const baseSlug = slugMatch?.matchedSlug ?? normalizeSlug(activeSlug);\n const restParams = slugMatch?.rest ?? \"\";\n\n // Derive mobile sub-tabs for the current section\n const mobileCurrentSection = findCurrentSection(\n filteredMobileNavItems,\n baseSlug,\n );\n const mobileSecondLevelTabs = mobileCurrentSection?.children ?? [];\n const currentNavItem = findNavItem(filteredNavItems, baseSlug);\n\n // Resolve screen title from nav label or screen definition name\n const screenTitle =\n currentNavItem?.label ||\n screens?.find((s) => s.id === currentNavItem?.screen_id)?.name ||\n undefined;\n\n // Determine content to render. Wrap in an error boundary keyed on the\n // active slug so a screen-level crash never takes down the navigation\n // chrome — and navigating to a different slug auto-recovers the boundary.\n const rawContent =\n typeof children === \"function\"\n ? children({ currentSlug: activeSlug, currentNavItem })\n : (children ?? (\n <ScreenHeaderProvider>\n <div className=\"flex h-full flex-col\">\n <ScreenHeader title={screenTitle} />\n <div className=\"min-h-0 flex-1\">\n <PageRouter\n currentSlug={activeSlug}\n currentNavItem={currentNavItem}\n customPages={customPages}\n screens={screens}\n baseSlug={baseSlug}\n restParams={restParams}\n navSlugs={allNavSlugs}\n />\n </div>\n </div>\n </ScreenHeaderProvider>\n ));\n\n const content = (\n <AppShellErrorBoundary key={activeSlug ?? \"\"}>\n {rawContent}\n </AppShellErrorBoundary>\n );\n\n // Show loading state while app data is being fetched for the first time.\n // This check is placed after all hooks to satisfy React's rules of hooks.\n if (isLoading && !appData) {\n return <AppShellLoading />;\n }\n\n return (\n <RepUserProvider user={repUser}>\n <ThemeModeProvider\n mode={themeMode}\n onModeChange={handleThemeModeChange}\n autoModeEnabled={false}\n >\n <div\n className=\"font-body\"\n data-theme={activeTheme.id}\n data-theme-mode={themeMode === \"auto\" ? undefined : themeMode}\n >\n <AppNavigationProvider\n currentSlug={activeSlug}\n basePath={normalizedBasePath}\n navigate={handleNavigate}\n >\n <AppShellLayout\n sidebarContent={\n <SdkNavigation\n navItems={filteredNavItems}\n currentSlug={activeSlug}\n onNavigate={handleNavigate}\n />\n }\n headerContent={\n <SdkHeader\n mobileTabs={mobileSecondLevelTabs}\n currentSlug={activeSlug}\n onNavigate={handleNavigate}\n onLogout={logout}\n />\n }\n sidebarHeader={\n sidebarHeader !== undefined ? (\n sidebarHeader\n ) : (\n <SdkCompanySwitcher />\n )\n }\n sidebarFooter={resolvedSidebarFooter}\n useBottomNav\n afterContent={\n <SdkBottomNav\n navItems={filteredMobileNavItems}\n currentSlug={activeSlug}\n onNavigate={handleNavigate}\n appDefinitionId={appData?.definition_id ?? 0}\n />\n }\n >\n {content}\n </AppShellLayout>\n </AppNavigationProvider>\n <Toaster />\n </div>\n </ThemeModeProvider>\n </RepUserProvider>\n );\n}\n","/**\n * Read Vite environment variables at runtime.\n *\n * Isolated into its own module so that Jest tests can mock it\n * (import.meta is a syntax-level construct that CJS/Jest cannot parse).\n */\nexport function getViteEnv(key: string): string | undefined {\n const env = import.meta.env as unknown as Record<string, string> | undefined;\n return env?.[key];\n}\n","import type { FluidSDKConfig } from \"../types/config\";\nimport { getViteEnv } from \"./env\";\n\n/**\n * Creates a FluidSDKConfig with sensible defaults.\n *\n * Default behavior:\n * - baseUrl: reads from `VITE_API_URL` env var, falls back to `\"\"` (same-origin relative)\n * - Auth: relies on session cookies sent via `credentials: 'include'`\n *\n * Pass overrides to customize any field:\n * ```ts\n * const config = createDefaultFluidConfig({ baseUrl: \"https://my-api.example.com\" });\n * ```\n */\nexport function createDefaultFluidConfig(\n overrides?: Partial<FluidSDKConfig>,\n): FluidSDKConfig {\n return {\n baseUrl: getViteEnv(\"VITE_API_URL\") ?? \"\",\n ...overrides,\n };\n}\n","import type { ComponentType } from \"react\";\nimport type { WidgetManifest } from \"@fluid-app/portal-core/registries\";\nimport { DEFAULT_SDK_WIDGET_REGISTRY } from \"../core/default-widget-registry\";\n\n/**\n * Merges custom widget components from manifests into the default\n * SDK widget registry. Returns the default registry unchanged when\n * no custom widgets are provided (avoids unnecessary object creation).\n */\nexport function buildWidgetRegistry(\n manifests: WidgetManifest[],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, ComponentType<any>> {\n if (manifests.length === 0) return DEFAULT_SDK_WIDGET_REGISTRY;\n\n const customEntries = Object.fromEntries(\n manifests.map((m) => [m.type, m.component]),\n );\n\n return { ...DEFAULT_SDK_WIDGET_REGISTRY, ...customEntries };\n}\n","import {\n Component,\n StrictMode,\n type ErrorInfo,\n type ReactNode,\n type ComponentType,\n} from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { FluidProvider } from \"../providers/FluidProvider\";\nimport { AppShell, type AppShellProps } from \"../shell/AppShell\";\nimport { createDefaultFluidConfig } from \"../config/defaults\";\nimport type { FluidSDKConfig } from \"../types/config\";\nimport type { WidgetManifest } from \"@fluid-app/portal-core/registries\";\nimport { buildWidgetRegistry } from \"../utils/build-widget-registry\";\n\n/**\n * Last-resort error boundary for crashes above the AppShell (provider\n * setup, theme/auth bootstrap). Renders above FluidThemeProvider, so the\n * theme CSS custom properties (`--color-foreground`, `--color-muted`, etc.)\n * are not yet applied — using inline styles + literal colors avoids\n * referencing theme tokens that would resolve to nothing.\n */\nclass RootBoundary extends Component<\n { children: ReactNode },\n { error: Error | null }\n> {\n override state = { error: null as Error | null };\n\n static getDerivedStateFromError(error: Error): { error: Error } {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo): void {\n console.error(\"[portal] Root crashed:\", error, info);\n }\n\n override render(): ReactNode {\n if (!this.state.error) return this.props.children;\n return (\n <div\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n fontFamily: \"system-ui, sans-serif\",\n }}\n >\n <div style={{ maxWidth: \"32rem\", textAlign: \"center\" }}>\n <h1 style={{ fontSize: \"1.25rem\", fontWeight: 600 }}>\n The app failed to load\n </h1>\n <p style={{ marginTop: \"0.5rem\", color: \"#666\" }}>\n Something went wrong while starting the portal. Please reload the\n page; if the problem persists, contact support.\n </p>\n <button\n type=\"button\"\n onClick={() => {\n window.location.reload();\n }}\n style={{\n marginTop: \"1.5rem\",\n padding: \"0.5rem 1rem\",\n borderRadius: \"0.375rem\",\n border: \"1px solid #ccc\",\n background: \"#fff\",\n cursor: \"pointer\",\n }}\n >\n Reload page\n </button>\n </div>\n </div>\n );\n }\n}\n\n/**\n * Configuration for `createPortal()`.\n *\n * Provides a single-call entry point that sets up the provider hierarchy\n * with sensible defaults. Every field is optional.\n */\nexport interface PortalConfig {\n /** Custom page components keyed by navigation slug */\n customPages?: Record<\n string,\n ComponentType<{ slug?: string; params?: string }>\n >;\n /** Custom widget manifests (type + component + propertySchema) */\n customWidgets?: WidgetManifest[];\n /** API client config overrides (merged with defaults) */\n fluid?: Partial<FluidSDKConfig>;\n /** Root element ID. @default \"root\" */\n rootId?: string;\n /** AppShell props passthrough (basePath, sidebarHeader, etc.) */\n shell?: Omit<AppShellProps, \"customPages\">;\n /** Wrap AppShell with additional providers (inserted inside RequireAuth, below FluidProvider) */\n providers?: ComponentType<{ children: ReactNode }>;\n /** Disable StrictMode. @default false */\n disableStrictMode?: boolean;\n}\n\n/**\n * Bootstrap a Fluid portal with a single function call.\n *\n * Sets up the provider hierarchy (FluidProvider → AppShell) and renders into the DOM.\n * Auth is handled server-side by Rails before the SPA loads.\n *\n * @example Minimal usage\n * ```ts\n * import { createPortal } from \"@fluid-app/portal-sdk\";\n * import \"./index.css\";\n *\n * createPortal();\n * ```\n *\n * @example With custom pages\n * ```ts\n * import { createPortal } from \"@fluid-app/portal-sdk\";\n * import { customPages } from \"./portal.config\";\n * import \"./index.css\";\n *\n * createPortal({ customPages });\n * ```\n *\n * @example With overrides\n * ```ts\n * createPortal({\n * customPages,\n * fluid: { baseUrl: \"https://my-api.example.com\" },\n * shell: { basePath: \"/portal\" },\n * });\n * ```\n */\nexport function createPortal(config: PortalConfig = {}): void {\n const rootElement = document.getElementById(config.rootId ?? \"root\");\n if (!rootElement) {\n throw new Error(\n `Portal root element \"#${config.rootId ?? \"root\"}\" not found`,\n );\n }\n\n const fluidConfig = createDefaultFluidConfig(config.fluid);\n\n // Merge custom widget components with built-in defaults\n const widgetRegistry = config.customWidgets?.length\n ? buildWidgetRegistry(config.customWidgets)\n : undefined;\n\n let app: ReactNode = (\n <AppShell customPages={config.customPages} {...config.shell} />\n );\n\n if (config.providers) {\n const Providers = config.providers;\n app = <Providers>{app}</Providers>;\n }\n\n const tree = (\n <RootBoundary>\n <FluidProvider config={fluidConfig} widgetRegistry={widgetRegistry}>\n {app}\n </FluidProvider>\n </RootBoundary>\n );\n\n createRoot(rootElement).render(\n config.disableStrictMode ? tree : <StrictMode>{tree}</StrictMode>,\n );\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useAppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api-context\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport { transformManifestToRepAppData } from \"../transforms\";\nimport type { RawManifestResponse } from \"../transforms\";\nimport type { Profile } from \"../types/profile\";\nimport { APP_DATA_QUERY_KEY, fetchRawManifest } from \"./use-fluid-app\";\n\n/**\n * Base query key for profile data.\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n *\n * @deprecated Use {@link APP_DATA_QUERY_KEY} with `useFluidApp` instead.\n */\nexport const PROFILE_QUERY_KEY = [\"fluid\", \"profile\"] as const;\n\n/**\n * Hook to fetch the portal profile (themes, navigation, screens).\n *\n * Internally fetches from the fluidos API (same data source as\n * {@link useFluidApp}) and selects the `profile` slice, so no\n * legacy `/api/rep_app/manifest` call is made.\n *\n * @deprecated Use `useFluidApp()` instead — it returns the full\n * `RepAppData` including `profile`, `screens`, and more.\n *\n * @example\n * ```tsx\n * function Navigation() {\n * const { data: profile, isLoading } = useFluidProfile();\n *\n * if (isLoading) return <Spinner />;\n *\n * return (\n * <nav>\n * {profile?.navigation.navigation_items.map(item => (\n * <NavItem key={item.id} item={item} />\n * ))}\n * </nav>\n * );\n * }\n * ```\n */\nexport function useFluidProfile(): UseQueryResult<Profile> {\n const appDefinitionApi = useAppDefinitionApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery<\n RawManifestResponse,\n Error,\n Profile,\n readonly (string | number)[]\n >({\n queryKey: scopeKey(APP_DATA_QUERY_KEY),\n queryFn: () => fetchRawManifest(appDefinitionApi),\n select: (raw) => {\n const appData = transformManifestToRepAppData(raw);\n return appData.profile;\n },\n });\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useAppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api-context\";\nimport type { AppDefinitionResponse } from \"@fluid-app/portal-core/app-definition-types\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\n\n/**\n * Base query key for the app definition endpoint.\n * The runtime key includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const APP_DEFINITION_QUERY_KEY = [\"fluid\", \"app-definition\"] as const;\n\n/**\n * Hook to fetch the active app manifest from the portal-tenant BFF.\n *\n * Returns the manifest metadata (id, name, version)\n * sourced from `GET /api/app/manifest` via the {@link AppDefinitionApi} port.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { data } = useAppDefinition();\n * const definitionId = data?.definition.id ?? 0;\n * }\n * ```\n */\nexport function useAppDefinition(options?: {\n enabled?: boolean;\n}): UseQueryResult<AppDefinitionResponse> {\n const api = useAppDefinitionApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery({\n queryKey: scopeKey(APP_DEFINITION_QUERY_KEY),\n queryFn: () => api.fetchDefinition(),\n ...(options?.enabled !== undefined && { enabled: options.enabled }),\n });\n}\n","import { useThemeContext } from \"../providers/FluidThemeProvider\";\nimport type { ThemeDefinition } from \"../types/theme\";\n\n/**\n * Result of useFluidTheme hook\n */\nexport interface UseFluidThemeResult {\n /** Currently active theme */\n currentTheme: ThemeDefinition | null;\n /** Switch to a different theme */\n setTheme: (theme: ThemeDefinition) => void;\n /** Switch between light and dark mode */\n setThemeMode: (mode: \"light\" | \"dark\") => void;\n /** Current theme mode (convenience accessor) */\n mode: \"light\" | \"dark\" | undefined;\n}\n\n/**\n * Hook to access and control theme settings\n *\n * @example\n * ```tsx\n * function ThemeSwitcher({ themes }: { themes: ThemeDefinition[] }) {\n * const { currentTheme, setTheme, setThemeMode, mode } = useFluidTheme();\n *\n * return (\n * <div>\n * <select\n * value={currentTheme?.name}\n * onChange={(e) => {\n * const theme = themes.find(t => t.name === e.target.value);\n * if (theme) setTheme(theme);\n * }}\n * >\n * {themes.map(theme => (\n * <option key={theme.name} value={theme.name}>\n * {theme.name}\n * </option>\n * ))}\n * </select>\n *\n * <button onClick={() => setThemeMode(mode === \"dark\" ? \"light\" : \"dark\")}>\n * Toggle {mode === \"dark\" ? \"Light\" : \"Dark\"} Mode\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useFluidTheme(): UseFluidThemeResult {\n const { currentTheme, setTheme, setThemeMode, mode } = useThemeContext();\n\n return {\n currentTheme,\n setTheme,\n setThemeMode,\n mode,\n };\n}\n","import { useCallback, useRef } from \"react\";\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { deleteDatabase } from \"@fluid-app/query-persister\";\nimport { usePortalTenantClient } from \"../providers/PortalTenantClientProvider\";\n\nexport interface UseCompanySwitchOptions {\n // Preserved for API compatibility; no longer used internally.\n}\n\n/**\n * Hook that handles company switching for the portal.\n *\n * Calls PUT /api/authentication/company/{id}/switch, clears the TanStack\n * Query cache and IndexedDB persisted cache, then reloads the page so all\n * queries re-fetch with the new company context.\n *\n * The server updates the session cookie automatically via the switch\n * endpoint response; no client-side token storage is needed.\n */\nexport function useCompanySwitch(_options?: UseCompanySwitchOptions): {\n switchCompany: (companyId: number) => void;\n isPending: boolean;\n isError: boolean;\n error: Error | null;\n} {\n const client = usePortalTenantClient();\n const queryClient = useQueryClient();\n const switchingRef = useRef(false);\n\n const { mutate, isPending, isError, error } = useMutation({\n mutationFn: (companyId: number) =>\n client.put(`/api/authentication/company/${companyId}/switch`),\n onSuccess: async () => {\n // Clear in-memory cache and IndexedDB to prevent stale data\n // rehydration after reload.\n queryClient.clear();\n try {\n await deleteDatabase(\"company-switch\");\n } catch {\n // Non-fatal: company-scoped query keys prevent cross-company reads\n // even if the IDB delete fails.\n }\n // Session cookie is updated server-side by the switch endpoint.\n // Reload to re-fetch all queries with the new company context.\n window.location.reload();\n },\n onError: () => {\n switchingRef.current = false;\n },\n });\n\n const switchCompany = useCallback(\n (companyId: number) => {\n if (switchingRef.current) return;\n switchingRef.current = true;\n mutate(companyId);\n },\n [mutate],\n );\n\n return {\n switchCompany: switchCompany,\n isPending: isPending,\n isError: isError,\n error: error,\n };\n}\n","import type { CalendarEvent } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number, hour: number, minute: number = 0): Date {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n d.setHours(hour, minute, 0, 0);\n return d;\n}\n\nexport const DEMO_CALENDAR_EVENTS: readonly CalendarEvent[] = [\n {\n id: 1,\n title: \"Team Standup\",\n description: { body: \"Daily sync with the sales team\" },\n color: \"#4f46e5\",\n start: daysFromNow(0, 9, 0).toISOString(),\n end: daysFromNow(0, 9, 30).toISOString(),\n active: true,\n status: \"confirmed\",\n },\n {\n id: 2,\n title: \"Client Review - Acme Corp\",\n description: { body: \"Quarterly business review with key accounts\" },\n color: \"#059669\",\n start: daysFromNow(2, 14, 0).toISOString(),\n end: daysFromNow(2, 15, 0).toISOString(),\n active: true,\n status: \"confirmed\",\n venue: \"Conference Room B\",\n },\n {\n id: 3,\n title: \"Product Training Webinar\",\n description: { body: \"New product line training for the field\" },\n color: \"#d97706\",\n start: daysFromNow(4, 11, 0).toISOString(),\n end: daysFromNow(4, 12, 30).toISOString(),\n active: true,\n status: \"confirmed\",\n url: \"https://example.com/webinar\",\n },\n {\n id: 4,\n title: \"Regional Conference\",\n description: { body: \"Annual West Coast regional conference\" },\n color: \"#dc2626\",\n start: daysFromNow(10, 8, 0).toISOString(),\n end: daysFromNow(12, 17, 0).toISOString(),\n active: true,\n status: \"confirmed\",\n venue: \"San Diego Convention Center\",\n isAllDay: true,\n },\n];\n","/**\n * Calendar events hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { CalendarEvent, CalendarEventDescription } from \"./hook-types\";\nimport { DEMO_CALENDAR_EVENTS } from \"./demo-data/calendar-events\";\n\n// Re-export types so external consumers are unaffected\nexport type { CalendarEvent, CalendarEventDescription };\n\n/**\n * Result type for useCalendarEvents hook.\n * Uses QueryResult<CalendarEvent[]> with default Error type.\n */\nexport type UseCalendarEventsResult = QueryResult<CalendarEvent[]>;\n\n/**\n * Hook to fetch calendar events.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useCalendarEvents(): UseCalendarEventsResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_CALENDAR_EVENTS],\n isLoading: false,\n isError: false,\n };\n}\n","import type { Todo } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n return d.toISOString();\n}\n\nexport const DEMO_TODOS: readonly Todo[] = [\n {\n id: 1,\n body: \"Follow up with Sarah about Q2 order\",\n dueAt: daysFromNow(1),\n completedAt: null,\n createdAt: daysFromNow(-2),\n contactName: \"Sarah Johnson\",\n },\n {\n id: 2,\n body: \"Send pricing proposal to Acme Corp\",\n dueAt: daysFromNow(7),\n completedAt: null,\n createdAt: daysFromNow(-1),\n contactName: \"Mike Chen\",\n },\n {\n id: 3,\n body: \"Schedule onboarding call with new team member\",\n dueAt: daysFromNow(3),\n completedAt: null,\n createdAt: daysFromNow(0),\n contactName: \"Emily Rodriguez\",\n },\n {\n id: 4,\n body: \"Review and approve Q1 expense report\",\n dueAt: daysFromNow(-1),\n completedAt: daysFromNow(-1),\n createdAt: daysFromNow(-5),\n contactName: null,\n },\n {\n id: 5,\n body: \"Prepare presentation for Friday team meeting\",\n dueAt: daysFromNow(4),\n completedAt: daysFromNow(0),\n createdAt: daysFromNow(-3),\n contactName: null,\n },\n];\n","/**\n * Todos hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { Todo } from \"./hook-types\";\nimport { DEMO_TODOS } from \"./demo-data/todos\";\n\n// Re-export type so external consumers are unaffected\nexport type { Todo };\n\n/**\n * Result type for useTodos hook.\n * Uses QueryResult<Todo[]> with default Error type.\n */\nexport type UseTodosResult = QueryResult<Todo[]>;\n\n/**\n * Hook to fetch todo items.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useTodos(): UseTodosResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_TODOS],\n isLoading: false,\n isError: false,\n };\n}\n","/**\n * Hook type utilities and type predicates.\n *\n * This module provides:\n * - Generic hook result types with default type parameters\n * - Type predicates for query state narrowing\n * - Reusable patterns for type-safe property access in hooks\n *\n * Following generics best practices:\n * - generics-default-type-parameters: Default E to Error for common case\n * - generics-type-predicates: Type predicates for result state narrowing\n * - generics-constrain-type-parameters: K extends keyof T for property access\n */\n\n// =============================================================================\n// Base Result Types with Default Type Parameters\n// =============================================================================\n\n/**\n * Base result type for query hooks with default error type.\n * Uses default type parameter for E (generics-default-type-parameters rule).\n *\n * @typeParam T - The data type\n * @typeParam E - The error type (defaults to Error)\n *\n * @example\n * // Error type defaults to Error\n * type UsersResult = QueryResult<User[]>;\n *\n * // Can override when needed\n * type CustomResult = QueryResult<User[], ApiError>;\n */\nexport interface QueryResult<T, E = Error> {\n readonly data: T;\n readonly isLoading: boolean;\n readonly isError: boolean;\n readonly error?: E | undefined;\n}\n\n/**\n * Result type for hooks that may not have data yet.\n * Extends QueryResult with nullable data.\n *\n * @typeParam T - The data type\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface QueryResultNullable<T, E = Error> {\n readonly data: T | null | undefined;\n readonly isLoading: boolean;\n readonly isError: boolean;\n readonly error?: E | undefined;\n}\n\n/**\n * Result type for list/collection hooks with aggregates.\n *\n * @typeParam T - The item type in the array\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface ListQueryResult<T, E = Error> extends QueryResult<T[], E> {\n readonly totalCount: number;\n}\n\n/**\n * Result type for list hooks with value aggregation (e.g., deals with total value).\n *\n * @typeParam T - The item type in the array\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface ValueListQueryResult<T, E = Error> extends ListQueryResult<\n T,\n E\n> {\n readonly totalValue: number;\n}\n\n// =============================================================================\n// Type Predicates for Query State Narrowing\n// =============================================================================\n\n/**\n * Type predicate to check if a query result has successfully loaded data.\n * Narrows the data type from T | null | undefined to T.\n *\n * @example\n * const result = useContact(id);\n * if (hasData(result)) {\n * // TypeScript knows result.data is Contact, not Contact | null\n * console.log(result.data.name);\n * }\n */\nexport function hasData<T, E = Error>(\n result: QueryResultNullable<T, E>,\n): result is QueryResultNullable<T, E> & { readonly data: T } {\n return result.data != null && !result.isLoading && !result.isError;\n}\n\n/**\n * Type predicate to check if a query result is in loading state.\n * Useful for conditional rendering.\n *\n * @example\n * if (isLoading(result)) {\n * return <Spinner />;\n * }\n */\nexport function isLoading<T, E = Error>(\n result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): boolean {\n return result.isLoading;\n}\n\n/**\n * Type predicate to check if a query result has an error.\n * Narrows to include the error property.\n *\n * @example\n * if (isErrorResult(result)) {\n * console.error(result.error); // error is E, not undefined\n * }\n */\nexport function isErrorResult<T, E = Error>(\n result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): result is (QueryResult<T, E> | QueryResultNullable<T, E>) & {\n readonly isError: true;\n readonly error: E;\n} {\n return result.isError && result.error !== undefined;\n}\n\n/**\n * Type predicate to check if a query result is in idle state (not loading, no error, has data).\n *\n * @example\n * if (isIdle(result)) {\n * // Safe to access and render data\n * }\n */\nexport function isIdle<T, E = Error>(\n result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): boolean {\n return !result.isLoading && !result.isError;\n}\n\n// =============================================================================\n// Generic Property Selector Pattern\n// =============================================================================\n\n/**\n * Type-safe property selector for hook results.\n * Uses K extends keyof T constraint (generics-function-constraints rule).\n *\n * @typeParam T - The data object type\n * @typeParam K - Key of T (constrained to actual keys)\n *\n * @example\n * const users = [{ name: \"Alice\", age: 30 }];\n * const names = selectProperty(users, \"name\"); // string[]\n * const ages = selectProperty(users, \"age\"); // number[]\n * selectProperty(users, \"invalid\"); // Error: \"invalid\" not in \"name\" | \"age\"\n */\nexport function selectProperty<T, K extends keyof T>(\n items: readonly T[],\n key: K,\n): T[K][] {\n return items.map((item) => item[key]);\n}\n\n/**\n * Type-safe property getter for a single item.\n * Returns undefined if item is null/undefined.\n *\n * @typeParam T - The data object type\n * @typeParam K - Key of T (constrained to actual keys)\n */\nexport function getProperty<T, K extends keyof T>(\n item: T | null | undefined,\n key: K,\n): T[K] | undefined {\n return item?.[key];\n}\n\n// =============================================================================\n// Hook Factory Types\n// =============================================================================\n\n/**\n * Generic type for hooks that fetch a single resource by ID.\n * Useful for creating consistent API across different resource types.\n *\n * @typeParam T - The resource type\n * @typeParam E - The error type (defaults to Error)\n */\nexport type UseSingleResourceHook<T, E = Error> = (\n id: string,\n) => QueryResultNullable<T, E>;\n\n/**\n * Generic type for hooks that fetch a list of resources with optional params.\n * Uses generics-default-type-parameters for the params type.\n *\n * @typeParam T - The item type\n * @typeParam P - The params type (defaults to empty object)\n * @typeParam E - The error type (defaults to Error)\n */\nexport type UseListResourceHook<\n T,\n P extends Record<string, unknown> = Record<string, never>,\n E = Error,\n> = (params?: P) => ListQueryResult<T, E>;\n\n/**\n * Transforms a nullable result to a non-nullable one if data exists.\n * Useful when you've already checked hasData().\n */\nexport type WithData<R extends QueryResultNullable<unknown>> =\n R extends QueryResultNullable<infer T, infer E>\n ? QueryResultNullable<T, E> & { readonly data: T }\n : never;\n\n// =============================================================================\n// Domain Types\n// Shared between hook files and demo-data files to avoid circular imports.\n// =============================================================================\n\n/**\n * Activity slug constants as a const object.\n * Derive the ActivitySlug type from this single source of truth.\n */\nexport const ACTIVITY_SLUGS = {\n abandonedCart: \"abandoned_cart\",\n announcements: \"announcements\",\n cartItemsAdded: \"cart_items_added\",\n commentReply: \"comment_reply\",\n directMessage: \"direct_message\",\n fantasyPoint: \"fantasy_point\",\n newLead: \"new_lead\",\n orderPlaced: \"order_placed\",\n pageViews: \"page_views\",\n pageViewsContact: \"page_views_contact\",\n tasks: \"tasks\",\n upcomingEvent: \"upcoming_event\",\n video: \"video\",\n videoComplete: \"video_complete\",\n videoCompleteContact: \"video_complete_contact\",\n videoContact: \"video_contact\",\n messageReceived: \"message_received\",\n messageSent: \"message_sent\",\n newCartItemsAdded: \"new_cart_items_added\",\n smartLinkClicked: \"smart_link_clicked\",\n reviewLeft: \"review_left\",\n} as const;\n\n/** Activity slug union type derived from ACTIVITY_SLUGS constant. */\nexport type ActivitySlug = (typeof ACTIVITY_SLUGS)[keyof typeof ACTIVITY_SLUGS];\n\n/** Type predicate to check if a string is a valid ActivitySlug. */\nexport function isActivitySlug(value: string): value is ActivitySlug {\n return Object.values(ACTIVITY_SLUGS).includes(value as ActivitySlug);\n}\n\n/** Transformed activity for display. */\nexport interface Activity {\n readonly id: number;\n readonly userName: string;\n readonly avatarUrl: string | null;\n readonly activityType: string;\n readonly targetName: string;\n readonly timestamp: string;\n readonly slug: ActivitySlug;\n}\n\n/** Description/rich text metadata for a calendar event. */\nexport interface CalendarEventDescription {\n readonly id?: number | null;\n readonly name?: string | null;\n readonly body?: string | null;\n readonly record_type?: string | null;\n readonly record_id?: number | null;\n readonly created_at?: string | null;\n readonly updated_at?: string | null;\n readonly locale?: string | null;\n}\n\n/** Calendar event data from the API. */\nexport interface CalendarEvent {\n readonly id: number;\n readonly title: string;\n readonly description?: CalendarEventDescription | null;\n readonly color?: string | null;\n readonly url?: string | null;\n readonly start: string;\n readonly end: string;\n readonly active?: boolean | null;\n readonly time_zone?: string | null;\n readonly status?: string | null;\n readonly image_url?: string | null;\n readonly images?: readonly unknown[] | null;\n readonly venue?: string | null;\n readonly countries?: readonly string[] | null;\n readonly hasTomorrow?: boolean | null;\n readonly hasYesterday?: boolean | null;\n readonly isAllDay?: boolean;\n}\n\n/** Catch up suggestion data from the API. */\nexport interface CatchUp {\n readonly id: number;\n readonly suggestion_title: string;\n}\n\n/** MySite data returned by the hook. */\nexport interface MySiteData {\n readonly url: string | null;\n readonly views: number;\n readonly leads: number;\n readonly userName: string;\n}\n\n/** Transformed todo for display. */\nexport interface Todo {\n readonly id: number;\n readonly body: string;\n readonly dueAt: string | null;\n readonly completedAt: string | null;\n readonly createdAt: string;\n readonly contactName: string | null;\n}\n","import type { Activity } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction hoursAgo(hours: number): string {\n const d = new Date(now);\n d.setHours(d.getHours() - hours);\n return d.toISOString();\n}\nexport const DEMO_ACTIVITIES: readonly Activity[] = [\n {\n id: 1,\n userName: \"Sarah Johnson\",\n avatarUrl: null,\n activityType: \"New Order\",\n targetName: \"Wellness Starter Kit\",\n timestamp: hoursAgo(1),\n slug: \"order_placed\",\n },\n {\n id: 2,\n userName: \"Mike Chen\",\n avatarUrl: null,\n activityType: \"New Lead\",\n targetName: \"Referral from LinkedIn campaign\",\n timestamp: hoursAgo(3),\n slug: \"new_lead\",\n },\n {\n id: 3,\n userName: \"Emily Rodriguez\",\n avatarUrl: null,\n activityType: \"Page View\",\n targetName: \"Product Catalog\",\n timestamp: hoursAgo(5),\n slug: \"page_views\",\n },\n {\n id: 4,\n userName: \"David Park\",\n avatarUrl: null,\n activityType: \"Cart Items Added\",\n targetName: \"Premium Bundle (3 items)\",\n timestamp: hoursAgo(8),\n slug: \"cart_items_added\",\n },\n {\n id: 5,\n userName: \"Lisa Thompson\",\n avatarUrl: null,\n activityType: \"Video Watched\",\n targetName: \"Getting Started Tutorial\",\n timestamp: hoursAgo(12),\n slug: \"video_complete\",\n },\n {\n id: 6,\n userName: \"James Wilson\",\n avatarUrl: null,\n activityType: \"Message Received\",\n targetName: \"Question about shipping\",\n timestamp: hoursAgo(18),\n slug: \"message_received\",\n },\n {\n id: 7,\n userName: \"Rachel Kim\",\n avatarUrl: null,\n activityType: \"Smart Link Clicked\",\n targetName: \"Holiday Promo Link\",\n timestamp: hoursAgo(24),\n slug: \"smart_link_clicked\",\n },\n {\n id: 8,\n userName: \"Tom Martinez\",\n avatarUrl: null,\n activityType: \"Review Left\",\n targetName: \"Essential Oil Set - 5 stars\",\n timestamp: hoursAgo(36),\n slug: \"review_left\",\n },\n];\n","/**\n * Activities hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport {\n ACTIVITY_SLUGS,\n isActivitySlug,\n type Activity,\n type ActivitySlug,\n} from \"./hook-types\";\nimport { DEMO_ACTIVITIES } from \"./demo-data/activities\";\n\n// Re-export types and constants so external consumers are unaffected\nexport { ACTIVITY_SLUGS, isActivitySlug };\nexport type { Activity, ActivitySlug };\n\n/**\n * Result type for useActivities hook.\n * Uses QueryResult generic with Activity[] and default Error type.\n */\nexport type UseActivitiesResult = QueryResult<Activity[]>;\n\n/**\n * Hook to fetch recent activities.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useActivities(): UseActivitiesResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_ACTIVITIES],\n isLoading: false,\n isError: false,\n };\n}\n","import type { CatchUp } from \"../hook-types\";\n\nexport const DEMO_CATCHUPS: readonly CatchUp[] = [\n {\n id: 1,\n suggestion_title: \"Sarah Johnson hasn't ordered in 30 days\",\n },\n {\n id: 2,\n suggestion_title: \"Mike Chen's subscription is expiring soon\",\n },\n {\n id: 3,\n suggestion_title: \"Emily Rodriguez left a cart with 3 items\",\n },\n];\n","/**\n * Catch ups hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { CatchUp } from \"./hook-types\";\nimport { DEMO_CATCHUPS } from \"./demo-data/catchups\";\n\n// Re-export type so external consumers are unaffected\nexport type { CatchUp };\n\n/**\n * Result type for useCatchUps hook.\n * Uses QueryResult<CatchUp[]> with default Error type.\n */\nexport type UseCatchUpsResult = QueryResult<CatchUp[]>;\n\n/**\n * Hook to fetch catch up items.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useCatchUps(): UseCatchUpsResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_CATCHUPS],\n isLoading: false,\n isError: false,\n };\n}\n","import type { MySiteData } from \"../hook-types\";\n\nexport const DEMO_MYSITE: MySiteData = {\n url: \"https://my-portal.example.com\",\n views: 1243,\n leads: 37,\n userName: \"Demo User\",\n};\n","/**\n * MySite hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResultNullable } from \"./hook-types\";\nimport type { MySiteData } from \"./hook-types\";\nimport { DEMO_MYSITE } from \"./demo-data/mysite\";\n\n// Re-export type so external consumers are unaffected\nexport type { MySiteData };\n\n/**\n * Result type for useMySite hook.\n * Uses QueryResultNullable since MySite data may not be available.\n */\nexport type UseMySiteResult = QueryResultNullable<MySiteData>;\n\n/**\n * Hook to fetch MySite data.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useMySite(): UseMySiteResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: DEMO_MYSITE,\n isLoading: false,\n isError: false,\n };\n}\n","import type { Conversation, Message } from \"../../types/screen-types\";\n\nconst now = new Date();\n\nfunction hoursAgo(hours: number): string {\n const d = new Date(now);\n d.setHours(d.getHours() - hours);\n return d.toISOString();\n}\n\nfunction daysAgo(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() - days);\n return d.toISOString();\n}\n\nexport const DEMO_CONVERSATIONS: readonly Conversation[] = [\n {\n id: \"conv-1\",\n title: \"Sarah Johnson\",\n participants: [\n { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n {\n id: \"user-2\",\n name: \"Sarah Johnson\",\n email: \"sarah.johnson@example.com\",\n isOnline: true,\n },\n ],\n lastMessage: {\n id: \"msg-1-3\",\n conversationId: \"conv-1\",\n senderId: \"user-2\",\n senderName: \"Sarah Johnson\",\n type: \"text\",\n content: \"Sounds great! I'll place the order by end of day.\",\n timestamp: hoursAgo(1),\n isRead: false,\n },\n unreadCount: 1,\n status: \"active\",\n createdAt: daysAgo(30),\n updatedAt: hoursAgo(1),\n },\n {\n id: \"conv-2\",\n title: \"Mike Chen\",\n participants: [\n { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n {\n id: \"user-3\",\n name: \"Mike Chen\",\n email: \"mike.chen@acmecorp.com\",\n isOnline: false,\n },\n ],\n lastMessage: {\n id: \"msg-2-2\",\n conversationId: \"conv-2\",\n senderId: \"user-1\",\n senderName: \"You\",\n type: \"text\",\n content:\n \"I've attached the updated pricing sheet. Let me know if you have any questions!\",\n timestamp: hoursAgo(5),\n isRead: true,\n },\n unreadCount: 0,\n status: \"active\",\n createdAt: daysAgo(14),\n updatedAt: hoursAgo(5),\n },\n {\n id: \"conv-3\",\n title: \"Team Updates\",\n participants: [\n { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n {\n id: \"user-4\",\n name: \"Emily Rodriguez\",\n email: \"emily.r@healthfirst.io\",\n },\n { id: \"user-5\", name: \"David Park\", email: \"david.park@email.com\" },\n ],\n lastMessage: {\n id: \"msg-3-4\",\n conversationId: \"conv-3\",\n senderId: \"user-4\",\n senderName: \"Emily Rodriguez\",\n type: \"text\",\n content:\n \"The new product samples arrived today. Will distribute to the team tomorrow.\",\n timestamp: daysAgo(1),\n isRead: true,\n },\n unreadCount: 0,\n status: \"active\",\n createdAt: daysAgo(60),\n updatedAt: daysAgo(1),\n },\n];\n\nexport const DEMO_MESSAGES: readonly Message[] = [\n {\n id: \"msg-1-1\",\n conversationId: \"conv-1\",\n senderId: \"user-1\",\n senderName: \"You\",\n type: \"text\",\n content:\n \"Hi Sarah! I wanted to follow up on the Wellness Starter Kit. We have a special promotion running this month.\",\n timestamp: hoursAgo(3),\n isRead: true,\n },\n {\n id: \"msg-1-2\",\n conversationId: \"conv-1\",\n senderId: \"user-2\",\n senderName: \"Sarah Johnson\",\n type: \"text\",\n content:\n \"That's perfect timing! I was just thinking about reordering. What's the promo?\",\n timestamp: hoursAgo(2),\n isRead: true,\n },\n {\n id: \"msg-1-3\",\n conversationId: \"conv-1\",\n senderId: \"user-2\",\n senderName: \"Sarah Johnson\",\n type: \"text\",\n content: \"Sounds great! I'll place the order by end of day.\",\n timestamp: hoursAgo(1),\n isRead: false,\n },\n];\n","/**\n * Conversations hooks - stub implementations for SDK\n * In production, implement these hooks to fetch from your API\n */\n\nimport type { Conversation, Message } from \"../types/screen-types\";\nimport type { QueryResult } from \"./hook-types\";\nimport { DEMO_CONVERSATIONS, DEMO_MESSAGES } from \"./demo-data/conversations\";\n\n// =============================================================================\n// useConversations Hook\n// =============================================================================\n\n/**\n * Result type for useConversations hook.\n * Uses QueryResult<Conversation[]> with default Error type.\n */\nexport type UseConversationsResult = QueryResult<Conversation[]>;\n\n/**\n * Hook to fetch all conversations.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @returns UseConversationsResult with empty data array\n *\n * @example\n * ```tsx\n * const { data: conversations, isLoading, isError } = useConversations();\n *\n * if (isLoading) return <Loading />;\n * if (isError) return <Error />;\n *\n * return conversations.map(conv => <ConversationItem key={conv.id} {...conv} />);\n * ```\n */\nexport function useConversations(): UseConversationsResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_CONVERSATIONS],\n isLoading: false,\n isError: false,\n };\n}\n\n// =============================================================================\n// useConversationMessages Hook\n// =============================================================================\n\n/**\n * Result type for useConversationMessages hook.\n * Uses QueryResult<Message[]> with default Error type.\n */\nexport type UseConversationMessagesResult = QueryResult<Message[]>;\n\n/**\n * Hook to fetch messages for a specific conversation.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param conversationId - The ID of the conversation to fetch messages for\n * @returns UseConversationMessagesResult with empty data array\n *\n * @example\n * ```tsx\n * const { data: messages, isLoading, isError } = useConversationMessages(conversationId);\n *\n * if (isLoading) return <Loading />;\n * if (isError) return <Error />;\n *\n * return messages.map(msg => <MessageBubble key={msg.id} {...msg} />);\n * ```\n */\nexport function useConversationMessages(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _conversationId: string,\n): UseConversationMessagesResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching using _conversationId\n return {\n data: [...DEMO_MESSAGES],\n isLoading: false,\n isError: false,\n };\n}\n","/**\n * Screen Types - Type definitions for core feature screens\n *\n * All status and type unions are derived from constants for single source of truth.\n * Use the constants (e.g., CONVERSATION_STATUSES.active) for type-safe comparisons.\n */\n\n// =============================================================================\n// Messaging Types\n// =============================================================================\n\n/**\n * Conversation status constant - single source of truth.\n */\nexport const CONVERSATION_STATUSES = {\n active: \"active\",\n archived: \"archived\",\n muted: \"muted\",\n} as const;\n\n/**\n * Union type derived from CONVERSATION_STATUSES constant.\n */\nexport type ConversationStatus =\n (typeof CONVERSATION_STATUSES)[keyof typeof CONVERSATION_STATUSES];\n\n/**\n * Message type constant - single source of truth.\n */\nexport const MESSAGE_TYPES = {\n text: \"text\",\n image: \"image\",\n file: \"file\",\n system: \"system\",\n} as const;\n\n/**\n * Union type derived from MESSAGE_TYPES constant.\n */\nexport type MessageType = (typeof MESSAGE_TYPES)[keyof typeof MESSAGE_TYPES];\n\nexport interface Participant {\n readonly id: string;\n readonly name: string;\n readonly email: string;\n readonly avatarUrl?: string;\n readonly isOnline?: boolean;\n}\n\n/**\n * Message attachment type - extracted for reusability and clarity.\n */\nexport interface MessageAttachment {\n readonly id: string;\n readonly name: string;\n readonly url: string;\n readonly type: string;\n readonly size?: number;\n}\n\nexport interface Message {\n readonly id: string;\n readonly conversationId: string;\n readonly senderId: string;\n readonly senderName: string;\n readonly senderAvatarUrl?: string;\n readonly type: MessageType;\n readonly content: string;\n readonly timestamp: string;\n readonly isRead: boolean;\n readonly attachments?: readonly MessageAttachment[];\n}\n\nexport interface Conversation {\n readonly id: string;\n readonly title: string;\n readonly participants: readonly Participant[];\n readonly lastMessage?: Message;\n readonly unreadCount: number;\n readonly status: ConversationStatus;\n readonly createdAt: string;\n readonly updatedAt: string;\n}\n\n// =============================================================================\n// Contacts Types\n// =============================================================================\n\n/**\n * Contact status constant - single source of truth.\n */\nexport const CONTACT_STATUSES = {\n active: \"active\",\n inactive: \"inactive\",\n lead: \"lead\",\n prospect: \"prospect\",\n} as const;\n\n/**\n * Union type derived from CONTACT_STATUSES constant.\n */\nexport type ContactStatus =\n (typeof CONTACT_STATUSES)[keyof typeof CONTACT_STATUSES];\n\n/**\n * Contact type constant - single source of truth.\n */\nexport const CONTACT_TYPES = {\n individual: \"individual\",\n company: \"company\",\n} as const;\n\n/**\n * Union type derived from CONTACT_TYPES constant.\n */\nexport type ContactType = (typeof CONTACT_TYPES)[keyof typeof CONTACT_TYPES];\n\nexport interface ContactAddress {\n readonly street?: string;\n readonly city?: string;\n readonly state?: string;\n readonly postalCode?: string;\n readonly country?: string;\n}\n\nexport interface Contact {\n readonly id: string;\n readonly firstName: string;\n readonly lastName: string;\n readonly email: string;\n readonly phone?: string;\n readonly company?: string;\n readonly jobTitle?: string;\n readonly avatarUrl?: string;\n readonly status: ContactStatus;\n readonly type: ContactType;\n readonly address?: ContactAddress;\n readonly tags?: readonly string[];\n readonly notes?: string;\n readonly createdAt: string;\n readonly updatedAt: string;\n}\n","import type { Contact } from \"../../types/screen-types\";\n\nconst now = new Date();\n\nfunction daysAgo(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() - days);\n return d.toISOString();\n}\n\nexport const DEMO_CONTACTS: readonly Contact[] = [\n {\n id: \"contact-1\",\n firstName: \"Sarah\",\n lastName: \"Johnson\",\n email: \"sarah.johnson@example.com\",\n phone: \"+1 (555) 123-4567\",\n company: \"Wellness Works Inc.\",\n jobTitle: \"Purchasing Manager\",\n status: \"active\",\n type: \"individual\",\n tags: [\"VIP\", \"Repeat Buyer\"],\n createdAt: daysAgo(90),\n updatedAt: daysAgo(2),\n },\n {\n id: \"contact-2\",\n firstName: \"Mike\",\n lastName: \"Chen\",\n email: \"mike.chen@acmecorp.com\",\n phone: \"+1 (555) 234-5678\",\n company: \"Acme Corp\",\n jobTitle: \"Director of Operations\",\n status: \"active\",\n type: \"individual\",\n tags: [\"Enterprise\"],\n createdAt: daysAgo(60),\n updatedAt: daysAgo(5),\n },\n {\n id: \"contact-3\",\n firstName: \"Emily\",\n lastName: \"Rodriguez\",\n email: \"emily.r@healthfirst.io\",\n company: \"HealthFirst\",\n status: \"lead\",\n type: \"individual\",\n notes: \"Interested in bulk pricing for team orders\",\n createdAt: daysAgo(7),\n updatedAt: daysAgo(1),\n },\n {\n id: \"contact-4\",\n firstName: \"David\",\n lastName: \"Park\",\n email: \"david.park@email.com\",\n phone: \"+1 (555) 345-6789\",\n status: \"prospect\",\n type: \"individual\",\n tags: [\"Referral\"],\n createdAt: daysAgo(14),\n updatedAt: daysAgo(10),\n },\n {\n id: \"contact-5\",\n firstName: \"Lisa\",\n lastName: \"Thompson\",\n email: \"lisa.t@globalfit.com\",\n company: \"Global Fitness\",\n jobTitle: \"CEO\",\n status: \"active\",\n type: \"individual\",\n address: {\n city: \"Los Angeles\",\n state: \"CA\",\n country: \"US\",\n },\n createdAt: daysAgo(120),\n updatedAt: daysAgo(15),\n },\n {\n id: \"contact-6\",\n firstName: \"James\",\n lastName: \"Wilson\",\n email: \"jwilson@retired.net\",\n status: \"inactive\",\n type: \"individual\",\n notes: \"Moved out of area, no longer purchasing\",\n createdAt: daysAgo(200),\n updatedAt: daysAgo(45),\n },\n];\n\nexport const DEMO_CONTACT: Contact = DEMO_CONTACTS[0]!;\n","/**\n * Contacts hooks - stub implementation for SDK\n * In production, implement these hooks to fetch from your API\n */\n\nimport type { Contact, ContactStatus } from \"../types/screen-types\";\nimport { CONTACT_STATUSES } from \"../types/screen-types\";\nimport type { ListQueryResult, QueryResultNullable } from \"./hook-types\";\nimport { DEMO_CONTACTS, DEMO_CONTACT } from \"./demo-data/contacts\";\n\n/**\n * Type predicate to check if a status string is a valid ContactStatus.\n * Enables runtime validation with type narrowing.\n */\nexport function isContactStatus(value: string): value is ContactStatus {\n return Object.values(CONTACT_STATUSES).includes(value as ContactStatus);\n}\n\n/**\n * Parameters for filtering and paginating contacts.\n * Uses readonly properties and proper ContactStatus type for status.\n */\nexport interface UseContactsParams {\n /** Search query to filter contacts by name, email, or company */\n readonly search?: string;\n /** Filter contacts by status - uses ContactStatus union type for type safety */\n readonly status?: ContactStatus;\n /** Maximum number of contacts to return */\n readonly limit?: number;\n}\n\n/**\n * Result type for the useContacts hook.\n * Uses ListQueryResult<Contact> with totalCount and default Error type.\n */\nexport type UseContactsResult = ListQueryResult<Contact>;\n\n/**\n * Result type for the useContact hook.\n * Uses QueryResultNullable since a specific contact may not exist.\n */\nexport type UseContactResult = QueryResultNullable<Contact>;\n\n/**\n * Hook to fetch a list of contacts with optional filtering and pagination.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param params - Optional parameters for filtering and pagination\n * @returns Object containing contacts data, loading state, error state, and total count\n *\n * @example\n * ```tsx\n * const { data: contacts, isLoading, totalCount } = useContacts({\n * search: 'john',\n * status: 'active',\n * limit: 20\n * });\n * ```\n */\nexport function useContacts(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _params?: UseContactsParams,\n): UseContactsResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_CONTACTS],\n isLoading: false,\n isError: false,\n totalCount: DEMO_CONTACTS.length,\n };\n}\n\n/**\n * Hook to fetch a single contact by ID.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param contactId - The unique identifier of the contact to fetch\n * @returns Object containing contact data, loading state, and error state\n *\n * @example\n * ```tsx\n * const { data: contact, isLoading, isError } = useContact('contact-123');\n * ```\n */\nexport function useContact(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _contactId: string,\n): UseContactResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching using _contactId\n return {\n data: DEMO_CONTACT,\n isLoading: false,\n isError: false,\n };\n}\n","/**\n * Auth Types\n *\n * These types define the JWT payload structure and authentication\n * configuration options.\n */\n\n// ============================================================================\n// User Types - Derive from constant for single source of truth\n// ============================================================================\n\n/**\n * User type constant - single source of truth for user role values.\n * Use USER_TYPES.admin instead of \"admin\" for type-safe comparisons.\n */\nexport const USER_TYPES = {\n admin: \"admin\",\n rep: \"rep\",\n root_admin: \"root_admin\",\n customer: \"customer\",\n} as const;\n\n/**\n * Union type of all user types, derived from USER_TYPES constant.\n * @see deriving-typeof-for-object-keys pattern\n */\nexport type UserType = (typeof USER_TYPES)[keyof typeof USER_TYPES];\n\n/**\n * Runtime validation for user types.\n * @param value - The value to check\n * @returns true if value is a valid UserType\n */\nexport function isUserType(value: string): value is UserType {\n return Object.values(USER_TYPES).includes(value as UserType);\n}\n\n/**\n * JWT payload structure from Fluid Commerce authentication.\n * Contains user identity and role information.\n */\nexport interface JWTPayload {\n /** User ID */\n id?: number | undefined;\n /** User email address */\n email?: string | undefined;\n /** Full name of the user */\n full_name?: string | undefined;\n /** User role type */\n user_type: UserType;\n /** Original user type (for impersonation scenarios) */\n og_user_type?: UserType | undefined;\n /** Company ID the user belongs to */\n company_id?: number | undefined;\n /** Token expiration timestamp (Unix seconds) */\n exp?: number | undefined;\n /** Authentication type (e.g., \"standard\", \"impersonation\") */\n auth_type?: string | undefined;\n}\n\n/**\n * Configuration options for FluidAuthProvider.\n * All options have sensible defaults.\n */\nexport interface FluidAuthConfig {\n /**\n * URL parameter name for the auth token.\n * @default \"fluidUserToken\"\n */\n tokenKey?: string;\n\n /**\n * Cookie name for storing the auth token.\n * @default \"auth_token\"\n */\n cookieKey?: string;\n\n /**\n * Cookie max age in seconds.\n * @default 777600 (9 days)\n */\n cookieMaxAge?: number;\n\n /**\n * Grace period in milliseconds to account for clock skew\n * when checking token expiration.\n * @default 30000 (30 seconds)\n */\n gracePeriodMs?: number;\n\n /**\n * Callback invoked when authentication fails (no valid token).\n * When omitted, the SDK redirects to `authUrl` with the current URL\n * as a redirect parameter so users can log in and return.\n */\n onAuthFailure?: () => void;\n\n /**\n * Base URL for the authentication page.\n * Used by the default auth failure redirect when `onAuthFailure` is not provided.\n * Ignored when a custom `onAuthFailure` callback is set.\n * @default \"https://auth.fluid.app\"\n */\n authUrl?: string;\n\n /**\n * Enable dev-mode auth bypass.\n * When true AND running in Vite dev mode (import.meta.env.DEV),\n * auth will use a synthetic mock user instead of requiring a real JWT.\n * The mock user allows UI rendering but API calls will fail (token is null).\n * @default false\n */\n devBypass?: boolean;\n\n /**\n * JWKS (JSON Web Key Set) URL for signature verification.\n * When provided, JWT signatures will be verified against keys\n * from this endpoint before accepting the token.\n *\n * This provides defense-in-depth client-side verification.\n * Without this, tokens are only decoded (not verified) client-side,\n * and real verification happens server-side on API calls.\n *\n * @example \"https://api.fluid.app/.well-known/jwks.json\"\n */\n jwksUrl?: string;\n}\n\n/**\n * Value provided by the FluidAuthContext.\n * All properties are readonly since context values should not be mutated by consumers.\n */\nexport interface FluidAuthContextValue {\n /** Whether the user is authenticated with a valid token */\n readonly isAuthenticated: boolean;\n /** Whether authentication is still being initialized */\n readonly isLoading: boolean;\n /** Decoded JWT payload if authenticated, null otherwise */\n readonly user: JWTPayload | null;\n /** Raw JWT token string if authenticated, null otherwise */\n readonly token: string | null;\n /** Clear authentication state and stored tokens */\n readonly clearAuth: () => void;\n /** Authentication error if any occurred during initialization */\n readonly error: Error | null;\n}\n\n/**\n * Result of token validation.\n * Uses a discriminated union for type-safe handling of valid/invalid states.\n */\nexport type TokenValidationResult =\n | {\n /** Token is valid */\n isValid: true;\n /** Decoded JWT payload */\n payload: JWTPayload;\n /** No error when valid */\n error?: undefined;\n }\n | {\n /** Token is invalid */\n isValid: false;\n /** Decoded JWT payload if parseable but expired */\n payload?: JWTPayload;\n /** Error message explaining why validation failed */\n error: string;\n };\n","import { z } from \"zod\";\nimport type { FetchClientInstance } from \"@fluid-app/api-client-core\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface Company {\n id: number;\n name: string;\n logo_url?: string | null;\n icon_url?: string | null;\n}\n\nexport interface SwitchCompanyResponseCompany {\n id: number;\n name: string;\n fluid_shop: string;\n logo_url?: string | null;\n jwt: string;\n}\n\nexport interface SwitchCompanyResponseMeta {\n request_id: string;\n timestamp: string;\n}\n\nexport interface SwitchCompanyResponse {\n company: SwitchCompanyResponseCompany;\n meta: SwitchCompanyResponseMeta;\n}\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\nexport const companySchema: z.ZodType<Company> = z.object({\n id: z.number(),\n name: z.string(),\n logo_url: z.string().optional().nullable(),\n icon_url: z.string().nullable().optional(),\n});\n\nexport const switchCompanyResponseCompanySchema: z.ZodType<SwitchCompanyResponseCompany> =\n z.object({\n id: z.number().int().positive(),\n name: z.string(),\n fluid_shop: z.string(),\n logo_url: z.string().url().nullable().optional(),\n jwt: z.string(),\n });\n\nexport const switchCompanyResponseMetaSchema: z.ZodType<SwitchCompanyResponseMeta> =\n z.object({\n request_id: z.string(),\n timestamp: z.string(),\n });\n\nexport const switchCompanyResponseSchema: z.ZodType<SwitchCompanyResponse> =\n z.object({\n company: switchCompanyResponseCompanySchema,\n meta: switchCompanyResponseMetaSchema,\n });\n\n// ============================================================================\n// API function\n// ============================================================================\n\nexport function switchCompany(\n client: FetchClientInstance,\n companyId: number,\n): Promise<SwitchCompanyResponse> {\n return client\n .put<unknown>(`/authentication/company/${companyId}/switch`)\n .then((data) => switchCompanyResponseSchema.parse(data));\n}\n","// Screen Components\nexport { ProfileScreen, profileScreenPropertySchema } from \"./ProfileScreen\";\nexport {\n MessagingScreen,\n messagingScreenPropertySchema,\n} from \"./MessagingScreen\";\nexport { ContactsScreen, contactsScreenPropertySchema } from \"./ContactsScreen\";\nexport { OrdersScreen, ordersScreenPropertySchema } from \"./OrdersScreen\";\nexport {\n SubscriptionsScreen,\n subscriptionsScreenPropertySchema,\n} from \"./SubscriptionsScreen\";\nexport {\n CustomersScreen,\n customersScreenPropertySchema,\n} from \"./CustomersScreen\";\nexport { MySiteScreen, mySiteScreenPropertySchema } from \"./MySiteScreen\";\nexport {\n ShareablesScreen,\n shareablesScreenPropertySchema,\n} from \"./ShareablesScreen\";\nexport { ShopScreen, shopScreenPropertySchema } from \"./ShopScreen\";\nexport { UpgradeScreen, upgradeScreenPropertySchema } from \"./UpgradeScreen\";\nexport {\n AppDownloadScreen,\n appDownloadScreenPropertySchema,\n} from \"./AppDownloadScreen\";\n\n// Re-export all property schemas as a lazy-loadable collection\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\n\nexport const screenPropertySchemas: Record<\n string,\n () => Promise<WidgetPropertySchema>\n> = {\n ProfileScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./ProfileScreen\").then((m) => m.profileScreenPropertySchema),\n MessagingScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./MessagingScreen\").then((m) => m.messagingScreenPropertySchema),\n ContactsScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./ContactsScreen\").then((m) => m.contactsScreenPropertySchema),\n OrdersScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./OrdersScreen\").then((m) => m.ordersScreenPropertySchema),\n SubscriptionsScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./SubscriptionsScreen\").then(\n (m) => m.subscriptionsScreenPropertySchema,\n ),\n CustomersScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./CustomersScreen\").then((m) => m.customersScreenPropertySchema),\n MySiteScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./MySiteScreen\").then((m) => m.mySiteScreenPropertySchema),\n ShareablesScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./ShareablesScreen\").then((m) => m.shareablesScreenPropertySchema),\n ShopScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./ShopScreen\").then((m) => m.shopScreenPropertySchema),\n UpgradeScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./UpgradeScreen\").then((m) => m.upgradeScreenPropertySchema),\n AppDownloadScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./AppDownloadScreen\").then(\n (m) => m.appDownloadScreenPropertySchema,\n ),\n};\n\n// Page Template Registration\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\nimport { PAGE_CATEGORIES } from \"../types/page-template\";\n\n/**\n * Core page template IDs\n */\nexport const CORE_PAGE_IDS = {\n PROFILE: \"core-profile\",\n MESSAGING: \"core-messaging\",\n CONTACTS: \"core-contacts\",\n ORDERS: \"core-orders\",\n SUBSCRIPTIONS: \"core-subscriptions\",\n CUSTOMERS: \"core-customers\",\n MY_SITE: \"core-my-site\",\n SHAREABLES: \"core-shareables\",\n SHOP: \"core-shop\",\n UPGRADE: \"core-upgrade\",\n APP_DOWNLOAD: \"core-app-download\",\n} as const;\n\n/**\n * Register core page templates.\n * These are automatically registered when the SDK is imported.\n */\nfunction registerCorePageTemplates(): void {\n // Profile Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.PROFILE,\n slug: \"profile\",\n name: \"Profile\",\n description: \"User profile management\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"profile\", \"account\", \"user\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"ProfileScreen\",\n id: \"profile-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Messaging Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.MESSAGING,\n slug: \"messaging\",\n name: \"Messaging\",\n description: \"Messaging interface provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.COMMUNICATION,\n tags: [\"messaging\", \"chat\", \"conversations\", \"communication\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"MessagingScreen\",\n id: \"messaging-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Contacts Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.CONTACTS,\n slug: \"contacts\",\n name: \"Contacts\",\n description: \"Contact management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"contacts\", \"people\", \"address-book\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"ContactsScreen\",\n id: \"contacts-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Orders Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.ORDERS,\n slug: \"orders\",\n name: \"Orders\",\n description: \"Order management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"orders\", \"commerce\", \"sales\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"OrdersScreen\",\n id: \"orders-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Subscriptions Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.SUBSCRIPTIONS,\n slug: \"subscriptions\",\n name: \"Subscriptions\",\n description: \"Subscription management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"subscriptions\", \"recurring\", \"commerce\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"SubscriptionsScreen\",\n id: \"subscriptions-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Customers Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.CUSTOMERS,\n slug: \"customers\",\n name: \"Customers\",\n description: \"Customer management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"customers\", \"people\", \"commerce\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"CustomersScreen\",\n id: \"customers-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Shop Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.SHOP,\n slug: \"shop\",\n name: \"Shop\",\n description: \"Product shop with catalog browsing and product details\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"shop\", \"store\", \"products\", \"commerce\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"ShopScreen\",\n id: \"shop-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // My Site Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.MY_SITE,\n slug: \"my-site\",\n name: \"My Site\",\n description: \"Personal site management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"my-site\", \"website\", \"portal\", \"personal\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"MySiteScreen\",\n id: \"my-site-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Upgrade Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.UPGRADE,\n slug: \"upgrade\",\n name: \"Upgrade\",\n description: \"Pro upgrade waitlist screen\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"upgrade\", \"pro\", \"waitlist\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"UpgradeScreen\",\n id: \"upgrade-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // App Download Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.APP_DOWNLOAD,\n slug: \"app-download\",\n name: \"App Download\",\n description: \"Mobile app download page with store links and QR code\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"app-download\", \"mobile\", \"qr-code\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"AppDownloadScreen\",\n id: \"app-download-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Shareables Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.SHAREABLES,\n slug: \"share\",\n name: \"Shareables\",\n description:\n \"Marketing assets and shareable content provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"shareables\", \"marketing\", \"assets\", \"media\", \"products\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"ShareablesScreen\",\n id: \"shareables-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n}\n\n// Auto-register core templates on module load\nregisterCorePageTemplates();\n","import { useState, useMemo } from \"react\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n Button,\n} from \"@fluid-app/ui-primitives\";\nimport { LayoutGrid } from \"lucide-react\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { getSystemNavigationBySection } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { filterRepOnlySections } from \"../navigation/filter-nav-items\";\nimport { useAccount } from \"../hooks/use-account\";\n\nexport interface QuickLinksDropdownProps {\n onNavigate: (slug: string) => void;\n}\n\nexport function QuickLinksDropdown({\n onNavigate,\n}: QuickLinksDropdownProps): React.JSX.Element {\n const [open, setOpen] = useState(false);\n\n const { data: account } = useAccount();\n const isCustomer = account?.member_type === \"customer\";\n\n const sections = useMemo(() => {\n const all = getSystemNavigationBySection();\n return isCustomer ? filterRepOnlySections(all) : all;\n }, [isCustomer]);\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shrink-0\"\n aria-label=\"Quick links\"\n >\n <LayoutGrid className=\"h-4 w-4\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n className=\"w-175 max-w-[90vw] overflow-hidden rounded-lg p-0 shadow-lg\"\n >\n <div className=\"flex flex-col\">\n {/* Header */}\n <div className=\"bg-background flex items-center gap-2 border-b p-4\">\n <LayoutGrid className=\"text-muted-foreground h-5 w-5\" />\n <h3 className=\"text-foreground text-sm font-semibold\">Shortcuts</h3>\n </div>\n\n {/* Sections */}\n <div className=\"bg-muted space-y-6 p-6\">\n {Object.entries(sections).map(([sectionName, items]) => (\n <div key={sectionName} className=\"space-y-3\">\n <h3 className=\"text-foreground text-sm font-semibold\">\n {sectionName}\n </h3>\n <div className=\"grid grid-cols-4 gap-2\">\n {items.map((item) => (\n <Button\n key={item.slug}\n variant=\"ghost\"\n className=\"text-sidebar-foreground hover:bg-sidebar-primary hover:text-sidebar-primary-foreground h-auto justify-start gap-2 rounded-lg px-3 py-2 text-sm\"\n onClick={() => {\n if (item.slug) onNavigate(item.slug);\n setOpen(false);\n }}\n >\n {item.icon && (\n <RepIcon\n name={item.icon}\n className=\"h-4 w-4 shrink-0\"\n />\n )}\n <span className=\"truncate\">{item.label}</span>\n </Button>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","import React, {\n forwardRef,\n type AnchorHTMLAttributes,\n type MouseEvent,\n} from \"react\";\nimport { useAppNavigation } from \"./AppNavigationContext\";\n\nexport interface AppLinkProps extends Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n \"href\"\n> {\n /** Slug to navigate to (e.g. \"contacts/123\") */\n to: string;\n}\n\n/**\n * SPA-aware link that renders a real `<a href>` for accessibility\n * (right-click, ctrl+click, screen readers) but intercepts normal\n * clicks for client-side navigation.\n */\nexport const AppLink: React.ForwardRefExoticComponent<\n AppLinkProps & React.RefAttributes<HTMLAnchorElement>\n> = forwardRef<HTMLAnchorElement, AppLinkProps>(function AppLink(\n { to, onClick, children, ...rest },\n ref,\n) {\n const { navigate, buildHref } = useAppNavigation();\n\n const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {\n // Allow custom onClick handlers to run first\n onClick?.(e);\n if (e.defaultPrevented) return;\n\n // Skip SPA navigation for modifier keys, non-primary button, or external target\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n if (e.button !== 0) return;\n if (rest.target && rest.target !== \"_self\") return;\n\n e.preventDefault();\n navigate(to);\n };\n\n return (\n <a ref={ref} href={buildHref(to)} onClick={handleClick} {...rest}>\n {children}\n </a>\n );\n});\n","/**\n * Scaffold Manifest\n *\n * Tracks which files belong to the portal scaffold and their category.\n * Used by `fluid doctor` to detect drift between a scaffolded portal\n * and the canonical templates shipped with the SDK.\n *\n * Categories:\n * - \"entry\" — App bootstrap files (main.tsx, index.css)\n * - \"config\" — Developer-owned config (portal.config.ts, navigation.config.ts)\n * - \"infrastructure\" — Build/tooling config (vite, tsconfig, index.html, linting)\n */\n\nexport type FileCategory = \"entry\" | \"config\" | \"infrastructure\";\n\nexport interface ManifestEntry {\n readonly category: FileCategory;\n}\n\n/**\n * Canonical scaffold file manifest.\n *\n * Files marked as \"entry\" or \"infrastructure\" are checked by `fluid doctor`.\n * Files marked as \"config\" are developer-owned and intentionally excluded from drift checks.\n */\nexport const SCAFFOLD_MANIFEST = {\n version: 2,\n files: {\n \"src/main.tsx\": { category: \"entry\" },\n \"src/index.css\": { category: \"entry\" },\n \"index.html\": { category: \"infrastructure\" },\n \"tsconfig.json\": { category: \"infrastructure\" },\n \"vite.config.ts\": { category: \"infrastructure\" },\n \".oxlintrc.json\": { category: \"infrastructure\" },\n },\n /** Developer-owned files — never checked for drift */\n developerOwned: [\n \"src/portal.config.ts\",\n \"src/navigation.config.ts\",\n \"src/screens/*\",\n ],\n} as const;\n\nexport type ScaffoldFile = keyof typeof SCAFFOLD_MANIFEST.files;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["React","Slot","useScreenHeaderContext","PanelLeft","ICON_MAP","ContactRound","Repeat","Bell","Box","Boxes","Briefcase","Calendar","ShoppingCart","CircleUser","MessageCircle","Compass","Mail","File","FileText","FileVideo","Folder","FolderOpen","Settings","Globe","GraduationCap","Heart","House","Image","ListMusic","Search","MessageSquare","PackageOpen","Star","Store","LayoutGrid","User","UserCog","Users","React","Ellipsis","X","getActiveThemeId","transformThemes","createPersister","useAppDefinitionApi","Collapsible","CollapsibleTrigger","ChevronRight","CollapsibleContent","useRepUser","X","Smartphone","Moon","Sun","LogOut","Moon","Sun","Menu","Building2","cn","Skeleton","useStore","Card","CardHeader","CardTitle","CardDescription","CardFooter","Compass","Button","useRegistry","DataAwareWidget","User","PackageOpen","Repeat","useAppNavigation","ProfileScreen","OrdersScreen","SubscriptionsScreen","MessagingScreen","ContactsScreen","ShopScreen","CustomersScreen","ShareablesScreen","MySiteScreen","useAccount","Suspense","CoreScreenPlaceholder","Component","TriangleAlert","Button","deleteDatabase","LogOut","useAccount","getDefaultThemeDefinition","resolveTheme","ScreenHeaderProvider","RepUserProvider","AppNavigationProvider","Toaster","DEFAULT_SDK_WIDGET_REGISTRY","Component","FluidProvider","StrictMode","useAppDefinitionApi","useAppDefinitionApi","useThemeContext","usePortalTenantClient","deleteDatabase","now","daysFromNow","now","now","hoursAgo","now","daysAgo","z","useAccount","Popover","PopoverTrigger","Button","LayoutGrid","PopoverContent","useAppNavigation"],"sources":["../src/types/page-template.ts","../src/registries/page-template-registry.ts","../src/core/resolve-pages.ts","../src/providers/PageTemplateProvider.tsx","../../react/src/shell/use-mobile.ts","../../react/src/shell/sidebar.tsx","../../react/src/shell/AppShellLayout.tsx","../../react/src/shell/ThemeModeContext.tsx","../../core/src/navigation/system-navigation-items.ts","../../core/src/navigation/default-navigation.ts","../../react/src/shell/ScreenHeader.tsx","../../react/src/components/RepIcon.tsx","../../core/src/navigation/navigation-storage.ts","../../core/src/navigation/navigation-utils.ts","../src/shell/SdkBottomNav.tsx","../src/hooks/query-keys.ts","../src/transforms/screen-transforms.ts","../src/transforms/navigation-transforms.ts","../src/transforms/index.ts","../src/hooks/use-fluid-app.ts","../src/shell/AppShellLoading.tsx","../src/shell/CollapsibleNavItem.tsx","../src/shell/SdkNavigation.tsx","../src/shell/SdkMobileProfileMenu.tsx","../src/shell/SdkHeader.tsx","../../../company-switcher/ui/src/components/CompanyImage.tsx","../../../company-switcher/ui/src/components/CompanyItem.tsx","../../../company-switcher/ui/src/components/CompanySwitcherSkeleton.tsx","../src/shell/SdkCompanySwitcher.tsx","../../core/src/navigation/account-manage.ts","../src/shell/go-back-or-home.ts","../src/screens/FallbackCard.tsx","../src/screens/ScreenNotFound.tsx","../src/screens/AccessDeniedScreen.tsx","../src/shell/BuilderScreenView.tsx","../src/account/account-management-layout.tsx","../src/shell/system-screen-map.ts","../src/shell/PageRouter.tsx","../../core/src/navigation/slug-utils.ts","../src/shell/AppShellErrorBoundary.tsx","../src/hooks/use-logout.ts","../src/shell/SdkLogoutButton.tsx","../src/navigation/filter-nav-items.ts","../src/shell/AppShell.tsx","../src/config/env.ts","../src/config/defaults.ts","../src/utils/build-widget-registry.ts","../src/entry/create-portal.tsx","../src/hooks/use-fluid-profile.ts","../src/hooks/use-app-definition.ts","../src/hooks/use-fluid-theme.ts","../src/hooks/use-company-switch.ts","../src/hooks/demo-data/calendar-events.ts","../src/hooks/use-calendar-events.ts","../src/hooks/demo-data/todos.ts","../src/hooks/use-todos.ts","../src/hooks/hook-types.ts","../src/hooks/demo-data/activities.ts","../src/hooks/use-activities.ts","../src/hooks/demo-data/catchups.ts","../src/hooks/use-catchups.ts","../src/hooks/demo-data/mysite.ts","../src/hooks/use-mysite.ts","../src/hooks/demo-data/conversations.ts","../src/hooks/use-conversations.ts","../src/types/screen-types.ts","../src/hooks/demo-data/contacts.ts","../src/hooks/use-contacts.ts","../../../platform/auth/src/types.ts","../../../platform/auth/src/company-switch.ts","../src/screens/index.ts","../src/shell/QuickLinksDropdown.tsx","../src/shell/AppLink.tsx","../src/scaffold/manifest.ts"],"sourcesContent":["import type { WidgetSchema } from \"./widget-schema\";\n\n/**\n * Category for organizing page templates in the registry\n */\nexport interface PageCategory {\n /** Unique identifier for the category */\n readonly id: string;\n /** Display label */\n label: string;\n /** Icon identifier (e.g., lucide icon name) */\n icon?: string;\n}\n\n/**\n * A reusable page template that can be shared across multiple navigations\n */\nexport interface PageTemplate {\n /** Unique identifier for the template */\n readonly id: string;\n /** URL-friendly slug */\n slug: string;\n /** Display name */\n name: string;\n /** Description of the template's purpose */\n description?: string;\n /** Category ID for organization */\n category: string;\n /** Tags for filtering and search */\n tags?: readonly string[];\n /** The widget tree that defines the page content */\n component_tree: readonly WidgetSchema[];\n /** Semantic version of the template */\n version: string;\n /** Whether this is a core feature that cannot be removed */\n isCore?: boolean;\n /** Default prop values that can be customized */\n defaultProps?: Readonly<Record<string, unknown>>;\n /** Thumbnail image URL for UI display */\n thumbnail?: string;\n}\n\n/**\n * Reference to a shared page template within a navigation\n */\nexport interface PageReference {\n /** ID of the page template being referenced */\n page_template_id: string;\n /** Screen ID to assign to this page in the navigation */\n screen_id: number;\n /** Optional prop overrides (only prop values, not widget structure) */\n overrides?: readonly PageOverride[];\n}\n\n/**\n * Override for a specific widget's props within a page template\n */\nexport interface PageOverride {\n /** ID of the widget to override (must match WidgetSchema.id in the template) */\n readonly widget_id: string;\n /** Props to override (merged with original props) */\n props: Readonly<Record<string, unknown>>;\n}\n\n/**\n * Built-in page category IDs\n */\nexport const PAGE_CATEGORIES = {\n CORE: \"core\",\n COMMERCE: \"commerce\",\n COMMUNICATION: \"communication\",\n DATA: \"data\",\n CUSTOM: \"custom\",\n} as const;\n\nexport type PageCategoryId =\n (typeof PAGE_CATEGORIES)[keyof typeof PAGE_CATEGORIES];\n","import type {\n PageTemplate,\n PageCategory,\n PageCategoryId,\n} from \"../types/page-template\";\nimport { PAGE_CATEGORIES } from \"../types/page-template\";\n\n/**\n * Registry for managing reusable page templates.\n *\n * The registry provides a central store for page templates that can be\n * shared across multiple navigations. Core pages (like Messaging, Contacts)\n * are pre-registered and cannot be removed.\n *\n * @example\n * ```ts\n * // Register a custom page template\n * PageTemplateRegistry.register({\n * id: 'custom-dashboard',\n * slug: 'dashboard',\n * name: 'Custom Dashboard',\n * category: 'custom',\n * version: '1.0.0',\n * component_tree: [{ type: 'TextWidget', props: { text: 'Hello' } }],\n * });\n *\n * // Get a template by ID\n * const template = PageTemplateRegistry.get('custom-dashboard');\n *\n * // List all templates in a category\n * const corePages = PageTemplateRegistry.getByCategory('core');\n * ```\n */\nclass PageTemplateRegistryImpl {\n private templates = new Map<string, PageTemplate>();\n private categories: PageCategory[] = [];\n\n constructor() {\n // Initialize default categories\n this.categories = [\n { id: PAGE_CATEGORIES.CORE, label: \"Core Features\", icon: \"star\" },\n {\n id: PAGE_CATEGORIES.COMMERCE,\n label: \"Commerce\",\n icon: \"shopping-cart\",\n },\n {\n id: PAGE_CATEGORIES.COMMUNICATION,\n label: \"Communication\",\n icon: \"message-circle\",\n },\n {\n id: PAGE_CATEGORIES.DATA,\n label: \"Data & Analytics\",\n icon: \"bar-chart\",\n },\n { id: PAGE_CATEGORIES.CUSTOM, label: \"Custom\", icon: \"puzzle\" },\n ];\n }\n\n /**\n * Register a new page template.\n * @throws Error if a template with the same ID already exists\n */\n register(template: PageTemplate): void {\n if (this.templates.has(template.id)) {\n throw new Error(\n `Page template with ID \"${template.id}\" is already registered`,\n );\n }\n this.templates.set(template.id, template);\n }\n\n /**\n * Unregister a page template by ID.\n * Core templates cannot be unregistered.\n * @returns true if the template was removed, false if it didn't exist or is a core template\n */\n unregister(id: string): boolean {\n const template = this.templates.get(id);\n if (!template) {\n return false;\n }\n if (template.isCore) {\n console.warn(\n `Cannot unregister core page template \"${id}\". Core templates are required.`,\n );\n return false;\n }\n return this.templates.delete(id);\n }\n\n /**\n * Get a page template by ID.\n */\n get(id: string): PageTemplate | undefined {\n return this.templates.get(id);\n }\n\n /**\n * Get all page templates in a specific category.\n */\n getByCategory(category: PageCategoryId | string): PageTemplate[] {\n return Array.from(this.templates.values()).filter(\n (t) => t.category === category,\n );\n }\n\n /**\n * List all registered page templates.\n */\n listAll(): PageTemplate[] {\n return Array.from(this.templates.values());\n }\n\n /**\n * List all core page templates (isCore: true).\n */\n listCore(): PageTemplate[] {\n return Array.from(this.templates.values()).filter((t) => t.isCore);\n }\n\n /**\n * List all non-core page templates.\n */\n listOptional(): PageTemplate[] {\n return Array.from(this.templates.values()).filter((t) => !t.isCore);\n }\n\n /**\n * List all registered categories.\n */\n listCategories(): PageCategory[] {\n return [...this.categories];\n }\n\n /**\n * Add a custom category.\n */\n addCategory(category: PageCategory): void {\n if (this.categories.some((c) => c.id === category.id)) {\n console.warn(`Category with ID \"${category.id}\" already exists`);\n return;\n }\n this.categories.push(category);\n }\n\n /**\n * Check if a template exists by ID.\n */\n has(id: string): boolean {\n return this.templates.has(id);\n }\n\n /**\n * Get the count of registered templates.\n */\n get size(): number {\n return this.templates.size;\n }\n\n /**\n * Clear all non-core templates.\n * Useful for testing or resetting the registry.\n */\n clearNonCore(): void {\n for (const [id, template] of this.templates) {\n if (!template.isCore) {\n this.templates.delete(id);\n }\n }\n }\n}\n\n/**\n * Global page template registry singleton.\n *\n * This registry is automatically populated with core page templates\n * (Messaging, Contacts) when the SDK is imported.\n */\nexport const PageTemplateRegistry: PageTemplateRegistryImpl =\n new PageTemplateRegistryImpl();\n","import type { Navigation, ScreenDefinition, WidgetSchema } from \"../types\";\nimport type {\n PageReference,\n PageOverride,\n PageTemplate,\n} from \"../types/page-template\";\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\n\n/**\n * Apply prop overrides to widgets in a component tree.\n * Recursively walks widget.props.children so overrides targeting\n * nested widgets (inside LayoutWidget, ContainerWidget, etc.) are applied.\n *\n * @param componentTree - The original component tree from the page template\n * @param overrides - Array of widget-specific prop overrides\n * @returns A new component tree with overrides applied\n */\nfunction applyOverrides(\n componentTree: readonly WidgetSchema[],\n overrides: readonly PageOverride[],\n): WidgetSchema[] {\n if (!overrides.length) {\n // Return a mutable copy to satisfy ScreenDefinition.component_tree type\n return [...componentTree];\n }\n\n // Build a map of widget_id -> override for O(1) lookup (built once, shared across recursion)\n const overrideMap = new Map(overrides.map((o) => [o.widget_id, o.props]));\n\n return componentTree.map((widget) =>\n applyWidgetOverrides(widget, overrideMap),\n );\n}\n\n/**\n * Recursively apply overrides to a widget and its children.\n * Only clones widgets that actually change (have an override or contain children that might).\n */\nfunction applyWidgetOverrides(\n widget: WidgetSchema,\n overrideMap: ReadonlyMap<string, Record<string, unknown>>,\n): WidgetSchema {\n const override = widget.id ? overrideMap.get(widget.id) : undefined;\n const children = widget.props.children;\n\n // Recurse into children if they exist (LayoutWidget, ContainerWidget)\n const hasChildren = Array.isArray(children) && children.length > 0;\n\n if (!override && !hasChildren) {\n return widget;\n }\n\n const newProps = override\n ? { ...widget.props, ...override }\n : { ...widget.props };\n\n if (hasChildren) {\n newProps.children = (children as readonly WidgetSchema[]).map((child) =>\n applyWidgetOverrides(child, overrideMap),\n );\n }\n\n return { ...widget, props: newProps };\n}\n\n/**\n * Resolve a page reference to a screen definition.\n *\n * @param ref - The page reference from navigation\n * @returns A ScreenDefinition or undefined if the template doesn't exist\n */\nfunction resolvePageReference(\n ref: Readonly<PageReference>,\n): ScreenDefinition | undefined {\n const template = PageTemplateRegistry.get(ref.page_template_id);\n if (!template) {\n console.warn(\n `Page template \"${ref.page_template_id}\" not found in registry`,\n );\n return undefined;\n }\n\n // Apply any overrides to the component tree\n // Spread to create mutable array for ScreenDefinition.component_tree\n const componentTree = ref.overrides\n ? applyOverrides(template.component_tree, ref.overrides)\n : [...template.component_tree];\n\n return {\n id: ref.screen_id,\n slug: template.slug,\n name: template.name,\n component_tree: componentTree,\n };\n}\n\n/**\n * Resolve all page references and local screens into a unified screen list.\n *\n * This function merges:\n * 1. Screen definitions from page_refs (shared templates)\n * 2. Local screen definitions (for backwards compatibility and custom screens)\n *\n * When a screen_id appears in both page_refs and screens, the local screen\n * takes precedence (allows local overrides of template pages).\n *\n * @param navigation - The navigation configuration\n * @returns A unified array of ScreenDefinition objects\n *\n * @example\n * ```ts\n * const navigation: Navigation = {\n * definition_id: 1,\n * id: 1,\n * name: \"Main Nav\",\n * navigation_items: [...],\n * screens: [\n * // Local custom screen\n * { id: 1, slug: \"home\", name: \"Home\", component_tree: [...] }\n * ],\n * page_refs: [\n * // Reference to shared messaging template\n * { page_template_id: \"core-messaging\", screen_id: 2 }\n * ],\n * };\n *\n * const allScreens = resolveNavigationPages(navigation);\n * // Returns: [home screen, messaging screen from template]\n * ```\n */\nexport function resolveNavigationPages(\n navigation: Readonly<Navigation>,\n): ScreenDefinition[] {\n // Start with local screens (these take precedence)\n const localScreenIds = new Set(navigation.screens.map((s) => s.id));\n const result: ScreenDefinition[] = [...navigation.screens];\n\n // Resolve page references (skip if local screen already exists with same ID)\n if (navigation.page_refs) {\n for (const ref of navigation.page_refs) {\n if (localScreenIds.has(ref.screen_id)) {\n // Local screen takes precedence\n continue;\n }\n\n const screen = resolvePageReference(ref);\n if (screen) {\n result.push(screen);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Get all available page templates for use in navigation.\n *\n * @returns Array of page templates from the registry\n */\nexport function getAvailablePageTemplates(): PageTemplate[] {\n return PageTemplateRegistry.listAll();\n}\n\n/**\n * Get core page templates that are required for basic functionality.\n *\n * @returns Array of core page templates\n */\nexport function getCorePageTemplates(): PageTemplate[] {\n return PageTemplateRegistry.listCore();\n}\n\n/**\n * Get optional page templates that can be added to navigation.\n *\n * @returns Array of optional (non-core) page templates\n */\nexport function getOptionalPageTemplates(): PageTemplate[] {\n return PageTemplateRegistry.listOptional();\n}\n\n/**\n * Check if a navigation has all required core pages.\n *\n * @param navigation - The navigation to check\n * @returns Object with validation result and missing page IDs\n */\nexport function validateNavigationPages(navigation: Readonly<Navigation>): {\n readonly valid: boolean;\n readonly missingCorePages: readonly string[];\n} {\n const corePages = PageTemplateRegistry.listCore();\n const referencedTemplateIds = new Set(\n navigation.page_refs?.map((ref) => ref.page_template_id) ?? [],\n );\n\n // Check which core pages are referenced\n const missingCorePages = corePages\n .filter((page) => !referencedTemplateIds.has(page.id))\n .map((page) => page.id);\n\n return {\n valid: missingCorePages.length === 0,\n missingCorePages,\n };\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport type { PageTemplate } from \"../types/page-template\";\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\nimport { resolveNavigationPages } from \"../core/resolve-pages\";\nimport type { Navigation, ScreenDefinition } from \"../types\";\n\n/** Stable empty array for the default `templates` prop (avoids new reference each render) */\nconst EMPTY_TEMPLATES: readonly PageTemplate[] = [];\n\n/**\n * Context value for page template resolution.\n * All properties are readonly since context values should not be mutated by consumers.\n */\ninterface PageTemplateContextValue {\n /**\n * Resolve a navigation's page_refs and screens into a unified screen list\n */\n readonly resolvePages: (navigation: Navigation) => ScreenDefinition[];\n /**\n * Get all available page templates\n */\n readonly listTemplates: () => PageTemplate[];\n /**\n * Get a specific template by ID\n */\n readonly getTemplate: (id: string) => PageTemplate | undefined;\n /**\n * Check if a template exists\n */\n readonly hasTemplate: (id: string) => boolean;\n}\n\nconst PageTemplateContext = createContext<PageTemplateContextValue | null>(\n null,\n);\n\n/**\n * Props for PageTemplateProvider\n */\ninterface PageTemplateProviderProps {\n children: React.ReactNode;\n /**\n * Additional custom page templates to register.\n * These are registered when the provider mounts and unregistered when it unmounts.\n */\n templates?: readonly PageTemplate[];\n}\n\n/**\n * Provider for page template resolution.\n *\n * This provider:\n * 1. Registers any custom templates passed via props\n * 2. Provides methods for resolving navigation pages\n * 3. Cleans up custom templates on unmount\n *\n * @example\n * ```tsx\n * // With custom templates\n * const customTemplates: PageTemplate[] = [\n * {\n * id: 'custom-dashboard',\n * slug: 'dashboard',\n * name: 'Dashboard',\n * category: 'custom',\n * version: '1.0.0',\n * component_tree: [{ type: 'TextWidget', props: { text: 'Custom Dashboard' } }],\n * },\n * ];\n *\n * <PageTemplateProvider templates={customTemplates}>\n * <App />\n * </PageTemplateProvider>\n *\n * // Without custom templates (uses only core templates)\n * <PageTemplateProvider>\n * <App />\n * </PageTemplateProvider>\n * ```\n */\nexport function PageTemplateProvider({\n children,\n templates = EMPTY_TEMPLATES,\n}: PageTemplateProviderProps): React.JSX.Element {\n // Track which templates we registered so we can clean them up\n const registeredIds = useRef<string[]>([]);\n\n // Derive a stable primitive key from template IDs\n // (rerender-dependencies rule: use primitive dependencies in effects)\n const templateKey = templates.map((t) => t.id).join(\",\");\n\n // Register custom templates when template IDs change\n useEffect(() => {\n const registered: string[] = [];\n\n for (const template of templates) {\n if (!PageTemplateRegistry.has(template.id)) {\n try {\n PageTemplateRegistry.register(template);\n registered.push(template.id);\n } catch (error) {\n console.warn(\n `Failed to register page template \"${template.id}\":`,\n error,\n );\n }\n }\n }\n\n registeredIds.current = registered;\n\n // Cleanup when template IDs change or on unmount\n return () => {\n for (const id of registeredIds.current) {\n PageTemplateRegistry.unregister(id);\n }\n registeredIds.current = [];\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [templateKey]);\n\n // Memoize context value to prevent unnecessary re-renders\n // Use `satisfies` to validate shape at compile time while preserving inference\n const contextValue = useMemo(\n () =>\n ({\n resolvePages: resolveNavigationPages,\n listTemplates: () => PageTemplateRegistry.listAll(),\n getTemplate: (id: string) => PageTemplateRegistry.get(id),\n hasTemplate: (id: string) => PageTemplateRegistry.has(id),\n }) satisfies PageTemplateContextValue,\n [],\n );\n\n return (\n <PageTemplateContext.Provider value={contextValue}>\n {children}\n </PageTemplateContext.Provider>\n );\n}\n\n/**\n * Hook to access page template functionality.\n *\n * @throws Error if used outside of PageTemplateProvider\n *\n * @example\n * ```tsx\n * function NavigationRenderer({ navigation }: { navigation: Navigation }) {\n * const { resolvePages } = usePageTemplates();\n * const screens = resolvePages(navigation);\n *\n * return (\n * <div>\n * {screens.map((screen) => (\n * <Screen key={screen.id} definition={screen} />\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function usePageTemplates(): PageTemplateContextValue {\n const context = useContext(PageTemplateContext);\n if (!context) {\n throw new Error(\n \"usePageTemplates must be used within a PageTemplateProvider\",\n );\n }\n return context;\n}\n\n/**\n * Hook to resolve navigation pages directly.\n * Convenience wrapper around usePageTemplates().resolvePages.\n *\n * @param navigation - The navigation to resolve\n * @returns Array of resolved screen definitions\n */\nexport function useResolvedPages(navigation: Navigation): ScreenDefinition[] {\n const { resolvePages } = usePageTemplates();\n return useMemo(() => resolvePages(navigation), [resolvePages, navigation]);\n}\n","import { useState, useEffect } from \"react\";\n\nconst MOBILE_BREAKPOINT = 768;\nconst TABLET_BREAKPOINT = 1024;\n\nexport function useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState<boolean>(false);\n\n useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return isMobile;\n}\n\nexport function useIsTablet(): boolean {\n const [isTablet, setIsTablet] = useState<boolean>(false);\n\n useEffect(() => {\n const mql = window.matchMedia(\n `(min-width: ${MOBILE_BREAKPOINT}px) and (max-width: ${TABLET_BREAKPOINT - 1}px)`,\n );\n const onChange = () => {\n setIsTablet(\n window.innerWidth >= MOBILE_BREAKPOINT &&\n window.innerWidth < TABLET_BREAKPOINT,\n );\n };\n mql.addEventListener(\"change\", onChange);\n setIsTablet(\n window.innerWidth >= MOBILE_BREAKPOINT &&\n window.innerWidth < TABLET_BREAKPOINT,\n );\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return isTablet;\n}\n\nexport function useIsMobileOrTablet(): boolean {\n const [isMobileOrTablet, setIsMobileOrTablet] = useState<boolean>(false);\n\n useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${TABLET_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobileOrTablet(window.innerWidth < TABLET_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobileOrTablet(window.innerWidth < TABLET_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return isMobileOrTablet;\n}\n","\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nimport * as React from \"react\";\n\nimport { useIsMobile } from \"./use-mobile\";\n\n// ---------------------------------------------------------------------------\n// Inlined utilities (avoid importing from builder's UI kit)\n// ---------------------------------------------------------------------------\n\nfunction cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nfunction Separator({\n className,\n orientation = \"horizontal\",\n ...props\n}: React.ComponentPropsWithRef<\"div\"> & {\n orientation?: \"horizontal\" | \"vertical\";\n decorative?: boolean;\n}) {\n return (\n <div\n role=\"separator\"\n aria-orientation={orientation}\n className={cn(\n \"bg-border shrink-0\",\n orientation === \"horizontal\" ? \"h-px w-full\" : \"h-full w-px\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Skeleton({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn(\"bg-muted animate-pulse rounded-md\", className)}\n {...props}\n />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst SIDEBAR_WIDTH = \"13rem\";\nconst SIDEBAR_WIDTH_MOBILE = \"18rem\";\nconst SIDEBAR_WIDTH_ICON = \"3rem\";\nconst SIDEBAR_KEYBOARD_SHORTCUT = \"b\";\n\n// ---------------------------------------------------------------------------\n// Sidebar Context\n// ---------------------------------------------------------------------------\n\ntype SidebarContextValue = {\n state: \"expanded\" | \"collapsed\";\n open: boolean;\n setOpen: (open: boolean) => void;\n openMobile: boolean;\n setOpenMobile: (open: boolean) => void;\n isMobile: boolean;\n toggleSidebar: () => void;\n isPreviewMode: boolean;\n useBottomNav: boolean;\n};\n\nexport const SidebarContext: React.Context<SidebarContextValue | null> =\n React.createContext<SidebarContextValue | null>(null);\n\nfunction useSidebar(): SidebarContextValue {\n const context = React.useContext(SidebarContext);\n if (!context) {\n throw new Error(\"useSidebar must be used within a SidebarProvider.\");\n }\n\n return context;\n}\n\n// ---------------------------------------------------------------------------\n// SidebarProvider\n// ---------------------------------------------------------------------------\n\nconst SidebarProvider: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n viewportWidth?: number;\n previewMode?: boolean;\n useBottomNav?: boolean;\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n viewportWidth?: number;\n previewMode?: boolean;\n useBottomNav?: boolean;\n }\n>(\n (\n {\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n viewportWidth,\n previewMode,\n useBottomNav: useBottomNavProp = false,\n className,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const windowIsMobile = useIsMobile();\n // Use viewportWidth if provided, otherwise use actual window detection\n const isMobile =\n viewportWidth !== undefined ? viewportWidth < 768 : windowIsMobile;\n // Preview mode is active when viewportWidth is provided\n const isPreviewMode = viewportWidth !== undefined || !!previewMode;\n const [openMobile, setOpenMobile] = React.useState(false);\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen);\n const open = openProp ?? _open;\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === \"function\" ? value(open) : value;\n if (setOpenProp) {\n setOpenProp(openState);\n } else {\n _setOpen(openState);\n }\n },\n [setOpenProp, open],\n );\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile\n ? setOpenMobile((open) => !open)\n : setOpen((open) => !open);\n }, [isMobile, setOpen, setOpenMobile]);\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === SIDEBAR_KEYBOARD_SHORTCUT &&\n (event.metaKey || event.ctrlKey)\n ) {\n // check if composer is focused - if so, let the composer handle the shortcut\n const activeElement = document.activeElement;\n const isComposerFocused =\n activeElement?.closest(\".group\\\\/composer\") ||\n activeElement?.closest(\"[data-toolbar]\") ||\n activeElement?.classList.contains(\"ProseMirror\");\n\n if (isComposerFocused) {\n return; // let the composer handle the shortcut\n }\n\n event.preventDefault();\n toggleSidebar();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [toggleSidebar]);\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? \"expanded\" : \"collapsed\";\n\n const contextValue = React.useMemo<SidebarContextValue>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n isPreviewMode,\n useBottomNav: useBottomNavProp,\n }),\n [\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n isPreviewMode,\n useBottomNavProp,\n ],\n );\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <div\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH,\n \"--sidebar-width-icon\": SIDEBAR_WIDTH_ICON,\n ...style,\n } as React.CSSProperties\n }\n className={cn(\n \"group/sidebar-wrapper flex min-h-0 w-full flex-1\",\n className,\n )}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n </SidebarContext.Provider>\n );\n },\n);\nSidebarProvider.displayName = \"SidebarProvider\";\n\n// ---------------------------------------------------------------------------\n// Sidebar\n// ---------------------------------------------------------------------------\n\nconst Sidebar: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n side?: \"left\" | \"right\";\n variant?: \"sidebar\" | \"floating\" | \"inset\";\n collapsible?: \"offcanvas\" | \"icon\" | \"none\";\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n side?: \"left\" | \"right\";\n variant?: \"sidebar\" | \"floating\" | \"inset\";\n collapsible?: \"offcanvas\" | \"icon\" | \"none\";\n }\n>(\n (\n {\n side = \"left\",\n variant = \"sidebar\",\n collapsible = \"offcanvas\",\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const {\n isMobile,\n state,\n openMobile,\n setOpenMobile,\n isPreviewMode,\n useBottomNav,\n } = useSidebar();\n\n // Define CSS variables for expanded and collapsed sidebar widths\n const sidebarWidth =\n state === \"expanded\" ? SIDEBAR_WIDTH : SIDEBAR_WIDTH_ICON;\n\n // When bottom nav is active on mobile, hide the sidebar entirely\n if (useBottomNav && isMobile) {\n return null;\n }\n\n if (collapsible === \"none\") {\n return (\n <div\n className={cn(\n \"bg-sidebar text-sidebar-foreground flex w-(--sidebar-width) flex-col rounded-tl-lg\",\n isPreviewMode ? \"h-full\" : \"h-[97vh]\",\n className,\n )}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n );\n }\n\n if (isMobile) {\n // For mobile, render a slide-out sidebar with overlay\n // Use absolute positioning in preview mode so it stays within the preview container\n const positionClass = isPreviewMode ? \"absolute\" : \"fixed\";\n return (\n <>\n {/* Overlay - only visible when sidebar is open */}\n {openMobile && (\n <div\n className={cn(positionClass, \"inset-0 z-40 bg-black/50\")}\n onClick={() => setOpenMobile(false)}\n aria-hidden=\"true\"\n />\n )}\n\n {/* Sidebar - slides in from left */}\n <div\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n className={cn(\n positionClass,\n \"bg-sidebar text-sidebar-foreground top-0 left-0 z-50 h-full w-[--sidebar-width] p-0 transition-transform duration-300 ease-in-out\",\n openMobile ? \"translate-x-0\" : \"-translate-x-full\",\n className,\n )}\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n ref={ref}\n {...props}\n >\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </div>\n </>\n );\n }\n\n return (\n <div\n ref={ref}\n className=\"group peer bg-sidebar text-sidebar-foreground hidden md:block\"\n data-state={state}\n data-collapsible={state === \"collapsed\" ? collapsible : \"\"}\n data-variant={variant}\n data-side={side}\n style={\n {\n \"--sidebar-width\": sidebarWidth,\n } as React.CSSProperties\n }\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n className={cn(\n \"relative bg-transparent transition-[width] duration-200 ease-linear\",\n \"group-data-[collapsible=offcanvas]:w-0\",\n \"group-data-[side=right]:rotate-180\",\n variant === \"floating\" || variant === \"inset\"\n ? \"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]\"\n : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon)\",\n )}\n />\n <div\n className={cn(\n \"relative inset-y-0 z-[20] hidden w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex\",\n isPreviewMode ? \"h-full\" : \"h-svh\",\n side === \"left\"\n ? \"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]\"\n : \"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]\",\n // Adjust the padding for floating and inset variants.\n variant === \"floating\" || variant === \"inset\"\n ? \"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]\"\n : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=right]:border-l\",\n className,\n )}\n {...props}\n >\n <div\n data-sidebar=\"sidebar\"\n className=\"group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm\"\n >\n {children}\n </div>\n </div>\n </div>\n );\n },\n);\nSidebar.displayName = \"Sidebar\";\n\n// ---------------------------------------------------------------------------\n// SidebarRail\n// ---------------------------------------------------------------------------\n\nconst SidebarRail: React.ForwardRefExoticComponent<\n React.ComponentProps<\"button\"> & React.RefAttributes<HTMLButtonElement>\n> = React.forwardRef<HTMLButtonElement, React.ComponentProps<\"button\">>(\n ({ className, ...props }, ref) => {\n const { toggleSidebar } = useSidebar();\n\n return (\n <button\n ref={ref}\n data-sidebar=\"rail\"\n aria-label=\"Toggle Sidebar\"\n tabIndex={-1}\n onClick={toggleSidebar}\n title=\"Toggle Sidebar\"\n className={cn(\n \"hover:after:bg-sidebar-border absolute inset-y-0 z-[10] hidden w-4 -translate-x-full transition-all ease-linear group-data-[side=left]:-right-[1.375rem] group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex\",\n \"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize\",\n \"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize\",\n \"hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full\",\n \"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2\",\n \"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarRail.displayName = \"SidebarRail\";\n\n// ---------------------------------------------------------------------------\n// SidebarInset\n// ---------------------------------------------------------------------------\n\nconst SidebarInset: React.ForwardRefExoticComponent<\n React.ComponentProps<\"main\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"main\">>(\n ({ className, ...props }, ref) => {\n const { isPreviewMode } = useSidebar();\n return (\n <main\n ref={ref}\n className={cn(\n \"relative flex flex-1 flex-col\",\n isPreviewMode\n ? \"max-h-[calc(100svh-(--spacing(4)))]\"\n : \"min-h-svh peer-data-[variant=inset]:min-h-[calc(100svh-(--spacing(4)))]\",\n \"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarInset.displayName = \"SidebarInset\";\n\n// ---------------------------------------------------------------------------\n// SidebarInput\n// ---------------------------------------------------------------------------\n\nconst SidebarInput: React.ForwardRefExoticComponent<\n React.ComponentProps<\"input\"> & React.RefAttributes<HTMLInputElement>\n> = React.forwardRef<HTMLInputElement, React.ComponentProps<\"input\">>(\n ({ className, ...props }, ref) => {\n return (\n <input\n ref={ref}\n data-sidebar=\"input\"\n className={cn(\n \"bg-background focus-visible:ring-sidebar-ring h-8 w-full rounded-md border px-3 text-sm shadow-none focus-visible:ring-2 focus-visible:outline-none\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarInput.displayName = \"SidebarInput\";\n\n// ---------------------------------------------------------------------------\n// SidebarHeader / Footer\n// ---------------------------------------------------------------------------\n\nconst SidebarHeader: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"header\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n );\n },\n);\nSidebarHeader.displayName = \"SidebarHeader\";\n\nconst SidebarFooter: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"footer\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n );\n },\n);\nSidebarFooter.displayName = \"SidebarFooter\";\n\n// ---------------------------------------------------------------------------\n// SidebarSeparator\n// ---------------------------------------------------------------------------\n\nconst SidebarSeparator: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n orientation?: \"horizontal\" | \"vertical\";\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n orientation?: \"horizontal\" | \"vertical\";\n }\n>(({ className, ...props }, ref) => {\n return (\n <Separator\n ref={ref}\n data-sidebar=\"separator\"\n className={cn(\"bg-sidebar-border mx-2 w-auto\", className)}\n {...props}\n />\n );\n});\nSidebarSeparator.displayName = \"SidebarSeparator\";\n\n// ---------------------------------------------------------------------------\n// SidebarContent\n// ---------------------------------------------------------------------------\n\nconst SidebarContent: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"content\"\n className={cn(\n \"scrollbar-none flex min-h-0 flex-1 flex-col gap-2 overflow-auto rounded group-data-[collapsible=icon]:gap-0 group-data-[collapsible=icon]:overflow-hidden group-data-[collapsible=icon]:pt-3\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarContent.displayName = \"SidebarContent\";\n\n// ---------------------------------------------------------------------------\n// SidebarGroup\n// ---------------------------------------------------------------------------\n\nconst SidebarGroup: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"group\"\n className={cn(\n \"relative flex w-full min-w-0 flex-col p-2 group-data-[collapsible=icon]:py-0 group-data-[collapsible=icon]:pt-4\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nSidebarGroup.displayName = \"SidebarGroup\";\n\nconst SidebarGroupLabel: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n asChild?: boolean;\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & { asChild?: boolean }\n>(({ className, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"div\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-label\"\n className={cn(\n \"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n \"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n );\n});\nSidebarGroupLabel.displayName = \"SidebarGroupLabel\";\n\nconst SidebarGroupAction: React.ForwardRefExoticComponent<\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n } & React.RefAttributes<HTMLButtonElement>\n> = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & { asChild?: boolean }\n>(({ className, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-action\"\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n // Increases the hit area of the button on mobile.\n \"after:absolute after:-inset-2 md:after:hidden\",\n \"group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n );\n});\nSidebarGroupAction.displayName = \"SidebarGroupAction\";\n\nconst SidebarGroupContent: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n data-sidebar=\"group-content\"\n className={cn(\"w-full text-sm\", className)}\n {...props}\n />\n ),\n);\nSidebarGroupContent.displayName = \"SidebarGroupContent\";\n\n// ---------------------------------------------------------------------------\n// SidebarMenu\n// ---------------------------------------------------------------------------\n\nconst SidebarMenu: React.ForwardRefExoticComponent<\n React.ComponentProps<\"ul\"> & React.RefAttributes<HTMLUListElement>\n> = React.forwardRef<HTMLUListElement, React.ComponentProps<\"ul\">>(\n ({ className, ...props }, ref) => (\n <ul\n ref={ref}\n data-sidebar=\"menu\"\n className={cn(\"flex w-full min-w-0 flex-col gap-1\", className)}\n {...props}\n />\n ),\n);\nSidebarMenu.displayName = \"SidebarMenu\";\n\nconst SidebarMenuItem: React.ForwardRefExoticComponent<\n React.ComponentProps<\"li\"> & React.RefAttributes<HTMLLIElement>\n> = React.forwardRef<HTMLLIElement, React.ComponentProps<\"li\">>(\n ({ className, ...props }, ref) => (\n <li\n ref={ref}\n data-sidebar=\"menu-item\"\n className={cn(\"group/menu-item relative\", className)}\n {...props}\n />\n ),\n);\nSidebarMenuItem.displayName = \"SidebarMenuItem\";\n\n// ---------------------------------------------------------------------------\n// SidebarMenuButton\n// ---------------------------------------------------------------------------\n\nconst sidebarMenuButtonVariants: (\n props?:\n | ({\n variant?: \"default\" | \"outline\" | null | undefined;\n size?: \"default\" | \"sm\" | \"lg\" | null | undefined;\n } & (\n | {\n class: ClassValue;\n className?: never;\n }\n | {\n class?: never;\n className: ClassValue;\n }\n | {\n class?: never;\n className?: never;\n }\n ))\n | undefined,\n) => string = cva(\n \"peer/menu-button ring-sidebar-ring hover:bg-sidebar-primary hover:text-sidebar-primary-foreground active:bg-sidebar-primary active:text-sidebar-primary-foreground data-[active=true]:bg-sidebar-primary data-[active=true]:text-sidebar-primary-foreground data-[state=open]:hover:bg-sidebar-primary data-[state=open]:hover:text-sidebar-primary-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden transition-[width,height,padding,background-color,color] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n {\n variants: {\n variant: {\n default:\n \"hover:bg-sidebar-primary hover:text-sidebar-primary-foreground\",\n outline:\n \"hover:bg-sidebar-primary hover:text-sidebar-primary-foreground shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:shadow-[0_0_0_1px_hsl(var(--sidebar-primary))]\",\n },\n size: {\n default: \"h-8 text-sm\",\n sm: \"h-7 text-xs\",\n lg: \"h-12 text-sm group-data-[collapsible=icon]:p-0!\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nconst SidebarMenuButton: React.ForwardRefExoticComponent<\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n isActive?: boolean;\n } & VariantProps<typeof sidebarMenuButtonVariants> &\n React.RefAttributes<HTMLButtonElement>\n> = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n isActive?: boolean;\n } & VariantProps<typeof sidebarMenuButtonVariants>\n>(\n (\n {\n asChild = false,\n isActive = false,\n variant = \"default\",\n size = \"default\",\n className,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"button\";\n\n const button = (\n <Comp\n ref={ref}\n data-sidebar=\"menu-button\"\n data-size={size}\n data-active={isActive}\n className={cn(sidebarMenuButtonVariants({ variant, size }), className)}\n {...props}\n />\n );\n\n return button;\n },\n);\nSidebarMenuButton.displayName = \"SidebarMenuButton\";\n\n// ---------------------------------------------------------------------------\n// SidebarMenuAction / Badge / Skeleton\n// ---------------------------------------------------------------------------\n\nconst SidebarMenuAction: React.ForwardRefExoticComponent<\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n showOnHover?: boolean;\n } & React.RefAttributes<HTMLButtonElement>\n> = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n showOnHover?: boolean;\n }\n>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-action\"\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n // Increases the hit area of the button on mobile.\n \"after:absolute after:-inset-2 md:after:hidden\",\n \"peer-data-[size=sm]/menu-button:top-1\",\n \"peer-data-[size=default]/menu-button:top-1.5\",\n \"peer-data-[size=lg]/menu-button:top-2.5\",\n \"group-data-[collapsible=icon]:hidden\",\n showOnHover &&\n \"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n});\nSidebarMenuAction.displayName = \"SidebarMenuAction\";\n\nconst SidebarMenuBadge: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n data-sidebar=\"menu-badge\"\n className={cn(\n \"text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none\",\n \"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground\",\n \"peer-data-[size=sm]/menu-button:top-1\",\n \"peer-data-[size=default]/menu-button:top-1.5\",\n \"peer-data-[size=lg]/menu-button:top-2.5\",\n \"group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n ),\n);\nSidebarMenuBadge.displayName = \"SidebarMenuBadge\";\n\nconst SidebarMenuSkeleton: React.ForwardRefExoticComponent<\n React.ComponentProps<\"div\"> & {\n showIcon?: boolean;\n } & React.RefAttributes<HTMLDivElement>\n> = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n showIcon?: boolean;\n }\n>(({ className, showIcon = false, ...props }, ref) => {\n // Random width between 50 to 90%.\n const width = React.useMemo(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`;\n }, []);\n\n return (\n <div\n ref={ref}\n data-sidebar=\"menu-skeleton\"\n className={cn(\"flex h-8 items-center gap-2 rounded-md px-2\", className)}\n {...props}\n >\n {showIcon && (\n <Skeleton\n className=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n )}\n <Skeleton\n className=\"h-4 max-w-(--skeleton-width) flex-1\"\n data-sidebar=\"menu-skeleton-text\"\n style={\n {\n \"--skeleton-width\": width,\n } as React.CSSProperties\n }\n />\n </div>\n );\n});\nSidebarMenuSkeleton.displayName = \"SidebarMenuSkeleton\";\n\n// ---------------------------------------------------------------------------\n// SidebarMenuSub\n// ---------------------------------------------------------------------------\n\nconst SidebarMenuSub: React.ForwardRefExoticComponent<\n React.ComponentProps<\"ul\"> & React.RefAttributes<HTMLUListElement>\n> = React.forwardRef<HTMLUListElement, React.ComponentProps<\"ul\">>(\n ({ className, ...props }, ref) => (\n <ul\n ref={ref}\n data-sidebar=\"menu-sub\"\n className={cn(\n \"border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5\",\n \"group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n ),\n);\nSidebarMenuSub.displayName = \"SidebarMenuSub\";\n\nconst SidebarMenuSubItem: React.ForwardRefExoticComponent<\n React.ComponentProps<\"li\"> & React.RefAttributes<HTMLLIElement>\n> = React.forwardRef<HTMLLIElement, React.ComponentProps<\"li\">>(\n ({ ...props }, ref) => <li ref={ref} {...props} />,\n);\nSidebarMenuSubItem.displayName = \"SidebarMenuSubItem\";\n\nconst SidebarMenuSubButton: React.ForwardRefExoticComponent<\n React.ComponentProps<\"a\"> & {\n asChild?: boolean;\n size?: \"sm\" | \"md\";\n isActive?: boolean;\n } & React.RefAttributes<HTMLAnchorElement>\n> = React.forwardRef<\n HTMLAnchorElement,\n React.ComponentProps<\"a\"> & {\n asChild?: boolean;\n size?: \"sm\" | \"md\";\n isActive?: boolean;\n }\n>(({ asChild = false, size = \"md\", isActive, className, ...props }, ref) => {\n const Comp = asChild ? Slot : \"a\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-sub-button\"\n data-size={size}\n data-active={isActive}\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n \"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground\",\n size === \"sm\" && \"text-xs\",\n size === \"md\" && \"text-sm\",\n \"group-data-[collapsible=icon]:hidden\",\n className,\n )}\n {...props}\n />\n );\n});\nSidebarMenuSubButton.displayName = \"SidebarMenuSubButton\";\n\n// ---------------------------------------------------------------------------\n// Exports\n// ---------------------------------------------------------------------------\n\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n useSidebar,\n};\n","\"use client\";\n\nimport * as React from \"react\";\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarHeader,\n SidebarInset,\n SidebarProvider,\n} from \"./sidebar\";\n\nexport interface AppShellLayoutProps {\n /** Navigation content rendered inside the sidebar's scrollable area */\n sidebarContent: React.ReactNode;\n /** Header content rendered above the main content area */\n headerContent: React.ReactNode;\n /** Main page content */\n children: React.ReactNode;\n /** Optional slot at the top of the sidebar (e.g. logo, search) */\n sidebarHeader?: React.ReactNode;\n /** Optional slot at the bottom of the sidebar (e.g. user info) */\n sidebarFooter?: React.ReactNode;\n /** Content rendered after SidebarInset (e.g. MobileBottomNav) */\n afterContent?: React.ReactNode;\n /** Enable bottom nav mode (hides sidebar on mobile, adds bottom padding) */\n useBottomNav?: boolean;\n}\n\n/**\n * Pure visual frame that replicates the RepApp layout:\n * - 13rem collapsible sidebar\n * - 52px header area\n * - rounded-xl bg-background shadow-lg content area with bg-muted gutters\n *\n * This component handles zero business logic — it simply provides the visual shell.\n */\nexport function AppShellLayout({\n sidebarContent,\n headerContent,\n children,\n sidebarHeader,\n sidebarFooter,\n afterContent,\n useBottomNav = false,\n}: AppShellLayoutProps): React.JSX.Element {\n return (\n <SidebarProvider useBottomNav={useBottomNav}>\n <div className=\"bg-muted relative flex max-h-dvh w-full overflow-hidden\">\n {/* Navigation Sidebar */}\n <Sidebar>\n {sidebarHeader && <SidebarHeader>{sidebarHeader}</SidebarHeader>}\n <SidebarContent className=\"p-4\">{sidebarContent}</SidebarContent>\n {sidebarFooter && <SidebarFooter>{sidebarFooter}</SidebarFooter>}\n </Sidebar>\n\n {/* Main Content Area */}\n <SidebarInset className=\"flex flex-1 flex-col overflow-hidden\">\n {/* Header */}\n {headerContent}\n\n {/* Screen Content */}\n <div\n className={`bg-muted flex-1 overflow-hidden md:pr-4 md:pb-4 ${useBottomNav ? \"max-md:pb-[calc(4rem+env(safe-area-inset-bottom))]\" : \"\"}`}\n >\n <div className=\"scrollbar-none bg-background text-foreground h-full overflow-auto rounded-xl shadow-lg\">\n {children}\n </div>\n </div>\n </SidebarInset>\n\n {/* After content (e.g. MobileBottomNav) */}\n {afterContent}\n </div>\n </SidebarProvider>\n );\n}\n","\"use client\";\n\nimport type React from \"react\";\nimport {\n createContext,\n useContext,\n useCallback,\n useMemo,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\n\nexport type ThemeMode = \"auto\" | \"light\" | \"dark\";\n\nexport type DisplayMode = \"light\" | \"dark\";\n\nexport interface ThemeModeContextValue {\n mode: ThemeMode;\n displayMode: DisplayMode;\n setMode: (mode: ThemeMode) => void;\n autoModeEnabled: boolean;\n cycleMode: () => void;\n dataAttribute: string | undefined;\n}\n\nconst ThemeModeContext = createContext<ThemeModeContextValue | null>(null);\n\nconst darkMediaQuery =\n typeof window !== \"undefined\"\n ? window.matchMedia(\"(prefers-color-scheme: dark)\")\n : null;\n\nfunction subscribeToPrefersColorScheme(callback: () => void) {\n darkMediaQuery?.addEventListener(\"change\", callback);\n return () => darkMediaQuery?.removeEventListener(\"change\", callback);\n}\n\nfunction getSystemPrefersDark(): boolean {\n return darkMediaQuery?.matches ?? false;\n}\n\nfunction getServerSnapshot(): boolean {\n return false;\n}\n\ninterface ThemeModeProviderProps {\n children: ReactNode;\n mode: ThemeMode;\n onModeChange: (mode: ThemeMode) => void;\n /** When false, auto mode is skipped in the cycle (light↔dark only). Default true. */\n autoModeEnabled?: boolean;\n}\n\nexport function ThemeModeProvider({\n children,\n mode,\n onModeChange,\n autoModeEnabled = true,\n}: ThemeModeProviderProps): React.JSX.Element {\n const systemPrefersDark = useSyncExternalStore(\n subscribeToPrefersColorScheme,\n getSystemPrefersDark,\n getServerSnapshot,\n );\n\n const systemMode: DisplayMode = systemPrefersDark ? \"dark\" : \"light\";\n\n const displayMode: DisplayMode = mode === \"auto\" ? systemMode : mode;\n\n const cycleMode = useCallback(() => {\n if (autoModeEnabled) {\n // Toggle displayed mode. If target matches system preference, use \"auto\".\n const target: DisplayMode = displayMode === \"light\" ? \"dark\" : \"light\";\n onModeChange(target === systemMode ? \"auto\" : target);\n } else {\n // light ↔ dark\n onModeChange(mode === \"light\" ? \"dark\" : \"light\");\n }\n }, [mode, displayMode, systemMode, onModeChange, autoModeEnabled]);\n\n const dataAttribute = getThemeModeAttribute(mode);\n\n const value = useMemo(\n () => ({\n mode,\n displayMode,\n setMode: onModeChange,\n autoModeEnabled,\n cycleMode,\n dataAttribute,\n }),\n [\n mode,\n displayMode,\n onModeChange,\n autoModeEnabled,\n cycleMode,\n dataAttribute,\n ],\n );\n\n return (\n <ThemeModeContext.Provider value={value}>\n {children}\n </ThemeModeContext.Provider>\n );\n}\n\n/** Access the current theme mode, setter, and cycle helper. Must be used within a `ThemeModeProvider`. */\nexport function useThemeMode(): ThemeModeContextValue {\n const ctx = useContext(ThemeModeContext);\n if (!ctx) {\n throw new Error(\"useThemeMode must be used within a ThemeModeProvider\");\n }\n return ctx;\n}\n\n/** Maps a ThemeMode to the value for `data-theme-mode`. Returns undefined for \"auto\". */\nexport function getThemeModeAttribute(mode: ThemeMode): string | undefined {\n return mode === \"auto\" ? undefined : mode;\n}\n","/**\n * System navigation items for portal apps\n * These are pre-built screens that cannot be edited or deleted in the builder.\n * They are handled by custom code (slugLibrary) rather than builder screens.\n */\n\nimport type { NavigationItem } from \"../types/navigation\";\n\nexport const SYSTEM_NAVIGATION_SLUGS = [\n \"app-download\",\n \"contacts\",\n \"account\",\n \"messages\",\n \"my-site\",\n \"orders\",\n \"profile\",\n \"subscriptions\",\n // \"share/enrollments\",\n \"share/media\",\n \"share/pages\",\n \"share/playlists\",\n \"share/products\",\n \"shop\",\n // \"upgrade\",\n] as const;\n\nexport type SystemNavigationSlug = (typeof SYSTEM_NAVIGATION_SLUGS)[number];\n\nexport type SystemNavigationItem = Omit<NavigationItem, \"children\">;\n\n/**\n * Slugs hidden from the quicklinks/shortcuts menu.\n * These screens still exist and are navigable, but don't appear in the grid.\n */\nexport const QUICKLINKS_HIDDEN_SLUGS: ReadonlySet<string> =\n new Set<SystemNavigationSlug>([\"app-download\"]);\n\n/**\n * Slugs restricted to rep (non-customer) users.\n * Customers will not see these in navigation and cannot access these routes.\n */\nexport const REP_ONLY_SLUGS: ReadonlySet<string> =\n new Set<SystemNavigationSlug>([\"messages\", \"my-site\"]);\n\n/**\n * Check if a slug is restricted to rep users only.\n * Handles both exact matches and prefix matches (e.g. \"contacts/123\").\n */\nexport function isRepOnlySlug(slug: string | undefined | null): boolean {\n if (!slug) return false;\n const normalized = slug.startsWith(\"/\") ? slug.slice(1) : slug;\n if (REP_ONLY_SLUGS.has(normalized)) return true;\n for (const repSlug of REP_ONLY_SLUGS) {\n if (normalized.startsWith(repSlug + \"/\")) return true;\n }\n return false;\n}\n\nexport const SYSTEM_NAVIGATION_ITEMS: Record<\n SystemNavigationSlug,\n SystemNavigationItem\n> = {\n \"app-download\": {\n slug: \"app-download\",\n label: \"App Download\",\n icon: \"mobile\",\n section: \"User\",\n },\n contacts: {\n slug: \"contacts\",\n label: \"Contacts\",\n icon: \"circle-user\",\n section: \"User\",\n },\n messages: {\n slug: \"messages\",\n label: \"Messaging\",\n icon: \"message\",\n section: \"User\",\n },\n \"my-site\": {\n slug: \"my-site\",\n label: \"My Site\",\n icon: \"globe\",\n section: \"Shareables\",\n },\n orders: {\n slug: \"orders\",\n label: \"Orders\",\n icon: \"package-open\",\n section: \"User\",\n },\n profile: {\n slug: \"profile\",\n label: \"Profile\",\n icon: \"user\",\n section: \"User\",\n },\n account: {\n slug: \"profile\",\n label: \"Account\",\n icon: \"user\",\n section: \"User\",\n },\n // \"share/enrollments\": {\n // slug: \"share/enrollments\",\n // label: \"Enrollments\",\n // icon: \"graduation-cap\",\n // section: \"Shareables\",\n // },\n \"share/media\": {\n slug: \"share/media\",\n label: \"Media\",\n icon: \"file-video\",\n section: \"Shareables\",\n },\n \"share/pages\": {\n slug: \"share/pages\",\n label: \"Pages\",\n icon: \"file-lines\",\n section: \"Shareables\",\n },\n \"share/playlists\": {\n slug: \"share/playlists\",\n label: \"Playlists\",\n icon: \"list-music\",\n section: \"Shareables\",\n },\n \"share/products\": {\n slug: \"share/products\",\n label: \"Products\",\n icon: \"box\",\n section: \"Shareables\",\n },\n shop: {\n slug: \"shop\",\n label: \"Shop\",\n icon: \"store\",\n section: \"User\",\n },\n subscriptions: {\n slug: \"subscriptions\",\n label: \"Subscriptions\",\n icon: \"arrows-repeat\",\n section: \"User\",\n },\n // upgrade: {\n // slug: \"upgrade\",\n // label: \"Upgrade\",\n // icon: \"arrow-up-from-bracket\",\n // section: \"User\",\n // },\n} as const;\n\n/**\n * Get the default system navigation items for a new portal app.\n * These items have no screen_id - they're handled by the slugLibrary.\n */\nexport function getDefaultSystemNavigationItems(): SystemNavigationItem[] {\n return Object.values(SYSTEM_NAVIGATION_ITEMS);\n}\n\n/**\n * Check if a navigation item is a system item that doesn't require a screen_id.\n * Used by RepApp to skip screen validation for these items.\n */\nexport function isSystemNavigationItem(\n slug?: string | null,\n): slug is SystemNavigationSlug {\n if (!slug) return false;\n return SYSTEM_NAVIGATION_SLUGS.includes(slug as SystemNavigationSlug);\n}\n\n/**\n * Get icon name for a navigation item by slug.\n */\nexport function getNavigationItemIcon(slug?: string): string | undefined {\n if (!slug) return undefined;\n const systemItem = SYSTEM_NAVIGATION_ITEMS[slug as SystemNavigationSlug];\n return systemItem?.icon;\n}\n\n/**\n * Get system navigation items grouped by section.\n */\nexport function getSystemNavigationBySection(): Record<\n string,\n SystemNavigationItem[]\n> {\n const sections: Record<string, SystemNavigationItem[]> = {};\n const seenSlugs = new Set<string>();\n for (const item of Object.values(SYSTEM_NAVIGATION_ITEMS)) {\n if (item.slug && seenSlugs.has(item.slug)) continue;\n if (item.slug) seenSlugs.add(item.slug);\n if (item.slug && QUICKLINKS_HIDDEN_SLUGS.has(item.slug)) continue;\n const section = item.section || \"Other\";\n if (!sections[section]) {\n sections[section] = [];\n }\n sections[section].push(item);\n }\n return sections;\n}\n\n/**\n * Normalize a navigation slug by stripping a leading slash.\n */\nexport function normalizeSlug(slug: string | undefined): string {\n if (!slug) return \"\";\n return slug.startsWith(\"/\") ? slug.slice(1) : slug;\n}\n","import {\n SYSTEM_NAVIGATION_ITEMS,\n type SystemNavigationSlug,\n} from \"./system-navigation-items\";\nimport type { NavigationItem } from \"../types/navigation\";\n\n/**\n * Build a NavigationItem from a system navigation slug.\n * Icons and labels come from SYSTEM_NAVIGATION_ITEMS (single source of truth).\n */\nfunction systemNavItem(slug: SystemNavigationSlug): NavigationItem {\n const item = SYSTEM_NAVIGATION_ITEMS[slug];\n return {\n slug: item.slug,\n label: item.label,\n icon: item.icon,\n children: [],\n };\n}\n\nfunction sectionHeader(label: string): NavigationItem {\n return { label, children: [] };\n}\n\n/**\n * Returns the default navigation items for a portal app when no\n * API data is available. All icons/labels derive from\n * SYSTEM_NAVIGATION_ITEMS so they can never drift.\n */\nexport function getDefaultNavigation(): NavigationItem[] {\n return [\n sectionHeader(\"We Commerce\"),\n systemNavItem(\"shop\"),\n systemNavItem(\"messages\"),\n systemNavItem(\"contacts\"),\n systemNavItem(\"account\"),\n sectionHeader(\"Marketing Assets\"),\n systemNavItem(\"share/products\"),\n ];\n}\n","\"use client\";\n\nimport type React from \"react\";\nimport { PanelLeft } from \"lucide-react\";\nimport { useSidebar } from \"./sidebar\";\nimport { useScreenHeaderContext } from \"./ScreenHeaderContext\";\n\nexport interface ScreenHeaderProps {\n title?: string;\n}\n\nexport function ScreenHeader({\n title,\n}: ScreenHeaderProps): React.JSX.Element | null {\n const { toggleSidebar, isMobile } = useSidebar();\n const { actions, breadcrumbs } = useScreenHeaderContext();\n\n if (!title && !breadcrumbs) return null;\n\n return (\n <div className=\"border-border bg-background sticky top-0 z-30 flex flex-row items-center border-b px-4 py-3 md:px-6\">\n {!isMobile && (\n <>\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"text-muted-foreground hover:text-foreground -ml-1 inline-flex items-center justify-center rounded-md p-1\"\n aria-label=\"Toggle Sidebar\"\n >\n <PanelLeft className=\"size-4\" />\n </button>\n <div className=\"bg-border mx-2 h-4 w-px\" />\n </>\n )}\n {breadcrumbs ? (\n <div className=\"min-w-0 flex-1\">{breadcrumbs}</div>\n ) : (\n <h1 className=\"text-foreground text-lg font-semibold\">{title}</h1>\n )}\n {actions && (\n <div className=\"ml-auto flex items-center gap-2\">{actions}</div>\n )}\n </div>\n );\n}\n","import type React from \"react\";\nimport type { LucideIcon } from \"lucide-react\";\nimport {\n Bell,\n Box,\n Boxes,\n Briefcase,\n Calendar,\n CircleUser,\n Compass,\n ContactRound,\n File,\n FileText,\n FileVideo,\n Folder,\n FolderOpen,\n Globe,\n GraduationCap,\n Heart,\n House,\n Image,\n LayoutGrid,\n ListMusic,\n Mail,\n MessageCircle,\n MessageSquare,\n PackageOpen,\n Repeat,\n Search,\n Settings,\n ShoppingCart,\n Star,\n Store,\n User,\n UserCog,\n Users,\n} from \"lucide-react\";\n\nconst ICON_MAP: Record<string, LucideIcon> = {\n \"address-card\": ContactRound,\n \"arrows-repeat\": Repeat,\n bell: Bell,\n box: Box,\n \"boxes-stacked\": Boxes,\n briefcase: Briefcase,\n calendar: Calendar,\n \"cart-shopping\": ShoppingCart,\n \"circle-user\": CircleUser,\n comment: MessageCircle,\n compass: Compass,\n envelope: Mail,\n file: File,\n \"file-lines\": FileText,\n \"file-video\": FileVideo,\n folder: Folder,\n \"folder-open\": FolderOpen,\n gear: Settings,\n globe: Globe,\n \"graduation-cap\": GraduationCap,\n heart: Heart,\n house: House,\n image: Image,\n \"list-music\": ListMusic,\n \"magnifying-glass\": Search,\n message: MessageSquare,\n \"package-open\": PackageOpen,\n star: Star,\n store: Store,\n \"table-cells-large\": LayoutGrid,\n user: User,\n \"user-gear\": UserCog,\n users: Users,\n};\n\ninterface RepIconProps {\n name: string;\n className?: string;\n}\n\nexport function RepIcon({ name, className }: RepIconProps): React.JSX.Element {\n const Icon = ICON_MAP[name] ?? File;\n return <Icon className={className} />;\n}\n","/**\n * Utility functions for managing navigation state in localStorage\n */\n\nconst STORAGE_PREFIX = \"portal-app-last-tab\";\n\n/**\n * Gets the localStorage key for a specific app and top-level section\n */\nfunction getStorageKey(appDefinitionId: number, topLevelSlug: string): string {\n return `${STORAGE_PREFIX}-${appDefinitionId}-${topLevelSlug}`;\n}\n\n/**\n * Retrieves the last visited tab slug for a given section\n */\nexport function getLastVisitedTab(\n appDefinitionId: number,\n topLevelSlug: string,\n): string | null {\n if (typeof window === \"undefined\") return null;\n\n try {\n const key = getStorageKey(appDefinitionId, topLevelSlug);\n return localStorage.getItem(key);\n } catch (error) {\n console.warn(\"Failed to read from localStorage:\", error);\n return null;\n }\n}\n\n/**\n * Stores the last visited tab slug for a given section\n */\nexport function setLastVisitedTab(\n appDefinitionId: number,\n topLevelSlug: string,\n tabSlug: string,\n): void {\n if (typeof window === \"undefined\") return;\n\n try {\n const key = getStorageKey(appDefinitionId, topLevelSlug);\n localStorage.setItem(key, tabSlug);\n } catch (error) {\n console.warn(\"Failed to write to localStorage:\", error);\n }\n}\n\n/**\n * Clears the last visited tab for a given section\n */\nexport function clearLastVisitedTab(\n appDefinitionId: number,\n topLevelSlug: string,\n): void {\n if (typeof window === \"undefined\") return;\n\n try {\n const key = getStorageKey(appDefinitionId, topLevelSlug);\n localStorage.removeItem(key);\n } catch (error) {\n console.warn(\"Failed to remove from localStorage:\", error);\n }\n}\n","import type { NavigationItem } from \"../types/navigation\";\nimport { normalizeSlug } from \"./system-navigation-items\";\nimport { getLastVisitedTab } from \"./navigation-storage\";\n\n/**\n * Helper function to determine if the current route is within a top-level section\n */\nexport function isInSection(\n topLevelItem: NavigationItem,\n currentRoute: string,\n): boolean {\n const normalizedCurrentRoute = normalizeSlug(currentRoute);\n\n if (\n (!topLevelItem.children || topLevelItem.children.length <= 0) &&\n topLevelItem.slug\n ) {\n const normalizedItemSlug = normalizeSlug(topLevelItem.slug);\n if (normalizedItemSlug === normalizedCurrentRoute) {\n return true;\n }\n } else {\n return topLevelItem.children.some((child: NavigationItem) => {\n const normalizedChildSlug = normalizeSlug(child.slug);\n return normalizedChildSlug === normalizedCurrentRoute;\n });\n }\n\n return false;\n}\n\n/**\n * Get the target slug when clicking a top-level navigation item\n */\nexport function getNavigationTarget(\n item: NavigationItem,\n appDefinitionId: number,\n): string | null {\n // If it has children, it's always a section parent — navigate to a child\n if (item.children && item.children.length > 0) {\n // Try to get the last visited tab from localStorage (only if parent has a slug for the key)\n if (item.slug) {\n const lastVisitedSlug = getLastVisitedTab(appDefinitionId, item.slug);\n\n // If we have a last visited tab and it exists in the children, use it\n if (lastVisitedSlug) {\n const normalizedLastVisited = normalizeSlug(lastVisitedSlug);\n const childExists = item.children.some((child: NavigationItem) => {\n const normalizedChildSlug = normalizeSlug(child.slug);\n return normalizedChildSlug === normalizedLastVisited;\n });\n if (childExists) {\n return normalizedLastVisited;\n }\n }\n }\n\n // Default to the first child's slug\n const firstChild = item.children[0];\n if (firstChild?.slug) {\n return normalizeSlug(firstChild.slug);\n }\n\n return null;\n }\n\n // If it's a leaf node with a screen, return its slug directly (normalized)\n if (item.screen_id && item.slug) {\n return normalizeSlug(item.slug);\n }\n\n // If it's a leaf node with just a slug (system nav items like account, messages, etc.)\n if (item.slug) {\n return normalizeSlug(item.slug);\n }\n\n return null;\n}\n","import * as React from \"react\";\nimport { Ellipsis, X } from \"lucide-react\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport {\n isInSection,\n getNavigationTarget,\n} from \"@fluid-app/portal-core/navigation/utils\";\nimport type { NavigationItem } from \"../types/navigation\";\n\ninterface SdkBottomNavProps {\n navItems: NavigationItem[];\n currentSlug: string;\n onNavigate: (slug: string) => void;\n appDefinitionId?: number;\n maxVisibleItems?: number;\n}\n\nexport function SdkBottomNav({\n navItems,\n currentSlug,\n onNavigate,\n appDefinitionId = 0,\n maxVisibleItems = 6,\n}: SdkBottomNavProps): React.JSX.Element | null {\n const { isMobile, useBottomNav } = useSidebar();\n const [moreOpen, setMoreOpen] = React.useState(false);\n\n if (!isMobile || !useBottomNav) return null;\n\n const navigableItems = navItems\n .filter((item) => !item.parent_id)\n .filter((item) => item.slug || (item.children && item.children.length > 0));\n\n const hasOverflow = navigableItems.length > maxVisibleItems;\n const visibleItems = hasOverflow\n ? navigableItems.slice(0, maxVisibleItems - 1)\n : navigableItems;\n const overflowItems = hasOverflow\n ? navigableItems.slice(maxVisibleItems - 1)\n : [];\n\n const handleItemClick = (item: NavigationItem) => {\n const target = getNavigationTarget(item, appDefinitionId);\n if (target) onNavigate(target);\n setMoreOpen(false);\n };\n\n return (\n <>\n <nav className=\"border-border bg-sidebar fixed right-0 bottom-0 left-0 z-40 flex h-16 items-end justify-around border-t pb-[env(safe-area-inset-bottom)]\">\n {visibleItems.map((item) => {\n const isActive = isInSection(item, currentSlug);\n return (\n <button\n key={item.id ?? item.slug ?? item.label}\n type=\"button\"\n onClick={() => handleItemClick(item)}\n className={`flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-[10px] font-medium transition-colors ${\n isActive ? \"text-primary\" : \"text-muted-foreground\"\n }`}\n >\n {item.icon ? (\n <RepIcon name={item.icon} className=\"size-5\" />\n ) : (\n <span className=\"size-5\" />\n )}\n <span className=\"max-w-[72px] truncate\">{item.label}</span>\n </button>\n );\n })}\n\n {hasOverflow && (\n <button\n type=\"button\"\n onClick={() => setMoreOpen(true)}\n className={`flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-[10px] font-medium transition-colors ${\n overflowItems.some((item) => isInSection(item, currentSlug))\n ? \"text-primary\"\n : \"text-muted-foreground\"\n }`}\n >\n <Ellipsis className=\"size-5\" />\n <span>More</span>\n </button>\n )}\n </nav>\n\n {moreOpen && (\n <div className=\"fixed inset-0 z-50 flex flex-col\">\n <div\n className=\"flex-1 bg-black/50\"\n onClick={() => setMoreOpen(false)}\n aria-hidden=\"true\"\n />\n <div className=\"bg-sidebar rounded-t-2xl pb-[env(safe-area-inset-bottom)]\">\n <div className=\"flex items-center justify-between px-4 pt-4 pb-2\">\n <span className=\"text-foreground text-sm font-semibold\">\n More\n </span>\n <button\n type=\"button\"\n onClick={() => setMoreOpen(false)}\n className=\"text-muted-foreground hover:bg-sidebar-accent flex items-center justify-center rounded-full p-1\"\n aria-label=\"Close\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n <div className=\"px-2 pb-4\">\n {overflowItems.map((item) => {\n const isActive = isInSection(item, currentSlug);\n return (\n <button\n key={item.id ?? item.slug ?? item.label}\n type=\"button\"\n onClick={() => handleItemClick(item)}\n className={`flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors ${\n isActive\n ? \"bg-sidebar-primary text-sidebar-primary-foreground\"\n : \"text-sidebar-foreground hover:bg-sidebar-accent\"\n }`}\n >\n {item.icon && (\n <RepIcon name={item.icon} className=\"size-5\" />\n )}\n <span>{item.label}</span>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n","/**\n * Company-scoped query key factory for TanStack Query.\n *\n * In portal-tenant, each tenant is a single company, so query keys are\n * returned unscoped. The `createCompanyQueryKey` utility is preserved for\n * potential future multi-company support.\n */\n\nimport { useCallback } from \"react\";\n\n/**\n * Create a company-scoped query key by prepending [\"company\", companyId].\n *\n * @param companyId - The company ID\n * @param baseKey - The base query key segments (e.g. [\"fluid\", \"profile\"])\n * @returns A tuple like [\"company\", 42, \"fluid\", \"profile\"]\n */\nexport function createCompanyQueryKey(\n companyId: number,\n ...baseKey: readonly string[]\n): readonly [\"company\", number, ...string[]] {\n return [\"company\", companyId, ...baseKey] as const;\n}\n\n/**\n * Hook that returns a `scopeKey` function.\n *\n * In portal-tenant, each tenant is a single company, so keys are\n * returned unscoped (no company prefix).\n */\nexport function useCompanyScopedQueryKey(): {\n readonly companyId: number | undefined;\n readonly scopeKey: <T extends readonly string[]>(\n baseKey: T,\n ) => readonly (string | number)[];\n} {\n const scopeKey = useCallback(\n <T extends readonly string[]>(baseKey: T): readonly (string | number)[] => {\n return baseKey;\n },\n [],\n );\n\n return { companyId: undefined, scopeKey } as const;\n}\n","/**\n * Screen Transforms\n * Convert FluidOS API screen objects to ScreenDefinition format.\n *\n * Extracted from:\n * - apps/fluid-admin/networking/app-builder/app-screens/types.ts\n * - apps/fluid-admin/networking/reps/screens.api.ts\n */\n\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type { ScreenDefinition } from \"@fluid-app/portal-core/types\";\n\n/** Raw screen from the FluidOS API */\nexport interface RawApiScreen {\n id: number | string;\n definition_id?: number | string;\n name?: string | null;\n slug?: string | null;\n component_tree?: unknown;\n}\n\n/**\n * Normalize component_tree to always be an array.\n * The API stores component_tree as a hash (object), but the frontend expects an array.\n */\nexport function normalizeComponentTree(componentTree: unknown): WidgetSchema[] {\n if (!componentTree) return [];\n if (Array.isArray(componentTree)) return componentTree as WidgetSchema[];\n if (typeof componentTree === \"object\") {\n return [componentTree as WidgetSchema];\n }\n return [];\n}\n\n/**\n * Convert a raw FluidOS screen to ScreenDefinition.\n * Normalizes component_tree and converts string IDs to numbers.\n */\nexport function toScreenDefinition(screen: RawApiScreen): ScreenDefinition {\n return {\n id: Number(screen.id),\n slug: screen.slug ?? \"\",\n name: screen.name ?? \"\",\n component_tree: normalizeComponentTree(screen.component_tree),\n };\n}\n","/**\n * Navigation Transforms\n * Convert FluidOS API navigation items to NavigationItem format.\n *\n * Extracted from:\n * - apps/fluid-admin/networking/app-builder/app-navigation-items/types.ts\n * - apps/fluid-admin/networking/reps/screens.api.ts\n */\n\nimport type { NavigationItem } from \"@fluid-app/portal-core/types\";\nimport type { FluidOsApiNavigationItem } from \"@fluid-app/portal-core/fluidos-api\";\n\n/** Raw navigation item from the FluidOS API. */\nexport type RawApiNavigationItem = FluidOsApiNavigationItem;\n\n/**\n * Convert a raw FluidOS navigation item to NavigationItem.\n * Recursively transforms children and sorts by position.\n */\nexport function toNavigationItem(item: RawApiNavigationItem): NavigationItem {\n const children = (item.children ?? [])\n .map(toNavigationItem)\n .sort((a, b) => (a.position ?? 0) - (b.position ?? 0));\n\n return {\n id: Number(item.id),\n label: item.label ?? \"Untitled\",\n // Use conditional spread for optional properties (exactOptionalPropertyTypes)\n ...(item.slug != null ? { slug: String(item.slug) } : {}),\n ...(item.icon != null ? { icon: String(item.icon) } : {}),\n ...(item.screen_id != null ? { screen_id: Number(item.screen_id) } : {}),\n ...(item.parent_id != null ? { parent_id: Number(item.parent_id) } : {}),\n ...(item.source != null ? { source: item.source } : {}),\n position: item.position ?? 0,\n children,\n };\n}\n","/**\n * Data Transforms\n * Convert FluidOS API responses to RepAppData format.\n *\n * This is the main entry point for all transforms used by the SDK client\n * and hooks when fetching from the fluidos API.\n */\n\nexport {\n transformThemes,\n buildThemeDefinition,\n getActiveThemeId,\n type RawApiTheme,\n} from \"@fluid-app/portal-core/theme\";\n\nexport {\n normalizeComponentTree,\n toScreenDefinition,\n type RawApiScreen,\n} from \"./screen-transforms\";\n\nexport {\n toNavigationItem,\n type RawApiNavigationItem,\n} from \"./navigation-transforms\";\n\nimport type { AppManifestResponse } from \"@fluid-app/portal-core/app-definition-types\";\nimport type { RepAppData, RepAppManifest } from \"@fluid-app/portal-core/types\";\nimport {\n transformThemes,\n getActiveThemeId,\n type RawApiTheme,\n} from \"@fluid-app/portal-core/theme\";\nimport { toScreenDefinition, type RawApiScreen } from \"./screen-transforms\";\nimport {\n toNavigationItem,\n type RawApiNavigationItem,\n} from \"./navigation-transforms\";\n\n/**\n * Raw manifest shape consumed by the transform pipeline.\n *\n * A structural superset of `AppManifestResponse` that also accommodates\n * the legacy `RepAppData` fixtures produced by\n * `packages/cli/portal/src/vite-plugin/build-manifest.ts` in dev mode.\n * Fields that are optional here are either (a) never emitted by\n * `/api/app/manifest` or (b) emitted only by the dev-mode fixture. In both\n * cases `transformManifestToRepAppData` supplies `?? fallback` defaults.\n */\nexport interface RawManifestResponse {\n manifest: {\n definition_id?: number;\n published_version?: number;\n screens?: RawApiScreen[];\n profile?: {\n name?: string;\n definition_id?: number;\n themes?: RawApiTheme[];\n navigation?: {\n id?: number;\n name?: string;\n definition_id?: number;\n navigation_items?: RawApiNavigationItem[];\n };\n mobile_navigation?: {\n id?: number;\n name?: string;\n definition_id?: number;\n navigation_items?: RawApiNavigationItem[];\n };\n };\n };\n}\n\n/**\n * Convert an `AppManifestResponse` into the `RawManifestResponse` shape\n * expected by the transform pipeline. `AppManifestResponse` is structurally\n * assignable to `RawManifestResponse`, so this is a runtime-only guard that\n * rejects empty payloads.\n */\nexport function toRawManifest(\n response: AppManifestResponse,\n): RawManifestResponse {\n if (!response.manifest) {\n throw new Error(\"Portal BFF returned empty manifest\");\n }\n return response;\n}\n\n/**\n * Transform a raw FluidOS manifest API response into RepAppData.\n *\n * Handles:\n * - Theme transformation (legacy and new formats)\n * - Screen normalization (component_tree array wrapping)\n * - Navigation item transformation (recursive with position sorting)\n */\nexport function transformManifestToRepAppData(\n response: RawManifestResponse,\n): RepAppData {\n const manifest = response.manifest;\n const rawProfile = manifest.profile;\n\n const rawThemes: RawApiTheme[] = Array.isArray(rawProfile?.themes)\n ? rawProfile.themes\n : [];\n\n const screens = (manifest.screens ?? []).map((screen) =>\n toScreenDefinition(screen),\n );\n\n const navigationItems = (rawProfile?.navigation?.navigation_items ?? []).map(\n toNavigationItem,\n );\n\n const nav = rawProfile?.navigation;\n const mobileNav = rawProfile?.mobile_navigation;\n const mobileNavigationItems = (mobileNav?.navigation_items ?? []).map(\n toNavigationItem,\n );\n const activeThemeId = getActiveThemeId(rawThemes);\n const definitionId = manifest.definition_id ?? 0;\n\n return {\n definition_id: definitionId,\n published_version: manifest.published_version ?? 0,\n screens,\n profile: {\n name: rawProfile?.name ?? \"Default\",\n definition_id: rawProfile?.definition_id ?? definitionId,\n themes: transformThemes(rawThemes),\n // Conditional spread for exactOptionalPropertyTypes compliance\n ...(activeThemeId !== undefined ? { activeThemeId } : {}),\n navigation: {\n definition_id: nav?.definition_id ?? definitionId,\n id: nav?.id ?? 0,\n name: nav?.name ?? \"Main Navigation\",\n navigation_items: navigationItems,\n screens,\n },\n ...(mobileNav\n ? {\n mobile_navigation: {\n definition_id: mobileNav.definition_id ?? definitionId,\n id: mobileNav.id ?? 0,\n name: mobileNav.name ?? \"Mobile Navigation\",\n navigation_items: mobileNavigationItems,\n screens,\n },\n }\n : {}),\n },\n };\n}\n\n/**\n * Transform a raw manifest response, unwrapping the `{ manifest }` envelope.\n * Convenience wrapper matching the `RepAppManifest` type.\n */\nexport function transformRawManifest(\n response: RawManifestResponse,\n): RepAppManifest {\n return {\n manifest: transformManifestToRepAppData(response),\n };\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { createPersister } from \"@fluid-app/query-persister\";\nimport { useAppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api-context\";\nimport type { AppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport { transformManifestToRepAppData, toRawManifest } from \"../transforms\";\nimport type { RawManifestResponse } from \"../transforms\";\nimport type { RepAppData } from \"@fluid-app/portal-core/types\";\n\n/**\n * Base query key for full app data (rendered manifest endpoint).\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const APP_DATA_QUERY_KEY = [\"fluid\", \"app\"] as const;\n\n/**\n * Fetch the raw rendered manifest via the portal-tenant BFF adapter.\n * Shared by `useFluidApp` and `useFluidProfile` to avoid drift.\n */\nexport async function fetchRawManifest(\n api: AppDefinitionApi,\n): Promise<RawManifestResponse> {\n const response = await api.fetchManifest();\n return toRawManifest(response);\n}\n\n/**\n * Module-level persister instance (browser only).\n * Created once when the module loads so all calls to useFluidApp share\n * the same IndexedDB connection. Applied at the query level so it works\n * regardless of which QueryClient the app provides.\n */\nconst appDataPersister =\n typeof window !== \"undefined\" && !import.meta.env?.DEV\n ? createPersister()\n : undefined;\n\n/**\n * Hook to fetch the full portal app data from the rendered-manifest endpoint.\n *\n * Returns a `RepAppData` object containing:\n * - `screens` — all screen definitions with normalized component trees\n * - `profile.themes` — fully-transformed ThemeDefinition[] (handles legacy + new formats)\n * - `profile.activeThemeId` — the currently active theme ID\n * - `profile.navigation.navigation_items` — sorted, recursive navigation tree\n *\n * Uses IndexedDB persistence so subsequent page loads hydrate instantly\n * from cache while revalidating in the background. The raw API response\n * (plain JSON) is cached; Color objects are recreated from cache via\n * `select` on every restore — this is fast (CPU only, no network).\n *\n * @example\n * ```tsx\n * function App() {\n * const { data: appData, isLoading } = useFluidApp();\n *\n * if (isLoading) return <Spinner />;\n *\n * return (\n * <AppShell\n * appData={appData}\n * navigation={appData.profile.navigation.navigation_items}\n * />\n * );\n * }\n * ```\n */\nexport function useFluidApp(options?: {\n enabled?: boolean;\n}): UseQueryResult<RepAppData> {\n const appDefinitionApi = useAppDefinitionApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery<\n RawManifestResponse,\n Error,\n RepAppData,\n readonly (string | number)[]\n >({\n queryKey: scopeKey(APP_DATA_QUERY_KEY),\n queryFn: () => fetchRawManifest(appDefinitionApi),\n select: transformManifestToRepAppData,\n ...(appDataPersister && { persister: appDataPersister.persisterFn }),\n ...(options?.enabled !== undefined && { enabled: options.enabled }),\n });\n}\n","import { useEffect } from \"react\";\n\nconst SPIN_STYLE_ID = \"fluid-app-shell-loading-spin\";\n\n/**\n * Inject the spin keyframes style once into the document head.\n */\nfunction ensureSpinStyle(): void {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(SPIN_STYLE_ID)) return;\n\n const style = document.createElement(\"style\");\n style.id = SPIN_STYLE_ID;\n style.textContent = `@keyframes spin { to { transform: rotate(360deg); } }`;\n document.head.appendChild(style);\n}\n\n/**\n * Full-page loading spinner shown while AppShell is fetching app data\n * for the first time. Uses inline styles (not Tailwind) since the theme\n * hasn't loaded yet.\n */\nexport function AppShellLoading(): React.JSX.Element {\n useEffect(() => {\n ensureSpinStyle();\n }, []);\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n backgroundColor: \"#f9fafb\",\n }}\n >\n <div\n style={{\n width: \"40px\",\n height: \"40px\",\n border: \"3px solid #e5e7eb\",\n borderTopColor: \"#3b82f6\",\n borderRadius: \"50%\",\n animation: \"spin 1s linear infinite\",\n }}\n />\n <p\n style={{\n marginTop: \"1rem\",\n color: \"#6b7280\",\n fontSize: \"0.875rem\",\n }}\n >\n Loading...\n </p>\n </div>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { ChevronRight } from \"lucide-react\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport {\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n} from \"@fluid-app/portal-react/shell/sidebar\";\nimport {\n Collapsible,\n CollapsibleTrigger,\n CollapsibleContent,\n} from \"@fluid-app/ui-primitives\";\nimport type { NavigationItem } from \"../types/navigation\";\n\nexport interface CollapsibleNavItemProps {\n item: NavigationItem;\n isActive: boolean;\n currentSlug: string;\n onNavigate: (slug: string) => void;\n}\n\nexport function CollapsibleNavItem({\n item,\n isActive,\n currentSlug,\n onNavigate,\n}: CollapsibleNavItemProps): React.JSX.Element {\n const [open, setOpen] = useState(isActive);\n\n useEffect(() => {\n if (isActive) setOpen(true);\n }, [isActive]);\n\n return (\n <Collapsible\n open={open}\n onOpenChange={setOpen}\n asChild\n className=\"group/collapsible\"\n >\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton>\n {item.icon && <RepIcon name={item.icon} />}\n <span className=\"truncate\">{item.label}</span>\n <ChevronRight className=\"ml-auto size-3 transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => {\n const childSlug = normalizeSlug(child.slug);\n const childIsActive = normalizeSlug(currentSlug) === childSlug;\n\n return (\n <SidebarMenuItem key={child.slug || child.label}>\n <SidebarMenuButton\n isActive={childIsActive}\n onClick={() => onNavigate(childSlug)}\n >\n <RepIcon name={child.icon || \"file\"} className=\"h-3 w-3\" />\n <span>{child.label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n );\n })}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n );\n}\n","import {\n SidebarGroupLabel,\n SidebarMenu,\n SidebarMenuItem,\n SidebarMenuButton,\n} from \"@fluid-app/portal-react/shell/sidebar\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { isInSection } from \"@fluid-app/portal-core/navigation/utils\";\nimport type { NavigationItem } from \"../types/navigation\";\nimport { CollapsibleNavItem } from \"./CollapsibleNavItem\";\n\nexport interface SdkNavigationProps {\n navItems: NavigationItem[];\n currentSlug: string;\n onNavigate: (slug: string) => void;\n}\n\nexport function SdkNavigation({\n navItems,\n currentSlug,\n onNavigate,\n}: SdkNavigationProps): React.JSX.Element {\n return (\n <SidebarMenu>\n {navItems.map((item, index) => {\n // Skip items without slug AND without label\n if (!item.slug && !item.label) return null;\n\n const isActive = isInSection(item, currentSlug);\n const hasChildren = item.children?.length > 0;\n\n // Items with children — collapsible\n if (hasChildren) {\n return (\n <CollapsibleNavItem\n key={item.slug || item.label}\n item={item}\n isActive={isActive}\n currentSlug={currentSlug}\n onNavigate={onNavigate}\n />\n );\n }\n\n // Items without a slug are section headers\n if (!item.slug) {\n return (\n <SidebarGroupLabel key={item.id ?? `section-${index}`}>\n {item.label}\n </SidebarGroupLabel>\n );\n }\n\n // Leaf item — no children\n const itemSlug = normalizeSlug(item.slug);\n\n return (\n <SidebarMenuItem key={item.id ?? itemSlug}>\n <SidebarMenuButton\n isActive={isActive}\n onClick={() => onNavigate(itemSlug)}\n >\n {item.icon && <RepIcon name={item.icon} />}\n <span className=\"truncate\">{item.label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n );\n })}\n </SidebarMenu>\n );\n}\n","import { useState, useCallback } from \"react\";\nimport { X, Moon, Sun, LogOut, Smartphone } from \"lucide-react\";\nimport { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport { useRepUser } from \"@fluid-app/portal-widgets/contexts\";\nimport { useThemeMode } from \"@fluid-app/portal-react/shell/ThemeModeContext\";\n// import { SdkMobileQuickLinksGrid } from \"./SdkMobileQuickLinksGrid\";\n\nexport interface SdkMobileProfileMenuProps {\n onNavigate: (slug: string) => void;\n onLogout?: () => void;\n}\n\nfunction getInitials(name: string | null | undefined): string {\n if (!name) return \"U\";\n const parts = name.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (\n (parts[0]?.[0] ?? \"\") + (parts[parts.length - 1]?.[0] ?? \"\")\n ).toUpperCase();\n }\n return (name[0] ?? \"U\").toUpperCase();\n}\n\nexport function SdkMobileProfileMenu({\n onNavigate,\n onLogout,\n}: SdkMobileProfileMenuProps): React.JSX.Element | null {\n const { isMobile, useBottomNav } = useSidebar();\n const [isOpen, setIsOpen] = useState(false);\n const user = useRepUser();\n const themeMode = useThemeMode();\n\n const handleNavigate = useCallback(\n (slug: string) => {\n setIsOpen(false);\n onNavigate(slug);\n },\n [onNavigate],\n );\n\n if (!isMobile || !useBottomNav) return null;\n\n const initials = getInitials(user?.name);\n\n return (\n <>\n <button\n type=\"button\"\n onClick={() => setIsOpen(true)}\n className=\"bg-background text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex shrink-0 items-center justify-center rounded-full p-1\"\n aria-label=\"Open profile menu\"\n >\n {user?.imageUrl ? (\n <img\n src={user.imageUrl}\n alt={user.name ?? \"User\"}\n className=\"size-8 rounded-full object-cover\"\n />\n ) : (\n <span className=\"flex size-8 items-center justify-center text-xs font-medium\">\n {initials}\n </span>\n )}\n </button>\n\n {isOpen && (\n <div className=\"animate-in fade-in slide-in-from-bottom-4 bg-background fixed inset-0 z-50 flex flex-col duration-200\">\n <div className=\"flex items-center justify-between px-4 py-3\">\n <span className=\"text-foreground text-lg font-semibold\">\n Profile\n </span>\n <button\n type=\"button\"\n onClick={() => setIsOpen(false)}\n className=\"text-muted-foreground rounded-full p-1\"\n aria-label=\"Close profile menu\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"flex-1 overflow-auto px-4 pb-[env(safe-area-inset-bottom)]\">\n {user && (\n <div className=\"border-border flex items-center gap-3 border-b py-4\">\n {user.imageUrl ? (\n <img\n src={user.imageUrl}\n alt={user.name ?? \"User\"}\n className=\"size-10 rounded-full object-cover\"\n />\n ) : (\n <span className=\"bg-muted flex size-10 items-center justify-center rounded-full text-sm font-medium\">\n {initials}\n </span>\n )}\n <div className=\"min-w-0 flex-1\">\n {user.name && (\n <p className=\"text-foreground truncate text-sm font-semibold\">\n {user.name}\n </p>\n )}\n {user.email && (\n <p className=\"text-muted-foreground truncate text-xs\">\n {user.email}\n </p>\n )}\n </div>\n </div>\n )}\n\n <div className=\"border-border border-b py-4\">\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"app-download\")}\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n >\n <Smartphone className=\"size-5\" />\n <span>App Download</span>\n </button>\n </div>\n\n {/* <div className=\"border-border border-b py-4\">\n <SdkMobileQuickLinksGrid onNavigate={handleNavigate} />\n </div> */}\n\n <div className=\"space-y-4 py-4\">\n <button\n type=\"button\"\n onClick={themeMode.cycleMode}\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n >\n {themeMode.mode === \"dark\" ? (\n <Moon className=\"size-5\" />\n ) : (\n <Sun className=\"size-5\" />\n )}\n <span>\n Theme: {themeMode.mode === \"light\" ? \"Light\" : \"Dark\"}\n </span>\n </button>\n\n {onLogout && (\n <button\n type=\"button\"\n onClick={onLogout}\n className=\"text-destructive hover:bg-sidebar-accent flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium\"\n >\n <LogOut className=\"size-5\" />\n <span>Log out</span>\n </button>\n )}\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n","import { useSidebar } from \"@fluid-app/portal-react/shell/sidebar\";\nimport { useThemeMode } from \"@fluid-app/portal-react/shell/ThemeModeContext\";\nimport { Menu, Moon, Sun } from \"lucide-react\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport type { NavigationItem } from \"../types/navigation\";\n// import { QuickLinksDropdown } from \"./QuickLinksDropdown\";\nimport { SdkMobileProfileMenu } from \"./SdkMobileProfileMenu\";\n\nexport interface SdkHeaderProps {\n mobileTabs?: NavigationItem[];\n currentSlug: string;\n onNavigate: (slug: string) => void;\n onLogout?: () => void;\n}\n\nexport function SdkHeader({\n mobileTabs,\n currentSlug,\n onNavigate,\n onLogout,\n}: SdkHeaderProps): React.JSX.Element {\n const sidebar = useSidebar();\n const themeMode = useThemeMode();\n\n const ThemeIcon = themeMode.mode === \"dark\" ? Moon : Sun;\n const isMobileWithBottomNav = sidebar.isMobile && sidebar.useBottomNav;\n\n return (\n <header className=\"bg-sidebar shrink-0\">\n {isMobileWithBottomNav ? (\n <div className=\"flex h-[52px] items-center px-4\">\n <div className=\"text-muted-foreground ml-auto flex flex-none items-center justify-end\">\n <SdkMobileProfileMenu onNavigate={onNavigate} onLogout={onLogout} />\n </div>\n </div>\n ) : (\n <div className=\"flex h-[52px] items-center gap-2 px-6\">\n {/* Mobile hamburger — only show if NOT using bottom nav */}\n {sidebar.isMobile && !sidebar.useBottomNav && (\n <button\n type=\"button\"\n onClick={sidebar.toggleSidebar}\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground mr-2 flex shrink-0 items-center justify-center rounded-md p-2\"\n aria-label=\"Toggle sidebar\"\n >\n <Menu className=\"size-5\" />\n </button>\n )}\n\n {/* Spacer to push actions to the right */}\n <div className=\"flex-1\" />\n\n {/* Quick Links */}\n {/* <QuickLinksDropdown onNavigate={onNavigate} /> */}\n\n {/* Theme toggle */}\n <button\n type=\"button\"\n onClick={themeMode.cycleMode}\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground ml-2 flex shrink-0 items-center justify-center rounded-md p-2\"\n aria-label={`Switch theme (current: ${themeMode.mode})`}\n >\n <ThemeIcon className=\"size-3\" />\n </button>\n </div>\n )}\n\n {/* Mobile child tabs — shown below header when parent has children */}\n {isMobileWithBottomNav && mobileTabs && mobileTabs.length > 0 && (\n <nav className=\"scrollbar-none flex items-center gap-1 overflow-x-auto px-4\">\n {mobileTabs.map((tab) => {\n const tabSlug = normalizeSlug(tab.slug);\n if (!tabSlug) return null;\n\n const isActive = normalizeSlug(currentSlug) === tabSlug;\n\n return (\n <button\n key={tab.id ?? tabSlug}\n type=\"button\"\n onClick={() => onNavigate(tabSlug)}\n className={`border-b-2 px-4 py-2.5 text-sm font-medium whitespace-nowrap transition-colors ${\n isActive\n ? \"border-primary text-foreground\"\n : \"text-muted-foreground hover:border-border hover:text-foreground border-transparent\"\n }`}\n >\n {tab.label}\n </button>\n );\n })}\n </nav>\n )}\n </header>\n );\n}\n","import { useState } from \"react\";\nimport { Building2 } from \"lucide-react\";\n\nexport function CompanyImage({\n src,\n alt,\n size,\n}: {\n size: number;\n src: string;\n alt: string;\n}) {\n const [error, setError] = useState(false);\n\n if (!src || error)\n return (\n <Building2\n style={{ height: size, width: size }}\n className=\"text-muted-foreground/25\"\n />\n );\n\n return (\n <img\n className=\"max-h-8 max-w-8 object-contain\"\n alt={alt}\n src={src}\n width={size}\n height={size}\n onError={() => setError(true)}\n />\n );\n}\n","import type { Company } from \"@fluid-app/company-switcher-core\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { CompanyImage } from \"./CompanyImage\";\n\nexport function CompanyItem({\n logo_url,\n icon_url,\n name,\n compact = false,\n}: Omit<Company, \"id\"> & { compact?: boolean }) {\n const resolvedSrc = icon_url || logo_url || \"\";\n return (\n <>\n <div className=\"flex aspect-square size-8 items-center justify-center rounded-lg\">\n <CompanyImage alt={name} src={resolvedSrc} size={32} />\n </div>\n <div\n className={cn(\n \"grid text-left text-sm leading-tight\",\n compact ? \"flex-shrink-0\" : \"flex-1\",\n )}\n >\n <span className=\"truncate font-semibold\">{name}</span>\n </div>\n </>\n );\n}\n","import { Skeleton } from \"@fluid-app/ui-primitives\";\n\nexport function CompanySwitcherSkeleton({ show }: { show: boolean }) {\n if (!show) return null;\n\n return (\n <div className=\"flex items-center gap-4 p-2\">\n <Skeleton className=\"size-5 shrink-0 rounded-sm bg-current\" />\n <Skeleton className=\"h-4 w-36 bg-current\" />\n </div>\n );\n}\n","import { useStore } from \"../hooks/use-store\";\nimport {\n CompanyItem,\n CompanySwitcherSkeleton,\n} from \"@fluid-app/company-switcher-ui\";\n\n/**\n * Static company display for single-tenant portal.\n * Shows logo + name in the sidebar header. No switching — just branding.\n */\nexport function SdkCompanySwitcher(): React.JSX.Element | null {\n const { data: store, isLoading } = useStore();\n\n if (isLoading) {\n return <CompanySwitcherSkeleton show />;\n }\n\n if (!store) {\n return null;\n }\n\n return (\n <div className=\"flex w-full items-center gap-2 rounded-md p-2\">\n <CompanyItem\n logo_url={store.logo_url}\n icon_url={store.icon_url}\n name={store.name || store.subdomain}\n />\n </div>\n );\n}\n","import {\n SYSTEM_NAVIGATION_ITEMS,\n type SystemNavigationSlug,\n} from \"./system-navigation-items\";\n\nexport const ACCOUNT_MANAGE_SLUGS = [\n \"profile\",\n \"orders\",\n \"subscriptions\",\n] as const satisfies readonly SystemNavigationSlug[];\n\nexport type AccountManageSlug = (typeof ACCOUNT_MANAGE_SLUGS)[number];\n\nexport interface AccountManageTab {\n key: AccountManageSlug;\n label: string;\n slug: string;\n}\n\n/** Account manage tabs with labels derived from SYSTEM_NAVIGATION_ITEMS. */\nexport const ACCOUNT_MANAGE_TABS: AccountManageTab[] = ACCOUNT_MANAGE_SLUGS.map(\n (slug) => ({\n key: slug,\n label: SYSTEM_NAVIGATION_ITEMS[slug].label,\n slug,\n }),\n);\n","/**\n * Navigate one step back in the browser history if anything is on the stack;\n * otherwise navigate to the SPA root. Used by fallback screens (error\n * boundary, 404) to give the user a way out without risking a navigation\n * outside the SPA when no prior history exists.\n */\nexport function goBackOrHome(): void {\n if (window.history.length > 1) {\n window.history.back();\n } else {\n window.location.assign(\"/\");\n }\n}\n","import type { ReactNode } from \"react\";\nimport {\n Card,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@fluid-app/ui-primitives\";\n\n/**\n * Internal centered card used for screen-level fallback states (errors,\n * 404s). Shared by `DefaultFallback` and `ScreenNotFound` so the two stay\n * visually consistent. Not exported from the SDK.\n */\nexport function FallbackCard({\n icon,\n title,\n description,\n actions,\n}: {\n readonly icon?: ReactNode;\n readonly title: string;\n readonly description?: ReactNode;\n readonly actions?: ReactNode;\n}): React.JSX.Element {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center p-4\">\n <Card className=\"h-auto w-full max-w-md\">\n <CardHeader className=\"text-center\">\n {icon && (\n <div className=\"text-muted-foreground flex justify-center [&_svg]:size-8\">\n {icon}\n </div>\n )}\n <CardTitle className=\"text-xl\">{title}</CardTitle>\n {description && <CardDescription>{description}</CardDescription>}\n </CardHeader>\n {actions && (\n <CardFooter className=\"justify-center gap-2\">{actions}</CardFooter>\n )}\n </Card>\n </div>\n );\n}\n","import { Button } from \"@fluid-app/ui-primitives\";\nimport { Compass } from \"lucide-react\";\nimport { goBackOrHome } from \"../shell/go-back-or-home\";\nimport { FallbackCard } from \"./FallbackCard\";\n\n/**\n * Rendered by `PageRouter` when the current slug doesn't match any custom\n * page, system screen, or builder screen. This is a true \"not found\" — the\n * portal isn't configured to render anything for this path.\n */\nexport function ScreenNotFound({\n name,\n}: {\n readonly name?: string;\n}): React.JSX.Element {\n return (\n <FallbackCard\n icon={<Compass />}\n title=\"Page not found\"\n description={\n name\n ? `We couldn't find a page for \"${name}\".`\n : \"We couldn't find the page you were looking for.\"\n }\n actions={\n <Button variant=\"default\" onClick={goBackOrHome}>\n Go back\n </Button>\n }\n />\n );\n}\n","import type React from \"react\";\n\n/**\n * Shown when a customer attempts to access a rep-only page via direct URL.\n */\nexport function AccessDeniedScreen(): React.JSX.Element {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"border-border max-w-sm rounded-lg border border-dashed p-8 text-center\">\n <h2 className=\"text-foreground text-xl font-semibold\">Access Denied</h2>\n <p className=\"text-muted-foreground mt-2\">\n You don't have permission to view this page.\n </p>\n <p className=\"text-muted-foreground mt-1 text-sm\">\n This feature is not available for your account type.\n </p>\n </div>\n </div>\n );\n}\n","/**\n * BuilderScreenView — renders a builder screen's component_tree with\n * DataAwareWidget support for data-bound widgets.\n *\n * Uses the shared ScreenRenderer from portal-widgets under the hood,\n * but wraps data-bound widgets with DataAwareWidget from portal-core.\n */\n\nimport React, { memo } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type { ScreenDefinition } from \"@fluid-app/portal-core/types\";\nimport { DataAwareWidget } from \"@fluid-app/portal-react/data-sources/DataAwareWidget\";\nimport { useRegistry } from \"@fluid-app/portal-widgets/contexts\";\n\ninterface WidgetRendererProps {\n widget: WidgetSchema;\n index: number;\n}\n\n/**\n * Renders a single widget, wrapping with DataAwareWidget if it has a dataSource.\n */\nfunction WidgetRenderer({ widget, index }: WidgetRendererProps) {\n const registry = useRegistry();\n const Component = registry[widget.type];\n\n if (!Component) {\n console.warn(\n `[BuilderScreenView] Widget type \"${String(widget.type)}\" not found in registry`,\n );\n return null;\n }\n\n if (widget.dataSource) {\n return (\n <div key={widget.id ?? index} className=\"h-full w-full overflow-x-hidden\">\n <DataAwareWidget widget={widget} Component={Component} />\n </div>\n );\n }\n\n return (\n <div key={widget.id ?? index} className=\"h-full w-full overflow-x-hidden\">\n <Component {...widget.props} />\n </div>\n );\n}\n\nexport interface BuilderScreenViewProps {\n /** The screen definition to render */\n screen: ScreenDefinition;\n /** Additional CSS classes for the wrapper div */\n className?: string;\n}\n\n/**\n * Renders a builder screen's component_tree with full data source support.\n * Widgets with `dataSource` config are automatically wrapped with `DataAwareWidget`\n * which fetches data and merges it with static props before rendering.\n */\nfunction BuilderScreenViewImpl({\n screen,\n className,\n}: BuilderScreenViewProps): React.JSX.Element | null {\n const widgets = screen.component_tree;\n\n if (!widgets || widgets.length === 0) {\n return (\n <div className={className ?? \"h-full w-full\"}>\n <div className=\"text-muted-foreground flex h-full items-center justify-center\">\n <p>This screen has no content yet.</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className={className ?? \"h-full w-full\"}>\n {widgets.map((widget, index) => {\n if (!widget) return null;\n return (\n <WidgetRenderer\n key={widget.id ?? index}\n widget={widget}\n index={index}\n />\n );\n })}\n </div>\n );\n}\n\nexport const BuilderScreenView: React.MemoExoticComponent<\n typeof BuilderScreenViewImpl\n> = memo(BuilderScreenViewImpl);\n","import { PackageOpen, Repeat, User, type LucideIcon } from \"lucide-react\";\nimport {\n ACCOUNT_MANAGE_TABS,\n type AccountManageSlug,\n} from \"@fluid-app/portal-core/navigation/account-manage\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\n\nconst ICON_MAP: Record<AccountManageSlug, LucideIcon> = {\n profile: User,\n orders: PackageOpen,\n subscriptions: Repeat,\n};\n\nconst NAV_ITEMS = ACCOUNT_MANAGE_TABS.map((tab) => ({\n ...tab,\n icon: ICON_MAP[tab.key],\n}));\n\nfunction getActiveTab(slug: string): AccountManageSlug {\n const root = slug.split(\"/\")[0];\n if (root === \"orders\") return \"orders\";\n if (root === \"subscriptions\") return \"subscriptions\";\n return \"profile\";\n}\n\nexport function AccountManageLayout({\n children,\n}: {\n children: React.ReactNode;\n}): React.JSX.Element {\n const { currentSlug, navigate } = useAppNavigation();\n const activeTab = getActiveTab(currentSlug);\n\n return (\n <div className=\"flex flex-col md:flex-row\">\n {/* Mobile: horizontal tab bar */}\n <nav className=\"flex gap-1 overflow-x-auto border-b px-4 py-2 md:hidden\">\n {NAV_ITEMS.map(({ key, slug, label, icon: Icon }) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => navigate(slug)}\n className={`flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium whitespace-nowrap ${\n activeTab === key\n ? \"bg-sidebar-primary text-sidebar-primary-foreground\"\n : \"hover:bg-sidebar-primary hover:text-sidebar-primary-foreground\"\n }`}\n >\n <Icon className=\"h-4 w-4\" />\n {label}\n </button>\n ))}\n </nav>\n\n {/* Desktop: vertical sidebar */}\n <nav className=\"hidden w-48 shrink-0 flex-col gap-1 p-4 md:flex\">\n {NAV_ITEMS.map(({ key, slug, label, icon: Icon }) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => navigate(slug)}\n className={`flex items-center gap-2 rounded-md px-3 py-2 text-left text-sm font-medium ${\n activeTab === key\n ? \"bg-sidebar-primary text-sidebar-primary-foreground\"\n : \"hover:bg-sidebar-primary hover:text-sidebar-primary-foreground\"\n }`}\n >\n <Icon className=\"h-4 w-4\" />\n {label}\n </button>\n ))}\n </nav>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">{children}</div>\n </div>\n );\n}\n","import { lazy, type ComponentType } from \"react\";\n\nconst ProfileScreen = lazy(() =>\n import(\"../screens/ProfileScreen\").then((m) => ({\n default: m.ProfileScreen,\n })),\n);\nconst OrdersScreen = lazy(() =>\n import(\"../screens/OrdersScreen\").then((m) => ({\n default: m.OrdersScreen,\n })),\n);\nconst SubscriptionsScreen = lazy(() =>\n import(\"../screens/SubscriptionsScreen\").then((m) => ({\n default: m.SubscriptionsScreen,\n })),\n);\nconst MessagingScreen = lazy(() =>\n import(\"../screens/MessagingScreen\").then((m) => ({\n default: m.MessagingScreen,\n })),\n);\nconst ContactsScreen = lazy(() =>\n import(\"../screens/ContactsScreen\").then((m) => ({\n default: m.ContactsScreen,\n })),\n);\nconst ShopScreen = lazy(() =>\n import(\"../screens/ShopScreen\").then((m) => ({ default: m.ShopScreen })),\n);\nconst CustomersScreen = lazy(() =>\n import(\"../screens/CustomersScreen\").then((m) => ({\n default: m.CustomersScreen,\n })),\n);\nconst ShareablesScreen = lazy(() =>\n import(\"../screens/ShareablesScreen\").then((m) => ({\n default: m.ShareablesScreen,\n })),\n);\nconst MySiteScreen = lazy(() =>\n import(\"../screens/MySiteScreen\").then((m) => ({\n default: m.MySiteScreen,\n })),\n);\nconst UpgradeScreen = lazy(() =>\n import(\"../screens/UpgradeScreen\").then((m) => ({\n default: m.UpgradeScreen,\n })),\n);\nconst AppDownloadScreen = lazy(() =>\n import(\"../screens/AppDownloadScreen\").then((m) => ({\n default: m.AppDownloadScreen,\n })),\n);\n\nexport const SYSTEM_SLUG_SCREEN_MAP: Record<string, ComponentType> = {\n profile: ProfileScreen,\n orders: OrdersScreen,\n subscriptions: SubscriptionsScreen,\n messages: MessagingScreen,\n contacts: ContactsScreen,\n shop: ShopScreen,\n customers: CustomersScreen,\n \"my-site\": MySiteScreen,\n \"share/products\": ShareablesScreen,\n \"share/product\": ShareablesScreen,\n \"share/media\": ShareablesScreen,\n \"share/playlists\": ShareablesScreen,\n \"share/playlist\": ShareablesScreen,\n \"share/files\": ShareablesScreen,\n \"share/pages\": ShareablesScreen,\n \"share/page\": ShareablesScreen,\n upgrade: UpgradeScreen,\n \"app-download\": AppDownloadScreen,\n};\n\n/**\n * System screens that render even when not in the active navigation.\n * Account-manage destinations (profile, orders, subscriptions) are always\n * reachable so customers can manage their account regardless of nav config.\n */\nexport const ALWAYS_AVAILABLE_SYSTEM_SCREENS: ReadonlySet<ComponentType> =\n new Set([ProfileScreen, OrdersScreen, SubscriptionsScreen]);\n\n/** Pre-sorted keys for greedy prefix matching (longest first). */\nconst SORTED_SCREEN_KEYS = Object.keys(SYSTEM_SLUG_SCREEN_MAP).sort(\n (a, b) => b.length - a.length,\n);\n\n/** Prefix-match a slug against screen map keys, longest match first. */\nexport function findScreenByPrefix(slug: string): ComponentType | undefined {\n for (const key of SORTED_SCREEN_KEYS) {\n if (slug === key || slug.startsWith(key + \"/\")) {\n return SYSTEM_SLUG_SCREEN_MAP[key];\n }\n }\n return undefined;\n}\n","import { Suspense, useMemo, type ComponentType } from \"react\";\nimport {\n isSystemNavigationItem,\n isRepOnlySlug,\n} from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { ACCOUNT_MANAGE_SLUGS } from \"@fluid-app/portal-core/navigation/account-manage\";\nimport type { NavigationItem, ScreenDefinition } from \"../types/navigation\";\nimport { CoreScreenPlaceholder } from \"../screens/CoreScreenPlaceholder\";\nimport { ScreenNotFound } from \"../screens/ScreenNotFound\";\nimport { AccessDeniedScreen } from \"../screens/AccessDeniedScreen\";\nimport { BuilderScreenView } from \"./BuilderScreenView\";\nimport { AccountManageLayout } from \"../account/account-management-layout\";\nimport { useAccount } from \"../hooks/use-account\";\nimport {\n ALWAYS_AVAILABLE_SYSTEM_SCREENS,\n SYSTEM_SLUG_SCREEN_MAP,\n findScreenByPrefix,\n} from \"./system-screen-map\";\n\nconst ACCOUNT_SLUGS = new Set<string>(ACCOUNT_MANAGE_SLUGS);\n\n/**\n * Returns true if any nav slug resolves to the given system screen component.\n * Lets detail routes (e.g. `share/product/:id`) render when their listing\n * slug (`share/products`) is in the nav, since both map to the same screen.\n */\nfunction isSystemScreenCoveredByNav(\n target: ComponentType,\n navSlugs: readonly string[],\n): boolean {\n for (const slug of navSlugs) {\n const navScreen = SYSTEM_SLUG_SCREEN_MAP[slug] ?? findScreenByPrefix(slug);\n if (navScreen === target) return true;\n }\n return false;\n}\n\nexport interface PageRouterProps {\n currentSlug: string;\n currentNavItem?: NavigationItem | undefined;\n customPages?:\n | Record<string, ComponentType<{ slug?: string; params?: string }>>\n | undefined;\n /** Builder screen definitions (from fluidos API) */\n screens?: ScreenDefinition[] | undefined;\n baseSlug: string;\n restParams: string;\n /**\n * Slugs from the active navigation. When provided, system screens only\n * render if they're reachable via the nav (matches the implicit gating\n * builder screens get from being sourced via `appData.screens`). Screens\n * in `ALWAYS_AVAILABLE_SYSTEM_SCREENS` (profile, orders, subscriptions)\n * bypass this check. Omit to render system screens unconditionally.\n */\n navSlugs?: readonly string[] | undefined;\n}\n\nexport function PageRouter({\n currentSlug,\n currentNavItem,\n customPages,\n screens,\n baseSlug,\n restParams,\n navSlugs,\n}: PageRouterProps): React.JSX.Element {\n const { data: account } = useAccount();\n const isCustomer = account?.member_type === \"customer\";\n\n // Build a screen lookup map by ID for O(1) access\n const screenById = useMemo(() => {\n if (!screens || screens.length === 0) return undefined;\n return new Map(screens.map((s) => [s.id, s]));\n }, [screens]);\n\n // Build a screen lookup map by slug for fallback resolution\n const screenBySlug = useMemo(() => {\n if (!screens || screens.length === 0) return undefined;\n return new Map(screens.filter((s) => s.slug).map((s) => [s.slug, s]));\n }, [screens]);\n\n // Resolve builder screen: screen_id first, then slug fallback\n const builderScreen = useMemo(() => {\n if (currentNavItem?.screen_id && screenById) {\n const byId = screenById.get(currentNavItem.screen_id);\n if (byId) return byId;\n }\n if (screenBySlug) {\n return (\n screenBySlug.get(currentSlug) ?? screenBySlug.get(baseSlug) ?? undefined\n );\n }\n return undefined;\n }, [\n currentNavItem?.screen_id,\n screenById,\n screenBySlug,\n currentSlug,\n baseSlug,\n ]);\n\n // 0. Block customer access to rep-only slugs\n if (isCustomer && isRepOnlySlug(currentSlug)) {\n return <AccessDeniedScreen />;\n }\n\n // 1. Custom page match (takes priority over system defaults)\n const ExactCustomPage = customPages?.[currentSlug];\n if (ExactCustomPage) {\n return <ExactCustomPage slug={currentSlug} params={restParams} />;\n }\n\n // 2. Prefix custom page match (base slug with rest params)\n if (baseSlug !== currentSlug) {\n const PrefixCustomPage = customPages?.[baseSlug];\n if (PrefixCustomPage) {\n return <PrefixCustomPage slug={currentSlug} params={restParams} />;\n }\n }\n\n // 3. System navigation item with a dedicated screen component\n // First try exact match on baseSlug, then prefix-match currentSlug\n // against screen map keys (handles detail routes like \"share/product/123\"\n // matching \"share/product\" when the slug isn't a registered nav item).\n const SystemScreen =\n SYSTEM_SLUG_SCREEN_MAP[baseSlug] ?? findScreenByPrefix(currentSlug);\n const systemScreenInNav =\n navSlugs === undefined ||\n (SystemScreen !== undefined &&\n (ALWAYS_AVAILABLE_SYSTEM_SCREENS.has(SystemScreen) ||\n isSystemScreenCoveredByNav(SystemScreen, navSlugs)));\n if (SystemScreen && systemScreenInNav) {\n const content = (\n <Suspense\n fallback={\n <div className=\"flex h-full items-center justify-center\">\n <div className=\"border-primary h-8 w-8 animate-spin rounded-full border-2 border-t-transparent\" />\n </div>\n }\n >\n <SystemScreen />\n </Suspense>\n );\n\n if (ACCOUNT_SLUGS.has(baseSlug)) {\n return <AccountManageLayout>{content}</AccountManageLayout>;\n }\n\n return content;\n }\n\n // 4. System slug without a dedicated screen (account, my-site, share/*)\n if (isSystemNavigationItem(baseSlug)) {\n return <CoreScreenPlaceholder name={currentNavItem?.label ?? baseSlug} />;\n }\n\n // 5. Builder screen (by screen_id or slug match)\n if (builderScreen) {\n return <BuilderScreenView screen={builderScreen} />;\n }\n\n // 6. True \"not found\" — slug didn't match any custom/system/builder screen\n return <ScreenNotFound name={currentNavItem?.label ?? currentSlug} />;\n}\n","import type { NavigationItem } from \"../types/navigation\";\nimport { normalizeSlug } from \"./system-navigation-items\";\n\nexport interface SlugMatch {\n matchedSlug: string;\n rest: string;\n}\n\n/**\n * Extract all slugs from a navigation tree, sorted by segment count descending.\n * Longest slugs first enables greedy prefix matching (e.g. \"share/playlists\"\n * is checked before \"share\").\n */\nexport function collectNavSlugs(items: NavigationItem[]): string[] {\n const slugs: string[] = [];\n\n for (const item of items) {\n if (item.slug) slugs.push(normalizeSlug(item.slug));\n for (const child of item.children ?? []) {\n if (child.slug) slugs.push(normalizeSlug(child.slug));\n }\n }\n\n return [...slugs].sort((a, b) => b.split(\"/\").length - a.split(\"/\").length);\n}\n\n/**\n * Find the longest registered nav slug that is a prefix of `fullSlug`.\n * Uses segment-boundary checking to prevent \"shop\" from matching \"shopping\".\n */\nexport function matchSlugPrefix(\n fullSlug: string,\n navSlugs: string[],\n): SlugMatch | undefined {\n const normalized = normalizeSlug(fullSlug);\n if (!normalized) return undefined;\n\n for (const navSlug of navSlugs) {\n if (normalized === navSlug) {\n return { matchedSlug: navSlug, rest: \"\" };\n }\n if (normalized.startsWith(navSlug + \"/\")) {\n return {\n matchedSlug: navSlug,\n rest: normalized.slice(navSlug.length + 1),\n };\n }\n }\n\n return undefined;\n}\n\n/**\n * Extract the slug portion from a full pathname by stripping the basePath prefix.\n * Returns an empty string when the pathname equals the basePath exactly.\n *\n * Examples:\n * extractSlugFromPathname(\"/contacts/123\", \"/\") → \"contacts/123\"\n * extractSlugFromPathname(\"/portal/contacts\", \"/portal\") → \"contacts\"\n * extractSlugFromPathname(\"/portal\", \"/portal\") → \"\"\n * extractSlugFromPathname(\"/\", \"/\") → \"\"\n */\nexport function extractSlugFromPathname(\n pathname: string,\n basePath: string,\n): string {\n // For root basePath, just strip the leading slash\n if (basePath === \"/\") {\n return pathname.replace(/^\\//, \"\");\n }\n\n // Strip basePath prefix, then strip leading slash from remainder\n if (pathname.startsWith(basePath)) {\n return pathname.slice(basePath.length).replace(/^\\//, \"\");\n }\n\n // Fallback: return pathname without leading slash\n return pathname.replace(/^\\//, \"\");\n}\n\nexport function isSlugInSection(\n item: NavigationItem,\n currentSlug: string,\n navSlugs: string[],\n): boolean {\n const match = matchSlugPrefix(currentSlug, navSlugs);\n const baseSlug = match?.matchedSlug ?? normalizeSlug(currentSlug);\n\n if (normalizeSlug(item.slug) === baseSlug) return true;\n return (\n item.children?.some((child) => normalizeSlug(child.slug) === baseSlug) ??\n false\n );\n}\n","import { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { TriangleAlert } from \"lucide-react\";\nimport { FallbackCard } from \"../screens/FallbackCard\";\nimport { goBackOrHome } from \"./go-back-or-home\";\n\nexport interface AppShellErrorBoundaryProps {\n children: ReactNode;\n /**\n * Invoked every time the boundary catches an error. Fires again on each\n * subsequent crash if `reset()` is called and the underlying issue persists.\n * When provided, the boundary will not log to `console.error` itself —\n * forward to your reporter (e.g. Sentry) inside this callback.\n *\n * @example\n * ```tsx\n * <AppShellErrorBoundary onError={(err, info) => Sentry.captureException(err, { extra: info })}>\n * ```\n */\n onError?: (error: Error, info: ErrorInfo) => void;\n /** Override the default fallback UI. Receives a reset callback. */\n fallback?: (props: { error: Error; reset: () => void }) => ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\n\nexport class AppShellErrorBoundary extends Component<\n AppShellErrorBoundaryProps,\n State\n> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo): void {\n if (this.props.onError) {\n try {\n this.props.onError(error, info);\n } catch (callbackError) {\n // A throwing onError (e.g. misconfigured Sentry transport) must not\n // mask the original crash. Surface both to console as a fallback.\n console.error(\"[portal] onError handler threw:\", callbackError);\n console.error(\"[portal] Original screen crash:\", error, info);\n }\n return;\n }\n console.error(\"[portal] Screen crashed:\", error, info);\n }\n\n reset = (): void => {\n this.setState({ error: null });\n };\n\n override render(): ReactNode {\n const { error } = this.state;\n if (!error) return this.props.children;\n\n if (this.props.fallback) {\n return this.props.fallback({ error, reset: this.reset });\n }\n\n return (\n <FallbackCard\n icon={<TriangleAlert />}\n title=\"Something went wrong\"\n description=\"We hit an unexpected error loading this page.\"\n actions={\n <>\n <Button variant=\"outline\" onClick={this.reset}>\n Try again\n </Button>\n <Button variant=\"default\" onClick={goBackOrHome}>\n Go back\n </Button>\n </>\n }\n />\n );\n }\n}\n","/**\n * useLogout Hook\n *\n * Provides a complete logout function that:\n * 1. Clears all client-side state (query cache, IndexedDB, sessionStorage)\n * 2. Navigates to GET /logout — Rails clears the session and redirects to the Hub\n */\n\nimport { useCallback } from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { deleteDatabase } from \"@fluid-app/query-persister\";\n\nexport interface UseLogoutOptions {\n /** URL to redirect to after logout. Triggers a full page navigation. */\n redirectUrl?: string;\n /** Callback invoked after all state is cleared. Ignored when `redirectUrl` is set. */\n onLogout?: () => void;\n}\n\n/**\n * Hook that returns a `logout` function which clears the server session\n * via `DELETE /logout` and all cached/persisted client state.\n *\n * @example\n * ```tsx\n * const logout = useLogout({ redirectUrl: \"/login\" });\n * <button onClick={logout}>Log out</button>\n * ```\n *\n * @example\n * ```tsx\n * const logout = useLogout({\n * onLogout: () => navigate(\"/signed-out\"),\n * });\n * ```\n */\nexport function useLogout({\n redirectUrl,\n onLogout,\n}: UseLogoutOptions = {}): () => Promise<void> {\n const queryClient = useQueryClient();\n\n const logout = useCallback(async () => {\n // 1. Cancel in-flight requests to prevent cache repopulation\n await queryClient.cancelQueries();\n\n // 2. Clear in-memory TanStack Query cache\n queryClient.clear();\n\n // 3. Clear IndexedDB persisted query cache\n try {\n await deleteDatabase();\n } catch (error) {\n // Non-fatal — continue with logout even if IndexedDB cleanup fails\n console.error(\"[useLogout] Failed to clear IndexedDB cache:\", error);\n }\n\n // 4. Clear sessionStorage — intentionally clears all keys because the\n // portal app owns the full page (not embedded as a micro-frontend).\n try {\n sessionStorage.clear();\n } catch {\n // sessionStorage may be unavailable in some contexts\n }\n\n // 5. Navigate to the server logout endpoint. Rails clears the session\n // cookie and redirects to the Portal Hub company list. A full page\n // navigation lets the browser follow the redirect naturally — no\n // fetch or JSON parsing needed.\n if (redirectUrl) {\n window.location.href = redirectUrl;\n } else if (onLogout) {\n onLogout();\n } else {\n window.location.href = \"/logout\";\n }\n }, [queryClient, redirectUrl, onLogout]);\n\n return logout;\n}\n","import { useCallback, useState } from \"react\";\nimport { LogOut } from \"lucide-react\";\nimport {\n SidebarMenu,\n SidebarMenuItem,\n SidebarMenuButton,\n} from \"@fluid-app/portal-react/shell/sidebar\";\n\nexport interface SdkLogoutButtonProps {\n onLogout: () => Promise<void>;\n}\n\n/**\n * Sidebar footer button that triggers the logout flow.\n * Rendered inside the AppShell sidebar footer slot.\n */\nexport function SdkLogoutButton({\n onLogout,\n}: SdkLogoutButtonProps): React.JSX.Element {\n const [isPending, setIsPending] = useState(false);\n\n const handleClick = useCallback(async () => {\n setIsPending(true);\n try {\n await onLogout();\n } catch (error) {\n console.error(\"[SdkLogoutButton] Logout failed:\", error);\n } finally {\n setIsPending(false);\n }\n }, [onLogout]);\n\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton onClick={handleClick} disabled={isPending}>\n <LogOut className=\"size-4\" />\n <span>{isPending ? \"Logging out\\u2026\" : \"Log out\"}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n );\n}\n","import type { NavigationItem } from \"@fluid-app/portal-core/types\";\nimport {\n isRepOnlySlug,\n type SystemNavigationItem,\n} from \"@fluid-app/portal-core/navigation/system-navigation-items\";\n\n/**\n * Filter navigation items by removing rep-only slugs.\n * Handles nested children: rep-only children are removed, and parents\n * with no remaining children are also removed.\n */\nexport function filterRepOnlyNavItems(\n items: NavigationItem[],\n): NavigationItem[] {\n const result: NavigationItem[] = [];\n\n for (const item of items) {\n // Leaf item with a rep-only slug — skip\n if (!item.children?.length) {\n if (isRepOnlySlug(item.slug)) continue;\n result.push(item);\n continue;\n }\n\n // Parent with a rep-only slug — skip entire group\n if (isRepOnlySlug(item.slug)) continue;\n\n // Recursively filter children\n const filteredChildren = filterRepOnlyNavItems(item.children);\n\n // Drop parent if all children were removed\n if (filteredChildren.length === 0) continue;\n\n result.push({ ...item, children: filteredChildren });\n }\n\n return result;\n}\n\n/**\n * Filter system navigation sections by removing rep-only items.\n * Sections with no remaining items are dropped entirely.\n */\nexport function filterRepOnlySections(\n sections: Record<string, SystemNavigationItem[]>,\n): Record<string, SystemNavigationItem[]> {\n const filtered: Record<string, SystemNavigationItem[]> = {};\n for (const [section, items] of Object.entries(sections)) {\n const allowed = items.filter((item) => !isRepOnlySlug(item.slug));\n if (allowed.length > 0) filtered[section] = allowed;\n }\n return filtered;\n}\n","import {\n useState,\n useEffect,\n useCallback,\n useMemo,\n type ReactNode,\n type ComponentType,\n} from \"react\";\nimport { AppShellLayout } from \"@fluid-app/portal-react/shell/AppShellLayout\";\nimport {\n ThemeModeProvider,\n type ThemeMode,\n} from \"@fluid-app/portal-react/shell/ThemeModeContext\";\nimport { normalizeSlug } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { getDefaultNavigation } from \"@fluid-app/portal-core/navigation/default-navigation\";\nimport { ScreenHeader } from \"@fluid-app/portal-react/shell/ScreenHeader\";\nimport { ScreenHeaderProvider } from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport { SdkBottomNav } from \"./SdkBottomNav\";\nimport type {\n RepAppData,\n ScreenDefinition,\n} from \"@fluid-app/portal-core/types\";\nimport {\n applyTheme,\n getDefaultThemeDefinition,\n removeAllThemes,\n resolveTheme,\n} from \"@fluid-app/portal-core/theme\";\nimport { useFluidApp } from \"../hooks/use-fluid-app\";\nimport type { NavigationItem } from \"../types/navigation\";\nimport { AppShellLoading } from \"./AppShellLoading\";\nimport { SdkNavigation } from \"./SdkNavigation\";\nimport { SdkHeader } from \"./SdkHeader\";\nimport { SdkCompanySwitcher } from \"./SdkCompanySwitcher\";\nimport { PageRouter } from \"./PageRouter\";\nimport {\n collectNavSlugs,\n matchSlugPrefix,\n extractSlugFromPathname,\n} from \"@fluid-app/portal-core/navigation/slug-utils\";\nimport { AppNavigationProvider } from \"./AppNavigationContext\";\nimport { AppShellErrorBoundary } from \"./AppShellErrorBoundary\";\n\nimport { useLogout } from \"../hooks/use-logout\";\nimport { SdkLogoutButton } from \"./SdkLogoutButton\";\nimport { RepUserProvider } from \"@fluid-app/portal-widgets/contexts\";\nimport { Toaster } from \"@fluid-app/ui-primitives\";\nimport { useAccount } from \"../hooks/use-account\";\nimport { filterRepOnlyNavItems } from \"../navigation/filter-nav-items\";\n\nconst THEME_STORAGE_KEY = \"portal-theme-mode\";\n\nfunction getInitialThemeMode(): ThemeMode {\n if (typeof window === \"undefined\") return \"light\";\n const stored = localStorage.getItem(THEME_STORAGE_KEY);\n if (stored === \"light\" || stored === \"dark\") return stored;\n return \"light\";\n}\n\nfunction findFirstNavigableSlug(items: NavigationItem[]): string {\n for (const item of items) {\n if (item.slug) return normalizeSlug(item.slug);\n for (const child of item.children ?? []) {\n if (child.slug) return normalizeSlug(child.slug);\n }\n }\n return \"\";\n}\n\nfunction findCurrentSection(\n items: NavigationItem[],\n slug: string,\n): NavigationItem | undefined {\n const normalized = normalizeSlug(slug);\n for (const item of items) {\n if (normalizeSlug(item.slug) === normalized) return item;\n if (\n item.children?.some((child) => normalizeSlug(child.slug) === normalized)\n ) {\n return item;\n }\n }\n return undefined;\n}\n\nfunction findNavItem(\n items: NavigationItem[],\n slug: string,\n): NavigationItem | undefined {\n const normalized = normalizeSlug(slug);\n for (const item of items) {\n if (normalizeSlug(item.slug) === normalized) return item;\n for (const child of item.children ?? []) {\n if (normalizeSlug(child.slug) === normalized) return child;\n }\n }\n return undefined;\n}\n\nexport interface AppShellProps {\n /** Pre-fetched app data (skips internal useFluidApp call if provided) */\n appData?: RepAppData;\n /** Override navigation items (otherwise derived from appData/API) */\n navigation?: NavigationItem[];\n /** Custom page components keyed by slug */\n customPages?: Record<\n string,\n ComponentType<{ slug?: string; params?: string }>\n >;\n /** Base path for subpath deployments (e.g. \"/portal\"). Default: \"/\" */\n basePath?: string;\n /** Controlled current slug */\n currentSlug?: string;\n /** Navigation callback */\n onNavigate?: (slug: string) => void;\n /** Custom sidebar header slot */\n sidebarHeader?: ReactNode;\n /** Custom sidebar footer slot. When provided, replaces the default logout button. */\n sidebarFooter?: ReactNode;\n /**\n * Callback invoked after the user logs out and all client state has been cleared.\n * If not provided, a default logout button is still rendered, but no post-logout\n * action is taken (consumers should pair this with `logoutRedirectUrl`\n * or provide their own `sidebarFooter`).\n */\n onLogout?: () => void;\n /** URL to redirect to after logout (e.g. \"/login\"). Takes precedence over `onLogout`. */\n logoutRedirectUrl?: string;\n /** Render prop or static children for the content area */\n children?:\n | ReactNode\n | ((props: {\n currentSlug: string;\n currentNavItem: NavigationItem | undefined;\n }) => ReactNode);\n}\n\nexport function AppShell({\n appData: appDataProp,\n navigation: navigationProp,\n customPages,\n basePath = \"/\",\n currentSlug: controlledSlug,\n onNavigate: onNavigateProp,\n sidebarHeader,\n sidebarFooter,\n onLogout,\n logoutRedirectUrl,\n children,\n}: AppShellProps): React.JSX.Element {\n // Normalize basePath: ensure leading slash, no trailing slash\n const normalizedBasePath = useMemo(() => {\n const stripped = basePath.replace(/^\\/|\\/$/g, \"\");\n return stripped ? `/${stripped}` : \"/\";\n }, [basePath]);\n\n // Fetch full app data from the rendered-manifest endpoint\n // (disabled when appData is provided). The response carries\n // `definition_id` directly, so no separate definition fetch is needed.\n const { data: fetchedAppData, isLoading } = useFluidApp({\n enabled: !appDataProp,\n });\n const appData = appDataProp ?? fetchedAppData;\n\n const { data: account } = useAccount();\n const repUser = useMemo(\n () => ({\n name:\n account?.first_name && account?.last_name\n ? `${account.first_name} ${account.last_name}`\n : null,\n email: account?.email ?? null,\n imageUrl: account?.avatar_url ?? null,\n publicId: account?.slug,\n }),\n [\n account?.first_name,\n account?.last_name,\n account?.email,\n account?.avatar_url,\n account?.slug,\n ],\n );\n\n // Resolve the active theme from app data, falling back to the theme-engine\n // default when the manifest has no themes. This guarantees CSS variables\n // are always emitted so the shell renders with proper styling.\n const activeTheme = useMemo(() => {\n const themes = appData?.profile?.themes;\n const activeId = appData?.profile?.activeThemeId;\n if (themes?.length) {\n const matched = activeId\n ? themes.find((t) => t.id === activeId)\n : undefined;\n const first = themes[0];\n if (matched) return matched;\n if (first) return first;\n }\n return getDefaultThemeDefinition();\n }, [appData?.profile?.themes, appData?.profile?.activeThemeId]);\n\n // Apply theme CSS via the shared theme pipeline\n const resolvedTheme = useMemo(() => resolveTheme(activeTheme), [activeTheme]);\n\n useEffect(() => {\n applyTheme(resolvedTheme);\n return () => {\n removeAllThemes();\n };\n }, [resolvedTheme]);\n\n // Mirror data-theme and data-theme-mode onto <html> so that Radix portals\n // (rendered at document.body) inherit the correct CSS custom properties.\n useEffect(() => {\n const root = document.documentElement;\n root.setAttribute(\"data-theme\", activeTheme.id);\n return () => {\n root.removeAttribute(\"data-theme\");\n };\n }, [activeTheme.id]);\n\n // Resolve navigation items\n const navItems = useMemo(() => {\n if (navigationProp) return navigationProp;\n const profileNav = appData?.profile?.navigation?.navigation_items;\n if (profileNav && profileNav.length > 0) return profileNav;\n return getDefaultNavigation();\n }, [navigationProp, appData?.profile?.navigation?.navigation_items]);\n\n // Resolve mobile navigation items (fall back to desktop nav)\n const mobileNavItems = useMemo(() => {\n const mobileNav = appData?.profile?.mobile_navigation?.navigation_items;\n if (mobileNav && mobileNav.length > 0) return mobileNav;\n return navItems;\n }, [appData?.profile?.mobile_navigation?.navigation_items, navItems]);\n\n const isCustomer = account?.member_type === \"customer\";\n\n const filteredNavItems = useMemo(\n () => (isCustomer ? filterRepOnlyNavItems(navItems) : navItems),\n [navItems, isCustomer],\n );\n\n const filteredMobileNavItems = useMemo(\n () => (isCustomer ? filterRepOnlyNavItems(mobileNavItems) : mobileNavItems),\n [mobileNavItems, isCustomer],\n );\n\n // Resolve builder screen definitions\n const screens: ScreenDefinition[] | undefined = appData?.screens;\n\n // Collect all nav slugs for prefix matching (sorted longest-first)\n const navSlugs = useMemo(\n () => collectNavSlugs(filteredNavItems),\n [filteredNavItems],\n );\n\n // Combined desktop + mobile nav slugs for gating system-screen rendering;\n // a slug present in either nav counts as \"in nav\".\n const allNavSlugs = useMemo(() => {\n const mobileSlugs = collectNavSlugs(filteredMobileNavItems);\n return Array.from(new Set([...navSlugs, ...mobileSlugs]));\n }, [navSlugs, filteredMobileNavItems]);\n\n // Theme mode state with localStorage persistence\n const [themeMode, setThemeMode] = useState<ThemeMode>(getInitialThemeMode);\n\n const handleThemeModeChange = useCallback((mode: ThemeMode) => {\n setThemeMode(mode);\n if (typeof window !== \"undefined\") {\n localStorage.setItem(THEME_STORAGE_KEY, mode);\n }\n }, []);\n\n // Mirror data-theme-mode onto <html> so that Radix portals\n // (rendered at document.body) inherit the correct CSS custom properties.\n useEffect(() => {\n const root = document.documentElement;\n const mode = themeMode === \"auto\" ? undefined : themeMode;\n if (mode) {\n root.setAttribute(\"data-theme-mode\", mode);\n } else {\n root.removeAttribute(\"data-theme-mode\");\n }\n return () => {\n root.removeAttribute(\"data-theme-mode\");\n };\n }, [themeMode]);\n\n // Set <meta name=\"theme-color\"> so mobile browser chrome matches the theme\n useEffect(() => {\n let meta = document.querySelector<HTMLMetaElement>(\n 'meta[name=\"theme-color\"]',\n );\n if (!meta) {\n meta = document.createElement(\"meta\");\n meta.name = \"theme-color\";\n document.head.appendChild(meta);\n }\n const metaEl = meta;\n\n const theme = resolvedTheme;\n function update(prefersDark: boolean) {\n const mode =\n themeMode === \"auto\" ? (prefersDark ? \"dark\" : \"light\") : themeMode;\n const color =\n mode === \"dark\" ? theme.dark.muted.base : theme.light.muted.base;\n const hex = color.toString();\n metaEl.content = hex;\n document.body.style.backgroundColor = hex;\n }\n\n const mql = window.matchMedia(\"(prefers-color-scheme: dark)\");\n update(mql.matches);\n\n if (themeMode === \"auto\") {\n const handler = (e: MediaQueryListEvent) => update(e.matches);\n mql.addEventListener(\"change\", handler);\n return () => {\n mql.removeEventListener(\"change\", handler);\n metaEl.remove();\n document.body.style.backgroundColor = \"\";\n };\n }\n\n return () => {\n metaEl.remove();\n document.body.style.backgroundColor = \"\";\n };\n }, [resolvedTheme, themeMode]);\n\n // Path-based routing for uncontrolled mode\n const [pathSlug, setPathSlug] = useState<string>(() => {\n if (typeof window === \"undefined\") return \"\";\n return extractSlugFromPathname(\n window.location.pathname,\n normalizedBasePath,\n );\n });\n\n // Sync initial path when navItems load — redirect to first nav slug if at root\n useEffect(() => {\n if (controlledSlug !== undefined) return;\n if (typeof window === \"undefined\") return;\n\n const currentPath = extractSlugFromPathname(\n window.location.pathname,\n normalizedBasePath,\n );\n\n if (!currentPath) {\n const firstSlug = findFirstNavigableSlug(filteredNavItems);\n if (firstSlug) {\n const targetPath =\n normalizedBasePath === \"/\"\n ? `/${firstSlug}`\n : `${normalizedBasePath}/${firstSlug}`;\n // replaceState to avoid polluting back-button history\n history.replaceState(null, \"\", targetPath);\n setPathSlug(firstSlug);\n }\n }\n }, [filteredNavItems, controlledSlug, normalizedBasePath]);\n\n // Listen for popstate (browser back/forward)\n useEffect(() => {\n if (controlledSlug !== undefined) return;\n\n const handlePopState = () => {\n const slug = extractSlugFromPathname(\n window.location.pathname,\n normalizedBasePath,\n );\n setPathSlug(slug);\n };\n\n window.addEventListener(\"popstate\", handlePopState);\n return () => window.removeEventListener(\"popstate\", handlePopState);\n }, [controlledSlug, normalizedBasePath]);\n\n // Logout hook — always called (rules of hooks) but only wired to UI below\n const logout = useLogout({\n redirectUrl: logoutRedirectUrl,\n onLogout,\n });\n\n const activeSlug = controlledSlug ?? pathSlug;\n\n const handleNavigate = useCallback(\n (slug: string) => {\n if (onNavigateProp) {\n onNavigateProp(slug);\n return;\n }\n const targetPath =\n normalizedBasePath === \"/\"\n ? `/${slug}`\n : `${normalizedBasePath}/${slug}`;\n history.pushState(null, \"\", targetPath);\n setPathSlug(slug);\n },\n [onNavigateProp, normalizedBasePath],\n );\n\n // Resolve sidebar footer: explicit prop wins, otherwise render default logout button\n const resolvedSidebarFooter = useMemo(\n () =>\n sidebarFooter !== undefined ? (\n sidebarFooter\n ) : (\n <SdkLogoutButton onLogout={logout} />\n ),\n [sidebarFooter, logout],\n );\n\n // Derive base slug and rest params via prefix matching\n const slugMatch = useMemo(\n () => matchSlugPrefix(activeSlug, navSlugs),\n [activeSlug, navSlugs],\n );\n const baseSlug = slugMatch?.matchedSlug ?? normalizeSlug(activeSlug);\n const restParams = slugMatch?.rest ?? \"\";\n\n // Derive mobile sub-tabs for the current section\n const mobileCurrentSection = findCurrentSection(\n filteredMobileNavItems,\n baseSlug,\n );\n const mobileSecondLevelTabs = mobileCurrentSection?.children ?? [];\n const currentNavItem = findNavItem(filteredNavItems, baseSlug);\n\n // Resolve screen title from nav label or screen definition name\n const screenTitle =\n currentNavItem?.label ||\n screens?.find((s) => s.id === currentNavItem?.screen_id)?.name ||\n undefined;\n\n // Determine content to render. Wrap in an error boundary keyed on the\n // active slug so a screen-level crash never takes down the navigation\n // chrome — and navigating to a different slug auto-recovers the boundary.\n const rawContent =\n typeof children === \"function\"\n ? children({ currentSlug: activeSlug, currentNavItem })\n : (children ?? (\n <ScreenHeaderProvider>\n <div className=\"flex h-full flex-col\">\n <ScreenHeader title={screenTitle} />\n <div className=\"min-h-0 flex-1\">\n <PageRouter\n currentSlug={activeSlug}\n currentNavItem={currentNavItem}\n customPages={customPages}\n screens={screens}\n baseSlug={baseSlug}\n restParams={restParams}\n navSlugs={allNavSlugs}\n />\n </div>\n </div>\n </ScreenHeaderProvider>\n ));\n\n const content = (\n <AppShellErrorBoundary key={activeSlug ?? \"\"}>\n {rawContent}\n </AppShellErrorBoundary>\n );\n\n // Show loading state while app data is being fetched for the first time.\n // This check is placed after all hooks to satisfy React's rules of hooks.\n if (isLoading && !appData) {\n return <AppShellLoading />;\n }\n\n return (\n <RepUserProvider user={repUser}>\n <ThemeModeProvider\n mode={themeMode}\n onModeChange={handleThemeModeChange}\n autoModeEnabled={false}\n >\n <div\n className=\"font-body\"\n data-theme={activeTheme.id}\n data-theme-mode={themeMode === \"auto\" ? undefined : themeMode}\n >\n <AppNavigationProvider\n currentSlug={activeSlug}\n basePath={normalizedBasePath}\n navigate={handleNavigate}\n >\n <AppShellLayout\n sidebarContent={\n <SdkNavigation\n navItems={filteredNavItems}\n currentSlug={activeSlug}\n onNavigate={handleNavigate}\n />\n }\n headerContent={\n <SdkHeader\n mobileTabs={mobileSecondLevelTabs}\n currentSlug={activeSlug}\n onNavigate={handleNavigate}\n onLogout={logout}\n />\n }\n sidebarHeader={\n sidebarHeader !== undefined ? (\n sidebarHeader\n ) : (\n <SdkCompanySwitcher />\n )\n }\n sidebarFooter={resolvedSidebarFooter}\n useBottomNav\n afterContent={\n <SdkBottomNav\n navItems={filteredMobileNavItems}\n currentSlug={activeSlug}\n onNavigate={handleNavigate}\n appDefinitionId={appData?.definition_id ?? 0}\n />\n }\n >\n {content}\n </AppShellLayout>\n </AppNavigationProvider>\n <Toaster />\n </div>\n </ThemeModeProvider>\n </RepUserProvider>\n );\n}\n","/**\n * Read Vite environment variables at runtime.\n *\n * Isolated into its own module so that Jest tests can mock it\n * (import.meta is a syntax-level construct that CJS/Jest cannot parse).\n */\nexport function getViteEnv(key: string): string | undefined {\n const env = import.meta.env as unknown as Record<string, string> | undefined;\n return env?.[key];\n}\n","import type { FluidSDKConfig } from \"../types/config\";\nimport { getViteEnv } from \"./env\";\n\n/**\n * Creates a FluidSDKConfig with sensible defaults.\n *\n * Default behavior:\n * - baseUrl: reads from `VITE_API_URL` env var, falls back to `\"\"` (same-origin relative)\n * - Auth: relies on session cookies sent via `credentials: 'include'`\n *\n * Pass overrides to customize any field:\n * ```ts\n * const config = createDefaultFluidConfig({ baseUrl: \"https://my-api.example.com\" });\n * ```\n */\nexport function createDefaultFluidConfig(\n overrides?: Partial<FluidSDKConfig>,\n): FluidSDKConfig {\n return {\n baseUrl: getViteEnv(\"VITE_API_URL\") ?? \"\",\n ...overrides,\n };\n}\n","import type { ComponentType } from \"react\";\nimport type { WidgetManifest } from \"@fluid-app/portal-core/registries\";\nimport { DEFAULT_SDK_WIDGET_REGISTRY } from \"../core/default-widget-registry\";\n\n/**\n * Merges custom widget components from manifests into the default\n * SDK widget registry. Returns the default registry unchanged when\n * no custom widgets are provided (avoids unnecessary object creation).\n */\nexport function buildWidgetRegistry(\n manifests: WidgetManifest[],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, ComponentType<any>> {\n if (manifests.length === 0) return DEFAULT_SDK_WIDGET_REGISTRY;\n\n const customEntries = Object.fromEntries(\n manifests.map((m) => [m.type, m.component]),\n );\n\n return { ...DEFAULT_SDK_WIDGET_REGISTRY, ...customEntries };\n}\n","import {\n Component,\n StrictMode,\n type ErrorInfo,\n type ReactNode,\n type ComponentType,\n} from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { FluidProvider } from \"../providers/FluidProvider\";\nimport { AppShell, type AppShellProps } from \"../shell/AppShell\";\nimport { createDefaultFluidConfig } from \"../config/defaults\";\nimport type { FluidSDKConfig } from \"../types/config\";\nimport type { WidgetManifest } from \"@fluid-app/portal-core/registries\";\nimport { buildWidgetRegistry } from \"../utils/build-widget-registry\";\n\n/**\n * Last-resort error boundary for crashes above the AppShell (provider\n * setup, theme/auth bootstrap). Renders above FluidThemeProvider, so the\n * theme CSS custom properties (`--color-foreground`, `--color-muted`, etc.)\n * are not yet applied — using inline styles + literal colors avoids\n * referencing theme tokens that would resolve to nothing.\n */\nclass RootBoundary extends Component<\n { children: ReactNode },\n { error: Error | null }\n> {\n override state = { error: null as Error | null };\n\n static getDerivedStateFromError(error: Error): { error: Error } {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo): void {\n console.error(\"[portal] Root crashed:\", error, info);\n }\n\n override render(): ReactNode {\n if (!this.state.error) return this.props.children;\n return (\n <div\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n fontFamily: \"system-ui, sans-serif\",\n }}\n >\n <div style={{ maxWidth: \"32rem\", textAlign: \"center\" }}>\n <h1 style={{ fontSize: \"1.25rem\", fontWeight: 600 }}>\n The app failed to load\n </h1>\n <p style={{ marginTop: \"0.5rem\", color: \"#666\" }}>\n Something went wrong while starting the portal. Please reload the\n page; if the problem persists, contact support.\n </p>\n <button\n type=\"button\"\n onClick={() => {\n window.location.reload();\n }}\n style={{\n marginTop: \"1.5rem\",\n padding: \"0.5rem 1rem\",\n borderRadius: \"0.375rem\",\n border: \"1px solid #ccc\",\n background: \"#fff\",\n cursor: \"pointer\",\n }}\n >\n Reload page\n </button>\n </div>\n </div>\n );\n }\n}\n\n/**\n * Configuration for `createPortal()`.\n *\n * Provides a single-call entry point that sets up the provider hierarchy\n * with sensible defaults. Every field is optional.\n */\nexport interface PortalConfig {\n /** Custom page components keyed by navigation slug */\n customPages?: Record<\n string,\n ComponentType<{ slug?: string; params?: string }>\n >;\n /** Custom widget manifests (type + component + propertySchema) */\n customWidgets?: WidgetManifest[];\n /** API client config overrides (merged with defaults) */\n fluid?: Partial<FluidSDKConfig>;\n /** Root element ID. @default \"root\" */\n rootId?: string;\n /** AppShell props passthrough (basePath, sidebarHeader, etc.) */\n shell?: Omit<AppShellProps, \"customPages\">;\n /** Wrap AppShell with additional providers (inserted inside RequireAuth, below FluidProvider) */\n providers?: ComponentType<{ children: ReactNode }>;\n /** Disable StrictMode. @default false */\n disableStrictMode?: boolean;\n}\n\n/**\n * Bootstrap a Fluid portal with a single function call.\n *\n * Sets up the provider hierarchy (FluidProvider → AppShell) and renders into the DOM.\n * Auth is handled server-side by Rails before the SPA loads.\n *\n * @example Minimal usage\n * ```ts\n * import { createPortal } from \"@fluid-app/portal-sdk\";\n * import \"./index.css\";\n *\n * createPortal();\n * ```\n *\n * @example With custom pages\n * ```ts\n * import { createPortal } from \"@fluid-app/portal-sdk\";\n * import { customPages } from \"./portal.config\";\n * import \"./index.css\";\n *\n * createPortal({ customPages });\n * ```\n *\n * @example With overrides\n * ```ts\n * createPortal({\n * customPages,\n * fluid: { baseUrl: \"https://my-api.example.com\" },\n * shell: { basePath: \"/portal\" },\n * });\n * ```\n */\nexport function createPortal(config: PortalConfig = {}): void {\n const rootElement = document.getElementById(config.rootId ?? \"root\");\n if (!rootElement) {\n throw new Error(\n `Portal root element \"#${config.rootId ?? \"root\"}\" not found`,\n );\n }\n\n const fluidConfig = createDefaultFluidConfig(config.fluid);\n\n // Merge custom widget components with built-in defaults\n const widgetRegistry = config.customWidgets?.length\n ? buildWidgetRegistry(config.customWidgets)\n : undefined;\n\n let app: ReactNode = (\n <AppShell customPages={config.customPages} {...config.shell} />\n );\n\n if (config.providers) {\n const Providers = config.providers;\n app = <Providers>{app}</Providers>;\n }\n\n const tree = (\n <RootBoundary>\n <FluidProvider config={fluidConfig} widgetRegistry={widgetRegistry}>\n {app}\n </FluidProvider>\n </RootBoundary>\n );\n\n createRoot(rootElement).render(\n config.disableStrictMode ? tree : <StrictMode>{tree}</StrictMode>,\n );\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useAppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api-context\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport { transformManifestToRepAppData } from \"../transforms\";\nimport type { RawManifestResponse } from \"../transforms\";\nimport type { Profile } from \"../types/profile\";\nimport { APP_DATA_QUERY_KEY, fetchRawManifest } from \"./use-fluid-app\";\n\n/**\n * Base query key for profile data.\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n *\n * @deprecated Use {@link APP_DATA_QUERY_KEY} with `useFluidApp` instead.\n */\nexport const PROFILE_QUERY_KEY = [\"fluid\", \"profile\"] as const;\n\n/**\n * Hook to fetch the portal profile (themes, navigation, screens).\n *\n * Internally fetches from the fluidos API (same data source as\n * {@link useFluidApp}) and selects the `profile` slice, so no\n * legacy `/api/rep_app/manifest` call is made.\n *\n * @deprecated Use `useFluidApp()` instead — it returns the full\n * `RepAppData` including `profile`, `screens`, and more.\n *\n * @example\n * ```tsx\n * function Navigation() {\n * const { data: profile, isLoading } = useFluidProfile();\n *\n * if (isLoading) return <Spinner />;\n *\n * return (\n * <nav>\n * {profile?.navigation.navigation_items.map(item => (\n * <NavItem key={item.id} item={item} />\n * ))}\n * </nav>\n * );\n * }\n * ```\n */\nexport function useFluidProfile(): UseQueryResult<Profile> {\n const appDefinitionApi = useAppDefinitionApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery<\n RawManifestResponse,\n Error,\n Profile,\n readonly (string | number)[]\n >({\n queryKey: scopeKey(APP_DATA_QUERY_KEY),\n queryFn: () => fetchRawManifest(appDefinitionApi),\n select: (raw) => {\n const appData = transformManifestToRepAppData(raw);\n return appData.profile;\n },\n });\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useAppDefinitionApi } from \"@fluid-app/portal-core/app-definition-api-context\";\nimport type { AppDefinitionResponse } from \"@fluid-app/portal-core/app-definition-types\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\n\n/**\n * Base query key for the app definition endpoint.\n * The runtime key includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const APP_DEFINITION_QUERY_KEY = [\"fluid\", \"app-definition\"] as const;\n\n/**\n * Hook to fetch the active app manifest from the portal-tenant BFF.\n *\n * Returns the manifest metadata (id, name, version)\n * sourced from `GET /api/app/manifest` via the {@link AppDefinitionApi} port.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { data } = useAppDefinition();\n * const definitionId = data?.definition.id ?? 0;\n * }\n * ```\n */\nexport function useAppDefinition(options?: {\n enabled?: boolean;\n}): UseQueryResult<AppDefinitionResponse> {\n const api = useAppDefinitionApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery({\n queryKey: scopeKey(APP_DEFINITION_QUERY_KEY),\n queryFn: () => api.fetchDefinition(),\n ...(options?.enabled !== undefined && { enabled: options.enabled }),\n });\n}\n","import { useThemeContext } from \"../providers/FluidThemeProvider\";\nimport type { ThemeDefinition } from \"../types/theme\";\n\n/**\n * Result of useFluidTheme hook\n */\nexport interface UseFluidThemeResult {\n /** Currently active theme */\n currentTheme: ThemeDefinition | null;\n /** Switch to a different theme */\n setTheme: (theme: ThemeDefinition) => void;\n /** Switch between light and dark mode */\n setThemeMode: (mode: \"light\" | \"dark\") => void;\n /** Current theme mode (convenience accessor) */\n mode: \"light\" | \"dark\" | undefined;\n}\n\n/**\n * Hook to access and control theme settings\n *\n * @example\n * ```tsx\n * function ThemeSwitcher({ themes }: { themes: ThemeDefinition[] }) {\n * const { currentTheme, setTheme, setThemeMode, mode } = useFluidTheme();\n *\n * return (\n * <div>\n * <select\n * value={currentTheme?.name}\n * onChange={(e) => {\n * const theme = themes.find(t => t.name === e.target.value);\n * if (theme) setTheme(theme);\n * }}\n * >\n * {themes.map(theme => (\n * <option key={theme.name} value={theme.name}>\n * {theme.name}\n * </option>\n * ))}\n * </select>\n *\n * <button onClick={() => setThemeMode(mode === \"dark\" ? \"light\" : \"dark\")}>\n * Toggle {mode === \"dark\" ? \"Light\" : \"Dark\"} Mode\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useFluidTheme(): UseFluidThemeResult {\n const { currentTheme, setTheme, setThemeMode, mode } = useThemeContext();\n\n return {\n currentTheme,\n setTheme,\n setThemeMode,\n mode,\n };\n}\n","import { useCallback, useRef } from \"react\";\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { deleteDatabase } from \"@fluid-app/query-persister\";\nimport { usePortalTenantClient } from \"../providers/PortalTenantClientProvider\";\n\nexport interface UseCompanySwitchOptions {\n // Preserved for API compatibility; no longer used internally.\n}\n\n/**\n * Hook that handles company switching for the portal.\n *\n * Calls PUT /api/authentication/company/{id}/switch, clears the TanStack\n * Query cache and IndexedDB persisted cache, then reloads the page so all\n * queries re-fetch with the new company context.\n *\n * The server updates the session cookie automatically via the switch\n * endpoint response; no client-side token storage is needed.\n */\nexport function useCompanySwitch(_options?: UseCompanySwitchOptions): {\n switchCompany: (companyId: number) => void;\n isPending: boolean;\n isError: boolean;\n error: Error | null;\n} {\n const client = usePortalTenantClient();\n const queryClient = useQueryClient();\n const switchingRef = useRef(false);\n\n const { mutate, isPending, isError, error } = useMutation({\n mutationFn: (companyId: number) =>\n client.put(`/api/authentication/company/${companyId}/switch`),\n onSuccess: async () => {\n // Clear in-memory cache and IndexedDB to prevent stale data\n // rehydration after reload.\n queryClient.clear();\n try {\n await deleteDatabase(\"company-switch\");\n } catch {\n // Non-fatal: company-scoped query keys prevent cross-company reads\n // even if the IDB delete fails.\n }\n // Session cookie is updated server-side by the switch endpoint.\n // Reload to re-fetch all queries with the new company context.\n window.location.reload();\n },\n onError: () => {\n switchingRef.current = false;\n },\n });\n\n const switchCompany = useCallback(\n (companyId: number) => {\n if (switchingRef.current) return;\n switchingRef.current = true;\n mutate(companyId);\n },\n [mutate],\n );\n\n return {\n switchCompany: switchCompany,\n isPending: isPending,\n isError: isError,\n error: error,\n };\n}\n","import type { CalendarEvent } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number, hour: number, minute: number = 0): Date {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n d.setHours(hour, minute, 0, 0);\n return d;\n}\n\nexport const DEMO_CALENDAR_EVENTS: readonly CalendarEvent[] = [\n {\n id: 1,\n title: \"Team Standup\",\n description: { body: \"Daily sync with the sales team\" },\n color: \"#4f46e5\",\n start: daysFromNow(0, 9, 0).toISOString(),\n end: daysFromNow(0, 9, 30).toISOString(),\n active: true,\n status: \"confirmed\",\n },\n {\n id: 2,\n title: \"Client Review - Acme Corp\",\n description: { body: \"Quarterly business review with key accounts\" },\n color: \"#059669\",\n start: daysFromNow(2, 14, 0).toISOString(),\n end: daysFromNow(2, 15, 0).toISOString(),\n active: true,\n status: \"confirmed\",\n venue: \"Conference Room B\",\n },\n {\n id: 3,\n title: \"Product Training Webinar\",\n description: { body: \"New product line training for the field\" },\n color: \"#d97706\",\n start: daysFromNow(4, 11, 0).toISOString(),\n end: daysFromNow(4, 12, 30).toISOString(),\n active: true,\n status: \"confirmed\",\n url: \"https://example.com/webinar\",\n },\n {\n id: 4,\n title: \"Regional Conference\",\n description: { body: \"Annual West Coast regional conference\" },\n color: \"#dc2626\",\n start: daysFromNow(10, 8, 0).toISOString(),\n end: daysFromNow(12, 17, 0).toISOString(),\n active: true,\n status: \"confirmed\",\n venue: \"San Diego Convention Center\",\n isAllDay: true,\n },\n];\n","/**\n * Calendar events hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { CalendarEvent, CalendarEventDescription } from \"./hook-types\";\nimport { DEMO_CALENDAR_EVENTS } from \"./demo-data/calendar-events\";\n\n// Re-export types so external consumers are unaffected\nexport type { CalendarEvent, CalendarEventDescription };\n\n/**\n * Result type for useCalendarEvents hook.\n * Uses QueryResult<CalendarEvent[]> with default Error type.\n */\nexport type UseCalendarEventsResult = QueryResult<CalendarEvent[]>;\n\n/**\n * Hook to fetch calendar events.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useCalendarEvents(): UseCalendarEventsResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_CALENDAR_EVENTS],\n isLoading: false,\n isError: false,\n };\n}\n","import type { Todo } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n return d.toISOString();\n}\n\nexport const DEMO_TODOS: readonly Todo[] = [\n {\n id: 1,\n body: \"Follow up with Sarah about Q2 order\",\n dueAt: daysFromNow(1),\n completedAt: null,\n createdAt: daysFromNow(-2),\n contactName: \"Sarah Johnson\",\n },\n {\n id: 2,\n body: \"Send pricing proposal to Acme Corp\",\n dueAt: daysFromNow(7),\n completedAt: null,\n createdAt: daysFromNow(-1),\n contactName: \"Mike Chen\",\n },\n {\n id: 3,\n body: \"Schedule onboarding call with new team member\",\n dueAt: daysFromNow(3),\n completedAt: null,\n createdAt: daysFromNow(0),\n contactName: \"Emily Rodriguez\",\n },\n {\n id: 4,\n body: \"Review and approve Q1 expense report\",\n dueAt: daysFromNow(-1),\n completedAt: daysFromNow(-1),\n createdAt: daysFromNow(-5),\n contactName: null,\n },\n {\n id: 5,\n body: \"Prepare presentation for Friday team meeting\",\n dueAt: daysFromNow(4),\n completedAt: daysFromNow(0),\n createdAt: daysFromNow(-3),\n contactName: null,\n },\n];\n","/**\n * Todos hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { Todo } from \"./hook-types\";\nimport { DEMO_TODOS } from \"./demo-data/todos\";\n\n// Re-export type so external consumers are unaffected\nexport type { Todo };\n\n/**\n * Result type for useTodos hook.\n * Uses QueryResult<Todo[]> with default Error type.\n */\nexport type UseTodosResult = QueryResult<Todo[]>;\n\n/**\n * Hook to fetch todo items.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useTodos(): UseTodosResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_TODOS],\n isLoading: false,\n isError: false,\n };\n}\n","/**\n * Hook type utilities and type predicates.\n *\n * This module provides:\n * - Generic hook result types with default type parameters\n * - Type predicates for query state narrowing\n * - Reusable patterns for type-safe property access in hooks\n *\n * Following generics best practices:\n * - generics-default-type-parameters: Default E to Error for common case\n * - generics-type-predicates: Type predicates for result state narrowing\n * - generics-constrain-type-parameters: K extends keyof T for property access\n */\n\n// =============================================================================\n// Base Result Types with Default Type Parameters\n// =============================================================================\n\n/**\n * Base result type for query hooks with default error type.\n * Uses default type parameter for E (generics-default-type-parameters rule).\n *\n * @typeParam T - The data type\n * @typeParam E - The error type (defaults to Error)\n *\n * @example\n * // Error type defaults to Error\n * type UsersResult = QueryResult<User[]>;\n *\n * // Can override when needed\n * type CustomResult = QueryResult<User[], ApiError>;\n */\nexport interface QueryResult<T, E = Error> {\n readonly data: T;\n readonly isLoading: boolean;\n readonly isError: boolean;\n readonly error?: E | undefined;\n}\n\n/**\n * Result type for hooks that may not have data yet.\n * Extends QueryResult with nullable data.\n *\n * @typeParam T - The data type\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface QueryResultNullable<T, E = Error> {\n readonly data: T | null | undefined;\n readonly isLoading: boolean;\n readonly isError: boolean;\n readonly error?: E | undefined;\n}\n\n/**\n * Result type for list/collection hooks with aggregates.\n *\n * @typeParam T - The item type in the array\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface ListQueryResult<T, E = Error> extends QueryResult<T[], E> {\n readonly totalCount: number;\n}\n\n/**\n * Result type for list hooks with value aggregation (e.g., deals with total value).\n *\n * @typeParam T - The item type in the array\n * @typeParam E - The error type (defaults to Error)\n */\nexport interface ValueListQueryResult<T, E = Error> extends ListQueryResult<\n T,\n E\n> {\n readonly totalValue: number;\n}\n\n// =============================================================================\n// Type Predicates for Query State Narrowing\n// =============================================================================\n\n/**\n * Type predicate to check if a query result has successfully loaded data.\n * Narrows the data type from T | null | undefined to T.\n *\n * @example\n * const result = useContact(id);\n * if (hasData(result)) {\n * // TypeScript knows result.data is Contact, not Contact | null\n * console.log(result.data.name);\n * }\n */\nexport function hasData<T, E = Error>(\n result: QueryResultNullable<T, E>,\n): result is QueryResultNullable<T, E> & { readonly data: T } {\n return result.data != null && !result.isLoading && !result.isError;\n}\n\n/**\n * Type predicate to check if a query result is in loading state.\n * Useful for conditional rendering.\n *\n * @example\n * if (isLoading(result)) {\n * return <Spinner />;\n * }\n */\nexport function isLoading<T, E = Error>(\n result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): boolean {\n return result.isLoading;\n}\n\n/**\n * Type predicate to check if a query result has an error.\n * Narrows to include the error property.\n *\n * @example\n * if (isErrorResult(result)) {\n * console.error(result.error); // error is E, not undefined\n * }\n */\nexport function isErrorResult<T, E = Error>(\n result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): result is (QueryResult<T, E> | QueryResultNullable<T, E>) & {\n readonly isError: true;\n readonly error: E;\n} {\n return result.isError && result.error !== undefined;\n}\n\n/**\n * Type predicate to check if a query result is in idle state (not loading, no error, has data).\n *\n * @example\n * if (isIdle(result)) {\n * // Safe to access and render data\n * }\n */\nexport function isIdle<T, E = Error>(\n result: QueryResult<T, E> | QueryResultNullable<T, E>,\n): boolean {\n return !result.isLoading && !result.isError;\n}\n\n// =============================================================================\n// Generic Property Selector Pattern\n// =============================================================================\n\n/**\n * Type-safe property selector for hook results.\n * Uses K extends keyof T constraint (generics-function-constraints rule).\n *\n * @typeParam T - The data object type\n * @typeParam K - Key of T (constrained to actual keys)\n *\n * @example\n * const users = [{ name: \"Alice\", age: 30 }];\n * const names = selectProperty(users, \"name\"); // string[]\n * const ages = selectProperty(users, \"age\"); // number[]\n * selectProperty(users, \"invalid\"); // Error: \"invalid\" not in \"name\" | \"age\"\n */\nexport function selectProperty<T, K extends keyof T>(\n items: readonly T[],\n key: K,\n): T[K][] {\n return items.map((item) => item[key]);\n}\n\n/**\n * Type-safe property getter for a single item.\n * Returns undefined if item is null/undefined.\n *\n * @typeParam T - The data object type\n * @typeParam K - Key of T (constrained to actual keys)\n */\nexport function getProperty<T, K extends keyof T>(\n item: T | null | undefined,\n key: K,\n): T[K] | undefined {\n return item?.[key];\n}\n\n// =============================================================================\n// Hook Factory Types\n// =============================================================================\n\n/**\n * Generic type for hooks that fetch a single resource by ID.\n * Useful for creating consistent API across different resource types.\n *\n * @typeParam T - The resource type\n * @typeParam E - The error type (defaults to Error)\n */\nexport type UseSingleResourceHook<T, E = Error> = (\n id: string,\n) => QueryResultNullable<T, E>;\n\n/**\n * Generic type for hooks that fetch a list of resources with optional params.\n * Uses generics-default-type-parameters for the params type.\n *\n * @typeParam T - The item type\n * @typeParam P - The params type (defaults to empty object)\n * @typeParam E - The error type (defaults to Error)\n */\nexport type UseListResourceHook<\n T,\n P extends Record<string, unknown> = Record<string, never>,\n E = Error,\n> = (params?: P) => ListQueryResult<T, E>;\n\n/**\n * Transforms a nullable result to a non-nullable one if data exists.\n * Useful when you've already checked hasData().\n */\nexport type WithData<R extends QueryResultNullable<unknown>> =\n R extends QueryResultNullable<infer T, infer E>\n ? QueryResultNullable<T, E> & { readonly data: T }\n : never;\n\n// =============================================================================\n// Domain Types\n// Shared between hook files and demo-data files to avoid circular imports.\n// =============================================================================\n\n/**\n * Activity slug constants as a const object.\n * Derive the ActivitySlug type from this single source of truth.\n */\nexport const ACTIVITY_SLUGS = {\n abandonedCart: \"abandoned_cart\",\n announcements: \"announcements\",\n cartItemsAdded: \"cart_items_added\",\n commentReply: \"comment_reply\",\n directMessage: \"direct_message\",\n fantasyPoint: \"fantasy_point\",\n newLead: \"new_lead\",\n orderPlaced: \"order_placed\",\n pageViews: \"page_views\",\n pageViewsContact: \"page_views_contact\",\n tasks: \"tasks\",\n upcomingEvent: \"upcoming_event\",\n video: \"video\",\n videoComplete: \"video_complete\",\n videoCompleteContact: \"video_complete_contact\",\n videoContact: \"video_contact\",\n messageReceived: \"message_received\",\n messageSent: \"message_sent\",\n newCartItemsAdded: \"new_cart_items_added\",\n smartLinkClicked: \"smart_link_clicked\",\n reviewLeft: \"review_left\",\n} as const;\n\n/** Activity slug union type derived from ACTIVITY_SLUGS constant. */\nexport type ActivitySlug = (typeof ACTIVITY_SLUGS)[keyof typeof ACTIVITY_SLUGS];\n\n/** Type predicate to check if a string is a valid ActivitySlug. */\nexport function isActivitySlug(value: string): value is ActivitySlug {\n return Object.values(ACTIVITY_SLUGS).includes(value as ActivitySlug);\n}\n\n/** Transformed activity for display. */\nexport interface Activity {\n readonly id: number;\n readonly userName: string;\n readonly avatarUrl: string | null;\n readonly activityType: string;\n readonly targetName: string;\n readonly timestamp: string;\n readonly slug: ActivitySlug;\n}\n\n/** Description/rich text metadata for a calendar event. */\nexport interface CalendarEventDescription {\n readonly id?: number | null;\n readonly name?: string | null;\n readonly body?: string | null;\n readonly record_type?: string | null;\n readonly record_id?: number | null;\n readonly created_at?: string | null;\n readonly updated_at?: string | null;\n readonly locale?: string | null;\n}\n\n/** Calendar event data from the API. */\nexport interface CalendarEvent {\n readonly id: number;\n readonly title: string;\n readonly description?: CalendarEventDescription | null;\n readonly color?: string | null;\n readonly url?: string | null;\n readonly start: string;\n readonly end: string;\n readonly active?: boolean | null;\n readonly time_zone?: string | null;\n readonly status?: string | null;\n readonly image_url?: string | null;\n readonly images?: readonly unknown[] | null;\n readonly venue?: string | null;\n readonly countries?: readonly string[] | null;\n readonly hasTomorrow?: boolean | null;\n readonly hasYesterday?: boolean | null;\n readonly isAllDay?: boolean;\n}\n\n/** Catch up suggestion data from the API. */\nexport interface CatchUp {\n readonly id: number;\n readonly suggestion_title: string;\n}\n\n/** MySite data returned by the hook. */\nexport interface MySiteData {\n readonly url: string | null;\n readonly views: number;\n readonly leads: number;\n readonly userName: string;\n}\n\n/** Transformed todo for display. */\nexport interface Todo {\n readonly id: number;\n readonly body: string;\n readonly dueAt: string | null;\n readonly completedAt: string | null;\n readonly createdAt: string;\n readonly contactName: string | null;\n}\n","import type { Activity } from \"../hook-types\";\n\nconst now = new Date();\n\nfunction hoursAgo(hours: number): string {\n const d = new Date(now);\n d.setHours(d.getHours() - hours);\n return d.toISOString();\n}\nexport const DEMO_ACTIVITIES: readonly Activity[] = [\n {\n id: 1,\n userName: \"Sarah Johnson\",\n avatarUrl: null,\n activityType: \"New Order\",\n targetName: \"Wellness Starter Kit\",\n timestamp: hoursAgo(1),\n slug: \"order_placed\",\n },\n {\n id: 2,\n userName: \"Mike Chen\",\n avatarUrl: null,\n activityType: \"New Lead\",\n targetName: \"Referral from LinkedIn campaign\",\n timestamp: hoursAgo(3),\n slug: \"new_lead\",\n },\n {\n id: 3,\n userName: \"Emily Rodriguez\",\n avatarUrl: null,\n activityType: \"Page View\",\n targetName: \"Product Catalog\",\n timestamp: hoursAgo(5),\n slug: \"page_views\",\n },\n {\n id: 4,\n userName: \"David Park\",\n avatarUrl: null,\n activityType: \"Cart Items Added\",\n targetName: \"Premium Bundle (3 items)\",\n timestamp: hoursAgo(8),\n slug: \"cart_items_added\",\n },\n {\n id: 5,\n userName: \"Lisa Thompson\",\n avatarUrl: null,\n activityType: \"Video Watched\",\n targetName: \"Getting Started Tutorial\",\n timestamp: hoursAgo(12),\n slug: \"video_complete\",\n },\n {\n id: 6,\n userName: \"James Wilson\",\n avatarUrl: null,\n activityType: \"Message Received\",\n targetName: \"Question about shipping\",\n timestamp: hoursAgo(18),\n slug: \"message_received\",\n },\n {\n id: 7,\n userName: \"Rachel Kim\",\n avatarUrl: null,\n activityType: \"Smart Link Clicked\",\n targetName: \"Holiday Promo Link\",\n timestamp: hoursAgo(24),\n slug: \"smart_link_clicked\",\n },\n {\n id: 8,\n userName: \"Tom Martinez\",\n avatarUrl: null,\n activityType: \"Review Left\",\n targetName: \"Essential Oil Set - 5 stars\",\n timestamp: hoursAgo(36),\n slug: \"review_left\",\n },\n];\n","/**\n * Activities hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport {\n ACTIVITY_SLUGS,\n isActivitySlug,\n type Activity,\n type ActivitySlug,\n} from \"./hook-types\";\nimport { DEMO_ACTIVITIES } from \"./demo-data/activities\";\n\n// Re-export types and constants so external consumers are unaffected\nexport { ACTIVITY_SLUGS, isActivitySlug };\nexport type { Activity, ActivitySlug };\n\n/**\n * Result type for useActivities hook.\n * Uses QueryResult generic with Activity[] and default Error type.\n */\nexport type UseActivitiesResult = QueryResult<Activity[]>;\n\n/**\n * Hook to fetch recent activities.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useActivities(): UseActivitiesResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_ACTIVITIES],\n isLoading: false,\n isError: false,\n };\n}\n","import type { CatchUp } from \"../hook-types\";\n\nexport const DEMO_CATCHUPS: readonly CatchUp[] = [\n {\n id: 1,\n suggestion_title: \"Sarah Johnson hasn't ordered in 30 days\",\n },\n {\n id: 2,\n suggestion_title: \"Mike Chen's subscription is expiring soon\",\n },\n {\n id: 3,\n suggestion_title: \"Emily Rodriguez left a cart with 3 items\",\n },\n];\n","/**\n * Catch ups hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResult } from \"./hook-types\";\nimport type { CatchUp } from \"./hook-types\";\nimport { DEMO_CATCHUPS } from \"./demo-data/catchups\";\n\n// Re-export type so external consumers are unaffected\nexport type { CatchUp };\n\n/**\n * Result type for useCatchUps hook.\n * Uses QueryResult<CatchUp[]> with default Error type.\n */\nexport type UseCatchUpsResult = QueryResult<CatchUp[]>;\n\n/**\n * Hook to fetch catch up items.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useCatchUps(): UseCatchUpsResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_CATCHUPS],\n isLoading: false,\n isError: false,\n };\n}\n","import type { MySiteData } from \"../hook-types\";\n\nexport const DEMO_MYSITE: MySiteData = {\n url: \"https://my-portal.example.com\",\n views: 1243,\n leads: 37,\n userName: \"Demo User\",\n};\n","/**\n * MySite hook - stub implementation for SDK\n * In production, implement this hook to fetch from your API\n */\n\nimport type { QueryResultNullable } from \"./hook-types\";\nimport type { MySiteData } from \"./hook-types\";\nimport { DEMO_MYSITE } from \"./demo-data/mysite\";\n\n// Re-export type so external consumers are unaffected\nexport type { MySiteData };\n\n/**\n * Result type for useMySite hook.\n * Uses QueryResultNullable since MySite data may not be available.\n */\nexport type UseMySiteResult = QueryResultNullable<MySiteData>;\n\n/**\n * Hook to fetch MySite data.\n * This is a stub implementation - override with your own data fetching logic.\n */\nexport function useMySite(): UseMySiteResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: DEMO_MYSITE,\n isLoading: false,\n isError: false,\n };\n}\n","import type { Conversation, Message } from \"../../types/screen-types\";\n\nconst now = new Date();\n\nfunction hoursAgo(hours: number): string {\n const d = new Date(now);\n d.setHours(d.getHours() - hours);\n return d.toISOString();\n}\n\nfunction daysAgo(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() - days);\n return d.toISOString();\n}\n\nexport const DEMO_CONVERSATIONS: readonly Conversation[] = [\n {\n id: \"conv-1\",\n title: \"Sarah Johnson\",\n participants: [\n { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n {\n id: \"user-2\",\n name: \"Sarah Johnson\",\n email: \"sarah.johnson@example.com\",\n isOnline: true,\n },\n ],\n lastMessage: {\n id: \"msg-1-3\",\n conversationId: \"conv-1\",\n senderId: \"user-2\",\n senderName: \"Sarah Johnson\",\n type: \"text\",\n content: \"Sounds great! I'll place the order by end of day.\",\n timestamp: hoursAgo(1),\n isRead: false,\n },\n unreadCount: 1,\n status: \"active\",\n createdAt: daysAgo(30),\n updatedAt: hoursAgo(1),\n },\n {\n id: \"conv-2\",\n title: \"Mike Chen\",\n participants: [\n { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n {\n id: \"user-3\",\n name: \"Mike Chen\",\n email: \"mike.chen@acmecorp.com\",\n isOnline: false,\n },\n ],\n lastMessage: {\n id: \"msg-2-2\",\n conversationId: \"conv-2\",\n senderId: \"user-1\",\n senderName: \"You\",\n type: \"text\",\n content:\n \"I've attached the updated pricing sheet. Let me know if you have any questions!\",\n timestamp: hoursAgo(5),\n isRead: true,\n },\n unreadCount: 0,\n status: \"active\",\n createdAt: daysAgo(14),\n updatedAt: hoursAgo(5),\n },\n {\n id: \"conv-3\",\n title: \"Team Updates\",\n participants: [\n { id: \"user-1\", name: \"You\", email: \"me@example.com\", isOnline: true },\n {\n id: \"user-4\",\n name: \"Emily Rodriguez\",\n email: \"emily.r@healthfirst.io\",\n },\n { id: \"user-5\", name: \"David Park\", email: \"david.park@email.com\" },\n ],\n lastMessage: {\n id: \"msg-3-4\",\n conversationId: \"conv-3\",\n senderId: \"user-4\",\n senderName: \"Emily Rodriguez\",\n type: \"text\",\n content:\n \"The new product samples arrived today. Will distribute to the team tomorrow.\",\n timestamp: daysAgo(1),\n isRead: true,\n },\n unreadCount: 0,\n status: \"active\",\n createdAt: daysAgo(60),\n updatedAt: daysAgo(1),\n },\n];\n\nexport const DEMO_MESSAGES: readonly Message[] = [\n {\n id: \"msg-1-1\",\n conversationId: \"conv-1\",\n senderId: \"user-1\",\n senderName: \"You\",\n type: \"text\",\n content:\n \"Hi Sarah! I wanted to follow up on the Wellness Starter Kit. We have a special promotion running this month.\",\n timestamp: hoursAgo(3),\n isRead: true,\n },\n {\n id: \"msg-1-2\",\n conversationId: \"conv-1\",\n senderId: \"user-2\",\n senderName: \"Sarah Johnson\",\n type: \"text\",\n content:\n \"That's perfect timing! I was just thinking about reordering. What's the promo?\",\n timestamp: hoursAgo(2),\n isRead: true,\n },\n {\n id: \"msg-1-3\",\n conversationId: \"conv-1\",\n senderId: \"user-2\",\n senderName: \"Sarah Johnson\",\n type: \"text\",\n content: \"Sounds great! I'll place the order by end of day.\",\n timestamp: hoursAgo(1),\n isRead: false,\n },\n];\n","/**\n * Conversations hooks - stub implementations for SDK\n * In production, implement these hooks to fetch from your API\n */\n\nimport type { Conversation, Message } from \"../types/screen-types\";\nimport type { QueryResult } from \"./hook-types\";\nimport { DEMO_CONVERSATIONS, DEMO_MESSAGES } from \"./demo-data/conversations\";\n\n// =============================================================================\n// useConversations Hook\n// =============================================================================\n\n/**\n * Result type for useConversations hook.\n * Uses QueryResult<Conversation[]> with default Error type.\n */\nexport type UseConversationsResult = QueryResult<Conversation[]>;\n\n/**\n * Hook to fetch all conversations.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @returns UseConversationsResult with empty data array\n *\n * @example\n * ```tsx\n * const { data: conversations, isLoading, isError } = useConversations();\n *\n * if (isLoading) return <Loading />;\n * if (isError) return <Error />;\n *\n * return conversations.map(conv => <ConversationItem key={conv.id} {...conv} />);\n * ```\n */\nexport function useConversations(): UseConversationsResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_CONVERSATIONS],\n isLoading: false,\n isError: false,\n };\n}\n\n// =============================================================================\n// useConversationMessages Hook\n// =============================================================================\n\n/**\n * Result type for useConversationMessages hook.\n * Uses QueryResult<Message[]> with default Error type.\n */\nexport type UseConversationMessagesResult = QueryResult<Message[]>;\n\n/**\n * Hook to fetch messages for a specific conversation.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param conversationId - The ID of the conversation to fetch messages for\n * @returns UseConversationMessagesResult with empty data array\n *\n * @example\n * ```tsx\n * const { data: messages, isLoading, isError } = useConversationMessages(conversationId);\n *\n * if (isLoading) return <Loading />;\n * if (isError) return <Error />;\n *\n * return messages.map(msg => <MessageBubble key={msg.id} {...msg} />);\n * ```\n */\nexport function useConversationMessages(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _conversationId: string,\n): UseConversationMessagesResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching using _conversationId\n return {\n data: [...DEMO_MESSAGES],\n isLoading: false,\n isError: false,\n };\n}\n","/**\n * Screen Types - Type definitions for core feature screens\n *\n * All status and type unions are derived from constants for single source of truth.\n * Use the constants (e.g., CONVERSATION_STATUSES.active) for type-safe comparisons.\n */\n\n// =============================================================================\n// Messaging Types\n// =============================================================================\n\n/**\n * Conversation status constant - single source of truth.\n */\nexport const CONVERSATION_STATUSES = {\n active: \"active\",\n archived: \"archived\",\n muted: \"muted\",\n} as const;\n\n/**\n * Union type derived from CONVERSATION_STATUSES constant.\n */\nexport type ConversationStatus =\n (typeof CONVERSATION_STATUSES)[keyof typeof CONVERSATION_STATUSES];\n\n/**\n * Message type constant - single source of truth.\n */\nexport const MESSAGE_TYPES = {\n text: \"text\",\n image: \"image\",\n file: \"file\",\n system: \"system\",\n} as const;\n\n/**\n * Union type derived from MESSAGE_TYPES constant.\n */\nexport type MessageType = (typeof MESSAGE_TYPES)[keyof typeof MESSAGE_TYPES];\n\nexport interface Participant {\n readonly id: string;\n readonly name: string;\n readonly email: string;\n readonly avatarUrl?: string;\n readonly isOnline?: boolean;\n}\n\n/**\n * Message attachment type - extracted for reusability and clarity.\n */\nexport interface MessageAttachment {\n readonly id: string;\n readonly name: string;\n readonly url: string;\n readonly type: string;\n readonly size?: number;\n}\n\nexport interface Message {\n readonly id: string;\n readonly conversationId: string;\n readonly senderId: string;\n readonly senderName: string;\n readonly senderAvatarUrl?: string;\n readonly type: MessageType;\n readonly content: string;\n readonly timestamp: string;\n readonly isRead: boolean;\n readonly attachments?: readonly MessageAttachment[];\n}\n\nexport interface Conversation {\n readonly id: string;\n readonly title: string;\n readonly participants: readonly Participant[];\n readonly lastMessage?: Message;\n readonly unreadCount: number;\n readonly status: ConversationStatus;\n readonly createdAt: string;\n readonly updatedAt: string;\n}\n\n// =============================================================================\n// Contacts Types\n// =============================================================================\n\n/**\n * Contact status constant - single source of truth.\n */\nexport const CONTACT_STATUSES = {\n active: \"active\",\n inactive: \"inactive\",\n lead: \"lead\",\n prospect: \"prospect\",\n} as const;\n\n/**\n * Union type derived from CONTACT_STATUSES constant.\n */\nexport type ContactStatus =\n (typeof CONTACT_STATUSES)[keyof typeof CONTACT_STATUSES];\n\n/**\n * Contact type constant - single source of truth.\n */\nexport const CONTACT_TYPES = {\n individual: \"individual\",\n company: \"company\",\n} as const;\n\n/**\n * Union type derived from CONTACT_TYPES constant.\n */\nexport type ContactType = (typeof CONTACT_TYPES)[keyof typeof CONTACT_TYPES];\n\nexport interface ContactAddress {\n readonly street?: string;\n readonly city?: string;\n readonly state?: string;\n readonly postalCode?: string;\n readonly country?: string;\n}\n\nexport interface Contact {\n readonly id: string;\n readonly firstName: string;\n readonly lastName: string;\n readonly email: string;\n readonly phone?: string;\n readonly company?: string;\n readonly jobTitle?: string;\n readonly avatarUrl?: string;\n readonly status: ContactStatus;\n readonly type: ContactType;\n readonly address?: ContactAddress;\n readonly tags?: readonly string[];\n readonly notes?: string;\n readonly createdAt: string;\n readonly updatedAt: string;\n}\n","import type { Contact } from \"../../types/screen-types\";\n\nconst now = new Date();\n\nfunction daysAgo(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() - days);\n return d.toISOString();\n}\n\nexport const DEMO_CONTACTS: readonly Contact[] = [\n {\n id: \"contact-1\",\n firstName: \"Sarah\",\n lastName: \"Johnson\",\n email: \"sarah.johnson@example.com\",\n phone: \"+1 (555) 123-4567\",\n company: \"Wellness Works Inc.\",\n jobTitle: \"Purchasing Manager\",\n status: \"active\",\n type: \"individual\",\n tags: [\"VIP\", \"Repeat Buyer\"],\n createdAt: daysAgo(90),\n updatedAt: daysAgo(2),\n },\n {\n id: \"contact-2\",\n firstName: \"Mike\",\n lastName: \"Chen\",\n email: \"mike.chen@acmecorp.com\",\n phone: \"+1 (555) 234-5678\",\n company: \"Acme Corp\",\n jobTitle: \"Director of Operations\",\n status: \"active\",\n type: \"individual\",\n tags: [\"Enterprise\"],\n createdAt: daysAgo(60),\n updatedAt: daysAgo(5),\n },\n {\n id: \"contact-3\",\n firstName: \"Emily\",\n lastName: \"Rodriguez\",\n email: \"emily.r@healthfirst.io\",\n company: \"HealthFirst\",\n status: \"lead\",\n type: \"individual\",\n notes: \"Interested in bulk pricing for team orders\",\n createdAt: daysAgo(7),\n updatedAt: daysAgo(1),\n },\n {\n id: \"contact-4\",\n firstName: \"David\",\n lastName: \"Park\",\n email: \"david.park@email.com\",\n phone: \"+1 (555) 345-6789\",\n status: \"prospect\",\n type: \"individual\",\n tags: [\"Referral\"],\n createdAt: daysAgo(14),\n updatedAt: daysAgo(10),\n },\n {\n id: \"contact-5\",\n firstName: \"Lisa\",\n lastName: \"Thompson\",\n email: \"lisa.t@globalfit.com\",\n company: \"Global Fitness\",\n jobTitle: \"CEO\",\n status: \"active\",\n type: \"individual\",\n address: {\n city: \"Los Angeles\",\n state: \"CA\",\n country: \"US\",\n },\n createdAt: daysAgo(120),\n updatedAt: daysAgo(15),\n },\n {\n id: \"contact-6\",\n firstName: \"James\",\n lastName: \"Wilson\",\n email: \"jwilson@retired.net\",\n status: \"inactive\",\n type: \"individual\",\n notes: \"Moved out of area, no longer purchasing\",\n createdAt: daysAgo(200),\n updatedAt: daysAgo(45),\n },\n];\n\nexport const DEMO_CONTACT: Contact = DEMO_CONTACTS[0]!;\n","/**\n * Contacts hooks - stub implementation for SDK\n * In production, implement these hooks to fetch from your API\n */\n\nimport type { Contact, ContactStatus } from \"../types/screen-types\";\nimport { CONTACT_STATUSES } from \"../types/screen-types\";\nimport type { ListQueryResult, QueryResultNullable } from \"./hook-types\";\nimport { DEMO_CONTACTS, DEMO_CONTACT } from \"./demo-data/contacts\";\n\n/**\n * Type predicate to check if a status string is a valid ContactStatus.\n * Enables runtime validation with type narrowing.\n */\nexport function isContactStatus(value: string): value is ContactStatus {\n return Object.values(CONTACT_STATUSES).includes(value as ContactStatus);\n}\n\n/**\n * Parameters for filtering and paginating contacts.\n * Uses readonly properties and proper ContactStatus type for status.\n */\nexport interface UseContactsParams {\n /** Search query to filter contacts by name, email, or company */\n readonly search?: string;\n /** Filter contacts by status - uses ContactStatus union type for type safety */\n readonly status?: ContactStatus;\n /** Maximum number of contacts to return */\n readonly limit?: number;\n}\n\n/**\n * Result type for the useContacts hook.\n * Uses ListQueryResult<Contact> with totalCount and default Error type.\n */\nexport type UseContactsResult = ListQueryResult<Contact>;\n\n/**\n * Result type for the useContact hook.\n * Uses QueryResultNullable since a specific contact may not exist.\n */\nexport type UseContactResult = QueryResultNullable<Contact>;\n\n/**\n * Hook to fetch a list of contacts with optional filtering and pagination.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param params - Optional parameters for filtering and pagination\n * @returns Object containing contacts data, loading state, error state, and total count\n *\n * @example\n * ```tsx\n * const { data: contacts, isLoading, totalCount } = useContacts({\n * search: 'john',\n * status: 'active',\n * limit: 20\n * });\n * ```\n */\nexport function useContacts(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _params?: UseContactsParams,\n): UseContactsResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching\n return {\n data: [...DEMO_CONTACTS],\n isLoading: false,\n isError: false,\n totalCount: DEMO_CONTACTS.length,\n };\n}\n\n/**\n * Hook to fetch a single contact by ID.\n * This is a stub implementation - override with your own data fetching logic.\n *\n * @param contactId - The unique identifier of the contact to fetch\n * @returns Object containing contact data, loading state, and error state\n *\n * @example\n * ```tsx\n * const { data: contact, isLoading, isError } = useContact('contact-123');\n * ```\n */\nexport function useContact(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _contactId: string,\n): UseContactResult {\n // Demo data for first-run experience\n // In production, replace with actual data fetching using _contactId\n return {\n data: DEMO_CONTACT,\n isLoading: false,\n isError: false,\n };\n}\n","/**\n * Auth Types\n *\n * These types define the JWT payload structure and authentication\n * configuration options.\n */\n\n// ============================================================================\n// User Types - Derive from constant for single source of truth\n// ============================================================================\n\n/**\n * User type constant - single source of truth for user role values.\n * Use USER_TYPES.admin instead of \"admin\" for type-safe comparisons.\n */\nexport const USER_TYPES = {\n admin: \"admin\",\n rep: \"rep\",\n root_admin: \"root_admin\",\n customer: \"customer\",\n} as const;\n\n/**\n * Union type of all user types, derived from USER_TYPES constant.\n * @see deriving-typeof-for-object-keys pattern\n */\nexport type UserType = (typeof USER_TYPES)[keyof typeof USER_TYPES];\n\n/**\n * Runtime validation for user types.\n * @param value - The value to check\n * @returns true if value is a valid UserType\n */\nexport function isUserType(value: string): value is UserType {\n return Object.values(USER_TYPES).includes(value as UserType);\n}\n\n/**\n * JWT payload structure from Fluid Commerce authentication.\n * Contains user identity and role information.\n */\nexport interface JWTPayload {\n /** User ID */\n id?: number | undefined;\n /** User email address */\n email?: string | undefined;\n /** Full name of the user */\n full_name?: string | undefined;\n /** User role type */\n user_type: UserType;\n /** Original user type (for impersonation scenarios) */\n og_user_type?: UserType | undefined;\n /** Company ID the user belongs to */\n company_id?: number | undefined;\n /** Token expiration timestamp (Unix seconds) */\n exp?: number | undefined;\n /** Authentication type (e.g., \"standard\", \"impersonation\") */\n auth_type?: string | undefined;\n}\n\n/**\n * Configuration options for FluidAuthProvider.\n * All options have sensible defaults.\n */\nexport interface FluidAuthConfig {\n /**\n * URL parameter name for the auth token.\n * @default \"fluidUserToken\"\n */\n tokenKey?: string;\n\n /**\n * Cookie name for storing the auth token.\n * @default \"auth_token\"\n */\n cookieKey?: string;\n\n /**\n * Cookie max age in seconds.\n * @default 777600 (9 days)\n */\n cookieMaxAge?: number;\n\n /**\n * Grace period in milliseconds to account for clock skew\n * when checking token expiration.\n * @default 30000 (30 seconds)\n */\n gracePeriodMs?: number;\n\n /**\n * Callback invoked when authentication fails (no valid token).\n * When omitted, the SDK redirects to `authUrl` with the current URL\n * as a redirect parameter so users can log in and return.\n */\n onAuthFailure?: () => void;\n\n /**\n * Base URL for the authentication page.\n * Used by the default auth failure redirect when `onAuthFailure` is not provided.\n * Ignored when a custom `onAuthFailure` callback is set.\n * @default \"https://auth.fluid.app\"\n */\n authUrl?: string;\n\n /**\n * Enable dev-mode auth bypass.\n * When true AND running in Vite dev mode (import.meta.env.DEV),\n * auth will use a synthetic mock user instead of requiring a real JWT.\n * The mock user allows UI rendering but API calls will fail (token is null).\n * @default false\n */\n devBypass?: boolean;\n\n /**\n * JWKS (JSON Web Key Set) URL for signature verification.\n * When provided, JWT signatures will be verified against keys\n * from this endpoint before accepting the token.\n *\n * This provides defense-in-depth client-side verification.\n * Without this, tokens are only decoded (not verified) client-side,\n * and real verification happens server-side on API calls.\n *\n * @example \"https://api.fluid.app/.well-known/jwks.json\"\n */\n jwksUrl?: string;\n}\n\n/**\n * Value provided by the FluidAuthContext.\n * All properties are readonly since context values should not be mutated by consumers.\n */\nexport interface FluidAuthContextValue {\n /** Whether the user is authenticated with a valid token */\n readonly isAuthenticated: boolean;\n /** Whether authentication is still being initialized */\n readonly isLoading: boolean;\n /** Decoded JWT payload if authenticated, null otherwise */\n readonly user: JWTPayload | null;\n /** Raw JWT token string if authenticated, null otherwise */\n readonly token: string | null;\n /** Clear authentication state and stored tokens */\n readonly clearAuth: () => void;\n /** Authentication error if any occurred during initialization */\n readonly error: Error | null;\n}\n\n/**\n * Result of token validation.\n * Uses a discriminated union for type-safe handling of valid/invalid states.\n */\nexport type TokenValidationResult =\n | {\n /** Token is valid */\n isValid: true;\n /** Decoded JWT payload */\n payload: JWTPayload;\n /** No error when valid */\n error?: undefined;\n }\n | {\n /** Token is invalid */\n isValid: false;\n /** Decoded JWT payload if parseable but expired */\n payload?: JWTPayload;\n /** Error message explaining why validation failed */\n error: string;\n };\n","import { z } from \"zod\";\nimport type { FetchClientInstance } from \"@fluid-app/api-client-core\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface Company {\n id: number;\n name: string;\n logo_url?: string | null;\n icon_url?: string | null;\n}\n\nexport interface SwitchCompanyResponseCompany {\n id: number;\n name: string;\n fluid_shop: string;\n logo_url?: string | null;\n jwt: string;\n}\n\nexport interface SwitchCompanyResponseMeta {\n request_id: string;\n timestamp: string;\n}\n\nexport interface SwitchCompanyResponse {\n company: SwitchCompanyResponseCompany;\n meta: SwitchCompanyResponseMeta;\n}\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\nexport const companySchema: z.ZodType<Company> = z.object({\n id: z.number(),\n name: z.string(),\n logo_url: z.string().optional().nullable(),\n icon_url: z.string().nullable().optional(),\n});\n\nexport const switchCompanyResponseCompanySchema: z.ZodType<SwitchCompanyResponseCompany> =\n z.object({\n id: z.number().int().positive(),\n name: z.string(),\n fluid_shop: z.string(),\n logo_url: z.string().url().nullable().optional(),\n jwt: z.string(),\n });\n\nexport const switchCompanyResponseMetaSchema: z.ZodType<SwitchCompanyResponseMeta> =\n z.object({\n request_id: z.string(),\n timestamp: z.string(),\n });\n\nexport const switchCompanyResponseSchema: z.ZodType<SwitchCompanyResponse> =\n z.object({\n company: switchCompanyResponseCompanySchema,\n meta: switchCompanyResponseMetaSchema,\n });\n\n// ============================================================================\n// API function\n// ============================================================================\n\nexport function switchCompany(\n client: FetchClientInstance,\n companyId: number,\n): Promise<SwitchCompanyResponse> {\n return client\n .put<unknown>(`/authentication/company/${companyId}/switch`)\n .then((data) => switchCompanyResponseSchema.parse(data));\n}\n","// Screen Components\nexport { ProfileScreen, profileScreenPropertySchema } from \"./ProfileScreen\";\nexport {\n MessagingScreen,\n messagingScreenPropertySchema,\n} from \"./MessagingScreen\";\nexport { ContactsScreen, contactsScreenPropertySchema } from \"./ContactsScreen\";\nexport { OrdersScreen, ordersScreenPropertySchema } from \"./OrdersScreen\";\nexport {\n SubscriptionsScreen,\n subscriptionsScreenPropertySchema,\n} from \"./SubscriptionsScreen\";\nexport {\n CustomersScreen,\n customersScreenPropertySchema,\n} from \"./CustomersScreen\";\nexport { MySiteScreen, mySiteScreenPropertySchema } from \"./MySiteScreen\";\nexport {\n ShareablesScreen,\n shareablesScreenPropertySchema,\n} from \"./ShareablesScreen\";\nexport { ShopScreen, shopScreenPropertySchema } from \"./ShopScreen\";\nexport { UpgradeScreen, upgradeScreenPropertySchema } from \"./UpgradeScreen\";\nexport {\n AppDownloadScreen,\n appDownloadScreenPropertySchema,\n} from \"./AppDownloadScreen\";\n\n// Re-export all property schemas as a lazy-loadable collection\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\n\nexport const screenPropertySchemas: Record<\n string,\n () => Promise<WidgetPropertySchema>\n> = {\n ProfileScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./ProfileScreen\").then((m) => m.profileScreenPropertySchema),\n MessagingScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./MessagingScreen\").then((m) => m.messagingScreenPropertySchema),\n ContactsScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./ContactsScreen\").then((m) => m.contactsScreenPropertySchema),\n OrdersScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./OrdersScreen\").then((m) => m.ordersScreenPropertySchema),\n SubscriptionsScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./SubscriptionsScreen\").then(\n (m) => m.subscriptionsScreenPropertySchema,\n ),\n CustomersScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./CustomersScreen\").then((m) => m.customersScreenPropertySchema),\n MySiteScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./MySiteScreen\").then((m) => m.mySiteScreenPropertySchema),\n ShareablesScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./ShareablesScreen\").then((m) => m.shareablesScreenPropertySchema),\n ShopScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./ShopScreen\").then((m) => m.shopScreenPropertySchema),\n UpgradeScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./UpgradeScreen\").then((m) => m.upgradeScreenPropertySchema),\n AppDownloadScreen: (): Promise<WidgetPropertySchema> =>\n import(\"./AppDownloadScreen\").then(\n (m) => m.appDownloadScreenPropertySchema,\n ),\n};\n\n// Page Template Registration\nimport { PageTemplateRegistry } from \"../registries/page-template-registry\";\nimport { PAGE_CATEGORIES } from \"../types/page-template\";\n\n/**\n * Core page template IDs\n */\nexport const CORE_PAGE_IDS = {\n PROFILE: \"core-profile\",\n MESSAGING: \"core-messaging\",\n CONTACTS: \"core-contacts\",\n ORDERS: \"core-orders\",\n SUBSCRIPTIONS: \"core-subscriptions\",\n CUSTOMERS: \"core-customers\",\n MY_SITE: \"core-my-site\",\n SHAREABLES: \"core-shareables\",\n SHOP: \"core-shop\",\n UPGRADE: \"core-upgrade\",\n APP_DOWNLOAD: \"core-app-download\",\n} as const;\n\n/**\n * Register core page templates.\n * These are automatically registered when the SDK is imported.\n */\nfunction registerCorePageTemplates(): void {\n // Profile Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.PROFILE,\n slug: \"profile\",\n name: \"Profile\",\n description: \"User profile management\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"profile\", \"account\", \"user\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"ProfileScreen\",\n id: \"profile-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Messaging Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.MESSAGING,\n slug: \"messaging\",\n name: \"Messaging\",\n description: \"Messaging interface provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.COMMUNICATION,\n tags: [\"messaging\", \"chat\", \"conversations\", \"communication\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"MessagingScreen\",\n id: \"messaging-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Contacts Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.CONTACTS,\n slug: \"contacts\",\n name: \"Contacts\",\n description: \"Contact management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"contacts\", \"people\", \"address-book\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"ContactsScreen\",\n id: \"contacts-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Orders Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.ORDERS,\n slug: \"orders\",\n name: \"Orders\",\n description: \"Order management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"orders\", \"commerce\", \"sales\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"OrdersScreen\",\n id: \"orders-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Subscriptions Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.SUBSCRIPTIONS,\n slug: \"subscriptions\",\n name: \"Subscriptions\",\n description: \"Subscription management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"subscriptions\", \"recurring\", \"commerce\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"SubscriptionsScreen\",\n id: \"subscriptions-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Customers Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.CUSTOMERS,\n slug: \"customers\",\n name: \"Customers\",\n description: \"Customer management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"customers\", \"people\", \"commerce\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"CustomersScreen\",\n id: \"customers-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Shop Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.SHOP,\n slug: \"shop\",\n name: \"Shop\",\n description: \"Product shop with catalog browsing and product details\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"shop\", \"store\", \"products\", \"commerce\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"ShopScreen\",\n id: \"shop-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // My Site Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.MY_SITE,\n slug: \"my-site\",\n name: \"My Site\",\n description: \"Personal site management provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"my-site\", \"website\", \"portal\", \"personal\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"MySiteScreen\",\n id: \"my-site-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Upgrade Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.UPGRADE,\n slug: \"upgrade\",\n name: \"Upgrade\",\n description: \"Pro upgrade waitlist screen\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"upgrade\", \"pro\", \"waitlist\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"UpgradeScreen\",\n id: \"upgrade-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // App Download Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.APP_DOWNLOAD,\n slug: \"app-download\",\n name: \"App Download\",\n description: \"Mobile app download page with store links and QR code\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"app-download\", \"mobile\", \"qr-code\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"AppDownloadScreen\",\n id: \"app-download-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n\n // Shareables Screen\n PageTemplateRegistry.register({\n id: CORE_PAGE_IDS.SHAREABLES,\n slug: \"share\",\n name: \"Shareables\",\n description:\n \"Marketing assets and shareable content provided by Fluid Commerce\",\n category: PAGE_CATEGORIES.CORE,\n tags: [\"shareables\", \"marketing\", \"assets\", \"media\", \"products\"],\n version: \"1.0.0\",\n isCore: true,\n component_tree: [\n {\n type: \"ShareablesScreen\",\n id: \"shareables-screen-root\",\n props: {},\n },\n ],\n defaultProps: {},\n });\n}\n\n// Auto-register core templates on module load\nregisterCorePageTemplates();\n","import { useState, useMemo } from \"react\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n Button,\n} from \"@fluid-app/ui-primitives\";\nimport { LayoutGrid } from \"lucide-react\";\nimport { RepIcon } from \"@fluid-app/portal-react/components/RepIcon\";\nimport { getSystemNavigationBySection } from \"@fluid-app/portal-core/navigation/system-navigation-items\";\nimport { filterRepOnlySections } from \"../navigation/filter-nav-items\";\nimport { useAccount } from \"../hooks/use-account\";\n\nexport interface QuickLinksDropdownProps {\n onNavigate: (slug: string) => void;\n}\n\nexport function QuickLinksDropdown({\n onNavigate,\n}: QuickLinksDropdownProps): React.JSX.Element {\n const [open, setOpen] = useState(false);\n\n const { data: account } = useAccount();\n const isCustomer = account?.member_type === \"customer\";\n\n const sections = useMemo(() => {\n const all = getSystemNavigationBySection();\n return isCustomer ? filterRepOnlySections(all) : all;\n }, [isCustomer]);\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shrink-0\"\n aria-label=\"Quick links\"\n >\n <LayoutGrid className=\"h-4 w-4\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n className=\"w-175 max-w-[90vw] overflow-hidden rounded-lg p-0 shadow-lg\"\n >\n <div className=\"flex flex-col\">\n {/* Header */}\n <div className=\"bg-background flex items-center gap-2 border-b p-4\">\n <LayoutGrid className=\"text-muted-foreground h-5 w-5\" />\n <h3 className=\"text-foreground text-sm font-semibold\">Shortcuts</h3>\n </div>\n\n {/* Sections */}\n <div className=\"bg-muted space-y-6 p-6\">\n {Object.entries(sections).map(([sectionName, items]) => (\n <div key={sectionName} className=\"space-y-3\">\n <h3 className=\"text-foreground text-sm font-semibold\">\n {sectionName}\n </h3>\n <div className=\"grid grid-cols-4 gap-2\">\n {items.map((item) => (\n <Button\n key={item.slug}\n variant=\"ghost\"\n className=\"text-sidebar-foreground hover:bg-sidebar-primary hover:text-sidebar-primary-foreground h-auto justify-start gap-2 rounded-lg px-3 py-2 text-sm\"\n onClick={() => {\n if (item.slug) onNavigate(item.slug);\n setOpen(false);\n }}\n >\n {item.icon && (\n <RepIcon\n name={item.icon}\n className=\"h-4 w-4 shrink-0\"\n />\n )}\n <span className=\"truncate\">{item.label}</span>\n </Button>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","import React, {\n forwardRef,\n type AnchorHTMLAttributes,\n type MouseEvent,\n} from \"react\";\nimport { useAppNavigation } from \"./AppNavigationContext\";\n\nexport interface AppLinkProps extends Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n \"href\"\n> {\n /** Slug to navigate to (e.g. \"contacts/123\") */\n to: string;\n}\n\n/**\n * SPA-aware link that renders a real `<a href>` for accessibility\n * (right-click, ctrl+click, screen readers) but intercepts normal\n * clicks for client-side navigation.\n */\nexport const AppLink: React.ForwardRefExoticComponent<\n AppLinkProps & React.RefAttributes<HTMLAnchorElement>\n> = forwardRef<HTMLAnchorElement, AppLinkProps>(function AppLink(\n { to, onClick, children, ...rest },\n ref,\n) {\n const { navigate, buildHref } = useAppNavigation();\n\n const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {\n // Allow custom onClick handlers to run first\n onClick?.(e);\n if (e.defaultPrevented) return;\n\n // Skip SPA navigation for modifier keys, non-primary button, or external target\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n if (e.button !== 0) return;\n if (rest.target && rest.target !== \"_self\") return;\n\n e.preventDefault();\n navigate(to);\n };\n\n return (\n <a ref={ref} href={buildHref(to)} onClick={handleClick} {...rest}>\n {children}\n </a>\n );\n});\n","/**\n * Scaffold Manifest\n *\n * Tracks which files belong to the portal scaffold and their category.\n * Used by `fluid doctor` to detect drift between a scaffolded portal\n * and the canonical templates shipped with the SDK.\n *\n * Categories:\n * - \"entry\" — App bootstrap files (main.tsx, index.css)\n * - \"config\" — Developer-owned config (portal.config.ts, navigation.config.ts)\n * - \"infrastructure\" — Build/tooling config (vite, tsconfig, index.html, linting)\n */\n\nexport type FileCategory = \"entry\" | \"config\" | \"infrastructure\";\n\nexport interface ManifestEntry {\n readonly category: FileCategory;\n}\n\n/**\n * Canonical scaffold file manifest.\n *\n * Files marked as \"entry\" or \"infrastructure\" are checked by `fluid doctor`.\n * Files marked as \"config\" are developer-owned and intentionally excluded from drift checks.\n */\nexport const SCAFFOLD_MANIFEST = {\n version: 2,\n files: {\n \"src/main.tsx\": { category: \"entry\" },\n \"src/index.css\": { category: \"entry\" },\n \"index.html\": { category: \"infrastructure\" },\n \"tsconfig.json\": { category: \"infrastructure\" },\n \"vite.config.ts\": { category: \"infrastructure\" },\n \".oxlintrc.json\": { category: \"infrastructure\" },\n },\n /** Developer-owned files — never checked for drift */\n developerOwned: [\n \"src/portal.config.ts\",\n \"src/navigation.config.ts\",\n \"src/screens/*\",\n ],\n} as const;\n\nexport type ScaffoldFile = keyof typeof SCAFFOLD_MANIFEST.files;\n"],"mappings":"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"}
|