@voyantjs/bookings-ui 0.35.0 → 0.37.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.
Files changed (55) hide show
  1. package/dist/components/booking-combobox.d.ts +13 -0
  2. package/dist/components/booking-combobox.d.ts.map +1 -0
  3. package/dist/components/booking-combobox.js +44 -0
  4. package/dist/components/booking-create-dialog.d.ts +9 -0
  5. package/dist/components/booking-create-dialog.d.ts.map +1 -1
  6. package/dist/components/booking-create-dialog.js +110 -90
  7. package/dist/components/booking-create-page.d.ts +11 -0
  8. package/dist/components/booking-create-page.d.ts.map +1 -0
  9. package/dist/components/booking-create-page.js +11 -0
  10. package/dist/components/booking-detail-page.d.ts.map +1 -1
  11. package/dist/components/booking-detail-page.js +4 -1
  12. package/dist/components/booking-item-list.d.ts.map +1 -1
  13. package/dist/components/booking-item-list.js +5 -3
  14. package/dist/components/booking-list-filters.d.ts +35 -0
  15. package/dist/components/booking-list-filters.d.ts.map +1 -0
  16. package/dist/components/booking-list-filters.js +148 -0
  17. package/dist/components/booking-list.d.ts.map +1 -1
  18. package/dist/components/booking-list.js +30 -46
  19. package/dist/components/person-picker-section.d.ts +15 -7
  20. package/dist/components/person-picker-section.d.ts.map +1 -1
  21. package/dist/components/person-picker-section.js +100 -21
  22. package/dist/components/price-breakdown-section.d.ts +16 -1
  23. package/dist/components/price-breakdown-section.d.ts.map +1 -1
  24. package/dist/components/price-breakdown-section.js +36 -5
  25. package/dist/components/product-picker-section.d.ts.map +1 -1
  26. package/dist/components/product-picker-section.js +38 -4
  27. package/dist/components/shared-room-section.d.ts +9 -8
  28. package/dist/components/shared-room-section.d.ts.map +1 -1
  29. package/dist/components/shared-room-section.js +67 -14
  30. package/dist/components/traveler-list.d.ts.map +1 -1
  31. package/dist/components/traveler-list.js +27 -16
  32. package/dist/i18n/en.d.ts +284 -1
  33. package/dist/i18n/en.d.ts.map +1 -1
  34. package/dist/i18n/en.js +300 -17
  35. package/dist/i18n/messages.d.ts +255 -1
  36. package/dist/i18n/messages.d.ts.map +1 -1
  37. package/dist/i18n/provider.d.ts +568 -2
  38. package/dist/i18n/provider.d.ts.map +1 -1
  39. package/dist/i18n/ro.d.ts +284 -1
  40. package/dist/i18n/ro.d.ts.map +1 -1
  41. package/dist/i18n/ro.js +301 -18
  42. package/dist/index.d.ts +3 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +3 -1
  45. package/dist/journey/components/booking-journey.d.ts.map +1 -1
  46. package/dist/journey/components/booking-journey.js +22 -13
  47. package/dist/journey/components/contract-preview-dialog.d.ts.map +1 -1
  48. package/dist/journey/components/contract-preview-dialog.js +9 -4
  49. package/dist/journey/components/journey-steps.d.ts.map +1 -1
  50. package/dist/journey/components/journey-steps.js +94 -72
  51. package/dist/journey/components/side-panel.d.ts.map +1 -1
  52. package/dist/journey/components/side-panel.js +58 -35
  53. package/dist/journey/components/step-header.d.ts.map +1 -1
  54. package/dist/journey/components/step-header.js +3 -19
  55. package/package.json +24 -20
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@voyantjs/ui/components/accordion";
4
4
  import { Card, CardContent } from "@voyantjs/ui/components/card";
5
5
  import { Skeleton } from "@voyantjs/ui/components/skeleton";
6
+ import { formatMessage, useBookingsUiMessagesOrDefault } from "../../i18n/index.js";
6
7
  /**
7
8
  * Right-rail summary panel. Shows what's being booked, an
8
9
  * accordion-per-step recap of the user's input, and the live
@@ -11,72 +12,87 @@ import { Skeleton } from "@voyantjs/ui/components/skeleton";
11
12
  * they've filled in elsewhere.
12
13
  */
13
14
  export function PriceSidePanel({ pricing, isQuoting, invalidReason, entitySummary, currentStep, steps, draft, className, }) {
14
- return (_jsxs(Card, { className: className, children: [entitySummary ? _jsx(EntityHeader, { summary: entitySummary }) : null, _jsxs(CardContent, { className: "space-y-4", children: [steps && steps.length > 0 && currentStep && draft ? (_jsx(StepRecap, { steps: steps, currentStep: currentStep, draft: draft })) : null, isQuoting && !pricing ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-4 w-24" }), _jsx(Skeleton, { className: "h-4 w-32" }), _jsx(Skeleton, { className: "h-4 w-20" })] })) : null, invalidReason ? _jsx("p", { className: "text-destructive text-sm", children: invalidReason }) : null, pricing ? (_jsxs("div", { className: "space-y-2 border-t pt-4", children: [_jsx("ul", { className: "space-y-1 text-sm", children: pricing.lines.map((line) => (_jsxs("li", { className: "flex justify-between", children: [_jsxs("span", { children: [line.label, line.quantity ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00D7 ", line.quantity] })) : null] }), _jsx("span", { children: formatMoney(line.totalAmount, pricing.currency) })] }, `${line.kind}-${line.label}-${line.totalAmount}`))) }), pricing.taxes.length > 0 ? (_jsx("ul", { className: "space-y-1 border-t pt-2 text-sm text-muted-foreground", children: pricing.taxes.map((tax) => (_jsxs("li", { className: "flex justify-between", children: [_jsx("span", { children: tax.label }), _jsx("span", { children: formatMoney(tax.amount, pricing.currency) })] }, tax.code))) })) : null, _jsxs("div", { className: "flex justify-between border-t pt-2 font-medium", children: [_jsx("span", { children: "Total" }), _jsx("span", { children: formatMoney(pricing.total, pricing.currency) })] })] })) : null] })] }));
15
+ const messages = useBookingsUiMessagesOrDefault();
16
+ return (_jsxs(Card, { className: className, children: [entitySummary ? _jsx(EntityHeader, { summary: entitySummary }) : null, _jsxs(CardContent, { className: "space-y-4", children: [steps && steps.length > 0 && currentStep && draft ? (_jsx(StepRecap, { steps: steps, currentStep: currentStep, draft: draft })) : null, isQuoting && !pricing ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-4 w-24" }), _jsx(Skeleton, { className: "h-4 w-32" }), _jsx(Skeleton, { className: "h-4 w-20" })] })) : null, invalidReason ? _jsx("p", { className: "text-destructive text-sm", children: invalidReason }) : null, pricing ? (_jsxs("div", { className: "space-y-2 border-t pt-4", children: [_jsx("ul", { className: "space-y-1 text-sm", children: pricing.lines.map((line) => (_jsxs("li", { className: "flex justify-between", children: [_jsxs("span", { children: [line.label, line.quantity ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00D7 ", line.quantity] })) : null] }), _jsx("span", { children: formatMoney(line.totalAmount, pricing.currency) })] }, `${line.kind}-${line.label}-${line.totalAmount}`))) }), pricing.taxes.length > 0 ? (_jsx("ul", { className: "space-y-1 border-t pt-2 text-sm text-muted-foreground", children: pricing.taxes.map((tax) => (_jsxs("li", { className: "flex justify-between", children: [_jsx("span", { children: tax.label }), _jsx("span", { children: formatMoney(tax.amount, pricing.currency) })] }, tax.code))) })) : null, _jsxs("div", { className: "flex justify-between border-t pt-2 font-medium", children: [_jsx("span", { children: messages.bookingJourney.sidePanel.total }), _jsx("span", { children: formatMoney(pricing.total, pricing.currency) })] })] })) : null] })] }));
15
17
  }
16
18
  function EntityHeader({ summary }) {
17
- return (_jsxs("div", { className: "overflow-hidden rounded-t-xl", children: [summary.heroImageUrl ? (_jsx("img", { src: summary.heroImageUrl, alt: summary.name, className: "aspect-video w-full object-cover" })) : null, _jsxs("div", { className: "space-y-1 px-6 pt-4 pb-2", children: [_jsx("div", { className: "text-muted-foreground text-xs uppercase tracking-wide", children: "You're booking" }), _jsx("div", { className: "font-semibold leading-tight", children: summary.name }), summary.subtitle ? (_jsx("div", { className: "text-muted-foreground text-sm", children: summary.subtitle })) : null, summary.whenLabel || summary.locationLabel ? (_jsx("div", { className: "text-muted-foreground text-xs", children: [summary.whenLabel, summary.locationLabel].filter(Boolean).join(" · ") })) : null] })] }));
19
+ const messages = useBookingsUiMessagesOrDefault();
20
+ return (_jsxs("div", { className: "overflow-hidden rounded-t-xl", children: [summary.heroImageUrl ? (_jsx("img", { src: summary.heroImageUrl, alt: summary.name, className: "aspect-video w-full object-cover" })) : null, _jsxs("div", { className: "space-y-1 px-6 pt-4 pb-2", children: [_jsx("div", { className: "text-muted-foreground text-xs uppercase tracking-wide", children: messages.bookingJourney.sidePanel.youAreBooking }), _jsx("div", { className: "font-semibold leading-tight", children: summary.name }), summary.subtitle ? (_jsx("div", { className: "text-muted-foreground text-sm", children: summary.subtitle })) : null, summary.whenLabel || summary.locationLabel ? (_jsx("div", { className: "text-muted-foreground text-xs", children: [summary.whenLabel, summary.locationLabel].filter(Boolean).join(" · ") })) : null] })] }));
18
21
  }
19
22
  function StepRecap({ steps, currentStep, draft, }) {
23
+ const messages = useBookingsUiMessagesOrDefault();
20
24
  if (!draft)
21
25
  return null;
22
26
  // Default-open the current step. Uncontrolled — users can toggle
23
27
  // freely. Re-mounts when currentStep changes (key) so the
24
28
  // newly-active step opens automatically as the user advances.
25
- return (_jsx(Accordion, { defaultValue: [currentStep], multiple: true, children: steps.map((step) => (_jsxs(AccordionItem, { value: step, children: [_jsx(AccordionTrigger, { className: "py-3", children: _jsxs("div", { className: "flex flex-1 flex-col text-left", children: [_jsx("span", { className: step === currentStep ? "font-semibold" : "text-muted-foreground font-medium", children: STEP_LABELS[step] }), _jsx(StepSummaryLine, { step: step, draft: draft })] }) }), _jsx(AccordionContent, { children: _jsx(StepDetails, { step: step, draft: draft }) })] }, step))) }, currentStep));
29
+ return (_jsx(Accordion, { defaultValue: [currentStep], multiple: true, children: steps.map((step) => (_jsxs(AccordionItem, { value: step, children: [_jsx(AccordionTrigger, { className: "py-3", children: _jsxs("div", { className: "flex flex-1 flex-col text-left", children: [_jsx("span", { className: step === currentStep ? "font-semibold" : "text-muted-foreground font-medium", children: stepLabel(step, messages) }), _jsx(StepSummaryLine, { step: step, draft: draft })] }) }), _jsx(AccordionContent, { children: _jsx(StepDetails, { step: step, draft: draft }) })] }, step))) }, currentStep));
26
30
  }
27
31
  function StepSummaryLine({ step, draft, }) {
28
- const text = stepHeadline(step, draft);
32
+ const messages = useBookingsUiMessagesOrDefault();
33
+ const text = stepHeadline(step, draft, messages);
29
34
  if (!text)
30
35
  return null;
31
36
  return _jsx("span", { className: "text-muted-foreground text-xs", children: text });
32
37
  }
33
- function stepHeadline(step, draft) {
38
+ function stepHeadline(step, draft, messages) {
34
39
  switch (step) {
35
40
  case "configure": {
36
41
  const total = paxTotal(draft);
37
42
  const slot = draft.configure?.departureSlotId ?? draft.configure?.departureDate ?? undefined;
38
43
  const range = draft.configure?.dateRange;
39
44
  const when = range?.checkIn && range?.checkOut ? `${range.checkIn} → ${range.checkOut}` : slot;
40
- return when ? `${total} ${total === 1 ? "guest" : "guests"} · ${when}` : `${total} guests`;
45
+ const guestLabel = total === 1
46
+ ? messages.bookingJourney.sidePanel.guestSingular
47
+ : messages.bookingJourney.sidePanel.guestPlural;
48
+ return when ? `${total} ${guestLabel} · ${when}` : `${total} ${guestLabel}`;
41
49
  }
42
50
  case "billing": {
43
51
  const c = draft.billing.contact;
44
52
  const name = [c.firstName, c.lastName].filter(Boolean).join(" ").trim();
45
- return name || c.email || "Not set";
53
+ return name || c.email || messages.bookingJourney.values.notSet;
46
54
  }
47
55
  case "travelers": {
48
56
  const filled = draft.travelers.filter((t) => t.firstName && t.lastName).length;
49
- return `${filled} of ${draft.travelers.length} filled`;
57
+ return formatMessage(messages.bookingJourney.sidePanel.filledOf, {
58
+ filled,
59
+ total: draft.travelers.length,
60
+ });
50
61
  }
51
62
  case "accommodation": {
52
63
  const rooms = draft.accommodation?.rooms ?? [];
53
64
  if (rooms.length === 0)
54
65
  return "";
55
- return `${rooms.length} room${rooms.length === 1 ? "" : "s"}`;
66
+ return `${rooms.length} ${rooms.length === 1
67
+ ? messages.bookingJourney.sidePanel.roomSingular
68
+ : messages.bookingJourney.sidePanel.roomPlural}`;
56
69
  }
57
70
  case "addons": {
58
71
  const addons = draft.addons ?? [];
59
72
  if (addons.length === 0)
60
- return "None";
61
- return `${addons.length} add-on${addons.length === 1 ? "" : "s"}`;
73
+ return messages.bookingJourney.values.none;
74
+ return `${addons.length} ${addons.length === 1
75
+ ? messages.bookingJourney.sidePanel.addOnSingular
76
+ : messages.bookingJourney.sidePanel.addOnPlural}`;
62
77
  }
63
78
  case "payment": {
64
79
  const intent = draft.payment.intent;
65
80
  if (intent === "card")
66
- return "Card";
81
+ return messages.bookingJourney.sidePanel.card;
67
82
  if (intent === "hold")
68
- return "Hold";
83
+ return messages.bookingJourney.sidePanel.hold;
69
84
  if (intent === "ticket_on_credit")
70
- return "On credit";
85
+ return messages.bookingJourney.sidePanel.onCredit;
71
86
  return "";
72
87
  }
73
88
  case "review":
74
- return "Confirm and book";
89
+ return messages.bookingJourney.sidePanel.confirmAndBook;
75
90
  default:
76
91
  return "";
77
92
  }
78
93
  }
79
94
  function StepDetails({ step, draft, }) {
95
+ const messages = useBookingsUiMessagesOrDefault();
80
96
  switch (step) {
81
97
  case "configure":
82
98
  return _jsx(ConfigureDetails, { draft: draft });
@@ -91,25 +107,31 @@ function StepDetails({ step, draft, }) {
91
107
  case "payment":
92
108
  return _jsx(PaymentDetails, { draft: draft });
93
109
  case "review":
94
- return (_jsx("p", { className: "text-muted-foreground text-xs", children: "Review your details and confirm to book." }));
110
+ return (_jsx("p", { className: "text-muted-foreground text-xs", children: messages.bookingJourney.sidePanel.reviewDetails }));
95
111
  default:
96
112
  return null;
97
113
  }
98
114
  }
99
115
  function ConfigureDetails({ draft, }) {
116
+ const messages = useBookingsUiMessagesOrDefault();
100
117
  const cfg = draft.configure ?? {};
101
118
  const range = cfg.dateRange;
102
- return (_jsxs("dl", { className: "space-y-1 text-xs", children: [_jsx(Row, { label: "Adults", value: String(cfg.pax?.adult ?? 0) }), (cfg.pax?.child ?? 0) > 0 ? _jsx(Row, { label: "Children", value: String(cfg.pax.child) }) : null, (cfg.pax?.infant ?? 0) > 0 ? _jsx(Row, { label: "Infants", value: String(cfg.pax.infant) }) : null, cfg.departureSlotId ? _jsx(Row, { label: "Departure", value: cfg.departureSlotId }) : null, cfg.departureDate ? _jsx(Row, { label: "Date", value: cfg.departureDate }) : null, range?.checkIn ? _jsx(Row, { label: "Check-in", value: range.checkIn }) : null, range?.checkOut ? _jsx(Row, { label: "Check-out", value: range.checkOut }) : null, cfg.cabinCategoryId ? _jsx(Row, { label: "Cabin", value: cfg.cabinCategoryId }) : null] }));
119
+ return (_jsxs("dl", { className: "space-y-1 text-xs", children: [_jsx(Row, { label: messages.bookingJourney.sidePanel.adults, value: String(cfg.pax?.adult ?? 0) }), (cfg.pax?.child ?? 0) > 0 ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.children, value: String(cfg.pax.child) })) : null, (cfg.pax?.infant ?? 0) > 0 ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.infants, value: String(cfg.pax.infant) })) : null, cfg.departureSlotId ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.departure, value: cfg.departureSlotId })) : null, cfg.departureDate ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.date, value: cfg.departureDate })) : null, range?.checkIn ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.checkIn, value: range.checkIn })) : null, range?.checkOut ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.checkOut, value: range.checkOut })) : null, cfg.cabinCategoryId ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.cabin, value: cfg.cabinCategoryId })) : null] }));
103
120
  }
104
121
  function BillingDetails({ draft, }) {
122
+ const messages = useBookingsUiMessagesOrDefault();
105
123
  const c = draft.billing.contact;
106
124
  const a = draft.billing.address;
107
125
  const addressLine = [a.line1, a.line2, a.city, a.postal, a.country].filter(Boolean).join(", ");
108
- return (_jsxs("dl", { className: "space-y-1 text-xs", children: [_jsx(Row, { label: "Name", value: [c.firstName, c.lastName].filter(Boolean).join(" ") || "—" }), _jsx(Row, { label: "Email", value: c.email || "—" }), c.phone ? _jsx(Row, { label: "Phone", value: c.phone }) : null, _jsx(Row, { label: "Buyer", value: draft.billing.buyerType === "B2B" ? "Company" : "Individual" }), draft.billing.company?.name ? (_jsx(Row, { label: "Company", value: draft.billing.company.name })) : null, draft.billing.company?.vatId ? (_jsx(Row, { label: "VAT", value: draft.billing.company.vatId })) : null, addressLine ? _jsx(Row, { label: "Address", value: addressLine }) : null] }));
126
+ return (_jsxs("dl", { className: "space-y-1 text-xs", children: [_jsx(Row, { label: messages.bookingJourney.sidePanel.name, value: [c.firstName, c.lastName].filter(Boolean).join(" ") ||
127
+ messages.bookingJourney.values.noValue }), _jsx(Row, { label: messages.bookingJourney.sidePanel.email, value: c.email || messages.bookingJourney.values.noValue }), c.phone ? _jsx(Row, { label: messages.bookingJourney.sidePanel.phone, value: c.phone }) : null, _jsx(Row, { label: messages.bookingJourney.sidePanel.buyer, value: draft.billing.buyerType === "B2B"
128
+ ? messages.bookingJourney.sidePanel.company
129
+ : messages.bookingJourney.sidePanel.individual }), draft.billing.company?.name ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.company, value: draft.billing.company.name })) : null, draft.billing.company?.vatId ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.vat, value: draft.billing.company.vatId })) : null, addressLine ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.address, value: addressLine })) : null] }));
109
130
  }
110
131
  function TravelersDetails({ draft, }) {
132
+ const messages = useBookingsUiMessagesOrDefault();
111
133
  if (draft.travelers.length === 0) {
112
- return _jsx("p", { className: "text-muted-foreground text-xs", children: "No travelers yet." });
134
+ return (_jsx("p", { className: "text-muted-foreground text-xs", children: messages.bookingJourney.sidePanel.noTravelersYet }));
113
135
  }
114
136
  return (_jsx("ul", { className: "space-y-3 text-xs", children: draft.travelers.map((t, i) => {
115
137
  const key = t.rowId ?? `t-${i}`;
@@ -120,44 +142,45 @@ function TravelersDetails({ draft, }) {
120
142
  const docLine = [docType, docNum, docExpiry ? `exp ${docExpiry}` : null]
121
143
  .filter(Boolean)
122
144
  .join(" · ");
123
- return (_jsxs("li", { className: "space-y-0.5", children: [_jsxs("div", { className: "flex justify-between gap-2", children: [_jsxs("span", { className: "text-muted-foreground", children: ["Traveler ", i + 1] }), _jsx("span", { className: "truncate font-medium", children: name || "—" })] }), t.email ? _jsx("div", { className: "text-muted-foreground truncate", children: t.email }) : null, t.phone ? _jsx("div", { className: "text-muted-foreground", children: t.phone }) : null, t.dateOfBirth ? (_jsxs("div", { className: "text-muted-foreground", children: ["DOB ", t.dateOfBirth] })) : null, docLine ? _jsx("div", { className: "text-muted-foreground", children: docLine }) : null] }, key));
145
+ return (_jsxs("li", { className: "space-y-0.5", children: [_jsxs("div", { className: "flex justify-between gap-2", children: [_jsx("span", { className: "text-muted-foreground", children: formatMessage(messages.bookingJourney.sidePanel.travelerNumber, {
146
+ number: i + 1,
147
+ }) }), _jsx("span", { className: "truncate font-medium", children: name || messages.bookingJourney.values.noValue })] }), t.email ? _jsx("div", { className: "text-muted-foreground truncate", children: t.email }) : null, t.phone ? _jsx("div", { className: "text-muted-foreground", children: t.phone }) : null, t.dateOfBirth ? (_jsxs("div", { className: "text-muted-foreground", children: [messages.bookingJourney.sidePanel.dob, " ", t.dateOfBirth] })) : null, docLine ? _jsx("div", { className: "text-muted-foreground", children: docLine }) : null] }, key));
124
148
  }) }));
125
149
  }
126
150
  function AccommodationDetails({ draft, }) {
151
+ const messages = useBookingsUiMessagesOrDefault();
127
152
  const rooms = draft.accommodation?.rooms ?? [];
128
153
  if (rooms.length === 0) {
129
- return _jsx("p", { className: "text-muted-foreground text-xs", children: "Not selected." });
154
+ return (_jsx("p", { className: "text-muted-foreground text-xs", children: messages.bookingJourney.sidePanel.notSelected }));
130
155
  }
131
156
  return (_jsx("ul", { className: "space-y-1 text-xs", children: rooms.map((r) => (_jsxs("li", { className: "flex justify-between gap-2", children: [_jsx("span", { className: "truncate", children: r.optionUnitId }), _jsxs("span", { className: "text-muted-foreground", children: ["\u00D7 ", r.quantity, r.ratePlanId ? ` · ${r.ratePlanId}` : ""] })] }, `${r.optionUnitId}-${r.ratePlanId ?? ""}-${r.quantity}`))) }));
132
157
  }
133
158
  function AddonsDetails({ draft, }) {
159
+ const messages = useBookingsUiMessagesOrDefault();
134
160
  const addons = draft.addons ?? [];
135
161
  if (addons.length === 0) {
136
- return _jsx("p", { className: "text-muted-foreground text-xs", children: "No add-ons selected." });
162
+ return (_jsx("p", { className: "text-muted-foreground text-xs", children: messages.bookingJourney.sidePanel.noAddonsSelected }));
137
163
  }
138
164
  return (_jsx("ul", { className: "space-y-1 text-xs", children: addons.map((a) => (_jsxs("li", { className: "flex justify-between gap-2", children: [_jsx("span", { className: "truncate", children: a.extraId }), _jsxs("span", { className: "text-muted-foreground", children: ["\u00D7 ", a.quantity] })] }, `${a.extraId}-${a.quantity}`))) }));
139
165
  }
140
166
  function PaymentDetails({ draft, }) {
167
+ const messages = useBookingsUiMessagesOrDefault();
141
168
  const intent = draft.payment.intent;
142
169
  const label = intent === "card"
143
- ? "Pay by card"
170
+ ? messages.bookingJourney.sidePanel.payByCard
144
171
  : intent === "ticket_on_credit"
145
- ? "Ticket on credit"
146
- : "Hold (no charge yet)";
147
- return (_jsxs("dl", { className: "space-y-1 text-xs", children: [_jsx(Row, { label: "Method", value: label }), draft.payment.schedule ? (_jsx(Row, { label: "Schedule", value: String(draft.payment.schedule) })) : null] }));
172
+ ? messages.bookingJourney.sidePanel.ticketOnCredit
173
+ : messages.bookingJourney.sidePanel.holdNoChargeYet;
174
+ return (_jsxs("dl", { className: "space-y-1 text-xs", children: [_jsx(Row, { label: messages.bookingJourney.sidePanel.method, value: label }), draft.payment.schedule ? (_jsx(Row, { label: messages.bookingJourney.sidePanel.schedule, value: String(draft.payment.schedule) })) : null] }));
148
175
  }
149
176
  function Row({ label, value }) {
150
177
  return (_jsxs("div", { className: "flex justify-between gap-2", children: [_jsx("dt", { className: "text-muted-foreground", children: label }), _jsx("dd", { className: "truncate text-right", children: value })] }));
151
178
  }
152
- const STEP_LABELS = {
153
- configure: "Configure",
154
- billing: "Billing & contact",
155
- travelers: "Travelers",
156
- accommodation: "Accommodation",
157
- addons: "Add-ons",
158
- payment: "Payment",
159
- review: "Review",
160
- };
179
+ function stepLabel(step, messages) {
180
+ if (step === "billing")
181
+ return messages.bookingJourney.steps.billingAndContact;
182
+ return messages.bookingJourney.steps[step];
183
+ }
161
184
  function paxTotal(draft) {
162
185
  const pax = draft.configure?.pax ?? {};
163
186
  return (pax.adult ?? 0) + (pax.child ?? 0) + (pax.infant ?? 0);
@@ -1 +1 @@
1
- {"version":3,"file":"step-header.d.ts","sourceRoot":"","sources":["../../../src/journey/components/step-header.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAElE,UAAU,eAAgB,SAAQ,kBAAkB;IAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;CACtC;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,OAAO,EACP,KAAK,EACL,QAAQ,GACT,EAAE,eAAe,GAAG,KAAK,CAAC,YAAY,CAuBtC"}
1
+ {"version":3,"file":"step-header.d.ts","sourceRoot":"","sources":["../../../src/journey/components/step-header.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAElE,UAAU,eAAgB,SAAQ,kBAAkB;IAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;CACtC;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,OAAO,EACP,KAAK,EACL,QAAQ,GACT,EAAE,eAAe,GAAG,KAAK,CAAC,YAAY,CAwBtC"}
@@ -1,28 +1,12 @@
1
1
  "use client";
2
2
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
3
  import { Button } from "@voyantjs/ui/components/button";
4
+ import { useBookingsUiMessagesOrDefault } from "../../i18n/index.js";
4
5
  export function StepHeader({ current, visited, steps, onJumpTo, }) {
6
+ const messages = useBookingsUiMessagesOrDefault();
5
7
  return (_jsx("ol", { className: "flex flex-wrap gap-2", children: steps.map((step, idx) => {
6
8
  const isCurrent = step === current;
7
9
  const isVisited = visited.includes(step);
8
- return (_jsx("li", { children: _jsxs(Button, { type: "button", variant: isCurrent ? "default" : isVisited ? "outline" : "ghost", size: "sm", disabled: !isVisited && !isCurrent, onClick: () => onJumpTo(step), children: [_jsxs("span", { className: "mr-1 font-mono text-xs", children: [idx + 1, "."] }), labelForStep(step)] }) }, step));
10
+ return (_jsx("li", { children: _jsxs(Button, { type: "button", variant: isCurrent ? "default" : isVisited ? "outline" : "ghost", size: "sm", disabled: !isVisited && !isCurrent, onClick: () => onJumpTo(step), children: [_jsxs("span", { className: "mr-1 font-mono text-xs", children: [idx + 1, "."] }), messages.bookingJourney.steps[step]] }) }, step));
9
11
  }) }));
10
12
  }
11
- function labelForStep(step) {
12
- switch (step) {
13
- case "configure":
14
- return "Configure";
15
- case "billing":
16
- return "Billing";
17
- case "travelers":
18
- return "Travelers";
19
- case "accommodation":
20
- return "Accommodation";
21
- case "addons":
22
- return "Add-ons";
23
- case "payment":
24
- return "Payment";
25
- case "review":
26
- return "Review";
27
- }
28
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/bookings-ui",
3
- "version": "0.35.0",
3
+ "version": "0.37.1",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -51,18 +51,20 @@
51
51
  "react-dom": "^19.0.0",
52
52
  "react-hook-form": "^7.60.0",
53
53
  "zod": "^4.3.6",
54
- "@voyantjs/availability-react": "0.35.0",
55
- "@voyantjs/bookings-react": "0.35.0",
56
- "@voyantjs/catalog": "0.35.0",
57
- "@voyantjs/catalog-react": "0.35.0",
58
- "@voyantjs/crm-react": "0.35.0",
59
- "@voyantjs/finance-react": "0.35.0",
60
- "@voyantjs/legal-react": "0.35.0",
61
- "@voyantjs/products-react": "0.35.0",
62
- "@voyantjs/ui": "0.35.0"
54
+ "@voyantjs/availability-react": "0.37.1",
55
+ "@voyantjs/bookings-react": "0.37.1",
56
+ "@voyantjs/catalog": "0.37.1",
57
+ "@voyantjs/catalog-react": "0.37.1",
58
+ "@voyantjs/crm-react": "0.37.1",
59
+ "@voyantjs/crm-ui": "0.37.1",
60
+ "@voyantjs/finance-react": "0.37.1",
61
+ "@voyantjs/legal-react": "0.37.1",
62
+ "@voyantjs/products-react": "0.37.1",
63
+ "@voyantjs/suppliers-react": "0.37.1",
64
+ "@voyantjs/ui": "0.37.1"
63
65
  },
64
66
  "dependencies": {
65
- "@voyantjs/i18n": "0.35.0"
67
+ "@voyantjs/i18n": "0.37.1"
66
68
  },
67
69
  "devDependencies": {
68
70
  "@tanstack/react-query": "^5.96.2",
@@ -75,16 +77,18 @@
75
77
  "typescript": "^6.0.2",
76
78
  "vitest": "^4.1.2",
77
79
  "zod": "^4.3.6",
78
- "@voyantjs/availability-react": "0.35.0",
79
- "@voyantjs/bookings-react": "0.35.0",
80
- "@voyantjs/catalog": "0.35.0",
81
- "@voyantjs/catalog-react": "0.35.0",
82
- "@voyantjs/crm-react": "0.35.0",
83
- "@voyantjs/finance-react": "0.35.0",
84
- "@voyantjs/legal-react": "0.35.0",
85
- "@voyantjs/products-react": "0.35.0",
80
+ "@voyantjs/availability-react": "0.37.1",
81
+ "@voyantjs/bookings-react": "0.37.1",
82
+ "@voyantjs/catalog": "0.37.1",
83
+ "@voyantjs/catalog-react": "0.37.1",
84
+ "@voyantjs/crm-react": "0.37.1",
85
+ "@voyantjs/crm-ui": "0.37.1",
86
+ "@voyantjs/finance-react": "0.37.1",
87
+ "@voyantjs/legal-react": "0.37.1",
88
+ "@voyantjs/products-react": "0.37.1",
89
+ "@voyantjs/suppliers-react": "0.37.1",
86
90
  "@voyantjs/voyant-typescript-config": "0.1.0",
87
- "@voyantjs/ui": "0.35.0"
91
+ "@voyantjs/ui": "0.37.1"
88
92
  },
89
93
  "files": [
90
94
  "dist",