@voyant-travel/bookings-react 0.185.0 → 0.186.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.
- package/dist/journey/components/booking-journey.js +14 -1
- package/dist/journey/components/side-panel.js +1 -1
- package/dist/requirements/hooks/use-booking-questions.d.ts +1 -1
- package/dist/requirements/hooks/use-contact-requirements.d.ts +1 -1
- package/dist/requirements/query-options.d.ts +8 -8
- package/dist/requirements/schemas.d.ts +9 -9
- package/package.json +33 -33
|
@@ -203,6 +203,19 @@ export function BookingJourney(props) {
|
|
|
203
203
|
(quote.data.available === false ||
|
|
204
204
|
(quote.data.invalidReason != null && quote.data.invalidReason !== ""));
|
|
205
205
|
const quoteBlocked = hasQuoteError || quoteUnpriceable;
|
|
206
|
+
// The pristine baseline quote is intentionally un-priceable: a product has no
|
|
207
|
+
// price until its price driver — a room, or a traveler count — is chosen, and
|
|
208
|
+
// the engine reports that empty draft as `no_sell_amount_configured`. Suppress
|
|
209
|
+
// the un-priceable banner (and the side-panel error) for exactly that baseline
|
|
210
|
+
// so step 1 doesn't scream "can't be priced" before the buyer has picked
|
|
211
|
+
// anything. Any other reason (e.g. `rates_missing` on an already-picked stay,
|
|
212
|
+
// #2638), or the same code once a driver IS picked (a room that carries no
|
|
213
|
+
// price), still surfaces. Commit stays gated on `quoteBlocked` regardless, so
|
|
214
|
+
// an unpriced booking can never be submitted.
|
|
215
|
+
const priceDriversConfigured = (draft?.configure?.optionSelections?.length ?? 0) > 0 ||
|
|
216
|
+
Object.values(draft?.configure?.pax ?? {}).reduce((sum, n) => sum + (n ?? 0), 0) > 0;
|
|
217
|
+
const isPristineUnconfigured = quote.data?.invalidReason === "no_sell_amount_configured" && !priceDriversConfigured;
|
|
218
|
+
const showQuoteUnpriceable = quoteBlocked && !isPristineUnconfigured;
|
|
206
219
|
const quoteReady = Boolean(quote.data?.quoteId);
|
|
207
220
|
// Step navigation only hard-blocks on a thrown quote error (a transient fetch
|
|
208
221
|
// failure that a retry fixes). An un-priceable quote (e.g. `rates_missing`
|
|
@@ -404,7 +417,7 @@ export function BookingJourney(props) {
|
|
|
404
417
|
setConfirmError(null);
|
|
405
418
|
void quote.refetch();
|
|
406
419
|
};
|
|
407
|
-
const quoteErrorBanner =
|
|
420
|
+
const quoteErrorBanner = showQuoteUnpriceable ? (_jsxs("div", { role: "alert", "aria-live": "polite", className: "flex flex-col items-start gap-2 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-destructive text-sm", children: [_jsx("span", { children: hasQuoteError
|
|
408
421
|
? messages.bookingJourney.validation.quoteFailed
|
|
409
422
|
: messages.bookingJourney.validation.pricingUnavailable }), hasQuoteError ? (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: retryQuote, disabled: quote.isQuoting, children: messages.bookingJourney.validation.retryQuote })) : null] })) : null;
|
|
410
423
|
// Renders one step's content. Shared by both layouts — the wizard shows
|
|
@@ -31,7 +31,7 @@ export function PriceSidePanel({ pricing, isQuoting, invalidReason, entitySummar
|
|
|
31
31
|
// Departure shows directly under the product title — it's the most-glanced
|
|
32
32
|
// fact, so it doesn't belong buried in the recap accordion.
|
|
33
33
|
const departureText = draft ? stepHeadline("departure", draft, messages, locale) : "";
|
|
34
|
-
return (_jsxs(Card, { className: className, children: [entitySummary?.heroImageUrl ? (_jsx("img", { src: entitySummary.heroImageUrl, alt: entitySummary.name, className: "aspect-video w-full object-cover" })) : null, entitySummary ? (_jsx(EntityHeader, { summary: entitySummary, departureText: departureText })) : null, _jsxs(CardContent, { className: "space-y-4", children: [steps && steps.length > 0 && currentStep && draft ? (_jsx(StepRecap, { steps: steps, currentStep: currentStep, draft: draft })) : null, invalidReason ? _jsx("p", { className: "text-destructive text-sm", children:
|
|
34
|
+
return (_jsxs(Card, { className: className, children: [entitySummary?.heroImageUrl ? (_jsx("img", { src: entitySummary.heroImageUrl, alt: entitySummary.name, className: "aspect-video w-full object-cover" })) : null, entitySummary ? (_jsx(EntityHeader, { summary: entitySummary, departureText: departureText })) : null, _jsxs(CardContent, { className: "space-y-4", children: [steps && steps.length > 0 && currentStep && draft ? (_jsx(StepRecap, { steps: steps, currentStep: currentStep, draft: draft })) : null, invalidReason && showPricing ? (_jsx("p", { className: "text-destructive text-sm", children: messages.bookingJourney.validation.pricingUnavailable })) : null, !showPricing ? (_jsx("p", { className: "border-t pt-4 text-muted-foreground text-sm", children: pricingHint })) : isQuoting && !pricing ? (_jsxs("div", { className: "space-y-2 border-t pt-4", children: [_jsx(Skeleton, { className: "h-4 w-24" }), _jsx(Skeleton, { className: "h-4 w-32" }), _jsx(Skeleton, { className: "h-4 w-20" })] })) : null, showPricing && 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, locale) })] }, `${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: [_jsxs("span", { children: [tax.label, tax.rate > 0 ? ` (${formatTaxRate(tax.rate)})` : ""] }), _jsx("span", { children: formatMoney(tax.amount, pricing.currency, locale) })] }, 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, locale) })] })] })) : null, pricingExtras ? _jsx("div", { className: "border-t pt-4", children: pricingExtras }) : null] })] }));
|
|
35
35
|
}
|
|
36
36
|
function EntityHeader({ summary, departureText, }) {
|
|
37
37
|
// Text block only — the hero image is rendered as a direct Card child above.
|
|
@@ -10,7 +10,7 @@ export declare function useBookingQuestions(options?: UseBookingQuestionsOptions
|
|
|
10
10
|
label: string;
|
|
11
11
|
description: string | null;
|
|
12
12
|
target: "service" | "extra" | "traveler" | "booking" | "lead_traveler" | "booker";
|
|
13
|
-
fieldType: "number" | "boolean" | "date" | "other" | "file" | "
|
|
13
|
+
fieldType: "number" | "boolean" | "date" | "other" | "file" | "textarea" | "text" | "email" | "phone" | "datetime" | "single_select" | "multi_select" | "country";
|
|
14
14
|
placeholder: string | null;
|
|
15
15
|
helpText: string | null;
|
|
16
16
|
isRequired: boolean;
|
|
@@ -7,7 +7,7 @@ export declare function useContactRequirements(options?: UseContactRequirementsO
|
|
|
7
7
|
id: string;
|
|
8
8
|
productId: string;
|
|
9
9
|
optionId: string | null;
|
|
10
|
-
fieldKey: "other" | "
|
|
10
|
+
fieldKey: "other" | "address" | "email" | "phone" | "nationality" | "first_name" | "last_name" | "date_of_birth" | "passport_number" | "passport_expiry" | "dietary_requirements" | "accessibility_needs" | "special_requests";
|
|
11
11
|
scope: "traveler" | "booking" | "lead_traveler" | "booker";
|
|
12
12
|
isRequired: boolean;
|
|
13
13
|
perTraveler: boolean;
|
|
@@ -57,7 +57,7 @@ export declare function getContactRequirementsQueryOptions(client: FetchWithVali
|
|
|
57
57
|
id: string;
|
|
58
58
|
productId: string;
|
|
59
59
|
optionId: string | null;
|
|
60
|
-
fieldKey: "other" | "
|
|
60
|
+
fieldKey: "other" | "address" | "email" | "phone" | "nationality" | "first_name" | "last_name" | "date_of_birth" | "passport_number" | "passport_expiry" | "dietary_requirements" | "accessibility_needs" | "special_requests";
|
|
61
61
|
scope: "traveler" | "booking" | "lead_traveler" | "booker";
|
|
62
62
|
isRequired: boolean;
|
|
63
63
|
perTraveler: boolean;
|
|
@@ -73,7 +73,7 @@ export declare function getContactRequirementsQueryOptions(client: FetchWithVali
|
|
|
73
73
|
id: string;
|
|
74
74
|
productId: string;
|
|
75
75
|
optionId: string | null;
|
|
76
|
-
fieldKey: "other" | "
|
|
76
|
+
fieldKey: "other" | "address" | "email" | "phone" | "nationality" | "first_name" | "last_name" | "date_of_birth" | "passport_number" | "passport_expiry" | "dietary_requirements" | "accessibility_needs" | "special_requests";
|
|
77
77
|
scope: "traveler" | "booking" | "lead_traveler" | "booker";
|
|
78
78
|
isRequired: boolean;
|
|
79
79
|
perTraveler: boolean;
|
|
@@ -90,7 +90,7 @@ export declare function getContactRequirementsQueryOptions(client: FetchWithVali
|
|
|
90
90
|
id: string;
|
|
91
91
|
productId: string;
|
|
92
92
|
optionId: string | null;
|
|
93
|
-
fieldKey: "other" | "
|
|
93
|
+
fieldKey: "other" | "address" | "email" | "phone" | "nationality" | "first_name" | "last_name" | "date_of_birth" | "passport_number" | "passport_expiry" | "dietary_requirements" | "accessibility_needs" | "special_requests";
|
|
94
94
|
scope: "traveler" | "booking" | "lead_traveler" | "booker";
|
|
95
95
|
isRequired: boolean;
|
|
96
96
|
perTraveler: boolean;
|
|
@@ -109,7 +109,7 @@ export declare function getContactRequirementsQueryOptions(client: FetchWithVali
|
|
|
109
109
|
id: string;
|
|
110
110
|
productId: string;
|
|
111
111
|
optionId: string | null;
|
|
112
|
-
fieldKey: "other" | "
|
|
112
|
+
fieldKey: "other" | "address" | "email" | "phone" | "nationality" | "first_name" | "last_name" | "date_of_birth" | "passport_number" | "passport_expiry" | "dietary_requirements" | "accessibility_needs" | "special_requests";
|
|
113
113
|
scope: "traveler" | "booking" | "lead_traveler" | "booker";
|
|
114
114
|
isRequired: boolean;
|
|
115
115
|
perTraveler: boolean;
|
|
@@ -132,7 +132,7 @@ export declare function getBookingQuestionsQueryOptions(client: FetchWithValidat
|
|
|
132
132
|
label: string;
|
|
133
133
|
description: string | null;
|
|
134
134
|
target: "service" | "extra" | "traveler" | "booking" | "lead_traveler" | "booker";
|
|
135
|
-
fieldType: "number" | "boolean" | "date" | "other" | "file" | "
|
|
135
|
+
fieldType: "number" | "boolean" | "date" | "other" | "file" | "textarea" | "text" | "email" | "phone" | "datetime" | "single_select" | "multi_select" | "country";
|
|
136
136
|
placeholder: string | null;
|
|
137
137
|
helpText: string | null;
|
|
138
138
|
isRequired: boolean;
|
|
@@ -150,7 +150,7 @@ export declare function getBookingQuestionsQueryOptions(client: FetchWithValidat
|
|
|
150
150
|
label: string;
|
|
151
151
|
description: string | null;
|
|
152
152
|
target: "service" | "extra" | "traveler" | "booking" | "lead_traveler" | "booker";
|
|
153
|
-
fieldType: "number" | "boolean" | "date" | "other" | "file" | "
|
|
153
|
+
fieldType: "number" | "boolean" | "date" | "other" | "file" | "textarea" | "text" | "email" | "phone" | "datetime" | "single_select" | "multi_select" | "country";
|
|
154
154
|
placeholder: string | null;
|
|
155
155
|
helpText: string | null;
|
|
156
156
|
isRequired: boolean;
|
|
@@ -169,7 +169,7 @@ export declare function getBookingQuestionsQueryOptions(client: FetchWithValidat
|
|
|
169
169
|
label: string;
|
|
170
170
|
description: string | null;
|
|
171
171
|
target: "service" | "extra" | "traveler" | "booking" | "lead_traveler" | "booker";
|
|
172
|
-
fieldType: "number" | "boolean" | "date" | "other" | "file" | "
|
|
172
|
+
fieldType: "number" | "boolean" | "date" | "other" | "file" | "textarea" | "text" | "email" | "phone" | "datetime" | "single_select" | "multi_select" | "country";
|
|
173
173
|
placeholder: string | null;
|
|
174
174
|
helpText: string | null;
|
|
175
175
|
isRequired: boolean;
|
|
@@ -190,7 +190,7 @@ export declare function getBookingQuestionsQueryOptions(client: FetchWithValidat
|
|
|
190
190
|
label: string;
|
|
191
191
|
description: string | null;
|
|
192
192
|
target: "service" | "extra" | "traveler" | "booking" | "lead_traveler" | "booker";
|
|
193
|
-
fieldType: "number" | "boolean" | "date" | "other" | "file" | "
|
|
193
|
+
fieldType: "number" | "boolean" | "date" | "other" | "file" | "textarea" | "text" | "email" | "phone" | "datetime" | "single_select" | "multi_select" | "country";
|
|
194
194
|
placeholder: string | null;
|
|
195
195
|
helpText: string | null;
|
|
196
196
|
isRequired: boolean;
|
|
@@ -22,10 +22,10 @@ export declare const questionFieldTypeSchema: z.ZodEnum<{
|
|
|
22
22
|
date: "date";
|
|
23
23
|
other: "other";
|
|
24
24
|
file: "file";
|
|
25
|
-
email: "email";
|
|
26
|
-
phone: "phone";
|
|
27
25
|
textarea: "textarea";
|
|
28
26
|
text: "text";
|
|
27
|
+
email: "email";
|
|
28
|
+
phone: "phone";
|
|
29
29
|
datetime: "datetime";
|
|
30
30
|
single_select: "single_select";
|
|
31
31
|
multi_select: "multi_select";
|
|
@@ -51,10 +51,10 @@ export declare const bookingQuestionSchema: z.ZodObject<{
|
|
|
51
51
|
date: "date";
|
|
52
52
|
other: "other";
|
|
53
53
|
file: "file";
|
|
54
|
-
email: "email";
|
|
55
|
-
phone: "phone";
|
|
56
54
|
textarea: "textarea";
|
|
57
55
|
text: "text";
|
|
56
|
+
email: "email";
|
|
57
|
+
phone: "phone";
|
|
58
58
|
datetime: "datetime";
|
|
59
59
|
single_select: "single_select";
|
|
60
60
|
multi_select: "multi_select";
|
|
@@ -79,9 +79,9 @@ export declare const bookingQuestionOptionSchema: z.ZodObject<{
|
|
|
79
79
|
export type BookingQuestionOption = z.infer<typeof bookingQuestionOptionSchema>;
|
|
80
80
|
export declare const contactFieldKeySchema: z.ZodEnum<{
|
|
81
81
|
other: "other";
|
|
82
|
+
address: "address";
|
|
82
83
|
email: "email";
|
|
83
84
|
phone: "phone";
|
|
84
|
-
address: "address";
|
|
85
85
|
nationality: "nationality";
|
|
86
86
|
first_name: "first_name";
|
|
87
87
|
last_name: "last_name";
|
|
@@ -104,9 +104,9 @@ export declare const contactRequirementSchema: z.ZodObject<{
|
|
|
104
104
|
optionId: z.ZodNullable<z.ZodString>;
|
|
105
105
|
fieldKey: z.ZodEnum<{
|
|
106
106
|
other: "other";
|
|
107
|
+
address: "address";
|
|
107
108
|
email: "email";
|
|
108
109
|
phone: "phone";
|
|
109
|
-
address: "address";
|
|
110
110
|
nationality: "nationality";
|
|
111
111
|
first_name: "first_name";
|
|
112
112
|
last_name: "last_name";
|
|
@@ -162,10 +162,10 @@ export declare const bookingQuestionListResponse: z.ZodObject<{
|
|
|
162
162
|
date: "date";
|
|
163
163
|
other: "other";
|
|
164
164
|
file: "file";
|
|
165
|
-
email: "email";
|
|
166
|
-
phone: "phone";
|
|
167
165
|
textarea: "textarea";
|
|
168
166
|
text: "text";
|
|
167
|
+
email: "email";
|
|
168
|
+
phone: "phone";
|
|
169
169
|
datetime: "datetime";
|
|
170
170
|
single_select: "single_select";
|
|
171
171
|
multi_select: "multi_select";
|
|
@@ -202,9 +202,9 @@ export declare const contactRequirementListResponse: z.ZodObject<{
|
|
|
202
202
|
optionId: z.ZodNullable<z.ZodString>;
|
|
203
203
|
fieldKey: z.ZodEnum<{
|
|
204
204
|
other: "other";
|
|
205
|
+
address: "address";
|
|
205
206
|
email: "email";
|
|
206
207
|
phone: "phone";
|
|
207
|
-
address: "address";
|
|
208
208
|
nationality: "nationality";
|
|
209
209
|
first_name: "first_name";
|
|
210
210
|
last_name: "last_name";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyant-travel/bookings-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.186.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -150,24 +150,24 @@
|
|
|
150
150
|
"react-dom": "^19.0.0",
|
|
151
151
|
"react-hook-form": "^7.80.0",
|
|
152
152
|
"zod": "^4.0.0",
|
|
153
|
-
"@voyant-travel/accommodations": "^0.145.0",
|
|
154
153
|
"@voyant-travel/admin": "^0.128.3",
|
|
155
|
-
"@voyant-travel/bookings": "^0.
|
|
156
|
-
"@voyant-travel/
|
|
157
|
-
"@voyant-travel/catalog
|
|
158
|
-
"@voyant-travel/
|
|
159
|
-
"@voyant-travel/
|
|
160
|
-
"@voyant-travel/
|
|
161
|
-
"@voyant-travel/finance-react": "^0.
|
|
162
|
-
"@voyant-travel/identity-react": "^0.
|
|
163
|
-
"@voyant-travel/legal-react": "^0.
|
|
164
|
-
"@voyant-travel/
|
|
165
|
-
"@voyant-travel/
|
|
166
|
-
"@voyant-travel/inventory
|
|
167
|
-
"@voyant-travel/inventory": "^0.14.21",
|
|
168
|
-
"@voyant-travel/storefront-react": "^0.187.0",
|
|
154
|
+
"@voyant-travel/bookings": "^0.186.1",
|
|
155
|
+
"@voyant-travel/accommodations": "^0.146.0",
|
|
156
|
+
"@voyant-travel/catalog": "^0.184.0",
|
|
157
|
+
"@voyant-travel/catalog-react": "^0.184.0",
|
|
158
|
+
"@voyant-travel/distribution-react": "^0.176.0",
|
|
159
|
+
"@voyant-travel/relationships-react": "^0.186.0",
|
|
160
|
+
"@voyant-travel/finance-react": "^0.186.0",
|
|
161
|
+
"@voyant-travel/identity-react": "^0.186.0",
|
|
162
|
+
"@voyant-travel/legal-react": "^0.186.0",
|
|
163
|
+
"@voyant-travel/cruises": "^0.185.0",
|
|
164
|
+
"@voyant-travel/inventory-react": "^0.68.0",
|
|
165
|
+
"@voyant-travel/inventory": "^0.14.22",
|
|
169
166
|
"@voyant-travel/ui": "^0.109.3",
|
|
170
|
-
"@voyant-travel/
|
|
167
|
+
"@voyant-travel/storefront-react": "^0.188.0",
|
|
168
|
+
"@voyant-travel/operations-react": "^0.67.0",
|
|
169
|
+
"@voyant-travel/finance": "^0.186.0",
|
|
170
|
+
"@voyant-travel/commerce-react": "^0.68.0"
|
|
171
171
|
},
|
|
172
172
|
"peerDependenciesMeta": {
|
|
173
173
|
"@tanstack/react-table": {
|
|
@@ -251,26 +251,26 @@
|
|
|
251
251
|
"typescript": "^6.0.3",
|
|
252
252
|
"vitest": "^4.1.9",
|
|
253
253
|
"zod": "^4.4.3",
|
|
254
|
-
"@voyant-travel/accommodations": "^0.
|
|
254
|
+
"@voyant-travel/accommodations": "^0.146.0",
|
|
255
255
|
"@voyant-travel/admin": "^0.128.3",
|
|
256
|
-
"@voyant-travel/bookings": "^0.
|
|
257
|
-
"@voyant-travel/catalog": "^0.
|
|
258
|
-
"@voyant-travel/catalog-react": "^0.
|
|
259
|
-
"@voyant-travel/distribution-react": "^0.
|
|
260
|
-
"@voyant-travel/relationships-react": "^0.
|
|
261
|
-
"@voyant-travel/finance": "^0.
|
|
262
|
-
"@voyant-travel/finance-react": "^0.
|
|
263
|
-
"@voyant-travel/identity-react": "^0.
|
|
264
|
-
"@voyant-travel/legal-react": "^0.
|
|
265
|
-
"@voyant-travel/commerce-react": "^0.
|
|
266
|
-
"@voyant-travel/cruises": "^0.
|
|
267
|
-
"@voyant-travel/inventory-react": "^0.
|
|
268
|
-
"@voyant-travel/inventory": "^0.14.
|
|
256
|
+
"@voyant-travel/bookings": "^0.186.1",
|
|
257
|
+
"@voyant-travel/catalog": "^0.184.0",
|
|
258
|
+
"@voyant-travel/catalog-react": "^0.184.0",
|
|
259
|
+
"@voyant-travel/distribution-react": "^0.176.0",
|
|
260
|
+
"@voyant-travel/relationships-react": "^0.186.0",
|
|
261
|
+
"@voyant-travel/finance": "^0.186.0",
|
|
262
|
+
"@voyant-travel/finance-react": "^0.186.0",
|
|
263
|
+
"@voyant-travel/identity-react": "^0.186.0",
|
|
264
|
+
"@voyant-travel/legal-react": "^0.186.0",
|
|
265
|
+
"@voyant-travel/commerce-react": "^0.68.0",
|
|
266
|
+
"@voyant-travel/cruises": "^0.185.0",
|
|
267
|
+
"@voyant-travel/inventory-react": "^0.68.0",
|
|
268
|
+
"@voyant-travel/inventory": "^0.14.22",
|
|
269
269
|
"@voyant-travel/react": "^0.104.2",
|
|
270
|
-
"@voyant-travel/storefront-react": "^0.
|
|
270
|
+
"@voyant-travel/storefront-react": "^0.188.0",
|
|
271
271
|
"@voyant-travel/ui": "^0.109.3",
|
|
272
272
|
"@voyant-travel/voyant-typescript-config": "^0.1.0",
|
|
273
|
-
"@voyant-travel/operations-react": "^0.
|
|
273
|
+
"@voyant-travel/operations-react": "^0.67.0"
|
|
274
274
|
},
|
|
275
275
|
"files": [
|
|
276
276
|
"dist",
|