@voyantjs/allocation-ui 0.39.0 → 0.40.1
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.
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
import { type AllocationManifestTraveler } from "@voyantjs/availability-react";
|
|
1
|
+
import { type AllocationManifestTraveler, type SlotAllocationManifest } from "@voyantjs/availability-react";
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
|
+
export interface SlotAllocationPageRenderContext {
|
|
4
|
+
slotId: string;
|
|
5
|
+
tabId: string;
|
|
6
|
+
kind: string;
|
|
7
|
+
allocationKind: string;
|
|
8
|
+
manifest: SlotAllocationManifest;
|
|
9
|
+
travelers: AllocationManifestTraveler[];
|
|
10
|
+
allocationKinds: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface SlotAllocationPageExtraTab {
|
|
13
|
+
id: string;
|
|
14
|
+
label: ReactNode;
|
|
15
|
+
icon?: ReactNode;
|
|
16
|
+
render: (context: SlotAllocationPageRenderContext) => ReactNode;
|
|
17
|
+
}
|
|
3
18
|
export interface SlotAllocationPageProps {
|
|
4
19
|
slotId: string;
|
|
5
20
|
className?: string;
|
|
@@ -9,6 +24,10 @@ export interface SlotAllocationPageProps {
|
|
|
9
24
|
kind: string;
|
|
10
25
|
}) => ReactNode;
|
|
11
26
|
renderTravelerActions?: (traveler: AllocationManifestTraveler) => ReactNode;
|
|
27
|
+
renderHeaderEnd?: (context: SlotAllocationPageRenderContext) => ReactNode;
|
|
28
|
+
renderBefore?: (context: SlotAllocationPageRenderContext) => ReactNode;
|
|
29
|
+
renderAfter?: (context: SlotAllocationPageRenderContext) => ReactNode;
|
|
30
|
+
extraTabs?: SlotAllocationPageExtraTab[];
|
|
12
31
|
}
|
|
13
|
-
export declare function SlotAllocationPage({ slotId, className, onBack, renderExtraActions, renderTravelerActions, }: SlotAllocationPageProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
export declare function SlotAllocationPage({ slotId, className, onBack, renderExtraActions, renderTravelerActions, renderHeaderEnd, renderBefore, renderAfter, extraTabs, }: SlotAllocationPageProps): import("react/jsx-runtime").JSX.Element;
|
|
14
33
|
//# 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,
|
|
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,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useAllocationAutomationMutation, useAllocationResourceMutation, useAssignTravelerAllocationMutation, useProductResourceTemplates, useSlotAllocation, useSlotAllocationAuditLog, } from "@voyantjs/availability-react";
|
|
4
4
|
import { Button, cn, Input, Label, Tabs, TabsList, TabsTrigger } from "@voyantjs/ui/components";
|
|
5
5
|
import { Armchair, ArrowLeft, Bed, Download, Plus, Sparkles, Users, Wand2 } from "lucide-react";
|
|
@@ -9,7 +9,7 @@ import { buildValidationIssues, collectOccupants, defaultCapacityFor, kindLabel,
|
|
|
9
9
|
import { ResourceColumnsView } from "./slot-allocation-resource-view.js";
|
|
10
10
|
import { VehicleSeatsView } from "./slot-allocation-seat-view.js";
|
|
11
11
|
import { AuditLogCard, ValidationSummary } from "./slot-allocation-shared.js";
|
|
12
|
-
export function SlotAllocationPage({ slotId, className, onBack, renderExtraActions, renderTravelerActions, }) {
|
|
12
|
+
export function SlotAllocationPage({ slotId, className, onBack, renderExtraActions, renderTravelerActions, renderHeaderEnd, renderBefore, renderAfter, extraTabs = [], }) {
|
|
13
13
|
const messages = useAllocationUiMessagesOrDefault();
|
|
14
14
|
const allocation = useSlotAllocation({ slotId });
|
|
15
15
|
const auditLog = useSlotAllocationAuditLog({ slotId });
|
|
@@ -21,6 +21,7 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
|
|
|
21
21
|
const [resourceLabel, setResourceLabel] = useState("");
|
|
22
22
|
const [resourceCapacity, setResourceCapacity] = useState(2);
|
|
23
23
|
const [error, setError] = useState(null);
|
|
24
|
+
const hasPageExtensions = Boolean(renderHeaderEnd || renderBefore || renderAfter || extraTabs.length);
|
|
24
25
|
const data = allocation.data?.data;
|
|
25
26
|
const templates = useProductResourceTemplates({
|
|
26
27
|
productId: data?.slot.productId,
|
|
@@ -54,6 +55,11 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
|
|
|
54
55
|
const activeKind = allocationKinds.includes(selectedKind)
|
|
55
56
|
? selectedKind
|
|
56
57
|
: (allocationKinds[0] ?? ROOM_KIND);
|
|
58
|
+
const visibleExtraTabs = extraTabs.filter((tab) => !allocationKinds.includes(tab.id));
|
|
59
|
+
const selectedExtraTab = allocationKinds.includes(selectedKind)
|
|
60
|
+
? undefined
|
|
61
|
+
: visibleExtraTabs.find((tab) => tab.id === selectedKind);
|
|
62
|
+
const activeTabId = selectedExtraTab?.id ?? activeKind;
|
|
57
63
|
const resources = useMemo(() => (data?.resources ?? []).filter((resource) => resource.kind === activeKind), [data?.resources, activeKind]);
|
|
58
64
|
const parentResources = useMemo(() => (data?.resources ?? []).filter((resource) => resource.kind === parentKindFor(activeKind)), [data?.resources, activeKind]);
|
|
59
65
|
const occupants = useMemo(() => collectOccupants(travelers, resources, activeKind), [travelers, resources, activeKind]);
|
|
@@ -131,17 +137,26 @@ export function SlotAllocationPage({ slotId, className, onBack, renderExtraActio
|
|
|
131
137
|
if (allocation.isPending) {
|
|
132
138
|
return (_jsx("div", { className: cn("p-6 text-sm text-muted-foreground", className), children: messages.loading }));
|
|
133
139
|
}
|
|
134
|
-
if (!data || travelers.length === 0) {
|
|
140
|
+
if (!data || (travelers.length === 0 && !hasPageExtensions)) {
|
|
135
141
|
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 })] }));
|
|
136
142
|
}
|
|
137
143
|
const isSeatMap = activeKind === VEHICLE_SEAT_KIND;
|
|
138
144
|
const canManuallyAddResource = !isSeatMap;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
const context = {
|
|
146
|
+
slotId,
|
|
147
|
+
tabId: activeTabId,
|
|
148
|
+
kind: activeTabId,
|
|
149
|
+
allocationKind: activeKind,
|
|
150
|
+
manifest: data,
|
|
151
|
+
travelers,
|
|
152
|
+
allocationKinds,
|
|
153
|
+
};
|
|
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 ?? [] })] }));
|
|
147
162
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { SlotAllocationPage, type SlotAllocationPageProps, } from "./components/slot-allocation-page.js";
|
|
1
|
+
export { SlotAllocationPage, type SlotAllocationPageExtraTab, type SlotAllocationPageProps, type SlotAllocationPageRenderContext, } from "./components/slot-allocation-page.js";
|
|
2
2
|
export { type AllocationUiMessageOverrides, type AllocationUiMessages, AllocationUiMessagesProvider, allocationUiEn, allocationUiMessageDefinitions, allocationUiRo, getAllocationUiI18n, resolveAllocationUiMessages, useAllocationUiI18n, useAllocationUiI18nOrDefault, useAllocationUiMessages, useAllocationUiMessagesOrDefault, } from "./i18n/index.js";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,+BAA+B,GACrC,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EACzB,4BAA4B,EAC5B,cAAc,EACd,8BAA8B,EAC9B,cAAc,EACd,mBAAmB,EACnB,2BAA2B,EAC3B,mBAAmB,EACnB,4BAA4B,EAC5B,uBAAuB,EACvB,gCAAgC,GACjC,MAAM,iBAAiB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/allocation-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.1",
|
|
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.
|
|
38
|
-
"@voyantjs/i18n": "0.
|
|
39
|
-
"@voyantjs/ui": "0.
|
|
37
|
+
"@voyantjs/availability-react": "0.40.1",
|
|
38
|
+
"@voyantjs/i18n": "0.40.1",
|
|
39
|
+
"@voyantjs/ui": "0.40.1"
|
|
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.
|
|
51
|
-
"@voyantjs/i18n": "0.
|
|
52
|
-
"@voyantjs/ui": "0.
|
|
50
|
+
"@voyantjs/availability-react": "0.40.1",
|
|
51
|
+
"@voyantjs/i18n": "0.40.1",
|
|
52
|
+
"@voyantjs/ui": "0.40.1",
|
|
53
53
|
"@voyantjs/voyant-typescript-config": "0.1.0"
|
|
54
54
|
},
|
|
55
55
|
"files": [
|