@voyantjs/allocation-ui 0.50.8 → 0.51.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.
@@ -62,5 +62,48 @@ export declare function seatName(seat: AllocationResource, messages: AllocationU
62
62
  export declare function parentKindFor(kind: string): "" | "vehicle";
63
63
  export declare function defaultCapacityFor(kind: string): 1 | 2;
64
64
  export declare function kindLabel(kind: string, messages: AllocationUiMessages): string;
65
+ /**
66
+ * Group resources for display by a "sub-type" — `refId` when present,
67
+ * otherwise the leading alphabetic token of `label` ("DBL" from
68
+ * "DBL 1"), otherwise a single "other" bucket. Lets the operator scan
69
+ * all DBLs together instead of an alphabetic interleave of mixed
70
+ * sub-types. Each group also exposes the count and the total person-
71
+ * capacity so the header summary stays consistent with the grid.
72
+ */
73
+ export interface ResourceSubTypeGroup {
74
+ key: string;
75
+ /**
76
+ * Human-readable group label derived from the resource's refId or
77
+ * label prefix. `null` for the catch-all bucket (unlabeled, refId-
78
+ * less resources) — consumers should fall back to a localized
79
+ * "Other" string.
80
+ */
81
+ label: string | null;
82
+ resources: AllocationResource[];
83
+ count: number;
84
+ capacity: number;
85
+ }
86
+ export declare function groupResourcesBySubType(resources: AllocationResource[]): ResourceSubTypeGroup[];
87
+ export interface ResourceCapacitySummary {
88
+ resourceCount: number;
89
+ resourceCapacity: number;
90
+ slotPax: number | null;
91
+ slotRemainingPax: number | null;
92
+ delta: number | null;
93
+ status: "fits" | "exact" | "over" | "unbounded";
94
+ }
95
+ /**
96
+ * Roll up slot pax vs. resource person-capacity into a single summary
97
+ * the header can render as a coloured pill. `slotPax` is the slot's
98
+ * `initialPax` when finite; if the slot is `unlimited` or has no
99
+ * initial pax we treat it as unbounded and the operator only sees the
100
+ * total resource capacity without a delta.
101
+ */
102
+ export declare function summarizeResourceCapacity(input: {
103
+ resources: AllocationResource[];
104
+ slotInitialPax: number | null | undefined;
105
+ slotRemainingPax: number | null | undefined;
106
+ unlimited: boolean;
107
+ }): ResourceCapacitySummary;
65
108
  export declare function flagString(value: unknown): string | null;
66
109
  //# sourceMappingURL=slot-allocation-model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slot-allocation-model.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAElG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAE5D,eAAO,MAAM,SAAS,SAAS,CAAA;AAC/B,eAAO,MAAM,YAAY,YAAY,CAAA;AACrC,eAAO,MAAM,iBAAiB,iBAAiB,CAAA;AAC/C,eAAO,MAAM,iBAAiB,aAA0B,CAAA;AAExD,MAAM,MAAM,mBAAmB,GAAG;IAChC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,0BAA0B,EAAE,CAAC,CAAA;IACrD,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAA;IACrD,WAAW,EAAE,0BAA0B,EAAE,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,0BAA0B,EAAE,EACvC,SAAS,EAAE,kBAAkB,EAAE,EAC/B,IAAI,EAAE,MAAM,GACX,mBAAmB,CAmBrB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,SAAS,EACT,SAAS,EACT,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,SAAS,EAAE,0BAA0B,EAAE,CAAA;IACvC,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,SAAS,EAAE,mBAAmB,CAAA;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,oBAAoB,CAAA;CAC/B,qBA4BA;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,0BAA0B,EAAE,EAAE,IAAI,EAAE,MAAM,YAevF;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,kBAAkB,EAAE,EAC3B,QAAQ,EAAE,kBAAkB,EAAE,EAC9B,QAAQ,EAAE,oBAAoB;;;;;;;;;;;;;;;QAKtB,MAAM;WAAS,MAAM;eAAa,MAAM;IA0BjD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,kBAAkB,EAAE;;;;;;;;;;;;;;;;IAenD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,oBAAoB,UAKhF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,kBAEzC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,SAE9C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,UAMrE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,iBAExC"}
1
+ {"version":3,"file":"slot-allocation-model.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-model.ts"],"names":[],"mappings":"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"}
@@ -125,6 +125,65 @@ export function kindLabel(kind, messages) {
125
125
  return messages.flightSeats;
126
126
  return titleCaseKind(kind);
127
127
  }
128
+ export function groupResourcesBySubType(resources) {
129
+ const buckets = new Map();
130
+ for (const resource of resources) {
131
+ const { key, label } = resourceSubTypeKey(resource);
132
+ const bucket = buckets.get(key) ?? { key, label, resources: [] };
133
+ bucket.resources.push(resource);
134
+ buckets.set(key, bucket);
135
+ }
136
+ return Array.from(buckets.values())
137
+ .map((bucket) => ({
138
+ key: bucket.key,
139
+ label: bucket.label,
140
+ resources: bucket.resources,
141
+ count: bucket.resources.length,
142
+ capacity: bucket.resources.reduce((sum, resource) => sum + resource.capacity, 0),
143
+ }))
144
+ .sort((a, b) => (a.label ?? "").localeCompare(b.label ?? "") || a.key.localeCompare(b.key));
145
+ }
146
+ function resourceSubTypeKey(resource) {
147
+ if (resource.refId)
148
+ return { key: `ref:${resource.refId}`, label: resource.refId };
149
+ const label = (resource.label ?? "").trim();
150
+ if (label.length > 0) {
151
+ const prefix = label.match(/^[A-Za-z]+/)?.[0];
152
+ if (prefix)
153
+ return { key: `prefix:${prefix.toUpperCase()}`, label: prefix.toUpperCase() };
154
+ }
155
+ return { key: "other", label: null };
156
+ }
157
+ /**
158
+ * Roll up slot pax vs. resource person-capacity into a single summary
159
+ * the header can render as a coloured pill. `slotPax` is the slot's
160
+ * `initialPax` when finite; if the slot is `unlimited` or has no
161
+ * initial pax we treat it as unbounded and the operator only sees the
162
+ * total resource capacity without a delta.
163
+ */
164
+ export function summarizeResourceCapacity(input) {
165
+ const resourceCapacity = input.resources.reduce((sum, resource) => sum + resource.capacity, 0);
166
+ const slotPax = input.unlimited ? null : (input.slotInitialPax ?? null);
167
+ if (slotPax == null) {
168
+ return {
169
+ resourceCount: input.resources.length,
170
+ resourceCapacity,
171
+ slotPax: null,
172
+ slotRemainingPax: input.unlimited ? null : (input.slotRemainingPax ?? null),
173
+ delta: null,
174
+ status: "unbounded",
175
+ };
176
+ }
177
+ const delta = resourceCapacity - slotPax;
178
+ return {
179
+ resourceCount: input.resources.length,
180
+ resourceCapacity,
181
+ slotPax,
182
+ slotRemainingPax: input.slotRemainingPax ?? null,
183
+ delta,
184
+ status: delta > 0 ? "over" : delta === 0 ? "exact" : "fits",
185
+ };
186
+ }
128
187
  export function flagString(value) {
129
188
  return typeof value === "string" ? value : null;
130
189
  }
@@ -28,6 +28,13 @@ export interface SlotAllocationPageProps {
28
28
  renderBefore?: (context: SlotAllocationPageRenderContext) => ReactNode;
29
29
  renderAfter?: (context: SlotAllocationPageRenderContext) => ReactNode;
30
30
  extraTabs?: SlotAllocationPageExtraTab[];
31
+ /**
32
+ * Drop the top-level page header (title + back arrow). The host is
33
+ * expected to render its own. Capacity badges + the actions cluster
34
+ * stay as an inline toolbar above the kind tabs so the body is
35
+ * still self-sufficient when embedded.
36
+ */
37
+ embed?: boolean;
31
38
  }
32
- export declare function SlotAllocationPage({ slotId, className, onBack, renderExtraActions, renderTravelerActions, renderHeaderEnd, renderBefore, renderAfter, extraTabs, }: SlotAllocationPageProps): import("react/jsx-runtime").JSX.Element;
39
+ export declare function SlotAllocationPage({ slotId, className, onBack, renderExtraActions, renderTravelerActions, renderHeaderEnd, renderBefore, renderAfter, extraTabs, embed, }: SlotAllocationPageProps): import("react/jsx-runtime").JSX.Element;
33
40
  //# sourceMappingURL=slot-allocation-page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slot-allocation-page.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-page.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAO5B,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAkB,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAA;AAiBzE,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,sBAAsB,CAAA;IAChC,SAAS,EAAE,0BAA0B,EAAE,CAAA;IACvC,eAAe,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,SAAS,CAAA;IAChB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,SAAS,CAAA;CAChE;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,SAAS,CAAA;IAC7E,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;IAC3E,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,SAAS,CAAA;IACzE,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,SAAS,CAAA;IACtE,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,SAAS,CAAA;IACrE,SAAS,CAAC,EAAE,0BAA0B,EAAE,CAAA;CACzC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,SAAS,EACT,MAAM,EACN,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,WAAW,EACX,SAAc,GACf,EAAE,uBAAuB,2CA6WzB"}
1
+ {"version":3,"file":"slot-allocation-page.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-page.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,0BAA0B,EAE/B,KAAK,sBAAsB,EAQ5B,MAAM,8BAA8B,CAAA;AAsBrC,OAAO,EAAkB,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAA;AAmBzE,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,sBAAsB,CAAA;IAChC,SAAS,EAAE,0BAA0B,EAAE,CAAA;IACvC,eAAe,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,SAAS,CAAA;IAChB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,SAAS,CAAA;CAChE;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,SAAS,CAAA;IAC7E,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;IAC3E,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,SAAS,CAAA;IACzE,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,SAAS,CAAA;IACtE,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,SAAS,CAAA;IACrE,SAAS,CAAC,EAAE,0BAA0B,EAAE,CAAA;IACxC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,SAAS,EACT,MAAM,EACN,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,WAAW,EACX,SAAc,EACd,KAAa,GACd,EAAE,uBAAuB,2CAybzB"}
@@ -1,17 +1,21 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useAllocationAutomationMutation, useAllocationResourceMutation, useAssignTravelerAllocationMutation, useProductResourceTemplates, useSlotAllocation, useSlotAllocationAuditLog, } from "@voyantjs/availability-react";
4
- import { Button, cn, Input, Label, Tabs, TabsList, TabsTrigger } from "@voyantjs/ui/components";
5
- import { Armchair, ArrowLeft, Bed, Download, Plus, Sparkles, Users, Wand2 } from "lucide-react";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ import { getSlotQueryOptions, useAllocationAutomationMutation, useAllocationResourceMutation, useAssignTravelerAllocationMutation, useProductResourceTemplates, useSlotAllocation, useSlotAllocationAuditLog, useVoyantAvailabilityContext, } from "@voyantjs/availability-react";
5
+ import { Badge, Button, cn, Input, Label, Tabs, TabsList, TabsTrigger, } from "@voyantjs/ui/components";
6
+ import { AlertTriangle, Armchair, ArrowLeft, Bed, Download, Plus, Sparkles, Users, Wand2, } from "lucide-react";
6
7
  import { useMemo, useState } from "react";
7
8
  import { useAllocationUiMessagesOrDefault } from "../i18n/index.js";
8
- import { buildValidationIssues, collectOccupants, defaultCapacityFor, kindLabel, PARENT_ONLY_KINDS, parentKindFor, ROOM_KIND, VEHICLE_SEAT_KIND, } from "./slot-allocation-model.js";
9
+ import { buildValidationIssues, collectOccupants, defaultCapacityFor, kindLabel, PARENT_ONLY_KINDS, parentKindFor, ROOM_KIND, summarizeResourceCapacity, VEHICLE_SEAT_KIND, } from "./slot-allocation-model.js";
9
10
  import { ResourceColumnsView } from "./slot-allocation-resource-view.js";
10
11
  import { VehicleSeatsView } from "./slot-allocation-seat-view.js";
11
12
  import { AuditLogCard, ValidationSummary } from "./slot-allocation-shared.js";
12
- export function SlotAllocationPage({ slotId, className, onBack, renderExtraActions, renderTravelerActions, renderHeaderEnd, renderBefore, renderAfter, extraTabs = [], }) {
13
+ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActions, renderTravelerActions, renderHeaderEnd, renderBefore, renderAfter, extraTabs = [], embed = false, }) {
13
14
  const messages = useAllocationUiMessagesOrDefault();
15
+ const availabilityClient = useVoyantAvailabilityContext();
14
16
  const allocation = useSlotAllocation({ slotId });
17
+ const slotRowQuery = useQuery(getSlotQueryOptions(availabilityClient, slotId));
18
+ const slotRow = slotRowQuery.data?.data;
15
19
  const auditLog = useSlotAllocationAuditLog({ slotId });
16
20
  const resourceMutation = useAllocationResourceMutation(slotId);
17
21
  const assignMutation = useAssignTravelerAllocationMutation(slotId);
@@ -21,7 +25,6 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
21
25
  const [resourceLabel, setResourceLabel] = useState("");
22
26
  const [resourceCapacity, setResourceCapacity] = useState(2);
23
27
  const [error, setError] = useState(null);
24
- const hasPageExtensions = Boolean(renderHeaderEnd || renderBefore || renderAfter || extraTabs.length);
25
28
  const data = allocation.data?.data;
26
29
  const templates = useProductResourceTemplates({
27
30
  productId: data?.slot.productId,
@@ -64,6 +67,48 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
64
67
  const parentResources = useMemo(() => (data?.resources ?? []).filter((resource) => resource.kind === parentKindFor(activeKind)), [data?.resources, activeKind]);
65
68
  const occupants = useMemo(() => collectOccupants(travelers, resources, activeKind), [travelers, resources, activeKind]);
66
69
  const validationIssues = useMemo(() => buildValidationIssues({ travelers, resources, occupants, kind: activeKind, messages }), [travelers, resources, occupants, activeKind, messages]);
70
+ const capacitySummary = useMemo(() => summarizeResourceCapacity({
71
+ resources,
72
+ slotInitialPax: slotRow?.initialPax ?? null,
73
+ slotRemainingPax: slotRow?.remainingPax ?? null,
74
+ unlimited: slotRow?.unlimited ?? false,
75
+ }), [resources, slotRow?.initialPax, slotRow?.remainingPax, slotRow?.unlimited]);
76
+ const projectedSummary = useMemo(() => {
77
+ if (!addingResource)
78
+ return null;
79
+ const capacityNumber = Number.isFinite(resourceCapacity) ? Math.max(0, resourceCapacity) : 0;
80
+ return summarizeResourceCapacity({
81
+ resources: [
82
+ ...resources,
83
+ {
84
+ id: "__projected__",
85
+ slotId,
86
+ kind: activeKind,
87
+ label: null,
88
+ refType: null,
89
+ refId: null,
90
+ capacity: capacityNumber,
91
+ flags: {},
92
+ parentId: null,
93
+ sortOrder: 0,
94
+ createdAt: new Date().toISOString(),
95
+ updatedAt: new Date().toISOString(),
96
+ },
97
+ ],
98
+ slotInitialPax: slotRow?.initialPax ?? null,
99
+ slotRemainingPax: slotRow?.remainingPax ?? null,
100
+ unlimited: slotRow?.unlimited ?? false,
101
+ });
102
+ }, [
103
+ addingResource,
104
+ resourceCapacity,
105
+ resources,
106
+ slotId,
107
+ activeKind,
108
+ slotRow?.initialPax,
109
+ slotRow?.remainingPax,
110
+ slotRow?.unlimited,
111
+ ]);
67
112
  function downloadExport(kind) {
68
113
  globalThis.location.assign(`/v1/admin/availability/slots/${encodeURIComponent(slotId)}/allocation/export-${kind}`);
69
114
  }
@@ -76,29 +121,6 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
76
121
  setError(err instanceof Error ? err.message : messages.allocationFailed);
77
122
  }
78
123
  }
79
- async function swapOrAssignSeat(travelerId, resourceId) {
80
- const traveler = occupants.byTravelerId.get(travelerId);
81
- if (!traveler)
82
- return;
83
- const currentResourceId = traveler.allocations[activeKind] ?? null;
84
- if (currentResourceId === resourceId)
85
- return;
86
- setError(null);
87
- try {
88
- const targetOccupant = (occupants.byResource.get(resourceId) ?? []).find((occupant) => occupant.id !== travelerId);
89
- if (targetOccupant) {
90
- await assignMutation.mutateAsync({
91
- travelerId: targetOccupant.id,
92
- kind: activeKind,
93
- resourceId: currentResourceId,
94
- });
95
- }
96
- await assignMutation.mutateAsync({ travelerId, kind: activeKind, resourceId });
97
- }
98
- catch (err) {
99
- setError(err instanceof Error ? err.message : messages.allocationFailed);
100
- }
101
- }
102
124
  async function createResource(event) {
103
125
  event.preventDefault();
104
126
  setError(null);
@@ -116,6 +138,16 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
116
138
  setError(err instanceof Error ? err.message : messages.createResourceFailed);
117
139
  }
118
140
  }
141
+ async function editResource(resourceId, input) {
142
+ setError(null);
143
+ try {
144
+ await resourceMutation.update.mutateAsync({ resourceId, input });
145
+ }
146
+ catch (err) {
147
+ setError(err instanceof Error ? err.message : messages.updateResourceFailed);
148
+ throw err;
149
+ }
150
+ }
119
151
  async function generateResources() {
120
152
  setError(null);
121
153
  try {
@@ -137,7 +169,14 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
137
169
  if (allocation.isPending) {
138
170
  return (_jsx("div", { className: cn("p-6 text-sm text-muted-foreground", className), children: messages.loading }));
139
171
  }
140
- if (!data || (travelers.length === 0 && !hasPageExtensions)) {
172
+ // Only short-circuit when we genuinely have no data to render
173
+ // against. The page intentionally renders even when both resources
174
+ // and travelers are empty so operators can seed the per-departure
175
+ // resource block before any bookings exist — setting up the room
176
+ // block before selling is the canonical flow. The per-kind resource
177
+ // view handles its own empty state (and the "Add resource" /
178
+ // "Generate resources" affordances stay reachable).
179
+ if (!data) {
141
180
  return (_jsxs("div", { className: cn("flex flex-col items-center justify-center gap-3 p-8", className), children: [_jsx(Users, { className: "size-6 text-muted-foreground", "aria-hidden": "true" }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.empty })] }));
142
181
  }
143
182
  const isSeatMap = activeKind === VEHICLE_SEAT_KIND;
@@ -151,12 +190,39 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
151
190
  travelers,
152
191
  allocationKinds,
153
192
  };
154
- return (_jsxs("div", { className: cn("flex flex-col gap-4 p-6", className), children: [_jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-start md:justify-between", children: [_jsxs("div", { className: "flex items-start gap-3", children: [onBack ? (_jsx(Button, { variant: "ghost", size: "icon", onClick: onBack, "aria-label": messages.back, children: _jsx(ArrowLeft, { "data-icon": true, "aria-hidden": "true" }) })) : null, _jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: messages.pageTitle }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-sm text-muted-foreground", children: [_jsxs("span", { children: [data.summary.travelerCount, " ", messages.travelers] }), selectedExtraTab ? null : (_jsxs("span", { children: [resources.length, " ", kindLabel(activeKind, messages).toLowerCase()] }))] })] })] }), _jsxs("div", { className: "flex flex-col gap-3 md:items-end", children: [renderHeaderEnd?.(context), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [selectedExtraTab ? null : renderExtraActions?.({ slotId, kind: activeKind }), _jsxs(Button, { variant: "outline", onClick: () => downloadExport("passengers"), children: [_jsx(Download, { "data-icon": "inline-start", "aria-hidden": "true" }), messages.exportPassengers] }), _jsxs(Button, { variant: "outline", onClick: () => downloadExport("rooming-list"), children: [_jsx(Download, { "data-icon": "inline-start", "aria-hidden": "true" }), messages.exportRooming] }), selectedExtraTab ? null : resources.length === 0 ? (_jsxs(Button, { variant: "outline", onClick: () => void generateResources(), disabled: automationMutation.autoMaterialize.isPending, children: [_jsx(Sparkles, { "data-icon": "inline-start", "aria-hidden": "true" }), automationMutation.autoMaterialize.isPending
155
- ? messages.generatingResources
156
- : messages.generateResources] })) : (_jsxs(Button, { variant: "outline", onClick: () => void autoAllocate(), disabled: automationMutation.autoAllocate.isPending, children: [_jsx(Wand2, { "data-icon": "inline-start", "aria-hidden": "true" }), automationMutation.autoAllocate.isPending
157
- ? messages.autoAllocating
158
- : messages.autoAllocate] })), !selectedExtraTab && canManuallyAddResource ? (_jsxs(Button, { variant: "outline", onClick: () => {
159
- setResourceCapacity(defaultCapacityFor(activeKind));
160
- setAddingResource((value) => !value);
161
- }, children: [_jsx(Plus, { "data-icon": "inline-start", "aria-hidden": "true" }), messages.addResource] })) : null] })] })] }), renderBefore?.(context), _jsx(Tabs, { value: activeTabId, onValueChange: setSelectedKind, children: _jsxs(TabsList, { className: "flex h-auto w-fit flex-wrap justify-start", children: [allocationKinds.map((kind) => (_jsxs(TabsTrigger, { value: kind, className: "gap-2", children: [kind === VEHICLE_SEAT_KIND ? (_jsx(Armchair, { className: "size-4", "aria-hidden": "true" })) : (_jsx(Bed, { className: "size-4", "aria-hidden": "true" })), kindLabel(kind, messages)] }, kind))), visibleExtraTabs.map((tab) => (_jsxs(TabsTrigger, { value: tab.id, className: "gap-2", children: [tab.icon, tab.label] }, tab.id)))] }) }), selectedExtraTab ? (selectedExtraTab.render(context)) : (_jsxs(_Fragment, { children: [error ? (_jsx("div", { className: "rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: error })) : null, addingResource && canManuallyAddResource ? (_jsxs("form", { className: "grid gap-3 rounded-md border bg-muted/30 p-3 sm:grid-cols-[1fr_8rem_auto_auto]", onSubmit: createResource, children: [_jsxs("div", { className: "grid gap-1", children: [_jsx(Label, { htmlFor: "allocation-resource-label", children: messages.resourceLabel }), _jsx(Input, { id: "allocation-resource-label", value: resourceLabel, onChange: (event) => setResourceLabel(event.target.value), placeholder: activeKind === ROOM_KIND ? "102" : kindLabel(activeKind, messages) })] }), _jsxs("div", { className: "grid gap-1", children: [_jsx(Label, { htmlFor: "allocation-resource-capacity", children: messages.resourceCapacity }), _jsx(Input, { id: "allocation-resource-capacity", type: "number", min: 1, value: resourceCapacity, onChange: (event) => setResourceCapacity(Number(event.target.value) || 1) })] }), _jsx(Button, { type: "submit", className: "self-end", disabled: resourceMutation.create.isPending, children: messages.createResource }), _jsx(Button, { type: "button", variant: "ghost", className: "self-end", onClick: () => setAddingResource(false), children: messages.cancel })] })) : null, _jsx(ValidationSummary, { issues: validationIssues, resources: resources, unallocatedCount: occupants.unallocated.length }), isSeatMap ? (_jsx(VehicleSeatsView, { seats: resources, vehicles: parentResources, occupants: occupants, sharingGroupLabels: data.sharingGroupLabels, onDropTraveler: (travelerId, resourceId) => void swapOrAssignSeat(travelerId, resourceId), onUnassignTraveler: (travelerId) => void assignTraveler(travelerId, null), renderTravelerActions: renderTravelerActions })) : (_jsx(ResourceColumnsView, { kind: activeKind, resources: resources, travelers: travelers, occupants: occupants, sharingGroupLabels: data.sharingGroupLabels, onDropTraveler: (travelerId, resourceId) => void assignTraveler(travelerId, resourceId), onRemoveResource: (resourceId) => void resourceMutation.remove.mutateAsync(resourceId), renderTravelerActions: renderTravelerActions }))] })), renderAfter?.(context), _jsx(AuditLogCard, { entries: auditLog.data?.data ?? [] })] }));
193
+ const summaryLine = (_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm text-muted-foreground", children: [_jsxs("span", { children: [data.summary.travelerCount, " ", messages.travelers] }), selectedExtraTab ? null : (_jsxs("span", { children: [resources.length, " ", kindLabel(activeKind, messages).toLowerCase()] })), selectedExtraTab ? null : (_jsx(CapacitySummaryBadges, { summary: capacitySummary, messages: messages, kind: activeKind }))] }));
194
+ const actionsCluster = (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [selectedExtraTab ? null : renderExtraActions?.({ slotId, kind: activeKind }), _jsxs(Button, { variant: "outline", onClick: () => downloadExport("passengers"), children: [_jsx(Download, { "data-icon": "inline-start", "aria-hidden": "true" }), messages.exportPassengers] }), _jsxs(Button, { variant: "outline", onClick: () => downloadExport("rooming-list"), children: [_jsx(Download, { "data-icon": "inline-start", "aria-hidden": "true" }), messages.exportRooming] }), selectedExtraTab ? null : resources.length === 0 ? (_jsxs(Button, { variant: "outline", onClick: () => void generateResources(), disabled: automationMutation.autoMaterialize.isPending, children: [_jsx(Sparkles, { "data-icon": "inline-start", "aria-hidden": "true" }), automationMutation.autoMaterialize.isPending
195
+ ? messages.generatingResources
196
+ : messages.generateResources] })) : (_jsxs(Button, { variant: "outline", onClick: () => void autoAllocate(), disabled: automationMutation.autoAllocate.isPending, children: [_jsx(Wand2, { "data-icon": "inline-start", "aria-hidden": "true" }), automationMutation.autoAllocate.isPending
197
+ ? messages.autoAllocating
198
+ : messages.autoAllocate] })), !selectedExtraTab && canManuallyAddResource ? (_jsxs(Button, { variant: "outline", onClick: () => {
199
+ setResourceCapacity(defaultCapacityFor(activeKind));
200
+ setAddingResource((value) => !value);
201
+ }, children: [_jsx(Plus, { "data-icon": "inline-start", "aria-hidden": "true" }), messages.addResource] })) : null] }));
202
+ return (_jsxs("div", { className: cn("flex flex-col gap-4", embed ? null : "p-6", className), children: [embed ? (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [summaryLine, actionsCluster] })) : (_jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-start md:justify-between", children: [_jsxs("div", { className: "flex items-start gap-3", children: [onBack ? (_jsx(Button, { variant: "ghost", size: "icon", onClick: onBack, "aria-label": messages.back, children: _jsx(ArrowLeft, { "data-icon": true, "aria-hidden": "true" }) })) : null, _jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: messages.pageTitle }), _jsx("div", { className: "mt-1", children: summaryLine })] })] }), _jsxs("div", { className: "flex flex-col gap-3 md:items-end", children: [renderHeaderEnd?.(context), actionsCluster] })] })), renderBefore?.(context), _jsx(Tabs, { value: activeTabId, onValueChange: setSelectedKind, children: _jsxs(TabsList, { className: "flex h-auto w-fit flex-wrap justify-start", children: [allocationKinds.map((kind) => (_jsxs(TabsTrigger, { value: kind, className: "gap-2", children: [kind === VEHICLE_SEAT_KIND ? (_jsx(Armchair, { className: "size-4", "aria-hidden": "true" })) : (_jsx(Bed, { className: "size-4", "aria-hidden": "true" })), kindLabel(kind, messages)] }, kind))), visibleExtraTabs.map((tab) => (_jsxs(TabsTrigger, { value: tab.id, className: "gap-2", children: [tab.icon, tab.label] }, tab.id)))] }) }), selectedExtraTab ? (selectedExtraTab.render(context)) : (_jsxs(_Fragment, { children: [error ? (_jsx("div", { className: "rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: error })) : null, addingResource && canManuallyAddResource ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("form", { className: "grid gap-3 rounded-md border bg-muted/30 p-3 sm:grid-cols-[1fr_8rem_auto_auto]", onSubmit: createResource, children: [_jsxs("div", { className: "grid gap-1", children: [_jsx(Label, { htmlFor: "allocation-resource-label", children: messages.resourceLabel }), _jsx(Input, { id: "allocation-resource-label", value: resourceLabel, onChange: (event) => setResourceLabel(event.target.value), placeholder: activeKind === ROOM_KIND ? "102" : kindLabel(activeKind, messages) })] }), _jsxs("div", { className: "grid gap-1", children: [_jsx(Label, { htmlFor: "allocation-resource-capacity", children: messages.resourceCapacity }), _jsx(Input, { id: "allocation-resource-capacity", type: "number", min: 1, value: resourceCapacity, onChange: (event) => setResourceCapacity(Number(event.target.value) || 1) })] }), _jsx(Button, { type: "submit", className: "self-end", disabled: resourceMutation.create.isPending, children: messages.createResource }), _jsx(Button, { type: "button", variant: "ghost", className: "self-end", onClick: () => setAddingResource(false), children: messages.cancel })] }), projectedSummary?.status === "over" && projectedSummary.delta != null ? (_jsxs("div", { className: "flex items-start gap-2 rounded-md border border-amber-500/40 bg-amber-50 px-3 py-2 text-sm text-amber-900 dark:bg-amber-950 dark:text-amber-100", role: "status", children: [_jsx(AlertTriangle, { className: "mt-0.5 size-4 shrink-0", "aria-hidden": "true" }), _jsxs("span", { children: [messages.overCapacityWarning, " ", projectedSummary.resourceCapacity, "/", projectedSummary.slotPax ?? "—", " (", messages.resourceCapacityOver, ":", " ", projectedSummary.delta, ")"] })] })) : null] })) : null, _jsx(ValidationSummary, { issues: validationIssues, resources: resources, unallocatedCount: occupants.unallocated.length }), isSeatMap ? (_jsx(VehicleSeatsView, { seats: resources, vehicles: parentResources, occupants: occupants, sharingGroupLabels: data.sharingGroupLabels, onAssignTraveler: (travelerId, resourceId) => void assignTraveler(travelerId, resourceId), onUnassignTraveler: (travelerId) => void assignTraveler(travelerId, null), renderTravelerActions: renderTravelerActions })) : (_jsx(ResourceColumnsView, { kind: activeKind, resources: resources, travelers: travelers, occupants: occupants, sharingGroupLabels: data.sharingGroupLabels, onAssignTraveler: (travelerId, resourceId) => void assignTraveler(travelerId, resourceId), onUnassignTraveler: (travelerId) => void assignTraveler(travelerId, null), onRemoveResource: (resourceId) => void resourceMutation.remove.mutateAsync(resourceId), onEditResource: editResource, renderTravelerActions: renderTravelerActions }))] })), renderAfter?.(context), _jsx(AuditLogCard, { entries: auditLog.data?.data ?? [] })] }));
203
+ }
204
+ function CapacitySummaryBadges({ summary, messages, kind, }) {
205
+ if (summary.resourceCount === 0 && summary.slotPax == null)
206
+ return null;
207
+ const slotLabel = summary.slotPax == null
208
+ ? messages.slotCapacityUnlimited
209
+ : `${summary.slotRemainingPax ?? 0}/${summary.slotPax}`;
210
+ const resourceLabel = summary.slotPax == null
211
+ ? String(summary.resourceCapacity)
212
+ : `${summary.resourceCapacity}/${summary.slotPax}`;
213
+ const deltaVariant = summary.status === "over"
214
+ ? "destructive"
215
+ : summary.status === "exact"
216
+ ? "default"
217
+ : summary.status === "fits"
218
+ ? "secondary"
219
+ : "outline";
220
+ const deltaLabel = summary.status === "over"
221
+ ? `${messages.resourceCapacityOver}: ${summary.delta ?? 0}`
222
+ : summary.status === "exact"
223
+ ? messages.resourceCapacityExact
224
+ : summary.status === "fits"
225
+ ? messages.resourceCapacityFits
226
+ : null;
227
+ return (_jsxs("span", { className: "contents", "data-kind": kind, title: kindLabel(kind, messages), children: [_jsxs(Badge, { variant: "outline", className: "gap-1", children: [_jsx(Users, { className: "size-3", "aria-hidden": "true" }), messages.slotCapacityLabel, ": ", slotLabel] }), _jsxs(Badge, { variant: "outline", className: "gap-1", children: [messages.resourceCapacityLabel, ": ", resourceLabel] }), deltaLabel ? _jsx(Badge, { variant: deltaVariant, children: deltaLabel }) : null] }));
162
228
  }
@@ -1,14 +1,22 @@
1
1
  import type { AllocationManifestTraveler, AllocationResource } from "@voyantjs/availability-react";
2
- import type { ReactNode } from "react";
2
+ import { type ReactNode } from "react";
3
3
  import { type AllocationOccupants } from "./slot-allocation-model.js";
4
- export declare function ResourceColumnsView({ kind, resources, travelers, occupants, sharingGroupLabels, onDropTraveler, onRemoveResource, renderTravelerActions, }: {
4
+ export interface EditResourceInput {
5
+ label: string | null;
6
+ capacity: number;
7
+ }
8
+ export declare function ResourceColumnsView({ kind, resources, travelers, occupants, sharingGroupLabels, onAssignTraveler, onUnassignTraveler, onRemoveResource, onEditResource, renderTravelerActions, }: {
5
9
  kind: string;
6
10
  resources: AllocationResource[];
7
11
  travelers: AllocationManifestTraveler[];
8
12
  occupants: AllocationOccupants;
9
13
  sharingGroupLabels: Record<string, string>;
10
- onDropTraveler: (travelerId: string, resourceId: string | null) => void;
14
+ /** Assign a single unallocated traveler to a specific resource. */
15
+ onAssignTraveler: (travelerId: string, resourceId: string) => void;
16
+ /** Remove a single traveler from their current resource. */
17
+ onUnassignTraveler: (travelerId: string) => void;
11
18
  onRemoveResource: (resourceId: string) => void;
19
+ onEditResource?: (resourceId: string, input: EditResourceInput) => Promise<void> | void;
12
20
  renderTravelerActions?: (traveler: AllocationManifestTraveler) => ReactNode;
13
21
  }): import("react/jsx-runtime").JSX.Element;
14
22
  //# sourceMappingURL=slot-allocation-resource-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slot-allocation-resource-view.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-resource-view.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAGlG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,EAAE,KAAK,mBAAmB,EAAgC,MAAM,4BAA4B,CAAA;AAGnG,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,SAAS,EACT,SAAS,EACT,SAAS,EACT,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,GACtB,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,SAAS,EAAE,0BAA0B,EAAE,CAAA;IACvC,SAAS,EAAE,mBAAmB,CAAA;IAC9B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACvE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9C,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CAC5E,2CAgDA"}
1
+ {"version":3,"file":"slot-allocation-resource-view.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-resource-view.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAuBlG,OAAO,EAAkB,KAAK,SAAS,EAAuB,MAAM,OAAO,CAAA;AAG3E,OAAO,EACL,KAAK,mBAAmB,EAGzB,MAAM,4BAA4B,CAAA;AAGnC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,SAAS,EACT,SAAS,EACT,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,GACtB,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,SAAS,EAAE,0BAA0B,EAAE,CAAA;IACvC,SAAS,EAAE,mBAAmB,CAAA;IAC9B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,mEAAmE;IACnE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAClE,4DAA4D;IAC5D,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9C,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACvF,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CAC5E,2CAgEA"}
@@ -1,16 +1,77 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Badge, Button } from "@voyantjs/ui/components";
4
- import { Armchair, Bed, Trash2, Users } from "lucide-react";
3
+ import { Badge, Button, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Input, Label, Popover, PopoverContent, PopoverTrigger, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@voyantjs/ui/components";
4
+ import { Bed, Pencil, Plus, Trash2, UserMinus, Users, X } from "lucide-react";
5
+ import { useEffect, useState } from "react";
5
6
  import { useAllocationUiMessagesOrDefault } from "../i18n/index.js";
6
- import { kindLabel, VEHICLE_SEAT_KIND } from "./slot-allocation-model.js";
7
- import { DropColumn, ResourceFlagBadges, TravelerTile } from "./slot-allocation-shared.js";
8
- export function ResourceColumnsView({ kind, resources, travelers, occupants, sharingGroupLabels, onDropTraveler, onRemoveResource, renderTravelerActions, }) {
7
+ import { groupResourcesBySubType, kindLabel, } from "./slot-allocation-model.js";
8
+ import { AllocationColumn, TravelerTile } from "./slot-allocation-shared.js";
9
+ export function ResourceColumnsView({ kind, resources, travelers, occupants, sharingGroupLabels, onAssignTraveler, onUnassignTraveler, onRemoveResource, onEditResource, renderTravelerActions, }) {
9
10
  const messages = useAllocationUiMessagesOrDefault();
10
- return (_jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(18rem,22rem)_1fr]", children: [_jsx(DropColumn, { id: "unallocated", icon: _jsx(Users, { className: "size-4", "aria-hidden": "true" }), title: messages.unallocated, description: messages.unallocatedDescription, count: occupants.unallocated.length, capacity: travelers.length, onDropTraveler: (travelerId) => onDropTraveler(travelerId, null), children: occupants.unallocated.map((traveler) => (_jsx(TravelerTile, { traveler: traveler, sharingGroupLabel: traveler.sharingGroupId ? sharingGroupLabels[traveler.sharingGroupId] : null, renderActions: renderTravelerActions }, traveler.id))) }), _jsx("div", { className: "grid min-w-0 gap-4 md:grid-cols-2 2xl:grid-cols-3", children: resources.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: messages.noResources })) : (resources.map((resource) => (_jsx(AllocationResourceColumn, { kind: kind, resource: resource, occupants: occupants.byResource.get(resource.id) ?? [], sharingGroupLabels: sharingGroupLabels, onDropTraveler: (travelerId) => onDropTraveler(travelerId, resource.id), onRemoveResource: () => onRemoveResource(resource.id), renderTravelerActions: renderTravelerActions }, resource.id)))) })] }));
11
+ return (_jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(18rem,22rem)_1fr]", children: [_jsx(AllocationColumn, { id: "unallocated", icon: _jsx(Users, { className: "size-4", "aria-hidden": "true" }), title: messages.unallocated, description: messages.unallocatedDescription, count: occupants.unallocated.length, capacity: travelers.length, children: occupants.unallocated.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: messages.unallocatedEmpty })) : (occupants.unallocated.map((traveler) => (_jsx(TravelerTile, { traveler: traveler, sharingGroupLabel: traveler.sharingGroupId ? sharingGroupLabels[traveler.sharingGroupId] : null, renderActions: renderTravelerActions }, traveler.id)))) }), _jsx("div", { className: "flex min-w-0 flex-col gap-6", children: resources.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: messages.noResources })) : (groupResourcesBySubType(resources).map((group) => {
12
+ const groupLabel = group.label ?? messages.resourceOtherGroup;
13
+ return (_jsxs("section", { "aria-label": groupLabel, className: "flex flex-col gap-2", children: [_jsxs("header", { className: "flex items-baseline justify-between gap-2 border-b pb-1", children: [_jsx("h3", { className: "text-sm font-semibold tracking-wide uppercase text-muted-foreground", children: groupLabel }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [group.count, " \u00B7 ", messages.capacity.toLowerCase(), " ", group.capacity] })] }), _jsx(ResourceGroupTable, { kind: kind, resources: group.resources, occupants: occupants, unallocated: occupants.unallocated, sharingGroupLabels: sharingGroupLabels, onAssignTraveler: onAssignTraveler, onUnassignTraveler: onUnassignTraveler, onRemoveResource: onRemoveResource, onEditResource: onEditResource })] }, group.key));
14
+ })) })] }));
11
15
  }
12
- function AllocationResourceColumn({ kind, resource, occupants, onDropTraveler, onRemoveResource, sharingGroupLabels, renderTravelerActions, }) {
16
+ function ResourceGroupTable({ kind, resources, occupants, unallocated, sharingGroupLabels, onAssignTraveler, onUnassignTraveler, onRemoveResource, onEditResource, }) {
13
17
  const messages = useAllocationUiMessagesOrDefault();
14
- const full = occupants.length >= resource.capacity;
15
- return (_jsxs(DropColumn, { id: `allocation-resource:${resource.id}`, icon: kind === VEHICLE_SEAT_KIND ? _jsx(Armchair, { className: "size-4" }) : _jsx(Bed, { className: "size-4" }), title: resource.label ?? kindLabel(kind, messages), description: `${messages.capacity}: ${occupants.length}/${resource.capacity}`, count: occupants.length, capacity: resource.capacity, disabled: full, onDropTraveler: onDropTraveler, action: _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: onRemoveResource, children: _jsx(Trash2, { className: "size-4", "aria-hidden": "true" }) }), children: [_jsx(ResourceFlagBadges, { resource: resource }), full ? (_jsx(Badge, { variant: "secondary", className: "w-fit", children: messages.overCapacity })) : null, occupants.map((traveler) => (_jsx(TravelerTile, { traveler: traveler, sharingGroupLabel: traveler.sharingGroupId ? sharingGroupLabels[traveler.sharingGroupId] : null, renderActions: renderTravelerActions }, traveler.id))), !full ? (_jsx("div", { className: "rounded-md border border-dashed p-3 text-xs text-muted-foreground", children: messages.dropHere })) : null] }));
18
+ const [editingId, setEditingId] = useState(null);
19
+ return (_jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { className: "bg-muted/40", children: [_jsx(TableHead, { className: "w-48", children: messages.resourceLabel }), _jsx(TableHead, { className: "w-20 text-center", children: messages.capacity }), _jsx(TableHead, { children: messages.travelers }), _jsx(TableHead, { className: "w-40 text-right", children: "\u00A0" })] }) }), _jsx(TableBody, { children: resources.map((resource) => {
20
+ const seated = occupants.byResource.get(resource.id) ?? [];
21
+ const isEditing = editingId === resource.id;
22
+ const isFull = seated.length >= resource.capacity;
23
+ return (_jsx(ResourceRow, { kind: kind, resource: resource, seated: seated, unallocated: unallocated, sharingGroupLabels: sharingGroupLabels, isEditing: isEditing, isFull: isFull, canEdit: Boolean(onEditResource), onBeginEdit: () => setEditingId(resource.id), onCancelEdit: () => setEditingId(null), onSaveEdit: async (input) => {
24
+ await Promise.resolve(onEditResource?.(resource.id, input));
25
+ setEditingId(null);
26
+ }, onAssignTraveler: (travelerId) => onAssignTraveler(travelerId, resource.id), onUnassignTraveler: onUnassignTraveler, onRemoveResource: () => onRemoveResource(resource.id) }, resource.id));
27
+ }) })] }) }));
28
+ }
29
+ function ResourceRow({ kind, resource, seated, unallocated, sharingGroupLabels, isEditing, isFull, canEdit, onBeginEdit, onCancelEdit, onSaveEdit, onAssignTraveler, onUnassignTraveler, onRemoveResource, }) {
30
+ const messages = useAllocationUiMessagesOrDefault();
31
+ const overCapacity = seated.length > resource.capacity;
32
+ if (isEditing && canEdit) {
33
+ return (_jsx(TableRow, { className: "bg-muted/30", children: _jsx(TableCell, { colSpan: 4, className: "whitespace-normal", children: _jsx(ResourceEditForm, { kind: kind, resource: resource, minCapacity: Math.max(1, seated.length), onCancel: onCancelEdit, onSave: onSaveEdit }) }) }));
34
+ }
35
+ return (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: _jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx(Bed, { className: "size-4 text-muted-foreground", "aria-hidden": "true" }), resource.label ?? kindLabel(kind, messages)] }) }), _jsx(TableCell, { className: "text-center", children: _jsxs(Badge, { variant: overCapacity ? "destructive" : "outline", children: [seated.length, "/", resource.capacity] }) }), _jsx(TableCell, { className: "whitespace-normal py-2", children: _jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [seated.map((traveler) => (_jsx(TravelerChip, { traveler: traveler, sharingGroupLabel: traveler.sharingGroupId
36
+ ? (sharingGroupLabels[traveler.sharingGroupId] ?? null)
37
+ : null, onUnassign: () => onUnassignTraveler(traveler.id) }, traveler.id))), !isFull ? (_jsx(AssignTravelerPopover, { unallocated: unallocated, onSelect: (travelerId) => onAssignTraveler(travelerId) })) : null] }) }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "inline-flex items-center justify-end gap-1", children: [canEdit ? (_jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: onBeginEdit, "aria-label": messages.editResource, children: _jsx(Pencil, { className: "size-4", "aria-hidden": "true" }) })) : null, _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: onRemoveResource, "aria-label": messages.remove, children: _jsx(Trash2, { className: "size-4", "aria-hidden": "true" }) })] }) })] }));
38
+ }
39
+ function TravelerChip({ traveler, sharingGroupLabel, onUnassign, }) {
40
+ const messages = useAllocationUiMessagesOrDefault();
41
+ return (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full border bg-background px-2 py-0.5 text-xs", children: [_jsx("span", { className: "truncate font-medium", title: sharingGroupLabel ?? undefined, children: traveler.fullName }), _jsx("span", { className: "text-muted-foreground", children: traveler.bookingNumber }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-4 rounded-full", onClick: onUnassign, "aria-label": `${messages.remove}: ${traveler.fullName}`, children: _jsx(X, { className: "size-3", "aria-hidden": "true" }) })] }));
42
+ }
43
+ function AssignTravelerPopover({ unallocated, onSelect, }) {
44
+ const messages = useAllocationUiMessagesOrDefault();
45
+ const [open, setOpen] = useState(false);
46
+ const disabled = unallocated.length === 0;
47
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { render: _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "h-7 gap-1 px-2 text-xs", disabled: disabled, "aria-label": messages.assignTraveler, title: disabled ? messages.assignTravelerEmpty : messages.assignTraveler, children: [_jsx(Plus, { className: "size-3.5", "aria-hidden": "true" }), messages.assignTraveler] }) }), _jsx(PopoverContent, { className: "w-72 p-0", align: "start", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: messages.assignTravelerSearch }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: messages.assignTravelerEmpty }), _jsx(CommandGroup, { children: unallocated.map((traveler) => (_jsxs(CommandItem, { value: `${traveler.fullName} ${traveler.bookingNumber}`, onSelect: () => {
48
+ onSelect(traveler.id);
49
+ setOpen(false);
50
+ }, children: [_jsx(UserMinus, { className: "mr-2 size-4 text-muted-foreground", "aria-hidden": "true" }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "font-medium", children: traveler.fullName }), _jsx("span", { className: "text-xs text-muted-foreground", children: traveler.bookingNumber })] })] }, traveler.id))) })] })] }) })] }));
51
+ }
52
+ function ResourceEditForm({ kind, resource, minCapacity, onCancel, onSave, }) {
53
+ const messages = useAllocationUiMessagesOrDefault();
54
+ const [label, setLabel] = useState(resource.label ?? "");
55
+ const [capacity, setCapacity] = useState(resource.capacity);
56
+ const [saving, setSaving] = useState(false);
57
+ useEffect(() => {
58
+ setLabel(resource.label ?? "");
59
+ setCapacity(resource.capacity);
60
+ }, [resource.label, resource.capacity]);
61
+ async function submit(event) {
62
+ event.preventDefault();
63
+ const trimmed = label.trim();
64
+ const nextCapacity = Math.max(minCapacity, Math.floor(capacity) || minCapacity);
65
+ setSaving(true);
66
+ try {
67
+ await onSave({
68
+ label: trimmed.length === 0 ? null : trimmed,
69
+ capacity: nextCapacity,
70
+ });
71
+ }
72
+ finally {
73
+ setSaving(false);
74
+ }
75
+ }
76
+ return (_jsxs("form", { className: "grid gap-2 sm:grid-cols-[1fr_8rem_auto_auto] sm:items-end", onSubmit: submit, "aria-label": messages.editResource, children: [_jsxs("div", { className: "grid gap-1", children: [_jsx(Label, { htmlFor: `edit-${resource.id}-label`, className: "text-xs", children: messages.resourceLabel }), _jsx(Input, { id: `edit-${resource.id}-label`, value: label, onChange: (event) => setLabel(event.target.value), placeholder: kindLabel(kind, messages) })] }), _jsxs("div", { className: "grid gap-1", children: [_jsx(Label, { htmlFor: `edit-${resource.id}-capacity`, className: "text-xs", children: messages.resourceCapacity }), _jsx(Input, { id: `edit-${resource.id}-capacity`, type: "number", min: minCapacity, value: capacity, onChange: (event) => setCapacity(Number(event.target.value) || minCapacity) })] }), _jsx(Button, { type: "submit", size: "sm", disabled: saving, children: messages.saveResource }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onCancel, disabled: saving, children: messages.cancel })] }));
16
77
  }
@@ -1,12 +1,14 @@
1
1
  import type { AllocationManifestTraveler, AllocationResource } from "@voyantjs/availability-react";
2
2
  import { type ReactNode } from "react";
3
3
  import { type AllocationOccupants } from "./slot-allocation-model.js";
4
- export declare function VehicleSeatsView({ seats, vehicles, occupants, sharingGroupLabels, onDropTraveler, onUnassignTraveler, renderTravelerActions, }: {
4
+ export declare function VehicleSeatsView({ seats, vehicles, occupants, sharingGroupLabels, onAssignTraveler, onUnassignTraveler, renderTravelerActions, }: {
5
5
  seats: AllocationResource[];
6
6
  vehicles: AllocationResource[];
7
7
  occupants: AllocationOccupants;
8
8
  sharingGroupLabels: Record<string, string>;
9
- onDropTraveler: (travelerId: string, resourceId: string) => void;
9
+ /** Assign an unallocated traveler to a specific seat resource. */
10
+ onAssignTraveler: (travelerId: string, resourceId: string) => void;
11
+ /** Remove a traveler from their current seat (no resource id required). */
10
12
  onUnassignTraveler: (travelerId: string) => void;
11
13
  renderTravelerActions?: (traveler: AllocationManifestTraveler) => ReactNode;
12
14
  }): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"slot-allocation-seat-view.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-seat-view.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAGlG,OAAO,EAAkB,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAGhE,OAAO,EACL,KAAK,mBAAmB,EAIzB,MAAM,4BAA4B,CAAA;AAGnC,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,qBAAqB,GACtB,EAAE;IACD,KAAK,EAAE,kBAAkB,EAAE,CAAA;IAC3B,QAAQ,EAAE,kBAAkB,EAAE,CAAA;IAC9B,SAAS,EAAE,mBAAmB,CAAA;IAC9B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAChE,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CAC5E,2CAsFA"}
1
+ {"version":3,"file":"slot-allocation-seat-view.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-seat-view.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAoBlG,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAGhD,OAAO,EACL,KAAK,mBAAmB,EAIzB,MAAM,4BAA4B,CAAA;AAGnC,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,GACtB,EAAE;IACD,KAAK,EAAE,kBAAkB,EAAE,CAAA;IAC3B,QAAQ,EAAE,kBAAkB,EAAE,CAAA;IAC9B,SAAS,EAAE,mBAAmB,CAAA;IAC9B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,kEAAkE;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAClE,2EAA2E;IAC3E,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CAC5E,2CA2FA"}
@@ -1,37 +1,33 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Badge, Card, CardContent, CardHeader, CardTitle, cn } from "@voyantjs/ui/components";
4
- import { Armchair, Crown, Users } from "lucide-react";
3
+ import { Badge, Button, Card, CardContent, CardHeader, CardTitle, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, cn, Popover, PopoverContent, PopoverTrigger, } from "@voyantjs/ui/components";
4
+ import { Armchair, Crown, Users, X } from "lucide-react";
5
5
  import { useState } from "react";
6
6
  import { useAllocationUiMessagesOrDefault } from "../i18n/index.js";
7
7
  import { groupSeatsByVehicle, seatName, seatRows, } from "./slot-allocation-model.js";
8
- import { DropColumn, SeatPositionBadge, TravelerTile } from "./slot-allocation-shared.js";
9
- export function VehicleSeatsView({ seats, vehicles, occupants, sharingGroupLabels, onDropTraveler, onUnassignTraveler, renderTravelerActions, }) {
8
+ import { AllocationColumn, SeatPositionBadge, TravelerTile } from "./slot-allocation-shared.js";
9
+ export function VehicleSeatsView({ seats, vehicles, occupants, sharingGroupLabels, onAssignTraveler, onUnassignTraveler, renderTravelerActions, }) {
10
10
  const messages = useAllocationUiMessagesOrDefault();
11
11
  const groups = groupSeatsByVehicle(seats, vehicles, messages);
12
- return (_jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(18rem,22rem)_1fr]", children: [_jsx(DropColumn, { id: "unallocated", icon: _jsx(Users, { className: "size-4", "aria-hidden": "true" }), title: messages.unallocated, description: messages.unallocatedDescription, count: occupants.unallocated.length, capacity: occupants.byTravelerId.size, onDropTraveler: onUnassignTraveler, children: occupants.unallocated.map((traveler) => (_jsx(TravelerTile, { traveler: traveler, sharingGroupLabel: traveler.sharingGroupId ? sharingGroupLabels[traveler.sharingGroupId] : null, renderActions: renderTravelerActions }, traveler.id))) }), _jsx("div", { className: "grid min-w-0 gap-4", children: seats.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: messages.noSeats })) : (groups.map((group) => (_jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-3", children: _jsxs(CardTitle, { className: "flex flex-wrap items-center gap-2 text-base", children: [_jsx(Armchair, { className: "size-4", "aria-hidden": "true" }), _jsx("span", { children: group.label }), _jsxs(Badge, { variant: "outline", children: [group.seats.filter((seat) => (occupants.byResource.get(seat.id) ?? []).length > 0).length, "/", group.seats.length] })] }) }), _jsx(CardContent, { children: _jsx("div", { className: "grid gap-2", children: seatRows(group.seats).map((row) => (_jsx("div", { className: "grid items-stretch gap-2", style: {
12
+ return (_jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(18rem,22rem)_1fr]", children: [_jsx(AllocationColumn, { id: "unallocated", icon: _jsx(Users, { className: "size-4", "aria-hidden": "true" }), title: messages.unallocated, description: messages.unallocatedDescription, count: occupants.unallocated.length, capacity: occupants.byTravelerId.size, children: occupants.unallocated.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: messages.unallocatedEmpty })) : (occupants.unallocated.map((traveler) => (_jsx(TravelerTile, { traveler: traveler, sharingGroupLabel: traveler.sharingGroupId ? sharingGroupLabels[traveler.sharingGroupId] : null, renderActions: renderTravelerActions }, traveler.id)))) }), _jsx("div", { className: "grid min-w-0 gap-4", children: seats.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: messages.noSeats })) : (groups.map((group) => (_jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-3", children: _jsxs(CardTitle, { className: "flex flex-wrap items-center gap-2 text-base", children: [_jsx(Armchair, { className: "size-4", "aria-hidden": "true" }), _jsx("span", { children: group.label }), _jsxs(Badge, { variant: "outline", children: [group.seats.filter((seat) => (occupants.byResource.get(seat.id) ?? []).length > 0).length, "/", group.seats.length] })] }) }), _jsx(CardContent, { children: _jsx("div", { className: "grid gap-2", children: seatRows(group.seats).map((row) => (_jsx("div", { className: "grid items-stretch gap-2", style: {
13
13
  gridTemplateColumns: `repeat(${row.seats.length}, minmax(4.25rem, 1fr))`,
14
14
  }, children: row.seats.map((seat) => {
15
15
  const seatOccupants = occupants.byResource.get(seat.id) ?? [];
16
- return (_jsx(VehicleSeatCell, { seat: seat, occupant: seatOccupants[0] ?? null, overflow: seatOccupants.length > 1, sharingGroupLabel: seatOccupants[0]?.sharingGroupId
16
+ return (_jsx(VehicleSeatCell, { seat: seat, occupant: seatOccupants[0] ?? null, overflow: seatOccupants.length > 1, unallocated: occupants.unallocated, sharingGroupLabel: seatOccupants[0]?.sharingGroupId
17
17
  ? sharingGroupLabels[seatOccupants[0].sharingGroupId]
18
- : null, onDropTraveler: (travelerId) => onDropTraveler(travelerId, seat.id) }, seat.id));
18
+ : null, onAssignTraveler: (travelerId) => onAssignTraveler(travelerId, seat.id), onUnassignTraveler: onUnassignTraveler }, seat.id));
19
19
  }) }, row.rowKey))) }) })] }, group.id)))) })] }));
20
20
  }
21
- function VehicleSeatCell({ seat, occupant, overflow, sharingGroupLabel, onDropTraveler, }) {
21
+ function VehicleSeatCell({ seat, occupant, overflow, unallocated, sharingGroupLabel, onAssignTraveler, onUnassignTraveler, }) {
22
22
  const messages = useAllocationUiMessagesOrDefault();
23
- const [over, setOver] = useState(false);
24
- function onDrop(event) {
25
- event.preventDefault();
26
- setOver(false);
27
- const travelerId = event.dataTransfer.getData("text/plain");
28
- if (travelerId)
29
- onDropTraveler(travelerId);
23
+ const [pickerOpen, setPickerOpen] = useState(false);
24
+ const cellClasses = cn("flex min-h-24 flex-col rounded-md border bg-background p-2 text-left text-xs", overflow ? "border-destructive bg-destructive/5" /* i18n-literal-ok CSS class token */ : null);
25
+ if (occupant) {
26
+ return (_jsxs("div", { id: `seat:${seat.id}`, className: cellClasses, children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("span", { className: "font-medium", children: seat.label ?? seatName(seat, messages) }), _jsx(SeatPositionBadge, { seat: seat })] }), _jsxs("div", { className: "mt-2 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1", children: [occupant.isLeadTraveler ? (_jsx(Crown, { className: "size-3 text-amber-500", "aria-label": messages.lead })) : null, _jsx("span", { className: "truncate font-medium", children: occupant.fullName })] }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-1 text-muted-foreground", children: [_jsx("span", { children: occupant.bookingNumber }), sharingGroupLabel ? (_jsx(Badge, { variant: "secondary", className: "max-w-full truncate text-[10px]", children: sharingGroupLabel })) : null] })] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "mt-auto h-6 self-end px-1 text-xs", onClick: () => onUnassignTraveler(occupant.id), "aria-label": `${messages.remove}: ${occupant.fullName}`, children: _jsx(X, { className: "size-3", "aria-hidden": "true" }) })] }));
30
27
  }
31
- return (_jsxs("div", { id: `seat:${seat.id}`, className: cn("min-h-24 rounded-md border bg-background p-2 text-left text-xs transition-colors", over ? "border-primary bg-primary/5" /* i18n-literal-ok CSS class token */ : null, overflow
32
- ? "border-destructive bg-destructive/5" /* i18n-literal-ok CSS class token */
33
- : null), onDragOver: (event) => {
34
- event.preventDefault();
35
- setOver(true);
36
- }, onDragLeave: () => setOver(false), onDrop: onDrop, children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("span", { className: "font-medium", children: seat.label ?? seatName(seat, messages) }), _jsx(SeatPositionBadge, { seat: seat })] }), occupant ? (_jsxs("div", { className: "mt-2 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1", children: [occupant.isLeadTraveler ? (_jsx(Crown, { className: "size-3 text-amber-500", "aria-label": messages.lead })) : null, _jsx("span", { className: "truncate font-medium", children: occupant.fullName })] }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-1 text-muted-foreground", children: [_jsx("span", { children: occupant.bookingNumber }), sharingGroupLabel ? (_jsx(Badge, { variant: "secondary", className: "max-w-full truncate text-[10px]", children: sharingGroupLabel })) : null] })] })) : (_jsx("div", { className: "mt-3 rounded border border-dashed p-2 text-muted-foreground", children: messages.dropHere }))] }));
28
+ const disabled = unallocated.length === 0;
29
+ return (_jsxs("div", { id: `seat:${seat.id}`, className: cellClasses, children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("span", { className: "font-medium", children: seat.label ?? seatName(seat, messages) }), _jsx(SeatPositionBadge, { seat: seat })] }), _jsxs(Popover, { open: pickerOpen, onOpenChange: setPickerOpen, children: [_jsx(PopoverTrigger, { render: _jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "mt-auto h-7 w-full justify-center rounded border border-dashed text-muted-foreground", disabled: disabled, "aria-label": messages.assignTraveler, children: disabled ? messages.assignTravelerEmpty : messages.assignTraveler }) }), _jsx(PopoverContent, { className: "w-72 p-0", align: "start", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: messages.assignTravelerSearch }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: messages.assignTravelerEmpty }), _jsx(CommandGroup, { children: unallocated.map((traveler) => (_jsx(CommandItem, { value: `${traveler.fullName} ${traveler.bookingNumber}`, onSelect: () => {
30
+ onAssignTraveler(traveler.id);
31
+ setPickerOpen(false);
32
+ }, children: _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "font-medium", children: traveler.fullName }), _jsx("span", { className: "text-xs text-muted-foreground", children: traveler.bookingNumber })] }) }, traveler.id))) })] })] }) })] })] }));
37
33
  }
@@ -1,17 +1,22 @@
1
1
  import type { AllocationAuditLogEntry, AllocationManifestTraveler, AllocationResource } from "@voyantjs/availability-react";
2
- import { type ReactNode } from "react";
2
+ import type { ReactNode } from "react";
3
3
  import { type ValidationIssue } from "./slot-allocation-model.js";
4
- export declare function DropColumn({ id, icon, title, description, count, capacity, disabled, action, children, onDropTraveler, }: {
4
+ /**
5
+ * Passive grouping container used by the unallocated column and other
6
+ * card-shaped sections. Used to be a drop target during the drag-and-
7
+ * drop era; switched to click-to-allocate, so it's now a plain layout
8
+ * primitive. Kept as a named export so render-prop consumers can
9
+ * compose new sections without re-exporting Card pieces themselves.
10
+ */
11
+ export declare function AllocationColumn({ id, icon, title, description, count, capacity, action, children, }: {
5
12
  id: string;
6
13
  icon: ReactNode;
7
14
  title: string;
8
15
  description: string;
9
16
  count: number;
10
17
  capacity: number;
11
- disabled?: boolean;
12
18
  action?: ReactNode;
13
19
  children: ReactNode;
14
- onDropTraveler: (travelerId: string) => void;
15
20
  }): import("react/jsx-runtime").JSX.Element;
16
21
  export declare function TravelerTile({ traveler, sharingGroupLabel, renderActions, }: {
17
22
  traveler: AllocationManifestTraveler;
@@ -1 +1 @@
1
- {"version":3,"file":"slot-allocation-shared.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-shared.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EACnB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAkB,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAGhE,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAE7E,wBAAgB,UAAU,CAAC,EACzB,EAAE,EACF,IAAI,EACJ,KAAK,EACL,WAAW,EACX,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,cAAc,GACf,EAAE;IACD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,QAAQ,EAAE,SAAS,CAAA;IACnB,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7C,2CA6CA;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,iBAAiB,EACjB,aAAa,GACd,EAAE;IACD,QAAQ,EAAE,0BAA0B,CAAA;IACpC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CACpE,2CA0CA;AAED,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,SAAS,EACT,gBAAgB,GACjB,EAAE;IACD,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,gBAAgB,EAAE,MAAM,CAAA;CACzB,2CA8BA;AAED,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,kBAAkB,CAAA;CAAE,kDAoBhF;AAED,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,kDAmBvE;AAED,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,uBAAuB,EAAE,CAAA;CAAE,kDA4B/E"}
1
+ {"version":3,"file":"slot-allocation-shared.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-shared.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EACnB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAE7E;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,EAAE,EACF,IAAI,EACJ,KAAK,EACL,WAAW,EACX,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,GACT,EAAE;IACD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,QAAQ,EAAE,SAAS,CAAA;CACpB,2CAqBA;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,iBAAiB,EACjB,aAAa,GACd,EAAE;IACD,QAAQ,EAAE,0BAA0B,CAAA;IACpC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CACpE,2CAgCA;AAED,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,SAAS,EACT,gBAAgB,GACjB,EAAE;IACD,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,gBAAgB,EAAE,MAAM,CAAA;CACzB,2CA8BA;AAED,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,kBAAkB,CAAA;CAAE,kDAoBhF;AAED,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,kDAmBvE;AAED,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,uBAAuB,EAAE,CAAA;CAAE,kDA4B/E"}
@@ -1,35 +1,22 @@
1
1
  "use client";
2
2
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
- import { Badge, Card, CardContent, CardHeader, CardTitle, cn } from "@voyantjs/ui/components";
3
+ import { Badge, Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components";
4
4
  import { Accessibility, CircleAlert, Crown, History, UtensilsCrossed } from "lucide-react";
5
- import { useState } from "react";
6
5
  import { useAllocationUiMessagesOrDefault } from "../i18n/index.js";
7
6
  import { flagString } from "./slot-allocation-model.js";
8
- export function DropColumn({ id, icon, title, description, count, capacity, disabled, action, children, onDropTraveler, }) {
9
- const [over, setOver] = useState(false);
10
- function onDrop(event) {
11
- event.preventDefault();
12
- setOver(false);
13
- if (disabled)
14
- return;
15
- const travelerId = event.dataTransfer.getData("text/plain");
16
- if (travelerId)
17
- onDropTraveler(travelerId);
18
- }
19
- return (_jsxs(Card, { id: id, className: cn("min-h-40 transition-colors", over && !disabled
20
- ? "border-primary bg-primary/5" /* i18n-literal-ok CSS class token */
21
- : null), onDragOver: (event) => {
22
- event.preventDefault();
23
- if (!disabled)
24
- setOver(true);
25
- }, onDragLeave: () => setOver(false), onDrop: onDrop, children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-3 space-y-0", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [icon, title] }), _jsx("p", { className: "text-xs text-muted-foreground", children: description })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Badge, { variant: count > capacity ? "destructive" : "outline", children: [count, "/", capacity] }), action] })] }), _jsx(CardContent, { className: "flex flex-col gap-2", children: children })] }));
7
+ /**
8
+ * Passive grouping container used by the unallocated column and other
9
+ * card-shaped sections. Used to be a drop target during the drag-and-
10
+ * drop era; switched to click-to-allocate, so it's now a plain layout
11
+ * primitive. Kept as a named export so render-prop consumers can
12
+ * compose new sections without re-exporting Card pieces themselves.
13
+ */
14
+ export function AllocationColumn({ id, icon, title, description, count, capacity, action, children, }) {
15
+ return (_jsxs(Card, { id: id, className: "min-h-40", children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-3 space-y-0", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [icon, title] }), _jsx("p", { className: "text-xs text-muted-foreground", children: description })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Badge, { variant: count > capacity ? "destructive" : "outline", children: [count, "/", capacity] }), action] })] }), _jsx(CardContent, { className: "flex flex-col gap-2", children: children })] }));
26
16
  }
27
17
  export function TravelerTile({ traveler, sharingGroupLabel, renderActions, }) {
28
18
  const messages = useAllocationUiMessagesOrDefault();
29
- return (_jsxs("div", { draggable: true, role: "button", tabIndex: 0, onDragStart: (event) => {
30
- event.dataTransfer.effectAllowed = "move";
31
- event.dataTransfer.setData("text/plain", traveler.id);
32
- }, className: "group flex cursor-grab items-start justify-between gap-3 rounded-md border bg-background p-3 text-sm shadow-sm active:cursor-grabbing", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-1.5", children: [traveler.isLeadTraveler ? (_jsx(Crown, { className: "size-3.5 text-amber-500", "aria-label": messages.lead })) : null, _jsx("span", { className: "truncate font-medium", children: traveler.fullName }), traveler.sharingGroupId ? (_jsx(Badge, { variant: "secondary", className: "max-w-full truncate text-[10px]", children: sharingGroupLabel ?? messages.sharingGroup })) : null] }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground", children: [_jsx("span", { children: traveler.bookingNumber }), traveler.roomTypeId ? _jsx("span", { children: traveler.roomTypeId }) : null, traveler.bedPreference ? _jsx("span", { children: traveler.bedPreference }) : null, traveler.hasAccessibilityNeeds ? (_jsx(Accessibility, { className: "size-3.5", "aria-label": messages.accessibility })) : null, traveler.hasDietaryRequirements ? (_jsx(UtensilsCrossed, { className: "size-3.5", "aria-label": messages.dietary })) : null] })] }), renderActions ? _jsx("div", { className: "shrink-0", children: renderActions(traveler) }) : null] }));
19
+ return (_jsxs("div", { className: "group flex items-start justify-between gap-3 rounded-md border bg-background p-3 text-sm shadow-sm", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-1.5", children: [traveler.isLeadTraveler ? (_jsx(Crown, { className: "size-3.5 text-amber-500", "aria-label": messages.lead })) : null, _jsx("span", { className: "truncate font-medium", children: traveler.fullName }), traveler.sharingGroupId ? (_jsx(Badge, { variant: "secondary", className: "max-w-full truncate text-[10px]", children: sharingGroupLabel ?? messages.sharingGroup })) : null] }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground", children: [_jsx("span", { children: traveler.bookingNumber }), traveler.roomTypeId ? _jsx("span", { children: traveler.roomTypeId }) : null, traveler.bedPreference ? _jsx("span", { children: traveler.bedPreference }) : null, traveler.hasAccessibilityNeeds ? (_jsx(Accessibility, { className: "size-3.5", "aria-label": messages.accessibility })) : null, traveler.hasDietaryRequirements ? (_jsx(UtensilsCrossed, { className: "size-3.5", "aria-label": messages.dietary })) : null] })] }), renderActions ? _jsx("div", { className: "shrink-0", children: renderActions(traveler) }) : null] }));
33
20
  }
34
21
  export function ValidationSummary({ issues, resources, unallocatedCount, }) {
35
22
  const messages = useAllocationUiMessagesOrDefault();
@@ -24,9 +24,17 @@ export type AllocationUiMessages = Record<string, unknown> & {
24
24
  resourceLabel: string;
25
25
  resourceCapacity: string;
26
26
  createResource: string;
27
+ editResource: string;
28
+ saveResource: string;
29
+ updateResourceFailed: string;
27
30
  cancel: string;
28
31
  unallocated: string;
29
32
  unallocatedDescription: string;
33
+ unallocatedEmpty: string;
34
+ assignTraveler: string;
35
+ assignTravelerSearch: string;
36
+ assignTravelerEmpty: string;
37
+ resourceOtherGroup: string;
30
38
  rooms: string;
31
39
  resources: string;
32
40
  vehicleSeats: string;
@@ -44,6 +52,13 @@ export type AllocationUiMessages = Record<string, unknown> & {
44
52
  remove: string;
45
53
  overCapacity: string;
46
54
  dropHere: string;
55
+ slotCapacityLabel: string;
56
+ slotCapacityUnlimited: string;
57
+ resourceCapacityLabel: string;
58
+ resourceCapacityFits: string;
59
+ resourceCapacityExact: string;
60
+ resourceCapacityOver: string;
61
+ overCapacityWarning: string;
47
62
  noRooms: string;
48
63
  noResources: string;
49
64
  noSeats: string;
@@ -98,9 +113,17 @@ export declare const allocationUiEn: {
98
113
  resourceLabel: string;
99
114
  resourceCapacity: string;
100
115
  createResource: string;
116
+ editResource: string;
117
+ saveResource: string;
118
+ updateResourceFailed: string;
101
119
  cancel: string;
102
120
  unallocated: string;
103
121
  unallocatedDescription: string;
122
+ unallocatedEmpty: string;
123
+ assignTraveler: string;
124
+ assignTravelerSearch: string;
125
+ assignTravelerEmpty: string;
126
+ resourceOtherGroup: string;
104
127
  rooms: string;
105
128
  resources: string;
106
129
  vehicleSeats: string;
@@ -118,6 +141,13 @@ export declare const allocationUiEn: {
118
141
  remove: string;
119
142
  overCapacity: string;
120
143
  dropHere: string;
144
+ slotCapacityLabel: string;
145
+ slotCapacityUnlimited: string;
146
+ resourceCapacityLabel: string;
147
+ resourceCapacityFits: string;
148
+ resourceCapacityExact: string;
149
+ resourceCapacityOver: string;
150
+ overCapacityWarning: string;
121
151
  noRooms: string;
122
152
  noResources: string;
123
153
  noSeats: string;
@@ -172,9 +202,17 @@ export declare const allocationUiRo: {
172
202
  resourceLabel: string;
173
203
  resourceCapacity: string;
174
204
  createResource: string;
205
+ editResource: string;
206
+ saveResource: string;
207
+ updateResourceFailed: string;
175
208
  cancel: string;
176
209
  unallocated: string;
177
210
  unallocatedDescription: string;
211
+ unallocatedEmpty: string;
212
+ assignTraveler: string;
213
+ assignTravelerSearch: string;
214
+ assignTravelerEmpty: string;
215
+ resourceOtherGroup: string;
178
216
  rooms: string;
179
217
  resources: string;
180
218
  vehicleSeats: string;
@@ -192,6 +230,13 @@ export declare const allocationUiRo: {
192
230
  remove: string;
193
231
  overCapacity: string;
194
232
  dropHere: string;
233
+ slotCapacityLabel: string;
234
+ slotCapacityUnlimited: string;
235
+ resourceCapacityLabel: string;
236
+ resourceCapacityFits: string;
237
+ resourceCapacityExact: string;
238
+ resourceCapacityOver: string;
239
+ overCapacityWarning: string;
195
240
  noRooms: string;
196
241
  noResources: string;
197
242
  noSeats: string;
@@ -247,9 +292,17 @@ export declare const allocationUiMessageDefinitions: {
247
292
  resourceLabel: string;
248
293
  resourceCapacity: string;
249
294
  createResource: string;
295
+ editResource: string;
296
+ saveResource: string;
297
+ updateResourceFailed: string;
250
298
  cancel: string;
251
299
  unallocated: string;
252
300
  unallocatedDescription: string;
301
+ unallocatedEmpty: string;
302
+ assignTraveler: string;
303
+ assignTravelerSearch: string;
304
+ assignTravelerEmpty: string;
305
+ resourceOtherGroup: string;
253
306
  rooms: string;
254
307
  resources: string;
255
308
  vehicleSeats: string;
@@ -267,6 +320,13 @@ export declare const allocationUiMessageDefinitions: {
267
320
  remove: string;
268
321
  overCapacity: string;
269
322
  dropHere: string;
323
+ slotCapacityLabel: string;
324
+ slotCapacityUnlimited: string;
325
+ resourceCapacityLabel: string;
326
+ resourceCapacityFits: string;
327
+ resourceCapacityExact: string;
328
+ resourceCapacityOver: string;
329
+ overCapacityWarning: string;
270
330
  noRooms: string;
271
331
  noResources: string;
272
332
  noSeats: string;
@@ -321,9 +381,17 @@ export declare const allocationUiMessageDefinitions: {
321
381
  resourceLabel: string;
322
382
  resourceCapacity: string;
323
383
  createResource: string;
384
+ editResource: string;
385
+ saveResource: string;
386
+ updateResourceFailed: string;
324
387
  cancel: string;
325
388
  unallocated: string;
326
389
  unallocatedDescription: string;
390
+ unallocatedEmpty: string;
391
+ assignTraveler: string;
392
+ assignTravelerSearch: string;
393
+ assignTravelerEmpty: string;
394
+ resourceOtherGroup: string;
327
395
  rooms: string;
328
396
  resources: string;
329
397
  vehicleSeats: string;
@@ -341,6 +409,13 @@ export declare const allocationUiMessageDefinitions: {
341
409
  remove: string;
342
410
  overCapacity: string;
343
411
  dropHere: string;
412
+ slotCapacityLabel: string;
413
+ slotCapacityUnlimited: string;
414
+ resourceCapacityLabel: string;
415
+ resourceCapacityFits: string;
416
+ resourceCapacityExact: string;
417
+ resourceCapacityOver: string;
418
+ overCapacityWarning: string;
344
419
  noRooms: string;
345
420
  noResources: string;
346
421
  noSeats: string;
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/i18n/provider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/i18n/provider.tsx"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ import { createLocaleFormatters, createPackageMessagesContext, resolvePackageMes
4
4
  export const allocationUiEn = {
5
5
  pageTitle: "Allocation",
6
6
  loading: "Loading allocation...",
7
- empty: "No travelers on this departure yet.",
7
+ empty: "Allocation data unavailable for this departure.",
8
8
  back: "Back",
9
9
  addRoom: "Add room",
10
10
  addResource: "Add resource",
@@ -37,9 +37,17 @@ export const allocationUiEn = {
37
37
  resourceLabel: "Resource label",
38
38
  resourceCapacity: "Capacity",
39
39
  createResource: "Create resource",
40
+ editResource: "Edit resource",
41
+ saveResource: "Save",
42
+ updateResourceFailed: "Could not update resource.",
40
43
  cancel: "Cancel",
41
44
  unallocated: "Unallocated",
42
45
  unallocatedDescription: "Travelers not assigned to this resource kind.",
46
+ unallocatedEmpty: "Everyone has been assigned.",
47
+ assignTraveler: "Assign",
48
+ assignTravelerSearch: "Search traveler...",
49
+ assignTravelerEmpty: "No unallocated travelers.",
50
+ resourceOtherGroup: "Other",
43
51
  rooms: "Rooms",
44
52
  resources: "Resources",
45
53
  vehicleSeats: "Vehicle seats",
@@ -57,6 +65,13 @@ export const allocationUiEn = {
57
65
  remove: "Remove",
58
66
  overCapacity: "Resource is full",
59
67
  dropHere: "Drop traveler here",
68
+ slotCapacityLabel: "Slot pax",
69
+ slotCapacityUnlimited: "Unlimited",
70
+ resourceCapacityLabel: "Resource capacity",
71
+ resourceCapacityFits: "fits in slot",
72
+ resourceCapacityExact: "matches slot",
73
+ resourceCapacityOver: "over slot cap",
74
+ overCapacityWarning: "Resource capacity exceeds the slot's pax cap.",
60
75
  noRooms: "No rooms have been added for this slot.",
61
76
  noResources: "No resources have been added for this slot.",
62
77
  noSeats: "No vehicle seats have been generated for this slot.",
@@ -78,7 +93,7 @@ export const allocationUiEn = {
78
93
  export const allocationUiRo = {
79
94
  pageTitle: "Alocare",
80
95
  loading: "Se incarca alocarea...",
81
- empty: "Nu exista calatori pe aceasta plecare.",
96
+ empty: "Datele de alocare nu sunt disponibile pentru aceasta plecare.",
82
97
  back: "Inapoi",
83
98
  addRoom: "Adauga camera",
84
99
  addResource: "Adauga resursa",
@@ -111,9 +126,17 @@ export const allocationUiRo = {
111
126
  resourceLabel: "Eticheta resursa",
112
127
  resourceCapacity: "Capacitate",
113
128
  createResource: "Creeaza resursa",
129
+ editResource: "Editeaza resursa",
130
+ saveResource: "Salveaza",
131
+ updateResourceFailed: "Resursa nu a putut fi actualizata.",
114
132
  cancel: "Anuleaza",
115
133
  unallocated: "Nealocati",
116
134
  unallocatedDescription: "Calatori fara acest tip de resursa alocat.",
135
+ unallocatedEmpty: "Toti calatorii sunt alocati.",
136
+ assignTraveler: "Aloca",
137
+ assignTravelerSearch: "Cauta calator...",
138
+ assignTravelerEmpty: "Nu exista calatori nealocati.",
139
+ resourceOtherGroup: "Altele",
117
140
  rooms: "Camere",
118
141
  resources: "Resurse",
119
142
  vehicleSeats: "Locuri vehicul",
@@ -131,6 +154,13 @@ export const allocationUiRo = {
131
154
  remove: "Scoate",
132
155
  overCapacity: "Resursa este plina",
133
156
  dropHere: "Trage calatorul aici",
157
+ slotCapacityLabel: "Pax slot",
158
+ slotCapacityUnlimited: "Nelimitat",
159
+ resourceCapacityLabel: "Capacitate resurse",
160
+ resourceCapacityFits: "incape in slot",
161
+ resourceCapacityExact: "egal cu slotul",
162
+ resourceCapacityOver: "depaseste slotul",
163
+ overCapacityWarning: "Capacitatea resurselor depaseste limita de pax a slotului.",
134
164
  noRooms: "Nu exista camere adaugate pentru acest slot.",
135
165
  noResources: "Nu exista resurse adaugate pentru acest slot.",
136
166
  noSeats: "Nu exista locuri generate pentru acest slot.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/allocation-ui",
3
- "version": "0.50.8",
3
+ "version": "0.51.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,9 +34,9 @@
34
34
  "lucide-react": "^0.475.0",
35
35
  "react": "^19.0.0",
36
36
  "react-dom": "^19.0.0",
37
- "@voyantjs/availability-react": "0.50.8",
38
- "@voyantjs/i18n": "0.50.8",
39
- "@voyantjs/ui": "0.50.8"
37
+ "@voyantjs/availability-react": "0.51.0",
38
+ "@voyantjs/i18n": "0.51.0",
39
+ "@voyantjs/ui": "0.51.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@tanstack/react-query": "^5.90.12",
@@ -47,9 +47,9 @@
47
47
  "react-dom": "^19.2.4",
48
48
  "typescript": "^6.0.2",
49
49
  "vitest": "^4.1.2",
50
- "@voyantjs/availability-react": "0.50.8",
51
- "@voyantjs/i18n": "0.50.8",
52
- "@voyantjs/ui": "0.50.8",
50
+ "@voyantjs/availability-react": "0.51.0",
51
+ "@voyantjs/i18n": "0.51.0",
52
+ "@voyantjs/ui": "0.51.0",
53
53
  "@voyantjs/voyant-typescript-config": "0.1.0"
54
54
  },
55
55
  "files": [