@voyantjs/allocation-ui 0.69.1 → 0.70.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.
@@ -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,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;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,2CA4FA"}
@@ -5,7 +5,7 @@ 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 { 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);
@@ -21,9 +21,10 @@ export function VehicleSeatsView({ seats, vehicles, occupants, sharingGroupLabel
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: () => {
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/allocation-ui",
3
- "version": "0.69.1",
3
+ "version": "0.70.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.70.0",
38
+ "@voyantjs/i18n": "0.70.0",
39
+ "@voyantjs/ui": "0.70.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.70.0",
51
+ "@voyantjs/i18n": "0.70.0",
52
+ "@voyantjs/ui": "0.70.0",
53
+ "@voyantjs/voyant-typescript-config": "0.1.0"
54
54
  },
55
55
  "files": [
56
56
  "dist",