@qite/tide-booking-component 1.4.98 → 1.4.100

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 (30) hide show
  1. package/build/build-cjs/index.js +1183 -669
  2. package/build/build-cjs/src/search-results/components/itinerary/index.d.ts +2 -0
  3. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +11 -10
  4. package/build/build-cjs/src/search-results/types.d.ts +23 -1
  5. package/build/build-cjs/src/search-results/utils/packaging-utils.d.ts +7 -0
  6. package/build/build-cjs/src/search-results/utils/query-utils.d.ts +11 -0
  7. package/build/build-cjs/src/shared/components/flyin/accommodation-flyin.d.ts +1 -2
  8. package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +4 -0
  9. package/build/build-cjs/src/shared/utils/localization-util.d.ts +1 -0
  10. package/build/build-esm/index.js +1183 -669
  11. package/build/build-esm/src/search-results/components/itinerary/index.d.ts +2 -0
  12. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +11 -10
  13. package/build/build-esm/src/search-results/types.d.ts +23 -1
  14. package/build/build-esm/src/search-results/utils/packaging-utils.d.ts +7 -0
  15. package/build/build-esm/src/search-results/utils/query-utils.d.ts +11 -0
  16. package/build/build-esm/src/shared/components/flyin/accommodation-flyin.d.ts +1 -2
  17. package/build/build-esm/src/shared/components/flyin/flyin.d.ts +4 -0
  18. package/build/build-esm/src/shared/utils/localization-util.d.ts +1 -0
  19. package/package.json +2 -2
  20. package/src/qsm/components/search-input-group/index.tsx +0 -1
  21. package/src/search-results/components/itinerary/index.tsx +150 -81
  22. package/src/search-results/components/search-results-container/search-results-container.tsx +463 -384
  23. package/src/search-results/store/search-results-slice.ts +28 -10
  24. package/src/search-results/types.ts +25 -1
  25. package/src/search-results/utils/packaging-utils.ts +75 -0
  26. package/src/search-results/utils/query-utils.ts +152 -0
  27. package/src/shared/components/flyin/accommodation-flyin.tsx +10 -11
  28. package/src/shared/components/flyin/flyin.tsx +52 -4
  29. package/styles/components/_flyin.scss +25 -0
  30. package/styles/components/_search.scss +26 -1
@@ -9,21 +9,22 @@ import {
9
9
  setIsLoading,
10
10
  setSelectedSearchResult,
11
11
  setBookingPackageDetails,
12
- setEntry,
13
12
  setFlyInIsOpen,
14
13
  setFilteredResults,
15
14
  setPackagingAccoResults,
16
15
  setFilteredPackagingAccoResults,
17
- setPackagingAccoSearchDetails
16
+ setPackagingAccoSearchDetails,
17
+ setEditablePackagingEntry,
18
+ setTransactionId,
19
+ setAccommodationFlyInStep,
20
+ setPriceDetails
18
21
  } from '../../store/search-results-slice';
19
- import { Filter, SortByType } from '../../types';
22
+ import { AccommodationFlyInStep, Filter, SearchSeed, SortByType } from '../../types';
20
23
  import useMediaQuery from '../../../shared/utils/use-media-query-util';
21
24
  import ItemPicker from '../item-picker';
22
25
  import {
23
26
  TideClientConfig,
24
27
  details,
25
- detailsWL,
26
- getEntryLight,
27
28
  search,
28
29
  searchPackagingAccommodations,
29
30
  BookingPackageDestination,
@@ -32,16 +33,16 @@ import {
32
33
  BookingPackageRequest,
33
34
  BookingPackageRequestRoom,
34
35
  BookingPackageSearchRequest,
35
- EntryLight,
36
- EntryRoom,
37
36
  PackagingAccommodationRequest,
38
37
  PackagingDestination,
39
- PackagingRoom,
40
- PackagingTraveller,
41
- PortalQsmType
38
+ PortalQsmType,
39
+ PackagingEntry,
40
+ startTransaction,
41
+ PackagingEntryLine,
42
+ getPriceDetails
42
43
  } from '@qite/tide-client';
43
44
  import { getDateFromParams, getNumberFromParams, getRoomsFromParams, getStringFromParams } from '../../../shared/utils/query-string-util';
44
- import { range } from 'lodash';
45
+ import { first, last, range } from 'lodash';
45
46
  import { Room } from '../../../booking-wizard/types';
46
47
  import Icon from '../icon';
47
48
  import Itinerary from '../itinerary';
@@ -61,8 +62,22 @@ import {
61
62
  enrichFiltersWithPackageAccoResults,
62
63
  enrichFiltersWithResults
63
64
  } from '../../utils/search-results-utils';
65
+ import {
66
+ ACCOMMODATION_SERVICE_TYPE,
67
+ FLIGHT_SERVICE_TYPE,
68
+ getDepartureAirportFromEntry,
69
+ getDestinationAirportFromEntry,
70
+ getPackagingRequestRoomsFromBookingRooms,
71
+ getRequestRoomsFromPackagingEntry,
72
+ GROUP_TOUR_SERVICE_TYPE,
73
+ parseHotelId,
74
+ toDateOnlyString
75
+ } from '../../utils/query-utils';
76
+ import { getRequestRoomsFromPackagingSegments, getRoomIndexFromLine, getSelectedOptionsPerRoom } from '../../utils/packaging-utils';
64
77
 
65
78
  const SearchResultsContainer: React.FC = () => {
79
+ const currentSearch = typeof window !== 'undefined' ? window.location.search : '';
80
+
66
81
  const dispatch = useDispatch();
67
82
 
68
83
  const context = useContext(SearchResultsConfigurationContext);
@@ -74,13 +89,16 @@ const SearchResultsContainer: React.FC = () => {
74
89
  packagingAccoResults,
75
90
  filteredPackagingAccoResults,
76
91
  bookingPackageDetails,
77
- entry,
78
92
  isLoading,
79
93
  filters,
80
94
  selectedSortType,
81
95
  selectedSearchResult,
82
96
  selectedPackagingAccoResultCode,
83
- flyInIsOpen
97
+ flyInIsOpen,
98
+ packagingAccoSearchDetails,
99
+ editablePackagingEntry,
100
+ transactionId,
101
+ accommodationFlyInStep
84
102
  } = useSelector((state: SearchResultsRootState) => state.searchResults);
85
103
 
86
104
  const isMobile = useMediaQuery('(max-width: 1200px)');
@@ -90,9 +108,12 @@ const SearchResultsContainer: React.FC = () => {
90
108
  const [filtersOpen, setFiltersOpen] = useState(false);
91
109
 
92
110
  const [detailsIsLoading, setDetailsIsLoading] = useState(false);
111
+ const [pricesAreLoading, setPricesAreLoading] = useState(false);
93
112
 
94
113
  const [itineraryOpen, setItineraryOpen] = useState(false);
95
114
 
115
+ const [selectedAccommodationSeed, setSelectedAccommodationSeed] = useState<SearchSeed | null>(null);
116
+
96
117
  const panelRef = useRef<HTMLDivElement | null>(null);
97
118
 
98
119
  const sortByTypes: SortByType[] = [
@@ -112,96 +133,43 @@ const SearchResultsContainer: React.FC = () => {
112
133
  }
113
134
  };
114
135
 
115
- const buildSearchFromEntry = (entry: EntryLight): BookingPackageRequest<BookingPackageSearchRequest> => {
116
- const from = new Date(Math.min(...entry.items.map((i) => i.startDate.getTime()))).toISOString();
117
- const to = new Date(Math.max(...entry.items.map((i) => i.endDate.getTime()))).toISOString();
118
- const rooms = entry.rooms;
119
-
120
- const hotelItem = entry.items.find((i) => i.productType === 3);
121
-
122
- let country = hotelItem ? hotelItem.countryId : null;
123
- let region = hotelItem ? hotelItem.regionId : null;
124
- let oord = hotelItem ? hotelItem.oordId : null;
125
- let city = hotelItem ? hotelItem.locationId : null;
126
- let hotel = hotelItem ? hotelItem.productCode : null;
127
-
128
- if (typeof window !== 'undefined') {
129
- window.scrollTo(0, 0);
130
- }
131
-
132
- let destinationId: number | null = null;
133
- let destinationIsCountry = false;
134
- let destinationIsRegion = false;
135
- let destinationIsOord = false;
136
- let destinationIsLocation = false;
137
-
138
- if (country) {
139
- destinationId = country;
140
- destinationIsCountry = true;
141
- } else if (region) {
142
- destinationId = region;
143
- destinationIsRegion = true;
144
- } else if (oord) {
145
- destinationId = oord;
146
- destinationIsOord = true;
147
- } else if (city) {
148
- destinationId = city;
149
- destinationIsLocation = true;
136
+ const getRequestRooms = (rooms: Room[] | null) => {
137
+ if (!rooms) {
138
+ // Fall back to 2 adults
139
+ var room = { index: 0, pax: [] } as BookingPackageRequestRoom;
140
+ range(0, 2).forEach(() => {
141
+ room.pax.push({
142
+ age: 30
143
+ } as BookingPackagePax);
144
+ });
145
+ return [room];
150
146
  }
151
147
 
152
- var searchRequest = {
153
- officeId: 1,
154
- agentId: context?.agentId,
155
- payload: {
156
- catalogueIds: context!.tideConnection.catalogueIds ?? [],
157
- serviceType:
158
- context!.searchConfiguration.qsmType === PortalQsmType.Accommodation || context!.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight
159
- ? 3
160
- : context!.searchConfiguration.qsmType === PortalQsmType.Flight
161
- ? 7
162
- : context!.searchConfiguration.qsmType === PortalQsmType.RoundTrip
163
- ? 1
164
- : 0,
165
- searchType: 0,
166
- destination: {
167
- id: Number(destinationId),
168
- isCountry: destinationIsCountry,
169
- isRegion: destinationIsRegion,
170
- isOord: destinationIsOord,
171
- isLocation: destinationIsLocation
172
- } as BookingPackageDestination,
173
- rooms: getRequestRoomsFromEntry(rooms),
174
- fromDate: from,
175
- toDate: to,
176
- earliestFromOffset: 0,
177
- latestToOffset: 0,
178
- includeFlights: true,
179
- regimeCodes: entry.items.map((i) => i.regimeCode) || [],
180
- useExactDates: true,
181
- onlyCachedResults: false,
182
- includeAllAllotments: true,
183
- productCodes: hotel ? [hotel] : []
184
- }
185
- };
148
+ const requestRooms = rooms?.map((x, i) => {
149
+ var room = { index: i, pax: [] } as BookingPackageRequestRoom;
150
+ range(0, x.adults).forEach(() => {
151
+ room.pax.push({
152
+ age: 30
153
+ } as BookingPackagePax);
154
+ });
155
+ x.childAges.forEach((x) => {
156
+ room.pax.push({
157
+ age: x
158
+ } as BookingPackagePax);
159
+ });
160
+ return room;
161
+ });
186
162
 
187
- return searchRequest;
163
+ return requestRooms;
188
164
  };
189
165
 
190
- const buildSearchFromQueryParams = (params: URLSearchParams): BookingPackageRequest<BookingPackageSearchRequest> | null => {
191
- let from = getDateFromParams(params, 'fromDate');
192
- let to = getDateFromParams(params, 'toDate');
193
- const rooms = getRoomsFromParams(params, 'rooms');
194
- let country = getNumberFromParams(params, 'country');
195
- let region = getNumberFromParams(params, 'region');
196
- let oord = getNumberFromParams(params, 'oord');
197
- let city = getNumberFromParams(params, 'location');
198
- let hotel = getNumberFromParams(params, 'hotel');
199
- let tagId = getNumberFromParams(params, 'tagId');
200
-
201
- if (!from || !to) {
202
- console.error('Missing fromDate or toDate in query params, using default values');
203
- return null;
204
- }
166
+ const buildSearchFromSeed = (seed: SearchSeed): BookingPackageRequest<BookingPackageSearchRequest> => {
167
+ const country = seed.country;
168
+ const region = seed.region;
169
+ const oord = seed.oord;
170
+ const city = seed.location;
171
+ const hotel = seed.hotel;
172
+ const tagId = seed.tagId;
205
173
 
206
174
  if (typeof window !== 'undefined') {
207
175
  window.scrollTo(0, 0);
@@ -227,18 +195,18 @@ const SearchResultsContainer: React.FC = () => {
227
195
  destinationIsLocation = true;
228
196
  }
229
197
 
230
- var searchRequest = {
198
+ return {
231
199
  officeId: 1,
232
200
  agentId: context?.agentId,
233
201
  payload: {
234
202
  catalogueIds: context!.tideConnection.catalogueIds ?? [],
235
203
  serviceType:
236
204
  context!.searchConfiguration.qsmType === PortalQsmType.Accommodation || context!.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight
237
- ? 3
205
+ ? ACCOMMODATION_SERVICE_TYPE
238
206
  : context!.searchConfiguration.qsmType === PortalQsmType.Flight
239
- ? 7
207
+ ? FLIGHT_SERVICE_TYPE
240
208
  : context!.searchConfiguration.qsmType === PortalQsmType.RoundTrip
241
- ? 1
209
+ ? GROUP_TOUR_SERVICE_TYPE
242
210
  : undefined,
243
211
  searchType: context!.searchConfiguration.qsmType === PortalQsmType.GroupTour ? 1 : 0,
244
212
  destination: {
@@ -248,19 +216,12 @@ const SearchResultsContainer: React.FC = () => {
248
216
  isOord: destinationIsOord,
249
217
  isLocation: destinationIsLocation
250
218
  } as BookingPackageDestination,
251
- rooms: getRequestRooms(rooms),
252
- fromDate: from,
253
- toDate: to,
219
+ rooms: seed.rooms,
220
+ fromDate: seed.fromDate,
221
+ toDate: seed.toDate,
254
222
  earliestFromOffset: 0,
255
223
  latestToOffset: 0,
256
- includeFlights: context!.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight ? true : false,
257
- // regimeCodes:
258
- // filters
259
- // .find((f) => f.property === 'regime')
260
- // ?.options?.filter((o) => o.isChecked)
261
- // .flatMap((o) => o.value.toString()) || [],
262
- // minPrice: filters.find((f) => f.property === 'price')?.selectedMin,
263
- // maxPrice: filters.find((f) => f.property === 'price')?.selectedMax,
224
+ includeFlights: context!.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight,
264
225
  useExactDates: context?.searchConfiguration.qsmType === PortalQsmType.GroupTour ? false : true,
265
226
  onlyCachedResults: false,
266
227
  includeAllAllotments: true,
@@ -268,86 +229,16 @@ const SearchResultsContainer: React.FC = () => {
268
229
  productTagIds: tagId ? [tagId] : []
269
230
  }
270
231
  };
271
-
272
- console.log('Built search request from query params', searchRequest);
273
-
274
- return searchRequest;
275
232
  };
276
233
 
277
- const getRequestRoomsFromEntry = (rooms: EntryRoom[] | null) => {
278
- if (!rooms) {
279
- // Fall back to 2 adults
280
- var room = { index: 0, pax: [] } as BookingPackageRequestRoom;
281
- range(0, 2).forEach(() => {
282
- room.pax.push({
283
- age: 30
284
- } as BookingPackagePax);
285
- });
286
- return [room];
287
- }
288
-
289
- const requestRooms = rooms?.map((x, i) => {
290
- var room = { index: i, pax: [] } as BookingPackageRequestRoom;
291
- x.travellers.forEach((p) => {
292
- room.pax.push({
293
- age: p.age,
294
- dateOfBirth: p.dateOfBirth
295
- } as BookingPackagePax);
296
- });
297
-
298
- return room;
299
- });
300
-
301
- return requestRooms;
302
- };
303
-
304
- const getRequestRooms = (rooms: Room[] | null) => {
305
- if (!rooms) {
306
- // Fall back to 2 adults
307
- var room = { index: 0, pax: [] } as BookingPackageRequestRoom;
308
- range(0, 2).forEach(() => {
309
- room.pax.push({
310
- age: 30
311
- } as BookingPackagePax);
312
- });
313
- return [room];
314
- }
315
-
316
- const requestRooms = rooms?.map((x, i) => {
317
- var room = { index: i, pax: [] } as BookingPackageRequestRoom;
318
- range(0, x.adults).forEach(() => {
319
- room.pax.push({
320
- age: 30
321
- } as BookingPackagePax);
322
- });
323
- x.childAges.forEach((x) => {
324
- room.pax.push({
325
- age: x
326
- } as BookingPackagePax);
327
- });
328
- return room;
329
- });
330
-
331
- return requestRooms;
332
- };
333
-
334
- const buildPackagingAccommodationRequestFromQueryParams = (params: URLSearchParams): PackagingAccommodationRequest | null => {
335
- let from = getDateFromParams(params, 'fromDate');
336
- let to = getDateFromParams(params, 'toDate');
337
- const rooms = getRoomsFromParams(params, 'rooms');
338
- let country = getNumberFromParams(params, 'country');
339
- let region = getNumberFromParams(params, 'region');
340
- let oord = getNumberFromParams(params, 'oord');
341
- let city = getNumberFromParams(params, 'location');
342
- let hotel = getNumberFromParams(params, 'hotel');
343
- let tagId = getNumberFromParams(params, 'tagId');
344
- let agentId = getNumberFromParams(params, 'agentId');
345
- let destinationAirport = getStringFromParams(params, 'destinationAirport');
346
-
347
- if (!from || !to) {
348
- console.error('Missing fromDate or toDate in query params, using default values');
349
- return null;
350
- }
234
+ const buildPackagingAccommodationRequestFromSeed = (seed: SearchSeed, currentTransactionId: string): PackagingAccommodationRequest => {
235
+ const country = seed.country;
236
+ const region = seed.region;
237
+ const oord = seed.oord;
238
+ const city = seed.location;
239
+ const hotelCode = seed.hotelCode ?? (seed.hotel ? seed.hotel.toString() : '');
240
+ const tagId = seed.tagId;
241
+ const destinationAirport = seed.destinationAirport;
351
242
 
352
243
  if (typeof window !== 'undefined') {
353
244
  window.scrollTo(0, 0);
@@ -361,32 +252,33 @@ const SearchResultsContainer: React.FC = () => {
361
252
  let destinationCode: string | null = null;
362
253
  let destinationIsAirport = false;
363
254
 
364
- if (country) {
365
- destinationId = country;
366
- destinationIsCountry = true;
367
- } else if (region) {
368
- destinationId = region;
369
- destinationIsRegion = true;
255
+ if (city) {
256
+ destinationId = city;
257
+ destinationIsLocation = true;
370
258
  } else if (oord) {
371
259
  destinationId = oord;
372
260
  destinationIsOord = true;
373
- } else if (city) {
374
- destinationId = city;
375
- destinationIsLocation = true;
261
+ } else if (region) {
262
+ destinationId = region;
263
+ destinationIsRegion = true;
264
+ } else if (country) {
265
+ destinationId = country;
266
+ destinationIsCountry = true;
376
267
  } else if (destinationAirport) {
377
268
  destinationCode = destinationAirport;
378
269
  destinationIsAirport = true;
379
270
  }
380
271
 
381
- var searchRequest = {
272
+ return {
273
+ transactionId: currentTransactionId,
382
274
  officeId: 1,
383
- agentId: agentId ?? null,
275
+ agentId: context?.agentId ?? null,
384
276
  catalogueId: context!.searchConfiguration.defaultCatalogueId ?? 0,
385
277
  searchConfigurationId: context!.searchConfiguration.id,
386
278
  language: context!.languageCode ?? 'en-GB',
387
- servicesType: 3, // accommodation
388
- fromDate: from,
389
- toDate: to,
279
+ serviceType: ACCOMMODATION_SERVICE_TYPE,
280
+ fromDate: seed.fromDate,
281
+ toDate: seed.toDate,
390
282
  destination: {
391
283
  id: Number(destinationId),
392
284
  isCountry: destinationIsCountry,
@@ -396,194 +288,307 @@ const SearchResultsContainer: React.FC = () => {
396
288
  isAirport: destinationIsAirport,
397
289
  code: destinationCode
398
290
  } as PackagingDestination,
399
- productCode: hotel ? hotel.toString() : '',
400
- rooms: getPackagingRequestRooms(rooms),
291
+ productCode: '',
292
+ rooms: getPackagingRequestRoomsFromBookingRooms(seed.rooms),
401
293
  tagIds: tagId ? [tagId] : []
402
294
  };
295
+ };
403
296
 
404
- console.log('Search request for packaging accommodation from query params', searchRequest);
297
+ const buildSearchSeedFromQueryParams = (params: URLSearchParams): SearchSeed | null => {
298
+ const from = getDateFromParams(params, 'fromDate');
299
+ const to = getDateFromParams(params, 'toDate');
300
+ const rooms = getRoomsFromParams(params, 'rooms');
301
+ const country = getNumberFromParams(params, 'country');
302
+ const region = getNumberFromParams(params, 'region');
303
+ const oord = getNumberFromParams(params, 'oord');
304
+ const city = getNumberFromParams(params, 'location');
305
+ const hotel = getNumberFromParams(params, 'hotel');
306
+ const tagId = getNumberFromParams(params, 'tagId');
307
+ const destinationAirport = getStringFromParams(params, 'destinationAirport');
308
+ const departureAirport = getStringFromParams(params, 'departureAirport');
405
309
 
406
- return searchRequest;
310
+ if (!from || !to) {
311
+ return null;
312
+ }
313
+
314
+ return {
315
+ fromDate: from,
316
+ toDate: to,
317
+ country,
318
+ region,
319
+ oord,
320
+ location: city,
321
+ hotel,
322
+ hotelCode: hotel ? hotel.toString() : null,
323
+ tagId,
324
+ destinationAirport,
325
+ departureAirport,
326
+ rooms: getRequestRooms(rooms)
327
+ };
407
328
  };
408
329
 
409
- const getPackagingRequestRooms = (rooms: Room[] | null) => {
410
- if (!rooms) {
411
- // Fall back to 2 adults
412
- var room = { index: 0, travellers: [] } as PackagingRoom;
413
- range(0, 2).forEach(() => {
414
- room.travellers.push({
415
- age: 30
416
- } as PackagingTraveller);
417
- });
418
- return [room];
419
- }
330
+ const handleConfirmHotelSwap = () => {
331
+ const updatedEntry = swapHotelInPackagingEntry();
332
+ if (!updatedEntry) return;
420
333
 
421
- const requestRooms = rooms?.map((x, i) => {
422
- var room = { index: i, travellers: [] } as PackagingRoom;
423
- range(0, x.adults).forEach(() => {
424
- room.travellers.push({
425
- age: 30
426
- } as PackagingTraveller);
427
- });
428
- x.childAges.forEach((x) => {
429
- room.travellers.push({
430
- age: x
431
- } as PackagingTraveller);
432
- });
433
- return room;
334
+ dispatch(setEditablePackagingEntry(updatedEntry));
335
+ handleFlyInToggle(false);
336
+ };
337
+
338
+ const swapHotelInPackagingEntry = (): PackagingEntry | null => {
339
+ const sourceEntry = editablePackagingEntry ?? context?.packagingEntry;
340
+ const details = packagingAccoSearchDetails;
341
+
342
+ if (!sourceEntry || !details?.length) return null;
343
+
344
+ const selectedOptionsPerRoom = getSelectedOptionsPerRoom(details);
345
+ if (!selectedOptionsPerRoom.length) return null;
346
+
347
+ const selectedHotel = details[0];
348
+
349
+ let roomIndex = 0;
350
+ const updatedLines = sourceEntry.lines.map((line) => {
351
+ if (line.serviceType !== ACCOMMODATION_SERVICE_TYPE) {
352
+ return line;
353
+ }
354
+
355
+ const selectedRoom = selectedOptionsPerRoom.find((x) => x.roomIndex === roomIndex);
356
+ const selectedOption = selectedRoom?.option;
357
+ roomIndex++;
358
+
359
+ if (!selectedOption) {
360
+ return line;
361
+ }
362
+
363
+ return {
364
+ ...line,
365
+ guid: selectedOption.guid,
366
+ productName: selectedHotel.name,
367
+ productCode: selectedHotel.code,
368
+ accommodationName: selectedOption.accommodationName,
369
+ accommodationCode: selectedOption.accommodationCode,
370
+ regimeName: selectedOption.regimeName,
371
+ regimeCode: selectedOption.regimeCode,
372
+
373
+ country: line.country
374
+ ? { ...line.country, id: selectedHotel.countryId ?? line.country.id, name: selectedHotel.countryName ?? line.country.name }
375
+ : selectedHotel.countryId
376
+ ? { id: selectedHotel.countryId, name: selectedHotel.countryName, localizations: [] }
377
+ : line.country,
378
+
379
+ region: line.region
380
+ ? { ...line.region, id: selectedHotel.regionId ?? line.region.id, name: selectedHotel.regionName ?? line.region.name }
381
+ : selectedHotel.regionId
382
+ ? { id: selectedHotel.regionId, name: selectedHotel.regionName, localizations: [] }
383
+ : line.region,
384
+
385
+ oord: line.oord
386
+ ? { ...line.oord, id: selectedHotel.oordId ?? line.oord.id, name: selectedHotel.oordName ?? line.oord.name }
387
+ : selectedHotel.oordId
388
+ ? { id: selectedHotel.oordId, name: selectedHotel.oordName, localizations: [] }
389
+ : line.oord,
390
+
391
+ location: line.location
392
+ ? { ...line.location, id: selectedHotel.locationId ?? line.location.id, name: selectedHotel.locationName ?? line.location.name }
393
+ : selectedHotel.locationId
394
+ ? { id: selectedHotel.locationId, name: selectedHotel.locationName, localizations: [] }
395
+ : line.location,
396
+
397
+ latitude: selectedHotel.latitude ?? line.latitude,
398
+ longitude: selectedHotel.longitude ?? line.longitude,
399
+
400
+ from: selectedHotel.fromDate ?? line.from,
401
+ to: selectedHotel.toDate ?? line.to,
402
+ isChanged: true
403
+ };
434
404
  });
435
405
 
436
- return requestRooms;
406
+ return {
407
+ ...sourceEntry,
408
+ lines: updatedLines
409
+ };
437
410
  };
438
411
 
412
+ const activeSearchSeed = React.useMemo(() => {
413
+ if (selectedAccommodationSeed) {
414
+ return selectedAccommodationSeed;
415
+ }
416
+
417
+ if (typeof window === 'undefined') return null;
418
+
419
+ const params = new URLSearchParams(window.location.search);
420
+ return buildSearchSeedFromQueryParams(params);
421
+ }, [selectedAccommodationSeed, currentSearch]);
422
+
439
423
  useEffect(() => {
440
424
  if (typeof document !== 'undefined') {
441
425
  document.body.classList.toggle('has-overlay', filtersOpen);
442
426
  }
443
427
  }, [filtersOpen]);
444
428
 
445
- // seperate Search
446
- useEffect(() => {
447
- const runSearch = async () => {
429
+ const runSearch = async () => {
430
+ try {
431
+ if (!context) return;
448
432
  dispatch(setIsLoading(true));
449
- try {
450
- if (!context) {
451
- return;
452
- }
453
433
 
454
- const config: TideClientConfig = {
455
- host: context.tideConnection.host,
456
- apiKey: context.tideConnection.apiKey
457
- };
434
+ const config: TideClientConfig = {
435
+ host: context.tideConnection.host,
436
+ apiKey: context.tideConnection.apiKey
437
+ };
458
438
 
459
- const params = new URLSearchParams(location.search);
460
- let entryId = getStringFromParams(params, 'entryId');
461
- let entryLight: EntryLight | null = null;
462
- // If entryId is present, we want to fetch the details of that entry and use the details to populate the search results, instead of running a search with the other query params
439
+ const seed = activeSearchSeed;
440
+ if (!seed) {
441
+ throw new Error('Invalid search parameters');
442
+ }
463
443
 
464
- let searchRequest: BookingPackageRequest<BookingPackageSearchRequest>;
444
+ const searchRequest = buildSearchFromSeed(seed);
445
+ const packageSearchResults = await search(config, searchRequest);
465
446
 
466
- if (entryId) {
467
- entryLight = await getEntryLight(config, entryId);
468
- // populate itinerary store
469
- dispatch(setEntry({ entry: entryLight }));
470
- searchRequest = buildSearchFromEntry(entryLight);
471
- } else {
472
- const rq = buildSearchFromQueryParams(params);
473
- if (!rq) {
474
- throw new Error('Invalid search parameters');
475
- }
447
+ const enrichedFilters = enrichFiltersWithResults(packageSearchResults, context.filters, context.tags ?? []);
448
+ if (!initialFiltersSet) {
449
+ dispatch(resetFilters(enrichedFilters));
450
+ setInitialFilters(enrichedFilters);
451
+ setInitialFiltersSet(true);
452
+ }
476
453
 
477
- searchRequest = rq;
454
+ dispatch(setResults(packageSearchResults));
455
+ const initialFilteredResults = applyFilters(packageSearchResults, filters, null);
456
+ dispatch(setFilteredResults(initialFilteredResults));
457
+
458
+ if (packageSearchResults?.length > 0) {
459
+ if (context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight) {
460
+ dispatch(setSelectedSearchResult(packageSearchResults[0]));
478
461
  }
479
- const packageSearchResults = await search(config, searchRequest);
462
+ }
463
+ } catch (err) {
464
+ console.error('Search failed', err);
465
+ } finally {
466
+ dispatch(setIsLoading(false));
467
+ }
468
+ };
480
469
 
481
- console.log('Search results', packageSearchResults);
470
+ const runStartTransaction = async (): Promise<string | null> => {
471
+ try {
472
+ if (!context) return null;
482
473
 
483
- const enrichedFilters = enrichFiltersWithResults(packageSearchResults, context.filters, context.tags ?? []);
484
- if (!initialFiltersSet) {
485
- dispatch(resetFilters(enrichedFilters));
486
- setInitialFilters(enrichedFilters);
487
- setInitialFiltersSet(true);
488
- }
474
+ const config: TideClientConfig = {
475
+ host: context.tideConnection.host,
476
+ apiKey: context.tideConnection.apiKey
477
+ };
489
478
 
490
- dispatch(setResults(packageSearchResults));
491
- const initialFilteredResults = applyFilters(packageSearchResults, filters, null);
492
- dispatch(setFilteredResults(initialFilteredResults));
493
-
494
- if (packageSearchResults?.length > 0) {
495
- if (entryId) {
496
- const matching = packageSearchResults.find((r) => r.productId === entry?.id);
497
-
498
- if (matching) {
499
- dispatch(setSelectedSearchResult(matching));
500
- }
501
- } else {
502
- if (context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight) {
503
- dispatch(setSelectedSearchResult(packageSearchResults[0]));
504
- }
505
- }
506
- }
479
+ const transaction = await startTransaction(config);
480
+ console.log('Transaction started', transaction);
507
481
 
508
- dispatch(setIsLoading(false));
509
- } catch (err) {
510
- console.error('Search failed', err);
511
- dispatch(setIsLoading(false));
512
- }
513
- };
482
+ dispatch(setTransactionId(transaction.transactionId));
483
+
484
+ return transaction.transactionId;
485
+ } catch (err) {
486
+ console.error('Transaction failed', err);
487
+ return null;
488
+ }
489
+ };
514
490
 
515
- const runHotelSearch = async () => {
491
+ const runHotelSearch = async (currentTransactionId: string, seed: SearchSeed) => {
492
+ try {
493
+ if (!context) return;
516
494
  dispatch(setIsLoading(true));
517
- try {
518
- if (!context) {
519
- return;
520
- }
521
495
 
522
- const config: TideClientConfig = {
523
- host: context.tideConnection.host,
524
- apiKey: context.tideConnection.apiKey
525
- };
496
+ const config: TideClientConfig = {
497
+ host: context.tideConnection.host,
498
+ apiKey: context.tideConnection.apiKey
499
+ };
526
500
 
527
- const params = new URLSearchParams(location.search);
501
+ let searchRequest: PackagingAccommodationRequest = buildPackagingAccommodationRequestFromSeed(seed, currentTransactionId);
502
+ searchRequest.portalId = context.portalId;
503
+ searchRequest.agentId = context.agentId;
528
504
 
529
- let searchRequest: PackagingAccommodationRequest;
505
+ const packageAccoSearchResults = await searchPackagingAccommodations(config, searchRequest);
530
506
 
531
- const rq = buildPackagingAccommodationRequestFromQueryParams(params);
532
- if (!rq) {
533
- throw new Error('Invalid search parameters');
534
- }
507
+ const enrichedFilters = enrichFiltersWithPackageAccoResults(packageAccoSearchResults, context.filters, context.tags ?? []);
508
+ if (!initialFiltersSet) {
509
+ dispatch(resetFilters(enrichedFilters));
510
+ setInitialFilters(enrichedFilters);
511
+ setInitialFiltersSet(true);
512
+ }
535
513
 
536
- searchRequest = rq;
537
- searchRequest.portalId = context.portalId;
538
- searchRequest.agentId = context.agentId;
514
+ dispatch(setPackagingAccoResults(packageAccoSearchResults));
515
+ const initialFilteredResults = applyFiltersToPackageAccoResults(packageAccoSearchResults, filters, null);
516
+ dispatch(setFilteredPackagingAccoResults(initialFilteredResults));
539
517
 
540
- const packageAccoSearchResults = await searchPackagingAccommodations(config, searchRequest);
518
+ dispatch(setIsLoading(false));
519
+ } catch (err) {
520
+ console.error('Search failed', err);
521
+ dispatch(setIsLoading(false));
522
+ }
523
+ };
541
524
 
542
- console.log('package Acco SearchResults', packageAccoSearchResults);
525
+ const runAccommodationFlow = async (seed: SearchSeed) => {
526
+ if (!context || context.showMockup) return;
543
527
 
544
- const enrichedFilters = enrichFiltersWithPackageAccoResults(packageAccoSearchResults, context.filters, context.tags ?? []);
545
- if (!initialFiltersSet) {
546
- dispatch(resetFilters(enrichedFilters));
547
- setInitialFilters(enrichedFilters);
548
- setInitialFiltersSet(true);
549
- }
528
+ let currentTransactionId = context?.packagingEntry?.transactionId || transactionId;
529
+ if (!currentTransactionId) {
530
+ dispatch(setIsLoading(true));
531
+ currentTransactionId = await runStartTransaction();
532
+ }
550
533
 
551
- dispatch(setPackagingAccoResults(packageAccoSearchResults));
552
- const initialFilteredResults = applyFiltersToPackageAccoResults(packageAccoSearchResults, filters, null);
553
- dispatch(setFilteredPackagingAccoResults(initialFilteredResults));
534
+ if (!currentTransactionId) {
535
+ dispatch(setIsLoading(false));
536
+ return;
537
+ }
554
538
 
555
- dispatch(setIsLoading(false));
556
- } catch (err) {
557
- console.error('Search failed', err);
558
- dispatch(setIsLoading(false));
559
- }
560
- };
539
+ await runHotelSearch(currentTransactionId, seed);
540
+ };
561
541
 
562
- if (!context?.showMockup) {
563
- if (
564
- context?.searchConfiguration.qsmType === PortalQsmType.GroupTour ||
565
- (context?.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && !context.searchConfiguration.enableManualPackaging)
566
- ) {
567
- runSearch();
568
- }
569
- if (context?.searchConfiguration.qsmType === PortalQsmType.Accommodation) {
570
- runHotelSearch();
542
+ // separate Search
543
+ useEffect(() => {
544
+ if (
545
+ context?.searchConfiguration.qsmType === PortalQsmType.GroupTour ||
546
+ (context?.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && !context.searchConfiguration.enableManualPackaging)
547
+ ) {
548
+ runSearch();
549
+ }
550
+
551
+ if (context?.searchConfiguration.qsmType === PortalQsmType.Accommodation) {
552
+ const seed = activeSearchSeed;
553
+ if (seed) {
554
+ runAccommodationFlow(seed);
571
555
  }
572
- if (context?.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && context.searchConfiguration.enableManualPackaging) {
573
- // Manual packaging flow.
574
- if (context.searchConfiguration.allowAccommodations) {
575
- runHotelSearch();
576
- }
556
+ }
557
+
558
+ if (
559
+ context?.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight &&
560
+ context.searchConfiguration.enableManualPackaging &&
561
+ context.searchConfiguration.allowAccommodations &&
562
+ !context?.packagingEntry
563
+ ) {
564
+ const seed = activeSearchSeed;
565
+ if (seed) {
566
+ runAccommodationFlow(seed);
577
567
  }
578
568
  }
579
- }, [location.search]);
569
+ }, [
570
+ location.search,
571
+ context?.showMockup,
572
+ context?.searchConfiguration.qsmType,
573
+ context?.searchConfiguration.enableManualPackaging,
574
+ context?.searchConfiguration.allowAccommodations,
575
+ context?.packagingEntry?.transactionId,
576
+ activeSearchSeed
577
+ ]);
580
578
 
581
- // Seperate detailsCall
579
+ useEffect(() => {
580
+ if (context?.packagingEntry) {
581
+ console.log('original packaging entry from context', context.packagingEntry);
582
+ dispatch(setEditablePackagingEntry(structuredClone(context.packagingEntry)));
583
+ dispatch(setTransactionId(context.packagingEntry.transactionId));
584
+ }
585
+ }, [context?.packagingEntry]);
586
+
587
+ // separate detailsCall
582
588
  useEffect(() => {
583
589
  const fetchDetails = async () => {
584
- setDetailsIsLoading(true);
585
- console.log('Fetching details for selected search result', selectedSearchResult);
586
590
  if (!selectedSearchResult || !context) return;
591
+ setDetailsIsLoading(true);
587
592
  if (context?.searchConfiguration.qsmType === PortalQsmType.Accommodation || context?.searchConfiguration.qsmType === PortalQsmType.GroupTour) {
588
593
  handleFlyInToggle(true);
589
594
  }
@@ -600,15 +605,13 @@ const SearchResultsContainer: React.FC = () => {
600
605
  return;
601
606
  }
602
607
 
603
- const params = new URLSearchParams(location.search);
604
- let entryId = getStringFromParams(params, 'entryId');
608
+ let requestRooms: BookingPackageRequestRoom[];
605
609
 
606
- let requestRooms;
607
- if (entry && entryId) {
608
- requestRooms = getRequestRoomsFromEntry(entry.rooms);
610
+ if (context?.packagingEntry) {
611
+ requestRooms = getRequestRoomsFromPackagingEntry(context.packagingEntry);
609
612
  } else {
610
- const rooms = getRoomsFromParams(params, 'rooms');
611
- requestRooms = getRequestRooms(rooms);
613
+ const seed = activeSearchSeed;
614
+ requestRooms = seed?.rooms?.length ? seed.rooms : getRequestRooms(null);
612
615
  }
613
616
 
614
617
  const detailsRequest: BookingPackageRequest<BookingPackageDetailsRequest> = {
@@ -632,21 +635,9 @@ const SearchResultsContainer: React.FC = () => {
632
635
  agentId: context.agentId
633
636
  };
634
637
 
635
- if (entry && entryId) {
636
- requestRooms = getRequestRoomsFromEntry(entry.rooms);
637
- const detailsResponse = await details(config, detailsRequest);
638
- console.log('Details:', detailsResponse);
639
- dispatch(setBookingPackageDetails({ details: detailsResponse?.payload }));
640
- } else {
641
- // const detailsWLResponse = await detailsWL(config, detailsRequest);
642
- // console.log('Details with entryLight:', detailsWLResponse);
643
- // dispatch(setBookingPackageDetails({ details: detailsWLResponse?.payload?.bookingPackage }));
644
- // dispatch(setEntry({ entry: detailsWLResponse?.payload?.entry }));
645
-
646
- const detailsResponse = await details(config, detailsRequest);
647
- dispatch(setBookingPackageDetails({ details: detailsResponse?.payload }));
648
- setDetailsIsLoading(false);
649
- }
638
+ const detailsResponse = await details(config, detailsRequest);
639
+ dispatch(setBookingPackageDetails({ details: detailsResponse?.payload }));
640
+ setDetailsIsLoading(false);
650
641
  } catch (err) {
651
642
  console.error('Failed to fetch package details', err);
652
643
  setDetailsIsLoading(false);
@@ -655,8 +646,12 @@ const SearchResultsContainer: React.FC = () => {
655
646
 
656
647
  const fetchPackagingAccoSearchDetails = async () => {
657
648
  if (!selectedPackagingAccoResultCode || !context) return;
658
-
659
- if (context?.searchConfiguration.qsmType === PortalQsmType.Accommodation || context?.searchConfiguration.qsmType === PortalQsmType.GroupTour) {
649
+ setDetailsIsLoading(true);
650
+ if (
651
+ context?.searchConfiguration.qsmType === PortalQsmType.Accommodation ||
652
+ context?.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight ||
653
+ context?.searchConfiguration.qsmType === PortalQsmType.GroupTour
654
+ ) {
660
655
  handleFlyInToggle(true);
661
656
  }
662
657
 
@@ -666,19 +661,15 @@ const SearchResultsContainer: React.FC = () => {
666
661
  apiKey: context.tideConnection.apiKey
667
662
  };
668
663
 
669
- console.log('selectedPackagingAccoResultCode', selectedPackagingAccoResultCode);
670
664
  const selectedItem = packagingAccoResults.find((r) => r.code === selectedPackagingAccoResultCode);
671
- console.log('Selected packaging acco item', selectedItem);
672
665
  if (!selectedItem) {
673
666
  // TODO: handle this case better, show an error message to the user
674
667
  return;
675
668
  }
676
669
 
677
- const params = new URLSearchParams(location.search);
678
- const rooms = getRoomsFromParams(params, 'rooms');
679
- let tagId = getNumberFromParams(params, 'tagId');
680
-
681
- let destinationAirport = getStringFromParams(params, 'destinationAirport');
670
+ const seed = activeSearchSeed;
671
+ const tagId = seed?.tagId ?? null;
672
+ const destinationAirport = seed?.destinationAirport ?? null;
682
673
 
683
674
  let destinationId: number | null = null;
684
675
  let destinationIsCountry = false;
@@ -706,6 +697,7 @@ const SearchResultsContainer: React.FC = () => {
706
697
  }
707
698
 
708
699
  const detailSearchRequest: PackagingAccommodationRequest = {
700
+ transactionId: transactionId ?? '',
709
701
  officeId: 1,
710
702
  portalId: context.portalId,
711
703
  agentId: context.agentId,
@@ -713,7 +705,7 @@ const SearchResultsContainer: React.FC = () => {
713
705
  searchConfigurationId: context!.searchConfiguration.id,
714
706
  vendorConfigurationId: selectedItem.vendorId,
715
707
  language: context!.languageCode ?? 'en-GB',
716
- serviceType: 3,
708
+ serviceType: ACCOMMODATION_SERVICE_TYPE,
717
709
  fromDate: selectedItem.fromDate,
718
710
  toDate: selectedItem.toDate,
719
711
  destination: {
@@ -726,15 +718,16 @@ const SearchResultsContainer: React.FC = () => {
726
718
  code: destinationCode
727
719
  } as PackagingDestination,
728
720
  productCode: selectedItem.code ? selectedItem.code : '',
729
- rooms: getPackagingRequestRooms(rooms),
721
+ rooms: getPackagingRequestRoomsFromBookingRooms(seed?.rooms ?? null),
730
722
  tagIds: tagId ? [tagId] : []
731
723
  };
732
724
 
733
725
  const packageAccoSearchDetails = await searchPackagingAccommodations(config, detailSearchRequest);
734
- console.log('Packaging Acco Search details', packageAccoSearchDetails);
735
726
  dispatch(setPackagingAccoSearchDetails(packageAccoSearchDetails));
727
+ setDetailsIsLoading(false);
736
728
  } catch (err) {
737
729
  console.error('Failed to fetch package details', err);
730
+ setDetailsIsLoading(false);
738
731
  }
739
732
  };
740
733
 
@@ -744,6 +737,7 @@ const SearchResultsContainer: React.FC = () => {
744
737
  if (selectedPackagingAccoResultCode) {
745
738
  fetchPackagingAccoSearchDetails();
746
739
  }
740
+ dispatch(setAccommodationFlyInStep('details'));
747
741
  }, [selectedSearchResult, selectedPackagingAccoResultCode]);
748
742
 
749
743
  useEffect(() => {
@@ -756,6 +750,75 @@ const SearchResultsContainer: React.FC = () => {
756
750
  }
757
751
  }, [filters, results, packagingAccoResults, selectedSortType]);
758
752
 
753
+ useEffect(() => {
754
+ setInitialFiltersSet(false);
755
+ }, [activeSearchSeed]);
756
+
757
+ const handleEditAccommodation = async (segments: PackagingEntryLine[]) => {
758
+ const sourceEntry = editablePackagingEntry ?? context?.packagingEntry;
759
+ if (!sourceEntry) return;
760
+
761
+ const seed = buildSearchSeedFromAccommodationSegments(sourceEntry, segments);
762
+ if (!seed) return;
763
+
764
+ setDetailsIsLoading(true);
765
+
766
+ setSelectedAccommodationSeed(seed);
767
+ dispatch(setAccommodationFlyInStep('results'));
768
+ handleFlyInToggle(true);
769
+
770
+ await runAccommodationFlow(seed);
771
+ setDetailsIsLoading(false);
772
+ };
773
+
774
+ const buildSearchSeedFromAccommodationSegments = (entry: PackagingEntry, segments: PackagingEntryLine[]): SearchSeed | null => {
775
+ if (!segments?.length) return null;
776
+
777
+ const sortedSegments = [...segments].sort((a, b) => new Date(a.from).getTime() - new Date(b.from).getTime());
778
+
779
+ const firstSegment = first(sortedSegments);
780
+ const lastSegment = last(sortedSegments);
781
+
782
+ if (!firstSegment || !lastSegment) return null;
783
+
784
+ return {
785
+ fromDate: toDateOnlyString(firstSegment.from),
786
+ toDate: toDateOnlyString(lastSegment.to),
787
+ country: firstSegment.country?.id ?? null,
788
+ region: firstSegment.region?.id ?? null,
789
+ oord: firstSegment.oord?.id ?? null,
790
+ location: firstSegment.location?.id ?? null,
791
+ hotel: parseHotelId(firstSegment),
792
+ hotelCode: firstSegment.productCode ?? null,
793
+ tagId: null,
794
+ destinationAirport: getDestinationAirportFromEntry(entry.lines ?? []),
795
+ departureAirport: getDepartureAirportFromEntry(entry.lines ?? []),
796
+ rooms: getRequestRoomsFromPackagingSegments(entry, sortedSegments)
797
+ };
798
+ };
799
+
800
+ useEffect(() => {
801
+ const fetchPriceDetails = async () => {
802
+ if (!context || !editablePackagingEntry) return;
803
+ setPricesAreLoading(true);
804
+ try {
805
+ const config: TideClientConfig = {
806
+ host: context.tideConnection.host,
807
+ apiKey: context.tideConnection.apiKey
808
+ };
809
+
810
+ const priceDetails = await getPriceDetails(config, editablePackagingEntry);
811
+ dispatch(setPriceDetails(priceDetails));
812
+ setPricesAreLoading(false);
813
+ } catch (err) {
814
+ console.error('Error fetching price details', err);
815
+ setPricesAreLoading(false);
816
+ }
817
+ };
818
+
819
+ fetchPriceDetails();
820
+ }, [editablePackagingEntry]);
821
+
759
822
  return (
760
823
  <div id="tide-booking" className="search__bg">
761
824
  {context && (
@@ -790,7 +853,12 @@ const SearchResultsContainer: React.FC = () => {
790
853
  />
791
854
  )}
792
855
  {context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && (
793
- <Itinerary isOpen={itineraryOpen} handleSetIsOpen={() => setItineraryOpen(!itineraryOpen)} isLoading={isLoading} />
856
+ <Itinerary
857
+ isOpen={itineraryOpen}
858
+ handleSetIsOpen={() => setItineraryOpen(!itineraryOpen)}
859
+ isLoading={pricesAreLoading}
860
+ onEditAccommodation={handleEditAccommodation}
861
+ />
794
862
  )}
795
863
  {/* ---------------- Results ---------------- */}
796
864
  <div className="search__results">
@@ -826,7 +894,7 @@ const SearchResultsContainer: React.FC = () => {
826
894
  )}
827
895
  <div className="search__result-row">
828
896
  <span className="search__result-row-text">
829
- {!isLoading && (
897
+ {!isLoading && !context.packagingEntry && (
830
898
  <>
831
899
  {((context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight &&
832
900
  context.searchConfiguration.enableManualPackaging) ||
@@ -838,7 +906,7 @@ const SearchResultsContainer: React.FC = () => {
838
906
  </>
839
907
  )}
840
908
  </span>
841
- {!isMobile && sortByTypes && sortByTypes.length > 0 && (
909
+ {!context.packagingEntry && !isMobile && sortByTypes && sortByTypes.length > 0 && (
842
910
  <div className="search__result-row-filter">
843
911
  <ItemPicker
844
912
  items={sortByTypes}
@@ -855,21 +923,29 @@ const SearchResultsContainer: React.FC = () => {
855
923
  </div>
856
924
 
857
925
  <div className="search__results__wrapper">
858
- {context.showTabViews && <TabViews />}
926
+ {context.showTabViews &&
927
+ (context.searchConfiguration.qsmType === PortalQsmType.GroupTour ||
928
+ context.searchConfiguration.qsmType === PortalQsmType.Accommodation) && <TabViews />}
859
929
 
860
930
  {context.showRoundTripResults && context.showMockup && <RoundTripResults />}
861
931
 
862
932
  {context.searchConfiguration.qsmType === PortalQsmType.GroupTour && <GroupTourResults isLoading={isLoading} />}
863
933
 
864
934
  {context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight &&
935
+ !context.packagingEntry &&
865
936
  context.showFlightResults &&
866
937
  bookingPackageDetails?.outwardFlights && <FlightResults flights={bookingPackageDetails?.outwardFlights} isDeparture={true} />}
867
938
 
868
- {context.showHotelAccommodationResults && <HotelAccommodationResults isLoading={isLoading} />}
939
+ {context.showHotelAccommodationResults && !context.packagingEntry && <HotelAccommodationResults isLoading={isLoading} />}
869
940
 
870
941
  {context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight &&
942
+ !context.packagingEntry &&
871
943
  context.showFlightResults &&
872
944
  bookingPackageDetails?.returnFlights && <FlightResults flights={bookingPackageDetails?.returnFlights} isDeparture={false} />}
945
+
946
+ {context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && context.packagingEntry && (
947
+ <span>TODO: Show Full Itinerary here</span>
948
+ )}
873
949
  </div>
874
950
  </div>
875
951
  {/* <button onClick={() => handleFlyInToggle(!flyInIsOpen)}>Toggle FlyIn</button> */}
@@ -878,8 +954,11 @@ const SearchResultsContainer: React.FC = () => {
878
954
  srpType={context.searchConfiguration.qsmType}
879
955
  isOpen={flyInIsOpen}
880
956
  setIsOpen={handleFlyInToggle}
957
+ handleConfirm={() => handleConfirmHotelSwap()}
881
958
  onPanelRef={(el) => (panelRef.current = el)}
882
959
  detailsLoading={detailsIsLoading}
960
+ accommodationStep={accommodationFlyInStep}
961
+ isPackageEditFlow={!!context.packagingEntry}
883
962
  />
884
963
  </>
885
964
  )}