@qite/tide-components 1.0.7 → 1.0.8
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 +391 -124
- package/build/build-cjs/src/search-results/hooks/use-bookable-entry.d.ts +11 -0
- package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +3 -1
- package/build/build-cjs/src/search-results/utils/traject-utils.d.ts +48 -10
- package/build/build-esm/index.js +391 -124
- package/build/build-esm/src/search-results/hooks/use-bookable-entry.d.ts +11 -0
- package/build/build-esm/src/search-results/store/search-results-slice.d.ts +3 -1
- package/build/build-esm/src/search-results/utils/traject-utils.d.ts +48 -10
- package/package.json +1 -1
package/build/build-cjs/index.js
CHANGED
|
@@ -458,6 +458,7 @@ var SRP$f = {
|
|
|
458
458
|
TRAVEL_GROUP: "مجموعة المسافرين",
|
|
459
459
|
EXCURSION: "رحلة",
|
|
460
460
|
LOADING_EXCURSIONS: "جارٍ تحميل الرحلات...",
|
|
461
|
+
LOADING_ACTIVITIES: "جارٍ تحميل الأنشطة...",
|
|
461
462
|
LOADING_FLIGHTS: "جارٍ تحميل الرحلات الجوية...",
|
|
462
463
|
LOADING_ACCOMMODATIONS: "جارٍ تحميل الإقامات...",
|
|
463
464
|
LOADING_ITINERARY: "جارٍ تحميل خط سير الرحلة...",
|
|
@@ -902,6 +903,7 @@ var SRP$e = {
|
|
|
902
903
|
TRAVEL_GROUP: "Rejseselskab",
|
|
903
904
|
EXCURSION: "Udflugt",
|
|
904
905
|
LOADING_EXCURSIONS: "Indlæser udflugter...",
|
|
906
|
+
LOADING_ACTIVITIES: "Indlæser aktiviteter...",
|
|
905
907
|
LOADING_FLIGHTS: "Indlæser fly...",
|
|
906
908
|
LOADING_ACCOMMODATIONS: "Indlæser indkvarteringer...",
|
|
907
909
|
LOADING_ITINERARY: "Indlæser rejseplan...",
|
|
@@ -1346,6 +1348,7 @@ var SRP$d = {
|
|
|
1346
1348
|
TRAVEL_GROUP: "Reisegruppe",
|
|
1347
1349
|
EXCURSION: "Ausflug",
|
|
1348
1350
|
LOADING_EXCURSIONS: "Lade Ausflüge...",
|
|
1351
|
+
LOADING_ACTIVITIES: "Lade Aktivitäten...",
|
|
1349
1352
|
LOADING_FLIGHTS: "Lade Flüge...",
|
|
1350
1353
|
LOADING_ACCOMMODATIONS: "Lade Unterkünfte...",
|
|
1351
1354
|
LOADING_ITINERARY: "Lade Reiseverlauf...",
|
|
@@ -1794,6 +1797,7 @@ var SRP$c = {
|
|
|
1794
1797
|
TRAVEL_GROUP: "Travel group",
|
|
1795
1798
|
EXCURSION: "Excursion",
|
|
1796
1799
|
LOADING_EXCURSIONS: "Loading excursions...",
|
|
1800
|
+
LOADING_ACTIVITIES: "Loading activities...",
|
|
1797
1801
|
LOADING_FLIGHTS: "Loading flights...",
|
|
1798
1802
|
LOADING_ACCOMMODATIONS: "Loading accommodations...",
|
|
1799
1803
|
LOADING_ITINERARY: "Loading itinerary...",
|
|
@@ -2238,6 +2242,7 @@ var SRP$b = {
|
|
|
2238
2242
|
TRAVEL_GROUP: "Grupo de viaje",
|
|
2239
2243
|
EXCURSION: "Excursión",
|
|
2240
2244
|
LOADING_EXCURSIONS: "Cargando excursiones...",
|
|
2245
|
+
LOADING_ACTIVITIES: "Cargando actividades...",
|
|
2241
2246
|
LOADING_FLIGHTS: "Cargando vuelos...",
|
|
2242
2247
|
LOADING_ACCOMMODATIONS: "Cargando alojamientos...",
|
|
2243
2248
|
LOADING_ITINERARY: "Cargando itinerario...",
|
|
@@ -2686,6 +2691,7 @@ var SRP$a = {
|
|
|
2686
2691
|
TRAVEL_GROUP: "Groupe de voyageurs",
|
|
2687
2692
|
EXCURSION: "Excursion",
|
|
2688
2693
|
LOADING_EXCURSIONS: "Chargement des excursions...",
|
|
2694
|
+
LOADING_ACTIVITIES: "Chargement des activités...",
|
|
2689
2695
|
LOADING_FLIGHTS: "Chargement des vols...",
|
|
2690
2696
|
LOADING_ACCOMMODATIONS: "Chargement des hébergements...",
|
|
2691
2697
|
LOADING_ITINERARY: "Chargement de l’itinéraire...",
|
|
@@ -3130,6 +3136,7 @@ var SRP$9 = {
|
|
|
3130
3136
|
TRAVEL_GROUP: "Groupe de voyageurs",
|
|
3131
3137
|
EXCURSION: "Excursion",
|
|
3132
3138
|
LOADING_EXCURSIONS: "Chargement des excursions...",
|
|
3139
|
+
LOADING_ACTIVITIES: "Chargement des activités...",
|
|
3133
3140
|
LOADING_FLIGHTS: "Chargement des vols...",
|
|
3134
3141
|
LOADING_ACCOMMODATIONS: "Chargement des hébergements...",
|
|
3135
3142
|
LOADING_ITINERARY: "Chargement de l’itinéraire...",
|
|
@@ -3574,6 +3581,7 @@ var SRP$8 = {
|
|
|
3574
3581
|
TRAVEL_GROUP: "Ferðahópur",
|
|
3575
3582
|
EXCURSION: "Útflutningur",
|
|
3576
3583
|
LOADING_EXCURSIONS: "Hleðst inn í útflutninga...",
|
|
3584
|
+
LOADING_ACTIVITIES: "Hleð inn afþreyingu...",
|
|
3577
3585
|
LOADING_FLIGHTS: "Hleðst inn í flug...",
|
|
3578
3586
|
LOADING_ACCOMMODATIONS: "Hleðst inn í gistingar...",
|
|
3579
3587
|
LOADING_ITINERARY: "Hleðst inn í ferðaráætlun...",
|
|
@@ -4018,6 +4026,7 @@ var SRP$7 = {
|
|
|
4018
4026
|
TRAVEL_GROUP: "Gruppo di viaggio",
|
|
4019
4027
|
EXCURSION: "Escursione",
|
|
4020
4028
|
LOADING_EXCURSIONS: "Caricamento delle escursioni...",
|
|
4029
|
+
LOADING_ACTIVITIES: "Caricamento delle attività...",
|
|
4021
4030
|
LOADING_FLIGHTS: "Caricamento dei voli...",
|
|
4022
4031
|
LOADING_ACCOMMODATIONS: "Caricamento degli alloggi...",
|
|
4023
4032
|
LOADING_ITINERARY: "Caricamento dell'itinerario...",
|
|
@@ -4466,6 +4475,7 @@ var SRP$6 = {
|
|
|
4466
4475
|
TRAVEL_GROUP: "Reisgezelschap",
|
|
4467
4476
|
EXCURSION: "Excursie",
|
|
4468
4477
|
LOADING_EXCURSIONS: "Excursies laden...",
|
|
4478
|
+
LOADING_ACTIVITIES: "Activiteiten laden...",
|
|
4469
4479
|
LOADING_FLIGHTS: "Vluchten laden...",
|
|
4470
4480
|
LOADING_ACCOMMODATIONS: "Accommodaties laden...",
|
|
4471
4481
|
LOADING_ITINERARY: "Reisplan laden...",
|
|
@@ -4910,6 +4920,7 @@ var SRP$5 = {
|
|
|
4910
4920
|
TRAVEL_GROUP: "Reisgezelschap",
|
|
4911
4921
|
EXCURSION: "Excursie",
|
|
4912
4922
|
LOADING_EXCURSIONS: "Excursies laden...",
|
|
4923
|
+
LOADING_ACTIVITIES: "Activiteiten laden...",
|
|
4913
4924
|
LOADING_FLIGHTS: "Vluchten laden...",
|
|
4914
4925
|
LOADING_ACCOMMODATIONS: "Accommodaties laden...",
|
|
4915
4926
|
LOADING_ITINERARY: "Reisplan laden...",
|
|
@@ -5354,6 +5365,7 @@ var SRP$4 = {
|
|
|
5354
5365
|
TRAVEL_GROUP: "Reisefølge",
|
|
5355
5366
|
EXCURSION: "Utflukt",
|
|
5356
5367
|
LOADING_EXCURSIONS: "Laster utflukter...",
|
|
5368
|
+
LOADING_ACTIVITIES: "Laster aktiviteter...",
|
|
5357
5369
|
LOADING_FLIGHTS: "Laster flyvninger...",
|
|
5358
5370
|
LOADING_ACCOMMODATIONS: "Laster overnattinger...",
|
|
5359
5371
|
LOADING_ITINERARY: "Laster reiserute...",
|
|
@@ -5798,6 +5810,7 @@ var SRP$3 = {
|
|
|
5798
5810
|
TRAVEL_GROUP: "Grupa podróżnych",
|
|
5799
5811
|
EXCURSION: "Wycieczka",
|
|
5800
5812
|
LOADING_EXCURSIONS: "Ładowanie wycieczek...",
|
|
5813
|
+
LOADING_ACTIVITIES: "Ładowanie atrakcji...",
|
|
5801
5814
|
LOADING_FLIGHTS: "Ładowanie lotów...",
|
|
5802
5815
|
LOADING_ACCOMMODATIONS: "Ładowanie zakwaterowań...",
|
|
5803
5816
|
LOADING_ITINERARY: "Ładowanie planu podróży...",
|
|
@@ -6242,6 +6255,7 @@ var SRP$2 = {
|
|
|
6242
6255
|
TRAVEL_GROUP: "Grupo de viajantes",
|
|
6243
6256
|
EXCURSION: "Excursão",
|
|
6244
6257
|
LOADING_EXCURSIONS: "A carregar excursões...",
|
|
6258
|
+
LOADING_ACTIVITIES: "A carregar atividades...",
|
|
6245
6259
|
LOADING_FLIGHTS: "A carregar voos...",
|
|
6246
6260
|
LOADING_ACCOMMODATIONS: "A carregar alojamentos...",
|
|
6247
6261
|
LOADING_ITINERARY: "A carregar itinerário...",
|
|
@@ -6686,6 +6700,7 @@ var SRP$1 = {
|
|
|
6686
6700
|
TRAVEL_GROUP: "Resesällskap",
|
|
6687
6701
|
EXCURSION: "Utflykt",
|
|
6688
6702
|
LOADING_EXCURSIONS: "Laddar utflykter...",
|
|
6703
|
+
LOADING_ACTIVITIES: "Laddar aktiviteter...",
|
|
6689
6704
|
LOADING_FLIGHTS: "Laddar flyg...",
|
|
6690
6705
|
LOADING_ACCOMMODATIONS: "Laddar boenden...",
|
|
6691
6706
|
LOADING_ITINERARY: "Laddar resplan...",
|
|
@@ -7130,6 +7145,7 @@ var SRP = {
|
|
|
7130
7145
|
TRAVEL_GROUP: "旅行グループ",
|
|
7131
7146
|
EXCURSION: "エクスカーション",
|
|
7132
7147
|
LOADING_EXCURSIONS: "エクスカーションを読み込み中...",
|
|
7148
|
+
LOADING_ACTIVITIES: "アクティビティを読み込み中...",
|
|
7133
7149
|
LOADING_FLIGHTS: "フライトを読み込み中...",
|
|
7134
7150
|
LOADING_ACCOMMODATIONS: "宿泊施設を読み込み中...",
|
|
7135
7151
|
LOADING_ITINERARY: "旅程を読み込み中...",
|
|
@@ -27471,7 +27487,9 @@ const initialState$1 = {
|
|
|
27471
27487
|
trajectFlightAvailability: {},
|
|
27472
27488
|
trajectDaySuggestions: {},
|
|
27473
27489
|
trajectEditLineGuid: null,
|
|
27474
|
-
trajectActivitiesDayOrder: null
|
|
27490
|
+
trajectActivitiesDayOrder: null,
|
|
27491
|
+
trajectResolving: false,
|
|
27492
|
+
trajectItineraryView: false
|
|
27475
27493
|
};
|
|
27476
27494
|
const searchResultsSlice = toolkit.createSlice({
|
|
27477
27495
|
name: 'searchResults',
|
|
@@ -27741,6 +27759,12 @@ const searchResultsSlice = toolkit.createSlice({
|
|
|
27741
27759
|
setTrajectActivitiesDayOrder(state, action) {
|
|
27742
27760
|
state.trajectActivitiesDayOrder = action.payload;
|
|
27743
27761
|
},
|
|
27762
|
+
setTrajectResolving(state, action) {
|
|
27763
|
+
state.trajectResolving = action.payload;
|
|
27764
|
+
},
|
|
27765
|
+
setTrajectItineraryView(state, action) {
|
|
27766
|
+
state.trajectItineraryView = action.payload;
|
|
27767
|
+
},
|
|
27744
27768
|
updateTrajectNodeResult(state, action) {
|
|
27745
27769
|
const { lineGuid, result } = action.payload;
|
|
27746
27770
|
const node = state.trajectNodeAvailability[lineGuid];
|
|
@@ -27756,10 +27780,12 @@ const searchResultsSlice = toolkit.createSlice({
|
|
|
27756
27780
|
state.trajectDaySuggestions = {};
|
|
27757
27781
|
state.trajectEditLineGuid = null;
|
|
27758
27782
|
state.trajectActivitiesDayOrder = null;
|
|
27783
|
+
state.trajectResolving = false;
|
|
27784
|
+
state.trajectItineraryView = false;
|
|
27759
27785
|
}
|
|
27760
27786
|
}
|
|
27761
27787
|
});
|
|
27762
|
-
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, setTrajectEditLineGuid, setTrajectActivitiesDayOrder, setTrajectDaySuggestionsLoading, setTrajectDaySuggestions, addEditableEntryLines, updateTrajectNodeResult, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
|
|
27788
|
+
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, setTrajectResolving, setTrajectItineraryView, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, setTrajectEditLineGuid, setTrajectActivitiesDayOrder, setTrajectDaySuggestionsLoading, setTrajectDaySuggestions, addEditableEntryLines, updateTrajectNodeResult, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
|
|
27763
27789
|
var searchResultsReducer = searchResultsSlice.reducer;
|
|
27764
27790
|
|
|
27765
27791
|
const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
|
|
@@ -28049,7 +28075,22 @@ const buildDestination = (line, node, result) => {
|
|
|
28049
28075
|
null;
|
|
28050
28076
|
return { id: 0, ...place, ...coordinates };
|
|
28051
28077
|
};
|
|
28052
|
-
const
|
|
28078
|
+
const hasDestination = (destination) => !!destination && (!!destination.id || (!!destination.latitude && !!destination.longitude));
|
|
28079
|
+
const buildTrajectClientConfig = (context) => ({
|
|
28080
|
+
host: context.tideConnection.host,
|
|
28081
|
+
apiKey: context.tideConnection.apiKey
|
|
28082
|
+
});
|
|
28083
|
+
const buildTrajectSearchContext = (context, trajectEntry) => ({
|
|
28084
|
+
transactionId: trajectEntry.entry.transactionId,
|
|
28085
|
+
officeId: context.tideConnection.officeId ?? 1,
|
|
28086
|
+
catalogueId: context.searchConfiguration.defaultCatalogueId ?? context.tideConnection.catalogueIds?.[0] ?? 1,
|
|
28087
|
+
searchConfigurationId: context.searchConfiguration.id,
|
|
28088
|
+
portalId: context.portalId ?? null,
|
|
28089
|
+
agentId: context.agentId ?? null,
|
|
28090
|
+
language: context.languageCode ?? 'en-GB',
|
|
28091
|
+
rooms: getPackagingRoomsFromEntry(trajectEntry.entry)
|
|
28092
|
+
});
|
|
28093
|
+
const buildTrajectNodeRequest = ({ node, line }, context, productCode, destination) => ({
|
|
28053
28094
|
transactionId: context.transactionId,
|
|
28054
28095
|
officeId: context.officeId,
|
|
28055
28096
|
agentId: context.agentId ?? null,
|
|
@@ -28060,25 +28101,69 @@ const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
|
|
|
28060
28101
|
language: context.language,
|
|
28061
28102
|
serviceType: node.serviceType,
|
|
28062
28103
|
fromDate: toDateOnlyString(line.from),
|
|
28063
|
-
|
|
28064
|
-
|
|
28104
|
+
// An excursion happens on a day rather than over a span. The traject gives its line an end a day
|
|
28105
|
+
// out, the way a night is counted, which asks the search for a window it does not have.
|
|
28106
|
+
toDate: toDateOnlyString(node.serviceType === EXCURSION_SERVICE_TYPE ? line.from : line.to),
|
|
28107
|
+
destination: destination ?? buildDestination(line, node),
|
|
28065
28108
|
productCode,
|
|
28066
28109
|
rooms: context.rooms,
|
|
28067
28110
|
tagIds: []
|
|
28068
28111
|
});
|
|
28069
|
-
|
|
28070
|
-
|
|
28071
|
-
|
|
28072
|
-
|
|
28073
|
-
|
|
28074
|
-
|
|
28075
|
-
|
|
28076
|
-
|
|
28077
|
-
|
|
28078
|
-
|
|
28079
|
-
|
|
28080
|
-
|
|
28112
|
+
const coversDay = ({ node, line }, dayOrder) => {
|
|
28113
|
+
const nights = Math.max(dateFns.differenceInCalendarDays(new Date(line.to), new Date(line.from)), 1);
|
|
28114
|
+
return dayOrder >= node.dayOrder && dayOrder < node.dayOrder + nights;
|
|
28115
|
+
};
|
|
28116
|
+
const getDayDestinationItem = (items, dayOrder) => {
|
|
28117
|
+
const knowsWhereItIs = (x) => hasDestination(buildDestination(x.line, x.node));
|
|
28118
|
+
const stay = items.find((x) => x.node.serviceType === ACCOMMODATION_SERVICE_TYPE && coversDay(x, dayOrder) && knowsWhereItIs(x));
|
|
28119
|
+
if (stay)
|
|
28120
|
+
return stay;
|
|
28121
|
+
return ([...items]
|
|
28122
|
+
.filter((x) => x.node.dayOrder <= dayOrder && knowsWhereItIs(x))
|
|
28123
|
+
.sort((a, b) => a.node.dayOrder - b.node.dayOrder || a.node.order - b.node.order)
|
|
28124
|
+
.pop() ?? null);
|
|
28125
|
+
};
|
|
28126
|
+
const getDayDestination = (items, availability, dayOrder) => {
|
|
28127
|
+
const item = getDayDestinationItem(items, dayOrder);
|
|
28128
|
+
if (!item)
|
|
28129
|
+
return null;
|
|
28130
|
+
const resolved = availability[item.line.guid];
|
|
28131
|
+
const result = resolved?.results.find((x) => x.code === resolved.selectedCode) ?? null;
|
|
28132
|
+
const destination = buildDestination(item.line, item.node, result);
|
|
28133
|
+
return hasDestination(destination) ? destination : null;
|
|
28134
|
+
};
|
|
28135
|
+
const buildTrajectDayExcursionRequest = (date, destination, context) => ({
|
|
28136
|
+
transactionId: context.transactionId,
|
|
28137
|
+
officeId: context.officeId,
|
|
28138
|
+
agentId: context.agentId ?? null,
|
|
28139
|
+
catalogueId: context.catalogueId,
|
|
28140
|
+
searchConfigurationId: context.searchConfigurationId,
|
|
28141
|
+
portalId: context.portalId ?? null,
|
|
28142
|
+
vendorConfigurationId: null,
|
|
28143
|
+
language: context.language,
|
|
28144
|
+
serviceType: EXCURSION_SERVICE_TYPE,
|
|
28145
|
+
fromDate: toDateOnlyString(date),
|
|
28146
|
+
toDate: toDateOnlyString(date),
|
|
28147
|
+
destination,
|
|
28148
|
+
productCode: '',
|
|
28149
|
+
rooms: context.rooms,
|
|
28150
|
+
tagIds: []
|
|
28151
|
+
});
|
|
28152
|
+
const getExcursionOptionGroups = (result) => {
|
|
28153
|
+
const groups = new Map();
|
|
28154
|
+
(result.rooms ?? [])
|
|
28155
|
+
.flatMap((room) => room.options ?? [])
|
|
28156
|
+
.forEach((option) => {
|
|
28157
|
+
const key = [...(option.paxIds ?? [])].sort((a, b) => a - b).join(',');
|
|
28158
|
+
groups.set(key, [...(groups.get(key) ?? []), option]);
|
|
28081
28159
|
});
|
|
28160
|
+
return [...groups.values()];
|
|
28161
|
+
};
|
|
28162
|
+
const excursionNeedsChoice = (result) => getExcursionOptionGroups(result).some((group) => group.length > 1 && !group.some((option) => option.isSelected));
|
|
28163
|
+
const buildTrajectExcursionLines = (result) => {
|
|
28164
|
+
const options = getExcursionOptionGroups(result)
|
|
28165
|
+
.map((group) => group.find((x) => x.isSelected) ?? (group.length === 1 ? group[0] : null))
|
|
28166
|
+
.filter((x) => !!x);
|
|
28082
28167
|
if (!options.length)
|
|
28083
28168
|
return [];
|
|
28084
28169
|
const guids = options.map((option) => option.guid || crypto.randomUUID());
|
|
@@ -28107,6 +28192,21 @@ const buildTrajectExcursionLines = (result) => {
|
|
|
28107
28192
|
flightInformation: null
|
|
28108
28193
|
}));
|
|
28109
28194
|
};
|
|
28195
|
+
const buildExcursionSearchParams = (result) => ({
|
|
28196
|
+
date: result.fromDate,
|
|
28197
|
+
fromDate: result.fromDate,
|
|
28198
|
+
toDate: result.toDate,
|
|
28199
|
+
countryId: result.countryId,
|
|
28200
|
+
regionId: result.regionId,
|
|
28201
|
+
oordId: result.oordId,
|
|
28202
|
+
locationId: result.locationId,
|
|
28203
|
+
locationName: result.locationName,
|
|
28204
|
+
accommodationCode: null,
|
|
28205
|
+
accommodationName: null,
|
|
28206
|
+
hotelCode: result.code,
|
|
28207
|
+
hotelName: result.name,
|
|
28208
|
+
rooms: result.rooms ?? []
|
|
28209
|
+
});
|
|
28110
28210
|
const buildDayActivityCards = (items, availability, suggestions) => {
|
|
28111
28211
|
const cards = [];
|
|
28112
28212
|
const seen = new Set();
|
|
@@ -28123,11 +28223,27 @@ const buildDayActivityCards = (items, availability, suggestions) => {
|
|
|
28123
28223
|
results.filter((x) => !!findCandidateForResult(item.node, x)).forEach((result) => push(result, item));
|
|
28124
28224
|
});
|
|
28125
28225
|
suggestions.forEach((result) => push(result));
|
|
28126
|
-
|
|
28127
|
-
// nothing, as they are the same search, but a node can resolve where a day has no place to look.
|
|
28128
|
-
items.forEach((item) => (availability[item.line.guid]?.results ?? []).forEach((result) => push(result, item)));
|
|
28226
|
+
items.forEach((item) => (availability[item.line.guid]?.results ?? []).forEach((result) => push(result)));
|
|
28129
28227
|
return cards;
|
|
28130
28228
|
};
|
|
28229
|
+
/**
|
|
28230
|
+
* Where to search for a node.
|
|
28231
|
+
*
|
|
28232
|
+
* Normally the node says so itself, through the product it was configured with. An excursion slot
|
|
28233
|
+
* left empty on the traject says nothing at all — no code, no alternatives, and a line with no
|
|
28234
|
+
* place on it — so it falls back to wherever the party is staying that day, the same anchor the
|
|
28235
|
+
* day's own activity search uses.
|
|
28236
|
+
*/
|
|
28237
|
+
const getNodeSearchDestination = (items, item) => {
|
|
28238
|
+
const own = buildDestination(item.line, item.node);
|
|
28239
|
+
if (hasDestination(own))
|
|
28240
|
+
return own;
|
|
28241
|
+
return getDayDestination(items, {}, item.node.dayOrder) ?? own;
|
|
28242
|
+
};
|
|
28243
|
+
const getConfiguredExcursionCodes = (items, dayOrder) => new Set(items
|
|
28244
|
+
.filter((x) => x.node.dayOrder === dayOrder && x.node.serviceType === EXCURSION_SERVICE_TYPE)
|
|
28245
|
+
.flatMap((x) => [x.node.code, ...getNodeCandidates(x.node).map((candidate) => candidate.code)])
|
|
28246
|
+
.filter((code) => !!code));
|
|
28131
28247
|
const getNodeCandidates = (node) => {
|
|
28132
28248
|
const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
|
|
28133
28249
|
if (configured.length)
|
|
@@ -28236,6 +28352,51 @@ const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
|
28236
28352
|
outward: { date: dateToDateStruct(new Date(line.from)) },
|
|
28237
28353
|
return: null
|
|
28238
28354
|
});
|
|
28355
|
+
/**
|
|
28356
|
+
* The entry as the backend can price it.
|
|
28357
|
+
*
|
|
28358
|
+
* A search caches an EntryLine per option and hands back that line's guid on the option. The
|
|
28359
|
+
* backend then rebuilds the entry by looking each line up in that cache on its guid, so a line
|
|
28360
|
+
* it cannot find is dropped — PackagingEntryBuilder.SyncEntryLines skips it, and an entry whose
|
|
28361
|
+
* lines all came off a traject prices as nothing at all.
|
|
28362
|
+
*
|
|
28363
|
+
* A traject entry is rendered before any search runs, so its lines carry the guids the traject
|
|
28364
|
+
* mapper gave them. This swaps in the guid of whatever each line resolved onto, leaving the
|
|
28365
|
+
* lines the traveller added themselves alone — those were built from a search result and already
|
|
28366
|
+
* carry the right one.
|
|
28367
|
+
*/
|
|
28368
|
+
const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightAvailability) => {
|
|
28369
|
+
const cachedGuids = new Map();
|
|
28370
|
+
getTrajectNodesWithLines(trajectEntry).forEach((item) => {
|
|
28371
|
+
if (isTrajectFlightNode(item.node)) {
|
|
28372
|
+
// A flight search caches the outward line under the guid it reports as outwardGuid.
|
|
28373
|
+
const guid = flightAvailability[item.line.guid]?.selectedGuid;
|
|
28374
|
+
if (guid)
|
|
28375
|
+
cachedGuids.set(item.line.guid, guid);
|
|
28376
|
+
return;
|
|
28377
|
+
}
|
|
28378
|
+
const availability = nodeAvailability[item.line.guid];
|
|
28379
|
+
const result = availability?.results.find((x) => x.code === availability.selectedCode);
|
|
28380
|
+
if (!result)
|
|
28381
|
+
return;
|
|
28382
|
+
// Room i took option i when the result was stamped on, so it takes option i here too.
|
|
28383
|
+
item.lines.forEach((line, index) => {
|
|
28384
|
+
const guid = getOptionForRoom(result, index)?.guid;
|
|
28385
|
+
if (guid)
|
|
28386
|
+
cachedGuids.set(line.guid, guid);
|
|
28387
|
+
});
|
|
28388
|
+
});
|
|
28389
|
+
if (!cachedGuids.size)
|
|
28390
|
+
return entry;
|
|
28391
|
+
return {
|
|
28392
|
+
...entry,
|
|
28393
|
+
lines: (entry.lines ?? []).map((line) => ({
|
|
28394
|
+
...line,
|
|
28395
|
+
guid: cachedGuids.get(line.guid) ?? line.guid,
|
|
28396
|
+
parentGuid: (line.parentGuid && cachedGuids.get(line.parentGuid)) ?? line.parentGuid
|
|
28397
|
+
}))
|
|
28398
|
+
};
|
|
28399
|
+
};
|
|
28239
28400
|
const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
28240
28401
|
const applyFlightToLine = (line, flight) => {
|
|
28241
28402
|
const segments = flight.outward?.segments ?? [];
|
|
@@ -31062,10 +31223,9 @@ const getOptionPaxIds = (option) => {
|
|
|
31062
31223
|
const optionAppliesToPax = (option, paxId) => {
|
|
31063
31224
|
return getOptionPaxIds(option).includes(paxId);
|
|
31064
31225
|
};
|
|
31065
|
-
const optionAppliesToAllTravellers = (option,
|
|
31226
|
+
const optionAppliesToAllTravellers = (option, travellerIds) => {
|
|
31066
31227
|
const paxIds = getOptionPaxIds(option);
|
|
31067
|
-
|
|
31068
|
-
return paxIds.length === expected.length && paxIds.every((id, index) => id === expected[index]);
|
|
31228
|
+
return paxIds.length === travellerIds.length && travellerIds.every((id) => paxIds.includes(id));
|
|
31069
31229
|
};
|
|
31070
31230
|
const groupOptionsByExcursion = (options) => {
|
|
31071
31231
|
const groupedMap = new Map();
|
|
@@ -31090,26 +31250,26 @@ const ExcursionDetails = () => {
|
|
|
31090
31250
|
return null;
|
|
31091
31251
|
}
|
|
31092
31252
|
const translations = getTranslations(context.languageCode ?? 'en-GB');
|
|
31093
|
-
const
|
|
31253
|
+
const travellerIds = editablePackagingEntry.pax.map((pax) => pax.id);
|
|
31094
31254
|
const allOptions = React.useMemo(() => {
|
|
31095
31255
|
return selectedExcursionSearchResult.rooms.flatMap((room) => room.options ?? []);
|
|
31096
31256
|
}, [selectedExcursionSearchResult]);
|
|
31097
31257
|
const sharedOptions = React.useMemo(() => {
|
|
31098
|
-
return allOptions.filter((option) => optionAppliesToAllTravellers(option,
|
|
31099
|
-
}, [allOptions,
|
|
31258
|
+
return allOptions.filter((option) => optionAppliesToAllTravellers(option, travellerIds));
|
|
31259
|
+
}, [allOptions, travellerIds]);
|
|
31100
31260
|
const sharedExcursions = React.useMemo(() => {
|
|
31101
31261
|
return groupOptionsByExcursion(sharedOptions);
|
|
31102
31262
|
}, [sharedOptions]);
|
|
31103
31263
|
const paxGroups = React.useMemo(() => {
|
|
31104
31264
|
return editablePackagingEntry.pax.map((pax) => {
|
|
31105
|
-
const paxOptions = allOptions.filter((option) => optionAppliesToPax(option, pax.id) && !optionAppliesToAllTravellers(option,
|
|
31265
|
+
const paxOptions = allOptions.filter((option) => optionAppliesToPax(option, pax.id) && !optionAppliesToAllTravellers(option, travellerIds));
|
|
31106
31266
|
return {
|
|
31107
31267
|
pax,
|
|
31108
31268
|
paxId: pax.id,
|
|
31109
31269
|
excursions: groupOptionsByExcursion(paxOptions)
|
|
31110
31270
|
};
|
|
31111
31271
|
});
|
|
31112
|
-
}, [editablePackagingEntry.pax, allOptions,
|
|
31272
|
+
}, [editablePackagingEntry.pax, allOptions, travellerIds]);
|
|
31113
31273
|
const getSelectedSharedOption = () => {
|
|
31114
31274
|
return sharedOptions.find((option) => option.isSelected);
|
|
31115
31275
|
};
|
|
@@ -31117,11 +31277,11 @@ const ExcursionDetails = () => {
|
|
|
31117
31277
|
return sharedOptions.find((option) => option.accommodationCode === accommodationCode && option.isSelected);
|
|
31118
31278
|
};
|
|
31119
31279
|
const getSelectedOptionForPax = (paxId) => {
|
|
31120
|
-
return allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option,
|
|
31280
|
+
return allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerIds) && option.isSelected);
|
|
31121
31281
|
};
|
|
31122
31282
|
const getSelectedOptionForExcursion = (paxId, accommodationCode) => {
|
|
31123
31283
|
return allOptions.find((option) => optionAppliesToPax(option, paxId) &&
|
|
31124
|
-
!optionAppliesToAllTravellers(option,
|
|
31284
|
+
!optionAppliesToAllTravellers(option, travellerIds) &&
|
|
31125
31285
|
option.accommodationCode === accommodationCode &&
|
|
31126
31286
|
option.isSelected);
|
|
31127
31287
|
};
|
|
@@ -31131,7 +31291,7 @@ const ExcursionDetails = () => {
|
|
|
31131
31291
|
rooms: selectedExcursionSearchResult.rooms.map((room) => ({
|
|
31132
31292
|
...room,
|
|
31133
31293
|
options: room.options.map((option) => {
|
|
31134
|
-
const isSharedOption = optionAppliesToAllTravellers(option,
|
|
31294
|
+
const isSharedOption = optionAppliesToAllTravellers(option, travellerIds);
|
|
31135
31295
|
if (paxId === undefined) {
|
|
31136
31296
|
if (!isSharedOption) {
|
|
31137
31297
|
return option;
|
|
@@ -31178,7 +31338,7 @@ const ExcursionDetails = () => {
|
|
|
31178
31338
|
targetPrice = selectedOption.price;
|
|
31179
31339
|
}
|
|
31180
31340
|
else {
|
|
31181
|
-
const firstOption = allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option,
|
|
31341
|
+
const firstOption = allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerIds) && option.accommodationCode === accommodationCode);
|
|
31182
31342
|
targetPrice = firstOption?.price || 0;
|
|
31183
31343
|
}
|
|
31184
31344
|
return targetPrice - (currentSelectedPrice || 0);
|
|
@@ -31200,6 +31360,13 @@ const ExcursionDetails = () => {
|
|
|
31200
31360
|
return 'flyin__acco__price';
|
|
31201
31361
|
};
|
|
31202
31362
|
const handleConfirm = () => {
|
|
31363
|
+
if (context.trajectEntry) {
|
|
31364
|
+
const lines = buildTrajectExcursionLines(selectedExcursionSearchResult);
|
|
31365
|
+
if (lines.length)
|
|
31366
|
+
dispatch(addEditableEntryLines(lines));
|
|
31367
|
+
dispatch(setFlyInIsOpen(false));
|
|
31368
|
+
return;
|
|
31369
|
+
}
|
|
31203
31370
|
const dayKey = getExcursionDayKey(excursionSearchParams.date);
|
|
31204
31371
|
dispatch(confirmExcursionForDay({
|
|
31205
31372
|
dayKey,
|
|
@@ -31441,6 +31608,12 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
31441
31608
|
dispatch(removeEditableEntryLines(added.map((line) => line.guid)));
|
|
31442
31609
|
return;
|
|
31443
31610
|
}
|
|
31611
|
+
if (excursionNeedsChoice(result)) {
|
|
31612
|
+
dispatch(setExcursionSearchParams(buildExcursionSearchParams(result)));
|
|
31613
|
+
dispatch(setSelectedExcursionSearchResult(result));
|
|
31614
|
+
dispatch(setFlyInType('excursion-details'));
|
|
31615
|
+
return;
|
|
31616
|
+
}
|
|
31444
31617
|
const lines = buildTrajectExcursionLines(result);
|
|
31445
31618
|
if (lines.length)
|
|
31446
31619
|
dispatch(addEditableEntryLines(lines));
|
|
@@ -31455,7 +31628,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
31455
31628
|
dispatch(setFlyInIsOpen(false));
|
|
31456
31629
|
};
|
|
31457
31630
|
if (isLoading || suggestions?.status === 'loading') {
|
|
31458
|
-
return React__default["default"].createElement(React__default["default"].Fragment, null, context.customSpinner ?? React__default["default"].createElement(Spinner, { label: translations.SRP.
|
|
31631
|
+
return React__default["default"].createElement(React__default["default"].Fragment, null, context.customSpinner ?? React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACTIVITIES }));
|
|
31459
31632
|
}
|
|
31460
31633
|
return (React__default["default"].createElement("div", { className: "flyin__content" },
|
|
31461
31634
|
React__default["default"].createElement("div", { className: "search__result-row" },
|
|
@@ -33403,6 +33576,27 @@ const DayByDayExcursions = () => {
|
|
|
33403
33576
|
})));
|
|
33404
33577
|
};
|
|
33405
33578
|
|
|
33579
|
+
/**
|
|
33580
|
+
* The entry to send to the backend, as opposed to the one the page works with.
|
|
33581
|
+
*
|
|
33582
|
+
* They differ only for a traject: the page keeps the line guids the traject was rendered with,
|
|
33583
|
+
* because that is what joins its nodes to its lines, while pricing and booking need the guids the
|
|
33584
|
+
* searches cached their lines under. Anything else passes through untouched, so this can be used
|
|
33585
|
+
* wherever the entry leaves the component without checking which flow is running.
|
|
33586
|
+
*/
|
|
33587
|
+
const useBookableEntry = () => {
|
|
33588
|
+
const context = React.useContext(SearchResultsConfigurationContext);
|
|
33589
|
+
const { editablePackagingEntry, trajectNodeAvailability, trajectFlightAvailability } = reactRedux.useSelector((state) => state.searchResults);
|
|
33590
|
+
const trajectEntry = context?.trajectEntry;
|
|
33591
|
+
return React.useMemo(() => {
|
|
33592
|
+
if (!editablePackagingEntry)
|
|
33593
|
+
return null;
|
|
33594
|
+
if (!trajectEntry)
|
|
33595
|
+
return editablePackagingEntry;
|
|
33596
|
+
return withCachedEntryLineGuids(editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability);
|
|
33597
|
+
}, [editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability]);
|
|
33598
|
+
};
|
|
33599
|
+
|
|
33406
33600
|
const renderEditablePackagingEntrySummaryOptions = (editablePackagingEntry, priceDetails, translations, currencyCode) => {
|
|
33407
33601
|
const priceDetailsByProduct = lodash.groupBy(priceDetails?.details ?? [], (detail) => `${detail.productCode}|${detail.accommodationCode}`);
|
|
33408
33602
|
return (editablePackagingEntry?.lines ?? []).map((line) => {
|
|
@@ -33787,6 +33981,8 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
33787
33981
|
setSelectedPackagingAccoResult(selectedPackagingAccoResult);
|
|
33788
33982
|
}
|
|
33789
33983
|
}, [selectedPackagingAccoResultCode, packagingAccoResults]);
|
|
33984
|
+
// What the page holds versus what the backend can look up; they differ for a traject.
|
|
33985
|
+
const bookableEntry = useBookableEntry();
|
|
33790
33986
|
if (!context || !editablePackagingEntry || !priceDetails || !config)
|
|
33791
33987
|
return React__default["default"].createElement(Spinner, { label: translations.SUMMARY.PROCESS_BOOKING });
|
|
33792
33988
|
const handleSummarySubmit = async (e) => {
|
|
@@ -33795,20 +33991,15 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
33795
33991
|
if (typeof window !== 'undefined') {
|
|
33796
33992
|
window.scrollTo(0, 0);
|
|
33797
33993
|
}
|
|
33798
|
-
|
|
33799
|
-
|
|
33800
|
-
remarks
|
|
33801
|
-
};
|
|
33994
|
+
// Held apart from the entry itself so they can be put on both copies of it.
|
|
33995
|
+
let bookingFields = { remarks };
|
|
33802
33996
|
if (context.generatePaymentUrl && typeof window !== 'undefined') {
|
|
33803
33997
|
const redirectUrl = new URL(window.location.href);
|
|
33804
33998
|
redirectUrl.searchParams.set('bookingConfirmation', 'true');
|
|
33805
33999
|
redirectUrl.searchParams.set('link', '');
|
|
33806
|
-
|
|
33807
|
-
...updatedEditablePackagingEntry,
|
|
33808
|
-
redirectUrl: redirectUrl.toString(),
|
|
33809
|
-
returnPaymentUrl: true
|
|
33810
|
-
};
|
|
34000
|
+
bookingFields = { ...bookingFields, redirectUrl: redirectUrl.toString(), returnPaymentUrl: true };
|
|
33811
34001
|
}
|
|
34002
|
+
const updatedEditablePackagingEntry = { ...editablePackagingEntry, ...bookingFields };
|
|
33812
34003
|
dispatch(setEditablePackagingEntry(updatedEditablePackagingEntry));
|
|
33813
34004
|
try {
|
|
33814
34005
|
const request = {
|
|
@@ -33816,7 +34007,8 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
33816
34007
|
officeId: context.tideConnection.officeId,
|
|
33817
34008
|
catalogueId: context.searchConfiguration.defaultCatalogueId ?? 0,
|
|
33818
34009
|
agentId: context.agentId,
|
|
33819
|
-
|
|
34010
|
+
// The page keeps the entry it works with; the backend gets the one it can look up.
|
|
34011
|
+
payload: { ...(bookableEntry ?? editablePackagingEntry), ...bookingFields }
|
|
33820
34012
|
};
|
|
33821
34013
|
const bookingResponse = await build.bookPackagingEntry(config, request);
|
|
33822
34014
|
dispatch(setBookingNumber(bookingResponse.number));
|
|
@@ -33848,6 +34040,41 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
33848
34040
|
React__default["default"].createElement(WLSidebar, { activeSearchSeed: activeSearchSeed, packagingAccoResult: selectedPackagingAccoResult }))));
|
|
33849
34041
|
};
|
|
33850
34042
|
|
|
34043
|
+
const useTrajectDayActivities = () => {
|
|
34044
|
+
const context = React.useContext(SearchResultsConfigurationContext);
|
|
34045
|
+
const dispatch = reactRedux.useDispatch();
|
|
34046
|
+
const { trajectDaySuggestions, trajectNodeAvailability } = reactRedux.useSelector((state) => state.searchResults);
|
|
34047
|
+
const trajectEntry = context?.trajectEntry;
|
|
34048
|
+
const showApiItems = !!context?.showApiItems;
|
|
34049
|
+
const loadDay = React.useCallback(async (day) => {
|
|
34050
|
+
if (!context || !trajectEntry)
|
|
34051
|
+
return;
|
|
34052
|
+
// Already asked for, or already answered: leave it be.
|
|
34053
|
+
if (trajectDaySuggestions[day.order])
|
|
34054
|
+
return;
|
|
34055
|
+
const nodesWithLines = getTrajectNodesWithLines(trajectEntry);
|
|
34056
|
+
const destination = getDayDestination(nodesWithLines, trajectNodeAvailability, day.order);
|
|
34057
|
+
if (!destination)
|
|
34058
|
+
return;
|
|
34059
|
+
dispatch(setTrajectDaySuggestionsLoading(day.order));
|
|
34060
|
+
try {
|
|
34061
|
+
const results = (await build.searchPackagingExcursions(buildTrajectClientConfig(context), buildTrajectDayExcursionRequest(day.date, destination, buildTrajectSearchContext(context, trajectEntry)))) ?? [];
|
|
34062
|
+
// With external items switched off a day only offers what Tide holds itself, and whatever
|
|
34063
|
+
// the traject already books that day has a card of its own further up the block.
|
|
34064
|
+
const configured = getConfiguredExcursionCodes(nodesWithLines, day.order);
|
|
34065
|
+
dispatch(setTrajectDaySuggestions({
|
|
34066
|
+
dayOrder: day.order,
|
|
34067
|
+
results: results.filter((x) => showApiItems || !isExternalResult(x)).filter((x) => !configured.has(x.code))
|
|
34068
|
+
}));
|
|
34069
|
+
}
|
|
34070
|
+
catch (error) {
|
|
34071
|
+
console.error('Failed to load traject day activities', day.order, error);
|
|
34072
|
+
dispatch(setTrajectDaySuggestions({ dayOrder: day.order, results: [] }));
|
|
34073
|
+
}
|
|
34074
|
+
}, [context, trajectEntry, showApiItems, trajectDaySuggestions, trajectNodeAvailability, dispatch]);
|
|
34075
|
+
return loadDay;
|
|
34076
|
+
};
|
|
34077
|
+
|
|
33851
34078
|
const getNodeIcon = (node) => {
|
|
33852
34079
|
if (isTrajectFlightNode(node))
|
|
33853
34080
|
return 'ui-flight';
|
|
@@ -33863,9 +34090,10 @@ const MAX_DAY_ACTIVITIES = 6;
|
|
|
33863
34090
|
const TrajectResults = ({ isLoading }) => {
|
|
33864
34091
|
const context = React.useContext(SearchResultsConfigurationContext);
|
|
33865
34092
|
const dispatch = reactRedux.useDispatch();
|
|
34093
|
+
const loadDay = useTrajectDayActivities();
|
|
33866
34094
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
33867
34095
|
const locale = getLocale(context?.languageCode ?? 'en-GB');
|
|
33868
|
-
const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry } = reactRedux.useSelector((state) => state.searchResults);
|
|
34096
|
+
const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry, trajectResolving } = reactRedux.useSelector((state) => state.searchResults);
|
|
33869
34097
|
const trajectEntry = context?.trajectEntry;
|
|
33870
34098
|
const hideShowMoreResults = !!context?.hideShowMoreResults;
|
|
33871
34099
|
const nodesWithLines = React.useMemo(() => (trajectEntry ? getTrajectNodesWithLines(trajectEntry) : []), [trajectEntry]);
|
|
@@ -33979,7 +34207,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33979
34207
|
React__default["default"].createElement(Icon, { name: getNodeIcon(node), height: 16 }),
|
|
33980
34208
|
React__default["default"].createElement("h3", null,
|
|
33981
34209
|
React__default["default"].createElement("strong", null, headerTitle || node.name))))),
|
|
33982
|
-
status === 'loading' &&
|
|
34210
|
+
status === 'loading' && React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACCOMMODATIONS }),
|
|
33983
34211
|
status === 'unavailable' && React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
|
|
33984
34212
|
status === 'resolved' && selected && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
33985
34213
|
availability.preferredUnavailable && node.preferredAccommodationName && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
@@ -34015,8 +34243,6 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34015
34243
|
React__default["default"].createElement("div", { className: "search__results__label__text" },
|
|
34016
34244
|
React__default["default"].createElement(Icon, { name: "ui-flight", height: 16 }),
|
|
34017
34245
|
React__default["default"].createElement("h3", null,
|
|
34018
|
-
translations.SRP.SELECT,
|
|
34019
|
-
' ',
|
|
34020
34246
|
React__default["default"].createElement("strong", null,
|
|
34021
34247
|
node.departureAirportCode,
|
|
34022
34248
|
" - ",
|
|
@@ -34042,10 +34268,22 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34042
34268
|
dispatch(removeEditableEntryLines(added.map((line) => line.guid)));
|
|
34043
34269
|
return;
|
|
34044
34270
|
}
|
|
34271
|
+
if (excursionNeedsChoice(result)) {
|
|
34272
|
+
dispatch(setExcursionSearchParams(buildExcursionSearchParams(result)));
|
|
34273
|
+
dispatch(setSelectedExcursionSearchResult(result));
|
|
34274
|
+
dispatch(setFlyInType('excursion-details'));
|
|
34275
|
+
dispatch(setFlyInIsOpen(true));
|
|
34276
|
+
return;
|
|
34277
|
+
}
|
|
34045
34278
|
const lines = buildTrajectExcursionLines(result);
|
|
34046
34279
|
if (lines.length)
|
|
34047
34280
|
dispatch(addEditableEntryLines(lines));
|
|
34048
34281
|
};
|
|
34282
|
+
const handleShowItinerary = () => {
|
|
34283
|
+
dispatch(setTrajectItineraryView(true));
|
|
34284
|
+
if (typeof window !== 'undefined')
|
|
34285
|
+
window.scrollTo(0, 0);
|
|
34286
|
+
};
|
|
34049
34287
|
const handleShowMoreActivities = (dayOrder) => {
|
|
34050
34288
|
dispatch(setTrajectActivitiesDayOrder(dayOrder));
|
|
34051
34289
|
dispatch(setFlyInType('traject-day-activities'));
|
|
@@ -34068,10 +34306,10 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34068
34306
|
const items = getDayExcursionItems(day.order);
|
|
34069
34307
|
const suggestions = trajectDaySuggestions[day.order];
|
|
34070
34308
|
const cards = buildDayActivityCards(items, trajectNodeAvailability, suggestions?.results ?? []);
|
|
34071
|
-
const
|
|
34072
|
-
|
|
34073
|
-
|
|
34074
|
-
if (!
|
|
34309
|
+
const nodesResolving = items.some((item) => (trajectNodeAvailability[item.line.guid]?.status ?? 'loading') === 'loading');
|
|
34310
|
+
const isSearching = suggestions?.status === 'loading';
|
|
34311
|
+
const canSearch = !!getDayDestination(nodesWithLines, trajectNodeAvailability, day.order);
|
|
34312
|
+
if (!items.length && !canSearch)
|
|
34075
34313
|
return null;
|
|
34076
34314
|
const visible = cards.slice(0, MAX_DAY_ACTIVITIES);
|
|
34077
34315
|
const hidden = cards.length - visible.length;
|
|
@@ -34084,16 +34322,16 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34084
34322
|
React__default["default"].createElement(Icon, { name: "ui-excursion", height: 16 }),
|
|
34085
34323
|
React__default["default"].createElement("h3", null,
|
|
34086
34324
|
React__default["default"].createElement("strong", null, translations.SRP.ACTIVITIES)))),
|
|
34087
|
-
|
|
34088
|
-
|
|
34089
|
-
|
|
34090
|
-
|
|
34091
|
-
|
|
34092
|
-
|
|
34093
|
-
|
|
34094
|
-
|
|
34095
|
-
|
|
34096
|
-
|
|
34325
|
+
(nodesResolving || isSearching) && !cards.length && React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACTIVITIES }),
|
|
34326
|
+
!!cards.length && React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--scroll" }, visible.map(renderActivityCard)),
|
|
34327
|
+
!nodesResolving && !isSearching && !cards.length && (!!items.length || !!suggestions) && (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)),
|
|
34328
|
+
React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
34329
|
+
!suggestions && canSearch && !cards.length && !hideShowMoreResults && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => loadDay(day) }, translations.SRP.SHOW_ACTIVITIES)),
|
|
34330
|
+
hidden > 0 && !hideShowMoreResults && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreActivities(day.order) },
|
|
34331
|
+
translations.SRP.SHOW_MORE,
|
|
34332
|
+
" (",
|
|
34333
|
+
hidden,
|
|
34334
|
+
")")))));
|
|
34097
34335
|
};
|
|
34098
34336
|
/**
|
|
34099
34337
|
* An activity the traject books is swapped for another, the way a hotel is; one the traveller
|
|
@@ -34105,32 +34343,35 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34105
34343
|
};
|
|
34106
34344
|
if (isLoading)
|
|
34107
34345
|
return React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
|
|
34108
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
34109
|
-
|
|
34110
|
-
|
|
34111
|
-
|
|
34112
|
-
|
|
34113
|
-
|
|
34114
|
-
|
|
34115
|
-
|
|
34116
|
-
|
|
34117
|
-
|
|
34118
|
-
|
|
34119
|
-
|
|
34120
|
-
|
|
34121
|
-
|
|
34122
|
-
|
|
34123
|
-
|
|
34124
|
-
|
|
34125
|
-
|
|
34126
|
-
|
|
34127
|
-
|
|
34128
|
-
|
|
34129
|
-
|
|
34130
|
-
|
|
34131
|
-
|
|
34132
|
-
|
|
34133
|
-
|
|
34346
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
34347
|
+
trajectEntry.traject.days.map((day) => {
|
|
34348
|
+
const stay = stayByDay.get(day.order);
|
|
34349
|
+
const dayNodes = (nodesByDay.get(day.order) ?? []).filter((node) => isRenderableNode(node) && lineByNodeId.has(node.nodeId));
|
|
34350
|
+
const stayLeadsDay = !!stay && (stay.night > 0 || dayNodes[0]?.nodeId === stay.item.node.nodeId);
|
|
34351
|
+
// Where the day's activities belong in the order: with the first excursion it carries.
|
|
34352
|
+
const firstExcursionNodeId = dayNodes.find((node) => node.serviceType === EXCURSION_SERVICE_TYPE)?.nodeId;
|
|
34353
|
+
const showDayHeader = stayLeadsDay || !!day.name?.trim();
|
|
34354
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, { key: `day-${day.order}` },
|
|
34355
|
+
showDayHeader && renderDayHeader(day, stayLeadsDay ? stay : undefined),
|
|
34356
|
+
dayNodes.map((node) => {
|
|
34357
|
+
const item = lineByNodeId.get(node.nodeId);
|
|
34358
|
+
if (node.serviceType === ACCOMMODATION_SERVICE_TYPE) {
|
|
34359
|
+
const stayStart = stayStartByNodeId.get(node.nodeId);
|
|
34360
|
+
const titledByDayHeader = stayLeadsDay && stay.item.node.nodeId === node.nodeId;
|
|
34361
|
+
return renderServiceNode(item, !titledByDayHeader, stayStart && getStayTitle(stayStart));
|
|
34362
|
+
}
|
|
34363
|
+
// Every excursion the day holds is drawn once, in one block, where the first of
|
|
34364
|
+
// them falls in the order — so the activities still sit between the stay and the
|
|
34365
|
+
// flight that follow them.
|
|
34366
|
+
if (node.serviceType === EXCURSION_SERVICE_TYPE) {
|
|
34367
|
+
return node.nodeId === firstExcursionNodeId ? renderDayActivities(day) : null;
|
|
34368
|
+
}
|
|
34369
|
+
return renderFlightNode(item);
|
|
34370
|
+
}),
|
|
34371
|
+
firstExcursionNodeId === undefined && renderDayActivities(day)));
|
|
34372
|
+
}),
|
|
34373
|
+
React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
34374
|
+
React__default["default"].createElement("button", { type: "button", className: "cta", disabled: trajectResolving, onClick: handleShowItinerary }, translations.STEPS.NEXT))));
|
|
34134
34375
|
};
|
|
34135
34376
|
|
|
34136
34377
|
const useTrajectAvailability = () => {
|
|
@@ -34144,6 +34385,7 @@ const useTrajectAvailability = () => {
|
|
|
34144
34385
|
return;
|
|
34145
34386
|
const controller = new AbortController();
|
|
34146
34387
|
dispatch(resetTrajectAvailability());
|
|
34388
|
+
dispatch(setTrajectResolving(true));
|
|
34147
34389
|
const config = {
|
|
34148
34390
|
host: context.tideConnection.host,
|
|
34149
34391
|
apiKey: context.tideConnection.apiKey
|
|
@@ -34170,42 +34412,51 @@ const useTrajectAvailability = () => {
|
|
|
34170
34412
|
const lineGuid = item.line.guid;
|
|
34171
34413
|
const search = item.node.serviceType === EXCURSION_SERVICE_TYPE ? build.searchPackagingExcursions : build.searchPackagingAccommodations;
|
|
34172
34414
|
dispatch(setTrajectNodeLoading(lineGuid));
|
|
34415
|
+
const destination = getNodeSearchDestination(nodesWithLines, item);
|
|
34416
|
+
const searchFor = async (productCode) => {
|
|
34417
|
+
try {
|
|
34418
|
+
const results = (await search(config, buildTrajectNodeRequest(item, searchContext, productCode, destination), controller.signal)) ?? [];
|
|
34419
|
+
return results.filter((x) => showApiItems || !isExternalResult(x));
|
|
34420
|
+
}
|
|
34421
|
+
catch (error) {
|
|
34422
|
+
if (!controller.signal.aborted)
|
|
34423
|
+
console.error('Traject product unavailable', item.node.name, productCode, error);
|
|
34424
|
+
return [];
|
|
34425
|
+
}
|
|
34426
|
+
};
|
|
34173
34427
|
try {
|
|
34174
34428
|
// With external items switched off the node only looks at products held inside Tide.
|
|
34175
34429
|
const candidates = getNodeCandidates(item.node).filter((x) => showApiItems || !isExternalCandidate(x));
|
|
34176
|
-
const
|
|
34177
|
-
|
|
34178
|
-
|
|
34179
|
-
|
|
34180
|
-
|
|
34181
|
-
|
|
34182
|
-
|
|
34183
|
-
|
|
34184
|
-
|
|
34185
|
-
}
|
|
34430
|
+
const areaResults = hideShowMoreResults ? [] : await searchFor('');
|
|
34431
|
+
if (controller.signal.aborted)
|
|
34432
|
+
return [];
|
|
34433
|
+
const configuredResults = [];
|
|
34434
|
+
const found = await Promise.all(candidates.map(async (candidate) => {
|
|
34435
|
+
const known = areaResults.find((x) => matchesCode(x, candidate.code));
|
|
34436
|
+
if (known)
|
|
34437
|
+
return known;
|
|
34438
|
+
return (await searchFor(candidate.code)).find((x) => matchesCode(x, candidate.code)) ?? null;
|
|
34186
34439
|
}));
|
|
34187
|
-
|
|
34188
|
-
|
|
34189
|
-
|
|
34440
|
+
if (controller.signal.aborted)
|
|
34441
|
+
return [];
|
|
34442
|
+
// Two configured codes can land on the same product — a hotel and one of its room types.
|
|
34443
|
+
found.forEach((result) => {
|
|
34444
|
+
if (!result || configuredResults.some((x) => x.code === result.code))
|
|
34445
|
+
return;
|
|
34446
|
+
configuredResults.push(result);
|
|
34447
|
+
});
|
|
34448
|
+
const configuredCodes = new Set(configuredResults.map((x) => x.code));
|
|
34449
|
+
const destinationResults = areaResults.filter((x) => !configuredCodes.has(x.code));
|
|
34190
34450
|
const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
|
|
34191
|
-
|
|
34192
|
-
|
|
34193
|
-
|
|
34194
|
-
// rather than quietly substituting a hotel nobody configured.
|
|
34195
|
-
const destinationResults = hideShowMoreResults
|
|
34196
|
-
? []
|
|
34197
|
-
: ((await search(config, buildTrajectNodeRequest(item, searchContext, ''), controller.signal)) ?? [])
|
|
34198
|
-
.filter((x) => showApiItems || !isExternalResult(x))
|
|
34199
|
-
.filter((x) => !configuredResults.some((configured) => configured.code === x.code));
|
|
34451
|
+
const preferredUnavailable = configuredResults.length
|
|
34452
|
+
? !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code))
|
|
34453
|
+
: candidates.length > 0;
|
|
34200
34454
|
const picked = configuredResults[0] ?? pickCheapest(destinationResults);
|
|
34201
|
-
const results = [...configuredResults, ...destinationResults];
|
|
34202
|
-
if (!configuredResults.length)
|
|
34203
|
-
preferredUnavailable = candidates.length > 0;
|
|
34204
34455
|
if (controller.signal.aborted)
|
|
34205
34456
|
return [];
|
|
34206
34457
|
dispatch(setTrajectNodeAvailability({
|
|
34207
34458
|
lineGuid,
|
|
34208
|
-
results,
|
|
34459
|
+
results: [...configuredResults, ...destinationResults],
|
|
34209
34460
|
selectedCode: picked?.code ?? null,
|
|
34210
34461
|
preferredUnavailable
|
|
34211
34462
|
}));
|
|
@@ -34249,11 +34500,11 @@ const useTrajectAvailability = () => {
|
|
|
34249
34500
|
}
|
|
34250
34501
|
};
|
|
34251
34502
|
(async () => {
|
|
34252
|
-
const
|
|
34253
|
-
const
|
|
34254
|
-
const unresolved = (await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)])).flat();
|
|
34503
|
+
const resolvable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node));
|
|
34504
|
+
const unresolved = (await Promise.all(resolvable.map((item) => (isTrajectFlightNode(item.node) ? resolveFlightNode(item) : resolveNode(item))))).flat();
|
|
34255
34505
|
if (controller.signal.aborted)
|
|
34256
34506
|
return;
|
|
34507
|
+
dispatch(setTrajectResolving(false));
|
|
34257
34508
|
// A node with no availability anywhere cannot be priced or booked, so its line comes off
|
|
34258
34509
|
// the entry. The card stays visible and reports the gap.
|
|
34259
34510
|
const emptyLineGuids = unresolved.filter(Boolean);
|
|
@@ -34269,10 +34520,12 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
34269
34520
|
const dispatch = reactRedux.useDispatch();
|
|
34270
34521
|
const context = React.useContext(SearchResultsConfigurationContext);
|
|
34271
34522
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
34272
|
-
const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry, trajectEditLineGuid } = reactRedux.useSelector((state) => state.searchResults);
|
|
34523
|
+
const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry, trajectEditLineGuid, trajectResolving, trajectItineraryView } = reactRedux.useSelector((state) => state.searchResults);
|
|
34273
34524
|
const isMobile = useMediaQuery('(max-width: 1200px)');
|
|
34274
34525
|
// Resolves live availability per traject node; no-op unless a traject entry is configured.
|
|
34275
34526
|
useTrajectAvailability();
|
|
34527
|
+
// The entry as the backend can price it: a traject swaps in the guids its searches cached.
|
|
34528
|
+
const bookableEntry = useBookableEntry();
|
|
34276
34529
|
const [initialFiltersSet, setInitialFiltersSet] = React.useState(false);
|
|
34277
34530
|
const [initialFlightFiltersSet, setInitialFlightFiltersSet] = React.useState(false);
|
|
34278
34531
|
const [filtersOpen, setFiltersOpen] = React.useState(false);
|
|
@@ -35039,6 +35292,10 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35039
35292
|
const fetchPriceDetails = async () => {
|
|
35040
35293
|
if (!context || !editablePackagingEntry || lodash.isEmpty(editablePackagingEntry.lines))
|
|
35041
35294
|
return;
|
|
35295
|
+
// A traject resolves one node at a time. Pricing each step would show a total that climbs
|
|
35296
|
+
// as the trip fills in, so the whole trip is priced once, when the last node is in.
|
|
35297
|
+
if (context.trajectEntry && trajectResolving)
|
|
35298
|
+
return;
|
|
35042
35299
|
setPricesAreLoading(true);
|
|
35043
35300
|
try {
|
|
35044
35301
|
const config = {
|
|
@@ -35050,7 +35307,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35050
35307
|
officeId: context.tideConnection.officeId,
|
|
35051
35308
|
catalogueId: context.searchConfiguration.defaultCatalogueId ?? lodash.first(context?.tideConnection?.catalogueIds) ?? 1,
|
|
35052
35309
|
agentId: context.agentId,
|
|
35053
|
-
payload: editablePackagingEntry
|
|
35310
|
+
payload: bookableEntry ?? editablePackagingEntry
|
|
35054
35311
|
};
|
|
35055
35312
|
const priceDetails = await build.getPriceDetails(config, request);
|
|
35056
35313
|
dispatch(setPriceDetails(priceDetails));
|
|
@@ -35064,8 +35321,9 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35064
35321
|
const fetchItinerary = async () => {
|
|
35065
35322
|
if (!context || !context.packagingEntry || !editablePackagingEntry || lodash.isEmpty(editablePackagingEntry.lines))
|
|
35066
35323
|
return;
|
|
35067
|
-
//
|
|
35068
|
-
|
|
35324
|
+
// While a traject is being composed its own day-by-day column is the itinerary; the generated
|
|
35325
|
+
// one is what the traveller reads the finished trip back from, so it waits until then.
|
|
35326
|
+
if (context.trajectEntry && (trajectResolving || !trajectItineraryView))
|
|
35069
35327
|
return;
|
|
35070
35328
|
setItineraryIsLoading(true);
|
|
35071
35329
|
try {
|
|
@@ -35078,7 +35336,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35078
35336
|
officeId: context.tideConnection.officeId,
|
|
35079
35337
|
catalogueId: context.searchConfiguration.defaultCatalogueId ?? lodash.first(context?.tideConnection?.catalogueIds) ?? 1,
|
|
35080
35338
|
agentId: context.agentId,
|
|
35081
|
-
payload: editablePackagingEntry
|
|
35339
|
+
payload: bookableEntry ?? editablePackagingEntry
|
|
35082
35340
|
};
|
|
35083
35341
|
const itinerary = await build.getItinerary(config, request);
|
|
35084
35342
|
dispatch(setItinerary(itinerary));
|
|
@@ -35091,7 +35349,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35091
35349
|
};
|
|
35092
35350
|
fetchPriceDetails();
|
|
35093
35351
|
fetchItinerary();
|
|
35094
|
-
}, [editablePackagingEntry]);
|
|
35352
|
+
}, [editablePackagingEntry, bookableEntry, trajectResolving, trajectItineraryView]);
|
|
35095
35353
|
// Flight selection
|
|
35096
35354
|
// const [selectedOutwardKey, setSelectedOutwardKey] = useState<string | null>(null);
|
|
35097
35355
|
// const [selectedReturnKey, setSelectedReturnKey] = useState<string | null>(null);
|
|
@@ -35440,6 +35698,11 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35440
35698
|
address: {}
|
|
35441
35699
|
};
|
|
35442
35700
|
};
|
|
35701
|
+
const handleComposeTraject = () => {
|
|
35702
|
+
dispatch(setTrajectItineraryView(false));
|
|
35703
|
+
if (typeof window !== 'undefined')
|
|
35704
|
+
window.scrollTo(0, 0);
|
|
35705
|
+
};
|
|
35443
35706
|
const handleShowMoreFlights = (flyInType) => {
|
|
35444
35707
|
dispatch(setFlyInType(flyInType));
|
|
35445
35708
|
dispatch(setFlyInIsOpen(true));
|
|
@@ -35455,7 +35718,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35455
35718
|
context.searchConfiguration.qsmType != build.PortalQsmType.AccommodationAndFlight && context.showFilters && (React__default["default"].createElement(Filters, { initialFilters: initialFilters, filters: filters, isOpen: filtersOpen, handleSetIsOpen: () => setFiltersOpen(!filtersOpen),
|
|
35456
35719
|
// handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
|
|
35457
35720
|
isLoading: isLoading, setFilters: (filters) => dispatch(setFilters(filters)), resetFilters: (filters) => dispatch(resetFilters(filters)) })),
|
|
35458
|
-
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default["default"].createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading, onEditAccommodation: handleEditAccommodation })),
|
|
35721
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default["default"].createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving, onEditAccommodation: handleEditAccommodation })),
|
|
35459
35722
|
React__default["default"].createElement("div", { className: "search__results" },
|
|
35460
35723
|
isMobile && (React__default["default"].createElement("div", { className: "search__result-row" },
|
|
35461
35724
|
React__default["default"].createElement("div", { className: "search__results__actions" },
|
|
@@ -35529,7 +35792,11 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35529
35792
|
React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--extended" },
|
|
35530
35793
|
selectedReturnKey && selectedReturn && (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${selectedReturnKey}`, item: selectedReturn.return, guid: selectedReturn.outwardGuid, selectedGuid: selectedReturn.outwardGuid, isOutward: false, showSelectedState: true, price: selectedReturn.price })),
|
|
35531
35794
|
uniqueReturnFlights.map((result) => (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.return, onSelect: () => dispatch(setSelectedReturnKey(getFlightKey(result.return.segments))), guid: result.outwardGuid, isOutward: false, currentSelectedPrice: selectedReturn?.price, price: result.price })))))),
|
|
35532
|
-
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && (React__default["default"].createElement(TrajectResults, { isLoading: isLoading })),
|
|
35795
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && !trajectItineraryView && (React__default["default"].createElement(TrajectResults, { isLoading: isLoading })),
|
|
35796
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && trajectItineraryView && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
35797
|
+
React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
35798
|
+
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: handleComposeTraject }, translations.STEPS.PREVIOUS)),
|
|
35799
|
+
React__default["default"].createElement(FullItinerary, { isLoading: itineraryIsLoading }))),
|
|
35533
35800
|
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.packagingEntry && !context.trajectEntry && (React__default["default"].createElement(FullItinerary, { isLoading: itineraryIsLoading })))),
|
|
35534
35801
|
React__default["default"].createElement(FlyIn, { srpType: context.searchConfiguration.qsmType, isOpen: flyInIsOpen, setIsOpen: handleFlyInToggle, handleConfirm: () => handleConfirmHotelSwap(), onPanelRef: (el) => (panelRef.current = el), detailsLoading: detailsIsLoading, flyInType: flyInType, isPackageEditFlow: !!context.packagingEntry, sortByTypes: sortByTypes, activeSearchSeed: activeSearchSeed, toggleFilters: () => setFiltersOpen(!filtersOpen), filtersOpen: filtersOpen })))))))));
|
|
35535
35802
|
};
|