@v-office/website-headless 1.1.1 → 1.2.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/README.md +7 -4
- package/dist/enhance/index.d.mts +1 -1
- package/dist/{index-CPMXjfFH.d.mts → index-Dlf8Hlzc.d.mts} +2 -0
- package/dist/index.d.mts +9 -2
- package/dist/index.mjs +88 -66
- package/instructions/CHANGELOG.md +1 -0
- package/instructions/MIGRATION.md +1 -0
- package/instructions/versions/1.2.0/CHANGELOG.md +24 -0
- package/instructions/versions/1.2.0/MIGRATION.md +11 -0
- package/instructions/versions/1.2.0/release.json +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1521,10 +1521,13 @@ flow.start();
|
|
|
1521
1521
|
|
|
1522
1522
|
- `readCheckoutHandover(search, options?)` (`CheckoutHandoverOptions`: `defaultAdults`,
|
|
1523
1523
|
`allowOption`) → `CheckoutHandover`: `stay` (`Stay` or null: the missing-stay card), `policyId` (a
|
|
1524
|
-
seed, applied only while still offered), `kind` (`"option"` only with `allowOption`),
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1524
|
+
seed, applied only while still offered), `kind` (`"option"` only with `allowOption`), `services`
|
|
1525
|
+
(`?service=<id>:<count>`, repeatable, `<id>` alone is one: extras to add; a seed like `policyId`,
|
|
1526
|
+
added only as far as the quote offers them), `paymentReturn` (`?return=1`). Reads `pets` and the
|
|
1527
|
+
legacy `petsCount`.
|
|
1528
|
+
- `checkoutSearch({ stay, policyId, kind, counts? }, current?)` → the query string for `replaceState`
|
|
1529
|
+
after an edit; with `counts` the chosen extras replace the URL's `service` keys, without them those
|
|
1530
|
+
stay; every other parameter of `current` is kept.
|
|
1528
1531
|
- `BookingKind`: `"booking" | "option"` (a non-binding option, SDK `kind: "OPTION"`).
|
|
1529
1532
|
- `Stay`: `{ start, end, party }`, serializable.
|
|
1530
1533
|
|
package/dist/enhance/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { An as LngLat, Mn as MapPoint, _a as EnhancePart, a as PlaceMarker, ba as GateMarkers, ga as ENHANCE_PARTS, jn as MapBounds, s as ClusterOptions, va as EnhanceParts, wn as SameSpotLayout, ya as GATE_MARKERS } from "../index-
|
|
1
|
+
import { An as LngLat, Mn as MapPoint, _a as EnhancePart, a as PlaceMarker, ba as GateMarkers, ga as ENHANCE_PARTS, jn as MapBounds, s as ClusterOptions, va as EnhanceParts, wn as SameSpotLayout, ya as GATE_MARKERS } from "../index-Dlf8Hlzc.mjs";
|
|
2
2
|
//#region src/enhance/lifecycle.d.ts
|
|
3
3
|
/** Removes everything a binder added. Safe to call more than once. */
|
|
4
4
|
type Dispose = () => void;
|
|
@@ -1646,6 +1646,8 @@ interface SearchParamKeys {
|
|
|
1646
1646
|
readonly policy: "policy";
|
|
1647
1647
|
/** A booking kind handed to the checkout. */
|
|
1648
1648
|
readonly kind: "kind";
|
|
1649
|
+
/** An extra handed to the checkout, `id:count`, repeatable (the website chat puts a stay together). */
|
|
1650
|
+
readonly service: "service";
|
|
1649
1651
|
/** The payment-return marker on the checkout page. */
|
|
1650
1652
|
readonly return: "return";
|
|
1651
1653
|
/** An offer label carried from a result to the rental page, repeatable. */
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as describeOutcome, $i as RentalFlag, $n as fetchRentalFlags, $r as CardSource, $t as GuestBound, A as QueryShape, Ai as SdkMode, An as LngLat, Ar as SdkConfigForInput, At as quickFilterDefs, B as toSdkQuery, Bi as RentalDistance, Bn as resultCardSource, Br as RouteParams, Bt as SEARCH_PARAMS, C as SearchState, Ci as isIsoDay, Cn as SameSpotGroup, Cr as EnvRecord, Ct as ResolvedFilters, D as createSearchStore, Di as Locale, Dn as circleOffsets, Dr as HUB_ENDPOINTS, Dt as facetOptions, E as SearchStoreOptions, Ei as Backend, En as SameSpotOptions, Er as sdkConfigFromEnv, Et as activeFilters, F as externalSearchHref, Fi as WebsiteSdk, Fn as mapPoints, Fr as CardSourceExtras, Ft as writeSelection, G as sortFromSearch, Gi as parseCounts, Gn as PreviewStrategy, Gr as CardBadge, Gt as SearchQuery, H as SORT_URL_VALUE, Hi as distanceFact, Hn as shortReviewerName, Hr as routeHref, Ht as SearchParamAliases, I as handoverQuery, Ii as resolveSdk, In as ResultLinkOptions, Ir as cardSource, It as partyPairs, J as EmptyCause, Ji as BedRun, Jn as DEFAULT_FLAG_FILTERS, Jr as CardImage, Jt as searchHref, K as sortResults, Ki as parseDistances, Kn as descriptionPreview, Kr as CardContext, Kt as WriteSearchOptions, L as queryShape, Li as ADJACENT_BELOW_M, Ln as SearchResultItem, Lr as loadRentalFacts, Lt as readParty, M as SanitizedSearch, Mi as SdkSetup, Mn as MapPoint, Mr as VofficeEndpointTable, Mt as resolveFilters, N as SdkQueryOptions, Ni as SdkSource, Nn as PinLabelOptions, Nr as VofficeEndpoints, Nt as withoutFilter, O as ExternalSearchLink, Oi as STAGES, On as distanceMeters, Or as HubEndpointTable, Ot as measureFilters, P as SdkSearchQuery, Pi as Stage, Pn as hasMapPoints, Pr as sdkConfigFor, Pt as withoutFilters, Q as SearchedParts, Qi as RentalDetail, Qn as assignSlugs, Qr as CardRating, Qt as DEFAULT_GUEST_LIMITS, R as resultsQueryFlagScript, Ri as DistanceKind, Rn as catalogueResultItem, Rr as rentalFactsMap, Rt as FlexibleStay, S as SearchScopeKind, Si as formatIsoDate, Sn as PixelOffset, Sr as createSdk, St as ResolveFiltersOptions, T as SearchStore, Ti as todayIso, Tn as SameSpotMode, Tr as SdkEnvError, Tt as WhenEmpty, U as SortKey, Ui as isAdjacent, Un as splitReviewAuthor, Ur as AlternativePeriod, Ut as SearchParamKeys, V as DEFAULT_SORT_OPTIONS, Vi as WATER_KINDS, Vn as newestReviewsFirst, Vr as RouteTemplate, Vt as SearchContract, W as SortOptionState, Wi as isSpecEcho, Wn as DescriptionPreview, Wr as BadgeRule, Wt as SearchPeriod, X as Relaxation, Xi as DescriptionContent, Xn as LoadRentalCatalogueOptions, Xr as CardModelOptions, Xt as ChildAgeRange, Y as OutcomeInput, Yi as CatalogueRental, Yn as FetchRentalFlagsOptions, Yr as CardLiveField, Yt as writeSearch, Z as SearchOutcome, Zi as RentalAddress, Zn as RentalFlagsResult, Zr as CardPill, Zt as DEFAULT_CHILD_AGE, _ as FAVORITE_LEAVE_MS, _a as EnhancePart, _i as Glyph, _n as DEFAULT_FIT, _r as fetchSearchPage, _t as FilterGroupSpec, a as PlaceMarker, aa as ReviewCriterion, ai as RentalFactsMap, an as Party, ar as AmenityPreviewItem, at as OffersWindowSpec, b as SearchActions, ba as GateMarkers, bi as IsoMonth, bn as frameFor, br as SharedSdk, bt as FilterSpec, c as DEFAULT_CLUSTER, ca as PlainTextOptions, ci as toCardModel, cn as clampParty, cr as AdaptEvent, ct as findCampaignStart, d as ResultsMapController, da as StructuredDocumentOptions, di as Range, dn as stayKeyOf, dr as adaptRental, dt as offersWindowQuery, ea as RentalImage, ei as CardStatus, en as GuestBounds, er as loadRentalCatalogue, et as CampaignChip, f as ResultsMapOptions, fa as TextMarkup, fi as matches, fn as Listener, fr as RawSearchPage, ft as ActiveFilter, g as CampaignOf, ga as ENHANCE_PARTS, gi as GLYPHS, gn as createStore, gr as WalkSummary, gt as FilterEntry, h as createResultsMapController, ha as plainText, hi as parsePriceLabel, hn as WritableStore, hr as WalkOptions, ht as FilterDef, i as MapPlace, ia as RentalRoom, ii as RentalFacts, in as GuestOptions, ir as ALWAYS_EXCLUDED_CATEGORIES, it as OfferWindow, j as ResultHandoverOptions, ji as SdkOptions, jn as MapBounds, jr as VOFFICE_ENDPOINTS, jt as readSelection, k as ExternalSearchSource, ki as SdkConfig, kn as layoutSameSpot, kr as HubEndpoints, kt as minimumSteps, l as MapResultsSource, la as RichBlock, li as CardMatch, ln as guestBounds, lr as AdaptRentalOptions, lt as findOfferWindows, m as ResultsMapSurface, ma as parseTextBlocks, mi as formatPriceLabel, mn as Unsubscribe, mr as SearchPageRequest, mt as FacetOptionsOptions, n as RentalAddressModeError, na as RentalReview, ni as PillOptions, nn as GuestKind, nr as slugify, nt as FindCampaignStartOptions, o as mergePlaces, oa as ReviewSummary, oi as StayPrice, on as QuoteOccupancy, or as AmenityPreviewOptions, ot as campaignChips, p as ResultsMapState, pa as normalizeStructuredDocument, pi as PriceCents, pn as Store, pr as SEARCH_PAGE_SIZE, pt as FacetOption, q as toSdkSort, qi as AmenityGroup, qn as descriptionSummary, qr as CardFact, qt as readSearch, r as rentalAddressLine, ra as RentalReviews, ri as RentalCardModel, rn as GuestLimits, rr as HIDDEN_ROOM_ATTRIBUTES, rt as FindOfferWindowsOptions, s as ClusterOptions, sa as RoomKind, si as StayWindow, sn as agesComplete, sr as amenityPreview, st as campaignGroup, t as RentalAddressMode, ta as RentalPropertyInfo, ti as FactKind, tn as GuestCaps, tr as rankHighlights, tt as CampaignChipsInput, u as MapViewReport, ua as RichInline, ui as CardSignal, un as occupancyOf, ur as RentalContentError, ut as offerWindowHref, v as FavoritesPort, va as EnhanceParts, vi as GlyphList, vn as DefaultFit, vr as walkSearchPages, vt as FilterMeasurement, w as SearchStatus, wi as nightsBetween, wn as SameSpotLayout, wr as SDK_ENV, wt as SdkFilterDefinition, x as SearchScope, xi as addDays, xn as idsInView, xr as shareSdk, xt as ImplicitScope, y as HistoryPort, ya as GATE_MARKERS, yi as IsoDay, yn as FitOptions, yr as loadSharedSdk, yt as FilterSelection, z as sanitizeSearch, zi as RentalCounts, zn as compareUndatedSearchOrder, zr as withRentalFacts, zt as QueryPair } from "./index-
|
|
1
|
+
import { $ as describeOutcome, $i as RentalFlag, $n as fetchRentalFlags, $r as CardSource, $t as GuestBound, A as QueryShape, Ai as SdkMode, An as LngLat, Ar as SdkConfigForInput, At as quickFilterDefs, B as toSdkQuery, Bi as RentalDistance, Bn as resultCardSource, Br as RouteParams, Bt as SEARCH_PARAMS, C as SearchState, Ci as isIsoDay, Cn as SameSpotGroup, Cr as EnvRecord, Ct as ResolvedFilters, D as createSearchStore, Di as Locale, Dn as circleOffsets, Dr as HUB_ENDPOINTS, Dt as facetOptions, E as SearchStoreOptions, Ei as Backend, En as SameSpotOptions, Er as sdkConfigFromEnv, Et as activeFilters, F as externalSearchHref, Fi as WebsiteSdk, Fn as mapPoints, Fr as CardSourceExtras, Ft as writeSelection, G as sortFromSearch, Gi as parseCounts, Gn as PreviewStrategy, Gr as CardBadge, Gt as SearchQuery, H as SORT_URL_VALUE, Hi as distanceFact, Hn as shortReviewerName, Hr as routeHref, Ht as SearchParamAliases, I as handoverQuery, Ii as resolveSdk, In as ResultLinkOptions, Ir as cardSource, It as partyPairs, J as EmptyCause, Ji as BedRun, Jn as DEFAULT_FLAG_FILTERS, Jr as CardImage, Jt as searchHref, K as sortResults, Ki as parseDistances, Kn as descriptionPreview, Kr as CardContext, Kt as WriteSearchOptions, L as queryShape, Li as ADJACENT_BELOW_M, Ln as SearchResultItem, Lr as loadRentalFacts, Lt as readParty, M as SanitizedSearch, Mi as SdkSetup, Mn as MapPoint, Mr as VofficeEndpointTable, Mt as resolveFilters, N as SdkQueryOptions, Ni as SdkSource, Nn as PinLabelOptions, Nr as VofficeEndpoints, Nt as withoutFilter, O as ExternalSearchLink, Oi as STAGES, On as distanceMeters, Or as HubEndpointTable, Ot as measureFilters, P as SdkSearchQuery, Pi as Stage, Pn as hasMapPoints, Pr as sdkConfigFor, Pt as withoutFilters, Q as SearchedParts, Qi as RentalDetail, Qn as assignSlugs, Qr as CardRating, Qt as DEFAULT_GUEST_LIMITS, R as resultsQueryFlagScript, Ri as DistanceKind, Rn as catalogueResultItem, Rr as rentalFactsMap, Rt as FlexibleStay, S as SearchScopeKind, Si as formatIsoDate, Sn as PixelOffset, Sr as createSdk, St as ResolveFiltersOptions, T as SearchStore, Ti as todayIso, Tn as SameSpotMode, Tr as SdkEnvError, Tt as WhenEmpty, U as SortKey, Ui as isAdjacent, Un as splitReviewAuthor, Ur as AlternativePeriod, Ut as SearchParamKeys, V as DEFAULT_SORT_OPTIONS, Vi as WATER_KINDS, Vn as newestReviewsFirst, Vr as RouteTemplate, Vt as SearchContract, W as SortOptionState, Wi as isSpecEcho, Wn as DescriptionPreview, Wr as BadgeRule, Wt as SearchPeriod, X as Relaxation, Xi as DescriptionContent, Xn as LoadRentalCatalogueOptions, Xr as CardModelOptions, Xt as ChildAgeRange, Y as OutcomeInput, Yi as CatalogueRental, Yn as FetchRentalFlagsOptions, Yr as CardLiveField, Yt as writeSearch, Z as SearchOutcome, Zi as RentalAddress, Zn as RentalFlagsResult, Zr as CardPill, Zt as DEFAULT_CHILD_AGE, _ as FAVORITE_LEAVE_MS, _a as EnhancePart, _i as Glyph, _n as DEFAULT_FIT, _r as fetchSearchPage, _t as FilterGroupSpec, a as PlaceMarker, aa as ReviewCriterion, ai as RentalFactsMap, an as Party, ar as AmenityPreviewItem, at as OffersWindowSpec, b as SearchActions, ba as GateMarkers, bi as IsoMonth, bn as frameFor, br as SharedSdk, bt as FilterSpec, c as DEFAULT_CLUSTER, ca as PlainTextOptions, ci as toCardModel, cn as clampParty, cr as AdaptEvent, ct as findCampaignStart, d as ResultsMapController, da as StructuredDocumentOptions, di as Range, dn as stayKeyOf, dr as adaptRental, dt as offersWindowQuery, ea as RentalImage, ei as CardStatus, en as GuestBounds, er as loadRentalCatalogue, et as CampaignChip, f as ResultsMapOptions, fa as TextMarkup, fi as matches, fn as Listener, fr as RawSearchPage, ft as ActiveFilter, g as CampaignOf, ga as ENHANCE_PARTS, gi as GLYPHS, gn as createStore, gr as WalkSummary, gt as FilterEntry, h as createResultsMapController, ha as plainText, hi as parsePriceLabel, hn as WritableStore, hr as WalkOptions, ht as FilterDef, i as MapPlace, ia as RentalRoom, ii as RentalFacts, in as GuestOptions, ir as ALWAYS_EXCLUDED_CATEGORIES, it as OfferWindow, j as ResultHandoverOptions, ji as SdkOptions, jn as MapBounds, jr as VOFFICE_ENDPOINTS, jt as readSelection, k as ExternalSearchSource, ki as SdkConfig, kn as layoutSameSpot, kr as HubEndpoints, kt as minimumSteps, l as MapResultsSource, la as RichBlock, li as CardMatch, ln as guestBounds, lr as AdaptRentalOptions, lt as findOfferWindows, m as ResultsMapSurface, ma as parseTextBlocks, mi as formatPriceLabel, mn as Unsubscribe, mr as SearchPageRequest, mt as FacetOptionsOptions, n as RentalAddressModeError, na as RentalReview, ni as PillOptions, nn as GuestKind, nr as slugify, nt as FindCampaignStartOptions, o as mergePlaces, oa as ReviewSummary, oi as StayPrice, on as QuoteOccupancy, or as AmenityPreviewOptions, ot as campaignChips, p as ResultsMapState, pa as normalizeStructuredDocument, pi as PriceCents, pn as Store, pr as SEARCH_PAGE_SIZE, pt as FacetOption, q as toSdkSort, qi as AmenityGroup, qn as descriptionSummary, qr as CardFact, qt as readSearch, r as rentalAddressLine, ra as RentalReviews, ri as RentalCardModel, rn as GuestLimits, rr as HIDDEN_ROOM_ATTRIBUTES, rt as FindOfferWindowsOptions, s as ClusterOptions, sa as RoomKind, si as StayWindow, sn as agesComplete, sr as amenityPreview, st as campaignGroup, t as RentalAddressMode, ta as RentalPropertyInfo, ti as FactKind, tn as GuestCaps, tr as rankHighlights, tt as CampaignChipsInput, u as MapViewReport, ua as RichInline, ui as CardSignal, un as occupancyOf, ur as RentalContentError, ut as offerWindowHref, v as FavoritesPort, va as EnhanceParts, vi as GlyphList, vn as DefaultFit, vr as walkSearchPages, vt as FilterMeasurement, w as SearchStatus, wi as nightsBetween, wn as SameSpotLayout, wr as SDK_ENV, wt as SdkFilterDefinition, x as SearchScope, xi as addDays, xn as idsInView, xr as shareSdk, xt as ImplicitScope, y as HistoryPort, ya as GATE_MARKERS, yi as IsoDay, yn as FitOptions, yr as loadSharedSdk, yt as FilterSelection, z as sanitizeSearch, zi as RentalCounts, zn as compareUndatedSearchOrder, zr as withRentalFacts, zt as QueryPair } from "./index-Dlf8Hlzc.mjs";
|
|
2
2
|
import { BookingPaymentOption, BookingPaymentScheduleKind, ContactSubmitInput, GuestQuote, GuestQuoteResult, SubmittableBookingPaymentOption } from "@v-office/website-sdk";
|
|
3
3
|
import { BackendKind } from "@v-office/website-sdk/capabilities/search";
|
|
4
4
|
//#region src/map/constants.d.ts
|
|
@@ -1666,6 +1666,10 @@ interface CheckoutHandover {
|
|
|
1666
1666
|
policyId: string | null;
|
|
1667
1667
|
/** `?kind=option`, honoured only with `allowOption`; otherwise "booking". */
|
|
1668
1668
|
kind: BookingKind;
|
|
1669
|
+
/** `?service=<id>:<count>` (repeatable; `<id>` alone is one): the extras to add, by service id. A
|
|
1670
|
+
* seed like `policyId`: the flow adds only what the quote offers, up to the count the PMS allows,
|
|
1671
|
+
* and keeps what it refuses out. Empty without any. */
|
|
1672
|
+
services?: Readonly<Record<string, number>> | undefined;
|
|
1669
1673
|
/** `?return=1`: a payment provider sent the guest back to this page (sites that return to the
|
|
1670
1674
|
* checkout itself; the package's own return page is a separate route). */
|
|
1671
1675
|
paymentReturn: boolean;
|
|
@@ -1682,11 +1686,14 @@ interface CheckoutHandoverOptions {
|
|
|
1682
1686
|
type ReadCheckoutHandover = (search: string, options?: CheckoutHandoverOptions) => CheckoutHandover;
|
|
1683
1687
|
/** The query string (no leading "?") for `history.replaceState` after an edit: the stay (pets as
|
|
1684
1688
|
* `pets`), an explicit policy only (never today's pre-selection, which would pin it), `kind=option`
|
|
1685
|
-
* for an option
|
|
1689
|
+
* for an option, and with `counts` the chosen extras (`service=<id>:<count>`; without `counts` the
|
|
1690
|
+
* URL's `service` keys stay as they are). Every other parameter in `current` (tracking, site keys)
|
|
1691
|
+
* is preserved after them. */
|
|
1686
1692
|
type CheckoutSearch = (input: {
|
|
1687
1693
|
stay: Stay | null;
|
|
1688
1694
|
policyId: string | null;
|
|
1689
1695
|
kind: BookingKind;
|
|
1696
|
+
counts?: Readonly<Record<string, number>> | undefined;
|
|
1690
1697
|
}, current?: string) => string;
|
|
1691
1698
|
/** See {@link ReadCheckoutHandover}. */
|
|
1692
1699
|
export declare const readCheckoutHandover: ReadCheckoutHandover;
|
package/dist/index.mjs
CHANGED
|
@@ -1469,6 +1469,7 @@ const SEARCH_PARAMS = {
|
|
|
1469
1469
|
campaign: "campaign",
|
|
1470
1470
|
policy: "policy",
|
|
1471
1471
|
kind: "kind",
|
|
1472
|
+
service: "service",
|
|
1472
1473
|
return: "return",
|
|
1473
1474
|
offer: "offer"
|
|
1474
1475
|
};
|
|
@@ -7136,6 +7137,83 @@ const payWithOption = (sdk, option) => sdk.live.booking.submitPaymentOption(opti
|
|
|
7136
7137
|
/** The window CustomEvent name. Renaming it is a major. */
|
|
7137
7138
|
const CHECKOUT_EVENT = "voffice:checkout";
|
|
7138
7139
|
//#endregion
|
|
7140
|
+
//#region src/checkout/handover.ts
|
|
7141
|
+
const DEFAULT_ADULTS$1 = 2;
|
|
7142
|
+
/** The most distinct extras a URL hands over: more than any quote offers, a bound for junk links. */
|
|
7143
|
+
const MAX_SERVICES = 50;
|
|
7144
|
+
const MAX_SERVICE_ID = 100;
|
|
7145
|
+
/** `id:count` or `id` (one) per `service` key; unreadable entries are skipped, a repeated id adds up
|
|
7146
|
+
* to the cap. */
|
|
7147
|
+
function readServices(params) {
|
|
7148
|
+
const services = /* @__PURE__ */ new Map();
|
|
7149
|
+
for (const raw of params.getAll(SEARCH_PARAMS.service)) {
|
|
7150
|
+
const at = raw.lastIndexOf(":");
|
|
7151
|
+
const id = (at === -1 ? raw : raw.slice(0, at)).trim();
|
|
7152
|
+
const count = at === -1 ? 1 : Number(raw.slice(at + 1));
|
|
7153
|
+
if (!id || id.length > MAX_SERVICE_ID || !Number.isInteger(count) || count < 1) continue;
|
|
7154
|
+
if (!services.has(id) && services.size >= MAX_SERVICES) continue;
|
|
7155
|
+
services.set(id, Math.min(99, (services.get(id) ?? 0) + count));
|
|
7156
|
+
}
|
|
7157
|
+
return Object.fromEntries(services);
|
|
7158
|
+
}
|
|
7159
|
+
/** The keys the write-back owns; everything else in the URL is carried through untouched. */
|
|
7160
|
+
const OWNED_KEYS = /* @__PURE__ */ new Set([
|
|
7161
|
+
SEARCH_PARAMS.start,
|
|
7162
|
+
SEARCH_PARAMS.end,
|
|
7163
|
+
SEARCH_PARAMS.adults,
|
|
7164
|
+
SEARCH_PARAMS.children,
|
|
7165
|
+
SEARCH_PARAMS.childrenAges,
|
|
7166
|
+
SEARCH_PARAMS.babies,
|
|
7167
|
+
SEARCH_PARAMS.pets,
|
|
7168
|
+
SEARCH_PARAMS.petsCount,
|
|
7169
|
+
SEARCH_PARAMS.policy,
|
|
7170
|
+
SEARCH_PARAMS.kind
|
|
7171
|
+
]);
|
|
7172
|
+
function readHandover(search, options) {
|
|
7173
|
+
const params = new URLSearchParams(search);
|
|
7174
|
+
const start = params.get(SEARCH_PARAMS.start);
|
|
7175
|
+
const end = params.get(SEARCH_PARAMS.end);
|
|
7176
|
+
const dated = isIsoDay(start) && isIsoDay(end) && nightsBetween(start, end) > 0;
|
|
7177
|
+
const party = readParty(params);
|
|
7178
|
+
const adults = party && party.adults > 0 ? party.adults : options.defaultAdults ?? DEFAULT_ADULTS$1;
|
|
7179
|
+
const withAdults = {
|
|
7180
|
+
...party ?? {
|
|
7181
|
+
children: 0,
|
|
7182
|
+
childrenAges: [],
|
|
7183
|
+
babies: 0,
|
|
7184
|
+
pets: 0
|
|
7185
|
+
},
|
|
7186
|
+
adults
|
|
7187
|
+
};
|
|
7188
|
+
return {
|
|
7189
|
+
stay: dated ? {
|
|
7190
|
+
start,
|
|
7191
|
+
end,
|
|
7192
|
+
party: withAdults
|
|
7193
|
+
} : null,
|
|
7194
|
+
policyId: params.get(SEARCH_PARAMS.policy) || null,
|
|
7195
|
+
kind: options.allowOption === true && params.get(SEARCH_PARAMS.kind) === "option" ? "option" : "booking",
|
|
7196
|
+
services: readServices(params),
|
|
7197
|
+
paymentReturn: params.get(SEARCH_PARAMS.return) === "1"
|
|
7198
|
+
};
|
|
7199
|
+
}
|
|
7200
|
+
function writeHandover({ stay, policyId, kind, counts }, current) {
|
|
7201
|
+
const pairs = [];
|
|
7202
|
+
if (stay) pairs.push([SEARCH_PARAMS.start, stay.start], [SEARCH_PARAMS.end, stay.end], ...partyPairs(stay.party, SEARCH_PARAMS.pets));
|
|
7203
|
+
if (policyId) pairs.push([SEARCH_PARAMS.policy, policyId]);
|
|
7204
|
+
if (kind === "option") pairs.push([SEARCH_PARAMS.kind, "option"]);
|
|
7205
|
+
if (counts) {
|
|
7206
|
+
for (const [id, count] of Object.entries(counts)) if (count > 0) pairs.push([SEARCH_PARAMS.service, `${id}:${count}`]);
|
|
7207
|
+
}
|
|
7208
|
+
const owned = (key) => OWNED_KEYS.has(key) || counts !== void 0 && key === SEARCH_PARAMS.service;
|
|
7209
|
+
const carried = [...new URLSearchParams(current)].filter(([key]) => !owned(key));
|
|
7210
|
+
return new URLSearchParams([...pairs, ...carried].map(([key, value]) => [key, value])).toString();
|
|
7211
|
+
}
|
|
7212
|
+
/** See {@link ReadCheckoutHandover}. */
|
|
7213
|
+
const readCheckoutHandover = (search, options) => readHandover(search, options ?? {});
|
|
7214
|
+
/** See {@link CheckoutSearch}. */
|
|
7215
|
+
const checkoutSearch = (input, current) => writeHandover(input, current ?? "");
|
|
7216
|
+
//#endregion
|
|
7139
7217
|
//#region src/checkout/insurance.ts
|
|
7140
7218
|
/** Nothing opened, nothing confirmed. */
|
|
7141
7219
|
const NO_INSURANCE_DOCS = {
|
|
@@ -7202,11 +7280,11 @@ async function run(sdk, input) {
|
|
|
7202
7280
|
};
|
|
7203
7281
|
const cleared = await clearQuoteServices(sdk, result.live);
|
|
7204
7282
|
if (!cleared.ok) throw new Error("clearAdditionalServices failed: the extras baseline is unknown");
|
|
7205
|
-
const
|
|
7206
|
-
const
|
|
7207
|
-
const reapply = insuranceIdToReapply(adaptGuestQuote(
|
|
7208
|
-
const insured = reapply === void 0 ? null : await selectQuoteInsurance(sdk,
|
|
7209
|
-
const quote = insured?.ok ? insured.quote :
|
|
7283
|
+
const policy = await applyPolicy(sdk, cleared.quote, input);
|
|
7284
|
+
const stepped = await stepServices(sdk, policy.quote, adaptGuestQuote(policy.quote), input.counts);
|
|
7285
|
+
const reapply = insuranceIdToReapply(adaptGuestQuote(stepped.quote), input.insurance);
|
|
7286
|
+
const insured = reapply === void 0 ? null : await selectQuoteInsurance(sdk, stepped.quote, reapply);
|
|
7287
|
+
const quote = insured?.ok ? insured.quote : stepped.quote;
|
|
7210
7288
|
return {
|
|
7211
7289
|
kind: "priced",
|
|
7212
7290
|
quote,
|
|
@@ -7266,8 +7344,7 @@ const requote = (sdk, input) => run(sdk, input);
|
|
|
7266
7344
|
//#region src/checkout/flow.ts
|
|
7267
7345
|
/** Later edits coalesce (a burst of stepper clicks prices once); the first quote runs at once. */
|
|
7268
7346
|
const REQUOTE_DELAY_MS = 350;
|
|
7269
|
-
const DEFAULT_ADULTS
|
|
7270
|
-
const DEFAULT_MAX_PER_BOOKING = 99;
|
|
7347
|
+
const DEFAULT_ADULTS = 2;
|
|
7271
7348
|
const chosenInsurance = (view) => selectedInsuranceOption(view?.insurance);
|
|
7272
7349
|
/** The handed-over stay under the same party rules as the quote: clamped to the bounds and every age
|
|
7273
7350
|
* outside the band unchosen (the child-ages blocker then asks for it). */
|
|
@@ -7281,7 +7358,7 @@ function handedOverStay(options, how) {
|
|
|
7281
7358
|
};
|
|
7282
7359
|
}
|
|
7283
7360
|
function initialRaw(options, how) {
|
|
7284
|
-
const { policyId } = options.handover;
|
|
7361
|
+
const { policyId, services } = options.handover;
|
|
7285
7362
|
const stay = handedOverStay(options, how);
|
|
7286
7363
|
return {
|
|
7287
7364
|
phase: stay ? { kind: "loading" } : { kind: "missing-stay" },
|
|
@@ -7289,7 +7366,7 @@ function initialRaw(options, how) {
|
|
|
7289
7366
|
live: null,
|
|
7290
7367
|
view: null,
|
|
7291
7368
|
quoted: null,
|
|
7292
|
-
counts: {},
|
|
7369
|
+
counts: services ?? {},
|
|
7293
7370
|
issue: null,
|
|
7294
7371
|
chosenPolicyId: policyId,
|
|
7295
7372
|
voucher: {
|
|
@@ -7311,7 +7388,7 @@ function initialRaw(options, how) {
|
|
|
7311
7388
|
function derivationOf(options) {
|
|
7312
7389
|
const { guests, caps } = options;
|
|
7313
7390
|
const emptyParty = {
|
|
7314
|
-
adults: guests?.defaultAdults ?? DEFAULT_ADULTS
|
|
7391
|
+
adults: guests?.defaultAdults ?? DEFAULT_ADULTS,
|
|
7315
7392
|
children: 0,
|
|
7316
7393
|
childrenAges: [],
|
|
7317
7394
|
babies: 0,
|
|
@@ -7341,7 +7418,7 @@ function derivationOf(options) {
|
|
|
7341
7418
|
function servicesOf(raw, busy) {
|
|
7342
7419
|
return (raw.view?.services ?? []).map((service) => {
|
|
7343
7420
|
const count = raw.counts[service.id] ?? 0;
|
|
7344
|
-
const max = service.maxPerBooking ??
|
|
7421
|
+
const max = service.maxPerBooking ?? 99;
|
|
7345
7422
|
return {
|
|
7346
7423
|
...service,
|
|
7347
7424
|
count,
|
|
@@ -8088,61 +8165,6 @@ function guestForm(options) {
|
|
|
8088
8165
|
/** See {@link CreateGuestForm}. */
|
|
8089
8166
|
const createGuestForm = (options) => guestForm(options);
|
|
8090
8167
|
//#endregion
|
|
8091
|
-
//#region src/checkout/handover.ts
|
|
8092
|
-
const DEFAULT_ADULTS = 2;
|
|
8093
|
-
/** The keys the write-back owns; everything else in the URL is carried through untouched. */
|
|
8094
|
-
const OWNED_KEYS = /* @__PURE__ */ new Set([
|
|
8095
|
-
SEARCH_PARAMS.start,
|
|
8096
|
-
SEARCH_PARAMS.end,
|
|
8097
|
-
SEARCH_PARAMS.adults,
|
|
8098
|
-
SEARCH_PARAMS.children,
|
|
8099
|
-
SEARCH_PARAMS.childrenAges,
|
|
8100
|
-
SEARCH_PARAMS.babies,
|
|
8101
|
-
SEARCH_PARAMS.pets,
|
|
8102
|
-
SEARCH_PARAMS.petsCount,
|
|
8103
|
-
SEARCH_PARAMS.policy,
|
|
8104
|
-
SEARCH_PARAMS.kind
|
|
8105
|
-
]);
|
|
8106
|
-
function readHandover(search, options) {
|
|
8107
|
-
const params = new URLSearchParams(search);
|
|
8108
|
-
const start = params.get(SEARCH_PARAMS.start);
|
|
8109
|
-
const end = params.get(SEARCH_PARAMS.end);
|
|
8110
|
-
const dated = isIsoDay(start) && isIsoDay(end) && nightsBetween(start, end) > 0;
|
|
8111
|
-
const party = readParty(params);
|
|
8112
|
-
const adults = party && party.adults > 0 ? party.adults : options.defaultAdults ?? DEFAULT_ADULTS;
|
|
8113
|
-
const withAdults = {
|
|
8114
|
-
...party ?? {
|
|
8115
|
-
children: 0,
|
|
8116
|
-
childrenAges: [],
|
|
8117
|
-
babies: 0,
|
|
8118
|
-
pets: 0
|
|
8119
|
-
},
|
|
8120
|
-
adults
|
|
8121
|
-
};
|
|
8122
|
-
return {
|
|
8123
|
-
stay: dated ? {
|
|
8124
|
-
start,
|
|
8125
|
-
end,
|
|
8126
|
-
party: withAdults
|
|
8127
|
-
} : null,
|
|
8128
|
-
policyId: params.get(SEARCH_PARAMS.policy) || null,
|
|
8129
|
-
kind: options.allowOption === true && params.get(SEARCH_PARAMS.kind) === "option" ? "option" : "booking",
|
|
8130
|
-
paymentReturn: params.get(SEARCH_PARAMS.return) === "1"
|
|
8131
|
-
};
|
|
8132
|
-
}
|
|
8133
|
-
function writeHandover({ stay, policyId, kind }, current) {
|
|
8134
|
-
const pairs = [];
|
|
8135
|
-
if (stay) pairs.push([SEARCH_PARAMS.start, stay.start], [SEARCH_PARAMS.end, stay.end], ...partyPairs(stay.party, SEARCH_PARAMS.pets));
|
|
8136
|
-
if (policyId) pairs.push([SEARCH_PARAMS.policy, policyId]);
|
|
8137
|
-
if (kind === "option") pairs.push([SEARCH_PARAMS.kind, "option"]);
|
|
8138
|
-
const carried = [...new URLSearchParams(current)].filter(([key]) => !OWNED_KEYS.has(key));
|
|
8139
|
-
return new URLSearchParams([...pairs, ...carried].map(([key, value]) => [key, value])).toString();
|
|
8140
|
-
}
|
|
8141
|
-
/** See {@link ReadCheckoutHandover}. */
|
|
8142
|
-
const readCheckoutHandover = (search, options) => readHandover(search, options ?? {});
|
|
8143
|
-
/** See {@link CheckoutSearch}. */
|
|
8144
|
-
const checkoutSearch = (input, current) => writeHandover(input, current ?? "");
|
|
8145
|
-
//#endregion
|
|
8146
8168
|
//#region src/checkout/structure.ts
|
|
8147
8169
|
/** The legal `data-part` vocabulary. Imported components carry it; a custom checkout must keep it.
|
|
8148
8170
|
* Style-only hooks are not here (components `BOOKING_PARTS`). Renaming a part is a major. */
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Release notes of `@v-office/website-headless`, newest first. Each version has its own directory.
|
|
6
6
|
|
|
7
|
+
- `versions/1.2.0/CHANGELOG.md`: release notes for 1.2.0
|
|
7
8
|
- `versions/1.1.1/CHANGELOG.md`: release notes for 1.1.1
|
|
8
9
|
- `versions/1.1.0/CHANGELOG.md`: release notes for 1.1.0
|
|
9
10
|
- `versions/1.0.0/CHANGELOG.md`: release notes for 1.0.0
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Migration guides of `@v-office/website-headless`, newest first. Apply them in order when skipping versions.
|
|
6
6
|
|
|
7
|
+
- `versions/1.2.0/MIGRATION.md`: Migration: 1.1.1 to 1.2.0
|
|
7
8
|
- `versions/1.1.1/MIGRATION.md`: Migration: 1.1.0 to 1.1.1
|
|
8
9
|
- `versions/1.1.0/MIGRATION.md`: Migration: 1.0.0 to 1.1.0
|
|
9
10
|
- `versions/1.0.0/MIGRATION.md`: Migration: 0.2.0 to 1.0.0
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog: 1.2.0
|
|
2
|
+
|
|
3
|
+
The booking page takes the extras a link hands over. AI Studio's website chat puts a stay together
|
|
4
|
+
with extras (bed linen, a cot, a second dog, …) and links to the booking page with them chosen.
|
|
5
|
+
|
|
6
|
+
## Added
|
|
7
|
+
|
|
8
|
+
- `readCheckoutHandover` reads `?service=<id>:<count>` (repeatable; `<id>` alone is one) into
|
|
9
|
+
`services`. The checkout flow adds them with its first quote, like the handed-over rate: only extras
|
|
10
|
+
the quote offers, only as many as the PMS allows. What it refuses stays out; the price on the
|
|
11
|
+
booking page is always the PMS's for what is selected.
|
|
12
|
+
- `checkoutSearch` takes `counts`, the chosen extras, and writes them as `service` keys; without
|
|
13
|
+
`counts` the URL's `service` keys stay as they are.
|
|
14
|
+
|
|
15
|
+
## Changed
|
|
16
|
+
|
|
17
|
+
- Nothing for existing links: a URL without `service` keys works as before.
|
|
18
|
+
|
|
19
|
+
## Fixed
|
|
20
|
+
|
|
21
|
+
- The checkout keeps the rate the guest chose when the extras already chosen exceed that rate's
|
|
22
|
+
limits. Each rate has its own extras and limits, and the checkout used to add the extras first,
|
|
23
|
+
so the PMS refused the rate and the price fell back to the standard rate. It now applies the rate
|
|
24
|
+
first and adds the extras within that rate's limits; what it refuses stays out.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Migration: 1.1.1 to 1.2.0
|
|
2
|
+
|
|
3
|
+
No changes required. A site with the platform's `Booking` gets the extras through
|
|
4
|
+
`@v-office/website-components` 1.1.0, which writes the chosen extras back into the URL. A site
|
|
5
|
+
with its own checkout passes `counts` (the chosen extras by id) to `checkoutSearch` to do the same.
|
|
6
|
+
|
|
7
|
+
## 1. Upgrade
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add --save-exact @v-office/website-headless@1.2.0
|
|
11
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@v-office/website-headless",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Framework-free behaviour layer for v-office websites, never UI: stores, pure rules and SDK runners for the search bar, results, map, showcase, quote, checkout and contact form, the rental and card models, and progressive-enhancement engines for server-rendered markup (./enhance)",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|