@voyant-travel/bookings-react 0.151.5 → 0.152.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 (35) hide show
  1. package/README.md +6 -1
  2. package/dist/admin/booking-detail-host.d.ts +12 -12
  3. package/dist/admin/booking-detail-host.d.ts.map +1 -1
  4. package/dist/admin/booking-detail-host.js +12 -5
  5. package/dist/admin/index.d.ts +5 -26
  6. package/dist/admin/index.d.ts.map +1 -1
  7. package/dist/admin/index.js +11 -25
  8. package/dist/admin/pages/booking-detail-page.d.ts +3 -5
  9. package/dist/admin/pages/booking-detail-page.d.ts.map +1 -1
  10. package/dist/admin/pages/booking-detail-page.js +3 -5
  11. package/dist/admin/pages/bookings-index-page.d.ts +2 -12
  12. package/dist/admin/pages/bookings-index-page.d.ts.map +1 -1
  13. package/dist/admin/pages/bookings-index-page.js +4 -3
  14. package/dist/admin/slots.d.ts +7 -0
  15. package/dist/admin/slots.d.ts.map +1 -1
  16. package/dist/admin/slots.js +7 -0
  17. package/dist/hooks/use-public-booking-session-flow-mutation.d.ts +1 -1
  18. package/dist/hooks/use-public-booking-session.d.ts +1 -1
  19. package/dist/query-options.d.ts +4 -4
  20. package/dist/storefront/index.d.ts +4 -0
  21. package/dist/storefront/index.d.ts.map +1 -0
  22. package/dist/storefront/index.js +3 -0
  23. package/dist/storefront/resolve-contract-variables.d.ts +131 -0
  24. package/dist/storefront/resolve-contract-variables.d.ts.map +1 -0
  25. package/dist/storefront/resolve-contract-variables.js +492 -0
  26. package/dist/storefront/storefront-booking-errors.d.ts +13 -0
  27. package/dist/storefront/storefront-booking-errors.d.ts.map +1 -0
  28. package/dist/storefront/storefront-booking-errors.js +50 -0
  29. package/dist/storefront/storefront-booking-journey.d.ts +72 -0
  30. package/dist/storefront/storefront-booking-journey.d.ts.map +1 -0
  31. package/dist/storefront/storefront-booking-journey.js +380 -0
  32. package/dist/storefront/storefront-booking-page.d.ts +36 -0
  33. package/dist/storefront/storefront-booking-page.d.ts.map +1 -0
  34. package/dist/storefront/storefront-booking-page.js +213 -0
  35. package/package.json +59 -24
@@ -0,0 +1,213 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { useStorefrontUi } from "@voyant-travel/storefront-react/storefront";
4
+ import { useMemo } from "react";
5
+ import { z } from "zod";
6
+ import { StorefrontBookingJourney, } from "./storefront-booking-journey.js";
7
+ export const storefrontBookingSearchSchema = z.object({
8
+ departureSlotId: z.string().optional(),
9
+ cabinCategoryId: z.string().optional(),
10
+ cabinNumberId: z.string().optional(),
11
+ airArrangement: z.enum(["cruise_line", "independent", "none"]).optional(),
12
+ checkIn: z.string().optional(),
13
+ checkOut: z.string().optional(),
14
+ roomTypeId: z.string().optional(),
15
+ ratePlanId: z.string().optional(),
16
+ board: z.string().optional(),
17
+ adult: z.coerce.number().int().min(0).optional(),
18
+ child: z.coerce.number().int().min(0).optional(),
19
+ infant: z.coerce.number().int().min(0).optional(),
20
+ draftId: z.string().optional(),
21
+ });
22
+ /** Customer booking page shared by Node applications and dedicated storefronts. */
23
+ export function StorefrontBookingPage({ entityModule, entityId, search, messages, extensions, }) {
24
+ const { apiUrl, navigate, scope } = useStorefrontUi();
25
+ const draftId = useMemo(() => search.draftId ?? generateDraftId(), [search.draftId]);
26
+ const initialConfigure = buildInitialConfigure(search);
27
+ const initialAccommodation = buildInitialAccommodation(search);
28
+ const { summary, source } = useEntityContent(apiUrl, entityModule, entityId, search);
29
+ return (_jsx(StorefrontBookingJourney, { entityModule: entityModule, entityId: entityId, draftId: draftId, initialConfigure: initialConfigure, initialAccommodation: initialAccommodation, entitySummary: summary, entitySource: source, messages: messages, scope: scope, onNavigateToShop: () => navigate({ to: "/shop" }), onNavigateToConfirmation: (bookingId, kind) => navigate({
30
+ to: "/shop/confirmation/$bookingId",
31
+ params: { bookingId },
32
+ ...(kind ? { search: { kind } } : {}),
33
+ }), ...(messages.marketingLabel !== undefined
34
+ ? { contractMarketingLabel: messages.marketingLabel }
35
+ : {}), ...extensions }));
36
+ }
37
+ function buildInitialConfigure(search) {
38
+ const configure = {
39
+ pax: {
40
+ adult: search.adult ?? 1,
41
+ child: search.child ?? 0,
42
+ infant: search.infant ?? 0,
43
+ },
44
+ };
45
+ if (search.departureSlotId)
46
+ configure.departureSlotId = search.departureSlotId;
47
+ if (search.cabinCategoryId)
48
+ configure.cabinCategoryId = search.cabinCategoryId;
49
+ if (search.cabinNumberId)
50
+ configure.cabinNumberId = search.cabinNumberId;
51
+ if (search.airArrangement)
52
+ configure.airArrangement = search.airArrangement;
53
+ if (search.checkIn && search.checkOut) {
54
+ configure.dateRange = { checkIn: search.checkIn, checkOut: search.checkOut };
55
+ }
56
+ if (search.roomTypeId)
57
+ configure.roomTypeId = search.roomTypeId;
58
+ if (search.ratePlanId)
59
+ configure.ratePlanId = search.ratePlanId;
60
+ if (search.board)
61
+ configure.board = search.board;
62
+ return configure;
63
+ }
64
+ function buildInitialAccommodation(search) {
65
+ if (!search.roomTypeId)
66
+ return undefined;
67
+ return {
68
+ rooms: [
69
+ {
70
+ optionUnitId: search.roomTypeId,
71
+ quantity: 1,
72
+ ...(search.ratePlanId ? { ratePlanId: search.ratePlanId } : {}),
73
+ },
74
+ ],
75
+ travelerAssignments: {},
76
+ };
77
+ }
78
+ function useEntityContent(apiUrl, entityModule, entityId, search) {
79
+ const url = entityContentUrl(apiUrl, entityModule, entityId);
80
+ const { data } = useQuery({
81
+ queryKey: ["public-entity-summary", entityModule, entityId],
82
+ queryFn: async () => {
83
+ if (!url)
84
+ return null;
85
+ const response = await fetch(url, { credentials: "include" });
86
+ if (!response.ok)
87
+ return null;
88
+ const json = (await response.json());
89
+ return json.data ?? null;
90
+ },
91
+ enabled: Boolean(url),
92
+ staleTime: 60_000,
93
+ });
94
+ const content = data?.content ?? null;
95
+ const source = useMemo(() => resolveEntitySource(entityModule, data?.provenance, content), [entityModule, data?.provenance, content]);
96
+ const summary = useMemo(() => resolveEntitySummary(entityModule, content, search), [content, entityModule, search]);
97
+ return { summary, source };
98
+ }
99
+ function entityContentUrl(apiUrl, entityModule, entityId) {
100
+ const encodedId = encodeURIComponent(entityId);
101
+ if (entityModule === "cruises")
102
+ return `${apiUrl}/v1/public/cruises/${encodedId}/content`;
103
+ if (entityModule === "accommodations") {
104
+ return `${apiUrl}/v1/public/accommodations/${encodedId}/content`;
105
+ }
106
+ if (entityModule === "products")
107
+ return `${apiUrl}/v1/public/products/${encodedId}/content`;
108
+ return null;
109
+ }
110
+ function resolveEntitySummary(entityModule, content, search) {
111
+ if (!content)
112
+ return undefined;
113
+ if (entityModule === "products")
114
+ return resolveProductSummary(content, search);
115
+ if (entityModule === "cruises")
116
+ return resolveCruiseSummary(content, search);
117
+ if (entityModule === "accommodations") {
118
+ return resolveAccommodationSummary(content, search);
119
+ }
120
+ return undefined;
121
+ }
122
+ function resolveProductSummary(content, search) {
123
+ const subtitle = [
124
+ content.product.duration_days
125
+ ? `${content.product.duration_days} day${content.product.duration_days === 1 ? "" : "s"}`
126
+ : null,
127
+ content.product.country ?? null,
128
+ ].filter(Boolean);
129
+ const departure = content.departures?.find((item) => item.id === search.departureSlotId);
130
+ return {
131
+ name: content.product.name,
132
+ subtitle: subtitle.join(" · ") || undefined,
133
+ heroImageUrl: content.product.hero_image_url ?? content.media?.[0]?.url ?? undefined,
134
+ vertical: "products",
135
+ whenLabel: departure ? formatDate(departure.starts_at) : undefined,
136
+ locationLabel: content.product.departure_city ?? content.product.country ?? undefined,
137
+ startDate: departure?.starts_at ?? undefined,
138
+ endDate: departure?.ends_at ?? undefined,
139
+ destination: content.product.country ?? content.product.departure_city ?? undefined,
140
+ };
141
+ }
142
+ function resolveCruiseSummary(content, search) {
143
+ const sailing = content.sailings.find((item) => item.id === search.departureSlotId);
144
+ const subtitle = [
145
+ content.cruise.duration_nights
146
+ ? `${content.cruise.duration_nights} night${content.cruise.duration_nights === 1 ? "" : "s"}`
147
+ : null,
148
+ content.ship?.name ?? null,
149
+ ].filter(Boolean);
150
+ const route = sailing
151
+ ? sailing.embarkation_port && sailing.disembarkation_port
152
+ ? `${sailing.embarkation_port} → ${sailing.disembarkation_port}`
153
+ : (sailing.embarkation_port ?? null)
154
+ : null;
155
+ return {
156
+ name: content.cruise.name,
157
+ subtitle: subtitle.join(" · ") || undefined,
158
+ heroImageUrl: content.cruise.hero_image_url ?? undefined,
159
+ vertical: "cruises",
160
+ whenLabel: sailing ? formatDate(sailing.start_date) : undefined,
161
+ locationLabel: route ?? undefined,
162
+ startDate: sailing?.start_date ?? undefined,
163
+ endDate: sailing?.end_date ?? undefined,
164
+ destination: route ?? undefined,
165
+ };
166
+ }
167
+ function resolveAccommodationSummary(content, search) {
168
+ const stars = content.hotel.star_rating ? "★".repeat(Math.floor(content.hotel.star_rating)) : null;
169
+ return {
170
+ name: content.hotel.name,
171
+ subtitle: stars ?? undefined,
172
+ heroImageUrl: content.hotel.hero_image_url ?? undefined,
173
+ vertical: "accommodations",
174
+ whenLabel: search.checkIn && search.checkOut
175
+ ? `${formatDate(search.checkIn)} → ${formatDate(search.checkOut)}`
176
+ : undefined,
177
+ startDate: search.checkIn ?? undefined,
178
+ endDate: search.checkOut ?? undefined,
179
+ destination: content.hotel.city ?? content.hotel.country ?? undefined,
180
+ };
181
+ }
182
+ function resolveEntitySource(entityModule, provenance, content) {
183
+ if (!provenance)
184
+ return undefined;
185
+ const supplierName = entityModule === "products" && content
186
+ ? (content.product.supplier ?? "")
187
+ : "";
188
+ return {
189
+ kind: provenance.source_kind,
190
+ connectionId: provenance.source_connection_id ?? "",
191
+ ref: provenance.source_ref ?? "",
192
+ supplier: { id: "", name: supplierName },
193
+ };
194
+ }
195
+ function formatDate(iso) {
196
+ try {
197
+ return new Date(iso).toLocaleDateString(undefined, {
198
+ weekday: "short",
199
+ day: "numeric",
200
+ month: "short",
201
+ year: "numeric",
202
+ });
203
+ }
204
+ catch {
205
+ return iso;
206
+ }
207
+ }
208
+ function generateDraftId() {
209
+ if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.randomUUID) {
210
+ return `bdrf_${globalThis.crypto.randomUUID().replace(/-/g, "")}`;
211
+ }
212
+ return `bdrf_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
213
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyant-travel/bookings-react",
3
- "version": "0.151.5",
3
+ "version": "0.152.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -116,6 +116,11 @@
116
116
  "import": "./dist/journey/index.js",
117
117
  "default": "./dist/journey/index.js"
118
118
  },
119
+ "./storefront": {
120
+ "types": "./dist/storefront/index.d.ts",
121
+ "import": "./dist/storefront/index.js",
122
+ "default": "./dist/storefront/index.js"
123
+ },
119
124
  "./extras": {
120
125
  "types": "./dist/extras.d.ts",
121
126
  "import": "./dist/extras.js",
@@ -145,26 +150,38 @@
145
150
  "react-dom": "^19.0.0",
146
151
  "react-hook-form": "^7.80.0",
147
152
  "zod": "^4.0.0",
148
- "@voyant-travel/admin": "^0.120.0",
149
- "@voyant-travel/bookings": "^0.151.5",
150
- "@voyant-travel/catalog-react": "^0.149.4",
151
- "@voyant-travel/distribution-react": "^0.141.5",
152
- "@voyant-travel/relationships-react": "^0.151.0",
153
- "@voyant-travel/finance-react": "^0.151.4",
154
- "@voyant-travel/identity-react": "^0.151.4",
155
- "@voyant-travel/legal-react": "^0.151.4",
156
- "@voyant-travel/commerce-react": "^0.33.0",
157
- "@voyant-travel/inventory-react": "^0.33.0",
153
+ "@voyant-travel/accommodations": "^0.112.5",
154
+ "@voyant-travel/admin": "^0.121.0",
155
+ "@voyant-travel/bookings": "^0.152.0",
156
+ "@voyant-travel/catalog": "^0.150.0",
157
+ "@voyant-travel/catalog-react": "^0.150.0",
158
+ "@voyant-travel/distribution-react": "^0.142.0",
159
+ "@voyant-travel/relationships-react": "^0.152.0",
160
+ "@voyant-travel/finance": "^0.152.0",
161
+ "@voyant-travel/finance-react": "^0.152.0",
162
+ "@voyant-travel/identity-react": "^0.152.0",
163
+ "@voyant-travel/legal-react": "^0.152.0",
164
+ "@voyant-travel/commerce-react": "^0.34.0",
165
+ "@voyant-travel/cruises": "^0.151.0",
166
+ "@voyant-travel/inventory-react": "^0.34.0",
167
+ "@voyant-travel/inventory": "^0.8.6",
168
+ "@voyant-travel/storefront-react": "^0.154.0",
158
169
  "@voyant-travel/ui": "^0.108.11",
159
- "@voyant-travel/operations-react": "^0.32.0"
170
+ "@voyant-travel/operations-react": "^0.33.0"
160
171
  },
161
172
  "peerDependenciesMeta": {
162
173
  "@tanstack/react-table": {
163
174
  "optional": true
164
175
  },
176
+ "@voyant-travel/accommodations": {
177
+ "optional": true
178
+ },
165
179
  "@voyant-travel/admin": {
166
180
  "optional": true
167
181
  },
182
+ "@voyant-travel/catalog": {
183
+ "optional": true
184
+ },
168
185
  "@voyant-travel/catalog-react": {
169
186
  "optional": true
170
187
  },
@@ -177,6 +194,9 @@
177
194
  "@voyant-travel/finance-react": {
178
195
  "optional": true
179
196
  },
197
+ "@voyant-travel/finance": {
198
+ "optional": true
199
+ },
180
200
  "@voyant-travel/identity-react": {
181
201
  "optional": true
182
202
  },
@@ -186,9 +206,18 @@
186
206
  "@voyant-travel/commerce-react": {
187
207
  "optional": true
188
208
  },
209
+ "@voyant-travel/cruises": {
210
+ "optional": true
211
+ },
189
212
  "@voyant-travel/inventory-react": {
190
213
  "optional": true
191
214
  },
215
+ "@voyant-travel/inventory": {
216
+ "optional": true
217
+ },
218
+ "@voyant-travel/storefront-react": {
219
+ "optional": true
220
+ },
192
221
  "@voyant-travel/ui": {
193
222
  "optional": true
194
223
  },
@@ -207,7 +236,7 @@
207
236
  "@voyant-travel/catalog-contracts": "^0.109.0",
208
237
  "@voyant-travel/i18n": "^0.110.0",
209
238
  "@voyant-travel/react": "^0.104.1",
210
- "@voyant-travel/types": "^0.107.3"
239
+ "@voyant-travel/types": "^0.108.0"
211
240
  },
212
241
  "devDependencies": {
213
242
  "@tanstack/react-query": "^5.101.2",
@@ -222,20 +251,26 @@
222
251
  "typescript": "^6.0.3",
223
252
  "vitest": "^4.1.9",
224
253
  "zod": "^4.4.3",
225
- "@voyant-travel/admin": "^0.120.0",
226
- "@voyant-travel/bookings": "^0.151.5",
227
- "@voyant-travel/catalog-react": "^0.149.4",
228
- "@voyant-travel/distribution-react": "^0.141.5",
229
- "@voyant-travel/relationships-react": "^0.151.0",
230
- "@voyant-travel/finance-react": "^0.151.4",
231
- "@voyant-travel/identity-react": "^0.151.4",
232
- "@voyant-travel/legal-react": "^0.151.4",
233
- "@voyant-travel/commerce-react": "^0.33.0",
234
- "@voyant-travel/inventory-react": "^0.33.0",
254
+ "@voyant-travel/accommodations": "^0.112.5",
255
+ "@voyant-travel/admin": "^0.121.0",
256
+ "@voyant-travel/bookings": "^0.152.0",
257
+ "@voyant-travel/catalog": "^0.150.0",
258
+ "@voyant-travel/catalog-react": "^0.150.0",
259
+ "@voyant-travel/distribution-react": "^0.142.0",
260
+ "@voyant-travel/relationships-react": "^0.152.0",
261
+ "@voyant-travel/finance": "^0.152.0",
262
+ "@voyant-travel/finance-react": "^0.152.0",
263
+ "@voyant-travel/identity-react": "^0.152.0",
264
+ "@voyant-travel/legal-react": "^0.152.0",
265
+ "@voyant-travel/commerce-react": "^0.34.0",
266
+ "@voyant-travel/cruises": "^0.151.0",
267
+ "@voyant-travel/inventory-react": "^0.34.0",
268
+ "@voyant-travel/inventory": "^0.8.6",
235
269
  "@voyant-travel/react": "^0.104.1",
270
+ "@voyant-travel/storefront-react": "^0.154.0",
236
271
  "@voyant-travel/ui": "^0.108.11",
237
272
  "@voyant-travel/voyant-typescript-config": "^0.1.0",
238
- "@voyant-travel/operations-react": "^0.32.0"
273
+ "@voyant-travel/operations-react": "^0.33.0"
239
274
  },
240
275
  "files": [
241
276
  "dist",