@voyantjs/bookings-ui 0.20.0 → 0.21.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.
Files changed (50) hide show
  1. package/dist/components/booking-dialog.d.ts.map +1 -1
  2. package/dist/components/booking-dialog.js +10 -1
  3. package/dist/components/booking-group-section.d.ts +11 -1
  4. package/dist/components/booking-group-section.d.ts.map +1 -1
  5. package/dist/components/booking-group-section.js +16 -2
  6. package/dist/components/booking-item-list.d.ts.map +1 -1
  7. package/dist/components/booking-item-list.js +71 -7
  8. package/dist/components/booking-list.d.ts.map +1 -1
  9. package/dist/components/booking-list.js +11 -3
  10. package/dist/components/booking-payments-summary.d.ts +28 -1
  11. package/dist/components/booking-payments-summary.d.ts.map +1 -1
  12. package/dist/components/booking-payments-summary.js +66 -11
  13. package/dist/components/traveler-list.d.ts +2 -1
  14. package/dist/components/traveler-list.d.ts.map +1 -1
  15. package/dist/components/traveler-list.js +126 -12
  16. package/dist/i18n/en.d.ts +12 -0
  17. package/dist/i18n/en.d.ts.map +1 -1
  18. package/dist/i18n/en.js +13 -1
  19. package/dist/i18n/messages.d.ts +14 -1
  20. package/dist/i18n/messages.d.ts.map +1 -1
  21. package/dist/i18n/provider.d.ts +24 -0
  22. package/dist/i18n/provider.d.ts.map +1 -1
  23. package/dist/i18n/ro.d.ts +12 -0
  24. package/dist/i18n/ro.d.ts.map +1 -1
  25. package/dist/i18n/ro.js +13 -1
  26. package/dist/journey/components/booking-journey.d.ts +3 -0
  27. package/dist/journey/components/booking-journey.d.ts.map +1 -0
  28. package/dist/journey/components/booking-journey.js +376 -0
  29. package/dist/journey/components/contract-preview-dialog.d.ts +47 -0
  30. package/dist/journey/components/contract-preview-dialog.d.ts.map +1 -0
  31. package/dist/journey/components/contract-preview-dialog.js +119 -0
  32. package/dist/journey/components/journey-steps.d.ts +47 -0
  33. package/dist/journey/components/journey-steps.d.ts.map +1 -0
  34. package/dist/journey/components/journey-steps.js +582 -0
  35. package/dist/journey/components/side-panel.d.ts +12 -0
  36. package/dist/journey/components/side-panel.d.ts.map +1 -0
  37. package/dist/journey/components/side-panel.js +172 -0
  38. package/dist/journey/components/step-header.d.ts +7 -0
  39. package/dist/journey/components/step-header.d.ts.map +1 -0
  40. package/dist/journey/components/step-header.js +28 -0
  41. package/dist/journey/index.d.ts +18 -0
  42. package/dist/journey/index.d.ts.map +1 -0
  43. package/dist/journey/index.js +17 -0
  44. package/dist/journey/lib/draft-state.d.ts +34 -0
  45. package/dist/journey/lib/draft-state.d.ts.map +1 -0
  46. package/dist/journey/lib/draft-state.js +54 -0
  47. package/dist/journey/types.d.ts +248 -0
  48. package/dist/journey/types.d.ts.map +1 -0
  49. package/dist/journey/types.js +17 -0
  50. package/package.json +26 -16
@@ -0,0 +1,172 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@voyantjs/ui/components/accordion";
4
+ import { Card, CardContent } from "@voyantjs/ui/components/card";
5
+ import { Skeleton } from "@voyantjs/ui/components/skeleton";
6
+ /**
7
+ * Right-rail summary panel. Shows what's being booked, an
8
+ * accordion-per-step recap of the user's input, and the live
9
+ * pricing breakdown at the bottom. The current step's accordion is
10
+ * expanded by default; users can click any step to peek at what
11
+ * they've filled in elsewhere.
12
+ */
13
+ 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
+ }
16
+ 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] })] }));
18
+ }
19
+ function StepRecap({ steps, currentStep, draft, }) {
20
+ if (!draft)
21
+ return null;
22
+ // Default-open the current step. Uncontrolled — users can toggle
23
+ // freely. Re-mounts when currentStep changes (key) so the
24
+ // 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));
26
+ }
27
+ function StepSummaryLine({ step, draft, }) {
28
+ const text = stepHeadline(step, draft);
29
+ if (!text)
30
+ return null;
31
+ return _jsx("span", { className: "text-muted-foreground text-xs", children: text });
32
+ }
33
+ function stepHeadline(step, draft) {
34
+ switch (step) {
35
+ case "configure": {
36
+ const total = paxTotal(draft);
37
+ const slot = draft.configure?.departureSlotId ?? draft.configure?.departureDate ?? undefined;
38
+ const range = draft.configure?.dateRange;
39
+ const when = range?.checkIn && range?.checkOut ? `${range.checkIn} → ${range.checkOut}` : slot;
40
+ return when ? `${total} ${total === 1 ? "guest" : "guests"} · ${when}` : `${total} guests`;
41
+ }
42
+ case "billing": {
43
+ const c = draft.billing.contact;
44
+ const name = [c.firstName, c.lastName].filter(Boolean).join(" ").trim();
45
+ return name || c.email || "Not set";
46
+ }
47
+ case "travelers": {
48
+ const filled = draft.travelers.filter((t) => t.firstName && t.lastName).length;
49
+ return `${filled} of ${draft.travelers.length} filled`;
50
+ }
51
+ case "accommodation": {
52
+ const rooms = draft.accommodation?.rooms ?? [];
53
+ if (rooms.length === 0)
54
+ return "";
55
+ return `${rooms.length} room${rooms.length === 1 ? "" : "s"}`;
56
+ }
57
+ case "addons": {
58
+ const addons = draft.addons ?? [];
59
+ if (addons.length === 0)
60
+ return "None";
61
+ return `${addons.length} add-on${addons.length === 1 ? "" : "s"}`;
62
+ }
63
+ case "payment": {
64
+ const intent = draft.payment.intent;
65
+ if (intent === "card")
66
+ return "Card";
67
+ if (intent === "hold")
68
+ return "Hold";
69
+ if (intent === "ticket_on_credit")
70
+ return "On credit";
71
+ return "";
72
+ }
73
+ case "review":
74
+ return "Confirm and book";
75
+ default:
76
+ return "";
77
+ }
78
+ }
79
+ function StepDetails({ step, draft, }) {
80
+ switch (step) {
81
+ case "configure":
82
+ return _jsx(ConfigureDetails, { draft: draft });
83
+ case "billing":
84
+ return _jsx(BillingDetails, { draft: draft });
85
+ case "travelers":
86
+ return _jsx(TravelersDetails, { draft: draft });
87
+ case "accommodation":
88
+ return _jsx(AccommodationDetails, { draft: draft });
89
+ case "addons":
90
+ return _jsx(AddonsDetails, { draft: draft });
91
+ case "payment":
92
+ return _jsx(PaymentDetails, { draft: draft });
93
+ case "review":
94
+ return (_jsx("p", { className: "text-muted-foreground text-xs", children: "Review your details and confirm to book." }));
95
+ default:
96
+ return null;
97
+ }
98
+ }
99
+ function ConfigureDetails({ draft, }) {
100
+ const cfg = draft.configure ?? {};
101
+ 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] }));
103
+ }
104
+ function BillingDetails({ draft, }) {
105
+ const c = draft.billing.contact;
106
+ const a = draft.billing.address;
107
+ 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] }));
109
+ }
110
+ function TravelersDetails({ draft, }) {
111
+ if (draft.travelers.length === 0) {
112
+ return _jsx("p", { className: "text-muted-foreground text-xs", children: "No travelers yet." });
113
+ }
114
+ return (_jsx("ul", { className: "space-y-3 text-xs", children: draft.travelers.map((t, i) => {
115
+ const key = t.rowId ?? `t-${i}`;
116
+ const name = [t.firstName, t.lastName].filter(Boolean).join(" ").trim();
117
+ const docType = t.documents?.documentType;
118
+ const docNum = t.documents?.documentNumber;
119
+ const docExpiry = t.documents?.documentExpiry;
120
+ const docLine = [docType, docNum, docExpiry ? `exp ${docExpiry}` : null]
121
+ .filter(Boolean)
122
+ .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));
124
+ }) }));
125
+ }
126
+ function AccommodationDetails({ draft, }) {
127
+ const rooms = draft.accommodation?.rooms ?? [];
128
+ if (rooms.length === 0) {
129
+ return _jsx("p", { className: "text-muted-foreground text-xs", children: "Not selected." });
130
+ }
131
+ 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
+ }
133
+ function AddonsDetails({ draft, }) {
134
+ const addons = draft.addons ?? [];
135
+ if (addons.length === 0) {
136
+ return _jsx("p", { className: "text-muted-foreground text-xs", children: "No add-ons selected." });
137
+ }
138
+ 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
+ }
140
+ function PaymentDetails({ draft, }) {
141
+ const intent = draft.payment.intent;
142
+ const label = intent === "card"
143
+ ? "Pay by card"
144
+ : 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] }));
148
+ }
149
+ function Row({ label, value }) {
150
+ 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
+ }
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
+ };
161
+ function paxTotal(draft) {
162
+ const pax = draft.configure?.pax ?? {};
163
+ return (pax.adult ?? 0) + (pax.child ?? 0) + (pax.infant ?? 0);
164
+ }
165
+ function formatMoney(cents, currency) {
166
+ try {
167
+ return new Intl.NumberFormat(undefined, { style: "currency", currency }).format(cents / 100);
168
+ }
169
+ catch {
170
+ return `${(cents / 100).toFixed(2)} ${currency}`;
171
+ }
172
+ }
@@ -0,0 +1,7 @@
1
+ import type { JourneyHeaderState, JourneyStep } from "../types.js";
2
+ interface StepHeaderProps extends JourneyHeaderState {
3
+ onJumpTo: (step: JourneyStep) => void;
4
+ }
5
+ export declare function StepHeader({ current, visited, steps, onJumpTo, }: StepHeaderProps): React.ReactElement;
6
+ export {};
7
+ //# sourceMappingURL=step-header.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
+ import { Button } from "@voyantjs/ui/components/button";
4
+ export function StepHeader({ current, visited, steps, onJumpTo, }) {
5
+ return (_jsx("ol", { className: "flex flex-wrap gap-2", children: steps.map((step, idx) => {
6
+ const isCurrent = step === current;
7
+ 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));
9
+ }) }));
10
+ }
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
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `@voyantjs/bookings-ui/journey` — the unified booking journey shell.
3
+ *
4
+ * Per `docs/architecture/booking-journey-architecture.md`.
5
+ *
6
+ * Single shell, slot-injected. Operator and storefront consume the
7
+ * same `<BookingJourney />` and inject surface-specific behavior
8
+ * (CRM picker, payment provider widget, B2B vs B2C defaults, post-
9
+ * commit handoff) via render-prop slots.
10
+ */
11
+ export { BookingJourney } from "./components/booking-journey.js";
12
+ export { type ContractAcceptance, ContractPreviewDialog, type ContractPreviewDialogProps, } from "./components/contract-preview-dialog.js";
13
+ export { AccommodationStep, AddonsStep, BillingStep, ConfigureStep, PaymentStep, ReviewStep, TravelersStep, } from "./components/journey-steps.js";
14
+ export { PriceSidePanel } from "./components/side-panel.js";
15
+ export { StepHeader } from "./components/step-header.js";
16
+ export { type Draft, emptyDraft, patchBilling, patchConfigure, patchPaxCount, setAccommodation, setAddons, setPayment, setTravelers, totalPax, } from "./lib/draft-state.js";
17
+ export { type BookingEntitySummary, type BookingJourneyCheckoutContext, type BookingJourneyProps, type ContractAcceptanceEvent, JOURNEY_STEP_ORDER, type JourneyHeaderState, type JourneyStep, type JourneySurface, type LeadContactPickerProps, type PaymentProviderCapabilities, type PaymentProviderStepRenderProps, type SidePanelState, type TravelerContactPickerProps, } from "./types.js";
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/journey/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AAChE,OAAO,EACL,KAAK,kBAAkB,EACvB,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,yCAAyC,CAAA;AAChD,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,aAAa,EACb,WAAW,EACX,UAAU,EACV,aAAa,GACd,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,OAAO,EACL,KAAK,KAAK,EACV,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,YAAY,EACZ,QAAQ,GACT,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,8BAA8B,EACnC,KAAK,cAAc,EACnB,KAAK,0BAA0B,GAChC,MAAM,YAAY,CAAA"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `@voyantjs/bookings-ui/journey` — the unified booking journey shell.
3
+ *
4
+ * Per `docs/architecture/booking-journey-architecture.md`.
5
+ *
6
+ * Single shell, slot-injected. Operator and storefront consume the
7
+ * same `<BookingJourney />` and inject surface-specific behavior
8
+ * (CRM picker, payment provider widget, B2B vs B2C defaults, post-
9
+ * commit handoff) via render-prop slots.
10
+ */
11
+ export { BookingJourney } from "./components/booking-journey.js";
12
+ export { ContractPreviewDialog, } from "./components/contract-preview-dialog.js";
13
+ export { AccommodationStep, AddonsStep, BillingStep, ConfigureStep, PaymentStep, ReviewStep, TravelersStep, } from "./components/journey-steps.js";
14
+ export { PriceSidePanel } from "./components/side-panel.js";
15
+ export { StepHeader } from "./components/step-header.js";
16
+ export { emptyDraft, patchBilling, patchConfigure, patchPaxCount, setAccommodation, setAddons, setPayment, setTravelers, totalPax, } from "./lib/draft-state.js";
17
+ export { JOURNEY_STEP_ORDER, } from "./types.js";
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Local draft-state reducers + initialization helpers.
3
+ *
4
+ * The journey holds the draft as a single useState at the root and
5
+ * passes immutable views down to step components, which call the
6
+ * supplied setter to apply patches. Per
7
+ * booking-journey-architecture §4.
8
+ */
9
+ import type { BookingDraftV1 } from "@voyantjs/catalog/booking-engine";
10
+ export type Draft = BookingDraftV1;
11
+ export interface DraftEntityIdentity {
12
+ module: string;
13
+ id: string;
14
+ /**
15
+ * Source kind. Empty string on the storefront before the engine's
16
+ * server-side resolver fills it in; operator-side wiring sets
17
+ * the real kind upfront.
18
+ */
19
+ sourceKind: string;
20
+ sourceConnectionId?: string;
21
+ sourceRef?: string;
22
+ }
23
+ export declare function emptyDraft(entity: DraftEntityIdentity, defaults?: {
24
+ buyerType?: "B2C" | "B2B";
25
+ }): Draft;
26
+ export declare function patchConfigure(draft: Draft, patch: Partial<Draft["configure"]>): Draft;
27
+ export declare function patchBilling(draft: Draft, patch: Partial<Draft["billing"]>): Draft;
28
+ export declare function patchPaxCount(draft: Draft, band: string, count: number): Draft;
29
+ export declare function setTravelers(draft: Draft, travelers: Draft["travelers"]): Draft;
30
+ export declare function setAccommodation(draft: Draft, accommodation: Draft["accommodation"]): Draft;
31
+ export declare function setAddons(draft: Draft, addons: Draft["addons"]): Draft;
32
+ export declare function setPayment(draft: Draft, payment: Draft["payment"]): Draft;
33
+ export declare function totalPax(draft: Draft): number;
34
+ //# sourceMappingURL=draft-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draft-state.d.ts","sourceRoot":"","sources":["../../../src/journey/lib/draft-state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAEtE,MAAM,MAAM,KAAK,GAAG,cAAc,CAAA;AAElC,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,MAAM,CAAA;IACV;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,GAAE;IAAE,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;CAAO,GAC3C,KAAK,CAaP;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,GAAG,KAAK,CAEtF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,CAElF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAK9E;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,GAAG,KAAK,CAE/E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG,KAAK,CAE3F;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,KAAK,CAEtE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAEzE;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAM7C"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Local draft-state reducers + initialization helpers.
3
+ *
4
+ * The journey holds the draft as a single useState at the root and
5
+ * passes immutable views down to step components, which call the
6
+ * supplied setter to apply patches. Per
7
+ * booking-journey-architecture §4.
8
+ */
9
+ export function emptyDraft(entity, defaults = {}) {
10
+ return {
11
+ entity,
12
+ configure: { pax: {} },
13
+ billing: {
14
+ buyerType: defaults.buyerType ?? "B2C",
15
+ contact: { firstName: "", lastName: "", email: "" },
16
+ address: {},
17
+ },
18
+ travelers: [],
19
+ addons: [],
20
+ payment: { intent: "hold" },
21
+ };
22
+ }
23
+ export function patchConfigure(draft, patch) {
24
+ return { ...draft, configure: { ...draft.configure, ...patch } };
25
+ }
26
+ export function patchBilling(draft, patch) {
27
+ return { ...draft, billing: { ...draft.billing, ...patch } };
28
+ }
29
+ export function patchPaxCount(draft, band, count) {
30
+ const safeCount = Number.isFinite(count) && count >= 0 ? Math.floor(count) : 0;
31
+ return patchConfigure(draft, {
32
+ pax: { ...draft.configure.pax, [band]: safeCount },
33
+ });
34
+ }
35
+ export function setTravelers(draft, travelers) {
36
+ return { ...draft, travelers };
37
+ }
38
+ export function setAccommodation(draft, accommodation) {
39
+ return { ...draft, accommodation };
40
+ }
41
+ export function setAddons(draft, addons) {
42
+ return { ...draft, addons };
43
+ }
44
+ export function setPayment(draft, payment) {
45
+ return { ...draft, payment };
46
+ }
47
+ export function totalPax(draft) {
48
+ let total = 0;
49
+ for (const v of Object.values(draft.configure.pax ?? {})) {
50
+ if (typeof v === "number")
51
+ total += v;
52
+ }
53
+ return total;
54
+ }
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Shell-side types for `<BookingJourney />`. These complement the
3
+ * engine contracts in `@voyantjs/catalog/booking-engine/contracts`
4
+ * with React-specific slots and event shapes that don't belong on
5
+ * the wire.
6
+ *
7
+ * Per booking-journey-architecture §8.1.
8
+ */
9
+ import type { BookingDraftShape, BookingDraftV1, BookResponseV1, PricingBreakdownV1 } from "@voyantjs/catalog/booking-engine";
10
+ import type { ReactNode } from "react";
11
+ export type JourneyStep = "configure" | "billing" | "travelers" | "accommodation" | "addons" | "payment" | "review";
12
+ export declare const JOURNEY_STEP_ORDER: ReadonlyArray<JourneyStep>;
13
+ export interface JourneySurface {
14
+ /** Operator-side or storefront — drives default slot behavior. */
15
+ kind: "admin" | "public";
16
+ }
17
+ export interface LeadContactPickerProps {
18
+ /** Apply a picked contact to the draft's billing fields. Email is
19
+ * optional because CRM-backed people may not have one stored —
20
+ * the billing form will surface it as empty for the operator to
21
+ * fill in. */
22
+ apply: (contact: {
23
+ firstName: string;
24
+ lastName: string;
25
+ email?: string;
26
+ phone?: string;
27
+ personId?: string;
28
+ }) => void;
29
+ }
30
+ export interface TravelerContactPickerProps {
31
+ rowIndex: number;
32
+ /** Apply a picked contact to the traveler at `rowIndex`. */
33
+ apply: (contact: {
34
+ firstName: string;
35
+ lastName: string;
36
+ email?: string;
37
+ phone?: string;
38
+ personId?: string;
39
+ }) => void;
40
+ }
41
+ /**
42
+ * Capabilities supplied by the template — checkout-ui's PaymentStep
43
+ * consumes these to render the right provider widget. Each flag is
44
+ * an independent on/off switch the operator configures per
45
+ * deployment / supplier:
46
+ *
47
+ * - `acceptsCard` — Stripe / Netopia / generic card flow. The
48
+ * `renderPaymentProviderStep` slot supplies the actual widget.
49
+ * - `acceptsBankTransfer` — operator emails the buyer bank details;
50
+ * booking is created with status "awaiting_payment". Inventory
51
+ * hold is still placed so capacity is reserved.
52
+ * - `acceptsHold` — staff/agent-only soft-hold path; useful when an
53
+ * operator is brokering for an end customer.
54
+ * - `acceptsTicketOnCredit` — agency credit account.
55
+ * - `acceptsInquiry` — lead-only flow: NO inventory hold, NO charge.
56
+ * The "booking" is recorded as an inquiry for the operator to
57
+ * manually follow up on. Right for tour operators where a quote
58
+ * conversation precedes booking.
59
+ */
60
+ export interface PaymentProviderCapabilities {
61
+ acceptsCard: boolean;
62
+ acceptsHold: boolean;
63
+ acceptsBankTransfer?: boolean;
64
+ acceptsTicketOnCredit: boolean;
65
+ acceptsInquiry?: boolean;
66
+ /** Free-form provider-specific config (e.g. Netopia merchant id,
67
+ * Stripe publishable key, bank-transfer instructions). */
68
+ config?: Record<string, unknown>;
69
+ }
70
+ export interface PaymentProviderStepRenderProps {
71
+ intent: BookingDraftV1["payment"]["intent"];
72
+ schedule: BookingDraftV1["payment"]["schedule"];
73
+ capabilities: PaymentProviderCapabilities;
74
+ }
75
+ export interface BookingJourneyProps {
76
+ /** What to book. */
77
+ entityModule: string;
78
+ entityId: string;
79
+ /**
80
+ * Source pointer fields. Optional on the public surface — the
81
+ * engine resolves provenance server-side from
82
+ * `(entityModule, entityId)` via the catalog plane's
83
+ * sourced-entry lookup. Operator surfaces should still pass
84
+ * `sourceKind` explicitly when known.
85
+ */
86
+ sourceKind?: string;
87
+ sourceConnectionId?: string;
88
+ sourceRef?: string;
89
+ /** Surface — drives audience defaults and slot wiring. */
90
+ surface?: "admin" | "public";
91
+ /** Stable draft id — caller persists in URL or session storage so
92
+ * the journey survives page refresh. */
93
+ draftId: string;
94
+ /** Default buyer type — operator: B2B, storefront: B2C. */
95
+ defaultBuyerType?: "B2C" | "B2B";
96
+ /** Initial fallback shape — rendered before the first quote
97
+ * resolves. The engine returns a more specific shape on the
98
+ * first quote response. */
99
+ fallbackShape?: BookingDraftShape;
100
+ /**
101
+ * Pre-locked configure state. When set, the journey skips the
102
+ * Configure step entirely — Configure already happened on the
103
+ * product detail page. Mirrors the BookingDraft's `configure`
104
+ * shape (loosely typed so storefront callers can pass a
105
+ * vertical-specific subset without fighting the contract).
106
+ */
107
+ initialConfigure?: Record<string, unknown>;
108
+ /** Pre-locked accommodation slice (room/rate picks made on the
109
+ * detail page). Loosely typed for the same reason. */
110
+ initialAccommodation?: Record<string, unknown>;
111
+ /**
112
+ * When true, the wizard hides Configure regardless of descriptor
113
+ * flags. Use for storefront flows where the product detail page
114
+ * already collected those choices.
115
+ */
116
+ hideConfigure?: boolean;
117
+ /** Per-payment-provider capabilities — passed through to the
118
+ * Payment step's provider widget. */
119
+ paymentCapabilities?: PaymentProviderCapabilities;
120
+ /** Operator: pulls from CRM. Storefront: bare inline form. */
121
+ renderLeadContactPicker?: (props: LeadContactPickerProps) => ReactNode;
122
+ renderTravelerContactPicker?: (props: TravelerContactPickerProps) => ReactNode;
123
+ /** Hook for the actual payment-provider widget — checkout-ui's
124
+ * PaymentStep is the canonical implementation. When omitted, the
125
+ * shell renders a "Hold only — no card collected" stub. */
126
+ renderPaymentProviderStep?: (props: PaymentProviderStepRenderProps) => ReactNode;
127
+ /** Optional pre/post-step extension slots — useful when a
128
+ * template wants to inject a custom block (e.g. coupon code
129
+ * banner, marketing opt-in). */
130
+ renderConfigureExtras?: () => ReactNode;
131
+ renderBillingExtras?: () => ReactNode;
132
+ renderReviewExtras?: () => ReactNode;
133
+ /** Fired on successful commit — typically a navigation. */
134
+ onCommitted?: (result: BookResponseV1) => void;
135
+ /** Fired when the user explicitly abandons the journey via the
136
+ * shell's cancel button. */
137
+ onCancelled?: () => void;
138
+ /** Optional class names. */
139
+ className?: string;
140
+ sidePanelClassName?: string;
141
+ /**
142
+ * Optional summary of the entity being booked — surfaces in the
143
+ * side panel so the customer keeps context while filling out the
144
+ * journey. Shape is loose because each vertical carries different
145
+ * fields (cruises have ports, hospitality has check-in/out, etc.).
146
+ */
147
+ entitySummary?: BookingEntitySummary;
148
+ /**
149
+ * Contract preview integration. When `templateSlug` is set, the
150
+ * Review step's "Continue to checkout" button opens the contract
151
+ * preview dialog with the rendered template instead of committing
152
+ * directly. The journey then surfaces the acceptance back to the
153
+ * caller via `onContractAccepted` so the storefront can call its
154
+ * own `/checkout/start` endpoint.
155
+ *
156
+ * - `previewUrl` — absolute URL of the public render endpoint.
157
+ * - `resolveVariables` — maps the draft to the template's variable
158
+ * schema. The storefront supplies a default mapper that covers
159
+ * passenger / billing / room / dates.
160
+ * - `marketingLabel` — when set, an additional opt-in checkbox is
161
+ * rendered in the dialog. Marketing consent is optional and is
162
+ * passed through `onContractAccepted` so the caller can decide
163
+ * what to do with it.
164
+ */
165
+ contract?: {
166
+ templateSlug: string;
167
+ previewUrl: string;
168
+ acceptLanguage?: string;
169
+ resolveVariables: (input: {
170
+ draft: BookingDraftV1;
171
+ pricing: PricingBreakdownV1 | null;
172
+ }) => Record<string, unknown>;
173
+ marketingLabel?: ReactNode;
174
+ termsLabel?: ReactNode;
175
+ };
176
+ /**
177
+ * Fired when the user accepts the contract in the preview dialog.
178
+ * The caller persists the acceptance + dispatches the checkout
179
+ * workflow. Receives the rendered HTML so it can be stored
180
+ * verbatim for the audit trail.
181
+ */
182
+ /**
183
+ * Called when the user clicks Confirm on the Review step. Receives
184
+ * the rendered contract acceptance when the contract dialog was
185
+ * shown; receives `null` when the journey skipped the dialog
186
+ * (no template configured — the storefront still wants to drive
187
+ * the post-confirm /checkout/start flow).
188
+ */
189
+ onContractAccepted?: (acceptance: ContractAcceptanceEvent | null, context: BookingJourneyCheckoutContext) => void | Promise<void>;
190
+ }
191
+ export interface BookingJourneyCheckoutContext {
192
+ draft: BookingDraftV1;
193
+ pricing: PricingBreakdownV1 | null;
194
+ quoteId?: string;
195
+ }
196
+ export interface ContractAcceptanceEvent {
197
+ templateId: string;
198
+ templateSlug: string;
199
+ templateName: string;
200
+ acceptedTerms: true;
201
+ acceptedMarketing: boolean;
202
+ acceptedAt: string;
203
+ renderedHtml: string;
204
+ }
205
+ /**
206
+ * Caller-provided context for the side-panel summary. Keep it
207
+ * vertical-agnostic — the panel renders whatever subset is present.
208
+ */
209
+ export interface BookingEntitySummary {
210
+ /** Headline name — e.g. product / cruise / hotel name. */
211
+ name: string;
212
+ /** Optional second line — e.g. "Iceland · 1 day", "7 nights · Mediterranean". */
213
+ subtitle?: string;
214
+ /** Optional hero image — small thumbnail at the top of the panel. */
215
+ heroImageUrl?: string;
216
+ /** Vertical badge — drives the "What you're booking" header copy. */
217
+ vertical?: "products" | "cruises" | "hospitality" | string;
218
+ /** Optional ISO date or formatted date — e.g. "Tue, May 5, 2026". */
219
+ whenLabel?: string;
220
+ /** Optional location label — e.g. "Reykjavík", "Mediterranean", "Bucharest". */
221
+ locationLabel?: string;
222
+ /** ISO start date (YYYY-MM-DD or full ISO) — used by the contract
223
+ * preview when the draft only carries a slot id. */
224
+ startDate?: string;
225
+ /** ISO end date — paired with `startDate` for ranges and contract
226
+ * variables like `departure.end_date`. */
227
+ endDate?: string;
228
+ /** Free-form destination / route string — surfaced as
229
+ * `product.destination` in contract variables. */
230
+ destination?: string;
231
+ }
232
+ export interface JourneyHeaderState {
233
+ current: JourneyStep;
234
+ visited: ReadonlyArray<JourneyStep>;
235
+ steps: ReadonlyArray<JourneyStep>;
236
+ shape: BookingDraftShape;
237
+ }
238
+ export interface SidePanelState {
239
+ pricing: PricingBreakdownV1 | null;
240
+ isQuoting: boolean;
241
+ invalidReason?: string;
242
+ entitySummary?: BookingEntitySummary;
243
+ currentStep?: JourneyStep;
244
+ steps?: ReadonlyArray<JourneyStep>;
245
+ shape?: BookingDraftShape;
246
+ draft?: BookingDraftV1;
247
+ }
248
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/journey/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Shell-side types for `<BookingJourney />`. These complement the
3
+ * engine contracts in `@voyantjs/catalog/booking-engine/contracts`
4
+ * with React-specific slots and event shapes that don't belong on
5
+ * the wire.
6
+ *
7
+ * Per booking-journey-architecture §8.1.
8
+ */
9
+ export const JOURNEY_STEP_ORDER = [
10
+ "configure",
11
+ "billing",
12
+ "travelers",
13
+ "accommodation",
14
+ "addons",
15
+ "payment",
16
+ "review",
17
+ ];