@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-esm/index.js
CHANGED
|
@@ -429,6 +429,7 @@ var SRP$f = {
|
|
|
429
429
|
TRAVEL_GROUP: "مجموعة المسافرين",
|
|
430
430
|
EXCURSION: "رحلة",
|
|
431
431
|
LOADING_EXCURSIONS: "جارٍ تحميل الرحلات...",
|
|
432
|
+
LOADING_ACTIVITIES: "جارٍ تحميل الأنشطة...",
|
|
432
433
|
LOADING_FLIGHTS: "جارٍ تحميل الرحلات الجوية...",
|
|
433
434
|
LOADING_ACCOMMODATIONS: "جارٍ تحميل الإقامات...",
|
|
434
435
|
LOADING_ITINERARY: "جارٍ تحميل خط سير الرحلة...",
|
|
@@ -873,6 +874,7 @@ var SRP$e = {
|
|
|
873
874
|
TRAVEL_GROUP: "Rejseselskab",
|
|
874
875
|
EXCURSION: "Udflugt",
|
|
875
876
|
LOADING_EXCURSIONS: "Indlæser udflugter...",
|
|
877
|
+
LOADING_ACTIVITIES: "Indlæser aktiviteter...",
|
|
876
878
|
LOADING_FLIGHTS: "Indlæser fly...",
|
|
877
879
|
LOADING_ACCOMMODATIONS: "Indlæser indkvarteringer...",
|
|
878
880
|
LOADING_ITINERARY: "Indlæser rejseplan...",
|
|
@@ -1317,6 +1319,7 @@ var SRP$d = {
|
|
|
1317
1319
|
TRAVEL_GROUP: "Reisegruppe",
|
|
1318
1320
|
EXCURSION: "Ausflug",
|
|
1319
1321
|
LOADING_EXCURSIONS: "Lade Ausflüge...",
|
|
1322
|
+
LOADING_ACTIVITIES: "Lade Aktivitäten...",
|
|
1320
1323
|
LOADING_FLIGHTS: "Lade Flüge...",
|
|
1321
1324
|
LOADING_ACCOMMODATIONS: "Lade Unterkünfte...",
|
|
1322
1325
|
LOADING_ITINERARY: "Lade Reiseverlauf...",
|
|
@@ -1765,6 +1768,7 @@ var SRP$c = {
|
|
|
1765
1768
|
TRAVEL_GROUP: "Travel group",
|
|
1766
1769
|
EXCURSION: "Excursion",
|
|
1767
1770
|
LOADING_EXCURSIONS: "Loading excursions...",
|
|
1771
|
+
LOADING_ACTIVITIES: "Loading activities...",
|
|
1768
1772
|
LOADING_FLIGHTS: "Loading flights...",
|
|
1769
1773
|
LOADING_ACCOMMODATIONS: "Loading accommodations...",
|
|
1770
1774
|
LOADING_ITINERARY: "Loading itinerary...",
|
|
@@ -2209,6 +2213,7 @@ var SRP$b = {
|
|
|
2209
2213
|
TRAVEL_GROUP: "Grupo de viaje",
|
|
2210
2214
|
EXCURSION: "Excursión",
|
|
2211
2215
|
LOADING_EXCURSIONS: "Cargando excursiones...",
|
|
2216
|
+
LOADING_ACTIVITIES: "Cargando actividades...",
|
|
2212
2217
|
LOADING_FLIGHTS: "Cargando vuelos...",
|
|
2213
2218
|
LOADING_ACCOMMODATIONS: "Cargando alojamientos...",
|
|
2214
2219
|
LOADING_ITINERARY: "Cargando itinerario...",
|
|
@@ -2657,6 +2662,7 @@ var SRP$a = {
|
|
|
2657
2662
|
TRAVEL_GROUP: "Groupe de voyageurs",
|
|
2658
2663
|
EXCURSION: "Excursion",
|
|
2659
2664
|
LOADING_EXCURSIONS: "Chargement des excursions...",
|
|
2665
|
+
LOADING_ACTIVITIES: "Chargement des activités...",
|
|
2660
2666
|
LOADING_FLIGHTS: "Chargement des vols...",
|
|
2661
2667
|
LOADING_ACCOMMODATIONS: "Chargement des hébergements...",
|
|
2662
2668
|
LOADING_ITINERARY: "Chargement de l’itinéraire...",
|
|
@@ -3101,6 +3107,7 @@ var SRP$9 = {
|
|
|
3101
3107
|
TRAVEL_GROUP: "Groupe de voyageurs",
|
|
3102
3108
|
EXCURSION: "Excursion",
|
|
3103
3109
|
LOADING_EXCURSIONS: "Chargement des excursions...",
|
|
3110
|
+
LOADING_ACTIVITIES: "Chargement des activités...",
|
|
3104
3111
|
LOADING_FLIGHTS: "Chargement des vols...",
|
|
3105
3112
|
LOADING_ACCOMMODATIONS: "Chargement des hébergements...",
|
|
3106
3113
|
LOADING_ITINERARY: "Chargement de l’itinéraire...",
|
|
@@ -3545,6 +3552,7 @@ var SRP$8 = {
|
|
|
3545
3552
|
TRAVEL_GROUP: "Ferðahópur",
|
|
3546
3553
|
EXCURSION: "Útflutningur",
|
|
3547
3554
|
LOADING_EXCURSIONS: "Hleðst inn í útflutninga...",
|
|
3555
|
+
LOADING_ACTIVITIES: "Hleð inn afþreyingu...",
|
|
3548
3556
|
LOADING_FLIGHTS: "Hleðst inn í flug...",
|
|
3549
3557
|
LOADING_ACCOMMODATIONS: "Hleðst inn í gistingar...",
|
|
3550
3558
|
LOADING_ITINERARY: "Hleðst inn í ferðaráætlun...",
|
|
@@ -3989,6 +3997,7 @@ var SRP$7 = {
|
|
|
3989
3997
|
TRAVEL_GROUP: "Gruppo di viaggio",
|
|
3990
3998
|
EXCURSION: "Escursione",
|
|
3991
3999
|
LOADING_EXCURSIONS: "Caricamento delle escursioni...",
|
|
4000
|
+
LOADING_ACTIVITIES: "Caricamento delle attività...",
|
|
3992
4001
|
LOADING_FLIGHTS: "Caricamento dei voli...",
|
|
3993
4002
|
LOADING_ACCOMMODATIONS: "Caricamento degli alloggi...",
|
|
3994
4003
|
LOADING_ITINERARY: "Caricamento dell'itinerario...",
|
|
@@ -4437,6 +4446,7 @@ var SRP$6 = {
|
|
|
4437
4446
|
TRAVEL_GROUP: "Reisgezelschap",
|
|
4438
4447
|
EXCURSION: "Excursie",
|
|
4439
4448
|
LOADING_EXCURSIONS: "Excursies laden...",
|
|
4449
|
+
LOADING_ACTIVITIES: "Activiteiten laden...",
|
|
4440
4450
|
LOADING_FLIGHTS: "Vluchten laden...",
|
|
4441
4451
|
LOADING_ACCOMMODATIONS: "Accommodaties laden...",
|
|
4442
4452
|
LOADING_ITINERARY: "Reisplan laden...",
|
|
@@ -4881,6 +4891,7 @@ var SRP$5 = {
|
|
|
4881
4891
|
TRAVEL_GROUP: "Reisgezelschap",
|
|
4882
4892
|
EXCURSION: "Excursie",
|
|
4883
4893
|
LOADING_EXCURSIONS: "Excursies laden...",
|
|
4894
|
+
LOADING_ACTIVITIES: "Activiteiten laden...",
|
|
4884
4895
|
LOADING_FLIGHTS: "Vluchten laden...",
|
|
4885
4896
|
LOADING_ACCOMMODATIONS: "Accommodaties laden...",
|
|
4886
4897
|
LOADING_ITINERARY: "Reisplan laden...",
|
|
@@ -5325,6 +5336,7 @@ var SRP$4 = {
|
|
|
5325
5336
|
TRAVEL_GROUP: "Reisefølge",
|
|
5326
5337
|
EXCURSION: "Utflukt",
|
|
5327
5338
|
LOADING_EXCURSIONS: "Laster utflukter...",
|
|
5339
|
+
LOADING_ACTIVITIES: "Laster aktiviteter...",
|
|
5328
5340
|
LOADING_FLIGHTS: "Laster flyvninger...",
|
|
5329
5341
|
LOADING_ACCOMMODATIONS: "Laster overnattinger...",
|
|
5330
5342
|
LOADING_ITINERARY: "Laster reiserute...",
|
|
@@ -5769,6 +5781,7 @@ var SRP$3 = {
|
|
|
5769
5781
|
TRAVEL_GROUP: "Grupa podróżnych",
|
|
5770
5782
|
EXCURSION: "Wycieczka",
|
|
5771
5783
|
LOADING_EXCURSIONS: "Ładowanie wycieczek...",
|
|
5784
|
+
LOADING_ACTIVITIES: "Ładowanie atrakcji...",
|
|
5772
5785
|
LOADING_FLIGHTS: "Ładowanie lotów...",
|
|
5773
5786
|
LOADING_ACCOMMODATIONS: "Ładowanie zakwaterowań...",
|
|
5774
5787
|
LOADING_ITINERARY: "Ładowanie planu podróży...",
|
|
@@ -6213,6 +6226,7 @@ var SRP$2 = {
|
|
|
6213
6226
|
TRAVEL_GROUP: "Grupo de viajantes",
|
|
6214
6227
|
EXCURSION: "Excursão",
|
|
6215
6228
|
LOADING_EXCURSIONS: "A carregar excursões...",
|
|
6229
|
+
LOADING_ACTIVITIES: "A carregar atividades...",
|
|
6216
6230
|
LOADING_FLIGHTS: "A carregar voos...",
|
|
6217
6231
|
LOADING_ACCOMMODATIONS: "A carregar alojamentos...",
|
|
6218
6232
|
LOADING_ITINERARY: "A carregar itinerário...",
|
|
@@ -6657,6 +6671,7 @@ var SRP$1 = {
|
|
|
6657
6671
|
TRAVEL_GROUP: "Resesällskap",
|
|
6658
6672
|
EXCURSION: "Utflykt",
|
|
6659
6673
|
LOADING_EXCURSIONS: "Laddar utflykter...",
|
|
6674
|
+
LOADING_ACTIVITIES: "Laddar aktiviteter...",
|
|
6660
6675
|
LOADING_FLIGHTS: "Laddar flyg...",
|
|
6661
6676
|
LOADING_ACCOMMODATIONS: "Laddar boenden...",
|
|
6662
6677
|
LOADING_ITINERARY: "Laddar resplan...",
|
|
@@ -7101,6 +7116,7 @@ var SRP = {
|
|
|
7101
7116
|
TRAVEL_GROUP: "旅行グループ",
|
|
7102
7117
|
EXCURSION: "エクスカーション",
|
|
7103
7118
|
LOADING_EXCURSIONS: "エクスカーションを読み込み中...",
|
|
7119
|
+
LOADING_ACTIVITIES: "アクティビティを読み込み中...",
|
|
7104
7120
|
LOADING_FLIGHTS: "フライトを読み込み中...",
|
|
7105
7121
|
LOADING_ACCOMMODATIONS: "宿泊施設を読み込み中...",
|
|
7106
7122
|
LOADING_ITINERARY: "旅程を読み込み中...",
|
|
@@ -27442,7 +27458,9 @@ const initialState$1 = {
|
|
|
27442
27458
|
trajectFlightAvailability: {},
|
|
27443
27459
|
trajectDaySuggestions: {},
|
|
27444
27460
|
trajectEditLineGuid: null,
|
|
27445
|
-
trajectActivitiesDayOrder: null
|
|
27461
|
+
trajectActivitiesDayOrder: null,
|
|
27462
|
+
trajectResolving: false,
|
|
27463
|
+
trajectItineraryView: false
|
|
27446
27464
|
};
|
|
27447
27465
|
const searchResultsSlice = createSlice({
|
|
27448
27466
|
name: 'searchResults',
|
|
@@ -27712,6 +27730,12 @@ const searchResultsSlice = createSlice({
|
|
|
27712
27730
|
setTrajectActivitiesDayOrder(state, action) {
|
|
27713
27731
|
state.trajectActivitiesDayOrder = action.payload;
|
|
27714
27732
|
},
|
|
27733
|
+
setTrajectResolving(state, action) {
|
|
27734
|
+
state.trajectResolving = action.payload;
|
|
27735
|
+
},
|
|
27736
|
+
setTrajectItineraryView(state, action) {
|
|
27737
|
+
state.trajectItineraryView = action.payload;
|
|
27738
|
+
},
|
|
27715
27739
|
updateTrajectNodeResult(state, action) {
|
|
27716
27740
|
const { lineGuid, result } = action.payload;
|
|
27717
27741
|
const node = state.trajectNodeAvailability[lineGuid];
|
|
@@ -27727,10 +27751,12 @@ const searchResultsSlice = createSlice({
|
|
|
27727
27751
|
state.trajectDaySuggestions = {};
|
|
27728
27752
|
state.trajectEditLineGuid = null;
|
|
27729
27753
|
state.trajectActivitiesDayOrder = null;
|
|
27754
|
+
state.trajectResolving = false;
|
|
27755
|
+
state.trajectItineraryView = false;
|
|
27730
27756
|
}
|
|
27731
27757
|
}
|
|
27732
27758
|
});
|
|
27733
|
-
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;
|
|
27759
|
+
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;
|
|
27734
27760
|
var searchResultsReducer = searchResultsSlice.reducer;
|
|
27735
27761
|
|
|
27736
27762
|
const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
|
|
@@ -28020,7 +28046,22 @@ const buildDestination = (line, node, result) => {
|
|
|
28020
28046
|
null;
|
|
28021
28047
|
return { id: 0, ...place, ...coordinates };
|
|
28022
28048
|
};
|
|
28023
|
-
const
|
|
28049
|
+
const hasDestination = (destination) => !!destination && (!!destination.id || (!!destination.latitude && !!destination.longitude));
|
|
28050
|
+
const buildTrajectClientConfig = (context) => ({
|
|
28051
|
+
host: context.tideConnection.host,
|
|
28052
|
+
apiKey: context.tideConnection.apiKey
|
|
28053
|
+
});
|
|
28054
|
+
const buildTrajectSearchContext = (context, trajectEntry) => ({
|
|
28055
|
+
transactionId: trajectEntry.entry.transactionId,
|
|
28056
|
+
officeId: context.tideConnection.officeId ?? 1,
|
|
28057
|
+
catalogueId: context.searchConfiguration.defaultCatalogueId ?? context.tideConnection.catalogueIds?.[0] ?? 1,
|
|
28058
|
+
searchConfigurationId: context.searchConfiguration.id,
|
|
28059
|
+
portalId: context.portalId ?? null,
|
|
28060
|
+
agentId: context.agentId ?? null,
|
|
28061
|
+
language: context.languageCode ?? 'en-GB',
|
|
28062
|
+
rooms: getPackagingRoomsFromEntry(trajectEntry.entry)
|
|
28063
|
+
});
|
|
28064
|
+
const buildTrajectNodeRequest = ({ node, line }, context, productCode, destination) => ({
|
|
28024
28065
|
transactionId: context.transactionId,
|
|
28025
28066
|
officeId: context.officeId,
|
|
28026
28067
|
agentId: context.agentId ?? null,
|
|
@@ -28031,25 +28072,69 @@ const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
|
|
|
28031
28072
|
language: context.language,
|
|
28032
28073
|
serviceType: node.serviceType,
|
|
28033
28074
|
fromDate: toDateOnlyString(line.from),
|
|
28034
|
-
|
|
28035
|
-
|
|
28075
|
+
// An excursion happens on a day rather than over a span. The traject gives its line an end a day
|
|
28076
|
+
// out, the way a night is counted, which asks the search for a window it does not have.
|
|
28077
|
+
toDate: toDateOnlyString(node.serviceType === EXCURSION_SERVICE_TYPE ? line.from : line.to),
|
|
28078
|
+
destination: destination ?? buildDestination(line, node),
|
|
28036
28079
|
productCode,
|
|
28037
28080
|
rooms: context.rooms,
|
|
28038
28081
|
tagIds: []
|
|
28039
28082
|
});
|
|
28040
|
-
|
|
28041
|
-
|
|
28042
|
-
|
|
28043
|
-
|
|
28044
|
-
|
|
28045
|
-
|
|
28046
|
-
|
|
28047
|
-
|
|
28048
|
-
|
|
28049
|
-
|
|
28050
|
-
|
|
28051
|
-
|
|
28083
|
+
const coversDay = ({ node, line }, dayOrder) => {
|
|
28084
|
+
const nights = Math.max(differenceInCalendarDays(new Date(line.to), new Date(line.from)), 1);
|
|
28085
|
+
return dayOrder >= node.dayOrder && dayOrder < node.dayOrder + nights;
|
|
28086
|
+
};
|
|
28087
|
+
const getDayDestinationItem = (items, dayOrder) => {
|
|
28088
|
+
const knowsWhereItIs = (x) => hasDestination(buildDestination(x.line, x.node));
|
|
28089
|
+
const stay = items.find((x) => x.node.serviceType === ACCOMMODATION_SERVICE_TYPE && coversDay(x, dayOrder) && knowsWhereItIs(x));
|
|
28090
|
+
if (stay)
|
|
28091
|
+
return stay;
|
|
28092
|
+
return ([...items]
|
|
28093
|
+
.filter((x) => x.node.dayOrder <= dayOrder && knowsWhereItIs(x))
|
|
28094
|
+
.sort((a, b) => a.node.dayOrder - b.node.dayOrder || a.node.order - b.node.order)
|
|
28095
|
+
.pop() ?? null);
|
|
28096
|
+
};
|
|
28097
|
+
const getDayDestination = (items, availability, dayOrder) => {
|
|
28098
|
+
const item = getDayDestinationItem(items, dayOrder);
|
|
28099
|
+
if (!item)
|
|
28100
|
+
return null;
|
|
28101
|
+
const resolved = availability[item.line.guid];
|
|
28102
|
+
const result = resolved?.results.find((x) => x.code === resolved.selectedCode) ?? null;
|
|
28103
|
+
const destination = buildDestination(item.line, item.node, result);
|
|
28104
|
+
return hasDestination(destination) ? destination : null;
|
|
28105
|
+
};
|
|
28106
|
+
const buildTrajectDayExcursionRequest = (date, destination, context) => ({
|
|
28107
|
+
transactionId: context.transactionId,
|
|
28108
|
+
officeId: context.officeId,
|
|
28109
|
+
agentId: context.agentId ?? null,
|
|
28110
|
+
catalogueId: context.catalogueId,
|
|
28111
|
+
searchConfigurationId: context.searchConfigurationId,
|
|
28112
|
+
portalId: context.portalId ?? null,
|
|
28113
|
+
vendorConfigurationId: null,
|
|
28114
|
+
language: context.language,
|
|
28115
|
+
serviceType: EXCURSION_SERVICE_TYPE,
|
|
28116
|
+
fromDate: toDateOnlyString(date),
|
|
28117
|
+
toDate: toDateOnlyString(date),
|
|
28118
|
+
destination,
|
|
28119
|
+
productCode: '',
|
|
28120
|
+
rooms: context.rooms,
|
|
28121
|
+
tagIds: []
|
|
28122
|
+
});
|
|
28123
|
+
const getExcursionOptionGroups = (result) => {
|
|
28124
|
+
const groups = new Map();
|
|
28125
|
+
(result.rooms ?? [])
|
|
28126
|
+
.flatMap((room) => room.options ?? [])
|
|
28127
|
+
.forEach((option) => {
|
|
28128
|
+
const key = [...(option.paxIds ?? [])].sort((a, b) => a - b).join(',');
|
|
28129
|
+
groups.set(key, [...(groups.get(key) ?? []), option]);
|
|
28052
28130
|
});
|
|
28131
|
+
return [...groups.values()];
|
|
28132
|
+
};
|
|
28133
|
+
const excursionNeedsChoice = (result) => getExcursionOptionGroups(result).some((group) => group.length > 1 && !group.some((option) => option.isSelected));
|
|
28134
|
+
const buildTrajectExcursionLines = (result) => {
|
|
28135
|
+
const options = getExcursionOptionGroups(result)
|
|
28136
|
+
.map((group) => group.find((x) => x.isSelected) ?? (group.length === 1 ? group[0] : null))
|
|
28137
|
+
.filter((x) => !!x);
|
|
28053
28138
|
if (!options.length)
|
|
28054
28139
|
return [];
|
|
28055
28140
|
const guids = options.map((option) => option.guid || crypto.randomUUID());
|
|
@@ -28078,6 +28163,21 @@ const buildTrajectExcursionLines = (result) => {
|
|
|
28078
28163
|
flightInformation: null
|
|
28079
28164
|
}));
|
|
28080
28165
|
};
|
|
28166
|
+
const buildExcursionSearchParams = (result) => ({
|
|
28167
|
+
date: result.fromDate,
|
|
28168
|
+
fromDate: result.fromDate,
|
|
28169
|
+
toDate: result.toDate,
|
|
28170
|
+
countryId: result.countryId,
|
|
28171
|
+
regionId: result.regionId,
|
|
28172
|
+
oordId: result.oordId,
|
|
28173
|
+
locationId: result.locationId,
|
|
28174
|
+
locationName: result.locationName,
|
|
28175
|
+
accommodationCode: null,
|
|
28176
|
+
accommodationName: null,
|
|
28177
|
+
hotelCode: result.code,
|
|
28178
|
+
hotelName: result.name,
|
|
28179
|
+
rooms: result.rooms ?? []
|
|
28180
|
+
});
|
|
28081
28181
|
const buildDayActivityCards = (items, availability, suggestions) => {
|
|
28082
28182
|
const cards = [];
|
|
28083
28183
|
const seen = new Set();
|
|
@@ -28094,11 +28194,27 @@ const buildDayActivityCards = (items, availability, suggestions) => {
|
|
|
28094
28194
|
results.filter((x) => !!findCandidateForResult(item.node, x)).forEach((result) => push(result, item));
|
|
28095
28195
|
});
|
|
28096
28196
|
suggestions.forEach((result) => push(result));
|
|
28097
|
-
|
|
28098
|
-
// nothing, as they are the same search, but a node can resolve where a day has no place to look.
|
|
28099
|
-
items.forEach((item) => (availability[item.line.guid]?.results ?? []).forEach((result) => push(result, item)));
|
|
28197
|
+
items.forEach((item) => (availability[item.line.guid]?.results ?? []).forEach((result) => push(result)));
|
|
28100
28198
|
return cards;
|
|
28101
28199
|
};
|
|
28200
|
+
/**
|
|
28201
|
+
* Where to search for a node.
|
|
28202
|
+
*
|
|
28203
|
+
* Normally the node says so itself, through the product it was configured with. An excursion slot
|
|
28204
|
+
* left empty on the traject says nothing at all — no code, no alternatives, and a line with no
|
|
28205
|
+
* place on it — so it falls back to wherever the party is staying that day, the same anchor the
|
|
28206
|
+
* day's own activity search uses.
|
|
28207
|
+
*/
|
|
28208
|
+
const getNodeSearchDestination = (items, item) => {
|
|
28209
|
+
const own = buildDestination(item.line, item.node);
|
|
28210
|
+
if (hasDestination(own))
|
|
28211
|
+
return own;
|
|
28212
|
+
return getDayDestination(items, {}, item.node.dayOrder) ?? own;
|
|
28213
|
+
};
|
|
28214
|
+
const getConfiguredExcursionCodes = (items, dayOrder) => new Set(items
|
|
28215
|
+
.filter((x) => x.node.dayOrder === dayOrder && x.node.serviceType === EXCURSION_SERVICE_TYPE)
|
|
28216
|
+
.flatMap((x) => [x.node.code, ...getNodeCandidates(x.node).map((candidate) => candidate.code)])
|
|
28217
|
+
.filter((code) => !!code));
|
|
28102
28218
|
const getNodeCandidates = (node) => {
|
|
28103
28219
|
const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
|
|
28104
28220
|
if (configured.length)
|
|
@@ -28207,6 +28323,51 @@ const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
|
28207
28323
|
outward: { date: dateToDateStruct(new Date(line.from)) },
|
|
28208
28324
|
return: null
|
|
28209
28325
|
});
|
|
28326
|
+
/**
|
|
28327
|
+
* The entry as the backend can price it.
|
|
28328
|
+
*
|
|
28329
|
+
* A search caches an EntryLine per option and hands back that line's guid on the option. The
|
|
28330
|
+
* backend then rebuilds the entry by looking each line up in that cache on its guid, so a line
|
|
28331
|
+
* it cannot find is dropped — PackagingEntryBuilder.SyncEntryLines skips it, and an entry whose
|
|
28332
|
+
* lines all came off a traject prices as nothing at all.
|
|
28333
|
+
*
|
|
28334
|
+
* A traject entry is rendered before any search runs, so its lines carry the guids the traject
|
|
28335
|
+
* mapper gave them. This swaps in the guid of whatever each line resolved onto, leaving the
|
|
28336
|
+
* lines the traveller added themselves alone — those were built from a search result and already
|
|
28337
|
+
* carry the right one.
|
|
28338
|
+
*/
|
|
28339
|
+
const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightAvailability) => {
|
|
28340
|
+
const cachedGuids = new Map();
|
|
28341
|
+
getTrajectNodesWithLines(trajectEntry).forEach((item) => {
|
|
28342
|
+
if (isTrajectFlightNode(item.node)) {
|
|
28343
|
+
// A flight search caches the outward line under the guid it reports as outwardGuid.
|
|
28344
|
+
const guid = flightAvailability[item.line.guid]?.selectedGuid;
|
|
28345
|
+
if (guid)
|
|
28346
|
+
cachedGuids.set(item.line.guid, guid);
|
|
28347
|
+
return;
|
|
28348
|
+
}
|
|
28349
|
+
const availability = nodeAvailability[item.line.guid];
|
|
28350
|
+
const result = availability?.results.find((x) => x.code === availability.selectedCode);
|
|
28351
|
+
if (!result)
|
|
28352
|
+
return;
|
|
28353
|
+
// Room i took option i when the result was stamped on, so it takes option i here too.
|
|
28354
|
+
item.lines.forEach((line, index) => {
|
|
28355
|
+
const guid = getOptionForRoom(result, index)?.guid;
|
|
28356
|
+
if (guid)
|
|
28357
|
+
cachedGuids.set(line.guid, guid);
|
|
28358
|
+
});
|
|
28359
|
+
});
|
|
28360
|
+
if (!cachedGuids.size)
|
|
28361
|
+
return entry;
|
|
28362
|
+
return {
|
|
28363
|
+
...entry,
|
|
28364
|
+
lines: (entry.lines ?? []).map((line) => ({
|
|
28365
|
+
...line,
|
|
28366
|
+
guid: cachedGuids.get(line.guid) ?? line.guid,
|
|
28367
|
+
parentGuid: (line.parentGuid && cachedGuids.get(line.parentGuid)) ?? line.parentGuid
|
|
28368
|
+
}))
|
|
28369
|
+
};
|
|
28370
|
+
};
|
|
28210
28371
|
const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
28211
28372
|
const applyFlightToLine = (line, flight) => {
|
|
28212
28373
|
const segments = flight.outward?.segments ?? [];
|
|
@@ -31033,10 +31194,9 @@ const getOptionPaxIds = (option) => {
|
|
|
31033
31194
|
const optionAppliesToPax = (option, paxId) => {
|
|
31034
31195
|
return getOptionPaxIds(option).includes(paxId);
|
|
31035
31196
|
};
|
|
31036
|
-
const optionAppliesToAllTravellers = (option,
|
|
31197
|
+
const optionAppliesToAllTravellers = (option, travellerIds) => {
|
|
31037
31198
|
const paxIds = getOptionPaxIds(option);
|
|
31038
|
-
|
|
31039
|
-
return paxIds.length === expected.length && paxIds.every((id, index) => id === expected[index]);
|
|
31199
|
+
return paxIds.length === travellerIds.length && travellerIds.every((id) => paxIds.includes(id));
|
|
31040
31200
|
};
|
|
31041
31201
|
const groupOptionsByExcursion = (options) => {
|
|
31042
31202
|
const groupedMap = new Map();
|
|
@@ -31061,26 +31221,26 @@ const ExcursionDetails = () => {
|
|
|
31061
31221
|
return null;
|
|
31062
31222
|
}
|
|
31063
31223
|
const translations = getTranslations(context.languageCode ?? 'en-GB');
|
|
31064
|
-
const
|
|
31224
|
+
const travellerIds = editablePackagingEntry.pax.map((pax) => pax.id);
|
|
31065
31225
|
const allOptions = useMemo(() => {
|
|
31066
31226
|
return selectedExcursionSearchResult.rooms.flatMap((room) => room.options ?? []);
|
|
31067
31227
|
}, [selectedExcursionSearchResult]);
|
|
31068
31228
|
const sharedOptions = useMemo(() => {
|
|
31069
|
-
return allOptions.filter((option) => optionAppliesToAllTravellers(option,
|
|
31070
|
-
}, [allOptions,
|
|
31229
|
+
return allOptions.filter((option) => optionAppliesToAllTravellers(option, travellerIds));
|
|
31230
|
+
}, [allOptions, travellerIds]);
|
|
31071
31231
|
const sharedExcursions = useMemo(() => {
|
|
31072
31232
|
return groupOptionsByExcursion(sharedOptions);
|
|
31073
31233
|
}, [sharedOptions]);
|
|
31074
31234
|
const paxGroups = useMemo(() => {
|
|
31075
31235
|
return editablePackagingEntry.pax.map((pax) => {
|
|
31076
|
-
const paxOptions = allOptions.filter((option) => optionAppliesToPax(option, pax.id) && !optionAppliesToAllTravellers(option,
|
|
31236
|
+
const paxOptions = allOptions.filter((option) => optionAppliesToPax(option, pax.id) && !optionAppliesToAllTravellers(option, travellerIds));
|
|
31077
31237
|
return {
|
|
31078
31238
|
pax,
|
|
31079
31239
|
paxId: pax.id,
|
|
31080
31240
|
excursions: groupOptionsByExcursion(paxOptions)
|
|
31081
31241
|
};
|
|
31082
31242
|
});
|
|
31083
|
-
}, [editablePackagingEntry.pax, allOptions,
|
|
31243
|
+
}, [editablePackagingEntry.pax, allOptions, travellerIds]);
|
|
31084
31244
|
const getSelectedSharedOption = () => {
|
|
31085
31245
|
return sharedOptions.find((option) => option.isSelected);
|
|
31086
31246
|
};
|
|
@@ -31088,11 +31248,11 @@ const ExcursionDetails = () => {
|
|
|
31088
31248
|
return sharedOptions.find((option) => option.accommodationCode === accommodationCode && option.isSelected);
|
|
31089
31249
|
};
|
|
31090
31250
|
const getSelectedOptionForPax = (paxId) => {
|
|
31091
|
-
return allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option,
|
|
31251
|
+
return allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerIds) && option.isSelected);
|
|
31092
31252
|
};
|
|
31093
31253
|
const getSelectedOptionForExcursion = (paxId, accommodationCode) => {
|
|
31094
31254
|
return allOptions.find((option) => optionAppliesToPax(option, paxId) &&
|
|
31095
|
-
!optionAppliesToAllTravellers(option,
|
|
31255
|
+
!optionAppliesToAllTravellers(option, travellerIds) &&
|
|
31096
31256
|
option.accommodationCode === accommodationCode &&
|
|
31097
31257
|
option.isSelected);
|
|
31098
31258
|
};
|
|
@@ -31102,7 +31262,7 @@ const ExcursionDetails = () => {
|
|
|
31102
31262
|
rooms: selectedExcursionSearchResult.rooms.map((room) => ({
|
|
31103
31263
|
...room,
|
|
31104
31264
|
options: room.options.map((option) => {
|
|
31105
|
-
const isSharedOption = optionAppliesToAllTravellers(option,
|
|
31265
|
+
const isSharedOption = optionAppliesToAllTravellers(option, travellerIds);
|
|
31106
31266
|
if (paxId === undefined) {
|
|
31107
31267
|
if (!isSharedOption) {
|
|
31108
31268
|
return option;
|
|
@@ -31149,7 +31309,7 @@ const ExcursionDetails = () => {
|
|
|
31149
31309
|
targetPrice = selectedOption.price;
|
|
31150
31310
|
}
|
|
31151
31311
|
else {
|
|
31152
|
-
const firstOption = allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option,
|
|
31312
|
+
const firstOption = allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerIds) && option.accommodationCode === accommodationCode);
|
|
31153
31313
|
targetPrice = firstOption?.price || 0;
|
|
31154
31314
|
}
|
|
31155
31315
|
return targetPrice - (currentSelectedPrice || 0);
|
|
@@ -31171,6 +31331,13 @@ const ExcursionDetails = () => {
|
|
|
31171
31331
|
return 'flyin__acco__price';
|
|
31172
31332
|
};
|
|
31173
31333
|
const handleConfirm = () => {
|
|
31334
|
+
if (context.trajectEntry) {
|
|
31335
|
+
const lines = buildTrajectExcursionLines(selectedExcursionSearchResult);
|
|
31336
|
+
if (lines.length)
|
|
31337
|
+
dispatch(addEditableEntryLines(lines));
|
|
31338
|
+
dispatch(setFlyInIsOpen(false));
|
|
31339
|
+
return;
|
|
31340
|
+
}
|
|
31174
31341
|
const dayKey = getExcursionDayKey(excursionSearchParams.date);
|
|
31175
31342
|
dispatch(confirmExcursionForDay({
|
|
31176
31343
|
dayKey,
|
|
@@ -31412,6 +31579,12 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
31412
31579
|
dispatch(removeEditableEntryLines(added.map((line) => line.guid)));
|
|
31413
31580
|
return;
|
|
31414
31581
|
}
|
|
31582
|
+
if (excursionNeedsChoice(result)) {
|
|
31583
|
+
dispatch(setExcursionSearchParams(buildExcursionSearchParams(result)));
|
|
31584
|
+
dispatch(setSelectedExcursionSearchResult(result));
|
|
31585
|
+
dispatch(setFlyInType('excursion-details'));
|
|
31586
|
+
return;
|
|
31587
|
+
}
|
|
31415
31588
|
const lines = buildTrajectExcursionLines(result);
|
|
31416
31589
|
if (lines.length)
|
|
31417
31590
|
dispatch(addEditableEntryLines(lines));
|
|
@@ -31426,7 +31599,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
31426
31599
|
dispatch(setFlyInIsOpen(false));
|
|
31427
31600
|
};
|
|
31428
31601
|
if (isLoading || suggestions?.status === 'loading') {
|
|
31429
|
-
return React__default.createElement(React__default.Fragment, null, context.customSpinner ?? React__default.createElement(Spinner, { label: translations.SRP.
|
|
31602
|
+
return React__default.createElement(React__default.Fragment, null, context.customSpinner ?? React__default.createElement(Spinner, { label: translations.SRP.LOADING_ACTIVITIES }));
|
|
31430
31603
|
}
|
|
31431
31604
|
return (React__default.createElement("div", { className: "flyin__content" },
|
|
31432
31605
|
React__default.createElement("div", { className: "search__result-row" },
|
|
@@ -33374,6 +33547,27 @@ const DayByDayExcursions = () => {
|
|
|
33374
33547
|
})));
|
|
33375
33548
|
};
|
|
33376
33549
|
|
|
33550
|
+
/**
|
|
33551
|
+
* The entry to send to the backend, as opposed to the one the page works with.
|
|
33552
|
+
*
|
|
33553
|
+
* They differ only for a traject: the page keeps the line guids the traject was rendered with,
|
|
33554
|
+
* because that is what joins its nodes to its lines, while pricing and booking need the guids the
|
|
33555
|
+
* searches cached their lines under. Anything else passes through untouched, so this can be used
|
|
33556
|
+
* wherever the entry leaves the component without checking which flow is running.
|
|
33557
|
+
*/
|
|
33558
|
+
const useBookableEntry = () => {
|
|
33559
|
+
const context = useContext(SearchResultsConfigurationContext);
|
|
33560
|
+
const { editablePackagingEntry, trajectNodeAvailability, trajectFlightAvailability } = useSelector((state) => state.searchResults);
|
|
33561
|
+
const trajectEntry = context?.trajectEntry;
|
|
33562
|
+
return useMemo(() => {
|
|
33563
|
+
if (!editablePackagingEntry)
|
|
33564
|
+
return null;
|
|
33565
|
+
if (!trajectEntry)
|
|
33566
|
+
return editablePackagingEntry;
|
|
33567
|
+
return withCachedEntryLineGuids(editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability);
|
|
33568
|
+
}, [editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability]);
|
|
33569
|
+
};
|
|
33570
|
+
|
|
33377
33571
|
const renderEditablePackagingEntrySummaryOptions = (editablePackagingEntry, priceDetails, translations, currencyCode) => {
|
|
33378
33572
|
const priceDetailsByProduct = groupBy(priceDetails?.details ?? [], (detail) => `${detail.productCode}|${detail.accommodationCode}`);
|
|
33379
33573
|
return (editablePackagingEntry?.lines ?? []).map((line) => {
|
|
@@ -33758,6 +33952,8 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
33758
33952
|
setSelectedPackagingAccoResult(selectedPackagingAccoResult);
|
|
33759
33953
|
}
|
|
33760
33954
|
}, [selectedPackagingAccoResultCode, packagingAccoResults]);
|
|
33955
|
+
// What the page holds versus what the backend can look up; they differ for a traject.
|
|
33956
|
+
const bookableEntry = useBookableEntry();
|
|
33761
33957
|
if (!context || !editablePackagingEntry || !priceDetails || !config)
|
|
33762
33958
|
return React__default.createElement(Spinner, { label: translations.SUMMARY.PROCESS_BOOKING });
|
|
33763
33959
|
const handleSummarySubmit = async (e) => {
|
|
@@ -33766,20 +33962,15 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
33766
33962
|
if (typeof window !== 'undefined') {
|
|
33767
33963
|
window.scrollTo(0, 0);
|
|
33768
33964
|
}
|
|
33769
|
-
|
|
33770
|
-
|
|
33771
|
-
remarks
|
|
33772
|
-
};
|
|
33965
|
+
// Held apart from the entry itself so they can be put on both copies of it.
|
|
33966
|
+
let bookingFields = { remarks };
|
|
33773
33967
|
if (context.generatePaymentUrl && typeof window !== 'undefined') {
|
|
33774
33968
|
const redirectUrl = new URL(window.location.href);
|
|
33775
33969
|
redirectUrl.searchParams.set('bookingConfirmation', 'true');
|
|
33776
33970
|
redirectUrl.searchParams.set('link', '');
|
|
33777
|
-
|
|
33778
|
-
...updatedEditablePackagingEntry,
|
|
33779
|
-
redirectUrl: redirectUrl.toString(),
|
|
33780
|
-
returnPaymentUrl: true
|
|
33781
|
-
};
|
|
33971
|
+
bookingFields = { ...bookingFields, redirectUrl: redirectUrl.toString(), returnPaymentUrl: true };
|
|
33782
33972
|
}
|
|
33973
|
+
const updatedEditablePackagingEntry = { ...editablePackagingEntry, ...bookingFields };
|
|
33783
33974
|
dispatch(setEditablePackagingEntry(updatedEditablePackagingEntry));
|
|
33784
33975
|
try {
|
|
33785
33976
|
const request = {
|
|
@@ -33787,7 +33978,8 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
33787
33978
|
officeId: context.tideConnection.officeId,
|
|
33788
33979
|
catalogueId: context.searchConfiguration.defaultCatalogueId ?? 0,
|
|
33789
33980
|
agentId: context.agentId,
|
|
33790
|
-
|
|
33981
|
+
// The page keeps the entry it works with; the backend gets the one it can look up.
|
|
33982
|
+
payload: { ...(bookableEntry ?? editablePackagingEntry), ...bookingFields }
|
|
33791
33983
|
};
|
|
33792
33984
|
const bookingResponse = await build.bookPackagingEntry(config, request);
|
|
33793
33985
|
dispatch(setBookingNumber(bookingResponse.number));
|
|
@@ -33819,6 +34011,41 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
33819
34011
|
React__default.createElement(WLSidebar, { activeSearchSeed: activeSearchSeed, packagingAccoResult: selectedPackagingAccoResult }))));
|
|
33820
34012
|
};
|
|
33821
34013
|
|
|
34014
|
+
const useTrajectDayActivities = () => {
|
|
34015
|
+
const context = useContext(SearchResultsConfigurationContext);
|
|
34016
|
+
const dispatch = useDispatch();
|
|
34017
|
+
const { trajectDaySuggestions, trajectNodeAvailability } = useSelector((state) => state.searchResults);
|
|
34018
|
+
const trajectEntry = context?.trajectEntry;
|
|
34019
|
+
const showApiItems = !!context?.showApiItems;
|
|
34020
|
+
const loadDay = useCallback(async (day) => {
|
|
34021
|
+
if (!context || !trajectEntry)
|
|
34022
|
+
return;
|
|
34023
|
+
// Already asked for, or already answered: leave it be.
|
|
34024
|
+
if (trajectDaySuggestions[day.order])
|
|
34025
|
+
return;
|
|
34026
|
+
const nodesWithLines = getTrajectNodesWithLines(trajectEntry);
|
|
34027
|
+
const destination = getDayDestination(nodesWithLines, trajectNodeAvailability, day.order);
|
|
34028
|
+
if (!destination)
|
|
34029
|
+
return;
|
|
34030
|
+
dispatch(setTrajectDaySuggestionsLoading(day.order));
|
|
34031
|
+
try {
|
|
34032
|
+
const results = (await build.searchPackagingExcursions(buildTrajectClientConfig(context), buildTrajectDayExcursionRequest(day.date, destination, buildTrajectSearchContext(context, trajectEntry)))) ?? [];
|
|
34033
|
+
// With external items switched off a day only offers what Tide holds itself, and whatever
|
|
34034
|
+
// the traject already books that day has a card of its own further up the block.
|
|
34035
|
+
const configured = getConfiguredExcursionCodes(nodesWithLines, day.order);
|
|
34036
|
+
dispatch(setTrajectDaySuggestions({
|
|
34037
|
+
dayOrder: day.order,
|
|
34038
|
+
results: results.filter((x) => showApiItems || !isExternalResult(x)).filter((x) => !configured.has(x.code))
|
|
34039
|
+
}));
|
|
34040
|
+
}
|
|
34041
|
+
catch (error) {
|
|
34042
|
+
console.error('Failed to load traject day activities', day.order, error);
|
|
34043
|
+
dispatch(setTrajectDaySuggestions({ dayOrder: day.order, results: [] }));
|
|
34044
|
+
}
|
|
34045
|
+
}, [context, trajectEntry, showApiItems, trajectDaySuggestions, trajectNodeAvailability, dispatch]);
|
|
34046
|
+
return loadDay;
|
|
34047
|
+
};
|
|
34048
|
+
|
|
33822
34049
|
const getNodeIcon = (node) => {
|
|
33823
34050
|
if (isTrajectFlightNode(node))
|
|
33824
34051
|
return 'ui-flight';
|
|
@@ -33834,9 +34061,10 @@ const MAX_DAY_ACTIVITIES = 6;
|
|
|
33834
34061
|
const TrajectResults = ({ isLoading }) => {
|
|
33835
34062
|
const context = useContext(SearchResultsConfigurationContext);
|
|
33836
34063
|
const dispatch = useDispatch();
|
|
34064
|
+
const loadDay = useTrajectDayActivities();
|
|
33837
34065
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
33838
34066
|
const locale = getLocale(context?.languageCode ?? 'en-GB');
|
|
33839
|
-
const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry } = useSelector((state) => state.searchResults);
|
|
34067
|
+
const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry, trajectResolving } = useSelector((state) => state.searchResults);
|
|
33840
34068
|
const trajectEntry = context?.trajectEntry;
|
|
33841
34069
|
const hideShowMoreResults = !!context?.hideShowMoreResults;
|
|
33842
34070
|
const nodesWithLines = useMemo(() => (trajectEntry ? getTrajectNodesWithLines(trajectEntry) : []), [trajectEntry]);
|
|
@@ -33950,7 +34178,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33950
34178
|
React__default.createElement(Icon, { name: getNodeIcon(node), height: 16 }),
|
|
33951
34179
|
React__default.createElement("h3", null,
|
|
33952
34180
|
React__default.createElement("strong", null, headerTitle || node.name))))),
|
|
33953
|
-
status === 'loading' &&
|
|
34181
|
+
status === 'loading' && React__default.createElement(Spinner, { label: translations.SRP.LOADING_ACCOMMODATIONS }),
|
|
33954
34182
|
status === 'unavailable' && React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
|
|
33955
34183
|
status === 'resolved' && selected && (React__default.createElement(React__default.Fragment, null,
|
|
33956
34184
|
availability.preferredUnavailable && node.preferredAccommodationName && (React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
@@ -33986,8 +34214,6 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33986
34214
|
React__default.createElement("div", { className: "search__results__label__text" },
|
|
33987
34215
|
React__default.createElement(Icon, { name: "ui-flight", height: 16 }),
|
|
33988
34216
|
React__default.createElement("h3", null,
|
|
33989
|
-
translations.SRP.SELECT,
|
|
33990
|
-
' ',
|
|
33991
34217
|
React__default.createElement("strong", null,
|
|
33992
34218
|
node.departureAirportCode,
|
|
33993
34219
|
" - ",
|
|
@@ -34013,10 +34239,22 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34013
34239
|
dispatch(removeEditableEntryLines(added.map((line) => line.guid)));
|
|
34014
34240
|
return;
|
|
34015
34241
|
}
|
|
34242
|
+
if (excursionNeedsChoice(result)) {
|
|
34243
|
+
dispatch(setExcursionSearchParams(buildExcursionSearchParams(result)));
|
|
34244
|
+
dispatch(setSelectedExcursionSearchResult(result));
|
|
34245
|
+
dispatch(setFlyInType('excursion-details'));
|
|
34246
|
+
dispatch(setFlyInIsOpen(true));
|
|
34247
|
+
return;
|
|
34248
|
+
}
|
|
34016
34249
|
const lines = buildTrajectExcursionLines(result);
|
|
34017
34250
|
if (lines.length)
|
|
34018
34251
|
dispatch(addEditableEntryLines(lines));
|
|
34019
34252
|
};
|
|
34253
|
+
const handleShowItinerary = () => {
|
|
34254
|
+
dispatch(setTrajectItineraryView(true));
|
|
34255
|
+
if (typeof window !== 'undefined')
|
|
34256
|
+
window.scrollTo(0, 0);
|
|
34257
|
+
};
|
|
34020
34258
|
const handleShowMoreActivities = (dayOrder) => {
|
|
34021
34259
|
dispatch(setTrajectActivitiesDayOrder(dayOrder));
|
|
34022
34260
|
dispatch(setFlyInType('traject-day-activities'));
|
|
@@ -34039,10 +34277,10 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34039
34277
|
const items = getDayExcursionItems(day.order);
|
|
34040
34278
|
const suggestions = trajectDaySuggestions[day.order];
|
|
34041
34279
|
const cards = buildDayActivityCards(items, trajectNodeAvailability, suggestions?.results ?? []);
|
|
34042
|
-
const
|
|
34043
|
-
|
|
34044
|
-
|
|
34045
|
-
if (!
|
|
34280
|
+
const nodesResolving = items.some((item) => (trajectNodeAvailability[item.line.guid]?.status ?? 'loading') === 'loading');
|
|
34281
|
+
const isSearching = suggestions?.status === 'loading';
|
|
34282
|
+
const canSearch = !!getDayDestination(nodesWithLines, trajectNodeAvailability, day.order);
|
|
34283
|
+
if (!items.length && !canSearch)
|
|
34046
34284
|
return null;
|
|
34047
34285
|
const visible = cards.slice(0, MAX_DAY_ACTIVITIES);
|
|
34048
34286
|
const hidden = cards.length - visible.length;
|
|
@@ -34055,16 +34293,16 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34055
34293
|
React__default.createElement(Icon, { name: "ui-excursion", height: 16 }),
|
|
34056
34294
|
React__default.createElement("h3", null,
|
|
34057
34295
|
React__default.createElement("strong", null, translations.SRP.ACTIVITIES)))),
|
|
34058
|
-
|
|
34059
|
-
|
|
34060
|
-
|
|
34061
|
-
|
|
34062
|
-
|
|
34063
|
-
|
|
34064
|
-
|
|
34065
|
-
|
|
34066
|
-
|
|
34067
|
-
|
|
34296
|
+
(nodesResolving || isSearching) && !cards.length && React__default.createElement(Spinner, { label: translations.SRP.LOADING_ACTIVITIES }),
|
|
34297
|
+
!!cards.length && React__default.createElement("div", { className: "search__results__cards search__results__cards--scroll" }, visible.map(renderActivityCard)),
|
|
34298
|
+
!nodesResolving && !isSearching && !cards.length && (!!items.length || !!suggestions) && (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)),
|
|
34299
|
+
React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
34300
|
+
!suggestions && canSearch && !cards.length && !hideShowMoreResults && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => loadDay(day) }, translations.SRP.SHOW_ACTIVITIES)),
|
|
34301
|
+
hidden > 0 && !hideShowMoreResults && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreActivities(day.order) },
|
|
34302
|
+
translations.SRP.SHOW_MORE,
|
|
34303
|
+
" (",
|
|
34304
|
+
hidden,
|
|
34305
|
+
")")))));
|
|
34068
34306
|
};
|
|
34069
34307
|
/**
|
|
34070
34308
|
* An activity the traject books is swapped for another, the way a hotel is; one the traveller
|
|
@@ -34076,32 +34314,35 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34076
34314
|
};
|
|
34077
34315
|
if (isLoading)
|
|
34078
34316
|
return React__default.createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
|
|
34079
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
34080
|
-
|
|
34081
|
-
|
|
34082
|
-
|
|
34083
|
-
|
|
34084
|
-
|
|
34085
|
-
|
|
34086
|
-
|
|
34087
|
-
|
|
34088
|
-
|
|
34089
|
-
|
|
34090
|
-
|
|
34091
|
-
|
|
34092
|
-
|
|
34093
|
-
|
|
34094
|
-
|
|
34095
|
-
|
|
34096
|
-
|
|
34097
|
-
|
|
34098
|
-
|
|
34099
|
-
|
|
34100
|
-
|
|
34101
|
-
|
|
34102
|
-
|
|
34103
|
-
|
|
34104
|
-
|
|
34317
|
+
return (React__default.createElement(React__default.Fragment, null,
|
|
34318
|
+
trajectEntry.traject.days.map((day) => {
|
|
34319
|
+
const stay = stayByDay.get(day.order);
|
|
34320
|
+
const dayNodes = (nodesByDay.get(day.order) ?? []).filter((node) => isRenderableNode(node) && lineByNodeId.has(node.nodeId));
|
|
34321
|
+
const stayLeadsDay = !!stay && (stay.night > 0 || dayNodes[0]?.nodeId === stay.item.node.nodeId);
|
|
34322
|
+
// Where the day's activities belong in the order: with the first excursion it carries.
|
|
34323
|
+
const firstExcursionNodeId = dayNodes.find((node) => node.serviceType === EXCURSION_SERVICE_TYPE)?.nodeId;
|
|
34324
|
+
const showDayHeader = stayLeadsDay || !!day.name?.trim();
|
|
34325
|
+
return (React__default.createElement(React__default.Fragment, { key: `day-${day.order}` },
|
|
34326
|
+
showDayHeader && renderDayHeader(day, stayLeadsDay ? stay : undefined),
|
|
34327
|
+
dayNodes.map((node) => {
|
|
34328
|
+
const item = lineByNodeId.get(node.nodeId);
|
|
34329
|
+
if (node.serviceType === ACCOMMODATION_SERVICE_TYPE) {
|
|
34330
|
+
const stayStart = stayStartByNodeId.get(node.nodeId);
|
|
34331
|
+
const titledByDayHeader = stayLeadsDay && stay.item.node.nodeId === node.nodeId;
|
|
34332
|
+
return renderServiceNode(item, !titledByDayHeader, stayStart && getStayTitle(stayStart));
|
|
34333
|
+
}
|
|
34334
|
+
// Every excursion the day holds is drawn once, in one block, where the first of
|
|
34335
|
+
// them falls in the order — so the activities still sit between the stay and the
|
|
34336
|
+
// flight that follow them.
|
|
34337
|
+
if (node.serviceType === EXCURSION_SERVICE_TYPE) {
|
|
34338
|
+
return node.nodeId === firstExcursionNodeId ? renderDayActivities(day) : null;
|
|
34339
|
+
}
|
|
34340
|
+
return renderFlightNode(item);
|
|
34341
|
+
}),
|
|
34342
|
+
firstExcursionNodeId === undefined && renderDayActivities(day)));
|
|
34343
|
+
}),
|
|
34344
|
+
React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
34345
|
+
React__default.createElement("button", { type: "button", className: "cta", disabled: trajectResolving, onClick: handleShowItinerary }, translations.STEPS.NEXT))));
|
|
34105
34346
|
};
|
|
34106
34347
|
|
|
34107
34348
|
const useTrajectAvailability = () => {
|
|
@@ -34115,6 +34356,7 @@ const useTrajectAvailability = () => {
|
|
|
34115
34356
|
return;
|
|
34116
34357
|
const controller = new AbortController();
|
|
34117
34358
|
dispatch(resetTrajectAvailability());
|
|
34359
|
+
dispatch(setTrajectResolving(true));
|
|
34118
34360
|
const config = {
|
|
34119
34361
|
host: context.tideConnection.host,
|
|
34120
34362
|
apiKey: context.tideConnection.apiKey
|
|
@@ -34141,42 +34383,51 @@ const useTrajectAvailability = () => {
|
|
|
34141
34383
|
const lineGuid = item.line.guid;
|
|
34142
34384
|
const search = item.node.serviceType === EXCURSION_SERVICE_TYPE ? build.searchPackagingExcursions : build.searchPackagingAccommodations;
|
|
34143
34385
|
dispatch(setTrajectNodeLoading(lineGuid));
|
|
34386
|
+
const destination = getNodeSearchDestination(nodesWithLines, item);
|
|
34387
|
+
const searchFor = async (productCode) => {
|
|
34388
|
+
try {
|
|
34389
|
+
const results = (await search(config, buildTrajectNodeRequest(item, searchContext, productCode, destination), controller.signal)) ?? [];
|
|
34390
|
+
return results.filter((x) => showApiItems || !isExternalResult(x));
|
|
34391
|
+
}
|
|
34392
|
+
catch (error) {
|
|
34393
|
+
if (!controller.signal.aborted)
|
|
34394
|
+
console.error('Traject product unavailable', item.node.name, productCode, error);
|
|
34395
|
+
return [];
|
|
34396
|
+
}
|
|
34397
|
+
};
|
|
34144
34398
|
try {
|
|
34145
34399
|
// With external items switched off the node only looks at products held inside Tide.
|
|
34146
34400
|
const candidates = getNodeCandidates(item.node).filter((x) => showApiItems || !isExternalCandidate(x));
|
|
34147
|
-
const
|
|
34148
|
-
|
|
34149
|
-
|
|
34150
|
-
|
|
34151
|
-
|
|
34152
|
-
|
|
34153
|
-
|
|
34154
|
-
|
|
34155
|
-
|
|
34156
|
-
}
|
|
34401
|
+
const areaResults = hideShowMoreResults ? [] : await searchFor('');
|
|
34402
|
+
if (controller.signal.aborted)
|
|
34403
|
+
return [];
|
|
34404
|
+
const configuredResults = [];
|
|
34405
|
+
const found = await Promise.all(candidates.map(async (candidate) => {
|
|
34406
|
+
const known = areaResults.find((x) => matchesCode(x, candidate.code));
|
|
34407
|
+
if (known)
|
|
34408
|
+
return known;
|
|
34409
|
+
return (await searchFor(candidate.code)).find((x) => matchesCode(x, candidate.code)) ?? null;
|
|
34157
34410
|
}));
|
|
34158
|
-
|
|
34159
|
-
|
|
34160
|
-
|
|
34411
|
+
if (controller.signal.aborted)
|
|
34412
|
+
return [];
|
|
34413
|
+
// Two configured codes can land on the same product — a hotel and one of its room types.
|
|
34414
|
+
found.forEach((result) => {
|
|
34415
|
+
if (!result || configuredResults.some((x) => x.code === result.code))
|
|
34416
|
+
return;
|
|
34417
|
+
configuredResults.push(result);
|
|
34418
|
+
});
|
|
34419
|
+
const configuredCodes = new Set(configuredResults.map((x) => x.code));
|
|
34420
|
+
const destinationResults = areaResults.filter((x) => !configuredCodes.has(x.code));
|
|
34161
34421
|
const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
|
|
34162
|
-
|
|
34163
|
-
|
|
34164
|
-
|
|
34165
|
-
// rather than quietly substituting a hotel nobody configured.
|
|
34166
|
-
const destinationResults = hideShowMoreResults
|
|
34167
|
-
? []
|
|
34168
|
-
: ((await search(config, buildTrajectNodeRequest(item, searchContext, ''), controller.signal)) ?? [])
|
|
34169
|
-
.filter((x) => showApiItems || !isExternalResult(x))
|
|
34170
|
-
.filter((x) => !configuredResults.some((configured) => configured.code === x.code));
|
|
34422
|
+
const preferredUnavailable = configuredResults.length
|
|
34423
|
+
? !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code))
|
|
34424
|
+
: candidates.length > 0;
|
|
34171
34425
|
const picked = configuredResults[0] ?? pickCheapest(destinationResults);
|
|
34172
|
-
const results = [...configuredResults, ...destinationResults];
|
|
34173
|
-
if (!configuredResults.length)
|
|
34174
|
-
preferredUnavailable = candidates.length > 0;
|
|
34175
34426
|
if (controller.signal.aborted)
|
|
34176
34427
|
return [];
|
|
34177
34428
|
dispatch(setTrajectNodeAvailability({
|
|
34178
34429
|
lineGuid,
|
|
34179
|
-
results,
|
|
34430
|
+
results: [...configuredResults, ...destinationResults],
|
|
34180
34431
|
selectedCode: picked?.code ?? null,
|
|
34181
34432
|
preferredUnavailable
|
|
34182
34433
|
}));
|
|
@@ -34220,11 +34471,11 @@ const useTrajectAvailability = () => {
|
|
|
34220
34471
|
}
|
|
34221
34472
|
};
|
|
34222
34473
|
(async () => {
|
|
34223
|
-
const
|
|
34224
|
-
const
|
|
34225
|
-
const unresolved = (await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)])).flat();
|
|
34474
|
+
const resolvable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node));
|
|
34475
|
+
const unresolved = (await Promise.all(resolvable.map((item) => (isTrajectFlightNode(item.node) ? resolveFlightNode(item) : resolveNode(item))))).flat();
|
|
34226
34476
|
if (controller.signal.aborted)
|
|
34227
34477
|
return;
|
|
34478
|
+
dispatch(setTrajectResolving(false));
|
|
34228
34479
|
// A node with no availability anywhere cannot be priced or booked, so its line comes off
|
|
34229
34480
|
// the entry. The card stays visible and reports the gap.
|
|
34230
34481
|
const emptyLineGuids = unresolved.filter(Boolean);
|
|
@@ -34240,10 +34491,12 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
34240
34491
|
const dispatch = useDispatch();
|
|
34241
34492
|
const context = useContext(SearchResultsConfigurationContext);
|
|
34242
34493
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
34243
|
-
const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry, trajectEditLineGuid } = useSelector((state) => state.searchResults);
|
|
34494
|
+
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 } = useSelector((state) => state.searchResults);
|
|
34244
34495
|
const isMobile = useMediaQuery('(max-width: 1200px)');
|
|
34245
34496
|
// Resolves live availability per traject node; no-op unless a traject entry is configured.
|
|
34246
34497
|
useTrajectAvailability();
|
|
34498
|
+
// The entry as the backend can price it: a traject swaps in the guids its searches cached.
|
|
34499
|
+
const bookableEntry = useBookableEntry();
|
|
34247
34500
|
const [initialFiltersSet, setInitialFiltersSet] = useState(false);
|
|
34248
34501
|
const [initialFlightFiltersSet, setInitialFlightFiltersSet] = useState(false);
|
|
34249
34502
|
const [filtersOpen, setFiltersOpen] = useState(false);
|
|
@@ -35010,6 +35263,10 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35010
35263
|
const fetchPriceDetails = async () => {
|
|
35011
35264
|
if (!context || !editablePackagingEntry || isEmpty$1(editablePackagingEntry.lines))
|
|
35012
35265
|
return;
|
|
35266
|
+
// A traject resolves one node at a time. Pricing each step would show a total that climbs
|
|
35267
|
+
// as the trip fills in, so the whole trip is priced once, when the last node is in.
|
|
35268
|
+
if (context.trajectEntry && trajectResolving)
|
|
35269
|
+
return;
|
|
35013
35270
|
setPricesAreLoading(true);
|
|
35014
35271
|
try {
|
|
35015
35272
|
const config = {
|
|
@@ -35021,7 +35278,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35021
35278
|
officeId: context.tideConnection.officeId,
|
|
35022
35279
|
catalogueId: context.searchConfiguration.defaultCatalogueId ?? first(context?.tideConnection?.catalogueIds) ?? 1,
|
|
35023
35280
|
agentId: context.agentId,
|
|
35024
|
-
payload: editablePackagingEntry
|
|
35281
|
+
payload: bookableEntry ?? editablePackagingEntry
|
|
35025
35282
|
};
|
|
35026
35283
|
const priceDetails = await build.getPriceDetails(config, request);
|
|
35027
35284
|
dispatch(setPriceDetails(priceDetails));
|
|
@@ -35035,8 +35292,9 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35035
35292
|
const fetchItinerary = async () => {
|
|
35036
35293
|
if (!context || !context.packagingEntry || !editablePackagingEntry || isEmpty$1(editablePackagingEntry.lines))
|
|
35037
35294
|
return;
|
|
35038
|
-
//
|
|
35039
|
-
|
|
35295
|
+
// While a traject is being composed its own day-by-day column is the itinerary; the generated
|
|
35296
|
+
// one is what the traveller reads the finished trip back from, so it waits until then.
|
|
35297
|
+
if (context.trajectEntry && (trajectResolving || !trajectItineraryView))
|
|
35040
35298
|
return;
|
|
35041
35299
|
setItineraryIsLoading(true);
|
|
35042
35300
|
try {
|
|
@@ -35049,7 +35307,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35049
35307
|
officeId: context.tideConnection.officeId,
|
|
35050
35308
|
catalogueId: context.searchConfiguration.defaultCatalogueId ?? first(context?.tideConnection?.catalogueIds) ?? 1,
|
|
35051
35309
|
agentId: context.agentId,
|
|
35052
|
-
payload: editablePackagingEntry
|
|
35310
|
+
payload: bookableEntry ?? editablePackagingEntry
|
|
35053
35311
|
};
|
|
35054
35312
|
const itinerary = await build.getItinerary(config, request);
|
|
35055
35313
|
dispatch(setItinerary(itinerary));
|
|
@@ -35062,7 +35320,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35062
35320
|
};
|
|
35063
35321
|
fetchPriceDetails();
|
|
35064
35322
|
fetchItinerary();
|
|
35065
|
-
}, [editablePackagingEntry]);
|
|
35323
|
+
}, [editablePackagingEntry, bookableEntry, trajectResolving, trajectItineraryView]);
|
|
35066
35324
|
// Flight selection
|
|
35067
35325
|
// const [selectedOutwardKey, setSelectedOutwardKey] = useState<string | null>(null);
|
|
35068
35326
|
// const [selectedReturnKey, setSelectedReturnKey] = useState<string | null>(null);
|
|
@@ -35411,6 +35669,11 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35411
35669
|
address: {}
|
|
35412
35670
|
};
|
|
35413
35671
|
};
|
|
35672
|
+
const handleComposeTraject = () => {
|
|
35673
|
+
dispatch(setTrajectItineraryView(false));
|
|
35674
|
+
if (typeof window !== 'undefined')
|
|
35675
|
+
window.scrollTo(0, 0);
|
|
35676
|
+
};
|
|
35414
35677
|
const handleShowMoreFlights = (flyInType) => {
|
|
35415
35678
|
dispatch(setFlyInType(flyInType));
|
|
35416
35679
|
dispatch(setFlyInIsOpen(true));
|
|
@@ -35426,7 +35689,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35426
35689
|
context.searchConfiguration.qsmType != build.PortalQsmType.AccommodationAndFlight && context.showFilters && (React__default.createElement(Filters, { initialFilters: initialFilters, filters: filters, isOpen: filtersOpen, handleSetIsOpen: () => setFiltersOpen(!filtersOpen),
|
|
35427
35690
|
// handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
|
|
35428
35691
|
isLoading: isLoading, setFilters: (filters) => dispatch(setFilters(filters)), resetFilters: (filters) => dispatch(resetFilters(filters)) })),
|
|
35429
|
-
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default.createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading, onEditAccommodation: handleEditAccommodation })),
|
|
35692
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default.createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving, onEditAccommodation: handleEditAccommodation })),
|
|
35430
35693
|
React__default.createElement("div", { className: "search__results" },
|
|
35431
35694
|
isMobile && (React__default.createElement("div", { className: "search__result-row" },
|
|
35432
35695
|
React__default.createElement("div", { className: "search__results__actions" },
|
|
@@ -35500,7 +35763,11 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35500
35763
|
React__default.createElement("div", { className: "search__results__cards search__results__cards--extended" },
|
|
35501
35764
|
selectedReturnKey && selectedReturn && (React__default.createElement(IndependentFlightOption, { key: `flight-${selectedReturnKey}`, item: selectedReturn.return, guid: selectedReturn.outwardGuid, selectedGuid: selectedReturn.outwardGuid, isOutward: false, showSelectedState: true, price: selectedReturn.price })),
|
|
35502
35765
|
uniqueReturnFlights.map((result) => (React__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 })))))),
|
|
35503
|
-
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && (React__default.createElement(TrajectResults, { isLoading: isLoading })),
|
|
35766
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && !trajectItineraryView && (React__default.createElement(TrajectResults, { isLoading: isLoading })),
|
|
35767
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && trajectItineraryView && (React__default.createElement(React__default.Fragment, null,
|
|
35768
|
+
React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
35769
|
+
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: handleComposeTraject }, translations.STEPS.PREVIOUS)),
|
|
35770
|
+
React__default.createElement(FullItinerary, { isLoading: itineraryIsLoading }))),
|
|
35504
35771
|
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.packagingEntry && !context.trajectEntry && (React__default.createElement(FullItinerary, { isLoading: itineraryIsLoading })))),
|
|
35505
35772
|
React__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 })))))))));
|
|
35506
35773
|
};
|