@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.
Files changed (70) hide show
  1. package/build/build-cjs/index.js +2782 -1052
  2. package/build/build-cjs/src/search-results/components/excursions/day-by-day-excursions.d.ts +4 -0
  3. package/build/build-cjs/src/search-results/components/excursions/excursion-details.d.ts +3 -0
  4. package/build/build-cjs/src/search-results/components/excursions/excursion-results.d.ts +8 -0
  5. package/build/build-cjs/src/search-results/components/filters/filters.d.ts +2 -0
  6. package/build/build-cjs/src/search-results/components/hotel/hotel-accommodation-results.d.ts +1 -0
  7. package/build/build-cjs/src/search-results/store/search-results-selectors.d.ts +546 -0
  8. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +55 -8
  9. package/build/build-cjs/src/search-results/types.d.ts +40 -2
  10. package/build/build-cjs/src/search-results/utils/query-utils.d.ts +1 -0
  11. package/build/build-cjs/src/search-results/utils/search-results-utils.d.ts +8 -6
  12. package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +4 -3
  13. package/build/build-cjs/src/shared/components/flyin/packaging-flights-flyin.d.ts +7 -0
  14. package/build/build-cjs/src/shared/utils/localization-util.d.ts +3 -0
  15. package/build/build-cjs/src/shared/utils/tide-api-utils.d.ts +6 -0
  16. package/build/build-esm/index.js +2735 -1023
  17. package/build/build-esm/src/search-results/components/excursions/day-by-day-excursions.d.ts +4 -0
  18. package/build/build-esm/src/search-results/components/excursions/excursion-details.d.ts +3 -0
  19. package/build/build-esm/src/search-results/components/excursions/excursion-results.d.ts +8 -0
  20. package/build/build-esm/src/search-results/components/filters/filters.d.ts +2 -0
  21. package/build/build-esm/src/search-results/components/hotel/hotel-accommodation-results.d.ts +1 -0
  22. package/build/build-esm/src/search-results/store/search-results-selectors.d.ts +546 -0
  23. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +55 -8
  24. package/build/build-esm/src/search-results/types.d.ts +40 -2
  25. package/build/build-esm/src/search-results/utils/query-utils.d.ts +1 -0
  26. package/build/build-esm/src/search-results/utils/search-results-utils.d.ts +8 -6
  27. package/build/build-esm/src/shared/components/flyin/flyin.d.ts +4 -3
  28. package/build/build-esm/src/shared/components/flyin/packaging-flights-flyin.d.ts +7 -0
  29. package/build/build-esm/src/shared/utils/localization-util.d.ts +3 -0
  30. package/build/build-esm/src/shared/utils/tide-api-utils.d.ts +6 -0
  31. package/package.json +2 -2
  32. package/src/booking-wizard/features/flight-options/index.tsx +6 -2
  33. package/src/search-results/components/excursions/day-by-day-excursions.tsx +169 -0
  34. package/src/search-results/components/excursions/excursion-details.tsx +340 -0
  35. package/src/search-results/components/excursions/excursion-results.tsx +186 -0
  36. package/src/search-results/components/filters/filters.tsx +8 -9
  37. package/src/search-results/components/hotel/hotel-accommodation-results.tsx +81 -24
  38. package/src/search-results/components/hotel/hotel-card.tsx +0 -3
  39. package/src/search-results/components/icon.tsx +1 -4
  40. package/src/search-results/components/search-results-container/search-results-container.tsx +208 -130
  41. package/src/search-results/store/search-results-selectors.ts +84 -0
  42. package/src/search-results/store/search-results-slice.ts +138 -15
  43. package/src/search-results/types.ts +55 -2
  44. package/src/search-results/utils/query-utils.ts +1 -0
  45. package/src/search-results/utils/search-results-utils.ts +310 -58
  46. package/src/shared/components/flyin/accommodation-flyin.tsx +4 -2
  47. package/src/shared/components/flyin/flights-flyin.tsx +3 -1
  48. package/src/shared/components/flyin/flyin.tsx +116 -21
  49. package/src/shared/components/flyin/group-tour-flyin.tsx +3 -1
  50. package/src/shared/components/flyin/packaging-flights-flyin.tsx +164 -0
  51. package/src/shared/translations/ar-SA.json +4 -2
  52. package/src/shared/translations/da-DK.json +4 -2
  53. package/src/shared/translations/de-DE.json +4 -2
  54. package/src/shared/translations/en-GB.json +4 -2
  55. package/src/shared/translations/es-ES.json +4 -2
  56. package/src/shared/translations/fr-BE.json +4 -2
  57. package/src/shared/translations/fr-FR.json +4 -2
  58. package/src/shared/translations/is-IS.json +4 -2
  59. package/src/shared/translations/it-IT.json +4 -2
  60. package/src/shared/translations/ja-JP.json +4 -2
  61. package/src/shared/translations/nl-BE.json +4 -2
  62. package/src/shared/translations/nl-NL.json +4 -2
  63. package/src/shared/translations/no-NO.json +4 -2
  64. package/src/shared/translations/pl-PL.json +4 -2
  65. package/src/shared/translations/pt-PT.json +4 -2
  66. package/src/shared/translations/sv-SE.json +4 -2
  67. package/src/shared/utils/localization-util.ts +14 -0
  68. package/src/shared/utils/tide-api-utils.ts +8 -0
  69. package/styles/components/_flyin.scss +16 -0
  70. package/styles/components/_search.scss +15 -2
@@ -16,15 +16,22 @@ import {
16
16
  setPackagingAccoSearchDetails,
17
17
  setEditablePackagingEntry,
18
18
  setTransactionId,
19
- setAccommodationFlyInStep,
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 { AccommodationFlyInStep, Filter, SearchSeed, SortByType } from '../../types';
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
- accommodationFlyInStep,
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 [initialFilters, setInitialFilters] = useState<Filter[]>([]);
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(setAccommodationFlyInStep('results'));
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.filters, context.tags ?? []);
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
- const firstResult = first(packageFlightSearchResults);
685
- if (firstResult) {
686
- setSelectedOutwardKey(getFlightKey(firstResult.outward.segments));
687
- setSelectedReturnKey(getFlightKey(firstResult.return.segments));
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 uniqueOutwardFlights: PackagingFlightResponse[] = React.useMemo(() => {
1006
- const map = new Map();
1007
-
1008
- packagingFlightResults.forEach((flight) => {
1009
- const key = getFlightKey(flight.outward.segments);
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
- setUniqueReturnFlights([]);
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
- const returnMap = new Map();
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
- setUniqueReturnFlights(returns);
1043
- const firstReturnKey = returns.length > 0 ? getFlightKey(first(returns)?.return.segments) : null;
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 selectedReturn = React.useMemo(() => {
1057
- if (!selectedReturnKey) return null;
1058
-
1059
- return packagingFlightResults.find((flight) => getFlightKey(flight.return.segments) === selectedReturnKey) || null;
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
- if (!selectedHotel) return [];
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 selectedHotel.rooms
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
- seed.rooms?.flatMap((room, roomIndex) =>
1128
- room.pax.map((p, paxIndex) => ({
1129
- paxId: p.id,
1130
- room: roomIndex,
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: selectedHotel.fromDate,
1142
- to: selectedHotel.toDate,
1143
- serviceType: ACCOMMODATION_SERVICE_TYPE,
1144
- productName: selectedHotel.name,
1145
- productCode: selectedHotel.code,
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: selectedHotel.countryId ? { id: selectedHotel.countryId, name: selectedHotel.countryName, localizations: [] } : null,
1151
- region: selectedHotel.regionId ? { id: selectedHotel.regionId, name: selectedHotel.regionName, localizations: [] } : null,
1152
- oord: selectedHotel.oordId ? { id: selectedHotel.oordId, name: selectedHotel.oordName, localizations: [] } : null,
1153
- location: selectedHotel.locationId ? { id: selectedHotel.locationId, name: selectedHotel.locationName, localizations: [] } : null,
1154
- longitude: selectedHotel.longitude ?? null,
1155
- latitude: selectedHotel.latitude ?? null,
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 = 1;
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 visibleOutwardFlights = React.useMemo(() => {
1371
- return showAllOutwardFlights ? uniqueOutwardFlights : uniqueOutwardFlights.slice(0, 3);
1372
- }, [showAllOutwardFlights, uniqueOutwardFlights]);
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
- <div className="search__result-row">
1448
- <span className="search__result-row-text">
1449
- {!isLoading && context.searchConfiguration.qsmType !== PortalQsmType.AccommodationAndFlight && (
1450
- <>
1451
- {context.searchConfiguration.qsmType === PortalQsmType.Accommodation &&
1452
- filteredPackagingAccoResults?.length &&
1453
- filteredPackagingAccoResults?.length}
1454
- {context.searchConfiguration.qsmType !== PortalQsmType.Accommodation && filteredResults?.length && filteredResults.length}
1455
- &nbsp;{translations.SRP.TOTAL_RESULTS_LABEL}
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
+ &nbsp;{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
- </span>
1459
- {!context.packagingEntry && !isMobile && sortByTypes && sortByTypes.length > 0 && (
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={() => setShowAllOutwardFlights(!showAllOutwardFlights)}>
1531
- {showAllOutwardFlights ? translations.SRP.SHOW_LESS : translations.SRP.SHOW_MORE}
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
- accommodationStep={accommodationFlyInStep}
1674
+ flyInType={flyInType}
1599
1675
  isPackageEditFlow={!!context.packagingEntry}
1676
+ sortByTypes={sortByTypes}
1677
+ activeSearchSeed={activeSearchSeed}
1600
1678
  />
1601
1679
  </>
1602
1680
  )}