@voyant-travel/admin 0.111.0

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 (115) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +285 -0
  3. package/dist/app/extension-routes.d.ts +99 -0
  4. package/dist/app/extension-routes.d.ts.map +1 -0
  5. package/dist/app/extension-routes.js +134 -0
  6. package/dist/app/index.d.ts +9 -0
  7. package/dist/app/index.d.ts.map +1 -0
  8. package/dist/app/index.js +4 -0
  9. package/dist/app/root.d.ts +47 -0
  10. package/dist/app/root.d.ts.map +1 -0
  11. package/dist/app/root.js +55 -0
  12. package/dist/app/router.d.ts +30 -0
  13. package/dist/app/router.d.ts.map +1 -0
  14. package/dist/app/router.js +51 -0
  15. package/dist/app/workspace.d.ts +84 -0
  16. package/dist/app/workspace.d.ts.map +1 -0
  17. package/dist/app/workspace.js +87 -0
  18. package/dist/components/admin-breadcrumbs.d.ts +18 -0
  19. package/dist/components/admin-breadcrumbs.d.ts.map +1 -0
  20. package/dist/components/admin-breadcrumbs.js +84 -0
  21. package/dist/components/admin-nav-group.d.ts +11 -0
  22. package/dist/components/admin-nav-group.d.ts.map +1 -0
  23. package/dist/components/admin-nav-group.js +49 -0
  24. package/dist/components/admin-nav-link.d.ts +10 -0
  25. package/dist/components/admin-nav-link.d.ts.map +1 -0
  26. package/dist/components/admin-nav-link.js +5 -0
  27. package/dist/components/admin-page-head.d.ts +17 -0
  28. package/dist/components/admin-page-head.d.ts.map +1 -0
  29. package/dist/components/admin-page-head.js +107 -0
  30. package/dist/components/admin-widget-slot.d.ts +8 -0
  31. package/dist/components/admin-widget-slot.d.ts.map +1 -0
  32. package/dist/components/admin-widget-slot.js +19 -0
  33. package/dist/components/brand/voyant-mark.d.ts +3 -0
  34. package/dist/components/brand/voyant-mark.d.ts.map +1 -0
  35. package/dist/components/brand/voyant-mark.js +4 -0
  36. package/dist/components/brand/voyant-wordmark.d.ts +3 -0
  37. package/dist/components/brand/voyant-wordmark.d.ts.map +1 -0
  38. package/dist/components/brand/voyant-wordmark.js +4 -0
  39. package/dist/components/operator-admin-bootstrap-gate.d.ts +26 -0
  40. package/dist/components/operator-admin-bootstrap-gate.d.ts.map +1 -0
  41. package/dist/components/operator-admin-bootstrap-gate.js +22 -0
  42. package/dist/components/operator-admin-page-shell.d.ts +13 -0
  43. package/dist/components/operator-admin-page-shell.d.ts.map +1 -0
  44. package/dist/components/operator-admin-page-shell.js +6 -0
  45. package/dist/components/operator-admin-sidebar.d.ts +57 -0
  46. package/dist/components/operator-admin-sidebar.d.ts.map +1 -0
  47. package/dist/components/operator-admin-sidebar.js +104 -0
  48. package/dist/components/operator-admin-user-menu.d.ts +10 -0
  49. package/dist/components/operator-admin-user-menu.d.ts.map +1 -0
  50. package/dist/components/operator-admin-user-menu.js +19 -0
  51. package/dist/components/team-settings-page.d.ts +10 -0
  52. package/dist/components/team-settings-page.d.ts.map +1 -0
  53. package/dist/components/team-settings-page.js +149 -0
  54. package/dist/dashboard/dashboard-empty-states.d.ts +67 -0
  55. package/dist/dashboard/dashboard-empty-states.d.ts.map +1 -0
  56. package/dist/dashboard/dashboard-empty-states.js +65 -0
  57. package/dist/dashboard/dashboard-kpi-card.d.ts +13 -0
  58. package/dist/dashboard/dashboard-kpi-card.d.ts.map +1 -0
  59. package/dist/dashboard/dashboard-kpi-card.js +12 -0
  60. package/dist/dashboard/dashboard-page.d.ts +7 -0
  61. package/dist/dashboard/dashboard-page.d.ts.map +1 -0
  62. package/dist/dashboard/dashboard-page.js +150 -0
  63. package/dist/dashboard/dashboard-query-options.d.ts +224 -0
  64. package/dist/dashboard/dashboard-query-options.d.ts.map +1 -0
  65. package/dist/dashboard/dashboard-query-options.js +153 -0
  66. package/dist/dashboard/dashboard-skeleton.d.ts +13 -0
  67. package/dist/dashboard/dashboard-skeleton.d.ts.map +1 -0
  68. package/dist/dashboard/dashboard-skeleton.js +28 -0
  69. package/dist/extensions.d.ts +254 -0
  70. package/dist/extensions.d.ts.map +1 -0
  71. package/dist/extensions.js +139 -0
  72. package/dist/index.d.ts +51 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +53 -0
  75. package/dist/lib/i18n.d.ts +2 -0
  76. package/dist/lib/i18n.d.ts.map +1 -0
  77. package/dist/lib/i18n.js +1 -0
  78. package/dist/lib/initials.d.ts +24 -0
  79. package/dist/lib/initials.d.ts.map +1 -0
  80. package/dist/lib/initials.js +45 -0
  81. package/dist/navigation/destinations.d.ts +83 -0
  82. package/dist/navigation/destinations.d.ts.map +1 -0
  83. package/dist/navigation/destinations.js +65 -0
  84. package/dist/navigation/operator-navigation.d.ts +10 -0
  85. package/dist/navigation/operator-navigation.d.ts.map +1 -0
  86. package/dist/navigation/operator-navigation.js +191 -0
  87. package/dist/providers/admin-extensions.d.ts +9 -0
  88. package/dist/providers/admin-extensions.d.ts.map +1 -0
  89. package/dist/providers/admin-extensions.js +10 -0
  90. package/dist/providers/admin-provider.d.ts +53 -0
  91. package/dist/providers/admin-provider.d.ts.map +1 -0
  92. package/dist/providers/admin-provider.js +26 -0
  93. package/dist/providers/locale-preferences.d.ts +12 -0
  94. package/dist/providers/locale-preferences.d.ts.map +1 -0
  95. package/dist/providers/locale-preferences.js +32 -0
  96. package/dist/providers/locale.d.ts +23 -0
  97. package/dist/providers/locale.d.ts.map +1 -0
  98. package/dist/providers/locale.js +98 -0
  99. package/dist/providers/operator-admin-messages.d.ts +14 -0
  100. package/dist/providers/operator-admin-messages.d.ts.map +1 -0
  101. package/dist/providers/operator-admin-messages.js +16 -0
  102. package/dist/providers/operator-admin-shell.d.ts +35 -0
  103. package/dist/providers/operator-admin-shell.d.ts.map +1 -0
  104. package/dist/providers/operator-admin-shell.js +20 -0
  105. package/dist/providers/query-client.d.ts +19 -0
  106. package/dist/providers/query-client.d.ts.map +1 -0
  107. package/dist/providers/query-client.js +34 -0
  108. package/dist/providers/theme.d.ts +29 -0
  109. package/dist/providers/theme.d.ts.map +1 -0
  110. package/dist/providers/theme.js +63 -0
  111. package/dist/types.d.ts +60 -0
  112. package/dist/types.d.ts.map +1 -0
  113. package/dist/types.js +2 -0
  114. package/package.json +222 -0
  115. package/src/styles.css +11 -0
@@ -0,0 +1,83 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Semantic admin navigation destinations (packaged-admin RFC §4.7).
4
+ *
5
+ * Package-owned admin pages cannot import a host's typed route tree, so they
6
+ * never navigate by route path. Instead they navigate to a semantic
7
+ * destination KEY; the host registers a key → href resolver map once.
8
+ *
9
+ * This interface ships empty. Domain packages declare the destinations their
10
+ * pages need via TypeScript declaration merging (the same `Register` trick
11
+ * TanStack Router uses):
12
+ *
13
+ * ```ts
14
+ * // inside @voyant-travel/catalog-react
15
+ * declare module "@voyant-travel/admin" {
16
+ * interface AdminDestinations {
17
+ * "supplier.detail": { supplierId: string }
18
+ * }
19
+ * }
20
+ * ```
21
+ *
22
+ * Naming convention: `<entity>.<action>` (e.g. `"product.detail"`,
23
+ * `"bookingJourney.start"`). The host then provides a resolver per declared
24
+ * key — `satisfies AdminDestinationResolvers` makes the map exhaustive.
25
+ */
26
+ export interface AdminDestinations {
27
+ }
28
+ /** Union of all declared destination keys (empty until packages augment). */
29
+ export type AdminDestinationKey = keyof AdminDestinations & string;
30
+ /**
31
+ * The host's resolver map: one `params → href` function per declared
32
+ * destination key. Mapped over {@link AdminDestinations}, so `satisfies
33
+ * AdminDestinationResolvers` fails to compile when a declared key is missing
34
+ * a resolver — exhaustiveness is the host's proof of contract.
35
+ */
36
+ export type AdminDestinationResolvers = {
37
+ [K in AdminDestinationKey]: (params: AdminDestinations[K]) => string;
38
+ };
39
+ /** Resolve a destination key + params to an href. Returned by {@link useAdminHref}. */
40
+ export type AdminHrefResolver = <K extends AdminDestinationKey>(key: K, params: AdminDestinations[K]) => string;
41
+ /**
42
+ * History options for a destination navigation. Packaged pages that REDIRECT
43
+ * (an alias route forwarding to its canonical page, a deep link that resolves
44
+ * straight into another flow) pass `replace: true` so the intermediate URL
45
+ * never lands in history — the same semantics a route-level redirect has.
46
+ */
47
+ export interface AdminNavigateOptions {
48
+ /** Replace the current history entry instead of pushing a new one. */
49
+ replace?: boolean;
50
+ }
51
+ /** Navigate to a destination key + params. Returned by {@link useAdminNavigate}. */
52
+ export type AdminDestinationNavigator = <K extends AdminDestinationKey>(key: K, params: AdminDestinations[K], options?: AdminNavigateOptions) => void;
53
+ export interface AdminNavigationProviderProps {
54
+ /** Host resolver map covering every destination key the mounted packages declare. */
55
+ resolvers: AdminDestinationResolvers;
56
+ /**
57
+ * Host-injected navigation primitive — typically the app router's
58
+ * href-based navigate. Keeping it injected keeps this package
59
+ * router-agnostic. Hosts should honor `options.replace` (map it onto the
60
+ * router's history-replace mode) so packaged redirects behave like route
61
+ * redirects; ignoring it only costs an extra history entry.
62
+ */
63
+ navigate: (href: string, options?: AdminNavigateOptions) => void;
64
+ children: React.ReactNode;
65
+ }
66
+ /**
67
+ * Provides destination resolution + navigation to packaged admin pages.
68
+ * Hosts mount it once around the workspace (e.g. via `AdminWorkspaceShell`'s
69
+ * `destinations` prop in `@voyant-travel/admin/app/workspace`).
70
+ */
71
+ export declare function AdminNavigationProvider({ resolvers, navigate, children, }: AdminNavigationProviderProps): import("react/jsx-runtime").JSX.Element;
72
+ /**
73
+ * Resolve destination keys to hrefs (for `<a href>` / link props). When a key
74
+ * cannot be resolved, warns once per key and returns `"#"` — render paths
75
+ * never throw over a missing link target.
76
+ */
77
+ export declare function useAdminHref(): AdminHrefResolver;
78
+ /**
79
+ * Navigate to a destination: resolve the href, then call the host-injected
80
+ * `navigate`. When the key cannot be resolved, warns once per key and no-ops.
81
+ */
82
+ export declare function useAdminNavigate(): AdminDestinationNavigator;
83
+ //# sourceMappingURL=destinations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destinations.d.ts","sourceRoot":"","sources":["../../src/navigation/destinations.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,iBAAiB;CAAG;AAErC,6EAA6E;AAC7E,MAAM,MAAM,mBAAmB,GAAG,MAAM,iBAAiB,GAAG,MAAM,CAAA;AAElE;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAAG;KACrC,CAAC,IAAI,mBAAmB,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,MAAM;CACrE,CAAA;AAED,uFAAuF;AACvF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,SAAS,mBAAmB,EAC5D,GAAG,EAAE,CAAC,EACN,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,KACzB,MAAM,CAAA;AAEX;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,oFAAoF;AACpF,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,SAAS,mBAAmB,EACpE,GAAG,EAAE,CAAC,EACN,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC5B,OAAO,CAAC,EAAE,oBAAoB,KAC3B,IAAI,CAAA;AAST,MAAM,WAAW,4BAA4B;IAC3C,qFAAqF;IACrF,SAAS,EAAE,yBAAyB,CAAA;IACpC;;;;;;OAMG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAChE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,SAAS,EACT,QAAQ,EACR,QAAQ,GACT,EAAE,4BAA4B,2CAI9B;AAoDD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,iBAAiB,CAOhD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,yBAAyB,CAW5D"}
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ const AdminNavigationContext = React.createContext(null);
4
+ /**
5
+ * Provides destination resolution + navigation to packaged admin pages.
6
+ * Hosts mount it once around the workspace (e.g. via `AdminWorkspaceShell`'s
7
+ * `destinations` prop in `@voyant-travel/admin/app/workspace`).
8
+ */
9
+ export function AdminNavigationProvider({ resolvers, navigate, children, }) {
10
+ const value = React.useMemo(() => ({ resolvers, navigate }), [resolvers, navigate]);
11
+ return _jsx(AdminNavigationContext.Provider, { value: value, children: children });
12
+ }
13
+ /** Keys already warned about — unresolvable destinations warn once, not per render. */
14
+ const warnedDestinationKeys = new Set();
15
+ function warnOnce(key, message, ...rest) {
16
+ if (warnedDestinationKeys.has(key))
17
+ return;
18
+ warnedDestinationKeys.add(key);
19
+ console.warn(message, ...rest);
20
+ }
21
+ /**
22
+ * Resolve a destination to an href, or `null` when unresolvable (no provider,
23
+ * no resolver for the key, or a throwing resolver). Never throws — these run
24
+ * in render paths, and a broken link must not take the page down with it.
25
+ */
26
+ function resolveDestinationHref(context, key, params) {
27
+ if (!context) {
28
+ warnOnce(key, `[voyant-admin] Destination "${key}" was resolved outside an <AdminNavigationProvider>; falling back to "#".`);
29
+ return null;
30
+ }
31
+ const resolver = context.resolvers[key];
32
+ if (!resolver) {
33
+ warnOnce(key, `[voyant-admin] No resolver registered for destination "${key}"; falling back to "#". Add it to the host's AdminNavigationProvider resolvers.`);
34
+ return null;
35
+ }
36
+ try {
37
+ return resolver(params);
38
+ }
39
+ catch (error) {
40
+ warnOnce(key, `[voyant-admin] Resolver for destination "${key}" threw; falling back to "#".`, error);
41
+ return null;
42
+ }
43
+ }
44
+ /**
45
+ * Resolve destination keys to hrefs (for `<a href>` / link props). When a key
46
+ * cannot be resolved, warns once per key and returns `"#"` — render paths
47
+ * never throw over a missing link target.
48
+ */
49
+ export function useAdminHref() {
50
+ const context = React.useContext(AdminNavigationContext);
51
+ return React.useCallback((key, params) => resolveDestinationHref(context, key, params) ?? "#", [context]);
52
+ }
53
+ /**
54
+ * Navigate to a destination: resolve the href, then call the host-injected
55
+ * `navigate`. When the key cannot be resolved, warns once per key and no-ops.
56
+ */
57
+ export function useAdminNavigate() {
58
+ const context = React.useContext(AdminNavigationContext);
59
+ return React.useCallback((key, params, options) => {
60
+ const href = resolveDestinationHref(context, key, params);
61
+ if (href === null || context === null)
62
+ return;
63
+ context.navigate(href, options);
64
+ }, [context]);
65
+ }
@@ -0,0 +1,10 @@
1
+ import type { OperatorAdminMessages } from "../providers/operator-admin-messages.js";
2
+ import type { NavItem } from "../types.js";
3
+ export type OperatorAdminNavigationIconName = "availability" | "bookings" | "catalog" | "channelSync" | "dashboard" | "finance" | "flights" | "legal" | "notifications" | "organizations" | "people" | "products" | "resources" | "settings" | "suppliers";
4
+ export type OperatorAdminNavigationIcons = Partial<Record<OperatorAdminNavigationIconName, NavItem["icon"]>>;
5
+ export interface CreateOperatorAdminNavigationOptions {
6
+ messages: OperatorAdminMessages["nav"];
7
+ icons?: OperatorAdminNavigationIcons;
8
+ }
9
+ export declare function createOperatorAdminNavigation({ icons, messages, }: CreateOperatorAdminNavigationOptions): NavItem[];
10
+ //# sourceMappingURL=operator-navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator-navigation.d.ts","sourceRoot":"","sources":["../../src/navigation/operator-navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAA;AACpF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAE1C,MAAM,MAAM,+BAA+B,GACvC,cAAc,GACd,UAAU,GACV,SAAS,GACT,aAAa,GACb,WAAW,GACX,SAAS,GACT,SAAS,GACT,OAAO,GACP,eAAe,GACf,eAAe,GACf,QAAQ,GACR,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,CAAA;AAEf,MAAM,MAAM,4BAA4B,GAAG,OAAO,CAChD,MAAM,CAAC,+BAA+B,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CACzD,CAAA;AAED,MAAM,WAAW,oCAAoC;IACnD,QAAQ,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAA;IACtC,KAAK,CAAC,EAAE,4BAA4B,CAAA;CACrC;AAED,wBAAgB,6BAA6B,CAAC,EAC5C,KAAU,EACV,QAAQ,GACT,EAAE,oCAAoC,GAAG,OAAO,EAAE,CA8LlD"}
@@ -0,0 +1,191 @@
1
+ export function createOperatorAdminNavigation({ icons = {}, messages, }) {
2
+ return [
3
+ {
4
+ id: "dashboard",
5
+ title: messages.dashboard,
6
+ url: "/",
7
+ icon: icons.dashboard,
8
+ },
9
+ {
10
+ id: "catalog",
11
+ title: messages.catalog,
12
+ url: "/catalog/products",
13
+ icon: icons.catalog,
14
+ items: [
15
+ {
16
+ id: "catalog-products",
17
+ title: messages.catalogProducts,
18
+ url: "/catalog/products",
19
+ },
20
+ {
21
+ id: "catalog-excursions",
22
+ title: messages.catalogExcursions,
23
+ url: "/catalog/excursions",
24
+ },
25
+ {
26
+ id: "catalog-tours",
27
+ title: messages.catalogTours,
28
+ url: "/catalog/tours",
29
+ },
30
+ {
31
+ id: "catalog-cruises",
32
+ title: messages.catalogCruises,
33
+ url: "/catalog/cruises",
34
+ },
35
+ {
36
+ id: "catalog-accommodations",
37
+ title: messages.catalogAccommodations,
38
+ url: "/catalog/accommodations",
39
+ },
40
+ ],
41
+ },
42
+ {
43
+ id: "flights",
44
+ title: messages.flights,
45
+ url: "/flights",
46
+ icon: icons.flights,
47
+ },
48
+ {
49
+ id: "products",
50
+ title: messages.products,
51
+ url: "/products",
52
+ icon: icons.products,
53
+ items: [
54
+ {
55
+ id: "product-categories",
56
+ title: messages.categories,
57
+ url: "/products/categories",
58
+ },
59
+ ],
60
+ },
61
+ {
62
+ id: "availability",
63
+ title: messages.availability,
64
+ url: "/operations/availability",
65
+ icon: icons.availability,
66
+ },
67
+ {
68
+ id: "bookings",
69
+ title: messages.bookings,
70
+ url: "/bookings",
71
+ icon: icons.bookings,
72
+ },
73
+ {
74
+ id: "notifications",
75
+ title: messages.notifications,
76
+ url: "/notifications/templates",
77
+ icon: icons.notifications,
78
+ items: [
79
+ {
80
+ id: "notification-templates",
81
+ title: messages.notificationTemplates,
82
+ url: "/notifications/templates",
83
+ },
84
+ {
85
+ id: "notification-reminder-rules",
86
+ title: messages.notificationReminderRules,
87
+ url: "/notifications/reminder-rules",
88
+ },
89
+ {
90
+ id: "notification-deliveries",
91
+ title: messages.notificationDeliveries,
92
+ url: "/notifications/deliveries",
93
+ },
94
+ {
95
+ id: "notification-reminder-runs",
96
+ title: messages.notificationReminderRuns,
97
+ url: "/notifications/reminder-runs",
98
+ },
99
+ {
100
+ id: "notification-preview",
101
+ title: messages.notificationPreview,
102
+ url: "/notifications/preview",
103
+ },
104
+ {
105
+ id: "notification-settings",
106
+ title: messages.notificationSettings,
107
+ url: "/notifications/settings",
108
+ },
109
+ ],
110
+ },
111
+ {
112
+ id: "suppliers",
113
+ title: messages.suppliers,
114
+ url: "/suppliers",
115
+ icon: icons.suppliers,
116
+ },
117
+ {
118
+ id: "people",
119
+ title: messages.people,
120
+ url: "/people",
121
+ icon: icons.people,
122
+ },
123
+ {
124
+ id: "organizations",
125
+ title: messages.organizations,
126
+ url: "/organizations",
127
+ icon: icons.organizations,
128
+ },
129
+ {
130
+ id: "resources",
131
+ title: messages.resources,
132
+ url: "/operations/resources",
133
+ icon: icons.resources,
134
+ },
135
+ {
136
+ id: "finance",
137
+ title: messages.finance,
138
+ url: "/finance/invoices",
139
+ icon: icons.finance,
140
+ items: [
141
+ { id: "invoices", title: messages.invoices, url: "/finance/invoices" },
142
+ {
143
+ id: "invoice-number-series",
144
+ title: messages.invoiceNumberSeries,
145
+ url: "/finance/invoice-number-series",
146
+ },
147
+ { id: "payments", title: messages.payments, url: "/finance/payments" },
148
+ {
149
+ id: "supplier-invoices",
150
+ title: messages.supplierInvoices,
151
+ url: "/finance/supplier-invoices",
152
+ },
153
+ {
154
+ id: "profitability",
155
+ title: messages.profitability,
156
+ url: "/finance/profitability",
157
+ },
158
+ ],
159
+ },
160
+ {
161
+ id: "legal",
162
+ title: messages.legal,
163
+ url: "/legal/contracts",
164
+ icon: icons.legal,
165
+ items: [
166
+ { id: "contracts", title: messages.contracts, url: "/legal/contracts" },
167
+ {
168
+ id: "contract-templates",
169
+ title: messages.contractTemplates,
170
+ url: "/legal/templates",
171
+ },
172
+ {
173
+ id: "policies",
174
+ title: messages.policies,
175
+ url: "/legal/policies",
176
+ },
177
+ {
178
+ id: "number-series",
179
+ title: messages.contractNumberSeries,
180
+ url: "/legal/number-series",
181
+ },
182
+ ],
183
+ },
184
+ {
185
+ id: "channel-sync",
186
+ title: messages.channelSync,
187
+ url: "/channel-sync",
188
+ icon: icons.channelSync,
189
+ },
190
+ ];
191
+ }
@@ -0,0 +1,9 @@
1
+ import { type ReactNode } from "react";
2
+ import type { AdminExtension } from "../extensions.js";
3
+ export interface AdminExtensionsProviderProps {
4
+ children: ReactNode;
5
+ extensions?: ReadonlyArray<AdminExtension>;
6
+ }
7
+ export declare function AdminExtensionsProvider({ children, extensions, }: AdminExtensionsProviderProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function useAdminExtensions(): ReadonlyArray<AdminExtension>;
9
+ //# sourceMappingURL=admin-extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-extensions.d.ts","sourceRoot":"","sources":["../../src/providers/admin-extensions.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,SAAS,EAAc,MAAM,OAAO,CAAA;AAEjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAItD,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,SAAS,CAAA;IACnB,UAAU,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAA;CAC3C;AAED,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,UAAe,GAChB,EAAE,4BAA4B,2CAI9B;AAED,wBAAgB,kBAAkB,IAAI,aAAa,CAAC,cAAc,CAAC,CAElE"}
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext } from "react";
4
+ const AdminExtensionsContext = createContext([]);
5
+ export function AdminExtensionsProvider({ children, extensions = [], }) {
6
+ return (_jsx(AdminExtensionsContext.Provider, { value: extensions, children: children }));
7
+ }
8
+ export function useAdminExtensions() {
9
+ return useContext(AdminExtensionsContext);
10
+ }
@@ -0,0 +1,53 @@
1
+ import { type QueryClient } from "@tanstack/react-query";
2
+ import { type ReactNode } from "react";
3
+ import type { ThemeMode } from "../types.js";
4
+ export interface AdminProviderProps {
5
+ children: ReactNode;
6
+ /**
7
+ * Pre-built QueryClient. If not provided, one is created per render-tree
8
+ * via `makeQueryClient()`. Pass your own for server-rendering setups where
9
+ * the client should be created outside React.
10
+ */
11
+ queryClient?: QueryClient;
12
+ /** Initial theme. Defaults to "system". */
13
+ defaultTheme?: ThemeMode;
14
+ /**
15
+ * localStorage key for theme persistence. Pass `null` to disable.
16
+ * Defaults to `"theme"`.
17
+ */
18
+ themeStorageKey?: string | null;
19
+ /** Initial locale. Defaults to browser locale with `en` fallback. */
20
+ defaultLocale?: string;
21
+ /** Initial timezone. Defaults to browser timezone. */
22
+ defaultTimeZone?: string | null;
23
+ /**
24
+ * localStorage key for locale persistence. Pass `null` to disable.
25
+ * Defaults to `"admin-locale"`.
26
+ */
27
+ localeStorageKey?: string | null;
28
+ /**
29
+ * localStorage key for timezone persistence. Pass `null` to disable.
30
+ * Defaults to `"admin-timezone"`.
31
+ */
32
+ timeZoneStorageKey?: string | null;
33
+ /** Supported admin locales. Defaults to `["en", "ro"]`. */
34
+ supportedLocales?: readonly string[];
35
+ /** Fallback locale when no supported locale is resolved. Defaults to `"en"`. */
36
+ fallbackLocale?: string;
37
+ }
38
+ /**
39
+ * Composes the shared admin providers — QueryClient, Theme, and Locale — so
40
+ * starters don't have to wire each one individually. Note: this does NOT include
41
+ * `<VoyantReactProvider>` (from `@voyant-travel/react`) because its API base
42
+ * URL is starter-specific. Wrap AdminProvider's children with your
43
+ * VoyantReactProvider at the same level.
44
+ *
45
+ * @example
46
+ * <AdminProvider>
47
+ * <VoyantReactProvider baseUrl="/api">
48
+ * <App />
49
+ * </VoyantReactProvider>
50
+ * </AdminProvider>
51
+ */
52
+ export declare function AdminProvider({ children, queryClient, defaultTheme, themeStorageKey, defaultLocale, defaultTimeZone, localeStorageKey, timeZoneStorageKey, supportedLocales, fallbackLocale, }: AdminProviderProps): import("react/jsx-runtime").JSX.Element;
53
+ //# sourceMappingURL=admin-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-provider.d.ts","sourceRoot":"","sources":["../../src/providers/admin-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAEhD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAK5C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,SAAS,CAAA;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,2CAA2C;IAC3C,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,WAAW,EACX,YAAuB,EACvB,eAAyB,EACzB,aAAa,EACb,eAAsB,EACtB,gBAAiC,EACjC,kBAAqC,EACrC,gBAAgB,EAChB,cAAc,GACf,EAAE,kBAAkB,2CAoBpB"}
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { QueryClientProvider } from "@tanstack/react-query";
4
+ import { useState } from "react";
5
+ import { LocaleProvider } from "./locale.js";
6
+ import { makeQueryClient } from "./query-client.js";
7
+ import { ThemeProvider } from "./theme.js";
8
+ /**
9
+ * Composes the shared admin providers — QueryClient, Theme, and Locale — so
10
+ * starters don't have to wire each one individually. Note: this does NOT include
11
+ * `<VoyantReactProvider>` (from `@voyant-travel/react`) because its API base
12
+ * URL is starter-specific. Wrap AdminProvider's children with your
13
+ * VoyantReactProvider at the same level.
14
+ *
15
+ * @example
16
+ * <AdminProvider>
17
+ * <VoyantReactProvider baseUrl="/api">
18
+ * <App />
19
+ * </VoyantReactProvider>
20
+ * </AdminProvider>
21
+ */
22
+ export function AdminProvider({ children, queryClient, defaultTheme = "system", themeStorageKey = "theme", defaultLocale, defaultTimeZone = null, localeStorageKey = "admin-locale", timeZoneStorageKey = "admin-timezone", supportedLocales, fallbackLocale, }) {
23
+ // Keep a single QueryClient instance per mount when one isn't passed in.
24
+ const [client] = useState(() => queryClient ?? makeQueryClient());
25
+ return (_jsx(QueryClientProvider, { client: client, children: _jsx(ThemeProvider, { defaultTheme: defaultTheme, storageKey: themeStorageKey, children: _jsx(LocaleProvider, { defaultLocale: defaultLocale, defaultTimeZone: defaultTimeZone, localeStorageKey: localeStorageKey, timeZoneStorageKey: timeZoneStorageKey, supportedLocales: supportedLocales, fallbackLocale: fallbackLocale, children: children }) }) }));
26
+ }
@@ -0,0 +1,12 @@
1
+ export interface AdminLocalePreferenceSource {
2
+ locale?: string | null;
3
+ timeZone?: string | null;
4
+ timezone?: string | null;
5
+ }
6
+ export interface AdminLocalePreferenceSyncProps {
7
+ source: AdminLocalePreferenceSource | null | undefined;
8
+ localeStorageKey?: string | null;
9
+ timeZoneStorageKey?: string | null;
10
+ }
11
+ export declare function AdminLocalePreferenceSync({ source, localeStorageKey, timeZoneStorageKey, }: AdminLocalePreferenceSyncProps): null;
12
+ //# sourceMappingURL=locale-preferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-preferences.d.ts","sourceRoot":"","sources":["../../src/providers/locale-preferences.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,2BAA2B,GAAG,IAAI,GAAG,SAAS,CAAA;IACtD,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACnC;AAED,wBAAgB,yBAAyB,CAAC,EACxC,MAAM,EACN,gBAAiC,EACjC,kBAAqC,GACtC,EAAE,8BAA8B,QAoChC"}
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ import { useLocale } from "./locale.js";
4
+ export function AdminLocalePreferenceSync({ source, localeStorageKey = "admin-locale", timeZoneStorageKey = "admin-timezone", }) {
5
+ const { locale, setLocale, setTimeZone, timeZone } = useLocale();
6
+ const preferredTimeZone = source?.timeZone ?? source?.timezone ?? null;
7
+ useEffect(() => {
8
+ if (!source || typeof window === "undefined") {
9
+ return;
10
+ }
11
+ if (source.locale &&
12
+ source.locale !== locale &&
13
+ (!localeStorageKey || !window.localStorage.getItem(localeStorageKey))) {
14
+ setLocale(source.locale);
15
+ }
16
+ if (preferredTimeZone &&
17
+ preferredTimeZone !== timeZone &&
18
+ (!timeZoneStorageKey || !window.localStorage.getItem(timeZoneStorageKey))) {
19
+ setTimeZone(preferredTimeZone);
20
+ }
21
+ }, [
22
+ locale,
23
+ localeStorageKey,
24
+ preferredTimeZone,
25
+ setLocale,
26
+ setTimeZone,
27
+ source,
28
+ timeZone,
29
+ timeZoneStorageKey,
30
+ ]);
31
+ return null;
32
+ }
@@ -0,0 +1,23 @@
1
+ import { type ReactNode } from "react";
2
+ export declare const DEFAULT_ADMIN_LOCALES: readonly ["en", "ro"];
3
+ export declare const DEFAULT_ADMIN_LOCALE = "en";
4
+ export interface LocaleContextValue {
5
+ locale: string;
6
+ resolvedLocale: string;
7
+ setLocale: (locale: string) => void;
8
+ timeZone: string | null;
9
+ setTimeZone: (timeZone: string | null) => void;
10
+ }
11
+ export interface LocaleProviderProps {
12
+ children: ReactNode;
13
+ defaultLocale?: string;
14
+ defaultTimeZone?: string | null;
15
+ localeStorageKey?: string | null;
16
+ timeZoneStorageKey?: string | null;
17
+ supportedLocales?: readonly string[];
18
+ fallbackLocale?: string;
19
+ }
20
+ export declare function LocaleProvider({ children, defaultLocale, defaultTimeZone, localeStorageKey, timeZoneStorageKey, supportedLocales, fallbackLocale, }: LocaleProviderProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function useLocale(): LocaleContextValue;
22
+ export declare function resolveAdminLocale(locale: string | null | undefined, supportedLocales?: readonly string[], fallbackLocale?: string): string;
23
+ //# sourceMappingURL=locale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../src/providers/locale.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAA;AAEd,eAAO,MAAM,qBAAqB,uBAAwB,CAAA;AAC1D,eAAO,MAAM,oBAAoB,OAAO,CAAA;AAExC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CAC/C;AA6CD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,SAAS,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,aAAa,EACb,eAAsB,EACtB,gBAAiC,EACjC,kBAAqC,EACrC,gBAAwC,EACxC,cAAqC,GACtC,EAAE,mBAAmB,2CAgFrB;AAED,wBAAgB,SAAS,IAAI,kBAAkB,CAO9C;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,gBAAgB,GAAE,SAAS,MAAM,EAA0B,EAC3D,cAAc,SAAuB,GACpC,MAAM,CAER"}
@@ -0,0 +1,98 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from "react";
4
+ export const DEFAULT_ADMIN_LOCALES = ["en", "ro"];
5
+ export const DEFAULT_ADMIN_LOCALE = "en";
6
+ const LocaleContext = createContext(undefined);
7
+ function pickSupportedLocale(locale, supportedLocales, fallbackLocale) {
8
+ if (!locale) {
9
+ return fallbackLocale;
10
+ }
11
+ const normalized = locale.trim().toLowerCase();
12
+ if (!normalized) {
13
+ return fallbackLocale;
14
+ }
15
+ const directMatch = supportedLocales.find((candidate) => candidate.toLowerCase() === normalized);
16
+ if (directMatch) {
17
+ return directMatch;
18
+ }
19
+ const languageMatch = supportedLocales.find((candidate) => candidate.toLowerCase() === normalized.split("-")[0]);
20
+ return languageMatch ?? fallbackLocale;
21
+ }
22
+ function readStoredValue(storageKey) {
23
+ if (typeof window === "undefined" || storageKey === null) {
24
+ return null;
25
+ }
26
+ return window.localStorage.getItem(storageKey);
27
+ }
28
+ function getBrowserLocale() {
29
+ if (typeof navigator === "undefined") {
30
+ return null;
31
+ }
32
+ return navigator.language ?? null;
33
+ }
34
+ export function LocaleProvider({ children, defaultLocale, defaultTimeZone = null, localeStorageKey = "admin-locale", timeZoneStorageKey = "admin-timezone", supportedLocales = DEFAULT_ADMIN_LOCALES, fallbackLocale = DEFAULT_ADMIN_LOCALE, }) {
35
+ const [locale, setLocaleState] = useState(() => {
36
+ const storedLocale = readStoredValue(localeStorageKey);
37
+ if (storedLocale) {
38
+ return storedLocale;
39
+ }
40
+ if (defaultLocale) {
41
+ return defaultLocale;
42
+ }
43
+ const browserLocale = getBrowserLocale();
44
+ return browserLocale ?? fallbackLocale;
45
+ });
46
+ const [timeZone, setTimeZoneState] = useState(() => {
47
+ const storedTimeZone = readStoredValue(timeZoneStorageKey);
48
+ if (storedTimeZone) {
49
+ return storedTimeZone;
50
+ }
51
+ if (defaultTimeZone !== undefined) {
52
+ return defaultTimeZone;
53
+ }
54
+ return Intl.DateTimeFormat().resolvedOptions().timeZone ?? null;
55
+ });
56
+ const resolvedLocale = useMemo(() => pickSupportedLocale(locale, supportedLocales, fallbackLocale), [fallbackLocale, locale, supportedLocales]);
57
+ const setLocale = useCallback((nextLocale) => {
58
+ setLocaleState(nextLocale);
59
+ if (typeof window !== "undefined" && localeStorageKey !== null) {
60
+ window.localStorage.setItem(localeStorageKey, nextLocale);
61
+ }
62
+ }, [localeStorageKey]);
63
+ const setTimeZone = useCallback((nextTimeZone) => {
64
+ setTimeZoneState(nextTimeZone);
65
+ if (typeof window === "undefined" || timeZoneStorageKey === null) {
66
+ return;
67
+ }
68
+ if (nextTimeZone) {
69
+ window.localStorage.setItem(timeZoneStorageKey, nextTimeZone);
70
+ }
71
+ else {
72
+ window.localStorage.removeItem(timeZoneStorageKey);
73
+ }
74
+ }, [timeZoneStorageKey]);
75
+ useEffect(() => {
76
+ if (typeof document === "undefined") {
77
+ return;
78
+ }
79
+ document.documentElement.lang = resolvedLocale;
80
+ }, [resolvedLocale]);
81
+ return (_jsx(LocaleContext.Provider, { value: {
82
+ locale,
83
+ resolvedLocale,
84
+ setLocale,
85
+ timeZone,
86
+ setTimeZone,
87
+ }, children: children }));
88
+ }
89
+ export function useLocale() {
90
+ const context = useContext(LocaleContext);
91
+ if (!context) {
92
+ throw new Error("useLocale must be used within <LocaleProvider>");
93
+ }
94
+ return context;
95
+ }
96
+ export function resolveAdminLocale(locale, supportedLocales = DEFAULT_ADMIN_LOCALES, fallbackLocale = DEFAULT_ADMIN_LOCALE) {
97
+ return pickSupportedLocale(locale, supportedLocales, fallbackLocale);
98
+ }