@qite/tide-components 1.0.3 → 1.0.4
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/build/build-cjs/index.js +101 -103
- package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +16 -2
- package/build/build-cjs/src/search-results/utils/traject-utils.d.ts +4 -7
- package/build/build-esm/index.js +101 -103
- package/build/build-esm/src/search-results/store/search-results-slice.d.ts +16 -2
- package/build/build-esm/src/search-results/utils/traject-utils.d.ts +4 -7
- package/package.json +2 -2
package/build/build-cjs/index.js
CHANGED
|
@@ -27370,7 +27370,7 @@ const initialState$1 = {
|
|
|
27370
27370
|
currentStep: 0,
|
|
27371
27371
|
bookingNumber: undefined,
|
|
27372
27372
|
trajectNodeAvailability: {},
|
|
27373
|
-
|
|
27373
|
+
trajectFlightAvailability: {}
|
|
27374
27374
|
};
|
|
27375
27375
|
const searchResultsSlice = toolkit.createSlice({
|
|
27376
27376
|
name: 'searchResults',
|
|
@@ -27592,16 +27592,38 @@ const searchResultsSlice = toolkit.createSlice({
|
|
|
27592
27592
|
const guids = new Set(action.payload);
|
|
27593
27593
|
state.editablePackagingEntry.lines = (state.editablePackagingEntry.lines ?? []).filter((x) => !guids.has(x.guid));
|
|
27594
27594
|
},
|
|
27595
|
-
|
|
27596
|
-
|
|
27595
|
+
setTrajectFlightLoading(state, action) {
|
|
27596
|
+
const lineGuid = action.payload;
|
|
27597
|
+
state.trajectFlightAvailability[lineGuid] = {
|
|
27598
|
+
lineGuid,
|
|
27599
|
+
status: 'loading',
|
|
27600
|
+
results: state.trajectFlightAvailability[lineGuid]?.results ?? [],
|
|
27601
|
+
selectedGuid: state.trajectFlightAvailability[lineGuid]?.selectedGuid ?? null
|
|
27602
|
+
};
|
|
27603
|
+
},
|
|
27604
|
+
setTrajectFlightAvailability(state, action) {
|
|
27605
|
+
const { lineGuid, results, selectedGuid } = action.payload;
|
|
27606
|
+
state.trajectFlightAvailability[lineGuid] = {
|
|
27607
|
+
lineGuid,
|
|
27608
|
+
status: selectedGuid ? 'resolved' : 'unavailable',
|
|
27609
|
+
results,
|
|
27610
|
+
selectedGuid
|
|
27611
|
+
};
|
|
27612
|
+
},
|
|
27613
|
+
setTrajectFlightSelection(state, action) {
|
|
27614
|
+
const flight = state.trajectFlightAvailability[action.payload.lineGuid];
|
|
27615
|
+
if (!flight)
|
|
27616
|
+
return;
|
|
27617
|
+
flight.selectedGuid = action.payload.guid;
|
|
27618
|
+
flight.status = 'resolved';
|
|
27597
27619
|
},
|
|
27598
27620
|
resetTrajectAvailability(state) {
|
|
27599
27621
|
state.trajectNodeAvailability = {};
|
|
27600
|
-
state.
|
|
27622
|
+
state.trajectFlightAvailability = {};
|
|
27601
27623
|
}
|
|
27602
27624
|
}
|
|
27603
27625
|
});
|
|
27604
|
-
const { setResults, setFilteredResults, setSelectedSearchResult, setPackagingAccoResults, setFilteredPackagingAccoResults, setFilteredPackagingFlightResults, setPackagingAccoSearchDetails, setSelectedPackagingAccoResult, setPackagingFlightResults, setSelectedPackagingFlight, setSelectedFlight, setSelectedFlightDetails, setBookingPackageDetails, selectFlight, setIsLoading, setFlightsLoading, setInitialFilters, setFilters, resetFilters, setInitialFlightFilters, setFlightFilters, resetFlightFilters, setSortType, setFlightSortType, setActiveTab, setCurrentPage, resetSearchState, setFlyInIsOpen, setEditablePackagingEntry, setTransactionId, setFlyInType, setPriceDetails, setItinerary, setSelectedOutwardKey, setSelectedReturnKey, resetFlightSelection, setExcursionSearchParams, setSelectedExcursionSearchResult, confirmExcursionForDay, removeConfirmedExcursionForDay, clearConfirmedExcursionsForDay, setBookPackagingEntry, setCurrentStep, setBookingNumber, setTrajectNodeLoading, setTrajectNodeAvailability, setTrajectNodeSelection,
|
|
27626
|
+
const { setResults, setFilteredResults, setSelectedSearchResult, setPackagingAccoResults, setFilteredPackagingAccoResults, setFilteredPackagingFlightResults, setPackagingAccoSearchDetails, setSelectedPackagingAccoResult, setPackagingFlightResults, setSelectedPackagingFlight, setSelectedFlight, setSelectedFlightDetails, setBookingPackageDetails, selectFlight, setIsLoading, setFlightsLoading, setInitialFilters, setFilters, resetFilters, setInitialFlightFilters, setFlightFilters, resetFlightFilters, setSortType, setFlightSortType, setActiveTab, setCurrentPage, resetSearchState, setFlyInIsOpen, setEditablePackagingEntry, setTransactionId, setFlyInType, setPriceDetails, setItinerary, setSelectedOutwardKey, setSelectedReturnKey, resetFlightSelection, setExcursionSearchParams, setSelectedExcursionSearchResult, confirmExcursionForDay, removeConfirmedExcursionForDay, clearConfirmedExcursionsForDay, setBookPackagingEntry, setCurrentStep, setBookingNumber, setTrajectNodeLoading, setTrajectNodeAvailability, setTrajectNodeSelection, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
|
|
27605
27627
|
var searchResultsReducer = searchResultsSlice.reducer;
|
|
27606
27628
|
|
|
27607
27629
|
const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
|
|
@@ -33072,8 +33094,26 @@ const mapFlightSegmentsToFlightLines = (segments) => segments.map((segment) => (
|
|
|
33072
33094
|
arrivalAirportDescription: segment.arrivalAirportName,
|
|
33073
33095
|
durationInTicks: segment.durationInTicks
|
|
33074
33096
|
}));
|
|
33075
|
-
const
|
|
33076
|
-
|
|
33097
|
+
const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
33098
|
+
transactionId: context.transactionId,
|
|
33099
|
+
officeId: context.officeId,
|
|
33100
|
+
catalogueId: context.catalogueId,
|
|
33101
|
+
agentId: context.agentId ?? null,
|
|
33102
|
+
language: context.language,
|
|
33103
|
+
departureAirportCode: node.departureAirportCode ?? '',
|
|
33104
|
+
arrivalAirportCode: node.arrivalAirportCode ?? '',
|
|
33105
|
+
returnAirportCode: null,
|
|
33106
|
+
luggageIncluded: null,
|
|
33107
|
+
maxStops: null,
|
|
33108
|
+
travelClass: null,
|
|
33109
|
+
vendorConfigurationId: node.externalVendorId ?? null,
|
|
33110
|
+
pax,
|
|
33111
|
+
outward: { date: dateToDateStruct(new Date(line.from)) },
|
|
33112
|
+
return: null
|
|
33113
|
+
});
|
|
33114
|
+
const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
33115
|
+
const applyFlightToLine = (line, flight) => {
|
|
33116
|
+
const segments = flight.outward?.segments ?? [];
|
|
33077
33117
|
if (!segments.length)
|
|
33078
33118
|
return line;
|
|
33079
33119
|
const firstSegment = segments[0];
|
|
@@ -33093,14 +33133,6 @@ const applyFlightToLine = (line, flight, isOutbound) => {
|
|
|
33093
33133
|
isChanged: true
|
|
33094
33134
|
};
|
|
33095
33135
|
};
|
|
33096
|
-
const pairTrajectFlights = (nodes) => {
|
|
33097
|
-
const flights = nodes.filter((x) => isTrajectFlightNode(x.node));
|
|
33098
|
-
return {
|
|
33099
|
-
outbound: flights[0] ?? null,
|
|
33100
|
-
inbound: flights.length > 1 ? flights[flights.length - 1] : null,
|
|
33101
|
-
unsupported: flights.slice(1, Math.max(flights.length - 1, 1))
|
|
33102
|
-
};
|
|
33103
|
-
};
|
|
33104
33136
|
|
|
33105
33137
|
const getLocation = (result) => {
|
|
33106
33138
|
const place = result.locationName || result.regionName || result.oordName;
|
|
@@ -33178,15 +33210,10 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33178
33210
|
const dispatch = reactRedux.useDispatch();
|
|
33179
33211
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
33180
33212
|
const locale = getLocale(context?.languageCode ?? 'en-GB');
|
|
33181
|
-
const { trajectNodeAvailability,
|
|
33182
|
-
const uniqueOutwardFlights = reactRedux.useSelector(selectUniqueOutwardFlights);
|
|
33183
|
-
const uniqueReturnFlights = reactRedux.useSelector(selectUniqueReturnFlights);
|
|
33184
|
-
const selectedOutward = reactRedux.useSelector(selectSelectedOutward);
|
|
33185
|
-
const selectedReturn = reactRedux.useSelector(selectSelectedReturn);
|
|
33213
|
+
const { trajectNodeAvailability, trajectFlightAvailability } = reactRedux.useSelector((state) => state.searchResults);
|
|
33186
33214
|
const [expandedNodes, setExpandedNodes] = React.useState({});
|
|
33187
33215
|
const trajectEntry = context?.trajectEntry;
|
|
33188
33216
|
const nodesWithLines = React.useMemo(() => (trajectEntry ? getTrajectNodesWithLines(trajectEntry) : []), [trajectEntry]);
|
|
33189
|
-
const flightPairing = React.useMemo(() => pairTrajectFlights(nodesWithLines), [nodesWithLines]);
|
|
33190
33217
|
const lineByNodeId = React.useMemo(() => new Map(nodesWithLines.map((x) => [x.node.nodeId, x])), [nodesWithLines]);
|
|
33191
33218
|
const nodesByDay = React.useMemo(() => {
|
|
33192
33219
|
const map = new Map();
|
|
@@ -33211,6 +33238,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33211
33238
|
dispatch(updateEditableEntryLine(applyResultToLine(item.line, result)));
|
|
33212
33239
|
};
|
|
33213
33240
|
const renderServiceNode = (item) => {
|
|
33241
|
+
console.log('renderServiceNode', item);
|
|
33214
33242
|
const { node, line } = item;
|
|
33215
33243
|
const availability = trajectNodeAvailability[line.guid];
|
|
33216
33244
|
const isExpanded = !!expandedNodes[line.guid];
|
|
@@ -33239,30 +33267,19 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33239
33267
|
others.length > 0 && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
33240
33268
|
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => toggleExpanded(line.guid) }, isExpanded ? translations.SRP.SHOW_LESS : `${translations.SRP.SHOW_MORE} (${others.length})`)))))));
|
|
33241
33269
|
};
|
|
33270
|
+
const handleSelectFlight = (item, flight) => {
|
|
33271
|
+
dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
|
|
33272
|
+
dispatch(updateEditableEntryLine(applyFlightToLine(item.line, flight)));
|
|
33273
|
+
};
|
|
33242
33274
|
const renderFlightNode = (item) => {
|
|
33243
33275
|
const { node, line } = item;
|
|
33244
|
-
const
|
|
33245
|
-
const
|
|
33246
|
-
|
|
33247
|
-
|
|
33248
|
-
|
|
33249
|
-
|
|
33250
|
-
|
|
33251
|
-
React__default["default"].createElement("p", { className: "search__results__label__date-date" }, dateFns.format(new Date(line.from), 'd', { locale })),
|
|
33252
|
-
React__default["default"].createElement("p", null, dateFns.format(new Date(line.from), 'MMM', { locale }))),
|
|
33253
|
-
React__default["default"].createElement("div", { className: "search__results__label__text" },
|
|
33254
|
-
React__default["default"].createElement(Icon, { name: "ui-flight", height: 16 }),
|
|
33255
|
-
React__default["default"].createElement("h3", null,
|
|
33256
|
-
React__default["default"].createElement("strong", null, node.name)))),
|
|
33257
|
-
React__default["default"].createElement("div", { className: "no-results" },
|
|
33258
|
-
node.departureAirportCode,
|
|
33259
|
-
" \u2192 ",
|
|
33260
|
-
node.arrivalAirportCode)));
|
|
33261
|
-
}
|
|
33262
|
-
const flights = isOutbound ? uniqueOutwardFlights : uniqueReturnFlights;
|
|
33263
|
-
const selectedFlight = isOutbound ? selectedOutward : selectedReturn;
|
|
33264
|
-
const selectedKey = isOutbound ? selectedOutwardKey : selectedReturnKey;
|
|
33265
|
-
const visible = flights.filter((x) => getFlightKey(isOutbound ? x.outward.segments : x.return.segments) !== selectedKey);
|
|
33276
|
+
const availability = trajectFlightAvailability[line.guid];
|
|
33277
|
+
const status = availability?.status ?? 'loading';
|
|
33278
|
+
const flights = availability?.results ?? [];
|
|
33279
|
+
const selected = flights.find((x) => x.outwardGuid === availability?.selectedGuid) ?? null;
|
|
33280
|
+
const others = flights.filter((x) => x.outwardGuid !== availability?.selectedGuid);
|
|
33281
|
+
const isExpanded = !!expandedNodes[line.guid];
|
|
33282
|
+
const visible = isExpanded ? others : others.slice(0, 2);
|
|
33266
33283
|
return (React__default["default"].createElement(React__default["default"].Fragment, { key: line.guid },
|
|
33267
33284
|
React__default["default"].createElement("div", { className: "search__results__label search__results__label--secondary" },
|
|
33268
33285
|
React__default["default"].createElement("div", { className: "search__results__label__date" },
|
|
@@ -33272,11 +33289,19 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33272
33289
|
React__default["default"].createElement(Icon, { name: "ui-flight", height: 16 }),
|
|
33273
33290
|
React__default["default"].createElement("h3", null,
|
|
33274
33291
|
translations.SRP.SELECT,
|
|
33275
|
-
|
|
33276
|
-
React__default["default"].createElement("strong", null,
|
|
33277
|
-
|
|
33278
|
-
|
|
33279
|
-
|
|
33292
|
+
' ',
|
|
33293
|
+
React__default["default"].createElement("strong", null,
|
|
33294
|
+
node.departureAirportCode,
|
|
33295
|
+
" - ",
|
|
33296
|
+
node.arrivalAirportCode)))),
|
|
33297
|
+
status === 'loading' && React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_FLIGHTS }),
|
|
33298
|
+
status === 'unavailable' && React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
|
|
33299
|
+
status === 'resolved' && selected && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
33300
|
+
React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--extended" },
|
|
33301
|
+
React__default["default"].createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price }),
|
|
33302
|
+
visible.map((result) => (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected.price, onSelect: () => handleSelectFlight(item, result) })))),
|
|
33303
|
+
others.length > 2 && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
33304
|
+
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => toggleExpanded(line.guid) }, isExpanded ? translations.SRP.SHOW_LESS : `${translations.SRP.SHOW_MORE} (${others.length - 2})`)))))));
|
|
33280
33305
|
};
|
|
33281
33306
|
if (isLoading)
|
|
33282
33307
|
return React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
|
|
@@ -33302,7 +33327,6 @@ const useTrajectAvailability = () => {
|
|
|
33302
33327
|
const context = React.useContext(SearchResultsConfigurationContext);
|
|
33303
33328
|
const dispatch = reactRedux.useDispatch();
|
|
33304
33329
|
const trajectEntry = context?.trajectEntry;
|
|
33305
|
-
const selectedCombinationFlight = reactRedux.useSelector(selectSelectedCombinationFlight);
|
|
33306
33330
|
React.useEffect(() => {
|
|
33307
33331
|
if (!context || !trajectEntry)
|
|
33308
33332
|
return;
|
|
@@ -33322,6 +33346,13 @@ const useTrajectAvailability = () => {
|
|
|
33322
33346
|
language: context.languageCode ?? 'en-GB',
|
|
33323
33347
|
rooms: getPackagingRoomsFromEntry(trajectEntry.entry)
|
|
33324
33348
|
};
|
|
33349
|
+
// Flight searches take passengers rather than rooms; the API buckets by age.
|
|
33350
|
+
const pax = trajectEntry.entry.pax ?? [];
|
|
33351
|
+
const ageOf = (p) => p.age ?? 30;
|
|
33352
|
+
const adults = pax.filter((p) => ageOf(p) >= 12).length;
|
|
33353
|
+
const kids = pax.filter((p) => ageOf(p) >= 2 && ageOf(p) < 12).length;
|
|
33354
|
+
const babies = pax.filter((p) => ageOf(p) < 2).length;
|
|
33355
|
+
const flightPax = lodash.concat(Array.from({ length: adults }, (_, index) => ({ id: index, age: 31 })), Array.from({ length: kids }, (_, index) => ({ id: index + adults, age: 8 })), Array.from({ length: babies }, (_, index) => ({ id: index + adults + kids, age: 1 })));
|
|
33325
33356
|
const nodesWithLines = getTrajectNodesWithLines(trajectEntry);
|
|
33326
33357
|
const resolveNode = async (item) => {
|
|
33327
33358
|
const lineGuid = item.line.guid;
|
|
@@ -33371,59 +33402,36 @@ const useTrajectAvailability = () => {
|
|
|
33371
33402
|
return lineGuid;
|
|
33372
33403
|
}
|
|
33373
33404
|
};
|
|
33374
|
-
const
|
|
33375
|
-
const
|
|
33376
|
-
if (!
|
|
33377
|
-
dispatch(
|
|
33378
|
-
return;
|
|
33405
|
+
const resolveFlightNode = async (item) => {
|
|
33406
|
+
const lineGuid = item.line.guid;
|
|
33407
|
+
if (!item.node.departureAirportCode || !item.node.arrivalAirportCode) {
|
|
33408
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
33409
|
+
return lineGuid;
|
|
33379
33410
|
}
|
|
33380
|
-
dispatch(
|
|
33411
|
+
dispatch(setTrajectFlightLoading(lineGuid));
|
|
33381
33412
|
try {
|
|
33382
|
-
const
|
|
33383
|
-
const ageOf = (p) => p.age ?? 30;
|
|
33384
|
-
const adults = pax.filter((p) => ageOf(p) >= 12).length;
|
|
33385
|
-
const kids = pax.filter((p) => ageOf(p) >= 2 && ageOf(p) < 12).length;
|
|
33386
|
-
const babies = pax.filter((p) => ageOf(p) < 2).length;
|
|
33387
|
-
const request = {
|
|
33388
|
-
transactionId: trajectEntry.entry.transactionId,
|
|
33389
|
-
officeId: searchContext.officeId,
|
|
33390
|
-
catalogueId: searchContext.catalogueId,
|
|
33391
|
-
agentId: searchContext.agentId,
|
|
33392
|
-
language: searchContext.language,
|
|
33393
|
-
departureAirportCode: outbound.node.departureAirportCode ?? '',
|
|
33394
|
-
arrivalAirportCode: outbound.node.arrivalAirportCode ?? '',
|
|
33395
|
-
returnAirportCode: inbound?.node.arrivalAirportCode ?? outbound.node.departureAirportCode ?? null,
|
|
33396
|
-
luggageIncluded: null,
|
|
33397
|
-
maxStops: null,
|
|
33398
|
-
travelClass: null,
|
|
33399
|
-
pax: lodash.concat(Array.from({ length: adults }, (_, index) => ({ id: index, age: 31 })), Array.from({ length: kids }, (_, index) => ({ id: index + adults, age: 8 })), Array.from({ length: babies }, (_, index) => ({ id: index + adults + kids, age: 1 }))),
|
|
33400
|
-
outward: { date: dateToDateStruct(new Date(outbound.line.from)) },
|
|
33401
|
-
return: { date: dateToDateStruct(new Date((inbound ?? outbound).line.from)) }
|
|
33402
|
-
};
|
|
33403
|
-
const flights = (await build.searchPackagingFlights(config, request, controller.signal)) ?? [];
|
|
33413
|
+
const flights = (await build.searchPackagingFlights(config, buildTrajectFlightRequest(item, searchContext, flightPax), controller.signal)) ?? [];
|
|
33404
33414
|
if (controller.signal.aborted)
|
|
33405
|
-
return;
|
|
33406
|
-
|
|
33407
|
-
|
|
33408
|
-
if (
|
|
33409
|
-
|
|
33410
|
-
|
|
33411
|
-
|
|
33415
|
+
return null;
|
|
33416
|
+
const picked = pickCheapestFlight(flights);
|
|
33417
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: flights, selectedGuid: picked?.outwardGuid ?? null }));
|
|
33418
|
+
if (!picked)
|
|
33419
|
+
return lineGuid;
|
|
33420
|
+
dispatch(updateEditableEntryLine(applyFlightToLine(item.line, picked)));
|
|
33421
|
+
return null;
|
|
33412
33422
|
}
|
|
33413
33423
|
catch (error) {
|
|
33414
|
-
if (
|
|
33415
|
-
|
|
33416
|
-
|
|
33417
|
-
|
|
33418
|
-
|
|
33419
|
-
dispatch(setFlightsLoading(false));
|
|
33420
|
-
dispatch(setTrajectFlightsResolved(true));
|
|
33421
|
-
}
|
|
33424
|
+
if (controller.signal.aborted)
|
|
33425
|
+
return null;
|
|
33426
|
+
console.error('Failed to resolve traject flight', item.node.name, error);
|
|
33427
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
33428
|
+
return lineGuid;
|
|
33422
33429
|
}
|
|
33423
33430
|
};
|
|
33424
33431
|
(async () => {
|
|
33425
33432
|
const searchable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node));
|
|
33426
|
-
const
|
|
33433
|
+
const flightNodes = nodesWithLines.filter((x) => isTrajectFlightNode(x.node));
|
|
33434
|
+
const unresolved = await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)]);
|
|
33427
33435
|
if (controller.signal.aborted)
|
|
33428
33436
|
return;
|
|
33429
33437
|
// A node with no availability anywhere cannot be priced or booked, so its line comes off
|
|
@@ -33434,16 +33442,6 @@ const useTrajectAvailability = () => {
|
|
|
33434
33442
|
})();
|
|
33435
33443
|
return () => controller.abort();
|
|
33436
33444
|
}, [trajectEntry]);
|
|
33437
|
-
// Keep the traject's own flight lines in step with whatever outward/return the user picks.
|
|
33438
|
-
React.useEffect(() => {
|
|
33439
|
-
if (!trajectEntry || !selectedCombinationFlight)
|
|
33440
|
-
return;
|
|
33441
|
-
const { outbound, inbound } = pairTrajectFlights(getTrajectNodesWithLines(trajectEntry));
|
|
33442
|
-
if (outbound)
|
|
33443
|
-
dispatch(updateEditableEntryLine(applyFlightToLine(outbound.line, selectedCombinationFlight, true)));
|
|
33444
|
-
if (inbound)
|
|
33445
|
-
dispatch(updateEditableEntryLine(applyFlightToLine(inbound.line, selectedCombinationFlight, false)));
|
|
33446
|
-
}, [trajectEntry, selectedCombinationFlight]);
|
|
33447
33445
|
};
|
|
33448
33446
|
|
|
33449
33447
|
const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
@@ -40,7 +40,8 @@ export interface SearchResultsState {
|
|
|
40
40
|
bookingNumber?: string;
|
|
41
41
|
/** Per-traject-node availability, keyed by the entry line guid the node maps to. */
|
|
42
42
|
trajectNodeAvailability: Record<string, TrajectNodeAvailability>;
|
|
43
|
-
|
|
43
|
+
/** Per-flight-node one-way search results, keyed by the entry line guid. */
|
|
44
|
+
trajectFlightAvailability: Record<string, TrajectFlightAvailability>;
|
|
44
45
|
}
|
|
45
46
|
export type TrajectNodeStatus = 'idle' | 'loading' | 'resolved' | 'unavailable';
|
|
46
47
|
export interface TrajectNodeAvailability {
|
|
@@ -50,6 +51,12 @@ export interface TrajectNodeAvailability {
|
|
|
50
51
|
selectedCode: string | null;
|
|
51
52
|
preferredUnavailable: boolean;
|
|
52
53
|
}
|
|
54
|
+
export interface TrajectFlightAvailability {
|
|
55
|
+
lineGuid: string;
|
|
56
|
+
status: TrajectNodeStatus;
|
|
57
|
+
results: PackagingFlightResponse[];
|
|
58
|
+
selectedGuid: string | null;
|
|
59
|
+
}
|
|
53
60
|
export declare const setResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<BookingPackageItem[], "searchResults/setResults">, setFilteredResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<BookingPackageItem[], "searchResults/setFilteredResults">, setSelectedSearchResult: import("@reduxjs/toolkit").ActionCreatorWithPayload<BookingPackageItem | null, "searchResults/setSelectedSearchResult">, setPackagingAccoResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingAccommodationResponse[], "searchResults/setPackagingAccoResults">, setFilteredPackagingAccoResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingAccommodationResponse[], "searchResults/setFilteredPackagingAccoResults">, setFilteredPackagingFlightResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingFlightResponse[], "searchResults/setFilteredPackagingFlightResults">, setPackagingAccoSearchDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingAccommodationResponse[], "searchResults/setPackagingAccoSearchDetails">, setSelectedPackagingAccoResult: import("@reduxjs/toolkit").ActionCreatorWithPayload<string | null, "searchResults/setSelectedPackagingAccoResult">, setPackagingFlightResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingFlightResponse[], "searchResults/setPackagingFlightResults">, setSelectedPackagingFlight: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingFlightResponse | null, "searchResults/setSelectedPackagingFlight">, setSelectedFlight: import("@reduxjs/toolkit").ActionCreatorWithPayload<ExtendedFlightSearchResponseItem | null, "searchResults/setSelectedFlight">, setSelectedFlightDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<ExtendedFlightSearchResponseItem | null, "searchResults/setSelectedFlightDetails">, setBookingPackageDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
54
61
|
details: BookingPackage;
|
|
55
62
|
}, "searchResults/setBookingPackageDetails">, selectFlight: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
@@ -71,6 +78,13 @@ export declare const setResults: import("@reduxjs/toolkit").ActionCreatorWithPay
|
|
|
71
78
|
}, "searchResults/setTrajectNodeAvailability">, setTrajectNodeSelection: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
72
79
|
lineGuid: string;
|
|
73
80
|
code: string;
|
|
74
|
-
}, "searchResults/setTrajectNodeSelection">,
|
|
81
|
+
}, "searchResults/setTrajectNodeSelection">, setTrajectFlightLoading: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "searchResults/setTrajectFlightLoading">, setTrajectFlightAvailability: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
82
|
+
lineGuid: string;
|
|
83
|
+
results: PackagingFlightResponse[];
|
|
84
|
+
selectedGuid: string | null;
|
|
85
|
+
}, "searchResults/setTrajectFlightAvailability">, setTrajectFlightSelection: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
86
|
+
lineGuid: string;
|
|
87
|
+
guid: string;
|
|
88
|
+
}, "searchResults/setTrajectFlightSelection">, resetTrajectAvailability: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"searchResults/resetTrajectAvailability">, updateEditableEntryLine: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingEntryLine, "searchResults/updateEditableEntryLine">, removeEditableEntryLines: import("@reduxjs/toolkit").ActionCreatorWithPayload<string[], "searchResults/removeEditableEntryLines">;
|
|
75
89
|
declare const _default: import("@reduxjs/toolkit").Reducer<SearchResultsState>;
|
|
76
90
|
export default _default;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PackagingAccommodationRequest, PackagingAccommodationResponse, PackagingEntry, PackagingEntryLine, PackagingFlightResponse, PackagingRoom, PackagingTrajectAlternative, PackagingTrajectNode, PackagingTrajectResponse } from '@qite/tide-client';
|
|
1
|
+
import { FlightSearchRequest, PackagingAccommodationRequest, PackagingAccommodationResponse, PackagingEntry, PackagingEntryLine, PackagingFlightResponse, PackagingRoom, PackagingTrajectAlternative, PackagingTrajectNode, PackagingTrajectResponse } from '@qite/tide-client';
|
|
2
2
|
export declare const REGULAR_TRAJECT_NODE_TYPE = 0;
|
|
3
3
|
export declare const CONNECTING_TRAJECT_NODE_TYPE = 1;
|
|
4
4
|
export interface TrajectNodeWithLine {
|
|
@@ -25,9 +25,6 @@ export declare const matchesCode: (result: PackagingAccommodationResponse, code:
|
|
|
25
25
|
export declare const getPackagingRoomsFromEntry: (entry: PackagingEntry) => PackagingRoom[];
|
|
26
26
|
export declare const pickCheapest: (results: PackagingAccommodationResponse[]) => PackagingAccommodationResponse | null;
|
|
27
27
|
export declare const applyResultToLine: (line: PackagingEntryLine, result: PackagingAccommodationResponse) => PackagingEntryLine;
|
|
28
|
-
export declare const
|
|
29
|
-
export declare const
|
|
30
|
-
|
|
31
|
-
inbound: TrajectNodeWithLine | null;
|
|
32
|
-
unsupported: TrajectNodeWithLine[];
|
|
33
|
-
};
|
|
28
|
+
export declare const buildTrajectFlightRequest: ({ node, line }: TrajectNodeWithLine, context: TrajectSearchContext, pax: FlightSearchRequest["pax"]) => FlightSearchRequest;
|
|
29
|
+
export declare const pickCheapestFlight: (flights: PackagingFlightResponse[]) => PackagingFlightResponse | null;
|
|
30
|
+
export declare const applyFlightToLine: (line: PackagingEntryLine, flight: PackagingFlightResponse) => PackagingEntryLine;
|
package/build/build-esm/index.js
CHANGED
|
@@ -27341,7 +27341,7 @@ const initialState$1 = {
|
|
|
27341
27341
|
currentStep: 0,
|
|
27342
27342
|
bookingNumber: undefined,
|
|
27343
27343
|
trajectNodeAvailability: {},
|
|
27344
|
-
|
|
27344
|
+
trajectFlightAvailability: {}
|
|
27345
27345
|
};
|
|
27346
27346
|
const searchResultsSlice = createSlice({
|
|
27347
27347
|
name: 'searchResults',
|
|
@@ -27563,16 +27563,38 @@ const searchResultsSlice = createSlice({
|
|
|
27563
27563
|
const guids = new Set(action.payload);
|
|
27564
27564
|
state.editablePackagingEntry.lines = (state.editablePackagingEntry.lines ?? []).filter((x) => !guids.has(x.guid));
|
|
27565
27565
|
},
|
|
27566
|
-
|
|
27567
|
-
|
|
27566
|
+
setTrajectFlightLoading(state, action) {
|
|
27567
|
+
const lineGuid = action.payload;
|
|
27568
|
+
state.trajectFlightAvailability[lineGuid] = {
|
|
27569
|
+
lineGuid,
|
|
27570
|
+
status: 'loading',
|
|
27571
|
+
results: state.trajectFlightAvailability[lineGuid]?.results ?? [],
|
|
27572
|
+
selectedGuid: state.trajectFlightAvailability[lineGuid]?.selectedGuid ?? null
|
|
27573
|
+
};
|
|
27574
|
+
},
|
|
27575
|
+
setTrajectFlightAvailability(state, action) {
|
|
27576
|
+
const { lineGuid, results, selectedGuid } = action.payload;
|
|
27577
|
+
state.trajectFlightAvailability[lineGuid] = {
|
|
27578
|
+
lineGuid,
|
|
27579
|
+
status: selectedGuid ? 'resolved' : 'unavailable',
|
|
27580
|
+
results,
|
|
27581
|
+
selectedGuid
|
|
27582
|
+
};
|
|
27583
|
+
},
|
|
27584
|
+
setTrajectFlightSelection(state, action) {
|
|
27585
|
+
const flight = state.trajectFlightAvailability[action.payload.lineGuid];
|
|
27586
|
+
if (!flight)
|
|
27587
|
+
return;
|
|
27588
|
+
flight.selectedGuid = action.payload.guid;
|
|
27589
|
+
flight.status = 'resolved';
|
|
27568
27590
|
},
|
|
27569
27591
|
resetTrajectAvailability(state) {
|
|
27570
27592
|
state.trajectNodeAvailability = {};
|
|
27571
|
-
state.
|
|
27593
|
+
state.trajectFlightAvailability = {};
|
|
27572
27594
|
}
|
|
27573
27595
|
}
|
|
27574
27596
|
});
|
|
27575
|
-
const { setResults, setFilteredResults, setSelectedSearchResult, setPackagingAccoResults, setFilteredPackagingAccoResults, setFilteredPackagingFlightResults, setPackagingAccoSearchDetails, setSelectedPackagingAccoResult, setPackagingFlightResults, setSelectedPackagingFlight, setSelectedFlight, setSelectedFlightDetails, setBookingPackageDetails, selectFlight, setIsLoading, setFlightsLoading, setInitialFilters, setFilters, resetFilters, setInitialFlightFilters, setFlightFilters, resetFlightFilters, setSortType, setFlightSortType, setActiveTab, setCurrentPage, resetSearchState, setFlyInIsOpen, setEditablePackagingEntry, setTransactionId, setFlyInType, setPriceDetails, setItinerary, setSelectedOutwardKey, setSelectedReturnKey, resetFlightSelection, setExcursionSearchParams, setSelectedExcursionSearchResult, confirmExcursionForDay, removeConfirmedExcursionForDay, clearConfirmedExcursionsForDay, setBookPackagingEntry, setCurrentStep, setBookingNumber, setTrajectNodeLoading, setTrajectNodeAvailability, setTrajectNodeSelection,
|
|
27597
|
+
const { setResults, setFilteredResults, setSelectedSearchResult, setPackagingAccoResults, setFilteredPackagingAccoResults, setFilteredPackagingFlightResults, setPackagingAccoSearchDetails, setSelectedPackagingAccoResult, setPackagingFlightResults, setSelectedPackagingFlight, setSelectedFlight, setSelectedFlightDetails, setBookingPackageDetails, selectFlight, setIsLoading, setFlightsLoading, setInitialFilters, setFilters, resetFilters, setInitialFlightFilters, setFlightFilters, resetFlightFilters, setSortType, setFlightSortType, setActiveTab, setCurrentPage, resetSearchState, setFlyInIsOpen, setEditablePackagingEntry, setTransactionId, setFlyInType, setPriceDetails, setItinerary, setSelectedOutwardKey, setSelectedReturnKey, resetFlightSelection, setExcursionSearchParams, setSelectedExcursionSearchResult, confirmExcursionForDay, removeConfirmedExcursionForDay, clearConfirmedExcursionsForDay, setBookPackagingEntry, setCurrentStep, setBookingNumber, setTrajectNodeLoading, setTrajectNodeAvailability, setTrajectNodeSelection, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
|
|
27576
27598
|
var searchResultsReducer = searchResultsSlice.reducer;
|
|
27577
27599
|
|
|
27578
27600
|
const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
|
|
@@ -33043,8 +33065,26 @@ const mapFlightSegmentsToFlightLines = (segments) => segments.map((segment) => (
|
|
|
33043
33065
|
arrivalAirportDescription: segment.arrivalAirportName,
|
|
33044
33066
|
durationInTicks: segment.durationInTicks
|
|
33045
33067
|
}));
|
|
33046
|
-
const
|
|
33047
|
-
|
|
33068
|
+
const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
33069
|
+
transactionId: context.transactionId,
|
|
33070
|
+
officeId: context.officeId,
|
|
33071
|
+
catalogueId: context.catalogueId,
|
|
33072
|
+
agentId: context.agentId ?? null,
|
|
33073
|
+
language: context.language,
|
|
33074
|
+
departureAirportCode: node.departureAirportCode ?? '',
|
|
33075
|
+
arrivalAirportCode: node.arrivalAirportCode ?? '',
|
|
33076
|
+
returnAirportCode: null,
|
|
33077
|
+
luggageIncluded: null,
|
|
33078
|
+
maxStops: null,
|
|
33079
|
+
travelClass: null,
|
|
33080
|
+
vendorConfigurationId: node.externalVendorId ?? null,
|
|
33081
|
+
pax,
|
|
33082
|
+
outward: { date: dateToDateStruct(new Date(line.from)) },
|
|
33083
|
+
return: null
|
|
33084
|
+
});
|
|
33085
|
+
const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
33086
|
+
const applyFlightToLine = (line, flight) => {
|
|
33087
|
+
const segments = flight.outward?.segments ?? [];
|
|
33048
33088
|
if (!segments.length)
|
|
33049
33089
|
return line;
|
|
33050
33090
|
const firstSegment = segments[0];
|
|
@@ -33064,14 +33104,6 @@ const applyFlightToLine = (line, flight, isOutbound) => {
|
|
|
33064
33104
|
isChanged: true
|
|
33065
33105
|
};
|
|
33066
33106
|
};
|
|
33067
|
-
const pairTrajectFlights = (nodes) => {
|
|
33068
|
-
const flights = nodes.filter((x) => isTrajectFlightNode(x.node));
|
|
33069
|
-
return {
|
|
33070
|
-
outbound: flights[0] ?? null,
|
|
33071
|
-
inbound: flights.length > 1 ? flights[flights.length - 1] : null,
|
|
33072
|
-
unsupported: flights.slice(1, Math.max(flights.length - 1, 1))
|
|
33073
|
-
};
|
|
33074
|
-
};
|
|
33075
33107
|
|
|
33076
33108
|
const getLocation = (result) => {
|
|
33077
33109
|
const place = result.locationName || result.regionName || result.oordName;
|
|
@@ -33149,15 +33181,10 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33149
33181
|
const dispatch = useDispatch();
|
|
33150
33182
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
33151
33183
|
const locale = getLocale(context?.languageCode ?? 'en-GB');
|
|
33152
|
-
const { trajectNodeAvailability,
|
|
33153
|
-
const uniqueOutwardFlights = useSelector(selectUniqueOutwardFlights);
|
|
33154
|
-
const uniqueReturnFlights = useSelector(selectUniqueReturnFlights);
|
|
33155
|
-
const selectedOutward = useSelector(selectSelectedOutward);
|
|
33156
|
-
const selectedReturn = useSelector(selectSelectedReturn);
|
|
33184
|
+
const { trajectNodeAvailability, trajectFlightAvailability } = useSelector((state) => state.searchResults);
|
|
33157
33185
|
const [expandedNodes, setExpandedNodes] = useState({});
|
|
33158
33186
|
const trajectEntry = context?.trajectEntry;
|
|
33159
33187
|
const nodesWithLines = useMemo(() => (trajectEntry ? getTrajectNodesWithLines(trajectEntry) : []), [trajectEntry]);
|
|
33160
|
-
const flightPairing = useMemo(() => pairTrajectFlights(nodesWithLines), [nodesWithLines]);
|
|
33161
33188
|
const lineByNodeId = useMemo(() => new Map(nodesWithLines.map((x) => [x.node.nodeId, x])), [nodesWithLines]);
|
|
33162
33189
|
const nodesByDay = useMemo(() => {
|
|
33163
33190
|
const map = new Map();
|
|
@@ -33182,6 +33209,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33182
33209
|
dispatch(updateEditableEntryLine(applyResultToLine(item.line, result)));
|
|
33183
33210
|
};
|
|
33184
33211
|
const renderServiceNode = (item) => {
|
|
33212
|
+
console.log('renderServiceNode', item);
|
|
33185
33213
|
const { node, line } = item;
|
|
33186
33214
|
const availability = trajectNodeAvailability[line.guid];
|
|
33187
33215
|
const isExpanded = !!expandedNodes[line.guid];
|
|
@@ -33210,30 +33238,19 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33210
33238
|
others.length > 0 && (React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
33211
33239
|
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => toggleExpanded(line.guid) }, isExpanded ? translations.SRP.SHOW_LESS : `${translations.SRP.SHOW_MORE} (${others.length})`)))))));
|
|
33212
33240
|
};
|
|
33241
|
+
const handleSelectFlight = (item, flight) => {
|
|
33242
|
+
dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
|
|
33243
|
+
dispatch(updateEditableEntryLine(applyFlightToLine(item.line, flight)));
|
|
33244
|
+
};
|
|
33213
33245
|
const renderFlightNode = (item) => {
|
|
33214
33246
|
const { node, line } = item;
|
|
33215
|
-
const
|
|
33216
|
-
const
|
|
33217
|
-
|
|
33218
|
-
|
|
33219
|
-
|
|
33220
|
-
|
|
33221
|
-
|
|
33222
|
-
React__default.createElement("p", { className: "search__results__label__date-date" }, format$2(new Date(line.from), 'd', { locale })),
|
|
33223
|
-
React__default.createElement("p", null, format$2(new Date(line.from), 'MMM', { locale }))),
|
|
33224
|
-
React__default.createElement("div", { className: "search__results__label__text" },
|
|
33225
|
-
React__default.createElement(Icon, { name: "ui-flight", height: 16 }),
|
|
33226
|
-
React__default.createElement("h3", null,
|
|
33227
|
-
React__default.createElement("strong", null, node.name)))),
|
|
33228
|
-
React__default.createElement("div", { className: "no-results" },
|
|
33229
|
-
node.departureAirportCode,
|
|
33230
|
-
" \u2192 ",
|
|
33231
|
-
node.arrivalAirportCode)));
|
|
33232
|
-
}
|
|
33233
|
-
const flights = isOutbound ? uniqueOutwardFlights : uniqueReturnFlights;
|
|
33234
|
-
const selectedFlight = isOutbound ? selectedOutward : selectedReturn;
|
|
33235
|
-
const selectedKey = isOutbound ? selectedOutwardKey : selectedReturnKey;
|
|
33236
|
-
const visible = flights.filter((x) => getFlightKey(isOutbound ? x.outward.segments : x.return.segments) !== selectedKey);
|
|
33247
|
+
const availability = trajectFlightAvailability[line.guid];
|
|
33248
|
+
const status = availability?.status ?? 'loading';
|
|
33249
|
+
const flights = availability?.results ?? [];
|
|
33250
|
+
const selected = flights.find((x) => x.outwardGuid === availability?.selectedGuid) ?? null;
|
|
33251
|
+
const others = flights.filter((x) => x.outwardGuid !== availability?.selectedGuid);
|
|
33252
|
+
const isExpanded = !!expandedNodes[line.guid];
|
|
33253
|
+
const visible = isExpanded ? others : others.slice(0, 2);
|
|
33237
33254
|
return (React__default.createElement(React__default.Fragment, { key: line.guid },
|
|
33238
33255
|
React__default.createElement("div", { className: "search__results__label search__results__label--secondary" },
|
|
33239
33256
|
React__default.createElement("div", { className: "search__results__label__date" },
|
|
@@ -33243,11 +33260,19 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33243
33260
|
React__default.createElement(Icon, { name: "ui-flight", height: 16 }),
|
|
33244
33261
|
React__default.createElement("h3", null,
|
|
33245
33262
|
translations.SRP.SELECT,
|
|
33246
|
-
|
|
33247
|
-
React__default.createElement("strong", null,
|
|
33248
|
-
|
|
33249
|
-
|
|
33250
|
-
|
|
33263
|
+
' ',
|
|
33264
|
+
React__default.createElement("strong", null,
|
|
33265
|
+
node.departureAirportCode,
|
|
33266
|
+
" - ",
|
|
33267
|
+
node.arrivalAirportCode)))),
|
|
33268
|
+
status === 'loading' && React__default.createElement(Spinner, { label: translations.SRP.LOADING_FLIGHTS }),
|
|
33269
|
+
status === 'unavailable' && React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
|
|
33270
|
+
status === 'resolved' && selected && (React__default.createElement(React__default.Fragment, null,
|
|
33271
|
+
React__default.createElement("div", { className: "search__results__cards search__results__cards--extended" },
|
|
33272
|
+
React__default.createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price }),
|
|
33273
|
+
visible.map((result) => (React__default.createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected.price, onSelect: () => handleSelectFlight(item, result) })))),
|
|
33274
|
+
others.length > 2 && (React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
33275
|
+
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => toggleExpanded(line.guid) }, isExpanded ? translations.SRP.SHOW_LESS : `${translations.SRP.SHOW_MORE} (${others.length - 2})`)))))));
|
|
33251
33276
|
};
|
|
33252
33277
|
if (isLoading)
|
|
33253
33278
|
return React__default.createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
|
|
@@ -33273,7 +33298,6 @@ const useTrajectAvailability = () => {
|
|
|
33273
33298
|
const context = useContext(SearchResultsConfigurationContext);
|
|
33274
33299
|
const dispatch = useDispatch();
|
|
33275
33300
|
const trajectEntry = context?.trajectEntry;
|
|
33276
|
-
const selectedCombinationFlight = useSelector(selectSelectedCombinationFlight);
|
|
33277
33301
|
useEffect(() => {
|
|
33278
33302
|
if (!context || !trajectEntry)
|
|
33279
33303
|
return;
|
|
@@ -33293,6 +33317,13 @@ const useTrajectAvailability = () => {
|
|
|
33293
33317
|
language: context.languageCode ?? 'en-GB',
|
|
33294
33318
|
rooms: getPackagingRoomsFromEntry(trajectEntry.entry)
|
|
33295
33319
|
};
|
|
33320
|
+
// Flight searches take passengers rather than rooms; the API buckets by age.
|
|
33321
|
+
const pax = trajectEntry.entry.pax ?? [];
|
|
33322
|
+
const ageOf = (p) => p.age ?? 30;
|
|
33323
|
+
const adults = pax.filter((p) => ageOf(p) >= 12).length;
|
|
33324
|
+
const kids = pax.filter((p) => ageOf(p) >= 2 && ageOf(p) < 12).length;
|
|
33325
|
+
const babies = pax.filter((p) => ageOf(p) < 2).length;
|
|
33326
|
+
const flightPax = concat(Array.from({ length: adults }, (_, index) => ({ id: index, age: 31 })), Array.from({ length: kids }, (_, index) => ({ id: index + adults, age: 8 })), Array.from({ length: babies }, (_, index) => ({ id: index + adults + kids, age: 1 })));
|
|
33296
33327
|
const nodesWithLines = getTrajectNodesWithLines(trajectEntry);
|
|
33297
33328
|
const resolveNode = async (item) => {
|
|
33298
33329
|
const lineGuid = item.line.guid;
|
|
@@ -33342,59 +33373,36 @@ const useTrajectAvailability = () => {
|
|
|
33342
33373
|
return lineGuid;
|
|
33343
33374
|
}
|
|
33344
33375
|
};
|
|
33345
|
-
const
|
|
33346
|
-
const
|
|
33347
|
-
if (!
|
|
33348
|
-
dispatch(
|
|
33349
|
-
return;
|
|
33376
|
+
const resolveFlightNode = async (item) => {
|
|
33377
|
+
const lineGuid = item.line.guid;
|
|
33378
|
+
if (!item.node.departureAirportCode || !item.node.arrivalAirportCode) {
|
|
33379
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
33380
|
+
return lineGuid;
|
|
33350
33381
|
}
|
|
33351
|
-
dispatch(
|
|
33382
|
+
dispatch(setTrajectFlightLoading(lineGuid));
|
|
33352
33383
|
try {
|
|
33353
|
-
const
|
|
33354
|
-
const ageOf = (p) => p.age ?? 30;
|
|
33355
|
-
const adults = pax.filter((p) => ageOf(p) >= 12).length;
|
|
33356
|
-
const kids = pax.filter((p) => ageOf(p) >= 2 && ageOf(p) < 12).length;
|
|
33357
|
-
const babies = pax.filter((p) => ageOf(p) < 2).length;
|
|
33358
|
-
const request = {
|
|
33359
|
-
transactionId: trajectEntry.entry.transactionId,
|
|
33360
|
-
officeId: searchContext.officeId,
|
|
33361
|
-
catalogueId: searchContext.catalogueId,
|
|
33362
|
-
agentId: searchContext.agentId,
|
|
33363
|
-
language: searchContext.language,
|
|
33364
|
-
departureAirportCode: outbound.node.departureAirportCode ?? '',
|
|
33365
|
-
arrivalAirportCode: outbound.node.arrivalAirportCode ?? '',
|
|
33366
|
-
returnAirportCode: inbound?.node.arrivalAirportCode ?? outbound.node.departureAirportCode ?? null,
|
|
33367
|
-
luggageIncluded: null,
|
|
33368
|
-
maxStops: null,
|
|
33369
|
-
travelClass: null,
|
|
33370
|
-
pax: concat(Array.from({ length: adults }, (_, index) => ({ id: index, age: 31 })), Array.from({ length: kids }, (_, index) => ({ id: index + adults, age: 8 })), Array.from({ length: babies }, (_, index) => ({ id: index + adults + kids, age: 1 }))),
|
|
33371
|
-
outward: { date: dateToDateStruct(new Date(outbound.line.from)) },
|
|
33372
|
-
return: { date: dateToDateStruct(new Date((inbound ?? outbound).line.from)) }
|
|
33373
|
-
};
|
|
33374
|
-
const flights = (await build.searchPackagingFlights(config, request, controller.signal)) ?? [];
|
|
33384
|
+
const flights = (await build.searchPackagingFlights(config, buildTrajectFlightRequest(item, searchContext, flightPax), controller.signal)) ?? [];
|
|
33375
33385
|
if (controller.signal.aborted)
|
|
33376
|
-
return;
|
|
33377
|
-
|
|
33378
|
-
|
|
33379
|
-
if (
|
|
33380
|
-
|
|
33381
|
-
|
|
33382
|
-
|
|
33386
|
+
return null;
|
|
33387
|
+
const picked = pickCheapestFlight(flights);
|
|
33388
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: flights, selectedGuid: picked?.outwardGuid ?? null }));
|
|
33389
|
+
if (!picked)
|
|
33390
|
+
return lineGuid;
|
|
33391
|
+
dispatch(updateEditableEntryLine(applyFlightToLine(item.line, picked)));
|
|
33392
|
+
return null;
|
|
33383
33393
|
}
|
|
33384
33394
|
catch (error) {
|
|
33385
|
-
if (
|
|
33386
|
-
|
|
33387
|
-
|
|
33388
|
-
|
|
33389
|
-
|
|
33390
|
-
dispatch(setFlightsLoading(false));
|
|
33391
|
-
dispatch(setTrajectFlightsResolved(true));
|
|
33392
|
-
}
|
|
33395
|
+
if (controller.signal.aborted)
|
|
33396
|
+
return null;
|
|
33397
|
+
console.error('Failed to resolve traject flight', item.node.name, error);
|
|
33398
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
33399
|
+
return lineGuid;
|
|
33393
33400
|
}
|
|
33394
33401
|
};
|
|
33395
33402
|
(async () => {
|
|
33396
33403
|
const searchable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node));
|
|
33397
|
-
const
|
|
33404
|
+
const flightNodes = nodesWithLines.filter((x) => isTrajectFlightNode(x.node));
|
|
33405
|
+
const unresolved = await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)]);
|
|
33398
33406
|
if (controller.signal.aborted)
|
|
33399
33407
|
return;
|
|
33400
33408
|
// A node with no availability anywhere cannot be priced or booked, so its line comes off
|
|
@@ -33405,16 +33413,6 @@ const useTrajectAvailability = () => {
|
|
|
33405
33413
|
})();
|
|
33406
33414
|
return () => controller.abort();
|
|
33407
33415
|
}, [trajectEntry]);
|
|
33408
|
-
// Keep the traject's own flight lines in step with whatever outward/return the user picks.
|
|
33409
|
-
useEffect(() => {
|
|
33410
|
-
if (!trajectEntry || !selectedCombinationFlight)
|
|
33411
|
-
return;
|
|
33412
|
-
const { outbound, inbound } = pairTrajectFlights(getTrajectNodesWithLines(trajectEntry));
|
|
33413
|
-
if (outbound)
|
|
33414
|
-
dispatch(updateEditableEntryLine(applyFlightToLine(outbound.line, selectedCombinationFlight, true)));
|
|
33415
|
-
if (inbound)
|
|
33416
|
-
dispatch(updateEditableEntryLine(applyFlightToLine(inbound.line, selectedCombinationFlight, false)));
|
|
33417
|
-
}, [trajectEntry, selectedCombinationFlight]);
|
|
33418
33416
|
};
|
|
33419
33417
|
|
|
33420
33418
|
const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
@@ -40,7 +40,8 @@ export interface SearchResultsState {
|
|
|
40
40
|
bookingNumber?: string;
|
|
41
41
|
/** Per-traject-node availability, keyed by the entry line guid the node maps to. */
|
|
42
42
|
trajectNodeAvailability: Record<string, TrajectNodeAvailability>;
|
|
43
|
-
|
|
43
|
+
/** Per-flight-node one-way search results, keyed by the entry line guid. */
|
|
44
|
+
trajectFlightAvailability: Record<string, TrajectFlightAvailability>;
|
|
44
45
|
}
|
|
45
46
|
export type TrajectNodeStatus = 'idle' | 'loading' | 'resolved' | 'unavailable';
|
|
46
47
|
export interface TrajectNodeAvailability {
|
|
@@ -50,6 +51,12 @@ export interface TrajectNodeAvailability {
|
|
|
50
51
|
selectedCode: string | null;
|
|
51
52
|
preferredUnavailable: boolean;
|
|
52
53
|
}
|
|
54
|
+
export interface TrajectFlightAvailability {
|
|
55
|
+
lineGuid: string;
|
|
56
|
+
status: TrajectNodeStatus;
|
|
57
|
+
results: PackagingFlightResponse[];
|
|
58
|
+
selectedGuid: string | null;
|
|
59
|
+
}
|
|
53
60
|
export declare const setResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<BookingPackageItem[], "searchResults/setResults">, setFilteredResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<BookingPackageItem[], "searchResults/setFilteredResults">, setSelectedSearchResult: import("@reduxjs/toolkit").ActionCreatorWithPayload<BookingPackageItem | null, "searchResults/setSelectedSearchResult">, setPackagingAccoResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingAccommodationResponse[], "searchResults/setPackagingAccoResults">, setFilteredPackagingAccoResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingAccommodationResponse[], "searchResults/setFilteredPackagingAccoResults">, setFilteredPackagingFlightResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingFlightResponse[], "searchResults/setFilteredPackagingFlightResults">, setPackagingAccoSearchDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingAccommodationResponse[], "searchResults/setPackagingAccoSearchDetails">, setSelectedPackagingAccoResult: import("@reduxjs/toolkit").ActionCreatorWithPayload<string | null, "searchResults/setSelectedPackagingAccoResult">, setPackagingFlightResults: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingFlightResponse[], "searchResults/setPackagingFlightResults">, setSelectedPackagingFlight: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingFlightResponse | null, "searchResults/setSelectedPackagingFlight">, setSelectedFlight: import("@reduxjs/toolkit").ActionCreatorWithPayload<ExtendedFlightSearchResponseItem | null, "searchResults/setSelectedFlight">, setSelectedFlightDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<ExtendedFlightSearchResponseItem | null, "searchResults/setSelectedFlightDetails">, setBookingPackageDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
54
61
|
details: BookingPackage;
|
|
55
62
|
}, "searchResults/setBookingPackageDetails">, selectFlight: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
@@ -71,6 +78,13 @@ export declare const setResults: import("@reduxjs/toolkit").ActionCreatorWithPay
|
|
|
71
78
|
}, "searchResults/setTrajectNodeAvailability">, setTrajectNodeSelection: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
72
79
|
lineGuid: string;
|
|
73
80
|
code: string;
|
|
74
|
-
}, "searchResults/setTrajectNodeSelection">,
|
|
81
|
+
}, "searchResults/setTrajectNodeSelection">, setTrajectFlightLoading: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "searchResults/setTrajectFlightLoading">, setTrajectFlightAvailability: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
82
|
+
lineGuid: string;
|
|
83
|
+
results: PackagingFlightResponse[];
|
|
84
|
+
selectedGuid: string | null;
|
|
85
|
+
}, "searchResults/setTrajectFlightAvailability">, setTrajectFlightSelection: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
86
|
+
lineGuid: string;
|
|
87
|
+
guid: string;
|
|
88
|
+
}, "searchResults/setTrajectFlightSelection">, resetTrajectAvailability: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"searchResults/resetTrajectAvailability">, updateEditableEntryLine: import("@reduxjs/toolkit").ActionCreatorWithPayload<PackagingEntryLine, "searchResults/updateEditableEntryLine">, removeEditableEntryLines: import("@reduxjs/toolkit").ActionCreatorWithPayload<string[], "searchResults/removeEditableEntryLines">;
|
|
75
89
|
declare const _default: import("@reduxjs/toolkit").Reducer<SearchResultsState>;
|
|
76
90
|
export default _default;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PackagingAccommodationRequest, PackagingAccommodationResponse, PackagingEntry, PackagingEntryLine, PackagingFlightResponse, PackagingRoom, PackagingTrajectAlternative, PackagingTrajectNode, PackagingTrajectResponse } from '@qite/tide-client';
|
|
1
|
+
import { FlightSearchRequest, PackagingAccommodationRequest, PackagingAccommodationResponse, PackagingEntry, PackagingEntryLine, PackagingFlightResponse, PackagingRoom, PackagingTrajectAlternative, PackagingTrajectNode, PackagingTrajectResponse } from '@qite/tide-client';
|
|
2
2
|
export declare const REGULAR_TRAJECT_NODE_TYPE = 0;
|
|
3
3
|
export declare const CONNECTING_TRAJECT_NODE_TYPE = 1;
|
|
4
4
|
export interface TrajectNodeWithLine {
|
|
@@ -25,9 +25,6 @@ export declare const matchesCode: (result: PackagingAccommodationResponse, code:
|
|
|
25
25
|
export declare const getPackagingRoomsFromEntry: (entry: PackagingEntry) => PackagingRoom[];
|
|
26
26
|
export declare const pickCheapest: (results: PackagingAccommodationResponse[]) => PackagingAccommodationResponse | null;
|
|
27
27
|
export declare const applyResultToLine: (line: PackagingEntryLine, result: PackagingAccommodationResponse) => PackagingEntryLine;
|
|
28
|
-
export declare const
|
|
29
|
-
export declare const
|
|
30
|
-
|
|
31
|
-
inbound: TrajectNodeWithLine | null;
|
|
32
|
-
unsupported: TrajectNodeWithLine[];
|
|
33
|
-
};
|
|
28
|
+
export declare const buildTrajectFlightRequest: ({ node, line }: TrajectNodeWithLine, context: TrajectSearchContext, pax: FlightSearchRequest["pax"]) => FlightSearchRequest;
|
|
29
|
+
export declare const pickCheapestFlight: (flights: PackagingFlightResponse[]) => PackagingFlightResponse | null;
|
|
30
|
+
export declare const applyFlightToLine: (line: PackagingEntryLine, flight: PackagingFlightResponse) => PackagingEntryLine;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qite/tide-components",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "React components for Tide (booking, product availability, form, ...)",
|
|
5
5
|
"main": "build/build-cjs/index.js",
|
|
6
6
|
"types": "build/build-cjs/src/index.d.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@jsonurl/jsonurl": "^1.1.4",
|
|
38
38
|
"@popperjs/core": "^2.10.2",
|
|
39
|
-
"@qite/tide-client": "^2.0.
|
|
39
|
+
"@qite/tide-client": "^2.0.13",
|
|
40
40
|
"@reduxjs/toolkit": "^2.8.2",
|
|
41
41
|
"@rollup/plugin-commonjs": "^19.0.1",
|
|
42
42
|
"@rollup/plugin-json": "^4.1.0",
|