@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,224 @@
1
+ import type { VoyantFetcher } from "@voyant-travel/react";
2
+ export interface DashboardQueryClient {
3
+ baseUrl: string;
4
+ fetcher: VoyantFetcher;
5
+ }
6
+ export type BookingsAggregates = {
7
+ total: number;
8
+ totalPax: number;
9
+ countsByStatus: Array<{
10
+ status: string;
11
+ count: number;
12
+ }>;
13
+ monthlyCounts: Array<{
14
+ yearMonth: string;
15
+ count: number;
16
+ }>;
17
+ monthlyRevenue: Array<{
18
+ yearMonth: string;
19
+ currency: string;
20
+ sellAmountCents: number;
21
+ }>;
22
+ upcomingDepartures: {
23
+ count: number;
24
+ items: Array<{
25
+ id: string;
26
+ bookingNumber: string | null;
27
+ status: string;
28
+ startDate: string | null;
29
+ endDate: string | null;
30
+ pax: number | null;
31
+ sellCurrency: string | null;
32
+ sellAmountCents: number | null;
33
+ }>;
34
+ };
35
+ };
36
+ export type ProductsAggregates = {
37
+ total: number;
38
+ active: number;
39
+ publicActive: number;
40
+ countsByStatus: Array<{
41
+ status: string;
42
+ count: number;
43
+ }>;
44
+ monthlyCreatedCounts: Array<{
45
+ yearMonth: string;
46
+ count: number;
47
+ }>;
48
+ };
49
+ export type SuppliersAggregates = {
50
+ total: number;
51
+ active: number;
52
+ countsByStatus: Array<{
53
+ status: string;
54
+ count: number;
55
+ }>;
56
+ countsByType: Array<{
57
+ type: string | null;
58
+ count: number;
59
+ }>;
60
+ };
61
+ export type FinanceAggregates = {
62
+ total: number;
63
+ countsByStatus: Array<{
64
+ status: string;
65
+ count: number;
66
+ }>;
67
+ monthlyRevenue: Array<{
68
+ yearMonth: string;
69
+ currency: string;
70
+ totalCents: number;
71
+ }>;
72
+ monthlyInvoiceCounts: Array<{
73
+ yearMonth: string;
74
+ count: number;
75
+ }>;
76
+ outstanding: Array<{
77
+ currency: string;
78
+ balanceDueCents: number;
79
+ count: number;
80
+ }>;
81
+ overdue: Array<{
82
+ currency: string;
83
+ balanceDueCents: number;
84
+ count: number;
85
+ }>;
86
+ outstandingTopN: Array<{
87
+ id: string;
88
+ invoiceNumber: string | null;
89
+ bookingId: string | null;
90
+ status: string;
91
+ currency: string;
92
+ totalCents: number;
93
+ balanceDueCents: number;
94
+ issueDate: string | null;
95
+ dueDate: string | null;
96
+ }>;
97
+ };
98
+ export declare class DashboardApiError extends Error {
99
+ readonly status: number;
100
+ readonly body: unknown;
101
+ constructor(message: string, status: number, body: unknown);
102
+ }
103
+ export declare const dashboardQueryKeys: {
104
+ bookingsAggregates: (from: string) => readonly ["dashboard-bookings-aggregates", string];
105
+ productsAggregates: () => readonly ["dashboard-products-aggregates"];
106
+ suppliersAggregates: () => readonly ["dashboard-suppliers-aggregates"];
107
+ financeAggregates: (from: string) => readonly ["dashboard-finance-aggregates", string];
108
+ };
109
+ export declare function buildDashboardSixMonthWindow(): {
110
+ from: string;
111
+ };
112
+ export declare function getDashboardBookingsAggregatesQueryOptions(client: DashboardQueryClient): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
113
+ data: BookingsAggregates;
114
+ }, Error, {
115
+ data: BookingsAggregates;
116
+ }, readonly ["dashboard-bookings-aggregates", string]>, "queryFn"> & {
117
+ queryFn?: import("@tanstack/react-query").QueryFunction<{
118
+ data: BookingsAggregates;
119
+ }, readonly ["dashboard-bookings-aggregates", string], never> | undefined;
120
+ } & {
121
+ queryKey: readonly ["dashboard-bookings-aggregates", string] & {
122
+ [dataTagSymbol]: {
123
+ data: BookingsAggregates;
124
+ };
125
+ [dataTagErrorSymbol]: Error;
126
+ };
127
+ };
128
+ export declare function getDashboardProductsAggregatesQueryOptions(client: DashboardQueryClient): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
129
+ data: ProductsAggregates;
130
+ }, Error, {
131
+ data: ProductsAggregates;
132
+ }, readonly ["dashboard-products-aggregates"]>, "queryFn"> & {
133
+ queryFn?: import("@tanstack/react-query").QueryFunction<{
134
+ data: ProductsAggregates;
135
+ }, readonly ["dashboard-products-aggregates"], never> | undefined;
136
+ } & {
137
+ queryKey: readonly ["dashboard-products-aggregates"] & {
138
+ [dataTagSymbol]: {
139
+ data: ProductsAggregates;
140
+ };
141
+ [dataTagErrorSymbol]: Error;
142
+ };
143
+ };
144
+ export declare function getDashboardSuppliersAggregatesQueryOptions(client: DashboardQueryClient): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
145
+ data: SuppliersAggregates;
146
+ }, Error, {
147
+ data: SuppliersAggregates;
148
+ }, readonly ["dashboard-suppliers-aggregates"]>, "queryFn"> & {
149
+ queryFn?: import("@tanstack/react-query").QueryFunction<{
150
+ data: SuppliersAggregates;
151
+ }, readonly ["dashboard-suppliers-aggregates"], never> | undefined;
152
+ } & {
153
+ queryKey: readonly ["dashboard-suppliers-aggregates"] & {
154
+ [dataTagSymbol]: {
155
+ data: SuppliersAggregates;
156
+ };
157
+ [dataTagErrorSymbol]: Error;
158
+ };
159
+ };
160
+ export declare function getDashboardFinanceAggregatesQueryOptions(client: DashboardQueryClient): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
161
+ data: FinanceAggregates;
162
+ }, Error, {
163
+ data: FinanceAggregates;
164
+ }, readonly ["dashboard-finance-aggregates", string]>, "queryFn"> & {
165
+ queryFn?: import("@tanstack/react-query").QueryFunction<{
166
+ data: FinanceAggregates;
167
+ }, readonly ["dashboard-finance-aggregates", string], never> | undefined;
168
+ } & {
169
+ queryKey: readonly ["dashboard-finance-aggregates", string] & {
170
+ [dataTagSymbol]: {
171
+ data: FinanceAggregates;
172
+ };
173
+ [dataTagErrorSymbol]: Error;
174
+ };
175
+ };
176
+ export declare function formatCurrency(cents: number, currency?: string): string;
177
+ export declare function getStatusColor(status: string): string;
178
+ export declare const revenueChartConfig: {
179
+ revenue: {
180
+ label: string;
181
+ color: string;
182
+ };
183
+ bookings: {
184
+ label: string;
185
+ color: string;
186
+ };
187
+ };
188
+ export declare const bookingStatusConfig: {
189
+ confirmed: {
190
+ label: string;
191
+ color: string;
192
+ };
193
+ completed: {
194
+ label: string;
195
+ color: string;
196
+ };
197
+ in_progress: {
198
+ label: string;
199
+ color: string;
200
+ };
201
+ draft: {
202
+ label: string;
203
+ color: string;
204
+ };
205
+ cancelled: {
206
+ label: string;
207
+ color: string;
208
+ };
209
+ };
210
+ export declare const monthlyBookingsConfig: {
211
+ count: {
212
+ label: string;
213
+ color: string;
214
+ };
215
+ };
216
+ export declare function buildMonthSeries(): {
217
+ yearMonth: string;
218
+ month: string;
219
+ }[];
220
+ export declare function pickPrimaryCurrency(rows: Array<{
221
+ currency: string;
222
+ sellAmountCents: number;
223
+ }>): string;
224
+ //# sourceMappingURL=dashboard-query-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-query-options.d.ts","sourceRoot":"","sources":["../../src/dashboard/dashboard-query-options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,153 @@
1
+ import { queryOptions } from "@tanstack/react-query";
2
+ export class DashboardApiError extends Error {
3
+ status;
4
+ body;
5
+ constructor(message, status, body) {
6
+ super(message);
7
+ this.status = status;
8
+ this.body = body;
9
+ this.name = "DashboardApiError";
10
+ }
11
+ }
12
+ export const dashboardQueryKeys = {
13
+ bookingsAggregates: (from) => ["dashboard-bookings-aggregates", from],
14
+ productsAggregates: () => ["dashboard-products-aggregates"],
15
+ suppliersAggregates: () => ["dashboard-suppliers-aggregates"],
16
+ financeAggregates: (from) => ["dashboard-finance-aggregates", from],
17
+ };
18
+ export function buildDashboardSixMonthWindow() {
19
+ const now = new Date();
20
+ const fromDate = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 5, 1, 0, 0, 0, 0));
21
+ return { from: fromDate.toISOString() };
22
+ }
23
+ function joinUrl(baseUrl, path) {
24
+ const trimmedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
25
+ const trimmedPath = path.startsWith("/") ? path : `/${path}`;
26
+ return `${trimmedBase}${trimmedPath}`;
27
+ }
28
+ function extractErrorMessage(status, statusText, body) {
29
+ if (typeof body === "object" && body !== null && "error" in body) {
30
+ const errorField = body.error;
31
+ if (typeof errorField === "string")
32
+ return errorField;
33
+ if (typeof errorField === "object" && errorField !== null && "message" in errorField) {
34
+ return String(errorField.message);
35
+ }
36
+ }
37
+ return `Dashboard API error: ${status} ${statusText}`;
38
+ }
39
+ async function readBody(response) {
40
+ const text = await response.text();
41
+ if (!text)
42
+ return undefined;
43
+ try {
44
+ return JSON.parse(text);
45
+ }
46
+ catch {
47
+ return text;
48
+ }
49
+ }
50
+ async function fetchDashboardJson(client, path) {
51
+ const response = await client.fetcher(joinUrl(client.baseUrl, path), {
52
+ headers: { Accept: "application/json" },
53
+ method: "GET",
54
+ });
55
+ const body = await readBody(response);
56
+ if (!response.ok) {
57
+ throw new DashboardApiError(extractErrorMessage(response.status, response.statusText, body), response.status, body);
58
+ }
59
+ return body;
60
+ }
61
+ export function getDashboardBookingsAggregatesQueryOptions(client) {
62
+ const { from } = buildDashboardSixMonthWindow();
63
+ return queryOptions({
64
+ queryKey: dashboardQueryKeys.bookingsAggregates(from),
65
+ queryFn: () => fetchDashboardJson(client, `/v1/admin/bookings/aggregates?from=${encodeURIComponent(from)}&upcomingLimit=8`),
66
+ staleTime: 60_000,
67
+ });
68
+ }
69
+ export function getDashboardProductsAggregatesQueryOptions(client) {
70
+ return queryOptions({
71
+ queryKey: dashboardQueryKeys.productsAggregates(),
72
+ queryFn: () => fetchDashboardJson(client, "/v1/admin/products/aggregates"),
73
+ staleTime: 60_000,
74
+ });
75
+ }
76
+ export function getDashboardSuppliersAggregatesQueryOptions(client) {
77
+ return queryOptions({
78
+ queryKey: dashboardQueryKeys.suppliersAggregates(),
79
+ queryFn: () => fetchDashboardJson(client, "/v1/admin/suppliers/aggregates"),
80
+ staleTime: 60_000,
81
+ });
82
+ }
83
+ export function getDashboardFinanceAggregatesQueryOptions(client) {
84
+ const { from } = buildDashboardSixMonthWindow();
85
+ return queryOptions({
86
+ queryKey: dashboardQueryKeys.financeAggregates(from),
87
+ queryFn: () => fetchDashboardJson(client, `/v1/admin/finance/aggregates?from=${encodeURIComponent(from)}&outstandingTopLimit=5`),
88
+ staleTime: 60_000,
89
+ });
90
+ }
91
+ export function formatCurrency(cents, currency = "USD") {
92
+ return new Intl.NumberFormat("en-US", {
93
+ style: "currency",
94
+ currency,
95
+ maximumFractionDigits: 0,
96
+ }).format(cents / 100);
97
+ }
98
+ export function getStatusColor(status) {
99
+ // Status colors are intentionally hard-coded — they carry meaning
100
+ // (green = confirmed, red = cancelled, etc.) and shouldn't change
101
+ // with theme palette tokens like --chart-1..5, which are general
102
+ // chart palette slots and may be set to a monochromatic series.
103
+ const map = {
104
+ confirmed: "hsl(142 71% 45%)",
105
+ completed: "hsl(221 83% 53%)",
106
+ in_progress: "hsl(47 96% 53%)",
107
+ draft: "hsl(215 14% 55%)",
108
+ cancelled: "hsl(0 84% 60%)",
109
+ };
110
+ return map[status] ?? "hsl(215 14% 55%)";
111
+ }
112
+ export const revenueChartConfig = {
113
+ revenue: { label: "Revenue", color: "hsl(221 83% 53%)" },
114
+ bookings: { label: "Bookings", color: "hsl(142 71% 45%)" },
115
+ };
116
+ export const bookingStatusConfig = {
117
+ confirmed: { label: "Confirmed", color: "hsl(142 71% 45%)" },
118
+ completed: { label: "Completed", color: "hsl(221 83% 53%)" },
119
+ in_progress: { label: "In Progress", color: "hsl(47 96% 53%)" },
120
+ draft: { label: "Draft", color: "hsl(215 14% 55%)" },
121
+ cancelled: { label: "Cancelled", color: "hsl(0 84% 60%)" },
122
+ };
123
+ export const monthlyBookingsConfig = {
124
+ count: { label: "Bookings", color: "hsl(221 83% 53%)" },
125
+ };
126
+ export function buildMonthSeries() {
127
+ const now = new Date();
128
+ return Array.from({ length: 6 }, (_, idx) => {
129
+ const offset = 5 - idx;
130
+ const date = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - offset, 1));
131
+ return {
132
+ yearMonth: `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, "0")}`,
133
+ month: date.toLocaleString("en-US", { month: "short", timeZone: "UTC" }),
134
+ };
135
+ });
136
+ }
137
+ export function pickPrimaryCurrency(rows) {
138
+ if (rows.length === 0)
139
+ return "USD";
140
+ const totals = new Map();
141
+ for (const row of rows) {
142
+ totals.set(row.currency, (totals.get(row.currency) ?? 0) + row.sellAmountCents);
143
+ }
144
+ let bestCurrency = "USD";
145
+ let bestTotal = -1;
146
+ for (const [currency, total] of totals) {
147
+ if (total > bestTotal) {
148
+ bestCurrency = currency;
149
+ bestTotal = total;
150
+ }
151
+ }
152
+ return bestCurrency;
153
+ }
@@ -0,0 +1,13 @@
1
+ export declare function DashboardKpiSkeleton(): import("react/jsx-runtime").JSX.Element;
2
+ export declare function DashboardKpiRowSkeleton(): import("react/jsx-runtime").JSX.Element;
3
+ export declare function DashboardAreaChartSkeleton(): import("react/jsx-runtime").JSX.Element;
4
+ export declare function DashboardPieChartSkeleton(): import("react/jsx-runtime").JSX.Element;
5
+ export declare function DashboardBarChartSkeleton(): import("react/jsx-runtime").JSX.Element;
6
+ export declare function DashboardUpcomingListSkeleton({ rows }?: {
7
+ rows?: number;
8
+ }): import("react/jsx-runtime").JSX.Element;
9
+ export declare function DashboardOutstandingInvoicesSkeleton({ rows }?: {
10
+ rows?: number;
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ export declare function DashboardSkeleton(): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=dashboard-skeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-skeleton.d.ts","sourceRoot":"","sources":["../../src/dashboard/dashboard-skeleton.tsx"],"names":[],"mappings":"AAGA,wBAAgB,oBAAoB,4CAcnC;AAED,wBAAgB,uBAAuB,4CAStC;AAED,wBAAgB,0BAA0B,4CAYzC;AAED,wBAAgB,yBAAyB,4CAexC;AAED,wBAAgB,yBAAyB,4CAkBxC;AAED,wBAAgB,6BAA6B,CAAC,EAAE,IAAQ,EAAE,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,2CAqBjF;AAED,wBAAgB,oCAAoC,CAAC,EAAE,IAAQ,EAAE,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,2CA4BxF;AAED,wBAAgB,iBAAiB,4CAoEhC"}
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Card, CardContent, CardHeader } from "@voyant-travel/ui/components/card";
3
+ import { Skeleton } from "@voyant-travel/ui/components/skeleton";
4
+ export function DashboardKpiSkeleton() {
5
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [_jsx(Skeleton, { className: "h-3.5 w-24" }), _jsx(Skeleton, { className: "h-4 w-4 rounded" })] }), _jsxs(CardContent, { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-7 w-28" }), _jsx(Skeleton, { className: "h-3 w-40" }), _jsx(Skeleton, { className: "mt-3 h-5 w-28 rounded-full" })] })] }));
6
+ }
7
+ export function DashboardKpiRowSkeleton() {
8
+ return (_jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: Array.from({ length: 4 }).map((_, i) => (_jsx(DashboardKpiSkeleton, {}, i))) }));
9
+ }
10
+ export function DashboardAreaChartSkeleton() {
11
+ return (_jsxs("div", { className: "flex h-[300px] w-full flex-col justify-end gap-2", children: [_jsx(Skeleton, { className: "h-full w-full rounded-md" }), _jsx("div", { className: "flex justify-between px-2", children: Array.from({ length: 6 }).map((_, i) => (_jsx(Skeleton, { className: "h-3 w-10" }, i))) })] }));
12
+ }
13
+ export function DashboardPieChartSkeleton() {
14
+ return (_jsxs("div", { className: "flex h-[300px] flex-col items-center justify-center gap-4", children: [_jsx(Skeleton, { className: "h-[200px] w-[200px] rounded-full" }), _jsx("div", { className: "flex flex-wrap justify-center gap-3", children: Array.from({ length: 4 }).map((_, i) => (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Skeleton, { className: "h-2.5 w-2.5 rounded-full" }), _jsx(Skeleton, { className: "h-3 w-14" })] }, i))) })] }));
15
+ }
16
+ export function DashboardBarChartSkeleton() {
17
+ const heights = ["h-24", "h-32", "h-20", "h-40", "h-28", "h-36"];
18
+ return (_jsxs("div", { className: "flex h-[250px] w-full flex-col justify-end gap-2", children: [_jsx("div", { className: "flex h-full items-end justify-between gap-2 px-1", children: heights.map((h, i) => (_jsx(Skeleton, { className: `${h} w-full rounded-sm` }, i))) }), _jsx("div", { className: "flex justify-between px-1", children: heights.map((_, i) => (_jsx(Skeleton, { className: "h-3 w-10" }, i))) })] }));
19
+ }
20
+ export function DashboardUpcomingListSkeleton({ rows = 4 } = {}) {
21
+ return (_jsx("div", { className: "space-y-3", children: Array.from({ length: rows }).map((_, i) => (_jsxs("div", { className: "flex items-center justify-between rounded-lg border p-3", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Skeleton, { className: "h-3.5 w-28" }), _jsx(Skeleton, { className: "h-3 w-40" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Skeleton, { className: "h-3.5 w-16" }), _jsx(Skeleton, { className: "h-5 w-20 rounded-full" })] })] }, i))) }));
22
+ }
23
+ export function DashboardOutstandingInvoicesSkeleton({ rows = 3 } = {}) {
24
+ return (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-dashed p-4", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Skeleton, { className: "h-3.5 w-28" }), _jsx(Skeleton, { className: "h-3 w-32" })] }), _jsx(Skeleton, { className: "h-5 w-24" })] }), Array.from({ length: rows }).map((_, i) => (_jsxs("div", { className: "flex items-center justify-between rounded-lg border p-3", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Skeleton, { className: "h-3.5 w-24" }), _jsx(Skeleton, { className: "h-3 w-32" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Skeleton, { className: "h-3.5 w-16" }), _jsx(Skeleton, { className: "h-5 w-14 rounded-full" })] })] }, i)))] }));
25
+ }
26
+ export function DashboardSkeleton() {
27
+ return (_jsxs("div", { className: "flex flex-col gap-6 p-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-7 w-32" }), _jsx(Skeleton, { className: "h-4 w-48" })] }), _jsx(DashboardKpiRowSkeleton, {}), _jsxs("div", { className: "grid gap-4 lg:grid-cols-7", children: [_jsxs(Card, { className: "lg:col-span-4", children: [_jsxs(CardHeader, { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-5 w-40" }), _jsx(Skeleton, { className: "h-3 w-56" })] }), _jsx(CardContent, { children: _jsx(DashboardAreaChartSkeleton, {}) })] }), _jsxs(Card, { className: "lg:col-span-3", children: [_jsxs(CardHeader, { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-5 w-32" }), _jsx(Skeleton, { className: "h-3 w-48" })] }), _jsx(CardContent, { children: _jsx(DashboardPieChartSkeleton, {}) })] })] }), _jsxs("div", { className: "grid gap-4 lg:grid-cols-7", children: [_jsxs(Card, { className: "lg:col-span-3", children: [_jsxs(CardHeader, { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-5 w-36" }), _jsx(Skeleton, { className: "h-3 w-40" })] }), _jsx(CardContent, { children: _jsx(DashboardBarChartSkeleton, {}) })] }), _jsxs(Card, { className: "lg:col-span-4", children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-5 w-40" }), _jsx(Skeleton, { className: "h-3 w-24" })] }), _jsx(Skeleton, { className: "h-4 w-16" })] }), _jsx(CardContent, { children: _jsx(DashboardUpcomingListSkeleton, {}) })] })] }), _jsx("div", { className: "grid gap-4 lg:grid-cols-2", children: _jsxs(Card, { children: [_jsxs(CardHeader, { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-5 w-44" }), _jsx(Skeleton, { className: "h-3 w-56" })] }), _jsx(CardContent, { children: _jsx(DashboardOutstandingInvoicesSkeleton, {}) })] }) })] }));
28
+ }