@qite/tide-booking-component 1.4.103 → 1.4.105
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 +2782 -1052
- package/build/build-cjs/src/search-results/components/excursions/day-by-day-excursions.d.ts +4 -0
- package/build/build-cjs/src/search-results/components/excursions/excursion-details.d.ts +3 -0
- package/build/build-cjs/src/search-results/components/excursions/excursion-results.d.ts +8 -0
- package/build/build-cjs/src/search-results/components/filters/filters.d.ts +2 -0
- package/build/build-cjs/src/search-results/components/hotel/hotel-accommodation-results.d.ts +1 -0
- package/build/build-cjs/src/search-results/store/search-results-selectors.d.ts +546 -0
- package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +55 -8
- package/build/build-cjs/src/search-results/types.d.ts +40 -2
- package/build/build-cjs/src/search-results/utils/query-utils.d.ts +1 -0
- package/build/build-cjs/src/search-results/utils/search-results-utils.d.ts +8 -6
- package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +4 -3
- package/build/build-cjs/src/shared/components/flyin/packaging-flights-flyin.d.ts +7 -0
- package/build/build-cjs/src/shared/utils/localization-util.d.ts +3 -0
- package/build/build-cjs/src/shared/utils/tide-api-utils.d.ts +6 -0
- package/build/build-esm/index.js +2735 -1023
- package/build/build-esm/src/search-results/components/excursions/day-by-day-excursions.d.ts +4 -0
- package/build/build-esm/src/search-results/components/excursions/excursion-details.d.ts +3 -0
- package/build/build-esm/src/search-results/components/excursions/excursion-results.d.ts +8 -0
- package/build/build-esm/src/search-results/components/filters/filters.d.ts +2 -0
- package/build/build-esm/src/search-results/components/hotel/hotel-accommodation-results.d.ts +1 -0
- package/build/build-esm/src/search-results/store/search-results-selectors.d.ts +546 -0
- package/build/build-esm/src/search-results/store/search-results-slice.d.ts +55 -8
- package/build/build-esm/src/search-results/types.d.ts +40 -2
- package/build/build-esm/src/search-results/utils/query-utils.d.ts +1 -0
- package/build/build-esm/src/search-results/utils/search-results-utils.d.ts +8 -6
- package/build/build-esm/src/shared/components/flyin/flyin.d.ts +4 -3
- package/build/build-esm/src/shared/components/flyin/packaging-flights-flyin.d.ts +7 -0
- package/build/build-esm/src/shared/utils/localization-util.d.ts +3 -0
- package/build/build-esm/src/shared/utils/tide-api-utils.d.ts +6 -0
- package/package.json +2 -2
- package/src/booking-wizard/features/flight-options/index.tsx +6 -2
- package/src/search-results/components/excursions/day-by-day-excursions.tsx +169 -0
- package/src/search-results/components/excursions/excursion-details.tsx +340 -0
- package/src/search-results/components/excursions/excursion-results.tsx +186 -0
- package/src/search-results/components/filters/filters.tsx +8 -9
- package/src/search-results/components/hotel/hotel-accommodation-results.tsx +81 -24
- package/src/search-results/components/hotel/hotel-card.tsx +0 -3
- package/src/search-results/components/icon.tsx +1 -4
- package/src/search-results/components/search-results-container/search-results-container.tsx +208 -130
- package/src/search-results/store/search-results-selectors.ts +84 -0
- package/src/search-results/store/search-results-slice.ts +138 -15
- package/src/search-results/types.ts +55 -2
- package/src/search-results/utils/query-utils.ts +1 -0
- package/src/search-results/utils/search-results-utils.ts +310 -58
- package/src/shared/components/flyin/accommodation-flyin.tsx +4 -2
- package/src/shared/components/flyin/flights-flyin.tsx +3 -1
- package/src/shared/components/flyin/flyin.tsx +116 -21
- package/src/shared/components/flyin/group-tour-flyin.tsx +3 -1
- package/src/shared/components/flyin/packaging-flights-flyin.tsx +164 -0
- package/src/shared/translations/ar-SA.json +4 -2
- package/src/shared/translations/da-DK.json +4 -2
- package/src/shared/translations/de-DE.json +4 -2
- package/src/shared/translations/en-GB.json +4 -2
- package/src/shared/translations/es-ES.json +4 -2
- package/src/shared/translations/fr-BE.json +4 -2
- package/src/shared/translations/fr-FR.json +4 -2
- package/src/shared/translations/is-IS.json +4 -2
- package/src/shared/translations/it-IT.json +4 -2
- package/src/shared/translations/ja-JP.json +4 -2
- package/src/shared/translations/nl-BE.json +4 -2
- package/src/shared/translations/nl-NL.json +4 -2
- package/src/shared/translations/no-NO.json +4 -2
- package/src/shared/translations/pl-PL.json +4 -2
- package/src/shared/translations/pt-PT.json +4 -2
- package/src/shared/translations/sv-SE.json +4 -2
- package/src/shared/utils/localization-util.ts +14 -0
- package/src/shared/utils/tide-api-utils.ts +8 -0
- package/styles/components/_flyin.scss +16 -0
- package/styles/components/_search.scss +15 -2
|
@@ -16,15 +16,22 @@ import {
|
|
|
16
16
|
setPackagingAccoSearchDetails,
|
|
17
17
|
setEditablePackagingEntry,
|
|
18
18
|
setTransactionId,
|
|
19
|
-
|
|
19
|
+
setFlyInType,
|
|
20
20
|
setPriceDetails,
|
|
21
21
|
setItinerary,
|
|
22
22
|
setFlightsLoading,
|
|
23
23
|
setPackagingFlightResults,
|
|
24
24
|
setSelectedPackagingFlight,
|
|
25
|
-
setSelectedPackagingAccoResult
|
|
25
|
+
setSelectedPackagingAccoResult,
|
|
26
|
+
setSelectedOutwardKey,
|
|
27
|
+
setSelectedReturnKey,
|
|
28
|
+
setFilteredPackagingFlightResults,
|
|
29
|
+
setInitialFlightFilters,
|
|
30
|
+
resetFlightFilters,
|
|
31
|
+
setFilters,
|
|
32
|
+
setInitialFilters
|
|
26
33
|
} from '../../store/search-results-slice';
|
|
27
|
-
import {
|
|
34
|
+
import { FlyInType, Filter, SearchSeed, SortByType } from '../../types';
|
|
28
35
|
import useMediaQuery from '../../../shared/utils/use-media-query-util';
|
|
29
36
|
import ItemPicker from '../item-picker';
|
|
30
37
|
import {
|
|
@@ -71,11 +78,14 @@ import GroupTourResults from '../group-tour/group-tour-results';
|
|
|
71
78
|
import {
|
|
72
79
|
applyFilters,
|
|
73
80
|
applyFiltersToPackageAccoResults,
|
|
81
|
+
applyFiltersToPackageFlightResults,
|
|
74
82
|
enrichFiltersWithPackageAccoResults,
|
|
83
|
+
enrichFiltersWithPackageFlightResults,
|
|
75
84
|
enrichFiltersWithResults
|
|
76
85
|
} from '../../utils/search-results-utils';
|
|
77
86
|
import {
|
|
78
87
|
ACCOMMODATION_SERVICE_TYPE,
|
|
88
|
+
EXCURSION_SERVICE_TYPE,
|
|
79
89
|
FLIGHT_SERVICE_TYPE,
|
|
80
90
|
getDepartureAirportFromEntry,
|
|
81
91
|
getDestinationAirportFromEntry,
|
|
@@ -91,12 +101,23 @@ import { getFlightKey } from '../../utils/flight-utils';
|
|
|
91
101
|
import IndependentFlightOption from '../flight/flight-selection/independent-flight-option';
|
|
92
102
|
import { Spinner } from '../../..';
|
|
93
103
|
import { PackagingRequestBase } from '@qite/tide-client/build/types/booking-v2/request/packaging/packaging-request-base';
|
|
104
|
+
import {
|
|
105
|
+
selectSelectedCombinationFlight,
|
|
106
|
+
selectSelectedOutward,
|
|
107
|
+
selectSelectedOutwardKey,
|
|
108
|
+
selectSelectedReturn,
|
|
109
|
+
selectSelectedReturnKey,
|
|
110
|
+
selectUniqueOutwardFlights,
|
|
111
|
+
selectUniqueReturnFlights
|
|
112
|
+
} from '../../store/search-results-selectors';
|
|
113
|
+
import DayByDayExcursions from '../excursions/day-by-day-excursions';
|
|
94
114
|
|
|
95
115
|
type BuildPackagingEntryPartialArgs = {
|
|
96
116
|
sourceEntry: PackagingEntry | null | undefined;
|
|
97
117
|
selectedHotelCode: string | null | undefined;
|
|
98
118
|
accommodationResults: PackagingAccommodationResponse[];
|
|
99
119
|
selectedFlight: PackagingFlightResponse | null;
|
|
120
|
+
confirmedExcursionsByDay: Record<string, PackagingAccommodationResponse[]>;
|
|
100
121
|
seed: SearchSeed;
|
|
101
122
|
transactionId: string;
|
|
102
123
|
language: string;
|
|
@@ -115,26 +136,29 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
115
136
|
filteredResults,
|
|
116
137
|
packagingAccoResults,
|
|
117
138
|
filteredPackagingAccoResults,
|
|
118
|
-
bookingPackageDetails,
|
|
119
139
|
isLoading,
|
|
120
140
|
flightsLoading,
|
|
141
|
+
initialFilters,
|
|
121
142
|
filters,
|
|
143
|
+
flightFilters,
|
|
122
144
|
selectedSortType,
|
|
145
|
+
selectedFlightSortType,
|
|
123
146
|
selectedSearchResult,
|
|
124
147
|
selectedPackagingAccoResultCode,
|
|
125
148
|
flyInIsOpen,
|
|
126
149
|
packagingAccoSearchDetails,
|
|
127
150
|
editablePackagingEntry,
|
|
128
151
|
transactionId,
|
|
129
|
-
|
|
152
|
+
flyInType,
|
|
130
153
|
itinerary,
|
|
131
|
-
packagingFlightResults
|
|
154
|
+
packagingFlightResults,
|
|
155
|
+
confirmedExcursionsByDay
|
|
132
156
|
} = useSelector((state: SearchResultsRootState) => state.searchResults);
|
|
133
157
|
|
|
134
158
|
const isMobile = useMediaQuery('(max-width: 1200px)');
|
|
135
159
|
|
|
136
160
|
const [initialFiltersSet, setInitialFiltersSet] = useState(false);
|
|
137
|
-
const [
|
|
161
|
+
const [initialFlightFiltersSet, setInitialFlightFiltersSet] = useState(false);
|
|
138
162
|
const [filtersOpen, setFiltersOpen] = useState(false);
|
|
139
163
|
|
|
140
164
|
const [detailsIsLoading, setDetailsIsLoading] = useState(false);
|
|
@@ -147,8 +171,6 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
147
171
|
|
|
148
172
|
const skipInitialPackagingAccoDetailsRef = useRef(false);
|
|
149
173
|
|
|
150
|
-
const [showAllOutwardFlights, setShowAllOutwardFlights] = useState(false);
|
|
151
|
-
|
|
152
174
|
const panelRef = useRef<HTMLDivElement | null>(null);
|
|
153
175
|
|
|
154
176
|
const sortByTypes: SortByType[] = [
|
|
@@ -439,7 +461,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
439
461
|
setDetailsIsLoading(true);
|
|
440
462
|
|
|
441
463
|
setSelectedAccommodationSeed(seed);
|
|
442
|
-
dispatch(
|
|
464
|
+
dispatch(setFlyInType('acco-results'));
|
|
443
465
|
handleFlyInToggle(true);
|
|
444
466
|
const currentTransactionId = await getOrCreateTransactionId();
|
|
445
467
|
await runAccommodationFlow(seed, currentTransactionId ?? '');
|
|
@@ -578,7 +600,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
578
600
|
const enrichedFilters = enrichFiltersWithResults(packageSearchResults, context.filters, context.tags ?? []);
|
|
579
601
|
if (!initialFiltersSet) {
|
|
580
602
|
dispatch(resetFilters(enrichedFilters));
|
|
581
|
-
setInitialFilters(enrichedFilters);
|
|
603
|
+
dispatch(setInitialFilters(enrichedFilters));
|
|
582
604
|
setInitialFiltersSet(true);
|
|
583
605
|
}
|
|
584
606
|
|
|
@@ -637,7 +659,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
637
659
|
|
|
638
660
|
const packageAccoSearchResults = await searchPackagingAccommodations(config, searchRequest);
|
|
639
661
|
|
|
640
|
-
const enrichedFilters = enrichFiltersWithPackageAccoResults(packageAccoSearchResults, context.
|
|
662
|
+
const enrichedFilters = enrichFiltersWithPackageAccoResults(packageAccoSearchResults, context.tags ?? []);
|
|
641
663
|
if (!initialFiltersSet) {
|
|
642
664
|
dispatch(resetFilters(enrichedFilters));
|
|
643
665
|
setInitialFilters(enrichedFilters);
|
|
@@ -680,11 +702,24 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
680
702
|
|
|
681
703
|
const packageFlightSearchResults = await searchPackagingFlights(config, searchRequest);
|
|
682
704
|
|
|
705
|
+
const enrichedFilters = enrichFiltersWithPackageFlightResults(packageFlightSearchResults, context.tags ?? [], translations);
|
|
706
|
+
if (!initialFlightFiltersSet) {
|
|
707
|
+
dispatch(resetFlightFilters(enrichedFilters));
|
|
708
|
+
dispatch(setInitialFlightFilters(enrichedFilters));
|
|
709
|
+
setInitialFlightFiltersSet(true);
|
|
710
|
+
}
|
|
711
|
+
|
|
683
712
|
dispatch(setPackagingFlightResults(packageFlightSearchResults));
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
713
|
+
|
|
714
|
+
const initialFilteredResults = applyFiltersToPackageFlightResults(packageFlightSearchResults, filters, null);
|
|
715
|
+
dispatch(setFilteredPackagingFlightResults(initialFilteredResults));
|
|
716
|
+
|
|
717
|
+
if (initialFilteredResults.length > 0) {
|
|
718
|
+
const firstResult = first(packageFlightSearchResults);
|
|
719
|
+
if (firstResult) {
|
|
720
|
+
dispatch(setSelectedOutwardKey(getFlightKey(firstResult.outward.segments)));
|
|
721
|
+
dispatch(setSelectedReturnKey(getFlightKey(firstResult.return.segments)));
|
|
722
|
+
}
|
|
688
723
|
}
|
|
689
724
|
|
|
690
725
|
dispatch(setFlightsLoading(false));
|
|
@@ -839,6 +874,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
839
874
|
context?.searchConfiguration.qsmType === PortalQsmType.GroupTour
|
|
840
875
|
) {
|
|
841
876
|
handleFlyInToggle(true);
|
|
877
|
+
dispatch(setFlyInType('acco-details'));
|
|
842
878
|
}
|
|
843
879
|
|
|
844
880
|
try {
|
|
@@ -923,11 +959,10 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
923
959
|
if (selectedPackagingAccoResultCode) {
|
|
924
960
|
fetchPackagingAccoSearchDetails();
|
|
925
961
|
}
|
|
926
|
-
dispatch(setAccommodationFlyInStep('details'));
|
|
927
962
|
}, [selectedSearchResult, selectedPackagingAccoResultCode]);
|
|
928
963
|
|
|
929
964
|
useEffect(() => {
|
|
930
|
-
if (context?.searchConfiguration.qsmType === PortalQsmType.Accommodation) {
|
|
965
|
+
if (context?.searchConfiguration.qsmType === PortalQsmType.Accommodation || context?.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight) {
|
|
931
966
|
const filteredPackageAccoResults = applyFiltersToPackageAccoResults(packagingAccoResults, filters, selectedSortType);
|
|
932
967
|
dispatch(setFilteredPackagingAccoResults(filteredPackageAccoResults));
|
|
933
968
|
} else {
|
|
@@ -936,6 +971,13 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
936
971
|
}
|
|
937
972
|
}, [filters, results, packagingAccoResults, selectedSortType]);
|
|
938
973
|
|
|
974
|
+
useEffect(() => {
|
|
975
|
+
if (context?.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight) {
|
|
976
|
+
const filteredPackageFlightResults = applyFiltersToPackageFlightResults(packagingFlightResults, flightFilters, selectedFlightSortType);
|
|
977
|
+
dispatch(setFilteredPackagingFlightResults(filteredPackageFlightResults));
|
|
978
|
+
}
|
|
979
|
+
}, [flightFilters, packagingFlightResults, selectedFlightSortType]);
|
|
980
|
+
|
|
939
981
|
useEffect(() => {
|
|
940
982
|
setInitialFiltersSet(false);
|
|
941
983
|
}, [activeSearchSeed]);
|
|
@@ -985,7 +1027,6 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
985
1027
|
} as PackagingRequestBase<PackagingEntry>;
|
|
986
1028
|
|
|
987
1029
|
const itinerary = await getItinerary(config, request);
|
|
988
|
-
console.log('Fetched itinerary', itinerary);
|
|
989
1030
|
dispatch(setItinerary(itinerary));
|
|
990
1031
|
setItineraryIsLoading(false);
|
|
991
1032
|
} catch (err) {
|
|
@@ -999,35 +1040,25 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
999
1040
|
}, [editablePackagingEntry]);
|
|
1000
1041
|
|
|
1001
1042
|
// Flight selection
|
|
1002
|
-
const [selectedOutwardKey, setSelectedOutwardKey] = useState<string | null>(null);
|
|
1003
|
-
const [selectedReturnKey, setSelectedReturnKey] = useState<string | null>(null);
|
|
1004
|
-
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
if (!map.has(key)) {
|
|
1012
|
-
map.set(key, flight);
|
|
1013
|
-
}
|
|
1014
|
-
});
|
|
1015
|
-
|
|
1016
|
-
return Array.from(map.values());
|
|
1017
|
-
}, [packagingFlightResults]);
|
|
1018
|
-
|
|
1019
|
-
const [uniqueReturnFlights, setUniqueReturnFlights] = useState<PackagingFlightResponse[]>([]);
|
|
1043
|
+
// const [selectedOutwardKey, setSelectedOutwardKey] = useState<string | null>(null);
|
|
1044
|
+
// const [selectedReturnKey, setSelectedReturnKey] = useState<string | null>(null);
|
|
1045
|
+
const selectedOutwardKey = useSelector(selectSelectedOutwardKey);
|
|
1046
|
+
const selectedReturnKey = useSelector(selectSelectedReturnKey);
|
|
1047
|
+
const uniqueOutwardFlights = useSelector(selectUniqueOutwardFlights);
|
|
1048
|
+
const uniqueReturnFlights = useSelector(selectUniqueReturnFlights);
|
|
1049
|
+
const selectedOutward = useSelector(selectSelectedOutward);
|
|
1050
|
+
const selectedReturn = useSelector(selectSelectedReturn);
|
|
1051
|
+
const selectedCombinationFlight = useSelector(selectSelectedCombinationFlight);
|
|
1020
1052
|
|
|
1021
1053
|
useEffect(() => {
|
|
1022
1054
|
if (!selectedOutwardKey) {
|
|
1023
|
-
|
|
1024
|
-
setSelectedReturnKey(null);
|
|
1055
|
+
dispatch(setSelectedReturnKey(null));
|
|
1025
1056
|
return;
|
|
1026
1057
|
}
|
|
1027
1058
|
|
|
1028
|
-
// Filter combinations that match selected outward fare
|
|
1029
1059
|
const matchingCombinations = packagingFlightResults.filter((flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey);
|
|
1030
|
-
|
|
1060
|
+
|
|
1061
|
+
const returnMap = new Map<string, PackagingFlightResponse>();
|
|
1031
1062
|
|
|
1032
1063
|
matchingCombinations.forEach((flight) => {
|
|
1033
1064
|
const key = getFlightKey(flight.return.segments);
|
|
@@ -1038,34 +1069,18 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1038
1069
|
});
|
|
1039
1070
|
|
|
1040
1071
|
const returns = Array.from(returnMap.values());
|
|
1072
|
+
const segments = first(returns)?.return.segments;
|
|
1073
|
+
const firstReturnKey = returns.length > 0 && segments ? getFlightKey(segments) : null;
|
|
1041
1074
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
if (firstReturnKey) {
|
|
1046
|
-
setSelectedReturnKey(firstReturnKey);
|
|
1075
|
+
if (!returns.some((x) => getFlightKey(x.return.segments) === selectedReturnKey)) {
|
|
1076
|
+
dispatch(setSelectedReturnKey(firstReturnKey));
|
|
1047
1077
|
}
|
|
1048
|
-
}, [selectedOutwardKey, packagingFlightResults]);
|
|
1049
|
-
|
|
1050
|
-
const selectedOutward = React.useMemo(() => {
|
|
1051
|
-
if (!selectedOutwardKey) return null;
|
|
1052
|
-
|
|
1053
|
-
return packagingFlightResults.find((flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey) || null;
|
|
1054
|
-
}, [packagingFlightResults, selectedOutwardKey]);
|
|
1078
|
+
}, [selectedOutwardKey, packagingFlightResults, selectedReturnKey, dispatch]);
|
|
1055
1079
|
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
}, [packagingFlightResults, selectedReturnKey]);
|
|
1061
|
-
|
|
1062
|
-
const selectedCombinationFlight = React.useMemo(() => {
|
|
1063
|
-
if (!selectedOutwardKey || !selectedReturnKey) return undefined;
|
|
1064
|
-
|
|
1065
|
-
return packagingFlightResults.find(
|
|
1066
|
-
(flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey && getFlightKey(flight.return.segments) === selectedReturnKey
|
|
1067
|
-
);
|
|
1068
|
-
}, [packagingFlightResults, selectedOutwardKey, selectedReturnKey]);
|
|
1080
|
+
const visibleOutwardFlights = React.useMemo(() => {
|
|
1081
|
+
const withoutSelected = uniqueOutwardFlights.filter((x) => getFlightKey(x.outward.segments) !== selectedOutwardKey);
|
|
1082
|
+
return withoutSelected.slice(0, 3);
|
|
1083
|
+
}, [uniqueOutwardFlights, selectedOutwardKey]);
|
|
1069
1084
|
|
|
1070
1085
|
// TODO: get details for selected combination flight and show in fly-in
|
|
1071
1086
|
// useEffect(() => {
|
|
@@ -1076,6 +1091,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1076
1091
|
// dispatch(setFlyInIsOpen(true));
|
|
1077
1092
|
// }, [selectedCombinationFlight, dispatch]);
|
|
1078
1093
|
|
|
1094
|
+
// Build packagingEntry
|
|
1079
1095
|
useEffect(() => {
|
|
1080
1096
|
if (!context) return;
|
|
1081
1097
|
|
|
@@ -1087,11 +1103,12 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1087
1103
|
selectedHotelCode: selectedPackagingAccoResultCode,
|
|
1088
1104
|
accommodationResults: packagingAccoResults,
|
|
1089
1105
|
selectedFlight: selectedCombinationFlight ?? null,
|
|
1106
|
+
confirmedExcursionsByDay,
|
|
1090
1107
|
seed,
|
|
1091
1108
|
transactionId: transactionId ?? context.packagingEntry?.transactionId ?? '',
|
|
1092
1109
|
language: context.languageCode ?? 'en-GB'
|
|
1093
1110
|
});
|
|
1094
|
-
|
|
1111
|
+
console.log('Built nextEntry', nextEntry);
|
|
1095
1112
|
if (!nextEntry) return;
|
|
1096
1113
|
|
|
1097
1114
|
dispatch(setEditablePackagingEntry(nextEntry));
|
|
@@ -1106,6 +1123,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1106
1123
|
packagingAccoResults,
|
|
1107
1124
|
packagingAccoSearchDetails,
|
|
1108
1125
|
selectedCombinationFlight,
|
|
1126
|
+
confirmedExcursionsByDay,
|
|
1109
1127
|
transactionId,
|
|
1110
1128
|
dispatch
|
|
1111
1129
|
]);
|
|
@@ -1114,23 +1132,70 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1114
1132
|
|
|
1115
1133
|
const removeFlightLines = (lines: PackagingEntryLine[]) => lines.filter((line) => line.serviceType !== FLIGHT_SERVICE_TYPE);
|
|
1116
1134
|
|
|
1135
|
+
const removeExcursionLines = (lines: PackagingEntryLine[]) => lines.filter((line) => line.serviceType !== EXCURSION_SERVICE_TYPE);
|
|
1136
|
+
|
|
1117
1137
|
const buildAccommodationLinesFromSelection = (selectedHotel: PackagingAccommodationResponse, seed: SearchSeed): PackagingEntryLine[] => {
|
|
1118
|
-
|
|
1138
|
+
return buildPackagingAccommodationLines(selectedHotel, seed, ACCOMMODATION_SERVICE_TYPE);
|
|
1139
|
+
};
|
|
1140
|
+
|
|
1141
|
+
const buildExcursionLinesFromConfirmedDays = (confirmedExcursionsByDay: Record<string, PackagingAccommodationResponse[]>): PackagingEntryLine[] => {
|
|
1142
|
+
return Object.values(confirmedExcursionsByDay)
|
|
1143
|
+
.flat()
|
|
1144
|
+
.flatMap((excursion) => {
|
|
1145
|
+
const selectedOptions = excursion.rooms.flatMap((room) => room.options.filter((option) => option.isSelected));
|
|
1146
|
+
|
|
1147
|
+
const parentGuid = crypto.randomUUID();
|
|
1148
|
+
|
|
1149
|
+
return selectedOptions.map(
|
|
1150
|
+
(option, index) =>
|
|
1151
|
+
({
|
|
1152
|
+
guid: option.guid ?? crypto.randomUUID(),
|
|
1153
|
+
moment: '',
|
|
1154
|
+
parentGuid: index === 0 ? null : parentGuid,
|
|
1155
|
+
order: index,
|
|
1156
|
+
isChanged: true,
|
|
1157
|
+
from: excursion.fromDate,
|
|
1158
|
+
to: excursion.toDate,
|
|
1159
|
+
serviceType: EXCURSION_SERVICE_TYPE,
|
|
1160
|
+
productName: excursion.name,
|
|
1161
|
+
productCode: excursion.code,
|
|
1162
|
+
accommodationName: option.accommodationName,
|
|
1163
|
+
accommodationCode: option.accommodationCode,
|
|
1164
|
+
regimeName: option.regimeName,
|
|
1165
|
+
regimeCode: option.regimeCode,
|
|
1166
|
+
country: excursion.countryId ? { id: excursion.countryId, name: excursion.countryName, localizations: [] } : null,
|
|
1167
|
+
region: excursion.regionId ? { id: excursion.regionId, name: excursion.regionName, localizations: [] } : null,
|
|
1168
|
+
oord: excursion.oordId ? { id: excursion.oordId, name: excursion.oordName, localizations: [] } : null,
|
|
1169
|
+
location: excursion.locationId ? { id: excursion.locationId, name: excursion.locationName, localizations: [] } : null,
|
|
1170
|
+
longitude: excursion.longitude ?? null,
|
|
1171
|
+
latitude: excursion.latitude ?? null,
|
|
1172
|
+
pax: Array.isArray(option.paxIds)
|
|
1173
|
+
? option.paxIds.map((paxId, paxIndex) => ({
|
|
1174
|
+
paxId: paxId,
|
|
1175
|
+
room: 0,
|
|
1176
|
+
order: paxIndex
|
|
1177
|
+
}))
|
|
1178
|
+
: [],
|
|
1179
|
+
flightInformation: null
|
|
1180
|
+
} satisfies PackagingEntryLine)
|
|
1181
|
+
);
|
|
1182
|
+
});
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
const buildPackagingAccommodationLines = (selectedItem: PackagingAccommodationResponse, seed: SearchSeed, serviceType: number): PackagingEntryLine[] => {
|
|
1186
|
+
if (!selectedItem) return [];
|
|
1119
1187
|
const parentGuid = crypto.randomUUID();
|
|
1120
1188
|
|
|
1121
|
-
return
|
|
1189
|
+
return selectedItem.rooms
|
|
1122
1190
|
.filter((room) => room.options.some((o) => o.isSelected))
|
|
1123
1191
|
.map((room, index) => {
|
|
1124
1192
|
const option = room.options.find((o) => o.isSelected)!;
|
|
1125
1193
|
|
|
1126
|
-
const pax =
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
order: paxIndex
|
|
1132
|
-
}))
|
|
1133
|
-
) ?? [];
|
|
1194
|
+
const pax = option.paxIds.map((p, paxIndex) => ({
|
|
1195
|
+
paxId: p,
|
|
1196
|
+
room: index,
|
|
1197
|
+
order: paxIndex
|
|
1198
|
+
}));
|
|
1134
1199
|
|
|
1135
1200
|
return {
|
|
1136
1201
|
guid: option.guid ?? crypto.randomUUID(),
|
|
@@ -1138,21 +1203,21 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1138
1203
|
parentGuid: index === 0 ? null : parentGuid,
|
|
1139
1204
|
order: index,
|
|
1140
1205
|
isChanged: true,
|
|
1141
|
-
from:
|
|
1142
|
-
to:
|
|
1143
|
-
serviceType:
|
|
1144
|
-
productName:
|
|
1145
|
-
productCode:
|
|
1206
|
+
from: selectedItem.fromDate,
|
|
1207
|
+
to: selectedItem.toDate,
|
|
1208
|
+
serviceType: serviceType,
|
|
1209
|
+
productName: selectedItem.name,
|
|
1210
|
+
productCode: selectedItem.code,
|
|
1146
1211
|
accommodationName: option.accommodationName,
|
|
1147
1212
|
accommodationCode: option.accommodationCode,
|
|
1148
1213
|
regimeName: option.regimeName,
|
|
1149
1214
|
regimeCode: option.regimeCode,
|
|
1150
|
-
country:
|
|
1151
|
-
region:
|
|
1152
|
-
oord:
|
|
1153
|
-
location:
|
|
1154
|
-
longitude:
|
|
1155
|
-
latitude:
|
|
1215
|
+
country: selectedItem.countryId ? { id: selectedItem.countryId, name: selectedItem.countryName, localizations: [] } : null,
|
|
1216
|
+
region: selectedItem.regionId ? { id: selectedItem.regionId, name: selectedItem.regionName, localizations: [] } : null,
|
|
1217
|
+
oord: selectedItem.oordId ? { id: selectedItem.oordId, name: selectedItem.oordName, localizations: [] } : null,
|
|
1218
|
+
location: selectedItem.locationId ? { id: selectedItem.locationId, name: selectedItem.locationName, localizations: [] } : null,
|
|
1219
|
+
longitude: selectedItem.longitude ?? null,
|
|
1220
|
+
latitude: selectedItem.latitude ?? null,
|
|
1156
1221
|
pax,
|
|
1157
1222
|
flightInformation: null
|
|
1158
1223
|
} satisfies PackagingEntryLine;
|
|
@@ -1286,6 +1351,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1286
1351
|
selectedHotelCode,
|
|
1287
1352
|
accommodationResults,
|
|
1288
1353
|
selectedFlight,
|
|
1354
|
+
confirmedExcursionsByDay,
|
|
1289
1355
|
seed,
|
|
1290
1356
|
transactionId,
|
|
1291
1357
|
language
|
|
@@ -1317,6 +1383,15 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1317
1383
|
}
|
|
1318
1384
|
}
|
|
1319
1385
|
|
|
1386
|
+
// excursions
|
|
1387
|
+
const excursionLines = buildExcursionLinesFromConfirmedDays(confirmedExcursionsByDay);
|
|
1388
|
+
|
|
1389
|
+
nextLines = removeExcursionLines(nextLines);
|
|
1390
|
+
|
|
1391
|
+
if (excursionLines.length) {
|
|
1392
|
+
nextLines = [...nextLines, ...excursionLines];
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1320
1395
|
nextLines = nextLines.map((line, index) => ({
|
|
1321
1396
|
...line,
|
|
1322
1397
|
order: index
|
|
@@ -1341,7 +1416,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1341
1416
|
return structuredClone(sourceEntry);
|
|
1342
1417
|
}
|
|
1343
1418
|
|
|
1344
|
-
let paxId =
|
|
1419
|
+
let paxId = 0;
|
|
1345
1420
|
|
|
1346
1421
|
const pax =
|
|
1347
1422
|
seed.rooms?.flatMap((room, roomIndex) =>
|
|
@@ -1367,9 +1442,10 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1367
1442
|
} as PackagingEntry;
|
|
1368
1443
|
};
|
|
1369
1444
|
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1445
|
+
const handleShowMoreFlights = (flyInType: FlyInType) => {
|
|
1446
|
+
dispatch(setFlyInType(flyInType));
|
|
1447
|
+
dispatch(setFlyInIsOpen(true));
|
|
1448
|
+
};
|
|
1373
1449
|
|
|
1374
1450
|
return (
|
|
1375
1451
|
<div id="tide-booking" className="search__bg">
|
|
@@ -1380,7 +1456,6 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1380
1456
|
<FlightSearchProvider tideConnection={context.tideConnection}>
|
|
1381
1457
|
<FlightResultsContainer isMobile={isMobile} />
|
|
1382
1458
|
<FlyIn
|
|
1383
|
-
title="Select your fare"
|
|
1384
1459
|
srpType={context.searchConfiguration.qsmType}
|
|
1385
1460
|
isOpen={flyInIsOpen}
|
|
1386
1461
|
setIsOpen={handleFlyInToggle}
|
|
@@ -1402,6 +1477,8 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1402
1477
|
handleSetIsOpen={() => setFiltersOpen(!filtersOpen)}
|
|
1403
1478
|
// handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
|
|
1404
1479
|
isLoading={isLoading}
|
|
1480
|
+
setFilters={(filters) => dispatch(setFilters(filters))}
|
|
1481
|
+
resetFilters={(filters) => dispatch(resetFilters(filters))}
|
|
1405
1482
|
/>
|
|
1406
1483
|
)}
|
|
1407
1484
|
{context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && (
|
|
@@ -1444,33 +1521,35 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1444
1521
|
)}
|
|
1445
1522
|
</div>
|
|
1446
1523
|
)}
|
|
1447
|
-
|
|
1448
|
-
<
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1524
|
+
{context.searchConfiguration.qsmType !== PortalQsmType.AccommodationAndFlight && (
|
|
1525
|
+
<div className="search__result-row">
|
|
1526
|
+
<span className="search__result-row-text">
|
|
1527
|
+
{!isLoading && (
|
|
1528
|
+
<>
|
|
1529
|
+
{context.searchConfiguration.qsmType === PortalQsmType.Accommodation &&
|
|
1530
|
+
filteredPackagingAccoResults?.length &&
|
|
1531
|
+
filteredPackagingAccoResults?.length}
|
|
1532
|
+
{context.searchConfiguration.qsmType !== PortalQsmType.Accommodation && filteredResults?.length && filteredResults.length}
|
|
1533
|
+
{translations.SRP.TOTAL_RESULTS_LABEL}
|
|
1534
|
+
</>
|
|
1535
|
+
)}
|
|
1536
|
+
</span>
|
|
1537
|
+
{!context.packagingEntry && !isMobile && sortByTypes && sortByTypes.length > 0 && (
|
|
1538
|
+
<div className="search__result-row-filter">
|
|
1539
|
+
<ItemPicker
|
|
1540
|
+
items={sortByTypes}
|
|
1541
|
+
selection={selectedSortType?.label || undefined}
|
|
1542
|
+
selectedSortByType={selectedSortType}
|
|
1543
|
+
label={translations.SRP.SORTBY}
|
|
1544
|
+
placeholder={translations.SRP.SORTBY}
|
|
1545
|
+
classModifier="travel-class-picker__items"
|
|
1546
|
+
valueFormatter={(value, direction) => getSortingName(translations, findSortByType(sortByTypes, value, direction ?? 'asc'))}
|
|
1547
|
+
onPick={(newSortKey, direction) => handleSortChange(newSortKey, direction)}
|
|
1548
|
+
/>
|
|
1549
|
+
</div>
|
|
1457
1550
|
)}
|
|
1458
|
-
</
|
|
1459
|
-
|
|
1460
|
-
<div className="search__result-row-filter">
|
|
1461
|
-
<ItemPicker
|
|
1462
|
-
items={sortByTypes}
|
|
1463
|
-
selection={selectedSortType?.label || undefined}
|
|
1464
|
-
selectedSortByType={selectedSortType}
|
|
1465
|
-
label={translations.SRP.SORTBY}
|
|
1466
|
-
placeholder={translations.SRP.SORTBY}
|
|
1467
|
-
classModifier="travel-class-picker__items"
|
|
1468
|
-
valueFormatter={(value, direction) => getSortingName(translations, findSortByType(sortByTypes, value, direction ?? 'asc'))}
|
|
1469
|
-
onPick={(newSortKey, direction) => handleSortChange(newSortKey, direction)}
|
|
1470
|
-
/>
|
|
1471
|
-
</div>
|
|
1472
|
-
)}
|
|
1473
|
-
</div>
|
|
1551
|
+
</div>
|
|
1552
|
+
)}
|
|
1474
1553
|
|
|
1475
1554
|
<div className="search__results__wrapper">
|
|
1476
1555
|
{context.showTabViews &&
|
|
@@ -1482,8 +1561,6 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1482
1561
|
{context.searchConfiguration.qsmType === PortalQsmType.GroupTour && <GroupTourResults isLoading={isLoading} />}
|
|
1483
1562
|
|
|
1484
1563
|
{context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && !context.packagingEntry && context.showFlightResults && (
|
|
1485
|
-
// bookingPackageDetails?.outwardFlights &&
|
|
1486
|
-
// <FlightResults flights={bookingPackageDetails?.outwardFlights} isDeparture={true} />
|
|
1487
1564
|
<>
|
|
1488
1565
|
<div className="search__results__label search__results__label--secondary">
|
|
1489
1566
|
<div className="search__results__label__date">
|
|
@@ -1506,7 +1583,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1506
1583
|
key={`flight-${selectedOutwardKey}`}
|
|
1507
1584
|
item={selectedOutward.outward}
|
|
1508
1585
|
guid={selectedOutward.outwardGuid}
|
|
1509
|
-
onSelect={() => setSelectedOutwardKey(null)}
|
|
1586
|
+
onSelect={() => dispatch(setSelectedOutwardKey(null))}
|
|
1510
1587
|
selectedGuid={selectedOutward.outwardGuid}
|
|
1511
1588
|
isOutward={true}
|
|
1512
1589
|
showSelectedState={true}
|
|
@@ -1517,7 +1594,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1517
1594
|
<IndependentFlightOption
|
|
1518
1595
|
key={`flight-${result.outwardGuid}`}
|
|
1519
1596
|
item={result.outward}
|
|
1520
|
-
onSelect={() => setSelectedOutwardKey(getFlightKey(result.outward.segments))}
|
|
1597
|
+
onSelect={() => dispatch(setSelectedOutwardKey(getFlightKey(result.outward.segments)))}
|
|
1521
1598
|
guid={result.outwardGuid}
|
|
1522
1599
|
isOutward={true}
|
|
1523
1600
|
price={result.price}
|
|
@@ -1527,8 +1604,8 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1527
1604
|
</div>
|
|
1528
1605
|
{uniqueOutwardFlights && uniqueOutwardFlights.length > 3 && (
|
|
1529
1606
|
<div className="search__results__cards__actions">
|
|
1530
|
-
<button className="cta cta--secondary" onClick={() =>
|
|
1531
|
-
{
|
|
1607
|
+
<button className="cta cta--secondary" onClick={() => handleShowMoreFlights('flight-outward-results')}>
|
|
1608
|
+
{translations.SRP.SHOW_MORE}
|
|
1532
1609
|
</button>
|
|
1533
1610
|
</div>
|
|
1534
1611
|
)}
|
|
@@ -1539,9 +1616,9 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1539
1616
|
|
|
1540
1617
|
{context.showHotelAccommodationResults && !context.packagingEntry && <HotelAccommodationResults isLoading={isLoading} />}
|
|
1541
1618
|
|
|
1619
|
+
{context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && !context.packagingEntry && <DayByDayExcursions />}
|
|
1620
|
+
|
|
1542
1621
|
{context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && !context.packagingEntry && context.showFlightResults && (
|
|
1543
|
-
// bookingPackageDetails?.returnFlights &&
|
|
1544
|
-
// <FlightResults flights={bookingPackageDetails?.returnFlights} isDeparture={false} />
|
|
1545
1622
|
<>
|
|
1546
1623
|
<div className="search__results__label search__results__label--secondary">
|
|
1547
1624
|
<div className="search__results__label__date">
|
|
@@ -1570,7 +1647,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1570
1647
|
<IndependentFlightOption
|
|
1571
1648
|
key={`flight-${result.outwardGuid}`}
|
|
1572
1649
|
item={result.return}
|
|
1573
|
-
onSelect={() => setSelectedReturnKey(getFlightKey(result.return.segments))}
|
|
1650
|
+
onSelect={() => dispatch(setSelectedReturnKey(getFlightKey(result.return.segments)))}
|
|
1574
1651
|
guid={result.outwardGuid}
|
|
1575
1652
|
isOutward={false}
|
|
1576
1653
|
currentSelectedPrice={selectedReturn?.price}
|
|
@@ -1588,15 +1665,16 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
1588
1665
|
</div>
|
|
1589
1666
|
{/* <button onClick={() => handleFlyInToggle(!flyInIsOpen)}>Toggle FlyIn</button> */}
|
|
1590
1667
|
<FlyIn
|
|
1591
|
-
title={`${translations.SRP.SELECT} ${translations.SRP.ACCOMMODATION}`}
|
|
1592
1668
|
srpType={context.searchConfiguration.qsmType}
|
|
1593
1669
|
isOpen={flyInIsOpen}
|
|
1594
1670
|
setIsOpen={handleFlyInToggle}
|
|
1595
1671
|
handleConfirm={() => handleConfirmHotelSwap()}
|
|
1596
1672
|
onPanelRef={(el) => (panelRef.current = el)}
|
|
1597
1673
|
detailsLoading={detailsIsLoading}
|
|
1598
|
-
|
|
1674
|
+
flyInType={flyInType}
|
|
1599
1675
|
isPackageEditFlow={!!context.packagingEntry}
|
|
1676
|
+
sortByTypes={sortByTypes}
|
|
1677
|
+
activeSearchSeed={activeSearchSeed}
|
|
1600
1678
|
/>
|
|
1601
1679
|
</>
|
|
1602
1680
|
)}
|