@fluid-app/portal-sdk 0.1.11

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.
Files changed (35) hide show
  1. package/README.md +415 -0
  2. package/dist/ContactsScreen-CB6l0Lf1.mjs +24 -0
  3. package/dist/ContactsScreen-CB6l0Lf1.mjs.map +1 -0
  4. package/dist/ContactsScreen-Cqyrl4AQ.cjs +41 -0
  5. package/dist/ContactsScreen-Cqyrl4AQ.cjs.map +1 -0
  6. package/dist/CoreScreenPlaceholder-CA2-2V5o.cjs +38 -0
  7. package/dist/CoreScreenPlaceholder-CA2-2V5o.cjs.map +1 -0
  8. package/dist/CoreScreenPlaceholder-D93ZYKt2.mjs +32 -0
  9. package/dist/CoreScreenPlaceholder-D93ZYKt2.mjs.map +1 -0
  10. package/dist/CustomersScreen-BEar6Leg.mjs +24 -0
  11. package/dist/CustomersScreen-BEar6Leg.mjs.map +1 -0
  12. package/dist/CustomersScreen-gFgOzBox.cjs +41 -0
  13. package/dist/CustomersScreen-gFgOzBox.cjs.map +1 -0
  14. package/dist/MessagingScreen-BklF48Fn.mjs +1281 -0
  15. package/dist/MessagingScreen-BklF48Fn.mjs.map +1 -0
  16. package/dist/MessagingScreen-CHb-scHD.cjs +1454 -0
  17. package/dist/MessagingScreen-CHb-scHD.cjs.map +1 -0
  18. package/dist/OrdersScreen-CPGDYvEd.cjs +41 -0
  19. package/dist/OrdersScreen-CPGDYvEd.cjs.map +1 -0
  20. package/dist/OrdersScreen-DB1v051q.mjs +24 -0
  21. package/dist/OrdersScreen-DB1v051q.mjs.map +1 -0
  22. package/dist/ProductsScreen-B1tlIth6.cjs +41 -0
  23. package/dist/ProductsScreen-B1tlIth6.cjs.map +1 -0
  24. package/dist/ProductsScreen-nVDsY6kf.mjs +24 -0
  25. package/dist/ProductsScreen-nVDsY6kf.mjs.map +1 -0
  26. package/dist/chunk-D1SwGrFN.mjs +27 -0
  27. package/dist/index.cjs +3610 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +2500 -0
  30. package/dist/index.d.cts.map +1 -0
  31. package/dist/index.d.mts +2498 -0
  32. package/dist/index.d.mts.map +1 -0
  33. package/dist/index.mjs +2921 -0
  34. package/dist/index.mjs.map +1 -0
  35. package/package.json +76 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,3610 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_MessagingScreen = require("./MessagingScreen-CHb-scHD.cjs");
3
+ const require_CoreScreenPlaceholder = require("./CoreScreenPlaceholder-CA2-2V5o.cjs");
4
+ const require_ContactsScreen = require("./ContactsScreen-Cqyrl4AQ.cjs");
5
+ const require_OrdersScreen = require("./OrdersScreen-CPGDYvEd.cjs");
6
+ const require_CustomersScreen = require("./CustomersScreen-gFgOzBox.cjs");
7
+ const require_ProductsScreen = require("./ProductsScreen-B1tlIth6.cjs");
8
+ let react = require("react");
9
+ react = require_MessagingScreen.__toESM(react);
10
+ let _tanstack_react_query = require("@tanstack/react-query");
11
+ let _fluid_app_portal_core_theme = require("@fluid-app/portal-core/theme");
12
+ let react_jsx_runtime = require("react/jsx-runtime");
13
+ let _fluid_app_portal_widgets_contexts = require("@fluid-app/portal-widgets/contexts");
14
+ let _fluid_app_portal_core_shell_AppShellLayout = require("@fluid-app/portal-core/shell/AppShellLayout");
15
+ let _fluid_app_portal_core_shell_ThemeModeContext = require("@fluid-app/portal-core/shell/ThemeModeContext");
16
+ let _fluid_app_portal_core_navigation_system_navigation_items = require("@fluid-app/portal-core/navigation/system-navigation-items");
17
+ let _fluid_app_portal_core_shell_ScreenHeader = require("@fluid-app/portal-core/shell/ScreenHeader");
18
+ let _fluid_app_portal_core_shell_ScreenHeaderContext = require("@fluid-app/portal-core/shell/ScreenHeaderContext");
19
+ let _fortawesome_react_fontawesome = require("@fortawesome/react-fontawesome");
20
+ let _fortawesome_pro_regular_svg_icons_faEllipsis = require("@fortawesome/pro-regular-svg-icons/faEllipsis");
21
+ let _fortawesome_pro_regular_svg_icons_faXmark = require("@fortawesome/pro-regular-svg-icons/faXmark");
22
+ let _fluid_app_portal_core_components_RepIcon = require("@fluid-app/portal-core/components/RepIcon");
23
+ let _fluid_app_portal_core_shell_sidebar = require("@fluid-app/portal-core/shell/sidebar");
24
+ let _fortawesome_pro_regular_svg_icons_faBars = require("@fortawesome/pro-regular-svg-icons/faBars");
25
+ let _fortawesome_pro_regular_svg_icons_faSun = require("@fortawesome/pro-regular-svg-icons/faSun");
26
+ let _fortawesome_pro_regular_svg_icons_faMoon = require("@fortawesome/pro-regular-svg-icons/faMoon");
27
+ let _fortawesome_pro_regular_svg_icons_faTableCellsLarge = require("@fortawesome/pro-regular-svg-icons/faTableCellsLarge");
28
+ let _fluid_app_portal_core_data_sources_DataAwareWidget = require("@fluid-app/portal-core/data-sources/DataAwareWidget");
29
+ let _fluid_app_portal_widgets_widgets = require("@fluid-app/portal-widgets/widgets");
30
+ let _fluid_app_portal_core_types = require("@fluid-app/portal-core/types");
31
+ let _fluid_app_auth = require("@fluid-app/auth");
32
+ let _fluid_app_portal_core_registries = require("@fluid-app/portal-core/registries");
33
+ let _fluid_app_portal_core_widget_utils = require("@fluid-app/portal-core/widget-utils");
34
+ //#region src/types/page-template.ts
35
+ /**
36
+ * Built-in page category IDs
37
+ */
38
+ const PAGE_CATEGORIES = {
39
+ CORE: "core",
40
+ COMMERCE: "commerce",
41
+ COMMUNICATION: "communication",
42
+ DATA: "data",
43
+ CUSTOM: "custom"
44
+ };
45
+ //#endregion
46
+ //#region src/registries/page-template-registry.ts
47
+ /**
48
+ * Registry for managing reusable page templates.
49
+ *
50
+ * The registry provides a central store for page templates that can be
51
+ * shared across multiple navigations. Core pages (like Messaging, Contacts)
52
+ * are pre-registered and cannot be removed.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * // Register a custom page template
57
+ * PageTemplateRegistry.register({
58
+ * id: 'custom-dashboard',
59
+ * slug: 'dashboard',
60
+ * name: 'Custom Dashboard',
61
+ * category: 'custom',
62
+ * version: '1.0.0',
63
+ * component_tree: [{ type: 'TextWidget', props: { text: 'Hello' } }],
64
+ * });
65
+ *
66
+ * // Get a template by ID
67
+ * const template = PageTemplateRegistry.get('custom-dashboard');
68
+ *
69
+ * // List all templates in a category
70
+ * const corePages = PageTemplateRegistry.getByCategory('core');
71
+ * ```
72
+ */
73
+ var PageTemplateRegistryImpl = class {
74
+ templates = /* @__PURE__ */ new Map();
75
+ categories = [];
76
+ constructor() {
77
+ this.categories = [
78
+ {
79
+ id: PAGE_CATEGORIES.CORE,
80
+ label: "Core Features",
81
+ icon: "star"
82
+ },
83
+ {
84
+ id: PAGE_CATEGORIES.COMMERCE,
85
+ label: "Commerce",
86
+ icon: "shopping-cart"
87
+ },
88
+ {
89
+ id: PAGE_CATEGORIES.COMMUNICATION,
90
+ label: "Communication",
91
+ icon: "message-circle"
92
+ },
93
+ {
94
+ id: PAGE_CATEGORIES.DATA,
95
+ label: "Data & Analytics",
96
+ icon: "bar-chart"
97
+ },
98
+ {
99
+ id: PAGE_CATEGORIES.CUSTOM,
100
+ label: "Custom",
101
+ icon: "puzzle"
102
+ }
103
+ ];
104
+ }
105
+ /**
106
+ * Register a new page template.
107
+ * @throws Error if a template with the same ID already exists
108
+ */
109
+ register(template) {
110
+ if (this.templates.has(template.id)) throw new Error(`Page template with ID "${template.id}" is already registered`);
111
+ this.templates.set(template.id, template);
112
+ }
113
+ /**
114
+ * Unregister a page template by ID.
115
+ * Core templates cannot be unregistered.
116
+ * @returns true if the template was removed, false if it didn't exist or is a core template
117
+ */
118
+ unregister(id) {
119
+ const template = this.templates.get(id);
120
+ if (!template) return false;
121
+ if (template.isCore) {
122
+ console.warn(`Cannot unregister core page template "${id}". Core templates are required.`);
123
+ return false;
124
+ }
125
+ return this.templates.delete(id);
126
+ }
127
+ /**
128
+ * Get a page template by ID.
129
+ */
130
+ get(id) {
131
+ return this.templates.get(id);
132
+ }
133
+ /**
134
+ * Get all page templates in a specific category.
135
+ */
136
+ getByCategory(category) {
137
+ return Array.from(this.templates.values()).filter((t) => t.category === category);
138
+ }
139
+ /**
140
+ * List all registered page templates.
141
+ */
142
+ listAll() {
143
+ return Array.from(this.templates.values());
144
+ }
145
+ /**
146
+ * List all core page templates (isCore: true).
147
+ */
148
+ listCore() {
149
+ return Array.from(this.templates.values()).filter((t) => t.isCore);
150
+ }
151
+ /**
152
+ * List all non-core page templates.
153
+ */
154
+ listOptional() {
155
+ return Array.from(this.templates.values()).filter((t) => !t.isCore);
156
+ }
157
+ /**
158
+ * List all registered categories.
159
+ */
160
+ listCategories() {
161
+ return [...this.categories];
162
+ }
163
+ /**
164
+ * Add a custom category.
165
+ */
166
+ addCategory(category) {
167
+ if (this.categories.some((c) => c.id === category.id)) {
168
+ console.warn(`Category with ID "${category.id}" already exists`);
169
+ return;
170
+ }
171
+ this.categories.push(category);
172
+ }
173
+ /**
174
+ * Check if a template exists by ID.
175
+ */
176
+ has(id) {
177
+ return this.templates.has(id);
178
+ }
179
+ /**
180
+ * Get the count of registered templates.
181
+ */
182
+ get size() {
183
+ return this.templates.size;
184
+ }
185
+ /**
186
+ * Clear all non-core templates.
187
+ * Useful for testing or resetting the registry.
188
+ */
189
+ clearNonCore() {
190
+ for (const [id, template] of this.templates) if (!template.isCore) this.templates.delete(id);
191
+ }
192
+ };
193
+ /**
194
+ * Global page template registry singleton.
195
+ *
196
+ * This registry is automatically populated with core page templates
197
+ * (Messaging, Contacts) when the SDK is imported.
198
+ */
199
+ const PageTemplateRegistry = new PageTemplateRegistryImpl();
200
+ //#endregion
201
+ //#region src/core/resolve-pages.ts
202
+ /**
203
+ * Apply prop overrides to widgets in a component tree.
204
+ * Recursively walks widget.props.children so overrides targeting
205
+ * nested widgets (inside LayoutWidget, ContainerWidget, etc.) are applied.
206
+ *
207
+ * @param componentTree - The original component tree from the page template
208
+ * @param overrides - Array of widget-specific prop overrides
209
+ * @returns A new component tree with overrides applied
210
+ */
211
+ function applyOverrides(componentTree, overrides) {
212
+ if (!overrides.length) return [...componentTree];
213
+ const overrideMap = new Map(overrides.map((o) => [o.widget_id, o.props]));
214
+ return componentTree.map((widget) => applyWidgetOverrides(widget, overrideMap));
215
+ }
216
+ /**
217
+ * Recursively apply overrides to a widget and its children.
218
+ * Only clones widgets that actually change (have an override or contain children that might).
219
+ */
220
+ function applyWidgetOverrides(widget, overrideMap) {
221
+ const override = widget.id ? overrideMap.get(widget.id) : void 0;
222
+ const children = widget.props.children;
223
+ const hasChildren = Array.isArray(children) && children.length > 0;
224
+ if (!override && !hasChildren) return widget;
225
+ const newProps = override ? {
226
+ ...widget.props,
227
+ ...override
228
+ } : { ...widget.props };
229
+ if (hasChildren) newProps.children = children.map((child) => applyWidgetOverrides(child, overrideMap));
230
+ return {
231
+ ...widget,
232
+ props: newProps
233
+ };
234
+ }
235
+ /**
236
+ * Resolve a page reference to a screen definition.
237
+ *
238
+ * @param ref - The page reference from navigation
239
+ * @returns A ScreenDefinition or undefined if the template doesn't exist
240
+ */
241
+ function resolvePageReference(ref) {
242
+ const template = PageTemplateRegistry.get(ref.page_template_id);
243
+ if (!template) {
244
+ console.warn(`Page template "${ref.page_template_id}" not found in registry`);
245
+ return;
246
+ }
247
+ const componentTree = ref.overrides ? applyOverrides(template.component_tree, ref.overrides) : [...template.component_tree];
248
+ return {
249
+ id: ref.screen_id,
250
+ slug: template.slug,
251
+ name: template.name,
252
+ component_tree: componentTree
253
+ };
254
+ }
255
+ /**
256
+ * Resolve all page references and local screens into a unified screen list.
257
+ *
258
+ * This function merges:
259
+ * 1. Screen definitions from page_refs (shared templates)
260
+ * 2. Local screen definitions (for backwards compatibility and custom screens)
261
+ *
262
+ * When a screen_id appears in both page_refs and screens, the local screen
263
+ * takes precedence (allows local overrides of template pages).
264
+ *
265
+ * @param navigation - The navigation configuration
266
+ * @returns A unified array of ScreenDefinition objects
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * const navigation: Navigation = {
271
+ * definition_id: 1,
272
+ * id: 1,
273
+ * name: "Main Nav",
274
+ * navigation_items: [...],
275
+ * screens: [
276
+ * // Local custom screen
277
+ * { id: 1, slug: "home", name: "Home", component_tree: [...] }
278
+ * ],
279
+ * page_refs: [
280
+ * // Reference to shared messaging template
281
+ * { page_template_id: "core-messaging", screen_id: 2 }
282
+ * ],
283
+ * };
284
+ *
285
+ * const allScreens = resolveNavigationPages(navigation);
286
+ * // Returns: [home screen, messaging screen from template]
287
+ * ```
288
+ */
289
+ function resolveNavigationPages(navigation) {
290
+ const localScreenIds = new Set(navigation.screens.map((s) => s.id));
291
+ const result = [...navigation.screens];
292
+ if (navigation.page_refs) for (const ref of navigation.page_refs) {
293
+ if (localScreenIds.has(ref.screen_id)) continue;
294
+ const screen = resolvePageReference(ref);
295
+ if (screen) result.push(screen);
296
+ }
297
+ return result;
298
+ }
299
+ /**
300
+ * Get all available page templates for use in navigation.
301
+ *
302
+ * @returns Array of page templates from the registry
303
+ */
304
+ function getAvailablePageTemplates() {
305
+ return PageTemplateRegistry.listAll();
306
+ }
307
+ /**
308
+ * Get core page templates that are required for basic functionality.
309
+ *
310
+ * @returns Array of core page templates
311
+ */
312
+ function getCorePageTemplates() {
313
+ return PageTemplateRegistry.listCore();
314
+ }
315
+ /**
316
+ * Get optional page templates that can be added to navigation.
317
+ *
318
+ * @returns Array of optional (non-core) page templates
319
+ */
320
+ function getOptionalPageTemplates() {
321
+ return PageTemplateRegistry.listOptional();
322
+ }
323
+ /**
324
+ * Check if a navigation has all required core pages.
325
+ *
326
+ * @param navigation - The navigation to check
327
+ * @returns Object with validation result and missing page IDs
328
+ */
329
+ function validateNavigationPages(navigation) {
330
+ const corePages = PageTemplateRegistry.listCore();
331
+ const referencedTemplateIds = new Set(navigation.page_refs?.map((ref) => ref.page_template_id) ?? []);
332
+ const missingCorePages = corePages.filter((page) => !referencedTemplateIds.has(page.id)).map((page) => page.id);
333
+ return {
334
+ valid: missingCorePages.length === 0,
335
+ missingCorePages
336
+ };
337
+ }
338
+ //#endregion
339
+ //#region src/providers/PageTemplateProvider.tsx
340
+ /** Stable empty array for the default `templates` prop (avoids new reference each render) */
341
+ const EMPTY_TEMPLATES = [];
342
+ const PageTemplateContext = (0, react.createContext)(null);
343
+ /**
344
+ * Provider for page template resolution.
345
+ *
346
+ * This provider:
347
+ * 1. Registers any custom templates passed via props
348
+ * 2. Provides methods for resolving navigation pages
349
+ * 3. Cleans up custom templates on unmount
350
+ *
351
+ * @example
352
+ * ```tsx
353
+ * // With custom templates
354
+ * const customTemplates: PageTemplate[] = [
355
+ * {
356
+ * id: 'custom-dashboard',
357
+ * slug: 'dashboard',
358
+ * name: 'Dashboard',
359
+ * category: 'custom',
360
+ * version: '1.0.0',
361
+ * component_tree: [{ type: 'TextWidget', props: { text: 'Custom Dashboard' } }],
362
+ * },
363
+ * ];
364
+ *
365
+ * <PageTemplateProvider templates={customTemplates}>
366
+ * <App />
367
+ * </PageTemplateProvider>
368
+ *
369
+ * // Without custom templates (uses only core templates)
370
+ * <PageTemplateProvider>
371
+ * <App />
372
+ * </PageTemplateProvider>
373
+ * ```
374
+ */
375
+ function PageTemplateProvider({ children, templates = EMPTY_TEMPLATES }) {
376
+ const registeredIds = (0, react.useRef)([]);
377
+ (0, react.useEffect)(() => {
378
+ const registered = [];
379
+ for (const template of templates) if (!PageTemplateRegistry.has(template.id)) try {
380
+ PageTemplateRegistry.register(template);
381
+ registered.push(template.id);
382
+ } catch (error) {
383
+ console.warn(`Failed to register page template "${template.id}":`, error);
384
+ }
385
+ registeredIds.current = registered;
386
+ return () => {
387
+ for (const id of registeredIds.current) PageTemplateRegistry.unregister(id);
388
+ registeredIds.current = [];
389
+ };
390
+ }, [templates.map((t) => t.id).join(",")]);
391
+ const contextValue = (0, react.useMemo)(() => ({
392
+ resolvePages: resolveNavigationPages,
393
+ listTemplates: () => PageTemplateRegistry.listAll(),
394
+ getTemplate: (id) => PageTemplateRegistry.get(id),
395
+ hasTemplate: (id) => PageTemplateRegistry.has(id)
396
+ }), []);
397
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageTemplateContext.Provider, {
398
+ value: contextValue,
399
+ children
400
+ });
401
+ }
402
+ /**
403
+ * Hook to access page template functionality.
404
+ *
405
+ * @throws Error if used outside of PageTemplateProvider
406
+ *
407
+ * @example
408
+ * ```tsx
409
+ * function NavigationRenderer({ navigation }: { navigation: Navigation }) {
410
+ * const { resolvePages } = usePageTemplates();
411
+ * const screens = resolvePages(navigation);
412
+ *
413
+ * return (
414
+ * <div>
415
+ * {screens.map((screen) => (
416
+ * <Screen key={screen.id} definition={screen} />
417
+ * ))}
418
+ * </div>
419
+ * );
420
+ * }
421
+ * ```
422
+ */
423
+ function usePageTemplates() {
424
+ const context = (0, react.useContext)(PageTemplateContext);
425
+ if (!context) throw new Error("usePageTemplates must be used within a PageTemplateProvider");
426
+ return context;
427
+ }
428
+ /**
429
+ * Hook to resolve navigation pages directly.
430
+ * Convenience wrapper around usePageTemplates().resolvePages.
431
+ *
432
+ * @param navigation - The navigation to resolve
433
+ * @returns Array of resolved screen definitions
434
+ */
435
+ function useResolvedPages(navigation) {
436
+ const { resolvePages } = usePageTemplates();
437
+ return (0, react.useMemo)(() => resolvePages(navigation), [resolvePages, navigation]);
438
+ }
439
+ //#endregion
440
+ //#region src/hooks/use-fluid-profile.ts
441
+ /**
442
+ * Query key for profile data
443
+ */
444
+ const PROFILE_QUERY_KEY = ["fluid", "profile"];
445
+ /**
446
+ * Hook to fetch the portal profile (themes, navigation, screens)
447
+ *
448
+ * @example
449
+ * ```tsx
450
+ * function Navigation() {
451
+ * const { data: profile, isLoading } = useFluidProfile();
452
+ *
453
+ * if (isLoading) return <Spinner />;
454
+ *
455
+ * return (
456
+ * <nav>
457
+ * {profile?.navigation.navigation_items.map(item => (
458
+ * <NavItem key={item.id} item={item} />
459
+ * ))}
460
+ * </nav>
461
+ * );
462
+ * }
463
+ * ```
464
+ */
465
+ function useFluidProfile() {
466
+ const api = require_MessagingScreen.useFluidApi();
467
+ return (0, _tanstack_react_query.useQuery)({
468
+ queryKey: PROFILE_QUERY_KEY,
469
+ queryFn: () => api.profile.get()
470
+ });
471
+ }
472
+ //#endregion
473
+ //#region ../../../node_modules/.pnpm/@tanstack+query-core@5.90.12/node_modules/@tanstack/query-core/build/modern/timeoutManager.js
474
+ var defaultTimeoutProvider = {
475
+ setTimeout: (callback, delay) => setTimeout(callback, delay),
476
+ clearTimeout: (timeoutId) => clearTimeout(timeoutId),
477
+ setInterval: (callback, delay) => setInterval(callback, delay),
478
+ clearInterval: (intervalId) => clearInterval(intervalId)
479
+ };
480
+ var TimeoutManager = class {
481
+ #provider = defaultTimeoutProvider;
482
+ #providerCalled = false;
483
+ setTimeoutProvider(provider) {
484
+ if (process.env.NODE_ENV !== "production") {
485
+ if (this.#providerCalled && provider !== this.#provider) console.error(`[timeoutManager]: Switching provider after calls to previous provider might result in unexpected behavior.`, {
486
+ previous: this.#provider,
487
+ provider
488
+ });
489
+ }
490
+ this.#provider = provider;
491
+ if (process.env.NODE_ENV !== "production") this.#providerCalled = false;
492
+ }
493
+ setTimeout(callback, delay) {
494
+ if (process.env.NODE_ENV !== "production") this.#providerCalled = true;
495
+ return this.#provider.setTimeout(callback, delay);
496
+ }
497
+ clearTimeout(timeoutId) {
498
+ this.#provider.clearTimeout(timeoutId);
499
+ }
500
+ setInterval(callback, delay) {
501
+ if (process.env.NODE_ENV !== "production") this.#providerCalled = true;
502
+ return this.#provider.setInterval(callback, delay);
503
+ }
504
+ clearInterval(intervalId) {
505
+ this.#provider.clearInterval(intervalId);
506
+ }
507
+ };
508
+ new TimeoutManager();
509
+ function systemSetTimeoutZero(callback) {
510
+ setTimeout(callback, 0);
511
+ }
512
+ typeof window === "undefined" || "Deno" in globalThis;
513
+ function matchQuery(filters, query) {
514
+ const { type = "all", exact, fetchStatus, predicate, queryKey, stale } = filters;
515
+ if (queryKey) {
516
+ if (exact) {
517
+ if (query.queryHash !== hashQueryKeyByOptions(queryKey, query.options)) return false;
518
+ } else if (!partialMatchKey(query.queryKey, queryKey)) return false;
519
+ }
520
+ if (type !== "all") {
521
+ const isActive = query.isActive();
522
+ if (type === "active" && !isActive) return false;
523
+ if (type === "inactive" && isActive) return false;
524
+ }
525
+ if (typeof stale === "boolean" && query.isStale() !== stale) return false;
526
+ if (fetchStatus && fetchStatus !== query.state.fetchStatus) return false;
527
+ if (predicate && !predicate(query)) return false;
528
+ return true;
529
+ }
530
+ function hashQueryKeyByOptions(queryKey, options) {
531
+ return (options?.queryKeyHashFn || hashKey)(queryKey);
532
+ }
533
+ function hashKey(queryKey) {
534
+ return JSON.stringify(queryKey, (_, val) => isPlainObject(val) ? Object.keys(val).sort().reduce((result, key) => {
535
+ result[key] = val[key];
536
+ return result;
537
+ }, {}) : val);
538
+ }
539
+ function partialMatchKey(a, b) {
540
+ if (a === b) return true;
541
+ if (typeof a !== typeof b) return false;
542
+ if (a && b && typeof a === "object" && typeof b === "object") return Object.keys(b).every((key) => partialMatchKey(a[key], b[key]));
543
+ return false;
544
+ }
545
+ function isPlainObject(o) {
546
+ if (!hasObjectPrototype(o)) return false;
547
+ const ctor = o.constructor;
548
+ if (ctor === void 0) return true;
549
+ const prot = ctor.prototype;
550
+ if (!hasObjectPrototype(prot)) return false;
551
+ if (!prot.hasOwnProperty("isPrototypeOf")) return false;
552
+ if (Object.getPrototypeOf(o) !== Object.prototype) return false;
553
+ return true;
554
+ }
555
+ function hasObjectPrototype(o) {
556
+ return Object.prototype.toString.call(o) === "[object Object]";
557
+ }
558
+ //#endregion
559
+ //#region ../../../node_modules/.pnpm/@tanstack+query-core@5.90.12/node_modules/@tanstack/query-core/build/modern/notifyManager.js
560
+ var defaultScheduler = systemSetTimeoutZero;
561
+ function createNotifyManager() {
562
+ let queue = [];
563
+ let transactions = 0;
564
+ let notifyFn = (callback) => {
565
+ callback();
566
+ };
567
+ let batchNotifyFn = (callback) => {
568
+ callback();
569
+ };
570
+ let scheduleFn = defaultScheduler;
571
+ const schedule = (callback) => {
572
+ if (transactions) queue.push(callback);
573
+ else scheduleFn(() => {
574
+ notifyFn(callback);
575
+ });
576
+ };
577
+ const flush = () => {
578
+ const originalQueue = queue;
579
+ queue = [];
580
+ if (originalQueue.length) scheduleFn(() => {
581
+ batchNotifyFn(() => {
582
+ originalQueue.forEach((callback) => {
583
+ notifyFn(callback);
584
+ });
585
+ });
586
+ });
587
+ };
588
+ return {
589
+ batch: (callback) => {
590
+ let result;
591
+ transactions++;
592
+ try {
593
+ result = callback();
594
+ } finally {
595
+ transactions--;
596
+ if (!transactions) flush();
597
+ }
598
+ return result;
599
+ },
600
+ batchCalls: (callback) => {
601
+ return (...args) => {
602
+ schedule(() => {
603
+ callback(...args);
604
+ });
605
+ };
606
+ },
607
+ schedule,
608
+ setNotifyFunction: (fn) => {
609
+ notifyFn = fn;
610
+ },
611
+ setBatchNotifyFunction: (fn) => {
612
+ batchNotifyFn = fn;
613
+ },
614
+ setScheduler: (fn) => {
615
+ scheduleFn = fn;
616
+ }
617
+ };
618
+ }
619
+ var notifyManager = createNotifyManager();
620
+ //#endregion
621
+ //#region ../../../node_modules/.pnpm/@tanstack+query-persist-client-core@5.91.11/node_modules/@tanstack/query-persist-client-core/build/modern/createPersister.js
622
+ var PERSISTER_KEY_PREFIX = "tanstack-query";
623
+ function experimental_createQueryPersister({ storage, buster = "", maxAge = 1e3 * 60 * 60 * 24, serialize = JSON.stringify, deserialize = JSON.parse, prefix = PERSISTER_KEY_PREFIX, refetchOnRestore = true, filters }) {
624
+ function isExpiredOrBusted(persistedQuery) {
625
+ if (persistedQuery.state.dataUpdatedAt) {
626
+ const expired = Date.now() - persistedQuery.state.dataUpdatedAt > maxAge;
627
+ const busted = persistedQuery.buster !== buster;
628
+ if (expired || busted) return true;
629
+ return false;
630
+ }
631
+ return true;
632
+ }
633
+ async function retrieveQuery(queryHash, afterRestoreMacroTask) {
634
+ if (storage != null) {
635
+ const storageKey = `${prefix}-${queryHash}`;
636
+ try {
637
+ const storedData = await storage.getItem(storageKey);
638
+ if (storedData) {
639
+ const persistedQuery = await deserialize(storedData);
640
+ if (isExpiredOrBusted(persistedQuery)) await storage.removeItem(storageKey);
641
+ else {
642
+ if (afterRestoreMacroTask) notifyManager.schedule(() => afterRestoreMacroTask(persistedQuery));
643
+ return persistedQuery.state.data;
644
+ }
645
+ }
646
+ } catch (err) {
647
+ if (process.env.NODE_ENV === "development") {
648
+ console.error(err);
649
+ console.warn("Encountered an error attempting to restore query cache from persisted location.");
650
+ }
651
+ await storage.removeItem(storageKey);
652
+ }
653
+ }
654
+ }
655
+ async function persistQueryByKey(queryKey, queryClient) {
656
+ if (storage != null) {
657
+ const query = queryClient.getQueryCache().find({ queryKey });
658
+ if (query) await persistQuery(query);
659
+ else if (process.env.NODE_ENV === "development") console.warn("Could not find query to be persisted. QueryKey:", JSON.stringify(queryKey));
660
+ }
661
+ }
662
+ async function persistQuery(query) {
663
+ if (storage != null) {
664
+ const storageKey = `${prefix}-${query.queryHash}`;
665
+ storage.setItem(storageKey, await serialize({
666
+ state: query.state,
667
+ queryKey: query.queryKey,
668
+ queryHash: query.queryHash,
669
+ buster
670
+ }));
671
+ }
672
+ }
673
+ async function persisterFn(queryFn, ctx, query) {
674
+ const matchesFilter = filters ? matchQuery(filters, query) : true;
675
+ if (matchesFilter && query.state.data === void 0 && storage != null) {
676
+ const restoredData = await retrieveQuery(query.queryHash, (persistedQuery) => {
677
+ query.setState({
678
+ dataUpdatedAt: persistedQuery.state.dataUpdatedAt,
679
+ errorUpdatedAt: persistedQuery.state.errorUpdatedAt
680
+ });
681
+ if (refetchOnRestore === "always" || refetchOnRestore === true && query.isStale()) query.fetch();
682
+ });
683
+ if (restoredData !== void 0) return Promise.resolve(restoredData);
684
+ }
685
+ const queryFnResult = await queryFn(ctx);
686
+ if (matchesFilter && storage != null) notifyManager.schedule(() => {
687
+ persistQuery(query);
688
+ });
689
+ return Promise.resolve(queryFnResult);
690
+ }
691
+ async function persisterGc() {
692
+ if (storage?.entries) {
693
+ const entries = await storage.entries();
694
+ for (const [key, value] of entries) if (key.startsWith(prefix)) {
695
+ if (isExpiredOrBusted(await deserialize(value))) await storage.removeItem(key);
696
+ }
697
+ } else if (process.env.NODE_ENV === "development") throw new Error("Provided storage does not implement `entries` method. Garbage collection is not possible without ability to iterate over storage items.");
698
+ }
699
+ async function restoreQueries(queryClient, filters2 = {}) {
700
+ const { exact, queryKey } = filters2;
701
+ if (storage?.entries) {
702
+ const entries = await storage.entries();
703
+ for (const [key, value] of entries) if (key.startsWith(prefix)) {
704
+ const persistedQuery = await deserialize(value);
705
+ if (isExpiredOrBusted(persistedQuery)) {
706
+ await storage.removeItem(key);
707
+ continue;
708
+ }
709
+ if (queryKey) {
710
+ if (exact) {
711
+ if (persistedQuery.queryHash !== hashKey(queryKey)) continue;
712
+ } else if (!partialMatchKey(persistedQuery.queryKey, queryKey)) continue;
713
+ }
714
+ queryClient.setQueryData(persistedQuery.queryKey, persistedQuery.state.data, { updatedAt: persistedQuery.state.dataUpdatedAt });
715
+ }
716
+ } else if (process.env.NODE_ENV === "development") throw new Error("Provided storage does not implement `entries` method. Restoration of all stored entries is not possible without ability to iterate over storage items.");
717
+ }
718
+ return {
719
+ persisterFn,
720
+ persistQuery,
721
+ persistQueryByKey,
722
+ retrieveQuery,
723
+ persisterGc,
724
+ restoreQueries
725
+ };
726
+ }
727
+ //#endregion
728
+ //#region ../../platform/query-persister/src/persister.ts
729
+ const DB_NAME = "fluid_tanstack_query_cache";
730
+ const STORE_NAME = "fluid_queries";
731
+ const VERSION = 1;
732
+ let dbPromise = null;
733
+ async function deleteDatabase() {
734
+ return new Promise((resolve, reject) => {
735
+ console.warn("[IDB] Deleting database due to error");
736
+ const req = indexedDB.deleteDatabase(DB_NAME);
737
+ req.onsuccess = () => {
738
+ console.log("[IDB] Database deleted successfully");
739
+ resolve();
740
+ };
741
+ req.onerror = () => {
742
+ console.error("[IDB] Failed to delete database:", req.error);
743
+ reject(req.error ?? /* @__PURE__ */ new Error("deleteDatabase failed"));
744
+ };
745
+ req.onblocked = () => {
746
+ console.warn("[IDB] Delete blocked: close all tabs using this database");
747
+ };
748
+ });
749
+ }
750
+ function openDatabase() {
751
+ return new Promise((resolve, reject) => {
752
+ const req = indexedDB.open(DB_NAME, VERSION);
753
+ req.onupgradeneeded = () => {
754
+ const upgradeDb = req.result;
755
+ if (!upgradeDb.objectStoreNames.contains(STORE_NAME)) upgradeDb.createObjectStore(STORE_NAME);
756
+ };
757
+ req.onsuccess = () => {
758
+ const conn = req.result;
759
+ conn.onversionchange = () => {
760
+ console.trace("[IDB] version change – closing connection");
761
+ conn.close();
762
+ dbPromise = null;
763
+ };
764
+ resolve(conn);
765
+ };
766
+ req.onblocked = () => {
767
+ console.warn("[IDB] open blocked: another connection is holding the DB");
768
+ };
769
+ req.onerror = () => {
770
+ reject(req.error instanceof Error ? req.error : /* @__PURE__ */ new Error(`IndexedDB open failed: ${String(req.error)}`));
771
+ };
772
+ });
773
+ }
774
+ async function getDbWithRecovery() {
775
+ try {
776
+ return await openDatabase();
777
+ } catch (err) {
778
+ console.warn("[IDB] Initial open failed, attempting recovery:", err);
779
+ try {
780
+ await deleteDatabase();
781
+ console.log("[IDB] Retrying database open after deletion");
782
+ return await openDatabase();
783
+ } catch (retryErr) {
784
+ console.error("[IDB] Recovery failed:", retryErr);
785
+ throw retryErr;
786
+ }
787
+ }
788
+ }
789
+ function getDb() {
790
+ if (dbPromise) return dbPromise;
791
+ dbPromise = getDbWithRecovery().catch((err) => {
792
+ dbPromise = null;
793
+ throw err;
794
+ });
795
+ return dbPromise;
796
+ }
797
+ const storage = {
798
+ async getItem(key) {
799
+ try {
800
+ const db = await getDb();
801
+ return new Promise((res) => {
802
+ try {
803
+ const r = db.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME).get(key);
804
+ r.onsuccess = () => res(r.result);
805
+ r.onerror = () => {
806
+ console.trace("[IDB] getItem error:", r.error);
807
+ res(void 0);
808
+ };
809
+ } catch (txErr) {
810
+ console.trace("[IDB] getItem transaction error:", txErr);
811
+ res(void 0);
812
+ }
813
+ });
814
+ } catch (err) {
815
+ console.trace("[IDB] getItem getDb error:", err);
816
+ try {
817
+ const db = await getDb();
818
+ return new Promise((res) => {
819
+ try {
820
+ const r = db.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME).get(key);
821
+ r.onsuccess = () => res(r.result);
822
+ r.onerror = () => {
823
+ console.trace("[IDB] getItem retry error:", r.error);
824
+ res(void 0);
825
+ };
826
+ } catch (txErr) {
827
+ console.trace("[IDB] getItem retry transaction error:", txErr);
828
+ res(void 0);
829
+ }
830
+ });
831
+ } catch (recoveryErr) {
832
+ console.trace("[IDB] getItem recovery failed:", recoveryErr);
833
+ }
834
+ return;
835
+ }
836
+ },
837
+ async setItem(key, value) {
838
+ const cloneableValue = JSON.parse(JSON.stringify(value));
839
+ try {
840
+ const db = await getDb();
841
+ if (!db) return;
842
+ await new Promise((resolve) => {
843
+ try {
844
+ const req = db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).put(cloneableValue, key);
845
+ req.onsuccess = () => resolve();
846
+ req.onerror = () => {
847
+ console.trace("[IDB] setItem error:", req.error);
848
+ resolve();
849
+ };
850
+ } catch (txErr) {
851
+ console.trace("[IDB] setItem transaction error:", txErr);
852
+ resolve();
853
+ }
854
+ });
855
+ } catch (err) {
856
+ console.trace("[IDB] setItem getDb error:", err);
857
+ try {
858
+ const db = await getDb();
859
+ await new Promise((resolve) => {
860
+ try {
861
+ const req = db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).put(cloneableValue, key);
862
+ req.onsuccess = () => resolve();
863
+ req.onerror = () => {
864
+ console.trace("[IDB] setItem retry error:", req.error);
865
+ resolve();
866
+ };
867
+ } catch (txErr) {
868
+ console.trace("[IDB] setItem retry transaction error:", txErr);
869
+ resolve();
870
+ }
871
+ });
872
+ } catch (recoveryErr) {
873
+ console.trace("[IDB] setItem recovery failed:", recoveryErr);
874
+ }
875
+ }
876
+ },
877
+ async removeItem(key) {
878
+ try {
879
+ const db = await getDb();
880
+ if (!db) return;
881
+ await new Promise((resolve) => {
882
+ try {
883
+ const req = db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).delete(key);
884
+ req.onsuccess = () => resolve();
885
+ req.onerror = () => {
886
+ console.trace("[IDB] removeItem error:", req.error);
887
+ resolve();
888
+ };
889
+ } catch (txErr) {
890
+ console.trace("[IDB] removeItem transaction error:", txErr);
891
+ resolve();
892
+ }
893
+ });
894
+ } catch (err) {
895
+ console.trace("[IDB] removeItem getDb error:", err);
896
+ try {
897
+ const db = await getDb();
898
+ await new Promise((resolve) => {
899
+ try {
900
+ const req = db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).delete(key);
901
+ req.onsuccess = () => resolve();
902
+ req.onerror = () => {
903
+ console.trace("[IDB] removeItem retry error:", req.error);
904
+ resolve();
905
+ };
906
+ } catch (txErr) {
907
+ console.trace("[IDB] removeItem retry transaction error:", txErr);
908
+ resolve();
909
+ }
910
+ });
911
+ } catch (recoveryErr) {
912
+ console.trace("[IDB] removeItem recovery failed:", recoveryErr);
913
+ }
914
+ }
915
+ }
916
+ };
917
+ function createPersister() {
918
+ return experimental_createQueryPersister({
919
+ storage,
920
+ serialize: (persistedQuery) => persistedQuery,
921
+ deserialize: (cached) => cached
922
+ });
923
+ }
924
+ //#endregion
925
+ //#region src/hooks/use-fluid-app.ts
926
+ /**
927
+ * Query key for full app data (fluidos endpoint)
928
+ */
929
+ const APP_DATA_QUERY_KEY = ["fluid", "app"];
930
+ /**
931
+ * Module-level persister instance (browser only).
932
+ * Created once when the module loads so all calls to useFluidApp share
933
+ * the same IndexedDB connection. Applied at the query level so it works
934
+ * regardless of which QueryClient the app provides.
935
+ */
936
+ const appDataPersister = typeof window !== "undefined" ? createPersister() : void 0;
937
+ /**
938
+ * Hook to fetch the full portal app data from the fluidos API.
939
+ *
940
+ * Returns a `RepAppData` object containing:
941
+ * - `screens` — all screen definitions with normalized component trees
942
+ * - `profile.themes` — fully-transformed ThemeDefinition[] (handles legacy + new formats)
943
+ * - `profile.activeThemeId` — the currently active theme ID
944
+ * - `profile.navigation.navigation_items` — sorted, recursive navigation tree
945
+ *
946
+ * Uses IndexedDB persistence so subsequent page loads hydrate instantly
947
+ * from cache while revalidating in the background. The raw API response
948
+ * (plain JSON) is cached; Color objects are recreated from cache via
949
+ * `select` on every restore — this is fast (CPU only, no network).
950
+ *
951
+ * @example
952
+ * ```tsx
953
+ * function App() {
954
+ * const { data: appData, isLoading } = useFluidApp();
955
+ *
956
+ * if (isLoading) return <Spinner />;
957
+ *
958
+ * return (
959
+ * <AppShell
960
+ * appData={appData}
961
+ * navigation={appData.profile.navigation.navigation_items}
962
+ * />
963
+ * );
964
+ * }
965
+ * ```
966
+ */
967
+ function useFluidApp(options) {
968
+ const api = require_MessagingScreen.useFluidApi();
969
+ return (0, _tanstack_react_query.useQuery)({
970
+ queryKey: APP_DATA_QUERY_KEY,
971
+ queryFn: () => api.app.getRaw(),
972
+ select: require_MessagingScreen.transformManifestToRepAppData,
973
+ ...appDataPersister && { persister: appDataPersister.persisterFn },
974
+ ...options?.enabled !== void 0 && { enabled: options.enabled }
975
+ });
976
+ }
977
+ //#endregion
978
+ //#region src/hooks/use-fluid-permissions.ts
979
+ /**
980
+ * Query key for permissions data
981
+ */
982
+ const PERMISSIONS_QUERY_KEY = ["fluid", "permissions"];
983
+ /**
984
+ * Hook to fetch and check user permissions
985
+ *
986
+ * @example
987
+ * ```tsx
988
+ * function TeamSettings() {
989
+ * const { can, isSuperAdmin } = useFluidPermissions();
990
+ *
991
+ * if (!can("team", "manage")) {
992
+ * return <AccessDenied />;
993
+ * }
994
+ *
995
+ * return <TeamSettingsForm canDelete={can("team", "delete")} />;
996
+ * }
997
+ * ```
998
+ */
999
+ function useFluidPermissions() {
1000
+ const api = require_MessagingScreen.useFluidApi();
1001
+ const query = (0, _tanstack_react_query.useQuery)({
1002
+ queryKey: PERMISSIONS_QUERY_KEY,
1003
+ queryFn: () => api.permissions.get()
1004
+ });
1005
+ const permissions = query.data;
1006
+ return {
1007
+ query,
1008
+ permissions,
1009
+ can: (0, react.useMemo)(() => {
1010
+ return (resource, action = "view") => {
1011
+ if (!permissions) return false;
1012
+ if (permissions.is_super_admin) return true;
1013
+ const resourcePermissions = permissions.permissions[resource];
1014
+ if (!resourcePermissions) return false;
1015
+ return resourcePermissions[action] ?? false;
1016
+ };
1017
+ }, [permissions]),
1018
+ isSuperAdmin: permissions?.is_super_admin ?? false
1019
+ };
1020
+ }
1021
+ //#endregion
1022
+ //#region src/hooks/use-fluid-theme.ts
1023
+ /**
1024
+ * Hook to access and control theme settings
1025
+ *
1026
+ * @example
1027
+ * ```tsx
1028
+ * function ThemeSwitcher({ themes }: { themes: ThemeDefinition[] }) {
1029
+ * const { currentTheme, setTheme, setThemeMode, mode } = useFluidTheme();
1030
+ *
1031
+ * return (
1032
+ * <div>
1033
+ * <select
1034
+ * value={currentTheme?.name}
1035
+ * onChange={(e) => {
1036
+ * const theme = themes.find(t => t.name === e.target.value);
1037
+ * if (theme) setTheme(theme);
1038
+ * }}
1039
+ * >
1040
+ * {themes.map(theme => (
1041
+ * <option key={theme.name} value={theme.name}>
1042
+ * {theme.name}
1043
+ * </option>
1044
+ * ))}
1045
+ * </select>
1046
+ *
1047
+ * <button onClick={() => setThemeMode(mode === "dark" ? "light" : "dark")}>
1048
+ * Toggle {mode === "dark" ? "Light" : "Dark"} Mode
1049
+ * </button>
1050
+ * </div>
1051
+ * );
1052
+ * }
1053
+ * ```
1054
+ */
1055
+ function useFluidTheme() {
1056
+ const { currentTheme, setTheme, setThemeMode, mode } = require_MessagingScreen.useThemeContext();
1057
+ return {
1058
+ currentTheme,
1059
+ setTheme,
1060
+ setThemeMode,
1061
+ mode
1062
+ };
1063
+ }
1064
+ //#endregion
1065
+ //#region src/hooks/use-current-rep.ts
1066
+ /**
1067
+ * Query key for current rep data
1068
+ */
1069
+ const CURRENT_REP_QUERY_KEY = ["fluid", "currentRep"];
1070
+ /**
1071
+ * Hook to fetch the currently authenticated rep's profile
1072
+ *
1073
+ * @example
1074
+ * ```tsx
1075
+ * function RepHeader() {
1076
+ * const { data: rep, isLoading } = useCurrentRep();
1077
+ *
1078
+ * if (isLoading) return <Skeleton />;
1079
+ *
1080
+ * return (
1081
+ * <div>
1082
+ * <Avatar src={rep?.avatar_url} />
1083
+ * <span>{rep?.first_name} {rep?.last_name}</span>
1084
+ * </div>
1085
+ * );
1086
+ * }
1087
+ * ```
1088
+ */
1089
+ function useCurrentRep() {
1090
+ const api = require_MessagingScreen.useFluidApi();
1091
+ return (0, _tanstack_react_query.useQuery)({
1092
+ queryKey: CURRENT_REP_QUERY_KEY,
1093
+ queryFn: () => api.reps.current()
1094
+ });
1095
+ }
1096
+ //#endregion
1097
+ //#region src/hooks/use-fluid-auth.ts
1098
+ /**
1099
+ * useFluidAuth Hook
1100
+ *
1101
+ * Provides access to authentication state and utilities.
1102
+ * This is the primary hook for interacting with auth in components.
1103
+ */
1104
+ /**
1105
+ * Hook to access authentication state and utilities.
1106
+ *
1107
+ * Must be used within a `FluidAuthProvider`.
1108
+ *
1109
+ * @returns Authentication context with user info, loading state, and utilities
1110
+ * @throws Error if used outside FluidAuthProvider
1111
+ *
1112
+ * @example
1113
+ * ```tsx
1114
+ * function UserProfile() {
1115
+ * const { isAuthenticated, isLoading, user, clearAuth } = useFluidAuth();
1116
+ *
1117
+ * if (isLoading) {
1118
+ * return <Spinner />;
1119
+ * }
1120
+ *
1121
+ * if (!isAuthenticated) {
1122
+ * return <p>Please log in</p>;
1123
+ * }
1124
+ *
1125
+ * return (
1126
+ * <div>
1127
+ * <p>Welcome, {user.full_name}!</p>
1128
+ * <button onClick={clearAuth}>Log out</button>
1129
+ * </div>
1130
+ * );
1131
+ * }
1132
+ * ```
1133
+ */
1134
+ function useFluidAuth() {
1135
+ return require_MessagingScreen.useFluidAuthContext();
1136
+ }
1137
+ //#endregion
1138
+ //#region src/hooks/demo-data/calendar-events.ts
1139
+ const now$4 = /* @__PURE__ */ new Date();
1140
+ function daysFromNow$1(days, hour, minute = 0) {
1141
+ const d = new Date(now$4);
1142
+ d.setDate(d.getDate() + days);
1143
+ d.setHours(hour, minute, 0, 0);
1144
+ return d;
1145
+ }
1146
+ const DEMO_CALENDAR_EVENTS = [
1147
+ {
1148
+ id: 1,
1149
+ title: "Team Standup",
1150
+ description: { body: "Daily sync with the sales team" },
1151
+ color: "#4f46e5",
1152
+ start: daysFromNow$1(0, 9, 0).toISOString(),
1153
+ end: daysFromNow$1(0, 9, 30).toISOString(),
1154
+ active: true,
1155
+ status: "confirmed"
1156
+ },
1157
+ {
1158
+ id: 2,
1159
+ title: "Client Review - Acme Corp",
1160
+ description: { body: "Quarterly business review with key accounts" },
1161
+ color: "#059669",
1162
+ start: daysFromNow$1(2, 14, 0).toISOString(),
1163
+ end: daysFromNow$1(2, 15, 0).toISOString(),
1164
+ active: true,
1165
+ status: "confirmed",
1166
+ venue: "Conference Room B"
1167
+ },
1168
+ {
1169
+ id: 3,
1170
+ title: "Product Training Webinar",
1171
+ description: { body: "New product line training for the field" },
1172
+ color: "#d97706",
1173
+ start: daysFromNow$1(4, 11, 0).toISOString(),
1174
+ end: daysFromNow$1(4, 12, 30).toISOString(),
1175
+ active: true,
1176
+ status: "confirmed",
1177
+ url: "https://example.com/webinar"
1178
+ },
1179
+ {
1180
+ id: 4,
1181
+ title: "Regional Conference",
1182
+ description: { body: "Annual West Coast regional conference" },
1183
+ color: "#dc2626",
1184
+ start: daysFromNow$1(10, 8, 0).toISOString(),
1185
+ end: daysFromNow$1(12, 17, 0).toISOString(),
1186
+ active: true,
1187
+ status: "confirmed",
1188
+ venue: "San Diego Convention Center",
1189
+ isAllDay: true
1190
+ }
1191
+ ];
1192
+ //#endregion
1193
+ //#region src/hooks/use-calendar-events.ts
1194
+ /**
1195
+ * Hook to fetch calendar events.
1196
+ * This is a stub implementation - override with your own data fetching logic.
1197
+ */
1198
+ function useCalendarEvents() {
1199
+ return {
1200
+ data: [...DEMO_CALENDAR_EVENTS],
1201
+ isLoading: false,
1202
+ isError: false
1203
+ };
1204
+ }
1205
+ //#endregion
1206
+ //#region src/hooks/demo-data/todos.ts
1207
+ const now$3 = /* @__PURE__ */ new Date();
1208
+ function daysFromNow(days) {
1209
+ const d = new Date(now$3);
1210
+ d.setDate(d.getDate() + days);
1211
+ return d.toISOString();
1212
+ }
1213
+ const DEMO_TODOS = [
1214
+ {
1215
+ id: 1,
1216
+ body: "Follow up with Sarah about Q2 order",
1217
+ dueAt: daysFromNow(1),
1218
+ completedAt: null,
1219
+ createdAt: daysFromNow(-2),
1220
+ contactName: "Sarah Johnson"
1221
+ },
1222
+ {
1223
+ id: 2,
1224
+ body: "Send pricing proposal to Acme Corp",
1225
+ dueAt: daysFromNow(7),
1226
+ completedAt: null,
1227
+ createdAt: daysFromNow(-1),
1228
+ contactName: "Mike Chen"
1229
+ },
1230
+ {
1231
+ id: 3,
1232
+ body: "Schedule onboarding call with new team member",
1233
+ dueAt: daysFromNow(3),
1234
+ completedAt: null,
1235
+ createdAt: daysFromNow(0),
1236
+ contactName: "Emily Rodriguez"
1237
+ },
1238
+ {
1239
+ id: 4,
1240
+ body: "Review and approve Q1 expense report",
1241
+ dueAt: daysFromNow(-1),
1242
+ completedAt: daysFromNow(-1),
1243
+ createdAt: daysFromNow(-5),
1244
+ contactName: null
1245
+ },
1246
+ {
1247
+ id: 5,
1248
+ body: "Prepare presentation for Friday team meeting",
1249
+ dueAt: daysFromNow(4),
1250
+ completedAt: daysFromNow(0),
1251
+ createdAt: daysFromNow(-3),
1252
+ contactName: null
1253
+ }
1254
+ ];
1255
+ //#endregion
1256
+ //#region src/hooks/use-todos.ts
1257
+ /**
1258
+ * Hook to fetch todo items.
1259
+ * This is a stub implementation - override with your own data fetching logic.
1260
+ */
1261
+ function useTodos() {
1262
+ return {
1263
+ data: [...DEMO_TODOS],
1264
+ isLoading: false,
1265
+ isError: false
1266
+ };
1267
+ }
1268
+ //#endregion
1269
+ //#region src/hooks/hook-types.ts
1270
+ /**
1271
+ * Type predicate to check if a query result has successfully loaded data.
1272
+ * Narrows the data type from T | null | undefined to T.
1273
+ *
1274
+ * @example
1275
+ * const result = useContact(id);
1276
+ * if (hasData(result)) {
1277
+ * // TypeScript knows result.data is Contact, not Contact | null
1278
+ * console.log(result.data.name);
1279
+ * }
1280
+ */
1281
+ function hasData(result) {
1282
+ return result.data != null && !result.isLoading && !result.isError;
1283
+ }
1284
+ /**
1285
+ * Type predicate to check if a query result is in loading state.
1286
+ * Useful for conditional rendering.
1287
+ *
1288
+ * @example
1289
+ * if (isLoading(result)) {
1290
+ * return <Spinner />;
1291
+ * }
1292
+ */
1293
+ function isLoading(result) {
1294
+ return result.isLoading;
1295
+ }
1296
+ /**
1297
+ * Type predicate to check if a query result has an error.
1298
+ * Narrows to include the error property.
1299
+ *
1300
+ * @example
1301
+ * if (isErrorResult(result)) {
1302
+ * console.error(result.error); // error is E, not undefined
1303
+ * }
1304
+ */
1305
+ function isErrorResult(result) {
1306
+ return result.isError && result.error !== void 0;
1307
+ }
1308
+ /**
1309
+ * Type predicate to check if a query result is in idle state (not loading, no error, has data).
1310
+ *
1311
+ * @example
1312
+ * if (isIdle(result)) {
1313
+ * // Safe to access and render data
1314
+ * }
1315
+ */
1316
+ function isIdle(result) {
1317
+ return !result.isLoading && !result.isError;
1318
+ }
1319
+ /**
1320
+ * Type-safe property selector for hook results.
1321
+ * Uses K extends keyof T constraint (generics-function-constraints rule).
1322
+ *
1323
+ * @typeParam T - The data object type
1324
+ * @typeParam K - Key of T (constrained to actual keys)
1325
+ *
1326
+ * @example
1327
+ * const users = [{ name: "Alice", age: 30 }];
1328
+ * const names = selectProperty(users, "name"); // string[]
1329
+ * const ages = selectProperty(users, "age"); // number[]
1330
+ * selectProperty(users, "invalid"); // Error: "invalid" not in "name" | "age"
1331
+ */
1332
+ function selectProperty(items, key) {
1333
+ return items.map((item) => item[key]);
1334
+ }
1335
+ /**
1336
+ * Type-safe property getter for a single item.
1337
+ * Returns undefined if item is null/undefined.
1338
+ *
1339
+ * @typeParam T - The data object type
1340
+ * @typeParam K - Key of T (constrained to actual keys)
1341
+ */
1342
+ function getProperty(item, key) {
1343
+ return item?.[key];
1344
+ }
1345
+ /**
1346
+ * Activity slug constants as a const object.
1347
+ * Derive the ActivitySlug type from this single source of truth.
1348
+ */
1349
+ const ACTIVITY_SLUGS = {
1350
+ abandonedCart: "abandoned_cart",
1351
+ announcements: "announcements",
1352
+ cartItemsAdded: "cart_items_added",
1353
+ commentReply: "comment_reply",
1354
+ directMessage: "direct_message",
1355
+ fantasyPoint: "fantasy_point",
1356
+ newLead: "new_lead",
1357
+ orderPlaced: "order_placed",
1358
+ pageViews: "page_views",
1359
+ pageViewsContact: "page_views_contact",
1360
+ tasks: "tasks",
1361
+ upcomingEvent: "upcoming_event",
1362
+ video: "video",
1363
+ videoComplete: "video_complete",
1364
+ videoCompleteContact: "video_complete_contact",
1365
+ videoContact: "video_contact",
1366
+ messageReceived: "message_received",
1367
+ messageSent: "message_sent",
1368
+ newCartItemsAdded: "new_cart_items_added",
1369
+ smartLinkClicked: "smart_link_clicked",
1370
+ reviewLeft: "review_left"
1371
+ };
1372
+ /** Type predicate to check if a string is a valid ActivitySlug. */
1373
+ function isActivitySlug(value) {
1374
+ return Object.values(ACTIVITY_SLUGS).includes(value);
1375
+ }
1376
+ //#endregion
1377
+ //#region src/hooks/demo-data/activities.ts
1378
+ const now$2 = /* @__PURE__ */ new Date();
1379
+ function hoursAgo$1(hours) {
1380
+ const d = new Date(now$2);
1381
+ d.setHours(d.getHours() - hours);
1382
+ return d.toISOString();
1383
+ }
1384
+ const DEMO_ACTIVITIES = [
1385
+ {
1386
+ id: 1,
1387
+ userName: "Sarah Johnson",
1388
+ avatarUrl: null,
1389
+ activityType: "New Order",
1390
+ targetName: "Wellness Starter Kit",
1391
+ timestamp: hoursAgo$1(1),
1392
+ slug: "order_placed"
1393
+ },
1394
+ {
1395
+ id: 2,
1396
+ userName: "Mike Chen",
1397
+ avatarUrl: null,
1398
+ activityType: "New Lead",
1399
+ targetName: "Referral from LinkedIn campaign",
1400
+ timestamp: hoursAgo$1(3),
1401
+ slug: "new_lead"
1402
+ },
1403
+ {
1404
+ id: 3,
1405
+ userName: "Emily Rodriguez",
1406
+ avatarUrl: null,
1407
+ activityType: "Page View",
1408
+ targetName: "Product Catalog",
1409
+ timestamp: hoursAgo$1(5),
1410
+ slug: "page_views"
1411
+ },
1412
+ {
1413
+ id: 4,
1414
+ userName: "David Park",
1415
+ avatarUrl: null,
1416
+ activityType: "Cart Items Added",
1417
+ targetName: "Premium Bundle (3 items)",
1418
+ timestamp: hoursAgo$1(8),
1419
+ slug: "cart_items_added"
1420
+ },
1421
+ {
1422
+ id: 5,
1423
+ userName: "Lisa Thompson",
1424
+ avatarUrl: null,
1425
+ activityType: "Video Watched",
1426
+ targetName: "Getting Started Tutorial",
1427
+ timestamp: hoursAgo$1(12),
1428
+ slug: "video_complete"
1429
+ },
1430
+ {
1431
+ id: 6,
1432
+ userName: "James Wilson",
1433
+ avatarUrl: null,
1434
+ activityType: "Message Received",
1435
+ targetName: "Question about shipping",
1436
+ timestamp: hoursAgo$1(18),
1437
+ slug: "message_received"
1438
+ },
1439
+ {
1440
+ id: 7,
1441
+ userName: "Rachel Kim",
1442
+ avatarUrl: null,
1443
+ activityType: "Smart Link Clicked",
1444
+ targetName: "Holiday Promo Link",
1445
+ timestamp: hoursAgo$1(24),
1446
+ slug: "smart_link_clicked"
1447
+ },
1448
+ {
1449
+ id: 8,
1450
+ userName: "Tom Martinez",
1451
+ avatarUrl: null,
1452
+ activityType: "Review Left",
1453
+ targetName: "Essential Oil Set - 5 stars",
1454
+ timestamp: hoursAgo$1(36),
1455
+ slug: "review_left"
1456
+ }
1457
+ ];
1458
+ //#endregion
1459
+ //#region src/hooks/use-activities.ts
1460
+ /**
1461
+ * Hook to fetch recent activities.
1462
+ * This is a stub implementation - override with your own data fetching logic.
1463
+ */
1464
+ function useActivities() {
1465
+ return {
1466
+ data: [...DEMO_ACTIVITIES],
1467
+ isLoading: false,
1468
+ isError: false
1469
+ };
1470
+ }
1471
+ //#endregion
1472
+ //#region src/hooks/demo-data/catchups.ts
1473
+ const DEMO_CATCHUPS = [
1474
+ {
1475
+ id: 1,
1476
+ suggestion_title: "Sarah Johnson hasn't ordered in 30 days"
1477
+ },
1478
+ {
1479
+ id: 2,
1480
+ suggestion_title: "Mike Chen's subscription is expiring soon"
1481
+ },
1482
+ {
1483
+ id: 3,
1484
+ suggestion_title: "Emily Rodriguez left a cart with 3 items"
1485
+ }
1486
+ ];
1487
+ //#endregion
1488
+ //#region src/hooks/use-catchups.ts
1489
+ /**
1490
+ * Hook to fetch catch up items.
1491
+ * This is a stub implementation - override with your own data fetching logic.
1492
+ */
1493
+ function useCatchUps() {
1494
+ return {
1495
+ data: [...DEMO_CATCHUPS],
1496
+ isLoading: false,
1497
+ isError: false
1498
+ };
1499
+ }
1500
+ //#endregion
1501
+ //#region src/hooks/demo-data/mysite.ts
1502
+ const DEMO_MYSITE = {
1503
+ url: "https://my-portal.example.com",
1504
+ views: 1243,
1505
+ leads: 37,
1506
+ userName: "Demo User"
1507
+ };
1508
+ //#endregion
1509
+ //#region src/hooks/use-mysite.ts
1510
+ /**
1511
+ * Hook to fetch MySite data.
1512
+ * This is a stub implementation - override with your own data fetching logic.
1513
+ */
1514
+ function useMySite() {
1515
+ return {
1516
+ data: DEMO_MYSITE,
1517
+ isLoading: false,
1518
+ isError: false
1519
+ };
1520
+ }
1521
+ //#endregion
1522
+ //#region src/hooks/demo-data/conversations.ts
1523
+ const now$1 = /* @__PURE__ */ new Date();
1524
+ function hoursAgo(hours) {
1525
+ const d = new Date(now$1);
1526
+ d.setHours(d.getHours() - hours);
1527
+ return d.toISOString();
1528
+ }
1529
+ function daysAgo$1(days) {
1530
+ const d = new Date(now$1);
1531
+ d.setDate(d.getDate() - days);
1532
+ return d.toISOString();
1533
+ }
1534
+ const DEMO_CONVERSATIONS = [
1535
+ {
1536
+ id: "conv-1",
1537
+ title: "Sarah Johnson",
1538
+ participants: [{
1539
+ id: "user-1",
1540
+ name: "You",
1541
+ email: "me@example.com",
1542
+ isOnline: true
1543
+ }, {
1544
+ id: "user-2",
1545
+ name: "Sarah Johnson",
1546
+ email: "sarah.johnson@example.com",
1547
+ isOnline: true
1548
+ }],
1549
+ lastMessage: {
1550
+ id: "msg-1-3",
1551
+ conversationId: "conv-1",
1552
+ senderId: "user-2",
1553
+ senderName: "Sarah Johnson",
1554
+ type: "text",
1555
+ content: "Sounds great! I'll place the order by end of day.",
1556
+ timestamp: hoursAgo(1),
1557
+ isRead: false
1558
+ },
1559
+ unreadCount: 1,
1560
+ status: "active",
1561
+ createdAt: daysAgo$1(30),
1562
+ updatedAt: hoursAgo(1)
1563
+ },
1564
+ {
1565
+ id: "conv-2",
1566
+ title: "Mike Chen",
1567
+ participants: [{
1568
+ id: "user-1",
1569
+ name: "You",
1570
+ email: "me@example.com",
1571
+ isOnline: true
1572
+ }, {
1573
+ id: "user-3",
1574
+ name: "Mike Chen",
1575
+ email: "mike.chen@acmecorp.com",
1576
+ isOnline: false
1577
+ }],
1578
+ lastMessage: {
1579
+ id: "msg-2-2",
1580
+ conversationId: "conv-2",
1581
+ senderId: "user-1",
1582
+ senderName: "You",
1583
+ type: "text",
1584
+ content: "I've attached the updated pricing sheet. Let me know if you have any questions!",
1585
+ timestamp: hoursAgo(5),
1586
+ isRead: true
1587
+ },
1588
+ unreadCount: 0,
1589
+ status: "active",
1590
+ createdAt: daysAgo$1(14),
1591
+ updatedAt: hoursAgo(5)
1592
+ },
1593
+ {
1594
+ id: "conv-3",
1595
+ title: "Team Updates",
1596
+ participants: [
1597
+ {
1598
+ id: "user-1",
1599
+ name: "You",
1600
+ email: "me@example.com",
1601
+ isOnline: true
1602
+ },
1603
+ {
1604
+ id: "user-4",
1605
+ name: "Emily Rodriguez",
1606
+ email: "emily.r@healthfirst.io"
1607
+ },
1608
+ {
1609
+ id: "user-5",
1610
+ name: "David Park",
1611
+ email: "david.park@email.com"
1612
+ }
1613
+ ],
1614
+ lastMessage: {
1615
+ id: "msg-3-4",
1616
+ conversationId: "conv-3",
1617
+ senderId: "user-4",
1618
+ senderName: "Emily Rodriguez",
1619
+ type: "text",
1620
+ content: "The new product samples arrived today. Will distribute to the team tomorrow.",
1621
+ timestamp: daysAgo$1(1),
1622
+ isRead: true
1623
+ },
1624
+ unreadCount: 0,
1625
+ status: "active",
1626
+ createdAt: daysAgo$1(60),
1627
+ updatedAt: daysAgo$1(1)
1628
+ }
1629
+ ];
1630
+ const DEMO_MESSAGES = [
1631
+ {
1632
+ id: "msg-1-1",
1633
+ conversationId: "conv-1",
1634
+ senderId: "user-1",
1635
+ senderName: "You",
1636
+ type: "text",
1637
+ content: "Hi Sarah! I wanted to follow up on the Wellness Starter Kit. We have a special promotion running this month.",
1638
+ timestamp: hoursAgo(3),
1639
+ isRead: true
1640
+ },
1641
+ {
1642
+ id: "msg-1-2",
1643
+ conversationId: "conv-1",
1644
+ senderId: "user-2",
1645
+ senderName: "Sarah Johnson",
1646
+ type: "text",
1647
+ content: "That's perfect timing! I was just thinking about reordering. What's the promo?",
1648
+ timestamp: hoursAgo(2),
1649
+ isRead: true
1650
+ },
1651
+ {
1652
+ id: "msg-1-3",
1653
+ conversationId: "conv-1",
1654
+ senderId: "user-2",
1655
+ senderName: "Sarah Johnson",
1656
+ type: "text",
1657
+ content: "Sounds great! I'll place the order by end of day.",
1658
+ timestamp: hoursAgo(1),
1659
+ isRead: false
1660
+ }
1661
+ ];
1662
+ //#endregion
1663
+ //#region src/hooks/use-conversations.ts
1664
+ /**
1665
+ * Hook to fetch all conversations.
1666
+ * This is a stub implementation - override with your own data fetching logic.
1667
+ *
1668
+ * @returns UseConversationsResult with empty data array
1669
+ *
1670
+ * @example
1671
+ * ```tsx
1672
+ * const { data: conversations, isLoading, isError } = useConversations();
1673
+ *
1674
+ * if (isLoading) return <Loading />;
1675
+ * if (isError) return <Error />;
1676
+ *
1677
+ * return conversations.map(conv => <ConversationItem key={conv.id} {...conv} />);
1678
+ * ```
1679
+ */
1680
+ function useConversations() {
1681
+ return {
1682
+ data: [...DEMO_CONVERSATIONS],
1683
+ isLoading: false,
1684
+ isError: false
1685
+ };
1686
+ }
1687
+ /**
1688
+ * Hook to fetch messages for a specific conversation.
1689
+ * This is a stub implementation - override with your own data fetching logic.
1690
+ *
1691
+ * @param conversationId - The ID of the conversation to fetch messages for
1692
+ * @returns UseConversationMessagesResult with empty data array
1693
+ *
1694
+ * @example
1695
+ * ```tsx
1696
+ * const { data: messages, isLoading, isError } = useConversationMessages(conversationId);
1697
+ *
1698
+ * if (isLoading) return <Loading />;
1699
+ * if (isError) return <Error />;
1700
+ *
1701
+ * return messages.map(msg => <MessageBubble key={msg.id} {...msg} />);
1702
+ * ```
1703
+ */
1704
+ function useConversationMessages(_conversationId) {
1705
+ return {
1706
+ data: [...DEMO_MESSAGES],
1707
+ isLoading: false,
1708
+ isError: false
1709
+ };
1710
+ }
1711
+ //#endregion
1712
+ //#region src/types/screen-types.ts
1713
+ /**
1714
+ * Contact status constant - single source of truth.
1715
+ */
1716
+ const CONTACT_STATUSES = {
1717
+ active: "active",
1718
+ inactive: "inactive",
1719
+ lead: "lead",
1720
+ prospect: "prospect"
1721
+ };
1722
+ //#endregion
1723
+ //#region src/hooks/demo-data/contacts.ts
1724
+ const now = /* @__PURE__ */ new Date();
1725
+ function daysAgo(days) {
1726
+ const d = new Date(now);
1727
+ d.setDate(d.getDate() - days);
1728
+ return d.toISOString();
1729
+ }
1730
+ const DEMO_CONTACTS = [
1731
+ {
1732
+ id: "contact-1",
1733
+ firstName: "Sarah",
1734
+ lastName: "Johnson",
1735
+ email: "sarah.johnson@example.com",
1736
+ phone: "+1 (555) 123-4567",
1737
+ company: "Wellness Works Inc.",
1738
+ jobTitle: "Purchasing Manager",
1739
+ status: "active",
1740
+ type: "individual",
1741
+ tags: ["VIP", "Repeat Buyer"],
1742
+ createdAt: daysAgo(90),
1743
+ updatedAt: daysAgo(2)
1744
+ },
1745
+ {
1746
+ id: "contact-2",
1747
+ firstName: "Mike",
1748
+ lastName: "Chen",
1749
+ email: "mike.chen@acmecorp.com",
1750
+ phone: "+1 (555) 234-5678",
1751
+ company: "Acme Corp",
1752
+ jobTitle: "Director of Operations",
1753
+ status: "active",
1754
+ type: "individual",
1755
+ tags: ["Enterprise"],
1756
+ createdAt: daysAgo(60),
1757
+ updatedAt: daysAgo(5)
1758
+ },
1759
+ {
1760
+ id: "contact-3",
1761
+ firstName: "Emily",
1762
+ lastName: "Rodriguez",
1763
+ email: "emily.r@healthfirst.io",
1764
+ company: "HealthFirst",
1765
+ status: "lead",
1766
+ type: "individual",
1767
+ notes: "Interested in bulk pricing for team orders",
1768
+ createdAt: daysAgo(7),
1769
+ updatedAt: daysAgo(1)
1770
+ },
1771
+ {
1772
+ id: "contact-4",
1773
+ firstName: "David",
1774
+ lastName: "Park",
1775
+ email: "david.park@email.com",
1776
+ phone: "+1 (555) 345-6789",
1777
+ status: "prospect",
1778
+ type: "individual",
1779
+ tags: ["Referral"],
1780
+ createdAt: daysAgo(14),
1781
+ updatedAt: daysAgo(10)
1782
+ },
1783
+ {
1784
+ id: "contact-5",
1785
+ firstName: "Lisa",
1786
+ lastName: "Thompson",
1787
+ email: "lisa.t@globalfit.com",
1788
+ company: "Global Fitness",
1789
+ jobTitle: "CEO",
1790
+ status: "active",
1791
+ type: "individual",
1792
+ address: {
1793
+ city: "Los Angeles",
1794
+ state: "CA",
1795
+ country: "US"
1796
+ },
1797
+ createdAt: daysAgo(120),
1798
+ updatedAt: daysAgo(15)
1799
+ },
1800
+ {
1801
+ id: "contact-6",
1802
+ firstName: "James",
1803
+ lastName: "Wilson",
1804
+ email: "jwilson@retired.net",
1805
+ status: "inactive",
1806
+ type: "individual",
1807
+ notes: "Moved out of area, no longer purchasing",
1808
+ createdAt: daysAgo(200),
1809
+ updatedAt: daysAgo(45)
1810
+ }
1811
+ ];
1812
+ const DEMO_CONTACT = DEMO_CONTACTS[0];
1813
+ //#endregion
1814
+ //#region src/hooks/use-contacts.ts
1815
+ /**
1816
+ * Type predicate to check if a status string is a valid ContactStatus.
1817
+ * Enables runtime validation with type narrowing.
1818
+ */
1819
+ function isContactStatus(value) {
1820
+ return Object.values(CONTACT_STATUSES).includes(value);
1821
+ }
1822
+ /**
1823
+ * Hook to fetch a list of contacts with optional filtering and pagination.
1824
+ * This is a stub implementation - override with your own data fetching logic.
1825
+ *
1826
+ * @param params - Optional parameters for filtering and pagination
1827
+ * @returns Object containing contacts data, loading state, error state, and total count
1828
+ *
1829
+ * @example
1830
+ * ```tsx
1831
+ * const { data: contacts, isLoading, totalCount } = useContacts({
1832
+ * search: 'john',
1833
+ * status: 'active',
1834
+ * limit: 20
1835
+ * });
1836
+ * ```
1837
+ */
1838
+ function useContacts(_params) {
1839
+ return {
1840
+ data: [...DEMO_CONTACTS],
1841
+ isLoading: false,
1842
+ isError: false,
1843
+ totalCount: DEMO_CONTACTS.length
1844
+ };
1845
+ }
1846
+ /**
1847
+ * Hook to fetch a single contact by ID.
1848
+ * This is a stub implementation - override with your own data fetching logic.
1849
+ *
1850
+ * @param contactId - The unique identifier of the contact to fetch
1851
+ * @returns Object containing contact data, loading state, and error state
1852
+ *
1853
+ * @example
1854
+ * ```tsx
1855
+ * const { data: contact, isLoading, isError } = useContact('contact-123');
1856
+ * ```
1857
+ */
1858
+ function useContact(_contactId) {
1859
+ return {
1860
+ data: DEMO_CONTACT,
1861
+ isLoading: false,
1862
+ isError: false
1863
+ };
1864
+ }
1865
+ //#endregion
1866
+ //#region src/components/AuthError.tsx
1867
+ /**
1868
+ * AuthError - Default Authentication Error Component
1869
+ *
1870
+ * Displayed when authentication fails. Can be customized or replaced
1871
+ * via the RequireAuth component's errorComponent prop.
1872
+ */
1873
+ /**
1874
+ * Default authentication error component.
1875
+ *
1876
+ * Displays a simple error message when authentication fails.
1877
+ * Can be customized via props or replaced entirely in RequireAuth.
1878
+ *
1879
+ * @example
1880
+ * ```tsx
1881
+ * // Use with default message
1882
+ * <AuthError />
1883
+ *
1884
+ * // Use with custom message
1885
+ * <AuthError message="Session expired. Please log in again." />
1886
+ *
1887
+ * // Use with custom content
1888
+ * <AuthError>
1889
+ * <CustomLoginButton />
1890
+ * </AuthError>
1891
+ * ```
1892
+ */
1893
+ function AuthError({ message = "You need to be authenticated to view this content.", title = "Authentication Required", children }) {
1894
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1895
+ style: {
1896
+ display: "flex",
1897
+ flexDirection: "column",
1898
+ alignItems: "center",
1899
+ justifyContent: "center",
1900
+ minHeight: "100vh",
1901
+ padding: "2rem",
1902
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif",
1903
+ backgroundColor: "#f9fafb",
1904
+ color: "#111827"
1905
+ },
1906
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1907
+ style: {
1908
+ maxWidth: "400px",
1909
+ textAlign: "center",
1910
+ padding: "2rem",
1911
+ backgroundColor: "#ffffff",
1912
+ borderRadius: "0.75rem",
1913
+ boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)"
1914
+ },
1915
+ children: [
1916
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1917
+ style: {
1918
+ width: "64px",
1919
+ height: "64px",
1920
+ margin: "0 auto 1.5rem",
1921
+ backgroundColor: "#fee2e2",
1922
+ borderRadius: "50%",
1923
+ display: "flex",
1924
+ alignItems: "center",
1925
+ justifyContent: "center"
1926
+ },
1927
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1928
+ width: "32",
1929
+ height: "32",
1930
+ viewBox: "0 0 24 24",
1931
+ fill: "none",
1932
+ stroke: "#dc2626",
1933
+ strokeWidth: "2",
1934
+ strokeLinecap: "round",
1935
+ strokeLinejoin: "round",
1936
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
1937
+ x: "3",
1938
+ y: "11",
1939
+ width: "18",
1940
+ height: "11",
1941
+ rx: "2",
1942
+ ry: "2"
1943
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })]
1944
+ })
1945
+ }),
1946
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
1947
+ style: {
1948
+ fontSize: "1.5rem",
1949
+ fontWeight: "600",
1950
+ marginBottom: "0.75rem",
1951
+ color: "#111827"
1952
+ },
1953
+ children: title
1954
+ }),
1955
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1956
+ style: {
1957
+ fontSize: "1rem",
1958
+ color: "#6b7280",
1959
+ marginBottom: children ? "1.5rem" : "0",
1960
+ lineHeight: "1.5"
1961
+ },
1962
+ children: message
1963
+ }),
1964
+ children
1965
+ ]
1966
+ })
1967
+ });
1968
+ }
1969
+ const SPIN_STYLE_ID$1 = "fluid-auth-loading-spin";
1970
+ /**
1971
+ * Inject the spin keyframes style once into the document head.
1972
+ */
1973
+ function ensureSpinStyle$1() {
1974
+ if (typeof document === "undefined") return;
1975
+ if (document.getElementById(SPIN_STYLE_ID$1)) return;
1976
+ const style = document.createElement("style");
1977
+ style.id = SPIN_STYLE_ID$1;
1978
+ style.textContent = `@keyframes spin { to { transform: rotate(360deg); } }`;
1979
+ document.head.appendChild(style);
1980
+ }
1981
+ /**
1982
+ * Simple loading spinner component for auth loading state.
1983
+ */
1984
+ function AuthLoading() {
1985
+ (0, react.useEffect)(() => {
1986
+ ensureSpinStyle$1();
1987
+ }, []);
1988
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1989
+ style: {
1990
+ display: "flex",
1991
+ flexDirection: "column",
1992
+ alignItems: "center",
1993
+ justifyContent: "center",
1994
+ minHeight: "100vh",
1995
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif",
1996
+ backgroundColor: "#f9fafb"
1997
+ },
1998
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
1999
+ width: "40px",
2000
+ height: "40px",
2001
+ border: "3px solid #e5e7eb",
2002
+ borderTopColor: "#3b82f6",
2003
+ borderRadius: "50%",
2004
+ animation: "spin 1s linear infinite"
2005
+ } }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2006
+ style: {
2007
+ marginTop: "1rem",
2008
+ color: "#6b7280",
2009
+ fontSize: "0.875rem"
2010
+ },
2011
+ children: "Authenticating..."
2012
+ })]
2013
+ });
2014
+ }
2015
+ //#endregion
2016
+ //#region src/components/RequireAuth.tsx
2017
+ /**
2018
+ * Component that protects content requiring authentication.
2019
+ *
2020
+ * **Important:** This provides UX-level protection only. It prevents
2021
+ * unauthenticated users from seeing the UI, but the real security
2022
+ * boundary is the server-side API. Client-side auth can always be
2023
+ * bypassed by modifying browser state.
2024
+ *
2025
+ * For defense-in-depth, configure `jwksUrl` in `FluidAuthConfig`
2026
+ * to enable client-side JWT signature verification.
2027
+ *
2028
+ * Shows different states based on auth status:
2029
+ * - Loading: Shows fallback (spinner by default)
2030
+ * - Not authenticated: Shows errorComponent (AuthError by default)
2031
+ * - Authenticated: Shows children
2032
+ *
2033
+ * @example
2034
+ * ```tsx
2035
+ * // Basic usage - shows default loading/error states
2036
+ * <RequireAuth>
2037
+ * <ProtectedContent />
2038
+ * </RequireAuth>
2039
+ *
2040
+ * // Custom loading state
2041
+ * <RequireAuth fallback={<CustomSpinner />}>
2042
+ * <ProtectedContent />
2043
+ * </RequireAuth>
2044
+ *
2045
+ * // Custom error component
2046
+ * <RequireAuth errorComponent={<LoginPrompt />}>
2047
+ * <ProtectedContent />
2048
+ * </RequireAuth>
2049
+ *
2050
+ * // Both custom
2051
+ * <RequireAuth
2052
+ * fallback={<SkeletonLoader />}
2053
+ * errorComponent={<RedirectToLogin />}
2054
+ * >
2055
+ * <Dashboard />
2056
+ * </RequireAuth>
2057
+ * ```
2058
+ */
2059
+ function RequireAuth({ children, fallback = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AuthLoading, {}), errorComponent = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AuthError, {}) }) {
2060
+ const { isAuthenticated, isLoading, error } = useFluidAuth();
2061
+ if (isLoading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: fallback });
2062
+ if (!isAuthenticated || error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: errorComponent });
2063
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
2064
+ }
2065
+ //#endregion
2066
+ //#region src/screens/index.ts
2067
+ const screenPropertySchemas = {
2068
+ MessagingScreen: () => Promise.resolve().then(() => require("./MessagingScreen-CHb-scHD.cjs")).then((n) => n.MessagingScreen_exports).then((m) => m.messagingScreenPropertySchema),
2069
+ ContactsScreen: () => Promise.resolve().then(() => require("./ContactsScreen-Cqyrl4AQ.cjs")).then((n) => n.ContactsScreen_exports).then((m) => m.contactsScreenPropertySchema),
2070
+ OrdersScreen: () => Promise.resolve().then(() => require("./OrdersScreen-CPGDYvEd.cjs")).then((n) => n.OrdersScreen_exports).then((m) => m.ordersScreenPropertySchema),
2071
+ CustomersScreen: () => Promise.resolve().then(() => require("./CustomersScreen-gFgOzBox.cjs")).then((n) => n.CustomersScreen_exports).then((m) => m.customersScreenPropertySchema),
2072
+ ProductsScreen: () => Promise.resolve().then(() => require("./ProductsScreen-B1tlIth6.cjs")).then((n) => n.ProductsScreen_exports).then((m) => m.productsScreenPropertySchema)
2073
+ };
2074
+ /**
2075
+ * Core page template IDs
2076
+ */
2077
+ const CORE_PAGE_IDS = {
2078
+ MESSAGING: "core-messaging",
2079
+ CONTACTS: "core-contacts",
2080
+ ORDERS: "core-orders",
2081
+ CUSTOMERS: "core-customers",
2082
+ PRODUCTS: "core-products"
2083
+ };
2084
+ /**
2085
+ * Register core page templates.
2086
+ * These are automatically registered when the SDK is imported.
2087
+ */
2088
+ function registerCorePageTemplates() {
2089
+ PageTemplateRegistry.register({
2090
+ id: CORE_PAGE_IDS.MESSAGING,
2091
+ slug: "messaging",
2092
+ name: "Messaging",
2093
+ description: "Messaging interface provided by Fluid Commerce",
2094
+ category: PAGE_CATEGORIES.COMMUNICATION,
2095
+ tags: [
2096
+ "messaging",
2097
+ "chat",
2098
+ "conversations",
2099
+ "communication"
2100
+ ],
2101
+ version: "1.0.0",
2102
+ isCore: true,
2103
+ component_tree: [{
2104
+ type: "MessagingScreen",
2105
+ id: "messaging-screen-root",
2106
+ props: {}
2107
+ }],
2108
+ defaultProps: {}
2109
+ });
2110
+ PageTemplateRegistry.register({
2111
+ id: CORE_PAGE_IDS.CONTACTS,
2112
+ slug: "contacts",
2113
+ name: "Contacts",
2114
+ description: "Contact management provided by Fluid Commerce",
2115
+ category: PAGE_CATEGORIES.CORE,
2116
+ tags: [
2117
+ "contacts",
2118
+ "people",
2119
+ "address-book"
2120
+ ],
2121
+ version: "1.0.0",
2122
+ isCore: true,
2123
+ component_tree: [{
2124
+ type: "ContactsScreen",
2125
+ id: "contacts-screen-root",
2126
+ props: {}
2127
+ }],
2128
+ defaultProps: {}
2129
+ });
2130
+ PageTemplateRegistry.register({
2131
+ id: CORE_PAGE_IDS.ORDERS,
2132
+ slug: "orders",
2133
+ name: "Orders",
2134
+ description: "Order management provided by Fluid Commerce",
2135
+ category: PAGE_CATEGORIES.CORE,
2136
+ tags: [
2137
+ "orders",
2138
+ "commerce",
2139
+ "sales"
2140
+ ],
2141
+ version: "1.0.0",
2142
+ isCore: true,
2143
+ component_tree: [{
2144
+ type: "OrdersScreen",
2145
+ id: "orders-screen-root",
2146
+ props: {}
2147
+ }],
2148
+ defaultProps: {}
2149
+ });
2150
+ PageTemplateRegistry.register({
2151
+ id: CORE_PAGE_IDS.CUSTOMERS,
2152
+ slug: "customers",
2153
+ name: "Customers",
2154
+ description: "Customer management provided by Fluid Commerce",
2155
+ category: PAGE_CATEGORIES.CORE,
2156
+ tags: [
2157
+ "customers",
2158
+ "people",
2159
+ "commerce"
2160
+ ],
2161
+ version: "1.0.0",
2162
+ isCore: true,
2163
+ component_tree: [{
2164
+ type: "CustomersScreen",
2165
+ id: "customers-screen-root",
2166
+ props: {}
2167
+ }],
2168
+ defaultProps: {}
2169
+ });
2170
+ PageTemplateRegistry.register({
2171
+ id: CORE_PAGE_IDS.PRODUCTS,
2172
+ slug: "products",
2173
+ name: "Products",
2174
+ description: "Product catalog provided by Fluid Commerce",
2175
+ category: PAGE_CATEGORIES.CORE,
2176
+ tags: [
2177
+ "products",
2178
+ "catalog",
2179
+ "commerce"
2180
+ ],
2181
+ version: "1.0.0",
2182
+ isCore: true,
2183
+ component_tree: [{
2184
+ type: "ProductsScreen",
2185
+ id: "products-screen-root",
2186
+ props: {}
2187
+ }],
2188
+ defaultProps: {}
2189
+ });
2190
+ }
2191
+ registerCorePageTemplates();
2192
+ //#endregion
2193
+ //#region src/shell/SdkBottomNav.tsx
2194
+ function isInSection(item, currentSlug) {
2195
+ const normalized = (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(currentSlug);
2196
+ if ((0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(item.slug) === normalized) return true;
2197
+ return item.children?.some((child) => (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(child.slug) === normalized) ?? false;
2198
+ }
2199
+ function getNavTarget(item) {
2200
+ if (item.slug && (!item.children || item.children.length === 0)) return (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(item.slug);
2201
+ if (item.children && item.children.length > 0) {
2202
+ const firstChild = item.children[0];
2203
+ if (firstChild?.slug) return (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(firstChild.slug);
2204
+ }
2205
+ return null;
2206
+ }
2207
+ function SdkBottomNav({ navItems, currentSlug, onNavigate, maxVisibleItems = 5 }) {
2208
+ const { isMobile, useBottomNav } = (0, _fluid_app_portal_core_shell_sidebar.useSidebar)();
2209
+ const [moreOpen, setMoreOpen] = react.useState(false);
2210
+ if (!isMobile || !useBottomNav) return null;
2211
+ const navigableItems = navItems.filter((item) => !item.parent_id).filter((item) => item.slug || item.children && item.children.length > 0);
2212
+ const hasOverflow = navigableItems.length > maxVisibleItems;
2213
+ const visibleItems = hasOverflow ? navigableItems.slice(0, maxVisibleItems - 1) : navigableItems;
2214
+ const overflowItems = hasOverflow ? navigableItems.slice(maxVisibleItems - 1) : [];
2215
+ const handleItemClick = (item) => {
2216
+ const target = getNavTarget(item);
2217
+ if (target) onNavigate(target);
2218
+ setMoreOpen(false);
2219
+ };
2220
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
2221
+ 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)]",
2222
+ children: [visibleItems.map((item) => {
2223
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2224
+ type: "button",
2225
+ onClick: () => handleItemClick(item),
2226
+ className: `flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-[10px] font-medium transition-colors ${isInSection(item, currentSlug) ? "text-primary" : "text-muted-foreground"}`,
2227
+ children: [item.icon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_components_RepIcon.RepIcon, {
2228
+ name: item.icon,
2229
+ className: "size-5"
2230
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "size-5" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2231
+ className: "max-w-[72px] truncate",
2232
+ children: item.label
2233
+ })]
2234
+ }, item.id ?? item.slug ?? item.label);
2235
+ }), hasOverflow && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2236
+ type: "button",
2237
+ onClick: () => setMoreOpen(true),
2238
+ className: `flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-[10px] font-medium transition-colors ${overflowItems.some((item) => isInSection(item, currentSlug)) ? "text-primary" : "text-muted-foreground"}`,
2239
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fortawesome_react_fontawesome.FontAwesomeIcon, {
2240
+ icon: _fortawesome_pro_regular_svg_icons_faEllipsis.faEllipsis,
2241
+ className: "size-5"
2242
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "More" })]
2243
+ })]
2244
+ }), moreOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2245
+ className: "fixed inset-0 z-50 flex flex-col",
2246
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2247
+ className: "flex-1 bg-black/50",
2248
+ onClick: () => setMoreOpen(false),
2249
+ "aria-hidden": "true"
2250
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2251
+ className: "bg-sidebar rounded-t-2xl pb-[env(safe-area-inset-bottom)]",
2252
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2253
+ className: "flex items-center justify-between px-4 pt-4 pb-2",
2254
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2255
+ className: "text-foreground text-sm font-semibold",
2256
+ children: "More"
2257
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2258
+ type: "button",
2259
+ onClick: () => setMoreOpen(false),
2260
+ className: "text-muted-foreground hover:bg-sidebar-accent flex items-center justify-center rounded-full p-1",
2261
+ "aria-label": "Close",
2262
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fortawesome_react_fontawesome.FontAwesomeIcon, {
2263
+ icon: _fortawesome_pro_regular_svg_icons_faXmark.faXmark,
2264
+ className: "size-5"
2265
+ })
2266
+ })]
2267
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2268
+ className: "px-2 pb-4",
2269
+ children: overflowItems.map((item) => {
2270
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2271
+ type: "button",
2272
+ onClick: () => handleItemClick(item),
2273
+ className: `flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors ${isInSection(item, currentSlug) ? "bg-sidebar-primary text-sidebar-primary-foreground" : "text-sidebar-foreground hover:bg-sidebar-accent"}`,
2274
+ children: [item.icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_components_RepIcon.RepIcon, {
2275
+ name: item.icon,
2276
+ className: "size-5"
2277
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.label })]
2278
+ }, item.id ?? item.slug ?? item.label);
2279
+ })
2280
+ })]
2281
+ })]
2282
+ })] });
2283
+ }
2284
+ //#endregion
2285
+ //#region src/shell/AppShellLoading.tsx
2286
+ const SPIN_STYLE_ID = "fluid-app-shell-loading-spin";
2287
+ /**
2288
+ * Inject the spin keyframes style once into the document head.
2289
+ */
2290
+ function ensureSpinStyle() {
2291
+ if (typeof document === "undefined") return;
2292
+ if (document.getElementById(SPIN_STYLE_ID)) return;
2293
+ const style = document.createElement("style");
2294
+ style.id = SPIN_STYLE_ID;
2295
+ style.textContent = `@keyframes spin { to { transform: rotate(360deg); } }`;
2296
+ document.head.appendChild(style);
2297
+ }
2298
+ /**
2299
+ * Full-page loading spinner shown while AppShell is fetching app data
2300
+ * for the first time. Uses inline styles (not Tailwind) since the theme
2301
+ * hasn't loaded yet.
2302
+ */
2303
+ function AppShellLoading() {
2304
+ (0, react.useEffect)(() => {
2305
+ ensureSpinStyle();
2306
+ }, []);
2307
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2308
+ style: {
2309
+ display: "flex",
2310
+ flexDirection: "column",
2311
+ alignItems: "center",
2312
+ justifyContent: "center",
2313
+ minHeight: "100vh",
2314
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif",
2315
+ backgroundColor: "#f9fafb"
2316
+ },
2317
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
2318
+ width: "40px",
2319
+ height: "40px",
2320
+ border: "3px solid #e5e7eb",
2321
+ borderTopColor: "#3b82f6",
2322
+ borderRadius: "50%",
2323
+ animation: "spin 1s linear infinite"
2324
+ } }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2325
+ style: {
2326
+ marginTop: "1rem",
2327
+ color: "#6b7280",
2328
+ fontSize: "0.875rem"
2329
+ },
2330
+ children: "Loading..."
2331
+ })]
2332
+ });
2333
+ }
2334
+ //#endregion
2335
+ //#region src/shell/slug-utils.ts
2336
+ /**
2337
+ * Extract all slugs from a navigation tree, sorted by segment count descending.
2338
+ * Longest slugs first enables greedy prefix matching (e.g. "share/playlists"
2339
+ * is checked before "share").
2340
+ */
2341
+ function collectNavSlugs(items) {
2342
+ const slugs = [];
2343
+ for (const item of items) {
2344
+ if (item.slug) slugs.push((0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(item.slug));
2345
+ for (const child of item.children ?? []) if (child.slug) slugs.push((0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(child.slug));
2346
+ }
2347
+ return [...slugs].sort((a, b) => b.split("/").length - a.split("/").length);
2348
+ }
2349
+ /**
2350
+ * Find the longest registered nav slug that is a prefix of `fullSlug`.
2351
+ * Uses segment-boundary checking to prevent "shop" from matching "shopping".
2352
+ */
2353
+ function matchSlugPrefix(fullSlug, navSlugs) {
2354
+ const normalized = (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(fullSlug);
2355
+ if (!normalized) return void 0;
2356
+ for (const navSlug of navSlugs) {
2357
+ if (normalized === navSlug) return {
2358
+ matchedSlug: navSlug,
2359
+ rest: ""
2360
+ };
2361
+ if (normalized.startsWith(navSlug + "/")) return {
2362
+ matchedSlug: navSlug,
2363
+ rest: normalized.slice(navSlug.length + 1)
2364
+ };
2365
+ }
2366
+ }
2367
+ /**
2368
+ * Extract the slug portion from a full pathname by stripping the basePath prefix.
2369
+ * Returns an empty string when the pathname equals the basePath exactly.
2370
+ *
2371
+ * Examples:
2372
+ * extractSlugFromPathname("/contacts/123", "/") → "contacts/123"
2373
+ * extractSlugFromPathname("/portal/contacts", "/portal") → "contacts"
2374
+ * extractSlugFromPathname("/portal", "/portal") → ""
2375
+ * extractSlugFromPathname("/", "/") → ""
2376
+ */
2377
+ function extractSlugFromPathname(pathname, basePath) {
2378
+ if (basePath === "/") return pathname.replace(/^\//, "");
2379
+ if (pathname.startsWith(basePath)) return pathname.slice(basePath.length).replace(/^\//, "");
2380
+ return pathname.replace(/^\//, "");
2381
+ }
2382
+ function isSlugInSection(item, currentSlug, navSlugs) {
2383
+ const baseSlug = matchSlugPrefix(currentSlug, navSlugs)?.matchedSlug ?? (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(currentSlug);
2384
+ if ((0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(item.slug) === baseSlug) return true;
2385
+ return item.children?.some((child) => (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(child.slug) === baseSlug) ?? false;
2386
+ }
2387
+ //#endregion
2388
+ //#region src/shell/SdkNavigation.tsx
2389
+ function SdkNavigation({ navItems, currentSlug, onNavigate, navSlugs }) {
2390
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_shell_sidebar.SidebarMenu, { children: navItems.map((item, index) => {
2391
+ if (!item.slug && !item.label) return null;
2392
+ if (!item.slug) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_shell_sidebar.SidebarGroupLabel, { children: item.label }, item.id ?? `section-${index}`);
2393
+ const itemSlug = (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(item.slug);
2394
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_shell_sidebar.SidebarMenuItem, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_fluid_app_portal_core_shell_sidebar.SidebarMenuButton, {
2395
+ isActive: isSlugInSection(item, currentSlug, navSlugs),
2396
+ onClick: () => onNavigate(itemSlug),
2397
+ children: [item.icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_components_RepIcon.RepIcon, { name: item.icon }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2398
+ className: "truncate",
2399
+ children: item.label
2400
+ })]
2401
+ }) }, item.id ?? itemSlug);
2402
+ }) });
2403
+ }
2404
+ //#endregion
2405
+ //#region src/shell/QuickLinksDropdown.tsx
2406
+ function QuickLinksDropdown({ onNavigate }) {
2407
+ const [open, setOpen] = (0, react.useState)(false);
2408
+ const panelRef = (0, react.useRef)(null);
2409
+ const buttonRef = (0, react.useRef)(null);
2410
+ const close = (0, react.useCallback)(() => setOpen(false), []);
2411
+ (0, react.useEffect)(() => {
2412
+ if (!open) return;
2413
+ const handleMouseDown = (e) => {
2414
+ if (panelRef.current && !panelRef.current.contains(e.target) && buttonRef.current && !buttonRef.current.contains(e.target)) close();
2415
+ };
2416
+ const handleKeyDown = (e) => {
2417
+ if (e.key === "Escape") close();
2418
+ };
2419
+ document.addEventListener("mousedown", handleMouseDown);
2420
+ document.addEventListener("keydown", handleKeyDown);
2421
+ return () => {
2422
+ document.removeEventListener("mousedown", handleMouseDown);
2423
+ document.removeEventListener("keydown", handleKeyDown);
2424
+ };
2425
+ }, [open, close]);
2426
+ const sections = (0, _fluid_app_portal_core_navigation_system_navigation_items.getSystemNavigationBySection)();
2427
+ const handleItemClick = (slug) => {
2428
+ onNavigate(slug);
2429
+ close();
2430
+ };
2431
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2432
+ className: "relative",
2433
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2434
+ ref: buttonRef,
2435
+ type: "button",
2436
+ onClick: () => setOpen((prev) => !prev),
2437
+ className: "text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex shrink-0 items-center justify-center rounded-md p-2",
2438
+ "aria-label": "Quick links",
2439
+ "aria-expanded": open,
2440
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fortawesome_react_fontawesome.FontAwesomeIcon, {
2441
+ icon: _fortawesome_pro_regular_svg_icons_faTableCellsLarge.faTableCellsLarge,
2442
+ className: "h-4 w-4"
2443
+ })
2444
+ }), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2445
+ ref: panelRef,
2446
+ className: "border-border bg-background absolute top-full right-0 z-50 mt-1 w-[700px] max-w-[90vw] overflow-hidden rounded-lg border shadow-lg",
2447
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2448
+ className: "flex flex-col",
2449
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2450
+ className: "bg-background flex items-center gap-2 border-b p-4",
2451
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fortawesome_react_fontawesome.FontAwesomeIcon, {
2452
+ icon: _fortawesome_pro_regular_svg_icons_faTableCellsLarge.faTableCellsLarge,
2453
+ className: "text-muted-foreground h-5 w-5"
2454
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2455
+ className: "text-foreground text-sm font-semibold",
2456
+ children: "Shortcuts"
2457
+ })]
2458
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2459
+ className: "bg-muted space-y-6 p-6",
2460
+ children: Object.entries(sections).map(([sectionName, items]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2461
+ className: "space-y-3",
2462
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2463
+ className: "text-foreground text-sm font-semibold",
2464
+ children: sectionName
2465
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2466
+ className: "grid grid-cols-4 gap-2",
2467
+ children: items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2468
+ type: "button",
2469
+ onClick: () => handleItemClick(item.slug),
2470
+ className: "text-sidebar-foreground hover:bg-sidebar-primary hover:text-sidebar-primary-foreground flex items-center gap-2 rounded-lg px-3 py-2 text-sm transition-colors",
2471
+ children: [item.icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_components_RepIcon.RepIcon, {
2472
+ name: item.icon,
2473
+ className: "text-muted-foreground h-4 w-4 shrink-0"
2474
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2475
+ className: "truncate",
2476
+ children: item.label
2477
+ })]
2478
+ }, item.slug))
2479
+ })]
2480
+ }, sectionName))
2481
+ })]
2482
+ })
2483
+ })]
2484
+ });
2485
+ }
2486
+ //#endregion
2487
+ //#region src/shell/SdkHeader.tsx
2488
+ function SdkHeader({ tabs, mobileTabs, currentSlug, onNavigate, navSlugs }) {
2489
+ const sidebar = (0, _fluid_app_portal_core_shell_sidebar.useSidebar)();
2490
+ const themeMode = (0, _fluid_app_portal_core_shell_ThemeModeContext.useThemeMode)();
2491
+ const baseSlug = matchSlugPrefix(currentSlug, navSlugs)?.matchedSlug ?? (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(currentSlug);
2492
+ const themeIcon = themeMode.mode === "dark" ? _fortawesome_pro_regular_svg_icons_faMoon.faMoon : _fortawesome_pro_regular_svg_icons_faSun.faSun;
2493
+ const activeTabs = sidebar.isMobile && sidebar.useBottomNav && mobileTabs ? mobileTabs : tabs;
2494
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2495
+ className: "bg-sidebar flex h-[52px] shrink-0 items-center gap-2 px-6",
2496
+ children: [
2497
+ sidebar.isMobile && !sidebar.useBottomNav && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2498
+ type: "button",
2499
+ onClick: sidebar.toggleSidebar,
2500
+ 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",
2501
+ "aria-label": "Toggle sidebar",
2502
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fortawesome_react_fontawesome.FontAwesomeIcon, {
2503
+ icon: _fortawesome_pro_regular_svg_icons_faBars.faBars,
2504
+ className: "size-5"
2505
+ })
2506
+ }),
2507
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
2508
+ className: "scrollbar-none flex flex-1 items-center gap-1 overflow-x-auto",
2509
+ children: activeTabs.map((tab) => {
2510
+ const tabSlug = (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(tab.slug);
2511
+ if (!tabSlug) return null;
2512
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2513
+ type: "button",
2514
+ onClick: () => onNavigate(tabSlug),
2515
+ className: `border-b-2 px-4 py-3 text-sm font-medium whitespace-nowrap transition-colors ${tabSlug === baseSlug ? "text-foreground border-primary" : "text-muted-foreground hover:border-border hover:text-foreground border-transparent"}`,
2516
+ children: tab.label
2517
+ }, tab.id ?? tabSlug);
2518
+ })
2519
+ }),
2520
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickLinksDropdown, { onNavigate }),
2521
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2522
+ type: "button",
2523
+ onClick: themeMode.cycleMode,
2524
+ 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",
2525
+ "aria-label": `Switch theme (current: ${themeMode.mode})`,
2526
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fortawesome_react_fontawesome.FontAwesomeIcon, {
2527
+ icon: themeIcon,
2528
+ className: "size-3"
2529
+ })
2530
+ })
2531
+ ]
2532
+ });
2533
+ }
2534
+ //#endregion
2535
+ //#region src/shell/BuilderScreenView.tsx
2536
+ /**
2537
+ * BuilderScreenView — renders a builder screen's component_tree with
2538
+ * DataAwareWidget support for data-bound widgets.
2539
+ *
2540
+ * Uses the shared ScreenRenderer from portal-widgets under the hood,
2541
+ * but wraps data-bound widgets with DataAwareWidget from portal-core.
2542
+ */
2543
+ /**
2544
+ * Renders a single widget, wrapping with DataAwareWidget if it has a dataSource.
2545
+ */
2546
+ function WidgetRenderer({ widget, index }) {
2547
+ const Component = (0, _fluid_app_portal_widgets_contexts.useRegistry)()[widget.type];
2548
+ if (!Component) {
2549
+ console.warn(`[BuilderScreenView] Widget type "${String(widget.type)}" not found in registry`);
2550
+ return null;
2551
+ }
2552
+ if (widget.dataSource) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2553
+ className: "h-full w-full overflow-x-hidden",
2554
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_data_sources_DataAwareWidget.DataAwareWidget, {
2555
+ widget,
2556
+ Component
2557
+ })
2558
+ }, widget.id ?? index);
2559
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2560
+ className: "h-full w-full overflow-x-hidden",
2561
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, { ...widget.props })
2562
+ }, widget.id ?? index);
2563
+ }
2564
+ /**
2565
+ * Renders a builder screen's component_tree with full data source support.
2566
+ * Widgets with `dataSource` config are automatically wrapped with `DataAwareWidget`
2567
+ * which fetches data and merges it with static props before rendering.
2568
+ */
2569
+ function BuilderScreenViewImpl({ screen, className }) {
2570
+ const widgets = screen.component_tree;
2571
+ if (!widgets || widgets.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2572
+ className: className ?? "h-full w-full",
2573
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2574
+ className: "text-muted-foreground flex h-full items-center justify-center",
2575
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "This screen has no content yet." })
2576
+ })
2577
+ });
2578
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2579
+ className: className ?? "h-full w-full",
2580
+ children: widgets.map((widget, index) => {
2581
+ if (!widget) return null;
2582
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetRenderer, {
2583
+ widget,
2584
+ index
2585
+ }, widget.id ?? index);
2586
+ })
2587
+ });
2588
+ }
2589
+ const BuilderScreenView = (0, react.memo)(BuilderScreenViewImpl);
2590
+ //#endregion
2591
+ //#region src/shell/PageRouter.tsx
2592
+ const SYSTEM_SLUG_SCREEN_MAP = {
2593
+ messages: require_MessagingScreen.MessagingScreen,
2594
+ contacts: require_ContactsScreen.ContactsScreen,
2595
+ shop: require_OrdersScreen.OrdersScreen,
2596
+ customers: require_CustomersScreen.CustomersScreen,
2597
+ products: require_ProductsScreen.ProductsScreen
2598
+ };
2599
+ function PageRouter({ currentSlug, currentNavItem, customPages, screens, baseSlug, restParams }) {
2600
+ const screenById = (0, react.useMemo)(() => {
2601
+ if (!screens || screens.length === 0) return void 0;
2602
+ return new Map(screens.map((s) => [s.id, s]));
2603
+ }, [screens]);
2604
+ const screenBySlug = (0, react.useMemo)(() => {
2605
+ if (!screens || screens.length === 0) return void 0;
2606
+ return new Map(screens.filter((s) => s.slug).map((s) => [s.slug, s]));
2607
+ }, [screens]);
2608
+ const builderScreen = (0, react.useMemo)(() => {
2609
+ if (currentNavItem?.screen_id && screenById) {
2610
+ const byId = screenById.get(currentNavItem.screen_id);
2611
+ if (byId) return byId;
2612
+ }
2613
+ if (screenBySlug) return screenBySlug.get(currentSlug) ?? screenBySlug.get(baseSlug) ?? void 0;
2614
+ }, [
2615
+ currentNavItem?.screen_id,
2616
+ screenById,
2617
+ screenBySlug,
2618
+ currentSlug,
2619
+ baseSlug
2620
+ ]);
2621
+ const SystemScreen = SYSTEM_SLUG_SCREEN_MAP[baseSlug];
2622
+ if (SystemScreen) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SystemScreen, {});
2623
+ if ((0, _fluid_app_portal_core_navigation_system_navigation_items.isSystemNavigationItem)(baseSlug)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CoreScreenPlaceholder.CoreScreenPlaceholder, { name: currentNavItem?.label ?? baseSlug });
2624
+ const ExactCustomPage = customPages?.[currentSlug];
2625
+ if (ExactCustomPage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExactCustomPage, {
2626
+ slug: currentSlug,
2627
+ params: restParams
2628
+ });
2629
+ if (baseSlug !== currentSlug) {
2630
+ const PrefixCustomPage = customPages?.[baseSlug];
2631
+ if (PrefixCustomPage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PrefixCustomPage, {
2632
+ slug: currentSlug,
2633
+ params: restParams
2634
+ });
2635
+ }
2636
+ if (builderScreen) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BuilderScreenView, { screen: builderScreen });
2637
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CoreScreenPlaceholder.CoreScreenPlaceholder, { name: currentNavItem?.label ?? currentSlug });
2638
+ }
2639
+ //#endregion
2640
+ //#region src/shell/AppNavigationContext.tsx
2641
+ const AppNavigationContext = (0, react.createContext)(null);
2642
+ function AppNavigationProvider({ currentSlug, basePath, navigate, children }) {
2643
+ const buildHref = (0, react.useMemo)(() => {
2644
+ return (slug) => {
2645
+ if (basePath === "/") return `/${slug}`;
2646
+ return `${basePath}/${slug}`;
2647
+ };
2648
+ }, [basePath]);
2649
+ const value = (0, react.useMemo)(() => ({
2650
+ currentSlug,
2651
+ basePath,
2652
+ navigate,
2653
+ buildHref
2654
+ }), [
2655
+ currentSlug,
2656
+ basePath,
2657
+ navigate,
2658
+ buildHref
2659
+ ]);
2660
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppNavigationContext.Provider, {
2661
+ value,
2662
+ children
2663
+ });
2664
+ }
2665
+ function useAppNavigation() {
2666
+ const ctx = (0, react.useContext)(AppNavigationContext);
2667
+ if (!ctx) throw new Error("useAppNavigation must be used within an <AppShell> or <AppNavigationProvider>");
2668
+ return ctx;
2669
+ }
2670
+ //#endregion
2671
+ //#region src/shell/AppShell.tsx
2672
+ const THEME_STORAGE_KEY = "portal-theme-mode";
2673
+ const DEFAULT_NAVIGATION = [
2674
+ {
2675
+ label: "We Commerce",
2676
+ children: []
2677
+ },
2678
+ {
2679
+ slug: "shop",
2680
+ label: "Shop",
2681
+ icon: "store",
2682
+ children: []
2683
+ },
2684
+ {
2685
+ slug: "account",
2686
+ label: "Account",
2687
+ icon: "user-gear",
2688
+ children: []
2689
+ },
2690
+ {
2691
+ slug: "messages",
2692
+ label: "Messaging",
2693
+ icon: "comment",
2694
+ children: []
2695
+ },
2696
+ {
2697
+ label: "Marketing Assets",
2698
+ children: []
2699
+ },
2700
+ {
2701
+ slug: "share/products",
2702
+ label: "Products",
2703
+ icon: "boxes-stacked",
2704
+ children: []
2705
+ }
2706
+ ];
2707
+ function getInitialThemeMode() {
2708
+ if (typeof window === "undefined") return "light";
2709
+ const stored = localStorage.getItem(THEME_STORAGE_KEY);
2710
+ if (stored === "light" || stored === "dark") return stored;
2711
+ return "light";
2712
+ }
2713
+ function findFirstNavigableSlug(items) {
2714
+ for (const item of items) {
2715
+ if (item.slug) return (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(item.slug);
2716
+ for (const child of item.children ?? []) if (child.slug) return (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(child.slug);
2717
+ }
2718
+ return "";
2719
+ }
2720
+ function findCurrentSection(items, slug) {
2721
+ const normalized = (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(slug);
2722
+ for (const item of items) {
2723
+ if ((0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(item.slug) === normalized) return item;
2724
+ if (item.children?.some((child) => (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(child.slug) === normalized)) return item;
2725
+ }
2726
+ }
2727
+ function findNavItem(items, slug) {
2728
+ const normalized = (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(slug);
2729
+ for (const item of items) {
2730
+ if ((0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(item.slug) === normalized) return item;
2731
+ for (const child of item.children ?? []) if ((0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(child.slug) === normalized) return child;
2732
+ }
2733
+ }
2734
+ function AppShell({ appData: appDataProp, navigation: navigationProp, customPages, basePath = "/", currentSlug: controlledSlug, onNavigate: onNavigateProp, sidebarHeader, sidebarFooter, children }) {
2735
+ const normalizedBasePath = (0, react.useMemo)(() => {
2736
+ const stripped = basePath.replace(/^\/|\/$/g, "");
2737
+ return stripped ? `/${stripped}` : "/";
2738
+ }, [basePath]);
2739
+ const { data: fetchedAppData, isLoading } = useFluidApp({ enabled: !appDataProp });
2740
+ const appData = appDataProp ?? fetchedAppData;
2741
+ const activeTheme = (0, react.useMemo)(() => {
2742
+ if (!appData?.profile?.themes?.length) return void 0;
2743
+ const themes = appData.profile.themes;
2744
+ const activeId = appData.profile.activeThemeId;
2745
+ return activeId ? themes.find((t) => t.id === activeId) ?? themes[0] : themes[0];
2746
+ }, [appData?.profile?.themes, appData?.profile?.activeThemeId]);
2747
+ (0, react.useEffect)(() => {
2748
+ if (!activeTheme) return;
2749
+ (0, _fluid_app_portal_core_theme.applyTheme)((0, _fluid_app_portal_core_theme.resolveTheme)(activeTheme));
2750
+ return () => {
2751
+ (0, _fluid_app_portal_core_theme.removeAllThemes)();
2752
+ };
2753
+ }, [activeTheme]);
2754
+ const navItems = (0, react.useMemo)(() => {
2755
+ if (navigationProp) return navigationProp;
2756
+ const profileNav = appData?.profile?.navigation?.navigation_items;
2757
+ if (profileNav && profileNav.length > 0) return profileNav;
2758
+ return DEFAULT_NAVIGATION;
2759
+ }, [navigationProp, appData?.profile?.navigation?.navigation_items]);
2760
+ const mobileNavItems = (0, react.useMemo)(() => {
2761
+ const mobileNav = appData?.profile?.mobile_navigation?.navigation_items;
2762
+ if (mobileNav && mobileNav.length > 0) return mobileNav;
2763
+ return navItems;
2764
+ }, [appData?.profile?.mobile_navigation?.navigation_items, navItems]);
2765
+ const screens = appData?.screens;
2766
+ const navSlugs = (0, react.useMemo)(() => collectNavSlugs(navItems), [navItems]);
2767
+ const [themeMode, setThemeMode] = (0, react.useState)(getInitialThemeMode);
2768
+ const handleThemeModeChange = (0, react.useCallback)((mode) => {
2769
+ setThemeMode(mode);
2770
+ if (typeof window !== "undefined") localStorage.setItem(THEME_STORAGE_KEY, mode);
2771
+ }, []);
2772
+ const [pathSlug, setPathSlug] = (0, react.useState)(() => {
2773
+ if (typeof window === "undefined") return "";
2774
+ return extractSlugFromPathname(window.location.pathname, normalizedBasePath);
2775
+ });
2776
+ (0, react.useEffect)(() => {
2777
+ if (controlledSlug !== void 0) return;
2778
+ if (typeof window === "undefined") return;
2779
+ if (!extractSlugFromPathname(window.location.pathname, normalizedBasePath)) {
2780
+ const firstSlug = findFirstNavigableSlug(navItems);
2781
+ if (firstSlug) {
2782
+ const targetPath = normalizedBasePath === "/" ? `/${firstSlug}` : `${normalizedBasePath}/${firstSlug}`;
2783
+ history.replaceState(null, "", targetPath);
2784
+ setPathSlug(firstSlug);
2785
+ }
2786
+ }
2787
+ }, [
2788
+ navItems,
2789
+ controlledSlug,
2790
+ normalizedBasePath
2791
+ ]);
2792
+ (0, react.useEffect)(() => {
2793
+ if (controlledSlug !== void 0) return;
2794
+ const handlePopState = () => {
2795
+ setPathSlug(extractSlugFromPathname(window.location.pathname, normalizedBasePath));
2796
+ };
2797
+ window.addEventListener("popstate", handlePopState);
2798
+ return () => window.removeEventListener("popstate", handlePopState);
2799
+ }, [controlledSlug, normalizedBasePath]);
2800
+ const activeSlug = controlledSlug ?? pathSlug;
2801
+ const handleNavigate = (0, react.useCallback)((slug) => {
2802
+ if (onNavigateProp) {
2803
+ onNavigateProp(slug);
2804
+ return;
2805
+ }
2806
+ const targetPath = normalizedBasePath === "/" ? `/${slug}` : `${normalizedBasePath}/${slug}`;
2807
+ history.pushState(null, "", targetPath);
2808
+ setPathSlug(slug);
2809
+ }, [onNavigateProp, normalizedBasePath]);
2810
+ const slugMatch = (0, react.useMemo)(() => matchSlugPrefix(activeSlug, navSlugs), [activeSlug, navSlugs]);
2811
+ const baseSlug = slugMatch?.matchedSlug ?? (0, _fluid_app_portal_core_navigation_system_navigation_items.normalizeSlug)(activeSlug);
2812
+ const restParams = slugMatch?.rest ?? "";
2813
+ const secondLevelTabs = findCurrentSection(navItems, baseSlug)?.children ?? [];
2814
+ const mobileSecondLevelTabs = findCurrentSection(mobileNavItems, baseSlug)?.children ?? [];
2815
+ const currentNavItem = findNavItem(navItems, baseSlug);
2816
+ const screenTitle = currentNavItem?.label || screens?.find((s) => s.id === currentNavItem?.screen_id)?.name || void 0;
2817
+ const content = typeof children === "function" ? children({
2818
+ currentSlug: activeSlug,
2819
+ currentNavItem
2820
+ }) : children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_fluid_app_portal_core_shell_ScreenHeaderContext.ScreenHeaderProvider, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_shell_ScreenHeader.ScreenHeader, { title: screenTitle }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageRouter, {
2821
+ currentSlug: activeSlug,
2822
+ currentNavItem,
2823
+ customPages,
2824
+ screens,
2825
+ baseSlug,
2826
+ restParams
2827
+ })] });
2828
+ if (isLoading && !appData) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppShellLoading, {});
2829
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_shell_ThemeModeContext.ThemeModeProvider, {
2830
+ mode: themeMode,
2831
+ onModeChange: handleThemeModeChange,
2832
+ autoModeEnabled: false,
2833
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppNavigationProvider, {
2834
+ currentSlug: activeSlug,
2835
+ basePath: normalizedBasePath,
2836
+ navigate: handleNavigate,
2837
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2838
+ "data-theme": activeTheme?.id,
2839
+ "data-theme-mode": themeMode === "auto" ? void 0 : themeMode,
2840
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_portal_core_shell_AppShellLayout.AppShellLayout, {
2841
+ sidebarContent: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SdkNavigation, {
2842
+ navItems,
2843
+ currentSlug: activeSlug,
2844
+ onNavigate: handleNavigate,
2845
+ navSlugs
2846
+ }),
2847
+ headerContent: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SdkHeader, {
2848
+ tabs: secondLevelTabs,
2849
+ mobileTabs: mobileSecondLevelTabs,
2850
+ currentSlug: activeSlug,
2851
+ onNavigate: handleNavigate,
2852
+ navSlugs
2853
+ }),
2854
+ sidebarHeader,
2855
+ sidebarFooter,
2856
+ useBottomNav: true,
2857
+ afterContent: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SdkBottomNav, {
2858
+ navItems: mobileNavItems,
2859
+ currentSlug: activeSlug,
2860
+ onNavigate: handleNavigate
2861
+ }),
2862
+ children: content
2863
+ })
2864
+ })
2865
+ })
2866
+ });
2867
+ }
2868
+ //#endregion
2869
+ //#region src/shell/AppLink.tsx
2870
+ /**
2871
+ * SPA-aware link that renders a real `<a href>` for accessibility
2872
+ * (right-click, ctrl+click, screen readers) but intercepts normal
2873
+ * clicks for client-side navigation.
2874
+ */
2875
+ const AppLink = (0, react.forwardRef)(function AppLink({ to, onClick, children, ...rest }, ref) {
2876
+ const { navigate, buildHref } = useAppNavigation();
2877
+ const handleClick = (e) => {
2878
+ onClick?.(e);
2879
+ if (e.defaultPrevented) return;
2880
+ if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
2881
+ if (e.button !== 0) return;
2882
+ if (rest.target && rest.target !== "_self") return;
2883
+ e.preventDefault();
2884
+ navigate(to);
2885
+ };
2886
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2887
+ ref,
2888
+ href: buildHref(to),
2889
+ onClick: handleClick,
2890
+ ...rest,
2891
+ children
2892
+ });
2893
+ });
2894
+ //#endregion
2895
+ exports.ACTIVITY_SLUGS = ACTIVITY_SLUGS;
2896
+ exports.APP_DATA_QUERY_KEY = APP_DATA_QUERY_KEY;
2897
+ Object.defineProperty(exports, "AUTH_CONSTANTS", {
2898
+ enumerable: true,
2899
+ get: function() {
2900
+ return _fluid_app_auth.AUTH_CONSTANTS;
2901
+ }
2902
+ });
2903
+ Object.defineProperty(exports, "AlertWidget", {
2904
+ enumerable: true,
2905
+ get: function() {
2906
+ return _fluid_app_portal_widgets_widgets.AlertWidget;
2907
+ }
2908
+ });
2909
+ exports.ApiError = require_MessagingScreen.ApiError;
2910
+ exports.AppLink = AppLink;
2911
+ exports.AppNavigationProvider = AppNavigationProvider;
2912
+ exports.AppShell = AppShell;
2913
+ exports.AuthError = AuthError;
2914
+ exports.AuthLoading = AuthLoading;
2915
+ exports.BuilderScreenView = BuilderScreenView;
2916
+ exports.CORE_PAGE_IDS = CORE_PAGE_IDS;
2917
+ exports.CURRENT_REP_QUERY_KEY = CURRENT_REP_QUERY_KEY;
2918
+ Object.defineProperty(exports, "CalendarWidget", {
2919
+ enumerable: true,
2920
+ get: function() {
2921
+ return _fluid_app_portal_widgets_widgets.CalendarWidget;
2922
+ }
2923
+ });
2924
+ Object.defineProperty(exports, "CarouselWidget", {
2925
+ enumerable: true,
2926
+ get: function() {
2927
+ return _fluid_app_portal_widgets_widgets.CarouselWidget;
2928
+ }
2929
+ });
2930
+ Object.defineProperty(exports, "CatchUpWidget", {
2931
+ enumerable: true,
2932
+ get: function() {
2933
+ return _fluid_app_portal_widgets_widgets.CatchUpWidget;
2934
+ }
2935
+ });
2936
+ Object.defineProperty(exports, "ChartWidget", {
2937
+ enumerable: true,
2938
+ get: function() {
2939
+ return _fluid_app_portal_widgets_widgets.ChartWidget;
2940
+ }
2941
+ });
2942
+ exports.ContactsScreen = require_ContactsScreen.ContactsScreen;
2943
+ Object.defineProperty(exports, "ContainerWidget", {
2944
+ enumerable: true,
2945
+ get: function() {
2946
+ return _fluid_app_portal_widgets_widgets.ContainerWidget;
2947
+ }
2948
+ });
2949
+ exports.CustomersScreen = require_CustomersScreen.CustomersScreen;
2950
+ Object.defineProperty(exports, "DEFAULT_AUTH_URL", {
2951
+ enumerable: true,
2952
+ get: function() {
2953
+ return _fluid_app_auth.DEFAULT_AUTH_URL;
2954
+ }
2955
+ });
2956
+ Object.defineProperty(exports, "DEFAULT_COLORS", {
2957
+ enumerable: true,
2958
+ get: function() {
2959
+ return themes_exports.DEFAULT_COLORS;
2960
+ }
2961
+ });
2962
+ Object.defineProperty(exports, "DEFAULT_FONT_FAMILIES", {
2963
+ enumerable: true,
2964
+ get: function() {
2965
+ return themes_exports.DEFAULT_FONT_FAMILIES;
2966
+ }
2967
+ });
2968
+ Object.defineProperty(exports, "DEFAULT_FONT_SIZES", {
2969
+ enumerable: true,
2970
+ get: function() {
2971
+ return themes_exports.DEFAULT_FONT_SIZES;
2972
+ }
2973
+ });
2974
+ Object.defineProperty(exports, "DEFAULT_RADII", {
2975
+ enumerable: true,
2976
+ get: function() {
2977
+ return themes_exports.DEFAULT_RADII;
2978
+ }
2979
+ });
2980
+ exports.DEFAULT_SDK_WIDGET_REGISTRY = require_MessagingScreen.DEFAULT_SDK_WIDGET_REGISTRY;
2981
+ Object.defineProperty(exports, "DEFAULT_SPACING", {
2982
+ enumerable: true,
2983
+ get: function() {
2984
+ return themes_exports.DEFAULT_SPACING;
2985
+ }
2986
+ });
2987
+ Object.defineProperty(exports, "DEFAULT_THEME_ID", {
2988
+ enumerable: true,
2989
+ get: function() {
2990
+ return themes_exports.DEFAULT_THEME_ID;
2991
+ }
2992
+ });
2993
+ Object.defineProperty(exports, "DEFAULT_THEME_NAME", {
2994
+ enumerable: true,
2995
+ get: function() {
2996
+ return themes_exports.DEFAULT_THEME_NAME;
2997
+ }
2998
+ });
2999
+ Object.defineProperty(exports, "EmbedWidget", {
3000
+ enumerable: true,
3001
+ get: function() {
3002
+ return _fluid_app_portal_widgets_widgets.EmbedWidget;
3003
+ }
3004
+ });
3005
+ Object.defineProperty(exports, "FONT_FAMILY_KEYS", {
3006
+ enumerable: true,
3007
+ get: function() {
3008
+ return themes_exports.FONT_FAMILY_KEYS;
3009
+ }
3010
+ });
3011
+ Object.defineProperty(exports, "FONT_SIZE_KEYS", {
3012
+ enumerable: true,
3013
+ get: function() {
3014
+ return themes_exports.FONT_SIZE_KEYS;
3015
+ }
3016
+ });
3017
+ exports.FluidAuthProvider = require_MessagingScreen.FluidAuthProvider;
3018
+ exports.FluidProvider = require_MessagingScreen.FluidProvider;
3019
+ exports.FluidThemeProvider = require_MessagingScreen.FluidThemeProvider;
3020
+ Object.defineProperty(exports, "ImageWidget", {
3021
+ enumerable: true,
3022
+ get: function() {
3023
+ return _fluid_app_portal_widgets_widgets.ImageWidget;
3024
+ }
3025
+ });
3026
+ Object.defineProperty(exports, "LayoutWidget", {
3027
+ enumerable: true,
3028
+ get: function() {
3029
+ return _fluid_app_portal_widgets_widgets.LayoutWidget;
3030
+ }
3031
+ });
3032
+ Object.defineProperty(exports, "ListWidget", {
3033
+ enumerable: true,
3034
+ get: function() {
3035
+ return _fluid_app_portal_widgets_widgets.ListWidget;
3036
+ }
3037
+ });
3038
+ exports.MessagingScreen = require_MessagingScreen.MessagingScreen;
3039
+ Object.defineProperty(exports, "MySiteWidget", {
3040
+ enumerable: true,
3041
+ get: function() {
3042
+ return _fluid_app_portal_widgets_widgets.MySiteWidget;
3043
+ }
3044
+ });
3045
+ Object.defineProperty(exports, "NestedWidget", {
3046
+ enumerable: true,
3047
+ get: function() {
3048
+ return _fluid_app_portal_widgets_widgets.NestedWidget;
3049
+ }
3050
+ });
3051
+ exports.OrdersScreen = require_OrdersScreen.OrdersScreen;
3052
+ exports.PAGE_CATEGORIES = PAGE_CATEGORIES;
3053
+ exports.PERMISSIONS_QUERY_KEY = PERMISSIONS_QUERY_KEY;
3054
+ exports.PROFILE_QUERY_KEY = PROFILE_QUERY_KEY;
3055
+ Object.defineProperty(exports, "PROPERTY_FIELD_TYPES", {
3056
+ enumerable: true,
3057
+ get: function() {
3058
+ return _fluid_app_portal_core_registries.PROPERTY_FIELD_TYPES;
3059
+ }
3060
+ });
3061
+ exports.PageRouter = PageRouter;
3062
+ exports.PageTemplateProvider = PageTemplateProvider;
3063
+ exports.PageTemplateRegistry = PageTemplateRegistry;
3064
+ exports.ProductsScreen = require_ProductsScreen.ProductsScreen;
3065
+ exports.QuickLinksDropdown = QuickLinksDropdown;
3066
+ Object.defineProperty(exports, "QuickShareWidget", {
3067
+ enumerable: true,
3068
+ get: function() {
3069
+ return _fluid_app_portal_widgets_widgets.QuickShareWidget;
3070
+ }
3071
+ });
3072
+ Object.defineProperty(exports, "RADIUS_KEYS", {
3073
+ enumerable: true,
3074
+ get: function() {
3075
+ return themes_exports.RADIUS_KEYS;
3076
+ }
3077
+ });
3078
+ Object.defineProperty(exports, "RecentActivityWidget", {
3079
+ enumerable: true,
3080
+ get: function() {
3081
+ return _fluid_app_portal_widgets_widgets.RecentActivityWidget;
3082
+ }
3083
+ });
3084
+ exports.RequireAuth = RequireAuth;
3085
+ Object.defineProperty(exports, "SEMANTIC_COLOR_NAMES", {
3086
+ enumerable: true,
3087
+ get: function() {
3088
+ return themes_exports.SEMANTIC_COLOR_NAMES;
3089
+ }
3090
+ });
3091
+ Object.defineProperty(exports, "SHADE_STEPS", {
3092
+ enumerable: true,
3093
+ get: function() {
3094
+ return themes_exports.SHADE_STEPS;
3095
+ }
3096
+ });
3097
+ Object.defineProperty(exports, "STORAGE_KEYS", {
3098
+ enumerable: true,
3099
+ get: function() {
3100
+ return _fluid_app_auth.STORAGE_KEYS;
3101
+ }
3102
+ });
3103
+ exports.SdkHeader = SdkHeader;
3104
+ exports.SdkNavigation = SdkNavigation;
3105
+ Object.defineProperty(exports, "SpacerWidget", {
3106
+ enumerable: true,
3107
+ get: function() {
3108
+ return _fluid_app_portal_widgets_widgets.SpacerWidget;
3109
+ }
3110
+ });
3111
+ Object.defineProperty(exports, "TableWidget", {
3112
+ enumerable: true,
3113
+ get: function() {
3114
+ return _fluid_app_portal_widgets_widgets.TableWidget;
3115
+ }
3116
+ });
3117
+ Object.defineProperty(exports, "TextWidget", {
3118
+ enumerable: true,
3119
+ get: function() {
3120
+ return _fluid_app_portal_widgets_widgets.TextWidget;
3121
+ }
3122
+ });
3123
+ Object.defineProperty(exports, "ThemeModeProvider", {
3124
+ enumerable: true,
3125
+ get: function() {
3126
+ return _fluid_app_portal_core_shell_ThemeModeContext.ThemeModeProvider;
3127
+ }
3128
+ });
3129
+ Object.defineProperty(exports, "ToDoWidget", {
3130
+ enumerable: true,
3131
+ get: function() {
3132
+ return _fluid_app_portal_widgets_widgets.ToDoWidget;
3133
+ }
3134
+ });
3135
+ Object.defineProperty(exports, "URL_PARAMS", {
3136
+ enumerable: true,
3137
+ get: function() {
3138
+ return _fluid_app_auth.URL_PARAMS;
3139
+ }
3140
+ });
3141
+ Object.defineProperty(exports, "USER_TYPES", {
3142
+ enumerable: true,
3143
+ get: function() {
3144
+ return _fluid_app_auth.USER_TYPES;
3145
+ }
3146
+ });
3147
+ Object.defineProperty(exports, "VideoWidget", {
3148
+ enumerable: true,
3149
+ get: function() {
3150
+ return _fluid_app_portal_widgets_widgets.VideoWidget;
3151
+ }
3152
+ });
3153
+ Object.defineProperty(exports, "WIDGET_TYPE_NAMES", {
3154
+ enumerable: true,
3155
+ get: function() {
3156
+ return _fluid_app_portal_core_types.WIDGET_TYPE_NAMES;
3157
+ }
3158
+ });
3159
+ Object.defineProperty(exports, "alertWidgetPropertySchema", {
3160
+ enumerable: true,
3161
+ get: function() {
3162
+ return _fluid_app_portal_widgets_widgets.alertWidgetPropertySchema;
3163
+ }
3164
+ });
3165
+ Object.defineProperty(exports, "applyTheme", {
3166
+ enumerable: true,
3167
+ get: function() {
3168
+ return themes_exports.applyTheme;
3169
+ }
3170
+ });
3171
+ Object.defineProperty(exports, "assertDefined", {
3172
+ enumerable: true,
3173
+ get: function() {
3174
+ return _fluid_app_portal_core_types.assertDefined;
3175
+ }
3176
+ });
3177
+ Object.defineProperty(exports, "assertNever", {
3178
+ enumerable: true,
3179
+ get: function() {
3180
+ return _fluid_app_portal_core_types.assertNever;
3181
+ }
3182
+ });
3183
+ Object.defineProperty(exports, "buildThemeDefinition", {
3184
+ enumerable: true,
3185
+ get: function() {
3186
+ return _fluid_app_portal_core_theme.buildThemeDefinition;
3187
+ }
3188
+ });
3189
+ Object.defineProperty(exports, "calendarWidgetPropertySchema", {
3190
+ enumerable: true,
3191
+ get: function() {
3192
+ return _fluid_app_portal_widgets_widgets.calendarWidgetPropertySchema;
3193
+ }
3194
+ });
3195
+ Object.defineProperty(exports, "carouselWidgetPropertySchema", {
3196
+ enumerable: true,
3197
+ get: function() {
3198
+ return _fluid_app_portal_widgets_widgets.carouselWidgetPropertySchema;
3199
+ }
3200
+ });
3201
+ Object.defineProperty(exports, "catchUpWidgetPropertySchema", {
3202
+ enumerable: true,
3203
+ get: function() {
3204
+ return _fluid_app_portal_widgets_widgets.catchUpWidgetPropertySchema;
3205
+ }
3206
+ });
3207
+ Object.defineProperty(exports, "chartWidgetPropertySchema", {
3208
+ enumerable: true,
3209
+ get: function() {
3210
+ return _fluid_app_portal_widgets_widgets.chartWidgetPropertySchema;
3211
+ }
3212
+ });
3213
+ Object.defineProperty(exports, "cleanTokenFromUrl", {
3214
+ enumerable: true,
3215
+ get: function() {
3216
+ return _fluid_app_auth.cleanTokenFromUrl;
3217
+ }
3218
+ });
3219
+ Object.defineProperty(exports, "clearTokens", {
3220
+ enumerable: true,
3221
+ get: function() {
3222
+ return _fluid_app_auth.clearTokens;
3223
+ }
3224
+ });
3225
+ exports.collectNavSlugs = collectNavSlugs;
3226
+ exports.contactsScreenPropertySchema = require_ContactsScreen.contactsScreenPropertySchema;
3227
+ Object.defineProperty(exports, "containerWidgetPropertySchema", {
3228
+ enumerable: true,
3229
+ get: function() {
3230
+ return _fluid_app_portal_widgets_widgets.containerWidgetPropertySchema;
3231
+ }
3232
+ });
3233
+ Object.defineProperty(exports, "createDefaultAuthRedirect", {
3234
+ enumerable: true,
3235
+ get: function() {
3236
+ return _fluid_app_auth.createDefaultAuthRedirect;
3237
+ }
3238
+ });
3239
+ exports.createFluidClient = require_MessagingScreen.createFluidClient;
3240
+ exports.createFluidFileUploader = require_MessagingScreen.createFluidFileUploader;
3241
+ Object.defineProperty(exports, "createScreen", {
3242
+ enumerable: true,
3243
+ get: function() {
3244
+ return _fluid_app_portal_core_widget_utils.createScreen;
3245
+ }
3246
+ });
3247
+ Object.defineProperty(exports, "createWidgetFromShareable", {
3248
+ enumerable: true,
3249
+ get: function() {
3250
+ return _fluid_app_portal_core_widget_utils.createWidgetFromShareable;
3251
+ }
3252
+ });
3253
+ Object.defineProperty(exports, "createWidgetRegistry", {
3254
+ enumerable: true,
3255
+ get: function() {
3256
+ return _fluid_app_portal_core_widget_utils.createWidgetRegistry;
3257
+ }
3258
+ });
3259
+ exports.customersScreenPropertySchema = require_CustomersScreen.customersScreenPropertySchema;
3260
+ Object.defineProperty(exports, "decodeToken", {
3261
+ enumerable: true,
3262
+ get: function() {
3263
+ return _fluid_app_auth.decodeToken;
3264
+ }
3265
+ });
3266
+ Object.defineProperty(exports, "deriveDarkVariant", {
3267
+ enumerable: true,
3268
+ get: function() {
3269
+ return themes_exports.deriveDarkVariant;
3270
+ }
3271
+ });
3272
+ Object.defineProperty(exports, "deserialiseTheme", {
3273
+ enumerable: true,
3274
+ get: function() {
3275
+ return themes_exports.deserialiseTheme;
3276
+ }
3277
+ });
3278
+ Object.defineProperty(exports, "embedWidgetPropertySchema", {
3279
+ enumerable: true,
3280
+ get: function() {
3281
+ return _fluid_app_portal_widgets_widgets.embedWidgetPropertySchema;
3282
+ }
3283
+ });
3284
+ Object.defineProperty(exports, "extractAllTokensFromUrl", {
3285
+ enumerable: true,
3286
+ get: function() {
3287
+ return _fluid_app_auth.extractAllTokensFromUrl;
3288
+ }
3289
+ });
3290
+ Object.defineProperty(exports, "extractCompanyTokenFromUrl", {
3291
+ enumerable: true,
3292
+ get: function() {
3293
+ return _fluid_app_auth.extractCompanyTokenFromUrl;
3294
+ }
3295
+ });
3296
+ exports.extractSlugFromPathname = extractSlugFromPathname;
3297
+ Object.defineProperty(exports, "extractTokenFromUrl", {
3298
+ enumerable: true,
3299
+ get: function() {
3300
+ return _fluid_app_auth.extractTokenFromUrl;
3301
+ }
3302
+ });
3303
+ Object.defineProperty(exports, "gapValues", {
3304
+ enumerable: true,
3305
+ get: function() {
3306
+ return _fluid_app_portal_core_registries.gapValues;
3307
+ }
3308
+ });
3309
+ Object.defineProperty(exports, "generateShades", {
3310
+ enumerable: true,
3311
+ get: function() {
3312
+ return themes_exports.generateShades;
3313
+ }
3314
+ });
3315
+ Object.defineProperty(exports, "generateThemeCSS", {
3316
+ enumerable: true,
3317
+ get: function() {
3318
+ return themes_exports.generateThemeCSS;
3319
+ }
3320
+ });
3321
+ Object.defineProperty(exports, "getActiveThemeId", {
3322
+ enumerable: true,
3323
+ get: function() {
3324
+ return _fluid_app_portal_core_theme.getActiveThemeId;
3325
+ }
3326
+ });
3327
+ exports.getAvailablePageTemplates = getAvailablePageTemplates;
3328
+ exports.getCorePageTemplates = getCorePageTemplates;
3329
+ Object.defineProperty(exports, "getDefaultThemeDefinition", {
3330
+ enumerable: true,
3331
+ get: function() {
3332
+ return themes_exports.getDefaultThemeDefinition;
3333
+ }
3334
+ });
3335
+ Object.defineProperty(exports, "getForegroundColor", {
3336
+ enumerable: true,
3337
+ get: function() {
3338
+ return themes_exports.getForegroundColor;
3339
+ }
3340
+ });
3341
+ exports.getOptionalPageTemplates = getOptionalPageTemplates;
3342
+ exports.getProperty = getProperty;
3343
+ Object.defineProperty(exports, "getStoredToken", {
3344
+ enumerable: true,
3345
+ get: function() {
3346
+ return _fluid_app_auth.getStoredToken;
3347
+ }
3348
+ });
3349
+ Object.defineProperty(exports, "getThemeModeAttribute", {
3350
+ enumerable: true,
3351
+ get: function() {
3352
+ return _fluid_app_portal_core_shell_ThemeModeContext.getThemeModeAttribute;
3353
+ }
3354
+ });
3355
+ Object.defineProperty(exports, "getTokenExpiration", {
3356
+ enumerable: true,
3357
+ get: function() {
3358
+ return _fluid_app_auth.getTokenExpiration;
3359
+ }
3360
+ });
3361
+ Object.defineProperty(exports, "getTokenTimeRemaining", {
3362
+ enumerable: true,
3363
+ get: function() {
3364
+ return _fluid_app_auth.getTokenTimeRemaining;
3365
+ }
3366
+ });
3367
+ Object.defineProperty(exports, "groupChildrenByColumn", {
3368
+ enumerable: true,
3369
+ get: function() {
3370
+ return _fluid_app_portal_core_widget_utils.groupChildrenByColumn;
3371
+ }
3372
+ });
3373
+ exports.hasData = hasData;
3374
+ Object.defineProperty(exports, "hasStoredToken", {
3375
+ enumerable: true,
3376
+ get: function() {
3377
+ return _fluid_app_auth.hasStoredToken;
3378
+ }
3379
+ });
3380
+ Object.defineProperty(exports, "hasTokenInUrl", {
3381
+ enumerable: true,
3382
+ get: function() {
3383
+ return _fluid_app_auth.hasTokenInUrl;
3384
+ }
3385
+ });
3386
+ Object.defineProperty(exports, "imageWidgetPropertySchema", {
3387
+ enumerable: true,
3388
+ get: function() {
3389
+ return _fluid_app_portal_widgets_widgets.imageWidgetPropertySchema;
3390
+ }
3391
+ });
3392
+ exports.isActivitySlug = isActivitySlug;
3393
+ exports.isApiError = require_MessagingScreen.isApiError;
3394
+ exports.isContactStatus = isContactStatus;
3395
+ exports.isErrorResult = isErrorResult;
3396
+ exports.isIdle = isIdle;
3397
+ exports.isLoading = isLoading;
3398
+ Object.defineProperty(exports, "isPropertyFieldType", {
3399
+ enumerable: true,
3400
+ get: function() {
3401
+ return _fluid_app_portal_core_registries.isPropertyFieldType;
3402
+ }
3403
+ });
3404
+ exports.isSlugInSection = isSlugInSection;
3405
+ Object.defineProperty(exports, "isTokenExpired", {
3406
+ enumerable: true,
3407
+ get: function() {
3408
+ return _fluid_app_auth.isTokenExpired;
3409
+ }
3410
+ });
3411
+ Object.defineProperty(exports, "isUserType", {
3412
+ enumerable: true,
3413
+ get: function() {
3414
+ return _fluid_app_auth.isUserType;
3415
+ }
3416
+ });
3417
+ Object.defineProperty(exports, "isValidToken", {
3418
+ enumerable: true,
3419
+ get: function() {
3420
+ return _fluid_app_auth.isValidToken;
3421
+ }
3422
+ });
3423
+ Object.defineProperty(exports, "isWidgetType", {
3424
+ enumerable: true,
3425
+ get: function() {
3426
+ return _fluid_app_portal_core_types.isWidgetType;
3427
+ }
3428
+ });
3429
+ Object.defineProperty(exports, "isWidgetTypeName", {
3430
+ enumerable: true,
3431
+ get: function() {
3432
+ return _fluid_app_portal_core_types.isWidgetTypeName;
3433
+ }
3434
+ });
3435
+ Object.defineProperty(exports, "layoutWidgetPropertySchema", {
3436
+ enumerable: true,
3437
+ get: function() {
3438
+ return _fluid_app_portal_widgets_widgets.layoutWidgetPropertySchema;
3439
+ }
3440
+ });
3441
+ Object.defineProperty(exports, "listWidgetPropertySchema", {
3442
+ enumerable: true,
3443
+ get: function() {
3444
+ return _fluid_app_portal_widgets_widgets.listWidgetPropertySchema;
3445
+ }
3446
+ });
3447
+ exports.matchSlugPrefix = matchSlugPrefix;
3448
+ Object.defineProperty(exports, "mergeDarkOverrides", {
3449
+ enumerable: true,
3450
+ get: function() {
3451
+ return themes_exports.mergeDarkOverrides;
3452
+ }
3453
+ });
3454
+ exports.messagingScreenPropertySchema = require_MessagingScreen.messagingScreenPropertySchema;
3455
+ Object.defineProperty(exports, "mySiteWidgetPropertySchema", {
3456
+ enumerable: true,
3457
+ get: function() {
3458
+ return _fluid_app_portal_widgets_widgets.mySiteWidgetPropertySchema;
3459
+ }
3460
+ });
3461
+ Object.defineProperty(exports, "nestedWidgetPropertySchema", {
3462
+ enumerable: true,
3463
+ get: function() {
3464
+ return _fluid_app_portal_widgets_widgets.nestedWidgetPropertySchema;
3465
+ }
3466
+ });
3467
+ exports.normalizeComponentTree = require_MessagingScreen.normalizeComponentTree;
3468
+ exports.ordersScreenPropertySchema = require_OrdersScreen.ordersScreenPropertySchema;
3469
+ Object.defineProperty(exports, "parseColor", {
3470
+ enumerable: true,
3471
+ get: function() {
3472
+ return themes_exports.parseColor;
3473
+ }
3474
+ });
3475
+ exports.productsScreenPropertySchema = require_ProductsScreen.productsScreenPropertySchema;
3476
+ Object.defineProperty(exports, "quickShareWidgetPropertySchema", {
3477
+ enumerable: true,
3478
+ get: function() {
3479
+ return _fluid_app_portal_widgets_widgets.quickShareWidgetPropertySchema;
3480
+ }
3481
+ });
3482
+ Object.defineProperty(exports, "recentActivityWidgetPropertySchema", {
3483
+ enumerable: true,
3484
+ get: function() {
3485
+ return _fluid_app_portal_widgets_widgets.recentActivityWidgetPropertySchema;
3486
+ }
3487
+ });
3488
+ Object.defineProperty(exports, "removeAllThemes", {
3489
+ enumerable: true,
3490
+ get: function() {
3491
+ return themes_exports.removeAllThemes;
3492
+ }
3493
+ });
3494
+ Object.defineProperty(exports, "removeTheme", {
3495
+ enumerable: true,
3496
+ get: function() {
3497
+ return themes_exports.removeTheme;
3498
+ }
3499
+ });
3500
+ exports.resolveNavigationPages = resolveNavigationPages;
3501
+ Object.defineProperty(exports, "resolveTheme", {
3502
+ enumerable: true,
3503
+ get: function() {
3504
+ return themes_exports.resolveTheme;
3505
+ }
3506
+ });
3507
+ exports.screenPropertySchemas = screenPropertySchemas;
3508
+ Object.defineProperty(exports, "sectionLayoutConfig", {
3509
+ enumerable: true,
3510
+ get: function() {
3511
+ return _fluid_app_portal_core_types.sectionLayoutConfig;
3512
+ }
3513
+ });
3514
+ exports.selectProperty = selectProperty;
3515
+ Object.defineProperty(exports, "serialiseTheme", {
3516
+ enumerable: true,
3517
+ get: function() {
3518
+ return themes_exports.serialiseTheme;
3519
+ }
3520
+ });
3521
+ Object.defineProperty(exports, "spacerWidgetPropertySchema", {
3522
+ enumerable: true,
3523
+ get: function() {
3524
+ return _fluid_app_portal_widgets_widgets.spacerWidgetPropertySchema;
3525
+ }
3526
+ });
3527
+ Object.defineProperty(exports, "storeToken", {
3528
+ enumerable: true,
3529
+ get: function() {
3530
+ return _fluid_app_auth.storeToken;
3531
+ }
3532
+ });
3533
+ Object.defineProperty(exports, "tableWidgetPropertySchema", {
3534
+ enumerable: true,
3535
+ get: function() {
3536
+ return _fluid_app_portal_widgets_widgets.tableWidgetPropertySchema;
3537
+ }
3538
+ });
3539
+ Object.defineProperty(exports, "textWidgetPropertySchema", {
3540
+ enumerable: true,
3541
+ get: function() {
3542
+ return _fluid_app_portal_widgets_widgets.textWidgetPropertySchema;
3543
+ }
3544
+ });
3545
+ Object.defineProperty(exports, "toDoWidgetPropertySchema", {
3546
+ enumerable: true,
3547
+ get: function() {
3548
+ return _fluid_app_portal_widgets_widgets.toDoWidgetPropertySchema;
3549
+ }
3550
+ });
3551
+ exports.toNavigationItem = require_MessagingScreen.toNavigationItem;
3552
+ exports.toScreenDefinition = require_MessagingScreen.toScreenDefinition;
3553
+ exports.transformManifestToRepAppData = require_MessagingScreen.transformManifestToRepAppData;
3554
+ Object.defineProperty(exports, "transformThemes", {
3555
+ enumerable: true,
3556
+ get: function() {
3557
+ return _fluid_app_portal_core_theme.transformThemes;
3558
+ }
3559
+ });
3560
+ exports.useActivities = useActivities;
3561
+ exports.useAppNavigation = useAppNavigation;
3562
+ exports.useCalendarEvents = useCalendarEvents;
3563
+ exports.useCatchUps = useCatchUps;
3564
+ exports.useContact = useContact;
3565
+ exports.useContacts = useContacts;
3566
+ exports.useConversationMessages = useConversationMessages;
3567
+ exports.useConversations = useConversations;
3568
+ exports.useCurrentRep = useCurrentRep;
3569
+ exports.useFluidApi = require_MessagingScreen.useFluidApi;
3570
+ exports.useFluidApp = useFluidApp;
3571
+ exports.useFluidAuth = useFluidAuth;
3572
+ exports.useFluidAuthContext = require_MessagingScreen.useFluidAuthContext;
3573
+ exports.useFluidContext = require_MessagingScreen.useFluidContext;
3574
+ exports.useFluidPermissions = useFluidPermissions;
3575
+ exports.useFluidProfile = useFluidProfile;
3576
+ exports.useFluidTheme = useFluidTheme;
3577
+ exports.useMessagingAuth = require_MessagingScreen.useMessagingAuth;
3578
+ exports.useMessagingConfig = require_MessagingScreen.useMessagingConfig;
3579
+ exports.useMySite = useMySite;
3580
+ exports.usePageTemplates = usePageTemplates;
3581
+ exports.useResolvedPages = useResolvedPages;
3582
+ exports.useThemeContext = require_MessagingScreen.useThemeContext;
3583
+ Object.defineProperty(exports, "useThemeMode", {
3584
+ enumerable: true,
3585
+ get: function() {
3586
+ return _fluid_app_portal_core_shell_ThemeModeContext.useThemeMode;
3587
+ }
3588
+ });
3589
+ exports.useTodos = useTodos;
3590
+ exports.validateNavigationPages = validateNavigationPages;
3591
+ Object.defineProperty(exports, "validateToken", {
3592
+ enumerable: true,
3593
+ get: function() {
3594
+ return _fluid_app_auth.validateToken;
3595
+ }
3596
+ });
3597
+ Object.defineProperty(exports, "videoWidgetPropertySchema", {
3598
+ enumerable: true,
3599
+ get: function() {
3600
+ return _fluid_app_portal_widgets_widgets.videoWidgetPropertySchema;
3601
+ }
3602
+ });
3603
+ Object.defineProperty(exports, "widgetPropertySchemas", {
3604
+ enumerable: true,
3605
+ get: function() {
3606
+ return _fluid_app_portal_widgets_widgets.widgetPropertySchemas;
3607
+ }
3608
+ });
3609
+
3610
+ //# sourceMappingURL=index.cjs.map