@voyantjs/availability-react 0.106.0 → 0.108.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 (81) hide show
  1. package/README.md +161 -1
  2. package/dist/admin/availability-index-host.d.ts +12 -0
  3. package/dist/admin/availability-index-host.d.ts.map +1 -0
  4. package/dist/admin/availability-index-host.js +125 -0
  5. package/dist/admin/availability-page-data.d.ts +9 -0
  6. package/dist/admin/availability-page-data.d.ts.map +1 -0
  7. package/dist/admin/availability-page-data.js +25 -0
  8. package/dist/admin/index.d.ts +72 -0
  9. package/dist/admin/index.d.ts.map +1 -0
  10. package/dist/admin/index.js +132 -0
  11. package/dist/admin/option-resource-templates-panel.d.ts +22 -0
  12. package/dist/admin/option-resource-templates-panel.d.ts.map +1 -0
  13. package/dist/admin/option-resource-templates-panel.js +251 -0
  14. package/dist/admin/pages/availability-rule-detail-page.d.ts +9 -0
  15. package/dist/admin/pages/availability-rule-detail-page.d.ts.map +1 -0
  16. package/dist/admin/pages/availability-rule-detail-page.js +11 -0
  17. package/dist/admin/pages/availability-slot-detail-page.d.ts +9 -0
  18. package/dist/admin/pages/availability-slot-detail-page.d.ts.map +1 -0
  19. package/dist/admin/pages/availability-slot-detail-page.js +11 -0
  20. package/dist/admin/pages/availability-start-time-detail-page.d.ts +9 -0
  21. package/dist/admin/pages/availability-start-time-detail-page.d.ts.map +1 -0
  22. package/dist/admin/pages/availability-start-time-detail-page.js +11 -0
  23. package/dist/admin/rule-detail-host.d.ts +14 -0
  24. package/dist/admin/rule-detail-host.d.ts.map +1 -0
  25. package/dist/admin/rule-detail-host.js +27 -0
  26. package/dist/admin/slot-detail-host.d.ts +29 -0
  27. package/dist/admin/slot-detail-host.d.ts.map +1 -0
  28. package/dist/admin/slot-detail-host.js +110 -0
  29. package/dist/admin/start-time-detail-host.d.ts +15 -0
  30. package/dist/admin/start-time-detail-host.d.ts.map +1 -0
  31. package/dist/admin/start-time-detail-host.js +37 -0
  32. package/dist/components/availability-columns.d.ts +42 -0
  33. package/dist/components/availability-columns.d.ts.map +1 -0
  34. package/dist/components/availability-columns.js +182 -0
  35. package/dist/components/availability-dialogs.d.ts +236 -0
  36. package/dist/components/availability-dialogs.d.ts.map +1 -0
  37. package/dist/components/availability-dialogs.js +369 -0
  38. package/dist/components/availability-overview.d.ts +54 -0
  39. package/dist/components/availability-overview.d.ts.map +1 -0
  40. package/dist/components/availability-overview.js +50 -0
  41. package/dist/components/availability-page.d.ts +32 -0
  42. package/dist/components/availability-page.d.ts.map +1 -0
  43. package/dist/components/availability-page.js +128 -0
  44. package/dist/components/availability-rule-detail-page.d.ts +251 -0
  45. package/dist/components/availability-rule-detail-page.d.ts.map +1 -0
  46. package/dist/components/availability-rule-detail-page.js +74 -0
  47. package/dist/components/availability-section-header.d.ts +8 -0
  48. package/dist/components/availability-section-header.d.ts.map +1 -0
  49. package/dist/components/availability-section-header.js +7 -0
  50. package/dist/components/availability-skeletons.d.ts +6 -0
  51. package/dist/components/availability-skeletons.d.ts.map +1 -0
  52. package/dist/components/availability-skeletons.js +34 -0
  53. package/dist/components/availability-slot-detail-page.d.ts +974 -0
  54. package/dist/components/availability-slot-detail-page.d.ts.map +1 -0
  55. package/dist/components/availability-slot-detail-page.js +383 -0
  56. package/dist/components/availability-start-time-detail-page.d.ts +246 -0
  57. package/dist/components/availability-start-time-detail-page.d.ts.map +1 -0
  58. package/dist/components/availability-start-time-detail-page.js +83 -0
  59. package/dist/components/availability-tabs.d.ts +152 -0
  60. package/dist/components/availability-tabs.d.ts.map +1 -0
  61. package/dist/components/availability-tabs.js +192 -0
  62. package/dist/components/slot-status-tone.d.ts +15 -0
  63. package/dist/components/slot-status-tone.d.ts.map +1 -0
  64. package/dist/components/slot-status-tone.js +18 -0
  65. package/dist/form-resolver.d.ts +4 -0
  66. package/dist/form-resolver.d.ts.map +1 -0
  67. package/dist/form-resolver.js +40 -0
  68. package/dist/i18n/index.d.ts +2 -0
  69. package/dist/i18n/index.d.ts.map +1 -0
  70. package/dist/i18n/index.js +1 -0
  71. package/dist/i18n/provider.d.ts +2003 -0
  72. package/dist/i18n/provider.d.ts.map +1 -0
  73. package/dist/i18n/provider.js +102 -0
  74. package/dist/ui.d.ts +13 -0
  75. package/dist/ui.d.ts.map +1 -0
  76. package/dist/ui.js +12 -0
  77. package/dist/utils.d.ts +1 -0
  78. package/dist/utils.d.ts.map +1 -1
  79. package/dist/utils.js +3 -0
  80. package/package.json +92 -9
  81. package/src/styles.css +11 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability-slot-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/availability-slot-detail-page.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,383 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Card, CardContent, CardHeader, CardTitle, cn, Tabs, TabsContent, TabsList, TabsTrigger, } from "@voyantjs/ui/components";
5
+ import { Activity, BookOpen, CalendarDays, History, Info, Package, Pencil, Plus, Sparkles, Trash2, Truck, UserMinus, UserPlus, Wrench, } from "lucide-react";
6
+ import { useState } from "react";
7
+ import { useAvailabilityUiI18nOrDefault } from "../i18n/index.js";
8
+ import { getPickupPointsQueryOptions, getProductQueryOptions, getSlotAllocationQueryOptions, getSlotAssignmentsQueryOptions, getSlotCloseoutsQueryOptions, getSlotPickupsQueryOptions, getSlotQueryOptions, getSlotResourcesQueryOptions, slotLocalEnd, slotLocalStart, slotStatusTone, useAvailabilitySlotMutation, useSlotAllocationAuditLog, useVoyantAvailabilityContext, } from "../index.js";
9
+ import { getSlotStatusLabel } from "./availability-columns.js";
10
+ import { AvailabilitySlotDetailSkeleton } from "./availability-skeletons.js";
11
+ import { slotStatusToneClass } from "./slot-status-tone.js";
12
+ export function getAvailabilitySlotDetailQueryOptions(client, id) {
13
+ return getSlotQueryOptions(client, id);
14
+ }
15
+ export function getAvailabilitySlotProductQueryOptions(client, productId) {
16
+ return getProductQueryOptions(client, productId);
17
+ }
18
+ export function getAvailabilitySlotPickupsQueryOptions(client, id) {
19
+ return getSlotPickupsQueryOptions(client, id, { limit: 25, offset: 0 });
20
+ }
21
+ export function getAvailabilitySlotPickupPointsQueryOptions(client, productId) {
22
+ return getPickupPointsQueryOptions(client, {
23
+ productId: productId ?? undefined,
24
+ limit: 25,
25
+ offset: 0,
26
+ });
27
+ }
28
+ export function getAvailabilitySlotCloseoutsQueryOptions(client, id) {
29
+ return getSlotCloseoutsQueryOptions(client, id, { limit: 25, offset: 0 });
30
+ }
31
+ export function getAvailabilitySlotAssignmentsQueryOptions(client, id) {
32
+ return getSlotAssignmentsQueryOptions(client, id, { limit: 25, offset: 0 });
33
+ }
34
+ export function getAvailabilitySlotResourcesQueryOptions(client) {
35
+ return getSlotResourcesQueryOptions(client, { limit: 25, offset: 0 });
36
+ }
37
+ export function getAvailabilitySlotAllocationQueryOptions(client, id) {
38
+ return getSlotAllocationQueryOptions(client, id);
39
+ }
40
+ export async function loadAvailabilitySlotDetailPage(queryClient, client, id) {
41
+ const slotData = await queryClient.ensureQueryData(getAvailabilitySlotDetailQueryOptions(client, id));
42
+ return Promise.all([
43
+ Promise.resolve(slotData),
44
+ queryClient.ensureQueryData(getAvailabilitySlotPickupsQueryOptions(client, id)),
45
+ queryClient.ensureQueryData(getAvailabilitySlotCloseoutsQueryOptions(client, id)),
46
+ queryClient.ensureQueryData(getAvailabilitySlotAssignmentsQueryOptions(client, id)),
47
+ queryClient.ensureQueryData(getAvailabilitySlotResourcesQueryOptions(client)),
48
+ queryClient.ensureQueryData(getAvailabilitySlotAllocationQueryOptions(client, id)),
49
+ queryClient.ensureQueryData(getAvailabilitySlotProductQueryOptions(client, slotData.data.productId)),
50
+ queryClient.ensureQueryData(getAvailabilitySlotPickupPointsQueryOptions(client, slotData.data.productId)),
51
+ ]);
52
+ }
53
+ export function AvailabilitySlotDetailPage({ id, className, onBack: _onBack, onDeleted, onOpenProduct, onOpenStartTime, onCreateBooking, onEdit, breadcrumb, headerActions, renderAllocation, renderExtras, extrasTabLabel, }) {
54
+ const client = useVoyantAvailabilityContext();
55
+ const i18n = useAvailabilityUiI18nOrDefault();
56
+ const messages = i18n.messages;
57
+ const detailMessages = messages.details;
58
+ const noValue = detailMessages.noValue;
59
+ const slotMutation = useAvailabilitySlotMutation();
60
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
61
+ const { data: slotData, isPending } = useQuery(getAvailabilitySlotDetailQueryOptions(client, id));
62
+ const slot = slotData?.data;
63
+ const productQuery = useQuery({
64
+ ...getAvailabilitySlotProductQueryOptions(client, slot?.productId ?? ""),
65
+ enabled: Boolean(slot?.productId),
66
+ });
67
+ const slotPickupsQuery = useQuery(getAvailabilitySlotPickupsQueryOptions(client, id));
68
+ const pickupPointsQuery = useQuery({
69
+ ...getAvailabilitySlotPickupPointsQueryOptions(client, slot?.productId ?? ""),
70
+ enabled: Boolean(slot?.productId),
71
+ });
72
+ const closeoutsQuery = useQuery(getAvailabilitySlotCloseoutsQueryOptions(client, id));
73
+ const assignmentsQuery = useQuery(getAvailabilitySlotAssignmentsQueryOptions(client, id));
74
+ const resourcesQuery = useQuery(getAvailabilitySlotResourcesQueryOptions(client));
75
+ const allocationQuery = useQuery(getAvailabilitySlotAllocationQueryOptions(client, id));
76
+ const auditLogQuery = useSlotAllocationAuditLog({ slotId: id });
77
+ if (isPending) {
78
+ return _jsx(AvailabilitySlotDetailSkeleton, {});
79
+ }
80
+ if (!slot) {
81
+ return (_jsx("div", { className: "flex flex-col items-center justify-center gap-4 py-12", children: _jsx("p", { className: "text-muted-foreground", children: detailMessages.slot.notFound }) }));
82
+ }
83
+ const pickupPointById = new Map((pickupPointsQuery.data?.data ?? []).map((item) => [item.id, item]));
84
+ const resourceById = new Map((resourcesQuery.data?.data ?? []).map((item) => [item.id, item]));
85
+ const allocationBookings = allocationQuery.data?.data.bookings ?? [];
86
+ const bookingById = new Map(allocationBookings.map((item) => [item.id, item]));
87
+ const travelerById = new Map();
88
+ for (const booking of allocationBookings) {
89
+ for (const traveler of booking.travelers) {
90
+ travelerById.set(traveler.id, {
91
+ fullName: traveler.fullName,
92
+ bookingNumber: traveler.bookingNumber,
93
+ bookingId: traveler.bookingId,
94
+ });
95
+ }
96
+ }
97
+ const productSellCurrency = productQuery.data?.data.sellCurrency ?? null;
98
+ const financialRollup = aggregateSlotFinancials(allocationBookings, productSellCurrency);
99
+ const productName = productQuery.data?.data.name ?? null;
100
+ const productTypeName = productQuery.data?.data.productType?.name ?? null;
101
+ const dateRangeLabel = formatSlotDateRange(slot);
102
+ const nightsLabel = computeSlotNightsLabel(slot, detailMessages.duration);
103
+ const titleText = productName ?? dateRangeLabel;
104
+ const flagBadges = [
105
+ slot.unlimited ? detailMessages.slot.unlimitedLabel : null,
106
+ slot.pastCutoff ? detailMessages.slot.pastCutoffLabel : null,
107
+ slot.tooEarly ? detailMessages.slot.tooEarlyLabel : null,
108
+ ].filter((value) => Boolean(value));
109
+ const pickupRows = slotPickupsQuery.data?.data ?? [];
110
+ const assignmentRows = assignmentsQuery.data?.data ?? [];
111
+ const closeoutRows = closeoutsQuery.data?.data ?? [];
112
+ const auditEntries = auditLogQuery.data?.data ?? [];
113
+ const handleDelete = async () => {
114
+ await slotMutation.remove.mutateAsync(slot.id);
115
+ setDeleteDialogOpen(false);
116
+ onDeleted?.();
117
+ };
118
+ const fallbackActions = headerActions ?? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [slot.productId && onCreateBooking ? (_jsxs(Button, { variant: "outline", onClick: () => onCreateBooking({ slotId: id, productId: slot.productId }), children: [_jsx(BookOpen, { "data-icon": "inline-start", "aria-hidden": "true" }), detailMessages.createBooking] })) : null, onEdit ? (_jsxs(Button, { variant: "outline", onClick: onEdit, children: [_jsx(Pencil, { "data-icon": "inline-start", "aria-hidden": "true" }), detailMessages.editSlot] })) : null, slot.productId && onOpenProduct ? (_jsxs(Button, { variant: "outline", onClick: () => onOpenProduct(slot.productId), children: [_jsx(Package, { "data-icon": "inline-start", "aria-hidden": "true" }), detailMessages.openProduct] })) : null, _jsx(Button, { variant: "destructive", onClick: () => setDeleteDialogOpen(true), disabled: slotMutation.remove.isPending, children: detailMessages.delete }), _jsx(AlertDialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: detailMessages.slot.deleteConfirm }), _jsx(AlertDialogDescription, { children: detailMessages.slot.deleteDescription })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: detailMessages.slot.deleteCancel }), _jsx(AlertDialogAction, { variant: "destructive", onClick: () => void handleDelete(), disabled: slotMutation.remove.isPending, children: detailMessages.slot.deleteConfirmAction })] })] }) })] }));
119
+ return (_jsxs("div", { className: cn("flex flex-col gap-6 p-6", className), children: [breadcrumb ? _jsx("div", { className: "text-sm", children: breadcrumb }) : null, _jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-start md:justify-between", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsx("h1", { className: "text-2xl font-bold tracking-tight", children: titleText }), _jsx(Badge, { variant: "outline", className: slotStatusToneClass[slotStatusTone[slot.status]], children: getSlotStatusLabel(slot.status, messages) }), productTypeName ? _jsx(Badge, { variant: "outline", children: productTypeName }) : null] }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-sm text-muted-foreground", children: [_jsxs("span", { children: [dateRangeLabel, nightsLabel ? ` · ${nightsLabel}` : null] }), _jsx(Badge, { variant: "outline", children: slot.timezone })] }), flagBadges.length > 0 ? (_jsx("div", { className: "mt-2 flex flex-wrap items-center gap-2", children: flagBadges.map((label) => (_jsx(Badge, { variant: "secondary", children: label }, label))) })) : null] }), fallbackActions] }), _jsx(KpiStrip, { slot: slot, rollup: financialRollup, formatCurrency: i18n.formatCurrency, i18nLabels: {
120
+ pax: detailMessages.slot.paxKpiLabel,
121
+ total: detailMessages.slot.totalKpiLabel,
122
+ paid: detailMessages.slot.paidKpiLabel,
123
+ outstanding: detailMessages.slot.outstandingKpiLabel,
124
+ mixedHint: detailMessages.slot.mixedCurrenciesHint,
125
+ noValue,
126
+ } }), _jsxs(Tabs, { defaultValue: "allocation", children: [_jsxs(TabsList, { className: "flex h-auto w-fit flex-wrap justify-start", children: [_jsx(TabsTrigger, { value: "allocation", children: detailMessages.tabs.allocation }), renderExtras ? (_jsx(TabsTrigger, { value: "extras", children: extrasTabLabel ?? detailMessages.tabs.extras })) : null, pickupRows.length > 0 ? (_jsxs(TabsTrigger, { value: "pickup", children: [detailMessages.tabs.pickup, _jsx(Badge, { variant: "outline", className: "ml-1.5", children: pickupRows.length })] })) : null, closeoutRows.length > 0 ? (_jsxs(TabsTrigger, { value: "closeouts", children: [detailMessages.tabs.closeouts, _jsx(Badge, { variant: "outline", className: "ml-1.5", children: closeoutRows.length })] })) : null, _jsxs(TabsTrigger, { value: "activity", children: [detailMessages.tabs.activity, auditEntries.length > 0 ? (_jsx(Badge, { variant: "outline", className: "ml-1.5", children: auditEntries.length })) : null] }), _jsx(TabsTrigger, { value: "meta", children: detailMessages.tabs.meta })] }), _jsx(TabsContent, { value: "allocation", className: "mt-4", children: renderAllocation ? (renderAllocation({ slotId: id, productId: slot.productId })) : (_jsx("p", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: detailMessages.tabs.allocationUnwired })) }), renderExtras ? (_jsx(TabsContent, { value: "extras", className: "mt-4", children: renderExtras({ slotId: id, productId: slot.productId }) })) : null, pickupRows.length > 0 ? (_jsx(TabsContent, { value: "pickup", className: "mt-4", children: _jsx("div", { className: "flex flex-col gap-3 text-sm", children: pickupRows.map((pickup) => {
127
+ const point = pickupPointById.get(pickup.pickupPointId);
128
+ return (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center gap-2 font-medium", children: [_jsx(Truck, { className: "size-4", "aria-hidden": "true" }), point?.name ?? pickup.pickupPointId] }), _jsx("div", { className: "mt-1 text-muted-foreground", children: point?.locationText ?? detailMessages.slot.noLocationText }), _jsxs("div", { className: "mt-2", children: [detailMessages.slot.initialLabel, ": ", pickup.initialCapacity ?? noValue, " \u00B7", " ", detailMessages.slot.remainingLabel, ": ", pickup.remainingCapacity ?? noValue] })] }, pickup.id));
129
+ }) }) })) : null, closeoutRows.length > 0 ? (_jsx(TabsContent, { value: "closeouts", className: "mt-4", children: _jsx("div", { className: "flex flex-col gap-3 text-sm", children: closeoutRows.map((closeout) => (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center gap-2 font-medium", children: [_jsx(CalendarDays, { className: "size-4", "aria-hidden": "true" }), closeout.dateLocal] }), _jsxs("div", { className: "mt-1 text-muted-foreground", children: [detailMessages.slot.createdByLabel, ": ", closeout.createdBy ?? noValue] }), closeout.reason ? (_jsx("div", { className: "mt-2 whitespace-pre-wrap", children: closeout.reason })) : null] }, closeout.id))) }) })) : null, _jsxs(TabsContent, { value: "activity", className: "mt-4 flex flex-col gap-4", children: [slot.notes ? (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: detailMessages.notesTitle }) }), _jsx(CardContent, { className: "whitespace-pre-wrap text-sm", children: slot.notes })] })) : null, _jsx(ActivityTimeline, { assignments: assignmentRows, auditEntries: auditEntries, resourceById: resourceById, bookingById: bookingById, travelerById: travelerById, formatDateTime: i18n.formatDateTime, i18n: {
130
+ title: detailMessages.tabs.activity,
131
+ empty: detailMessages.tabs.activityEmpty,
132
+ filterAll: detailMessages.tabs.activityFilterAll,
133
+ filterAudit: detailMessages.tabs.activityFilterAudit,
134
+ filterAssignments: detailMessages.tabs.activityFilterAssignments,
135
+ byActor: detailMessages.tabs.activityByActor,
136
+ unassignedResource: detailMessages.slot.unassignedResource,
137
+ bookingLabel: detailMessages.slot.bookingLabel,
138
+ auditActionLabels: detailMessages.tabs.auditActionLabels,
139
+ ongoing: detailMessages.tabs.activityOngoing,
140
+ noValue,
141
+ } })] }), _jsx(TabsContent, { value: "meta", className: "mt-4", children: _jsx(MetaTab, { slot: slot, productName: productName, statusLabel: getSlotStatusLabel(slot.status, messages), onOpenProduct: onOpenProduct, onOpenStartTime: onOpenStartTime, i18n: {
142
+ title: detailMessages.tabs.metaTitle,
143
+ slotIdLabel: detailMessages.tabs.metaSlotId,
144
+ ruleLabel: detailMessages.slot.ruleLabel,
145
+ startTimeLabel: detailMessages.slot.startTimeIdLabel,
146
+ endsAtLabel: detailMessages.slot.endsAtLabel,
147
+ createdLabel: detailMessages.createdLabel,
148
+ updatedLabel: detailMessages.updatedLabel,
149
+ productLabel: messages.productLabel,
150
+ statusLabel: messages.statusLabel,
151
+ timezoneLabel: messages.timezoneLabel,
152
+ noValue,
153
+ format: i18n.formatDateTime,
154
+ } }) })] })] }));
155
+ }
156
+ function KpiStrip({ slot, rollup, formatCurrency, i18nLabels, }) {
157
+ const paxValue = slot.unlimited ? "∞" : `${slot.remainingPax ?? 0} / ${slot.initialPax ?? 0}`;
158
+ const renderAmount = (pick) => {
159
+ if (rollup.entries.length === 0 || !rollup.primaryCurrency) {
160
+ return i18nLabels.noValue;
161
+ }
162
+ const primary = rollup.entries.find((entry) => entry.currency === rollup.primaryCurrency);
163
+ return primary
164
+ ? formatCurrency(pick(primary) / 100, primary.currency)
165
+ : formatCurrency(0, rollup.primaryCurrency);
166
+ };
167
+ const renderHint = (pick) => {
168
+ if (rollup.entries.length <= 1)
169
+ return undefined;
170
+ const others = rollup.entries.filter((entry) => entry.currency !== rollup.primaryCurrency);
171
+ if (others.length === 0)
172
+ return i18nLabels.mixedHint;
173
+ return `+ ${others.map((entry) => formatCurrency(pick(entry) / 100, entry.currency)).join(" · ")}`;
174
+ };
175
+ const primary = rollup.primaryCurrency
176
+ ? rollup.entries.find((entry) => entry.currency === rollup.primaryCurrency)
177
+ : null;
178
+ const paidPercent = primary && primary.sellCents > 0
179
+ ? Math.round((primary.paidCents / primary.sellCents) * 100)
180
+ : null;
181
+ const outstandingPercent = paidPercent != null ? Math.max(0, 100 - paidPercent) : null;
182
+ return (_jsxs("div", { className: "grid grid-cols-2 gap-4 sm:grid-cols-4", children: [_jsx(StatCard, { label: i18nLabels.pax, children: paxValue }), _jsx(StatCard, { label: i18nLabels.total, hint: renderHint((t) => t.sellCents), children: renderAmount((t) => t.sellCents) }), _jsx(StatCard, { label: i18nLabels.paid, hint: renderHint((t) => t.paidCents), badge: paidPercent != null ? renderPercentBadge(paidPercent, paidBadgeClass) : null, children: renderAmount((t) => t.paidCents) }), _jsx(StatCard, { label: i18nLabels.outstanding, hint: renderHint((t) => t.outstandingCents), badge: outstandingPercent != null
183
+ ? renderPercentBadge(outstandingPercent, outstandingBadgeClass)
184
+ : null, children: renderAmount((t) => t.outstandingCents) })] }));
185
+ }
186
+ function StatCard({ label, children, hint, badge, }) {
187
+ return (_jsx(Card, { children: _jsxs(CardContent, { className: "flex flex-col gap-1", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground", children: label }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("div", { className: "text-xl font-semibold tabular-nums leading-none", children: children }), badge] }), hint ? _jsx("div", { className: "text-xs text-muted-foreground", children: hint }) : null] }) }));
188
+ }
189
+ function renderPercentBadge(percent, classFor) {
190
+ return (_jsxs(Badge, { variant: "outline", className: cn("border-transparent", classFor(percent)), children: [percent, "%"] }));
191
+ }
192
+ function paidBadgeClass(percent) {
193
+ if (percent <= 0)
194
+ return "bg-red-500/10 text-red-600 dark:text-red-400";
195
+ if (percent >= 100)
196
+ return "bg-green-500/10 text-green-600 dark:text-green-400";
197
+ return "bg-yellow-500/10 text-yellow-700 dark:text-yellow-400";
198
+ }
199
+ function outstandingBadgeClass(percent) {
200
+ if (percent <= 0)
201
+ return "bg-green-500/10 text-green-600 dark:text-green-400";
202
+ if (percent >= 100)
203
+ return "bg-red-500/10 text-red-600 dark:text-red-400";
204
+ return "bg-yellow-500/10 text-yellow-700 dark:text-yellow-400";
205
+ }
206
+ const FINANCIAL_BOOKING_STATUSES = new Set([
207
+ "on_hold",
208
+ "awaiting_payment",
209
+ "confirmed",
210
+ "in_progress",
211
+ "completed",
212
+ ]);
213
+ export function aggregateSlotFinancials(bookings, productCurrency) {
214
+ const byCurrency = new Map();
215
+ for (const booking of bookings) {
216
+ if (!FINANCIAL_BOOKING_STATUSES.has(booking.status))
217
+ continue;
218
+ const currency = booking.sellCurrency;
219
+ if (!currency)
220
+ continue;
221
+ const sell = booking.sellAmountCents ?? 0;
222
+ const paid = booking.paidAmountCents ?? 0;
223
+ if (sell <= 0 && paid <= 0)
224
+ continue;
225
+ const entry = byCurrency.get(currency) ?? {
226
+ currency,
227
+ sellCents: 0,
228
+ paidCents: 0,
229
+ outstandingCents: 0,
230
+ };
231
+ entry.sellCents += sell;
232
+ entry.paidCents += paid;
233
+ byCurrency.set(currency, entry);
234
+ }
235
+ for (const entry of byCurrency.values()) {
236
+ entry.outstandingCents = Math.max(0, entry.sellCents - entry.paidCents);
237
+ }
238
+ const entries = [...byCurrency.values()].sort((left, right) => right.sellCents - left.sellCents);
239
+ const primaryCurrency = (productCurrency && byCurrency.has(productCurrency) ? productCurrency : null) ??
240
+ entries[0]?.currency ??
241
+ productCurrency ??
242
+ null;
243
+ return { primaryCurrency, entries };
244
+ }
245
+ function MetaTab({ slot, productName, statusLabel, onOpenProduct, onOpenStartTime, i18n: msg, }) {
246
+ const rows = [
247
+ {
248
+ label: msg.slotIdLabel,
249
+ value: _jsx("span", { className: "font-mono text-xs", children: slot.id }),
250
+ },
251
+ {
252
+ label: msg.productLabel,
253
+ value: slot.productId && onOpenProduct ? (_jsx(Button, { variant: "link", className: "h-auto p-0 text-right", onClick: () => onOpenProduct(slot.productId), children: productName ?? slot.productId })) : ((productName ??
254
+ slot.productId ?? _jsx("span", { className: "text-muted-foreground", children: msg.noValue }))),
255
+ },
256
+ {
257
+ label: msg.statusLabel,
258
+ value: (_jsx(Badge, { variant: "outline", className: slotStatusToneClass[slotStatusTone[slot.status]], children: statusLabel })),
259
+ },
260
+ {
261
+ label: msg.timezoneLabel,
262
+ value: _jsx(Badge, { variant: "outline", children: slot.timezone }),
263
+ },
264
+ {
265
+ label: msg.endsAtLabel,
266
+ value: slot.endsAt ? (formatSlotLocalDateTime(slotLocalEnd(slot) ?? slotLocalStart(slot))) : (_jsx("span", { className: "text-muted-foreground", children: msg.noValue })),
267
+ },
268
+ ];
269
+ if (slot.availabilityRuleId) {
270
+ rows.push({
271
+ label: msg.ruleLabel,
272
+ value: _jsx("span", { className: "font-mono text-xs", children: slot.availabilityRuleId }),
273
+ });
274
+ }
275
+ if (slot.startTimeId) {
276
+ rows.push({
277
+ label: msg.startTimeLabel,
278
+ value: onOpenStartTime ? (_jsx(Button, { variant: "link", className: "h-auto p-0 text-right font-mono text-xs", onClick: () => onOpenStartTime(slot.startTimeId ?? ""), children: slot.startTimeId })) : (_jsx("span", { className: "font-mono text-xs", children: slot.startTimeId })),
279
+ });
280
+ }
281
+ rows.push({ label: msg.createdLabel, value: msg.format(slot.createdAt) });
282
+ rows.push({ label: msg.updatedLabel, value: msg.format(slot.updatedAt) });
283
+ return (_jsxs("div", { "data-slot": "slot-metadata", className: "flex flex-col gap-3", children: [_jsxs("h2", { className: "flex items-center gap-2 text-base font-semibold", children: [_jsx(Info, { className: "h-4 w-4 text-muted-foreground", "aria-hidden": "true" }), msg.title] }), _jsx("div", { className: "overflow-hidden rounded-md border bg-background", children: _jsx("dl", { className: "divide-y", children: rows.map((row) => (_jsxs("div", { className: "flex items-center justify-between gap-4 px-4 py-3 text-sm", children: [_jsx("dt", { className: "text-muted-foreground", children: row.label }), _jsx("dd", { className: "text-right", children: row.value })] }, row.label))) }) })] }));
284
+ }
285
+ function formatSlotDateRange(slot) {
286
+ const start = formatSlotLocalDateTime(slotLocalStart(slot));
287
+ if (!slot.endsAt)
288
+ return start;
289
+ return `${start} → ${formatSlotLocalDateTime(slotLocalEnd(slot) ?? slotLocalStart(slot))}`;
290
+ }
291
+ function formatSlotLocalDateTime(value) {
292
+ return `${value.date} ${value.time}`;
293
+ }
294
+ function computeSlotNightsLabel(slot, labels) {
295
+ if (slot.nights && slot.nights > 0) {
296
+ return slot.nights === 1
297
+ ? labels.nightSingular
298
+ : labels.nightsPlural.replace("{count}", String(slot.nights));
299
+ }
300
+ if (slot.days && slot.days > 0) {
301
+ return slot.days === 1
302
+ ? labels.daySingular
303
+ : labels.daysPlural.replace("{count}", String(slot.days));
304
+ }
305
+ return null;
306
+ }
307
+ const AUDIT_ACTION_ICONS = {
308
+ "resource.create": Plus,
309
+ "resource.update": Pencil,
310
+ "resource.delete": Trash2,
311
+ "traveler.assign": UserPlus,
312
+ "traveler.unassign": UserMinus,
313
+ "resources.materialize": Sparkles,
314
+ "auto-allocate": Sparkles,
315
+ };
316
+ function humanizeAction(action, labels) {
317
+ return labels[action] ?? action.replace(/[._-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
318
+ }
319
+ function ActivityTimeline({ assignments, auditEntries, resourceById, bookingById, travelerById, formatDateTime: formatDateTimeFn, i18n, }) {
320
+ const [filter, setFilter] = useState("all");
321
+ const resourceLabel = (id) => (id ? resourceById.get(id)?.name : null) ?? id ?? i18n.unassignedResource;
322
+ const events = [];
323
+ const nowIso = new Date().toISOString();
324
+ for (const assignment of assignments) {
325
+ const resource = resourceLabel(assignment.resourceId);
326
+ const booking = bookingById.get(assignment.bookingId ?? "");
327
+ // Active assignments don't carry a released timestamp. Sort them
328
+ // alongside current activity using `now`, and flag the entry so
329
+ // the row meta line renders "ongoing" instead of formatting the
330
+ // sentinel time.
331
+ const isOngoing = assignment.releasedAt == null;
332
+ events.push({
333
+ id: `assignment:${assignment.id}`,
334
+ source: "assignment",
335
+ icon: Wrench,
336
+ title: resource,
337
+ badge: assignment.status,
338
+ description: (_jsxs("span", { children: [i18n.bookingLabel, ": ", booking?.bookingNumber ?? assignment.bookingId ?? i18n.noValue, assignment.notes ? ` · ${assignment.notes}` : null] })),
339
+ timestamp: assignment.releasedAt ?? nowIso,
340
+ isOngoing,
341
+ actorId: assignment.assignedBy,
342
+ });
343
+ }
344
+ for (const entry of auditEntries) {
345
+ const resource = entry.resourceId ? resourceLabel(entry.resourceId) : null;
346
+ const traveler = entry.travelerId ? travelerById.get(entry.travelerId) : null;
347
+ const detailParts = [];
348
+ if (traveler)
349
+ detailParts.push(traveler.fullName);
350
+ if (resource)
351
+ detailParts.push(resource);
352
+ events.push({
353
+ id: `audit:${entry.id}`,
354
+ source: "audit",
355
+ icon: AUDIT_ACTION_ICONS[entry.action] ?? History,
356
+ title: humanizeAction(entry.action, i18n.auditActionLabels),
357
+ description: detailParts.length > 0 ? detailParts.join(" → ") : null,
358
+ timestamp: entry.createdAt,
359
+ actorId: entry.actorId,
360
+ });
361
+ }
362
+ events.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
363
+ const visible = filter === "all" ? events : events.filter((e) => e.source === filter);
364
+ const hasAssignments = assignments.length > 0;
365
+ const hasAudit = auditEntries.length > 0;
366
+ const filters = [
367
+ { id: "all", label: i18n.filterAll, show: true },
368
+ { id: "assignment", label: i18n.filterAssignments, show: hasAssignments },
369
+ { id: "audit", label: i18n.filterAudit, show: hasAudit },
370
+ ];
371
+ return (_jsxs("div", { "data-slot": "slot-activity-timeline", className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("h2", { className: "flex items-center gap-2 text-base font-semibold", children: [_jsx(Activity, { className: "h-4 w-4 text-muted-foreground", "aria-hidden": "true" }), i18n.title] }), events.length > 0 && hasAssignments && hasAudit ? (_jsx("div", { className: "flex flex-wrap items-center gap-1", children: filters
372
+ .filter((f) => f.show)
373
+ .map((f) => (_jsx(Button, { variant: filter === f.id ? "default" : "ghost", size: "sm", className: "h-7 capitalize", onClick: () => setFilter(f.id), children: f.label }, f.id))) })) : null] }), visible.length === 0 ? (_jsx("div", { className: "rounded-md border bg-background p-6 text-center", children: _jsx("p", { className: "text-sm text-muted-foreground", children: i18n.empty }) })) : (_jsx("div", { className: "flex flex-col gap-2", children: visible.map((event) => (_jsx(ActivityTimelineItem, { event: event, formatDateTime: formatDateTimeFn, byActor: i18n.byActor, ongoingLabel: i18n.ongoing }, event.id))) }))] }));
374
+ }
375
+ function ActivityTimelineItem({ event, formatDateTime: formatDateTimeFn, byActor, ongoingLabel, }) {
376
+ const Icon = event.icon;
377
+ const timestamp = event.isOngoing ? ongoingLabel : formatDateTimeFn(event.timestamp);
378
+ const actor = event.actorId && event.actorId !== "system" ? event.actorId : null;
379
+ const meta = actor
380
+ ? byActor.replace("{actor}", actor).replace("{timestamp}", timestamp)
381
+ : timestamp;
382
+ return (_jsxs("div", { className: "flex items-start gap-3 rounded-md border p-3", children: [_jsx(Icon, { className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "text-sm font-medium capitalize", children: event.title }), event.badge ? (_jsx(Badge, { variant: "outline", className: "text-xs capitalize", children: event.badge })) : null] }), event.description ? (_jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: event.description })) : null, _jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: meta })] })] }));
383
+ }
@@ -0,0 +1,246 @@
1
+ import type { QueryClient } from "@tanstack/react-query";
2
+ import { type VoyantAvailabilityContextValue } from "../index.js";
3
+ export interface AvailabilityStartTimeDetailPageProps {
4
+ id: string;
5
+ className?: string;
6
+ onBack?: () => void;
7
+ onDeleted?: () => void;
8
+ onOpenProduct?: (productId: string) => void;
9
+ onOpenSlot?: (slotId: string) => void;
10
+ confirmAction?: (message: string) => boolean;
11
+ }
12
+ export declare function getAvailabilityStartTimeDetailQueryOptions(client: VoyantAvailabilityContextValue, id: string | null | undefined): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
13
+ data: {
14
+ id: string;
15
+ productId: string;
16
+ optionId: string | null;
17
+ facilityId: string | null;
18
+ label: string | null;
19
+ startTimeLocal: string;
20
+ durationMinutes: number | null;
21
+ sortOrder: number;
22
+ active: boolean;
23
+ productName?: string | null | undefined;
24
+ createdAt?: string | undefined;
25
+ updatedAt?: string | undefined;
26
+ };
27
+ }, Error, {
28
+ data: {
29
+ id: string;
30
+ productId: string;
31
+ optionId: string | null;
32
+ facilityId: string | null;
33
+ label: string | null;
34
+ startTimeLocal: string;
35
+ durationMinutes: number | null;
36
+ sortOrder: number;
37
+ active: boolean;
38
+ productName?: string | null | undefined;
39
+ createdAt?: string | undefined;
40
+ updatedAt?: string | undefined;
41
+ };
42
+ }, readonly ["voyant", "availability", "start-times", "detail", string]>, "queryFn"> & {
43
+ queryFn?: import("@tanstack/react-query").QueryFunction<{
44
+ data: {
45
+ id: string;
46
+ productId: string;
47
+ optionId: string | null;
48
+ facilityId: string | null;
49
+ label: string | null;
50
+ startTimeLocal: string;
51
+ durationMinutes: number | null;
52
+ sortOrder: number;
53
+ active: boolean;
54
+ productName?: string | null | undefined;
55
+ createdAt?: string | undefined;
56
+ updatedAt?: string | undefined;
57
+ };
58
+ }, readonly ["voyant", "availability", "start-times", "detail", string], never> | undefined;
59
+ } & {
60
+ queryKey: readonly ["voyant", "availability", "start-times", "detail", string] & {
61
+ [dataTagSymbol]: {
62
+ data: {
63
+ id: string;
64
+ productId: string;
65
+ optionId: string | null;
66
+ facilityId: string | null;
67
+ label: string | null;
68
+ startTimeLocal: string;
69
+ durationMinutes: number | null;
70
+ sortOrder: number;
71
+ active: boolean;
72
+ productName?: string | null | undefined;
73
+ createdAt?: string | undefined;
74
+ updatedAt?: string | undefined;
75
+ };
76
+ };
77
+ [dataTagErrorSymbol]: Error;
78
+ };
79
+ };
80
+ export declare function getAvailabilityStartTimeSlotsQueryOptions(client: VoyantAvailabilityContextValue, id: string | null | undefined): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
81
+ data: {
82
+ id: string;
83
+ productId: string;
84
+ itineraryId: string | null;
85
+ optionId: string | null;
86
+ facilityId: string | null;
87
+ availabilityRuleId: string | null;
88
+ startTimeId: string | null;
89
+ dateLocal: string;
90
+ startsAt: string;
91
+ endsAt: string | null;
92
+ timezone: string;
93
+ status: "cancelled" | "open" | "closed" | "sold_out";
94
+ unlimited: boolean;
95
+ initialPax: number | null;
96
+ remainingPax: number | null;
97
+ nights: number | null;
98
+ days: number | null;
99
+ notes: string | null;
100
+ productName?: string | null | undefined;
101
+ endDateLocal?: string | null | undefined;
102
+ }[];
103
+ total: number;
104
+ limit: number;
105
+ offset: number;
106
+ }, Error, {
107
+ data: {
108
+ id: string;
109
+ productId: string;
110
+ itineraryId: string | null;
111
+ optionId: string | null;
112
+ facilityId: string | null;
113
+ availabilityRuleId: string | null;
114
+ startTimeId: string | null;
115
+ dateLocal: string;
116
+ startsAt: string;
117
+ endsAt: string | null;
118
+ timezone: string;
119
+ status: "cancelled" | "open" | "closed" | "sold_out";
120
+ unlimited: boolean;
121
+ initialPax: number | null;
122
+ remainingPax: number | null;
123
+ nights: number | null;
124
+ days: number | null;
125
+ notes: string | null;
126
+ productName?: string | null | undefined;
127
+ endDateLocal?: string | null | undefined;
128
+ }[];
129
+ total: number;
130
+ limit: number;
131
+ offset: number;
132
+ }, readonly ["voyant", "availability", "slots", "list", import("../query-keys.js").AvailabilitySlotsListFilters]>, "queryFn"> & {
133
+ queryFn?: import("@tanstack/react-query").QueryFunction<{
134
+ data: {
135
+ id: string;
136
+ productId: string;
137
+ itineraryId: string | null;
138
+ optionId: string | null;
139
+ facilityId: string | null;
140
+ availabilityRuleId: string | null;
141
+ startTimeId: string | null;
142
+ dateLocal: string;
143
+ startsAt: string;
144
+ endsAt: string | null;
145
+ timezone: string;
146
+ status: "cancelled" | "open" | "closed" | "sold_out";
147
+ unlimited: boolean;
148
+ initialPax: number | null;
149
+ remainingPax: number | null;
150
+ nights: number | null;
151
+ days: number | null;
152
+ notes: string | null;
153
+ productName?: string | null | undefined;
154
+ endDateLocal?: string | null | undefined;
155
+ }[];
156
+ total: number;
157
+ limit: number;
158
+ offset: number;
159
+ }, readonly ["voyant", "availability", "slots", "list", import("../query-keys.js").AvailabilitySlotsListFilters], never> | undefined;
160
+ } & {
161
+ queryKey: readonly ["voyant", "availability", "slots", "list", import("../query-keys.js").AvailabilitySlotsListFilters] & {
162
+ [dataTagSymbol]: {
163
+ data: {
164
+ id: string;
165
+ productId: string;
166
+ itineraryId: string | null;
167
+ optionId: string | null;
168
+ facilityId: string | null;
169
+ availabilityRuleId: string | null;
170
+ startTimeId: string | null;
171
+ dateLocal: string;
172
+ startsAt: string;
173
+ endsAt: string | null;
174
+ timezone: string;
175
+ status: "cancelled" | "open" | "closed" | "sold_out";
176
+ unlimited: boolean;
177
+ initialPax: number | null;
178
+ remainingPax: number | null;
179
+ nights: number | null;
180
+ days: number | null;
181
+ notes: string | null;
182
+ productName?: string | null | undefined;
183
+ endDateLocal?: string | null | undefined;
184
+ }[];
185
+ total: number;
186
+ limit: number;
187
+ offset: number;
188
+ };
189
+ [dataTagErrorSymbol]: Error;
190
+ };
191
+ };
192
+ export declare function loadAvailabilityStartTimeDetailPage(queryClient: QueryClient, client: VoyantAvailabilityContextValue, id: string): Promise<[{
193
+ data: {
194
+ id: string;
195
+ productId: string;
196
+ optionId: string | null;
197
+ facilityId: string | null;
198
+ label: string | null;
199
+ startTimeLocal: string;
200
+ durationMinutes: number | null;
201
+ sortOrder: number;
202
+ active: boolean;
203
+ productName?: string | null | undefined;
204
+ createdAt?: string | undefined;
205
+ updatedAt?: string | undefined;
206
+ };
207
+ }, {
208
+ data: {
209
+ id: string;
210
+ productId: string;
211
+ itineraryId: string | null;
212
+ optionId: string | null;
213
+ facilityId: string | null;
214
+ availabilityRuleId: string | null;
215
+ startTimeId: string | null;
216
+ dateLocal: string;
217
+ startsAt: string;
218
+ endsAt: string | null;
219
+ timezone: string;
220
+ status: "cancelled" | "open" | "closed" | "sold_out";
221
+ unlimited: boolean;
222
+ initialPax: number | null;
223
+ remainingPax: number | null;
224
+ nights: number | null;
225
+ days: number | null;
226
+ notes: string | null;
227
+ productName?: string | null | undefined;
228
+ endDateLocal?: string | null | undefined;
229
+ }[];
230
+ total: number;
231
+ limit: number;
232
+ offset: number;
233
+ }, {
234
+ data: {
235
+ id: string;
236
+ name: string;
237
+ sellCurrency: string | null;
238
+ productType: {
239
+ id: string;
240
+ name: string;
241
+ code: string | null;
242
+ } | null;
243
+ };
244
+ }]>;
245
+ export declare function AvailabilityStartTimeDetailPage({ id, className, onBack, onDeleted, onOpenProduct, onOpenSlot, confirmAction, }: AvailabilityStartTimeDetailPageProps): import("react/jsx-runtime").JSX.Element;
246
+ //# sourceMappingURL=availability-start-time-detail-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability-start-time-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/availability-start-time-detail-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAexD,OAAO,EAYL,KAAK,8BAA8B,EACpC,MAAM,aAAa,CAAA;AAWpB,MAAM,WAAW,oCAAoC;IACnD,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAA;CAC7C;AAED,wBAAgB,0CAA0C,CACxD,MAAM,EAAE,8BAA8B,EACtC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAa9B;AAED,wBAAgB,yCAAyC,CACvD,MAAM,EAAE,8BAA8B,EACtC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAG9B;AAED,wBAAsB,mCAAmC,CACvD,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,8BAA8B,EACtC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAWX;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,EAAE,EACF,SAAS,EACT,MAAM,EACN,SAAS,EACT,aAAa,EACb,UAAU,EACV,aAAkE,GACnE,EAAE,oCAAoC,2CA+HtC"}