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