@voyantjs/bookings-ui 0.107.0 → 0.108.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.
- package/dist/components/option-units-stepper-section.d.ts +9 -1
- package/dist/components/option-units-stepper-section.d.ts.map +1 -1
- package/dist/components/option-units-stepper-section.js +10 -2
- package/dist/components/person-picker-section.d.ts +7 -1
- package/dist/components/person-picker-section.d.ts.map +1 -1
- package/dist/components/person-picker-section.js +2 -2
- package/dist/i18n/en.d.ts +37 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +40 -4
- package/dist/i18n/messages.d.ts +37 -1
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/i18n/provider.d.ts +74 -2
- package/dist/i18n/provider.d.ts.map +1 -1
- package/dist/i18n/ro.d.ts +37 -1
- package/dist/i18n/ro.d.ts.map +1 -1
- package/dist/i18n/ro.js +39 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/journey/components/booking-journey.d.ts.map +1 -1
- package/dist/journey/components/booking-journey.js +270 -27
- package/dist/journey/components/journey-steps/accommodation-step.d.ts +3 -0
- package/dist/journey/components/journey-steps/accommodation-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/accommodation-step.js +71 -0
- package/dist/journey/components/journey-steps/addons-step.d.ts +3 -0
- package/dist/journey/components/journey-steps/addons-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/addons-step.js +40 -0
- package/dist/journey/components/journey-steps/billing-step.d.ts +8 -0
- package/dist/journey/components/journey-steps/billing-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/billing-step.js +78 -0
- package/dist/journey/components/journey-steps/configure-steps.d.ts +28 -0
- package/dist/journey/components/journey-steps/configure-steps.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/configure-steps.js +231 -0
- package/dist/journey/components/journey-steps/documents-step.d.ts +11 -0
- package/dist/journey/components/journey-steps/documents-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/documents-step.js +36 -0
- package/dist/journey/components/journey-steps/payment-step.d.ts +29 -0
- package/dist/journey/components/journey-steps/payment-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/payment-step.js +224 -0
- package/dist/journey/components/journey-steps/review-step.d.ts +27 -0
- package/dist/journey/components/journey-steps/review-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/review-step.js +18 -0
- package/dist/journey/components/journey-steps/shared.d.ts +75 -0
- package/dist/journey/components/journey-steps/shared.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/shared.js +108 -0
- package/dist/journey/components/journey-steps/travelers-step.d.ts +7 -0
- package/dist/journey/components/journey-steps/travelers-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/travelers-step.js +201 -0
- package/dist/journey/components/journey-steps.d.ts +13 -39
- package/dist/journey/components/journey-steps.d.ts.map +1 -1
- package/dist/journey/components/journey-steps.js +16 -613
- package/dist/journey/components/side-panel.d.ts +7 -2
- package/dist/journey/components/side-panel.d.ts.map +1 -1
- package/dist/journey/components/side-panel.js +73 -24
- package/dist/journey/index.d.ts +2 -2
- package/dist/journey/index.d.ts.map +1 -1
- package/dist/journey/index.js +1 -1
- package/dist/journey/lib/pax-band-dependencies.d.ts +27 -0
- package/dist/journey/lib/pax-band-dependencies.d.ts.map +1 -0
- package/dist/journey/lib/pax-band-dependencies.js +50 -0
- package/dist/journey/lib/payment-schedule.d.ts +19 -0
- package/dist/journey/lib/payment-schedule.d.ts.map +1 -0
- package/dist/journey/lib/payment-schedule.js +90 -0
- package/dist/journey/types.d.ts +141 -8
- package/dist/journey/types.d.ts.map +1 -1
- package/dist/journey/types.js +3 -1
- package/package.json +32 -32
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Separator } from "@voyantjs/ui/components";
|
|
4
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components/card";
|
|
5
|
+
import { Checkbox } from "@voyantjs/ui/components/checkbox";
|
|
6
|
+
import { Input } from "@voyantjs/ui/components/input";
|
|
7
|
+
import { Label } from "@voyantjs/ui/components/label";
|
|
8
|
+
import { RadioGroup, RadioGroupItem } from "@voyantjs/ui/components/radio-group";
|
|
9
|
+
import { Textarea } from "@voyantjs/ui/components/textarea";
|
|
10
|
+
import { useEffect, useRef, useState } from "react";
|
|
11
|
+
import { PaymentScheduleSection, } from "../../../components/payment-schedule-section.js";
|
|
12
|
+
import { emptyVoucherPickerValue, VoucherPickerSection, } from "../../../components/voucher-picker-section.js";
|
|
13
|
+
import { useBookingsUiMessagesOrDefault } from "../../../i18n/index.js";
|
|
14
|
+
import { setPayment } from "../../lib/draft-state.js";
|
|
15
|
+
import { paymentScheduleValueToRows, rowsToPaymentScheduleValue, } from "../../lib/payment-schedule.js";
|
|
16
|
+
// ─────────────────────────────────────────────────────────────────
|
|
17
|
+
// Payment
|
|
18
|
+
// ─────────────────────────────────────────────────────────────────
|
|
19
|
+
export function PaymentStep({ draft, setDraft, shape, capabilities, renderProviderStep, surface, pricing, }) {
|
|
20
|
+
const messages = useBookingsUiMessagesOrDefault();
|
|
21
|
+
// The descriptor lists what the *engine* supports; capabilities
|
|
22
|
+
// narrow further to what the *deployment* turned on. Both must
|
|
23
|
+
// accept an intent for the user to see it.
|
|
24
|
+
const allowed = shape.paymentIntents.filter((i) => isCapabilityEnabled(i, capabilities));
|
|
25
|
+
const intent = draft.payment.intent;
|
|
26
|
+
// Admin simplification: when the only choices are reserve-now (hold) and an
|
|
27
|
+
// online payment link (card), don't make it a radio — the booking is always
|
|
28
|
+
// reserved; a single checkbox decides whether to ALSO send a payment link.
|
|
29
|
+
const simpleHoldCard = surface === "admin" &&
|
|
30
|
+
allowed.length > 0 &&
|
|
31
|
+
allowed.includes("hold") &&
|
|
32
|
+
allowed.includes("card") &&
|
|
33
|
+
allowed.every((i) => i === "hold" || i === "card");
|
|
34
|
+
// Snap the draft's intent to a sensible value when the current pick isn't on
|
|
35
|
+
// the list — covers descriptor changes mid-flow (e.g. owned→sourced narrows
|
|
36
|
+
// the list). In checkbox mode the baseline is always "hold".
|
|
37
|
+
if (allowed.length > 0 && !allowed.includes(intent)) {
|
|
38
|
+
setDraft(setPayment(draft, {
|
|
39
|
+
...draft.payment,
|
|
40
|
+
intent: (simpleHoldCard ? "hold" : allowed[0]),
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: messages.bookingJourney.payment.title }) }), _jsx(Separator, {}), _jsxs(CardContent, { className: "space-y-4", children: [allowed.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: messages.bookingJourney.payment.empty })) : simpleHoldCard ? (_jsxs("label", { className: "flex cursor-pointer items-start gap-3 rounded-md border border-input p-3 text-sm transition-colors hover:bg-muted/50", children: [_jsx(Checkbox, { id: "bj-generate-link", checked: intent === "card", onCheckedChange: (v) => setDraft(setPayment(draft, {
|
|
44
|
+
...draft.payment,
|
|
45
|
+
intent: (v === true ? "card" : "hold"),
|
|
46
|
+
})), className: "mt-0.5" }), _jsxs("div", { className: "space-y-0.5", children: [_jsx("div", { className: "font-medium", children: messages.bookingJourney.payment.generateLinkLabel }), _jsx("div", { className: "text-muted-foreground text-xs", children: messages.bookingJourney.payment.generateLinkHint })] })] })) : (_jsx(RadioGroup, { value: intent, onValueChange: (v) => setDraft(setPayment(draft, { ...draft.payment, intent: v })), className: "grid grid-cols-1 gap-2", children: allowed.map((i) => {
|
|
47
|
+
const meta = intentMeta(i, messages, surface);
|
|
48
|
+
const selected = i === intent;
|
|
49
|
+
return (_jsxs("label", { className: "flex cursor-pointer items-start gap-3 rounded-md border p-3 text-sm transition-colors " +
|
|
50
|
+
(selected ? "border-primary bg-primary/5" : "border-input hover:bg-muted/50"), children: [_jsx(RadioGroupItem, { value: i, className: "mt-0.5" }), _jsxs("div", { className: "space-y-0.5", children: [_jsx("div", { className: "font-medium", children: meta.label }), _jsx("div", { className: "text-muted-foreground text-xs", children: meta.description })] })] }, i));
|
|
51
|
+
}) })), surface !== "public" ? (_jsx(PaymentScheduleEditor, { draft: draft, setDraft: setDraft, pricing: pricing })) : null, intent === "card" ? (renderProviderStep ? (_jsx("div", { children: renderProviderStep({
|
|
52
|
+
intent,
|
|
53
|
+
schedule: draft.payment.schedule,
|
|
54
|
+
capabilities,
|
|
55
|
+
}) })) : simpleHoldCard ? null : (_jsx("p", { className: "text-muted-foreground text-sm", children: surface === "admin"
|
|
56
|
+
? messages.bookingJourney.payment.linkSentAfterConfirm
|
|
57
|
+
: messages.bookingJourney.payment.redirectedAfterConfirm }))) : null, intent === "bank_transfer" ? _jsx(BankTransferDetails, { capabilities: capabilities }) : null, intent === "inquiry" ? (_jsx("p", { className: "rounded-md border border-amber-300 bg-amber-50 p-3 text-amber-900 text-xs dark:border-amber-700 dark:bg-amber-950 dark:text-amber-100", children: messages.bookingJourney.payment.inquiryNotice })) : null] })] }));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Operator-only payment-schedule editor for the journey. Holds the editor
|
|
61
|
+
* value (`{ mode, installments }`) in local state — stable installment ids
|
|
62
|
+
* survive re-quotes — and syncs it to `draft.paymentSchedules` on every change.
|
|
63
|
+
* Re-initialised from the draft when the step remounts (navigation), preserving
|
|
64
|
+
* any paid-installment metadata via the `notes` round-trip.
|
|
65
|
+
*/
|
|
66
|
+
function PaymentScheduleEditor({ draft, setDraft, pricing, }) {
|
|
67
|
+
const departureDate = draft.configure.departureDate ?? null;
|
|
68
|
+
const [value, setValue] = useState(() => rowsToPaymentScheduleValue(draft.paymentSchedules, departureDate));
|
|
69
|
+
const currency = pricing?.currency ?? "";
|
|
70
|
+
// A manual price override is the booking's real total — schedules must sum
|
|
71
|
+
// to it (booking-create enforces this), so the editor anchors on it.
|
|
72
|
+
const total = draft.priceOverride?.amountCents ?? pricing?.total ?? null;
|
|
73
|
+
// Persist the default schedule (a single full-amount payment) to the draft
|
|
74
|
+
// once the total is known — otherwise an operator who never touches the
|
|
75
|
+
// editor commits a booking with NO payment schedule. Seeds once; after that
|
|
76
|
+
// the operator owns it via onChange.
|
|
77
|
+
const seeded = useRef(false);
|
|
78
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: one-shot seed guarded by the ref; reads latest via closure
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (seeded.current || total == null)
|
|
81
|
+
return;
|
|
82
|
+
if (draft.paymentSchedules && draft.paymentSchedules.length > 0) {
|
|
83
|
+
seeded.current = true;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const rows = paymentScheduleValueToRows(value, currency, total);
|
|
87
|
+
if (rows && rows.length > 0) {
|
|
88
|
+
seeded.current = true;
|
|
89
|
+
setDraft({ ...draft, paymentSchedules: rows });
|
|
90
|
+
}
|
|
91
|
+
}, [total, currency]);
|
|
92
|
+
return (_jsx(PaymentScheduleSection, { value: value, onChange: (next) => {
|
|
93
|
+
setValue(next);
|
|
94
|
+
setDraft({
|
|
95
|
+
...draft,
|
|
96
|
+
paymentSchedules: paymentScheduleValueToRows(next, currency, total),
|
|
97
|
+
});
|
|
98
|
+
}, totalAmountCents: total ?? undefined, departureDate: departureDate, currency: currency }));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Operator-only manual price override for the journey. Local string state for
|
|
102
|
+
* the amount field keeps decimal entry smooth; syncs cents to `draft.priceOverride`.
|
|
103
|
+
* The owned handler sends it as `confirmedSellAmountCents` (wins over the quote)
|
|
104
|
+
* with a required reason when it differs from the quoted total.
|
|
105
|
+
*/
|
|
106
|
+
function PriceOverrideEditor({ draft, setDraft, pricing, }) {
|
|
107
|
+
const messages = useBookingsUiMessagesOrDefault().bookingJourney.review;
|
|
108
|
+
const quoteTotal = pricing?.total ?? null;
|
|
109
|
+
const currency = pricing?.currency ?? "";
|
|
110
|
+
const override = draft.priceOverride;
|
|
111
|
+
const [amount, setAmount] = useState(() => override ? (override.amountCents / 100).toString() : "");
|
|
112
|
+
const setOverride = (next) => setDraft({ ...draft, priceOverride: next });
|
|
113
|
+
const reasonNeeded = override != null &&
|
|
114
|
+
quoteTotal != null &&
|
|
115
|
+
override.amountCents !== quoteTotal &&
|
|
116
|
+
override.reason.trim().length === 0;
|
|
117
|
+
return (_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { id: "bj-price-override", checked: override != null, onCheckedChange: (v) => {
|
|
118
|
+
if (v === true) {
|
|
119
|
+
const cents = quoteTotal ?? 0;
|
|
120
|
+
setAmount((cents / 100).toString());
|
|
121
|
+
setOverride({ amountCents: cents, reason: "" });
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
setOverride(undefined);
|
|
125
|
+
}
|
|
126
|
+
} }), _jsx(Label, { htmlFor: "bj-price-override", className: "cursor-pointer", children: messages.priceOverrideToggle })] }), override ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs(Label, { htmlFor: "bj-price-override-amount", className: "text-xs", children: [messages.priceOverrideAmount, currency ? ` (${currency})` : ""] }), _jsx(Input, { id: "bj-price-override-amount", type: "number", min: 0, step: "0.01", value: amount, onChange: (e) => {
|
|
127
|
+
setAmount(e.target.value);
|
|
128
|
+
const parsed = Number(e.target.value);
|
|
129
|
+
setOverride({
|
|
130
|
+
amountCents: Number.isFinite(parsed) ? Math.round(parsed * 100) : 0,
|
|
131
|
+
reason: override.reason,
|
|
132
|
+
});
|
|
133
|
+
} })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "bj-price-override-reason", className: "text-xs", children: messages.priceOverrideReason }), _jsx(Textarea, { id: "bj-price-override-reason", placeholder: messages.priceOverrideReasonPlaceholder, value: override.reason, onChange: (e) => setOverride({
|
|
134
|
+
amountCents: override.amountCents,
|
|
135
|
+
reason: e.target.value,
|
|
136
|
+
}) }), reasonNeeded ? (_jsx("p", { className: "text-destructive text-xs", children: messages.priceOverrideReasonRequired })) : null] })] })) : null] }));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Operator-only voucher editor for the review step. Wraps the shared
|
|
140
|
+
* `VoucherPickerSection` (which validates the code against
|
|
141
|
+
* `/v1/public/vouchers/validate`) and mirrors the picked voucher into
|
|
142
|
+
* `draft.voucherRedemption` so the owned handler redeems it atomically at
|
|
143
|
+
* commit — matching the standalone create-sheet's behaviour. Redeems the
|
|
144
|
+
* full remaining balance, same as the create-sheet.
|
|
145
|
+
*/
|
|
146
|
+
function VoucherEditor({ draft, setDraft, pricing, renderVoucherPicker, }) {
|
|
147
|
+
const labels = useBookingsUiMessagesOrDefault().bookingCreateDialog.labels;
|
|
148
|
+
const [voucher, setVoucher] = useState(emptyVoucherPickerValue);
|
|
149
|
+
// Operator surface: an async search combobox (no need to know the code).
|
|
150
|
+
if (renderVoucherPicker) {
|
|
151
|
+
return (_jsx(_Fragment, { children: renderVoucherPicker({
|
|
152
|
+
value: {
|
|
153
|
+
voucherId: draft.voucherRedemption?.voucherId,
|
|
154
|
+
amountCents: draft.voucherRedemption?.amountCents,
|
|
155
|
+
},
|
|
156
|
+
onApply: (picked) => setDraft({ ...draft, voucherRedemption: picked ?? undefined }),
|
|
157
|
+
currency: pricing?.currency,
|
|
158
|
+
amountCents: pricing?.total ?? undefined,
|
|
159
|
+
}) }));
|
|
160
|
+
}
|
|
161
|
+
return (_jsx(VoucherPickerSection, { value: voucher, onChange: (next) => {
|
|
162
|
+
setVoucher(next);
|
|
163
|
+
const redemption = next.picked && next.picked.remainingAmountCents != null
|
|
164
|
+
? {
|
|
165
|
+
voucherId: next.picked.id,
|
|
166
|
+
amountCents: next.picked.remainingAmountCents,
|
|
167
|
+
}
|
|
168
|
+
: undefined;
|
|
169
|
+
setDraft({ ...draft, voucherRedemption: redemption });
|
|
170
|
+
}, currency: pricing?.currency, amountCents: pricing?.total ?? undefined, labels: {
|
|
171
|
+
heading: labels.voucherHeading,
|
|
172
|
+
codePlaceholder: labels.voucherCodePlaceholder,
|
|
173
|
+
apply: labels.voucherApply,
|
|
174
|
+
clear: labels.voucherClear,
|
|
175
|
+
remainingLabel: labels.voucherRemainingLabel,
|
|
176
|
+
invalidLabel: labels.voucherInvalidLabel,
|
|
177
|
+
} }));
|
|
178
|
+
}
|
|
179
|
+
function BankTransferDetails({ capabilities, }) {
|
|
180
|
+
const messages = useBookingsUiMessagesOrDefault();
|
|
181
|
+
const note = capabilities.config?.bankTransferNote;
|
|
182
|
+
return (_jsxs("div", { className: "rounded-md border bg-muted/30 p-3 text-sm", children: [_jsx("p", { className: "font-medium", children: messages.bookingJourney.payment.bankTransferInstructions }), _jsx("p", { className: "text-muted-foreground text-xs", children: typeof note === "string" && note.length > 0
|
|
183
|
+
? note
|
|
184
|
+
: messages.bookingJourney.payment.bankTransferDefaultNote })] }));
|
|
185
|
+
}
|
|
186
|
+
function isCapabilityEnabled(intent, capabilities) {
|
|
187
|
+
switch (intent) {
|
|
188
|
+
case "card":
|
|
189
|
+
return capabilities.acceptsCard;
|
|
190
|
+
case "hold":
|
|
191
|
+
return capabilities.acceptsHold;
|
|
192
|
+
case "bank_transfer":
|
|
193
|
+
return capabilities.acceptsBankTransfer === true;
|
|
194
|
+
case "ticket_on_credit":
|
|
195
|
+
return capabilities.acceptsTicketOnCredit;
|
|
196
|
+
case "inquiry":
|
|
197
|
+
return capabilities.acceptsInquiry === true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function intentMeta(intent, messages, surface) {
|
|
201
|
+
// On the operator surface "card" isn't an instant charge — the operator
|
|
202
|
+
// generates a hosted payment link the customer pays later (Netopia, Stripe
|
|
203
|
+
// Checkout, etc). Use operator-framed copy so it doesn't read as "charged
|
|
204
|
+
// immediately".
|
|
205
|
+
if (intent === "card" && surface === "admin") {
|
|
206
|
+
return {
|
|
207
|
+
label: messages.bookingJourney.payment.cardOperatorLabel,
|
|
208
|
+
description: messages.bookingJourney.payment.cardOperatorDescription,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
label: messages.bookingJourney.payment.intentLabels[intent],
|
|
213
|
+
description: messages.bookingJourney.payment.intentDescriptions[intent],
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Operator-only PAYMENT-RELATED finalize controls — manual price override and
|
|
218
|
+
* voucher redemption (both change the amount due, so they live in the Payment
|
|
219
|
+
* block). Non-payment finalization (internal notes, document generation) lives
|
|
220
|
+
* in the separate Documents step.
|
|
221
|
+
*/
|
|
222
|
+
export function FinalizeControls({ draft, setDraft, pricing, renderVoucherPicker, }) {
|
|
223
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(PriceOverrideEditor, { draft: draft, setDraft: setDraft, pricing: pricing }), _jsx(VoucherEditor, { draft: draft, setDraft: setDraft, pricing: pricing, renderVoucherPicker: renderVoucherPicker })] }));
|
|
224
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Draft } from "../../lib/draft-state.js";
|
|
2
|
+
export declare function ReviewStep({ draft, setDraft, isCommitting, onConfirm, canConfirm, renderExtras, surface, warnings, }: {
|
|
3
|
+
draft: Draft;
|
|
4
|
+
setDraft: (next: Draft) => void;
|
|
5
|
+
isCommitting: boolean;
|
|
6
|
+
onConfirm: () => void;
|
|
7
|
+
warnings?: ReadonlyArray<string>;
|
|
8
|
+
/** Gate the confirm button — when `false`, it's disabled with a hint
|
|
9
|
+
* (stacked layout, where there are no per-step advance gates). The
|
|
10
|
+
* wizard reaches Review only after passing every gate, so it omits
|
|
11
|
+
* this (defaults to enabled). */
|
|
12
|
+
canConfirm?: boolean;
|
|
13
|
+
renderExtras?: () => React.ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Drives the notes field. Public storefronts collect
|
|
16
|
+
* customer-facing "anything we should know?" notes; operator
|
|
17
|
+
* surfaces collect operator-only internal notes. Defaults to
|
|
18
|
+
* `admin` so existing operator usage stays unchanged.
|
|
19
|
+
*/
|
|
20
|
+
surface?: "admin" | "public";
|
|
21
|
+
/** Live quote total + currency — drives the price-override default. */
|
|
22
|
+
pricing?: {
|
|
23
|
+
total: number;
|
|
24
|
+
currency: string;
|
|
25
|
+
} | null;
|
|
26
|
+
}): React.ReactElement;
|
|
27
|
+
//# sourceMappingURL=review-step.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-step.d.ts","sourceRoot":"","sources":["../../../../src/journey/components/journey-steps/review-step.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAOrD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,UAAU,EACV,YAAY,EACZ,OAAO,EACP,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/B,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAChC;;;sCAGkC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAA;IACpC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC5B,uEAAuE;IACvE,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CACrD,GAAG,KAAK,CAAC,YAAY,CAiErB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Separator } from "@voyantjs/ui/components";
|
|
4
|
+
import { Button } from "@voyantjs/ui/components/button";
|
|
5
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components/card";
|
|
6
|
+
import { Label } from "@voyantjs/ui/components/label";
|
|
7
|
+
import { Textarea } from "@voyantjs/ui/components/textarea";
|
|
8
|
+
import { Loader2 } from "lucide-react";
|
|
9
|
+
import { useBookingsUiMessagesOrDefault } from "../../../i18n/index.js";
|
|
10
|
+
import { JourneyWarnings } from "./shared.js";
|
|
11
|
+
// ─────────────────────────────────────────────────────────────────
|
|
12
|
+
// Review
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────
|
|
14
|
+
export function ReviewStep({ draft, setDraft, isCommitting, onConfirm, canConfirm, renderExtras, surface, warnings, }) {
|
|
15
|
+
const messages = useBookingsUiMessagesOrDefault();
|
|
16
|
+
const isPublic = surface === "public";
|
|
17
|
+
return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: messages.bookingJourney.review.title }) }), _jsx(Separator, {}), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("div", { className: "font-medium", children: messages.bookingJourney.review.leadContact }), _jsxs("div", { className: "text-muted-foreground text-sm", children: [draft.billing.contact.firstName, " ", draft.billing.contact.lastName, " \u00B7", " ", draft.billing.contact.email] })] }), _jsxs("div", { children: [_jsx("div", { className: "font-medium", children: messages.bookingJourney.review.travelers }), _jsx("ul", { className: "text-muted-foreground text-sm", children: draft.travelers.map((t, i) => (_jsxs("li", { children: [t.firstName, " ", t.lastName, " (", t.band, ")"] }, t.rowId ?? i))) })] }), isPublic ? (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: "bj-customer-notes", children: messages.bookingJourney.review.customerNotes }), _jsx(Textarea, { id: "bj-customer-notes", placeholder: messages.bookingJourney.review.customerNotesPlaceholder, value: draft.customerNotes ?? "", onChange: (e) => setDraft({ ...draft, customerNotes: e.target.value }) })] })) : null, renderExtras ? _jsx("div", { children: renderExtras() }) : null, _jsx(JourneyWarnings, { warnings: warnings }), _jsxs("div", { className: "space-y-2", children: [_jsx(Button, { onClick: onConfirm, disabled: isCommitting || canConfirm === false, children: isCommitting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.bookingJourney.review.confirming] })) : (messages.bookingJourney.review.confirmBooking) }), canConfirm === false ? (_jsx("p", { className: "text-muted-foreground text-sm", children: messages.bookingJourney.review.completeToConfirm })) : null] })] })] }));
|
|
18
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-used leaf helpers + shared types for the journey step components.
|
|
3
|
+
* Everything else imports shared helpers from here.
|
|
4
|
+
*/
|
|
5
|
+
import type { BookingDraftShape } from "@voyantjs/catalog/booking-engine";
|
|
6
|
+
import { useBookingsUiMessagesOrDefault } from "../../../i18n/index.js";
|
|
7
|
+
import type { Draft } from "../../lib/draft-state.js";
|
|
8
|
+
import type { DeparturePickerProps, UnitsPickerProps } from "../../types.js";
|
|
9
|
+
/** Injectable departure-picker render slot, threaded from BookingJourneyProps. */
|
|
10
|
+
export type RenderDeparturePicker = (props: DeparturePickerProps) => React.ReactNode;
|
|
11
|
+
/** Injectable units (rooms) render slot, threaded from BookingJourneyProps. */
|
|
12
|
+
export type RenderUnitsPicker = (props: UnitsPickerProps) => React.ReactNode;
|
|
13
|
+
export interface StepCommonProps {
|
|
14
|
+
draft: Draft;
|
|
15
|
+
setDraft: (next: Draft) => void;
|
|
16
|
+
shape: BookingDraftShape;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Soft validation warnings for a step, rendered INSIDE its card (below the
|
|
20
|
+
* content) so they're visibly scoped to the block they belong to.
|
|
21
|
+
*/
|
|
22
|
+
export declare function JourneyWarnings({ warnings, }: {
|
|
23
|
+
warnings?: ReadonlyArray<string>;
|
|
24
|
+
}): React.ReactElement | null;
|
|
25
|
+
export declare function Field({ id, label, value, onChange, type, placeholder, }: {
|
|
26
|
+
id: string;
|
|
27
|
+
label: string;
|
|
28
|
+
value: string;
|
|
29
|
+
onChange: (v: string) => void;
|
|
30
|
+
type?: string;
|
|
31
|
+
placeholder?: string;
|
|
32
|
+
}): React.ReactElement;
|
|
33
|
+
export declare function PhoneField({ id, label, value, onChange, }: {
|
|
34
|
+
id: string;
|
|
35
|
+
label: string;
|
|
36
|
+
value: string;
|
|
37
|
+
onChange: (v: string) => void;
|
|
38
|
+
}): React.ReactElement;
|
|
39
|
+
/**
|
|
40
|
+
* Date field that uses the shared `<DatePicker />` from
|
|
41
|
+
* `@voyantjs/ui` with a month + year dropdown caption so users can
|
|
42
|
+
* jump across decades without arrow-clicking. The `range` hint picks
|
|
43
|
+
* a reasonable startMonth/endMonth window per use case:
|
|
44
|
+
*
|
|
45
|
+
* - `"past"` — DOB-style picks (today back ~120 years)
|
|
46
|
+
* - `"future"` — departure / check-in / check-out (today forward ~5 years)
|
|
47
|
+
* - `"document"` — passport / ID expiry (today forward ~20 years)
|
|
48
|
+
*/
|
|
49
|
+
export declare function DateField({ id, label, value, onChange, range, }: {
|
|
50
|
+
id: string;
|
|
51
|
+
label: string;
|
|
52
|
+
value: string;
|
|
53
|
+
onChange: (v: string) => void;
|
|
54
|
+
range?: "past" | "future" | "document";
|
|
55
|
+
}): React.ReactElement;
|
|
56
|
+
export declare function SelectField({ id, label, value, options, onChange, }: {
|
|
57
|
+
id: string;
|
|
58
|
+
label: string;
|
|
59
|
+
value: string;
|
|
60
|
+
options: ReadonlyArray<{
|
|
61
|
+
value: string;
|
|
62
|
+
label: string;
|
|
63
|
+
}>;
|
|
64
|
+
onChange: (v: string) => void;
|
|
65
|
+
}): React.ReactElement;
|
|
66
|
+
/**
|
|
67
|
+
* Years between an ISO date-of-birth and today. Returns `null` for
|
|
68
|
+
* unparseable input or future dates so the UI can hide the badge
|
|
69
|
+
* gracefully rather than rendering "age -3".
|
|
70
|
+
*/
|
|
71
|
+
export declare function computeAge(dob: string): number | null;
|
|
72
|
+
export declare function ageHint(min: number | undefined, max: number | undefined, messages: ReturnType<typeof useBookingsUiMessagesOrDefault>): string;
|
|
73
|
+
export declare function bucketBy<T>(items: ReadonlyArray<T>, keyFn: (item: T) => string): Map<string, T[]>;
|
|
74
|
+
export declare function cryptoRowId(): string;
|
|
75
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../../src/journey/components/journey-steps/shared.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { DatePicker } from "@voyantjs/ui/components/date-picker";
|
|
4
|
+
import { Input } from "@voyantjs/ui/components/input";
|
|
5
|
+
import { Label } from "@voyantjs/ui/components/label";
|
|
6
|
+
import { PhoneInput } from "@voyantjs/ui/components/phone-input";
|
|
7
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@voyantjs/ui/components/select";
|
|
8
|
+
import { formatMessage, useBookingsUiMessagesOrDefault } from "../../../i18n/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Soft validation warnings for a step, rendered INSIDE its card (below the
|
|
11
|
+
* content) so they're visibly scoped to the block they belong to.
|
|
12
|
+
*/
|
|
13
|
+
export function JourneyWarnings({ warnings, }) {
|
|
14
|
+
if (!warnings || warnings.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
return (_jsx("ul", { className: "space-y-1 rounded-md border border-amber-300 bg-amber-50 p-3 text-amber-900 text-sm dark:border-amber-700 dark:bg-amber-950 dark:text-amber-100", children: warnings.map((w) => (_jsxs("li", { children: ["\u26A0 ", w] }, w))) }));
|
|
17
|
+
}
|
|
18
|
+
export function Field({ id, label, value, onChange, type, placeholder, }) {
|
|
19
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: id, children: label }), _jsx(Input, { id: id, type: type ?? "text", value: value, placeholder: placeholder, onChange: (e) => onChange(e.target.value) })] }));
|
|
20
|
+
}
|
|
21
|
+
export function PhoneField({ id, label, value, onChange, }) {
|
|
22
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: id, children: label }), _jsx(PhoneInput, { id: id, defaultCountry: "GB", international: true, value: value || undefined, onChange: (v) => onChange(v ? String(v) : "") })] }));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Date field that uses the shared `<DatePicker />` from
|
|
26
|
+
* `@voyantjs/ui` with a month + year dropdown caption so users can
|
|
27
|
+
* jump across decades without arrow-clicking. The `range` hint picks
|
|
28
|
+
* a reasonable startMonth/endMonth window per use case:
|
|
29
|
+
*
|
|
30
|
+
* - `"past"` — DOB-style picks (today back ~120 years)
|
|
31
|
+
* - `"future"` — departure / check-in / check-out (today forward ~5 years)
|
|
32
|
+
* - `"document"` — passport / ID expiry (today forward ~20 years)
|
|
33
|
+
*/
|
|
34
|
+
export function DateField({ id, label, value, onChange, range = "future", }) {
|
|
35
|
+
const today = new Date();
|
|
36
|
+
const todayMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
|
37
|
+
const startMonth = range === "past"
|
|
38
|
+
? new Date(today.getFullYear() - 120, 0, 1)
|
|
39
|
+
: range === "document"
|
|
40
|
+
? todayMonth
|
|
41
|
+
: todayMonth;
|
|
42
|
+
const endMonth = range === "past"
|
|
43
|
+
? new Date(today.getFullYear() + 1, 11, 1)
|
|
44
|
+
: range === "document"
|
|
45
|
+
? new Date(today.getFullYear() + 20, 11, 1)
|
|
46
|
+
: new Date(today.getFullYear() + 5, 11, 1);
|
|
47
|
+
const defaultMonth = range === "past" && !value ? new Date(today.getFullYear() - 30, 0, 1) : undefined;
|
|
48
|
+
return (_jsxs("div", { className: "space-y-1", id: id, children: [_jsx(Label, { children: label }), _jsx(DatePicker, { value: value || null, onChange: (v) => onChange(v ?? ""), captionLayout: "dropdown", startMonth: startMonth, endMonth: endMonth, defaultMonth: defaultMonth, displayFormat: "PPP" })] }));
|
|
49
|
+
}
|
|
50
|
+
export function SelectField({ id, label, value, options, onChange, }) {
|
|
51
|
+
const messages = useBookingsUiMessagesOrDefault();
|
|
52
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: id, children: label }), _jsxs(Select, { value: value || undefined, onValueChange: (v) => onChange(v ?? ""), children: [_jsx(SelectTrigger, { id: id, className: "w-full", children: _jsx(SelectValue, { placeholder: messages.bookingJourney.values.selectPlaceholder }) }), _jsx(SelectContent, { children: options.map((opt) => (_jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value))) })] })] }));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Years between an ISO date-of-birth and today. Returns `null` for
|
|
56
|
+
* unparseable input or future dates so the UI can hide the badge
|
|
57
|
+
* gracefully rather than rendering "age -3".
|
|
58
|
+
*/
|
|
59
|
+
export function computeAge(dob) {
|
|
60
|
+
const d = new Date(dob);
|
|
61
|
+
if (Number.isNaN(d.getTime()))
|
|
62
|
+
return null;
|
|
63
|
+
const now = new Date();
|
|
64
|
+
let age = now.getFullYear() - d.getFullYear();
|
|
65
|
+
const m = now.getMonth() - d.getMonth();
|
|
66
|
+
if (m < 0 || (m === 0 && now.getDate() < d.getDate()))
|
|
67
|
+
age -= 1;
|
|
68
|
+
return age >= 0 ? age : null;
|
|
69
|
+
}
|
|
70
|
+
export function ageHint(min, max, messages) {
|
|
71
|
+
if (min != null && max != null) {
|
|
72
|
+
return formatMessage(messages.bookingJourney.configure.ageHintRange, {
|
|
73
|
+
min,
|
|
74
|
+
max,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (min != null) {
|
|
78
|
+
return formatMessage(messages.bookingJourney.configure.ageHintMinimum, {
|
|
79
|
+
min,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (max != null) {
|
|
83
|
+
return formatMessage(messages.bookingJourney.configure.ageHintMaximum, {
|
|
84
|
+
max,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
// i18n-literal-ok Generic helper type signature, not user-visible copy.
|
|
90
|
+
export function bucketBy(items, keyFn) {
|
|
91
|
+
const map = new Map();
|
|
92
|
+
for (const item of items) {
|
|
93
|
+
const key = keyFn(item);
|
|
94
|
+
let bucket = map.get(key);
|
|
95
|
+
if (!bucket) {
|
|
96
|
+
bucket = [];
|
|
97
|
+
map.set(key, bucket);
|
|
98
|
+
}
|
|
99
|
+
bucket.push(item);
|
|
100
|
+
}
|
|
101
|
+
return map;
|
|
102
|
+
}
|
|
103
|
+
export function cryptoRowId() {
|
|
104
|
+
if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.randomUUID) {
|
|
105
|
+
return globalThis.crypto.randomUUID();
|
|
106
|
+
}
|
|
107
|
+
return `r_${Math.random().toString(36).slice(2, 10)}`;
|
|
108
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TravelerContactPickerProps } from "../../types.js";
|
|
2
|
+
import { type StepCommonProps } from "./shared.js";
|
|
3
|
+
export declare function TravelersStep({ draft, setDraft, shape, renderTravelerContactPicker, warnings, }: StepCommonProps & {
|
|
4
|
+
renderTravelerContactPicker?: (props: TravelerContactPickerProps) => React.ReactNode;
|
|
5
|
+
warnings?: ReadonlyArray<string>;
|
|
6
|
+
}): React.ReactElement;
|
|
7
|
+
//# sourceMappingURL=travelers-step.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"travelers-step.d.ts","sourceRoot":"","sources":["../../../../src/journey/components/journey-steps/travelers-step.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AAEhE,OAAO,EAQL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAA;AA+BpB,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,2BAA2B,EAC3B,QAAQ,GACT,EAAE,eAAe,GAAG;IACnB,2BAA2B,CAAC,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,KAAK,CAAC,SAAS,CAAA;IACpF,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACjC,GAAG,KAAK,CAAC,YAAY,CAwGrB"}
|