@voyantjs/allocation-ui 0.69.1 → 0.71.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.
@@ -0,0 +1,25 @@
1
+ import type { SeatLayoutSpec } from "@voyantjs/availability-react";
2
+ /**
3
+ * Visual editor for a vehicle seat map. Renders a 2D grid the operator can
4
+ * click to cycle each cell through `seat → aisle → door → void`. Used inside
5
+ * the resource-template dialog; the resulting `SeatLayoutSpec` is stored on
6
+ * the template's `flags.layoutSpec` and consumed by the backend materializer.
7
+ *
8
+ * Designed to be controlled — `value` and `onChange` own the spec. Passing
9
+ * `null` clears the spec; the consumer can offer a preset chooser elsewhere
10
+ * if it wants to reset to a starter.
11
+ */
12
+ export interface SeatMapBuilderProps {
13
+ value: SeatLayoutSpec | null;
14
+ onChange(spec: SeatLayoutSpec | null): void;
15
+ /** Hard cap on row count. Defaults to 20, well under the schema's 40. */
16
+ maxRows?: number;
17
+ /** Hard cap on cells per row. Defaults to 12, well under the schema's 20. */
18
+ maxColumns?: number;
19
+ }
20
+ export declare const SEAT_MAP_PRESETS: ReadonlyArray<{
21
+ id: "standardCoach" | "miniCoach" | "largeBus" | "doubleDecker" | "withMidDoor";
22
+ spec: SeatLayoutSpec;
23
+ }>;
24
+ export declare function SeatMapBuilder({ value, onChange, maxRows, maxColumns, }: SeatMapBuilderProps): import("react/jsx-runtime").JSX.Element;
25
+ //# sourceMappingURL=seat-map-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seat-map-builder.d.ts","sourceRoot":"","sources":["../../src/components/seat-map-builder.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAQlF;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3C,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAUD,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC;IAC3C,EAAE,EAAE,eAAe,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAA;IAC/E,IAAI,EAAE,cAAc,CAAA;CACrB,CASA,CAAA;AAED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,OAAY,EACZ,UAAe,GAChB,EAAE,mBAAmB,2CAkLrB"}
@@ -0,0 +1,133 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { formatMessage } from "@voyantjs/i18n";
4
+ import { Badge, Button, cn } from "@voyantjs/ui/components";
5
+ import { DoorOpen, Minus, Plus, RotateCcw, Square, X } from "lucide-react";
6
+ import { useMemo } from "react";
7
+ import { useAllocationUiMessagesOrDefault } from "../i18n/index.js";
8
+ const DEFAULT_COLUMNS = 5;
9
+ const NEXT_KIND = {
10
+ seat: "aisle",
11
+ aisle: "door",
12
+ door: "void",
13
+ void: "seat",
14
+ };
15
+ export const SEAT_MAP_PRESETS = [
16
+ { id: "standardCoach", spec: makeUniformSpec(["seat", "seat", "aisle", "seat", "seat"], 11) },
17
+ { id: "miniCoach", spec: makeUniformSpec(["seat", "seat", "aisle", "seat"], 7) },
18
+ { id: "largeBus", spec: makeUniformSpec(["seat", "seat", "seat", "aisle", "seat", "seat"], 11) },
19
+ {
20
+ id: "doubleDecker",
21
+ spec: makeUniformSpec(["seat", "seat", "aisle", "seat", "aisle", "seat", "seat"], 11),
22
+ },
23
+ { id: "withMidDoor", spec: withMidDoor(["seat", "seat", "aisle", "seat", "seat"], 11, 7) },
24
+ ];
25
+ export function SeatMapBuilder({ value, onChange, maxRows = 20, maxColumns = 12, }) {
26
+ const messages = useAllocationUiMessagesOrDefault();
27
+ const t = messages.seatMapBuilder;
28
+ const spec = value;
29
+ const columns = spec?.rows[0]?.cells.length ?? DEFAULT_COLUMNS;
30
+ const seatCount = useMemo(() => countSeats(spec), [spec]);
31
+ function emitOrClear(next) {
32
+ onChange(next.rows.length === 0 ? null : next);
33
+ }
34
+ function cycleCell(rowIndex, cellIndex) {
35
+ if (!spec)
36
+ return;
37
+ const nextRows = spec.rows.map((row, rIdx) => {
38
+ if (rIdx !== rowIndex)
39
+ return row;
40
+ return {
41
+ cells: row.cells.map((cell, cIdx) => (cIdx === cellIndex ? NEXT_KIND[cell] : cell)),
42
+ };
43
+ });
44
+ emitOrClear({ rows: nextRows });
45
+ }
46
+ function addRow() {
47
+ if (spec && spec.rows.length >= maxRows)
48
+ return;
49
+ const baseCells = spec?.rows[spec.rows.length - 1]?.cells.map(() => "seat") ??
50
+ new Array(DEFAULT_COLUMNS).fill("seat");
51
+ emitOrClear({ rows: [...(spec?.rows ?? []), { cells: baseCells }] });
52
+ }
53
+ function removeRow() {
54
+ if (!spec || spec.rows.length <= 1) {
55
+ onChange(null);
56
+ return;
57
+ }
58
+ emitOrClear({ rows: spec.rows.slice(0, -1) });
59
+ }
60
+ function addColumn() {
61
+ if (!spec || columns >= maxColumns)
62
+ return;
63
+ emitOrClear({
64
+ rows: spec.rows.map((row) => ({ cells: [...row.cells, "seat"] })),
65
+ });
66
+ }
67
+ function removeColumn() {
68
+ if (!spec || columns <= 1)
69
+ return;
70
+ emitOrClear({
71
+ rows: spec.rows.map((row) => ({ cells: row.cells.slice(0, -1) })),
72
+ });
73
+ }
74
+ function applyPreset(preset) {
75
+ onChange(preset);
76
+ }
77
+ if (!spec) {
78
+ return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium text-sm", children: t.presetHeading }), _jsx("p", { className: "text-muted-foreground text-xs", children: t.presetHint })] }), _jsx("div", { className: "flex flex-wrap gap-2", children: SEAT_MAP_PRESETS.map((preset) => (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => applyPreset(preset.spec), children: t.presets[preset.id] }, preset.id))) })] }));
79
+ }
80
+ return (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium text-sm", children: t.heading }), _jsx("p", { className: "text-muted-foreground text-xs", children: t.description })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Badge, { variant: "outline", children: formatMessage(t.capacityChip, { count: seatCount }) }), _jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onChange(null), children: [_jsx(RotateCcw, { className: "mr-1 size-3.5", "aria-hidden": "true" }), t.resetSpec] })] })] }), _jsx(CellKindLegend, { messages: t }), _jsx("div", { className: "flex flex-col items-start gap-1.5 overflow-x-auto rounded-md border bg-muted/10 p-3", children: spec.rows.map((row, rowIndex) => (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "w-6 shrink-0 text-right text-[10px] text-muted-foreground tabular-nums", children: rowIndex + 1 }), row.cells.map((cell, cellIndex) => (_jsx("button", { type: "button", "aria-label": formatMessage(t.columnAria, {
81
+ row: rowIndex + 1,
82
+ column: cellIndex + 1,
83
+ }), title: t.cellKinds[cell], onClick: () => cycleCell(rowIndex, cellIndex), className: cn("flex size-9 items-center justify-center rounded border text-[11px] font-medium transition-colors", cellStyles(cell)), children: _jsx(CellGlyph, { cell: cell, short: t.cellKindShort[cell] }) }, `cell-${rowIndex}-${cellIndex}`)))] }, `row-${rowIndex}`))) }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addRow, disabled: spec.rows.length >= maxRows, children: [_jsx(Plus, { className: "mr-1 size-3.5", "aria-hidden": "true" }), t.addRow] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: removeRow, children: [_jsx(Minus, { className: "mr-1 size-3.5", "aria-hidden": "true" }), t.removeRow] }), _jsx("span", { className: "text-muted-foreground text-xs", children: formatMessage(t.seatCountSummary, { count: seatCount }) }), _jsxs("div", { className: "ml-auto flex items-center gap-1", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: removeColumn, disabled: columns <= 1, children: _jsx(Minus, { className: "size-3.5", "aria-hidden": "true" }) }), _jsx("span", { className: "text-muted-foreground text-[10px] uppercase tracking-wider", children: columns }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: addColumn, disabled: columns >= maxColumns, children: _jsx(Plus, { className: "size-3.5", "aria-hidden": "true" }) })] })] }), _jsx("p", { className: "text-muted-foreground text-xs", children: t.voidDoorReminder })] }));
84
+ }
85
+ function CellKindLegend({ messages, }) {
86
+ const kinds = ["seat", "aisle", "door", "void"];
87
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("p", { className: "font-medium text-xs", children: messages.cellKindHeading }), _jsx("div", { className: "flex flex-wrap items-center gap-2 text-xs", children: kinds.map((kind) => (_jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx("span", { className: cn("inline-flex size-5 items-center justify-center rounded border text-[10px]", cellStyles(kind)), "aria-hidden": "true", children: _jsx(CellGlyph, { cell: kind, short: messages.cellKindShort[kind] }) }), messages.cellKinds[kind]] }, kind))) }), _jsx("p", { className: "text-muted-foreground text-[11px]", children: messages.cellKindHint })] }));
88
+ }
89
+ function CellGlyph({ cell, short }) {
90
+ if (cell === "door")
91
+ return _jsx(DoorOpen, { className: "size-3.5", "aria-hidden": "true" });
92
+ if (cell === "void")
93
+ return _jsx(X, { className: "size-3 opacity-40", "aria-hidden": "true" });
94
+ if (cell === "aisle")
95
+ return _jsx(Square, { className: "size-2.5 opacity-30", "aria-hidden": "true" });
96
+ return _jsx("span", { children: short });
97
+ }
98
+ function cellStyles(cell) {
99
+ switch (cell) {
100
+ case "seat":
101
+ return "border-primary/40 bg-primary/10 text-primary hover:bg-primary/20";
102
+ case "aisle":
103
+ return "border-dashed border-muted-foreground/30 bg-transparent text-muted-foreground hover:bg-muted/30";
104
+ case "door":
105
+ return "border-amber-500/50 bg-amber-500/15 text-amber-700 hover:bg-amber-500/25 dark:text-amber-300";
106
+ case "void":
107
+ return "border-muted-foreground/20 bg-muted/20 text-muted-foreground/40 hover:bg-muted/40";
108
+ }
109
+ }
110
+ function countSeats(spec) {
111
+ if (!spec)
112
+ return 0;
113
+ let count = 0;
114
+ for (const row of spec.rows) {
115
+ for (const cell of row.cells) {
116
+ if (cell === "seat")
117
+ count += 1;
118
+ }
119
+ }
120
+ return count;
121
+ }
122
+ function makeUniformSpec(template, rowCount) {
123
+ return { rows: Array.from({ length: rowCount }, () => ({ cells: [...template] })) };
124
+ }
125
+ function withMidDoor(rowTemplate, rowCount, doorRowIndex) {
126
+ const rows = makeUniformSpec(rowTemplate, rowCount).rows;
127
+ const safeIndex = Math.min(Math.max(0, doorRowIndex - 1), rows.length - 1);
128
+ const target = rows[safeIndex];
129
+ if (target) {
130
+ rows[safeIndex] = { cells: target.cells.map(() => "door") };
131
+ }
132
+ return { rows };
133
+ }
@@ -1,4 +1,4 @@
1
- import type { AllocationManifestTraveler, AllocationResource } from "@voyantjs/availability-react";
1
+ import { type AllocationManifestTraveler, type AllocationResource, type SeatLayoutSpec } from "@voyantjs/availability-react";
2
2
  import type { AllocationUiMessages } from "../i18n/index.js";
3
3
  export declare const ROOM_KIND = "room";
4
4
  export declare const VEHICLE_KIND = "vehicle";
@@ -22,25 +22,19 @@ export declare function buildValidationIssues({ travelers, resources, occupants,
22
22
  messages: AllocationUiMessages;
23
23
  }): ValidationIssue[];
24
24
  export declare function splitSharingGroups(travelers: AllocationManifestTraveler[], kind: string): string[];
25
- export declare function groupSeatsByVehicle(seats: AllocationResource[], vehicles: AllocationResource[], messages: AllocationUiMessages): {
26
- seats: {
27
- id: string;
28
- slotId: string;
29
- kind: string;
30
- refType: string | null;
31
- refId: string | null;
32
- label: string | null;
33
- capacity: number;
34
- flags: Record<string, unknown>;
35
- parentId: string | null;
36
- sortOrder: number;
37
- createdAt: string | Date;
38
- updatedAt: string | Date;
39
- }[];
25
+ export interface VehicleSeatGroup {
40
26
  id: string;
41
27
  label: string;
42
28
  sortOrder: number;
43
- }[];
29
+ seats: AllocationResource[];
30
+ /**
31
+ * Parsed 2D layout for this vehicle when the operator drew a custom map
32
+ * via `<SeatMapBuilder />`. Renderers honor this to draw aisles, doors,
33
+ * and voids; absent means fall back to the row-grouped layout.
34
+ */
35
+ layoutSpec: SeatLayoutSpec | null;
36
+ }
37
+ export declare function groupSeatsByVehicle(seats: AllocationResource[], vehicles: AllocationResource[], messages: AllocationUiMessages): VehicleSeatGroup[];
44
38
  export declare function seatRows(seats: AllocationResource[]): {
45
39
  rowKey: string;
46
40
  seats: {
@@ -1 +1 @@
1
- {"version":3,"file":"slot-allocation-model.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slot-allocation-model.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-model.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { seatLayoutSpecSchema, } from "@voyantjs/availability-react";
1
2
  export const ROOM_KIND = "room";
2
3
  export const VEHICLE_KIND = "vehicle";
3
4
  export const VEHICLE_SEAT_KIND = "vehicle_seat";
@@ -74,6 +75,7 @@ export function groupSeatsByVehicle(seats, vehicles, messages) {
74
75
  id: parentId,
75
76
  label: parent?.label ?? messages.vehicle,
76
77
  sortOrder: parent?.sortOrder ?? 0,
78
+ layoutSpec: parseLayoutSpecFromFlags(parent?.flags ?? null),
77
79
  seats: [],
78
80
  })
79
81
  .get(parentId);
@@ -86,6 +88,13 @@ export function groupSeatsByVehicle(seats, vehicles, messages) {
86
88
  }))
87
89
  .sort((a, b) => a.sortOrder - b.sortOrder || a.label.localeCompare(b.label));
88
90
  }
91
+ function parseLayoutSpecFromFlags(flags) {
92
+ const raw = flags?.layoutSpec;
93
+ if (!raw)
94
+ return null;
95
+ const parsed = seatLayoutSpecSchema.safeParse(raw);
96
+ return parsed.success ? parsed.data : null;
97
+ }
89
98
  export function seatRows(seats) {
90
99
  const byRow = new Map();
91
100
  for (const seat of seats) {
@@ -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,EACV,0BAA0B,EAE1B,kBAAkB,EACnB,MAAM,8BAA8B,CAAA;AAmCrC,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,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,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;;;;;OAKG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7C,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;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CAC5E,2CAgEA"}
1
+ {"version":3,"file":"slot-allocation-resource-view.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-resource-view.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,0BAA0B,EAE1B,kBAAkB,EACnB,MAAM,8BAA8B,CAAA;AAmCrC,OAAO,EAAkB,KAAK,SAAS,EAAuB,MAAM,OAAO,CAAA;AAG3E,OAAO,EACL,KAAK,mBAAmB,EAGzB,MAAM,4BAA4B,CAAA;AAOnC,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,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,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;;;;;OAKG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7C,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;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CAC5E,2CAgEA"}
@@ -5,7 +5,7 @@ import { Accessibility, Bed, Crown, Pencil, Plus, Trash2, UserMinus, Users, Uten
5
5
  import { useEffect, useState } from "react";
6
6
  import { useAllocationUiMessagesOrDefault } from "../i18n/index.js";
7
7
  import { groupResourcesBySubType, kindLabel, } from "./slot-allocation-model.js";
8
- import { AllocationColumn } from "./slot-allocation-shared.js";
8
+ import { AllocationColumn, paymentStatusChipClass, paymentStatusTooltip, } from "./slot-allocation-shared.js";
9
9
  export function ResourceColumnsView({ kind, resources, travelers, occupants, sharingGroupLabels, optionNamesById, onAssignTraveler, onUnassignTraveler, onRemoveResource, onEditResource, onBookingOpen, renderTravelerActions, }) {
10
10
  const messages = useAllocationUiMessagesOrDefault();
11
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 })) : (_jsx(UnallocatedTravelersTable, { travelers: occupants.unallocated, sharingGroupLabels: sharingGroupLabels, onBookingOpen: onBookingOpen, renderActions: renderTravelerActions })) }), _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) => {
@@ -44,25 +44,7 @@ function ResourceRow({ kind, resource, seated, unallocated, sharingGroupLabels,
44
44
  }
45
45
  function TravelerChip({ traveler, sharingGroupLabel, onUnassign, onBookingOpen, }) {
46
46
  const messages = useAllocationUiMessagesOrDefault();
47
- return (_jsxs("span", { className: cn("inline-flex items-center gap-1 rounded-full border bg-background px-2 py-0.5 text-xs", paymentStatusChipClass(traveler.paymentStatus)), title: paymentStatusTooltip(traveler.paymentStatus, messages), children: [_jsx("span", { className: "truncate font-medium", title: sharingGroupLabel ?? undefined, children: traveler.fullName }), onBookingOpen ? (_jsx("button", { type: "button", onClick: () => onBookingOpen(traveler.bookingId), className: "text-muted-foreground hover:text-foreground hover:underline", children: traveler.bookingNumber })) : (_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" }) })] }));
48
- }
49
- /**
50
- * Border + background tint that mirrors the booking's payment status:
51
- * red for unpaid, amber for partial, emerald for paid. Tailwind classes
52
- * are explicit (no template strings) so the v4 JIT scanner picks them up.
53
- */
54
- function paymentStatusChipClass(status) {
55
- switch (status) {
56
- case "paid":
57
- return "border-emerald-500/40 bg-emerald-500/5";
58
- case "partial":
59
- return "border-amber-500/40 bg-amber-500/5";
60
- case "unpaid":
61
- return "border-rose-500/40 bg-rose-500/5";
62
- }
63
- }
64
- function paymentStatusTooltip(status, messages) {
65
- return messages.paymentStatusLabels?.[status] ?? status;
47
+ return (_jsxs("span", { className: cn("inline-flex items-center gap-1 rounded-full border bg-background px-2 py-0.5 text-xs", paymentStatusChipClass(traveler.paymentStatus)), title: paymentStatusTooltip(traveler.paymentStatus, messages), children: [traveler.bookingSequence > 0 ? (_jsxs("span", { className: "text-muted-foreground tabular-nums", "aria-hidden": "true", children: ["(", traveler.bookingSequence, ")"] })) : null, _jsx("span", { className: "truncate font-medium", title: sharingGroupLabel ?? undefined, children: traveler.fullName }), onBookingOpen ? (_jsx("button", { type: "button", onClick: () => onBookingOpen(traveler.bookingId), className: "text-muted-foreground hover:text-foreground hover:underline", children: traveler.bookingNumber })) : (_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" }) })] }));
66
48
  }
67
49
  function AssignTravelerPopover({ unallocated, seatedBookingIds, onSelect, }) {
68
50
  const messages = useAllocationUiMessagesOrDefault();
@@ -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;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,aAAa,EACb,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,wEAAwE;IACxE,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CAC5E,2CA4FA"}
1
+ {"version":3,"file":"slot-allocation-seat-view.d.ts","sourceRoot":"","sources":["../../src/components/slot-allocation-seat-view.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,0BAA0B,EAC1B,kBAAkB,EAGnB,MAAM,8BAA8B,CAAA;AAoBrC,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAGhD,OAAO,EACL,KAAK,mBAAmB,EAIzB,MAAM,4BAA4B,CAAA;AASnC,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,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,wEAAwE;IACxE,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,SAAS,CAAA;CAC5E,2CA0GA"}
@@ -1,29 +1,30 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
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";
4
+ import { Armchair, Crown, DoorOpen, 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 { AllocationColumn, SeatPositionBadge, TravelerTile } from "./slot-allocation-shared.js";
8
+ import { AllocationColumn, paymentStatusChipClass, paymentStatusTooltip, SeatPositionBadge, TravelerTile, } from "./slot-allocation-shared.js";
9
9
  export function VehicleSeatsView({ seats, vehicles, occupants, sharingGroupLabels, onAssignTraveler, onUnassignTraveler, onBookingOpen, 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(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: {
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: group.layoutSpec ? (_jsx(SpecGrid, { spec: group.layoutSpec, seats: group.seats, occupants: occupants, sharingGroupLabels: sharingGroupLabels, onAssignTraveler: onAssignTraveler, onUnassignTraveler: onUnassignTraveler, onBookingOpen: onBookingOpen })) : (_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
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
18
  : null, onAssignTraveler: (travelerId) => onAssignTraveler(travelerId, seat.id), onUnassignTraveler: onUnassignTraveler, onBookingOpen: onBookingOpen }, seat.id));
19
- }) }, row.rowKey))) }) })] }, group.id)))) })] }));
19
+ }) }, row.rowKey))) })) })] }, group.id)))) })] }));
20
20
  }
21
21
  function VehicleSeatCell({ seat, occupant, overflow, unallocated, sharingGroupLabel, onAssignTraveler, onUnassignTraveler, onBookingOpen, }) {
22
22
  const messages = useAllocationUiMessagesOrDefault();
23
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);
24
+ const occupiedClasses = occupant ? paymentStatusChipClass(occupant.paymentStatus) : null;
25
+ const cellClasses = cn("flex min-h-24 flex-col rounded-md border bg-background p-2 text-left text-xs", occupiedClasses, overflow ? "border-destructive bg-destructive/5" /* i18n-literal-ok CSS class token */ : null);
25
26
  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: [onBookingOpen ? (_jsx("button", { type: "button", onClick: () => onBookingOpen(occupant.bookingId), className: "hover:text-foreground hover:underline", children: occupant.bookingNumber })) : (_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" }) })] }));
27
+ return (_jsxs("div", { id: `seat:${seat.id}`, className: cellClasses, title: paymentStatusTooltip(occupant.paymentStatus, messages), 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, occupant.bookingSequence > 0 ? (_jsxs("span", { className: "text-muted-foreground tabular-nums", "aria-hidden": "true", children: ["(", occupant.bookingSequence, ")"] })) : 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: [onBookingOpen ? (_jsx("button", { type: "button", onClick: () => onBookingOpen(occupant.bookingId), className: "hover:text-foreground hover:underline", children: occupant.bookingNumber })) : (_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" }) })] }));
27
28
  }
28
29
  const disabled = unallocated.length === 0;
29
30
  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: () => {
@@ -31,3 +32,66 @@ function VehicleSeatCell({ seat, occupant, overflow, unallocated, sharingGroupLa
31
32
  setPickerOpen(false);
32
33
  }, 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))) })] })] }) })] })] }));
33
34
  }
35
+ /**
36
+ * Render the bus as the operator drew it. Walks `layoutSpec.rows` and maps
37
+ * each `"seat"` cell to its materialized resource by (row, seat-column-letter).
38
+ * Other cell kinds render as visible spacers — doors as a striped row, voids
39
+ * and aisles as gap tiles — so the rendered map mirrors the builder view.
40
+ */
41
+ function SpecGrid({ spec, seats, occupants, sharingGroupLabels, onAssignTraveler, onUnassignTraveler, onBookingOpen, }) {
42
+ const seatsByRowColumn = indexSeats(seats);
43
+ return (_jsx("div", { className: "flex flex-col gap-2 overflow-x-auto", children: spec.rows.map((row, rowIndex) => {
44
+ const rowNumber = rowIndex + 1;
45
+ let seatColumn = 0;
46
+ return (_jsx("div", { className: "grid items-stretch gap-2", style: { gridTemplateColumns: `repeat(${row.cells.length}, minmax(4.25rem, 1fr))` }, children: row.cells.map((cell, cellIndex) => {
47
+ if (cell === "seat") {
48
+ seatColumn += 1;
49
+ const columnName = columnLetter(seatColumn);
50
+ const seat = seatsByRowColumn.get(`${rowNumber}:${columnName}`);
51
+ if (!seat) {
52
+ return (_jsx(SpacerCell
53
+ // biome-ignore lint/suspicious/noArrayIndexKey: positional cell within a fixed row.
54
+ , { kind: "void", rowNumber: rowNumber }, `spec-${rowIndex}-${cellIndex}`));
55
+ }
56
+ const seatOccupants = occupants.byResource.get(seat.id) ?? [];
57
+ return (_jsx(VehicleSeatCell, { seat: seat, occupant: seatOccupants[0] ?? null, overflow: seatOccupants.length > 1, unallocated: occupants.unallocated, sharingGroupLabel: seatOccupants[0]?.sharingGroupId
58
+ ? sharingGroupLabels[seatOccupants[0].sharingGroupId]
59
+ : null, onAssignTraveler: (travelerId) => onAssignTraveler(travelerId, seat.id), onUnassignTraveler: onUnassignTraveler, onBookingOpen: onBookingOpen }, seat.id));
60
+ }
61
+ return (_jsx(SpacerCell
62
+ // biome-ignore lint/suspicious/noArrayIndexKey: positional cell within a fixed row.
63
+ , { kind: cell, rowNumber: rowNumber }, `spec-${rowIndex}-${cellIndex}`));
64
+ }) }, `spec-row-${rowIndex}`));
65
+ }) }));
66
+ }
67
+ function SpacerCell({ kind, rowNumber: _rowNumber, }) {
68
+ if (kind === "door") {
69
+ return (_jsx("div", { className: "flex min-h-24 items-center justify-center rounded-md border border-amber-500/50 bg-amber-500/10 text-amber-700 dark:text-amber-300", children: _jsx(DoorOpen, { className: "size-5", "aria-hidden": "true" }) }));
70
+ }
71
+ if (kind === "void") {
72
+ return _jsx("div", { className: "min-h-24 rounded-md border border-dashed border-muted-foreground/20" });
73
+ }
74
+ // aisle
75
+ return _jsx("div", { className: "min-h-24", "aria-hidden": "true" });
76
+ }
77
+ function indexSeats(seats) {
78
+ const map = new Map();
79
+ for (const seat of seats) {
80
+ const row = typeof seat.flags?.row === "number" ? seat.flags.row : null;
81
+ const column = typeof seat.flags?.column === "string" ? seat.flags.column : null;
82
+ if (row === null || column === null)
83
+ continue;
84
+ map.set(`${row}:${column}`, seat);
85
+ }
86
+ return map;
87
+ }
88
+ function columnLetter(value) {
89
+ let result = "";
90
+ let n = value;
91
+ while (n > 0) {
92
+ const remainder = (n - 1) % 26;
93
+ result = String.fromCharCode(65 + remainder) + result;
94
+ n = Math.floor((n - 1) / 26);
95
+ }
96
+ return result;
97
+ }
@@ -1,5 +1,6 @@
1
- import type { AllocationAuditLogEntry, AllocationManifestTraveler, AllocationResource } from "@voyantjs/availability-react";
1
+ import type { AllocationAuditLogEntry, AllocationManifestTraveler, AllocationPaymentStatus, AllocationResource } from "@voyantjs/availability-react";
2
2
  import type { ReactNode } from "react";
3
+ import { useAllocationUiMessagesOrDefault } from "../i18n/index.js";
3
4
  import { type ValidationIssue } from "./slot-allocation-model.js";
4
5
  /**
5
6
  * Passive grouping container used by the unallocated column and other
@@ -37,4 +38,17 @@ export declare function SeatPositionBadge({ seat }: {
37
38
  export declare function AuditLogCard({ entries }: {
38
39
  entries: AllocationAuditLogEntry[];
39
40
  }): import("react/jsx-runtime").JSX.Element | null;
41
+ /**
42
+ * Border + background tint that mirrors the booking's payment status:
43
+ * red for unpaid, amber for partial, emerald for paid. Tailwind class
44
+ * names are written explicitly (no template strings) so the v4 JIT
45
+ * scanner picks them up.
46
+ *
47
+ * The saturation was bumped to `/20` background + `/70` border (from the
48
+ * earlier `/5` + `/40`) because the lower opacities rendered as no color
49
+ * on dark themes — the chips looked uncolored even though the helper
50
+ * was being applied.
51
+ */
52
+ export declare function paymentStatusChipClass(status: AllocationPaymentStatus): string;
53
+ export declare function paymentStatusTooltip(status: AllocationPaymentStatus, messages: ReturnType<typeof useAllocationUiMessagesOrDefault>): string;
40
54
  //# sourceMappingURL=slot-allocation-shared.d.ts.map
@@ -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,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,2CAkCA;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,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,EAAE,gCAAgC,EAAE,MAAM,kBAAkB,CAAA;AACnE,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,2CA2CA;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,2CAkCA;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;AAwBD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,uBAAuB,GAAG,MAAM,CAS9E;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,uBAAuB,EAC/B,QAAQ,EAAE,UAAU,CAAC,OAAO,gCAAgC,CAAC,GAC5D,MAAM,CAER"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
- import { Badge, Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components";
3
+ import { Badge, Card, CardContent, CardHeader, CardTitle, cn } from "@voyantjs/ui/components";
4
4
  import { Accessibility, CircleAlert, Crown, History, UtensilsCrossed } from "lucide-react";
5
5
  import { useAllocationUiMessagesOrDefault } from "../i18n/index.js";
6
6
  import { flagString } from "./slot-allocation-model.js";
@@ -16,7 +16,7 @@ export function AllocationColumn({ id, icon, title, description, count, capacity
16
16
  }
17
17
  export function TravelerTile({ traveler, sharingGroupLabel, renderActions, }) {
18
18
  const messages = useAllocationUiMessagesOrDefault();
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] }));
19
+ return (_jsxs("div", { className: cn("group flex items-start justify-between gap-3 rounded-md border bg-background p-3 text-sm shadow-sm", paymentStatusChipClass(traveler.paymentStatus)), title: paymentStatusTooltip(traveler.paymentStatus, messages), 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, traveler.bookingSequence > 0 ? (_jsxs("span", { className: "text-muted-foreground tabular-nums", "aria-hidden": "true", children: ["(", traveler.bookingSequence, ")"] })) : 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] }));
20
20
  }
21
21
  export function ValidationSummary({ issues, resources, unallocatedCount, }) {
22
22
  const messages = useAllocationUiMessagesOrDefault();
@@ -80,3 +80,27 @@ function entryDetail(entry) {
80
80
  }
81
81
  return JSON.stringify(after);
82
82
  }
83
+ /**
84
+ * Border + background tint that mirrors the booking's payment status:
85
+ * red for unpaid, amber for partial, emerald for paid. Tailwind class
86
+ * names are written explicitly (no template strings) so the v4 JIT
87
+ * scanner picks them up.
88
+ *
89
+ * The saturation was bumped to `/20` background + `/70` border (from the
90
+ * earlier `/5` + `/40`) because the lower opacities rendered as no color
91
+ * on dark themes — the chips looked uncolored even though the helper
92
+ * was being applied.
93
+ */
94
+ export function paymentStatusChipClass(status) {
95
+ switch (status) {
96
+ case "paid":
97
+ return "border-emerald-500/70 bg-emerald-500/20 text-emerald-700 dark:text-emerald-200";
98
+ case "partial":
99
+ return "border-amber-500/70 bg-amber-500/20 text-amber-700 dark:text-amber-200";
100
+ case "unpaid":
101
+ return "border-rose-500/70 bg-rose-500/20 text-rose-700 dark:text-rose-200";
102
+ }
103
+ }
104
+ export function paymentStatusTooltip(status, messages) {
105
+ return messages.paymentStatusLabels?.[status] ?? status;
106
+ }
@@ -82,6 +82,32 @@ export type AllocationUiMessages = Record<string, unknown> & {
82
82
  generateResourcesFailed: string;
83
83
  autoAllocateFailed: string;
84
84
  paymentStatusLabels: Record<"paid" | "partial" | "unpaid", string>;
85
+ seatMapBuilder: {
86
+ heading: string;
87
+ description: string;
88
+ cellKindHeading: string;
89
+ cellKindHint: string;
90
+ cellKinds: Record<"seat" | "aisle" | "door" | "void", string>;
91
+ cellKindShort: Record<"seat" | "aisle" | "door" | "void", string>;
92
+ addRow: string;
93
+ removeRow: string;
94
+ rowAria: string;
95
+ columnAria: string;
96
+ seatCountSummary: string;
97
+ capacityChip: string;
98
+ presetHeading: string;
99
+ presetHint: string;
100
+ presets: {
101
+ standardCoach: string;
102
+ miniCoach: string;
103
+ largeBus: string;
104
+ doubleDecker: string;
105
+ withMidDoor: string;
106
+ };
107
+ resetSpec: string;
108
+ rowLabel: string;
109
+ voidDoorReminder: string;
110
+ };
85
111
  };
86
112
  export declare const allocationUiEn: {
87
113
  pageTitle: string;
@@ -181,6 +207,42 @@ export declare const allocationUiEn: {
181
207
  partial: string;
182
208
  unpaid: string;
183
209
  };
210
+ seatMapBuilder: {
211
+ heading: string;
212
+ description: string;
213
+ cellKindHeading: string;
214
+ cellKindHint: string;
215
+ cellKinds: {
216
+ seat: string;
217
+ aisle: string;
218
+ door: string;
219
+ void: string;
220
+ };
221
+ cellKindShort: {
222
+ seat: string;
223
+ aisle: string;
224
+ door: string;
225
+ void: string;
226
+ };
227
+ addRow: string;
228
+ removeRow: string;
229
+ rowAria: string;
230
+ columnAria: string;
231
+ seatCountSummary: string;
232
+ capacityChip: string;
233
+ presetHeading: string;
234
+ presetHint: string;
235
+ presets: {
236
+ standardCoach: string;
237
+ miniCoach: string;
238
+ largeBus: string;
239
+ doubleDecker: string;
240
+ withMidDoor: string;
241
+ };
242
+ resetSpec: string;
243
+ rowLabel: string;
244
+ voidDoorReminder: string;
245
+ };
184
246
  };
185
247
  export declare const allocationUiRo: {
186
248
  pageTitle: string;
@@ -280,6 +342,42 @@ export declare const allocationUiRo: {
280
342
  partial: string;
281
343
  unpaid: string;
282
344
  };
345
+ seatMapBuilder: {
346
+ heading: string;
347
+ description: string;
348
+ cellKindHeading: string;
349
+ cellKindHint: string;
350
+ cellKinds: {
351
+ seat: string;
352
+ aisle: string;
353
+ door: string;
354
+ void: string;
355
+ };
356
+ cellKindShort: {
357
+ seat: string;
358
+ aisle: string;
359
+ door: string;
360
+ void: string;
361
+ };
362
+ addRow: string;
363
+ removeRow: string;
364
+ rowAria: string;
365
+ columnAria: string;
366
+ seatCountSummary: string;
367
+ capacityChip: string;
368
+ presetHeading: string;
369
+ presetHint: string;
370
+ presets: {
371
+ standardCoach: string;
372
+ miniCoach: string;
373
+ largeBus: string;
374
+ doubleDecker: string;
375
+ withMidDoor: string;
376
+ };
377
+ resetSpec: string;
378
+ rowLabel: string;
379
+ voidDoorReminder: string;
380
+ };
283
381
  };
284
382
  export declare const allocationUiMessageDefinitions: {
285
383
  en: {
@@ -380,6 +478,42 @@ export declare const allocationUiMessageDefinitions: {
380
478
  partial: string;
381
479
  unpaid: string;
382
480
  };
481
+ seatMapBuilder: {
482
+ heading: string;
483
+ description: string;
484
+ cellKindHeading: string;
485
+ cellKindHint: string;
486
+ cellKinds: {
487
+ seat: string;
488
+ aisle: string;
489
+ door: string;
490
+ void: string;
491
+ };
492
+ cellKindShort: {
493
+ seat: string;
494
+ aisle: string;
495
+ door: string;
496
+ void: string;
497
+ };
498
+ addRow: string;
499
+ removeRow: string;
500
+ rowAria: string;
501
+ columnAria: string;
502
+ seatCountSummary: string;
503
+ capacityChip: string;
504
+ presetHeading: string;
505
+ presetHint: string;
506
+ presets: {
507
+ standardCoach: string;
508
+ miniCoach: string;
509
+ largeBus: string;
510
+ doubleDecker: string;
511
+ withMidDoor: string;
512
+ };
513
+ resetSpec: string;
514
+ rowLabel: string;
515
+ voidDoorReminder: string;
516
+ };
383
517
  };
384
518
  ro: {
385
519
  pageTitle: string;
@@ -479,6 +613,42 @@ export declare const allocationUiMessageDefinitions: {
479
613
  partial: string;
480
614
  unpaid: string;
481
615
  };
616
+ seatMapBuilder: {
617
+ heading: string;
618
+ description: string;
619
+ cellKindHeading: string;
620
+ cellKindHint: string;
621
+ cellKinds: {
622
+ seat: string;
623
+ aisle: string;
624
+ door: string;
625
+ void: string;
626
+ };
627
+ cellKindShort: {
628
+ seat: string;
629
+ aisle: string;
630
+ door: string;
631
+ void: string;
632
+ };
633
+ addRow: string;
634
+ removeRow: string;
635
+ rowAria: string;
636
+ columnAria: string;
637
+ seatCountSummary: string;
638
+ capacityChip: string;
639
+ presetHeading: string;
640
+ presetHint: string;
641
+ presets: {
642
+ standardCoach: string;
643
+ miniCoach: string;
644
+ largeBus: string;
645
+ doubleDecker: string;
646
+ withMidDoor: string;
647
+ };
648
+ resetSpec: string;
649
+ rowLabel: string;
650
+ voidDoorReminder: string;
651
+ };
482
652
  };
483
653
  };
484
654
  export type AllocationUiMessageOverrides = LocaleMessageOverrides<AllocationUiMessages>;
@@ -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":"AAEA,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EAEtB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAC3D,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,gBAAgB,EAAE,MAAM,CAAA;IACxB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,yBAAyB,EAAE,MAAM,CAAA;IACjC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,gBAAgB,EAAE,MAAM,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,yBAAyB,EAAE,MAAM,CAAA;IACjC,oBAAoB,EAAE,MAAM,CAAA;IAC5B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,iBAAiB,EAAE,MAAM,CAAA;IACzB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,sBAAsB,EAAE,MAAM,CAAA;IAC9B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,uBAAuB,EAAE,MAAM,CAAA;IAC/B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,mBAAmB,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,GAAG,QAAQ,EAAE,MAAM,CAAC,CAAA;IAClE,cAAc,EAAE;QACd,OAAO,EAAE,MAAM,CAAA;QACf,WAAW,EAAE,MAAM,CAAA;QACnB,eAAe,EAAE,MAAM,CAAA;QACvB,YAAY,EAAE,MAAM,CAAA;QACpB,SAAS,EAAE,MAAM,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,CAAA;QAC7D,aAAa,EAAE,MAAM,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,CAAA;QACjE,MAAM,EAAE,MAAM,CAAA;QACd,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,UAAU,EAAE,MAAM,CAAA;QAClB,gBAAgB,EAAE,MAAM,CAAA;QACxB,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;QACrB,UAAU,EAAE,MAAM,CAAA;QAClB,OAAO,EAAE;YACP,aAAa,EAAE,MAAM,CAAA;YACrB,SAAS,EAAE,MAAM,CAAA;YACjB,QAAQ,EAAE,MAAM,CAAA;YAChB,YAAY,EAAE,MAAM,CAAA;YACpB,WAAW,EAAE,MAAM,CAAA;SACpB,CAAA;QACD,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,gBAAgB,EAAE,MAAM,CAAA;KACzB,CAAA;CACF,CAAA;AAED,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwIK,CAAA;AAEhC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwIK,CAAA;AAIhC,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGe,CAAA;AAE1D,MAAM,MAAM,4BAA4B,GAAG,sBAAsB,CAAC,oBAAoB,CAAC,CAAA;AAUvF,wBAAgB,2BAA2B,CAAC,EAC1C,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACjC,SAAS,CAAC,EAAE,4BAA4B,GAAG,IAAI,CAAA;CAChD,wBAOA;AAED,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAClC,SAAS,CAAC,EAAE,4BAA4B,GAAG,IAAI,CAAA;CAChD,GAAG,gBAAgB,CAAC,oBAAoB,CAAC,CAUzC;AAED,wBAAgB,4BAA4B,CAAC,EAC3C,QAAQ,EACR,MAAM,EACN,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACjC,SAAS,CAAC,EAAE,4BAA4B,GAAG,IAAI,CAAA;CAChD,2CAWA;AAED,eAAO,MAAM,mBAAmB,8CAA8B,CAAA;AAC9D,eAAO,MAAM,uBAAuB,4BAAkC,CAAA;AAEtE,wBAAgB,4BAA4B,2CAE3C;AAED,wBAAgB,gCAAgC,yBAE/C"}
@@ -99,6 +99,42 @@ export const allocationUiEn = {
99
99
  partial: "Partially paid",
100
100
  unpaid: "Unpaid",
101
101
  },
102
+ seatMapBuilder: {
103
+ heading: "Seat map",
104
+ description: "Click a cell to cycle through seat → aisle → door → void. Capacity is computed from the seat cells.",
105
+ cellKindHeading: "Cell kinds",
106
+ cellKindHint: "Tip: doors and voids do not count toward capacity.",
107
+ cellKinds: {
108
+ seat: "Seat",
109
+ aisle: "Aisle",
110
+ door: "Door",
111
+ void: "Empty space",
112
+ },
113
+ cellKindShort: {
114
+ seat: "S",
115
+ aisle: "·",
116
+ door: "D",
117
+ void: " ",
118
+ },
119
+ addRow: "Add row",
120
+ removeRow: "Remove last row",
121
+ rowAria: "Row {row}",
122
+ columnAria: "Row {row}, column {column}",
123
+ seatCountSummary: "{count} seats",
124
+ capacityChip: "Capacity {count}",
125
+ presetHeading: "Start from a preset",
126
+ presetHint: "Pick a starter layout and tweak any cell.",
127
+ presets: {
128
+ standardCoach: "Standard coach (2-2, 11 rows)",
129
+ miniCoach: "Mini-coach (2-1, 7 rows)",
130
+ largeBus: "Large bus (3-2, 11 rows)",
131
+ doubleDecker: "Double-aisle (2-1-2, 11 rows)",
132
+ withMidDoor: "Coach with mid-door (2-2, door at row 7)",
133
+ },
134
+ resetSpec: "Clear layout",
135
+ rowLabel: "Row {row}",
136
+ voidDoorReminder: "Use a void cell for permanent obstacles (toilet, wheelchair spot). Use a door cell for boarding doors that interrupt seating mid-coach.",
137
+ },
102
138
  };
103
139
  export const allocationUiRo = {
104
140
  pageTitle: "Alocare",
@@ -198,6 +234,42 @@ export const allocationUiRo = {
198
234
  partial: "Partial achitata",
199
235
  unpaid: "Neachitata",
200
236
  },
237
+ seatMapBuilder: {
238
+ heading: "Harta locurilor",
239
+ description: "Apasa o celula pentru a comuta scaun → culoar → usa → spatiu gol. Capacitatea este calculata din celulele de tip scaun.",
240
+ cellKindHeading: "Tipuri de celule",
241
+ cellKindHint: "Sfat: usile si spatiile goale nu se numara in capacitate.",
242
+ cellKinds: {
243
+ seat: "Scaun",
244
+ aisle: "Culoar",
245
+ door: "Usa",
246
+ void: "Spatiu gol",
247
+ },
248
+ cellKindShort: {
249
+ seat: "S",
250
+ aisle: "·",
251
+ door: "U",
252
+ void: " ",
253
+ },
254
+ addRow: "Adauga rand",
255
+ removeRow: "Sterge ultimul rand",
256
+ rowAria: "Randul {row}",
257
+ columnAria: "Randul {row}, coloana {column}",
258
+ seatCountSummary: "{count} scaune",
259
+ capacityChip: "Capacitate {count}",
260
+ presetHeading: "Porneste de la o configuratie predefinita",
261
+ presetHint: "Alege o configuratie de start si modifica orice celula.",
262
+ presets: {
263
+ standardCoach: "Autocar standard (2-2, 11 randuri)",
264
+ miniCoach: "Minibus (2-1, 7 randuri)",
265
+ largeBus: "Autocar mare (3-2, 11 randuri)",
266
+ doubleDecker: "Doua culoare (2-1-2, 11 randuri)",
267
+ withMidDoor: "Autocar cu usa centrala (2-2, usa la randul 7)",
268
+ },
269
+ resetSpec: "Sterge configuratia",
270
+ rowLabel: "Randul {row}",
271
+ voidDoorReminder: "Foloseste o celula de tip spatiu gol pentru obstacole permanente (toaleta, loc pentru scaun cu rotile). Foloseste o usa pentru usile de imbarcare care intrerup scaunele in mijlocul autocarului.",
272
+ },
201
273
  };
202
274
  const fallbackLocale = "en";
203
275
  export const allocationUiMessageDefinitions = {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { SEAT_MAP_PRESETS, SeatMapBuilder, type SeatMapBuilderProps, } from "./components/seat-map-builder.js";
1
2
  export { SlotAllocationPage, type SlotAllocationPageExtraTab, type SlotAllocationPageProps, type SlotAllocationPageRenderContext, } from "./components/slot-allocation-page.js";
2
3
  export { type AllocationUiMessageOverrides, type AllocationUiMessages, AllocationUiMessagesProvider, allocationUiEn, allocationUiMessageDefinitions, allocationUiRo, getAllocationUiI18n, resolveAllocationUiMessages, useAllocationUiI18n, useAllocationUiI18nOrDefault, useAllocationUiMessages, useAllocationUiMessagesOrDefault, } from "./i18n/index.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,KAAK,mBAAmB,GACzB,MAAM,kCAAkC,CAAA;AACzC,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/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
+ export { SEAT_MAP_PRESETS, SeatMapBuilder, } from "./components/seat-map-builder.js";
1
2
  export { SlotAllocationPage, } from "./components/slot-allocation-page.js";
2
3
  export { AllocationUiMessagesProvider, allocationUiEn, allocationUiMessageDefinitions, allocationUiRo, getAllocationUiI18n, resolveAllocationUiMessages, useAllocationUiI18n, useAllocationUiI18nOrDefault, useAllocationUiMessages, useAllocationUiMessagesOrDefault, } from "./i18n/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/allocation-ui",
3
- "version": "0.69.1",
3
+ "version": "0.71.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.69.1",
38
- "@voyantjs/i18n": "0.69.1",
39
- "@voyantjs/ui": "0.69.1"
37
+ "@voyantjs/availability-react": "0.71.0",
38
+ "@voyantjs/i18n": "0.71.0",
39
+ "@voyantjs/ui": "0.71.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@tanstack/react-query": "^5.100.11",
@@ -47,10 +47,10 @@
47
47
  "react-dom": "^19.2.4",
48
48
  "typescript": "^6.0.2",
49
49
  "vitest": "^4.1.2",
50
- "@voyantjs/availability-react": "0.69.1",
51
- "@voyantjs/voyant-typescript-config": "0.1.0",
52
- "@voyantjs/ui": "0.69.1",
53
- "@voyantjs/i18n": "0.69.1"
50
+ "@voyantjs/availability-react": "0.71.0",
51
+ "@voyantjs/i18n": "0.71.0",
52
+ "@voyantjs/ui": "0.71.0",
53
+ "@voyantjs/voyant-typescript-config": "0.1.0"
54
54
  },
55
55
  "files": [
56
56
  "dist",