@qite/tide-booking-component 1.4.53 → 1.4.55
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 +612 -116
- package/build/build-esm/index.js +612 -116
- package/package.json +2 -2
- package/src/content/navbar/index.tsx +3 -2
- package/src/qsm/components/QSMContainer/qsm-container.tsx +32 -34
- package/src/search-results/components/hotel/hotel-accommodation-results.tsx +3 -1
- package/src/search-results/components/search-results-container/search-results-container.tsx +50 -45
- package/src/search-results/features/flights/flight-search-results-self-contained.tsx +1 -1
- package/src/shared/translations/ar-SA.json +3 -0
- package/src/shared/translations/da-DK.json +3 -0
- package/src/shared/translations/de-DE.json +3 -0
- package/src/shared/translations/en-GB.json +3 -0
- package/src/shared/translations/es-ES.json +3 -0
- package/src/shared/translations/fr-BE.json +3 -0
- package/src/shared/translations/fr-FR.json +3 -0
- package/src/shared/translations/is-IS.json +3 -0
- package/src/shared/translations/it-IT.json +3 -0
- package/src/shared/translations/ja-JP.json +3 -0
- package/src/shared/translations/nl-BE.json +3 -0
- package/src/shared/translations/nl-NL.json +3 -0
- package/src/shared/translations/no-NO.json +3 -0
- package/src/shared/translations/pl-PL.json +3 -0
- package/src/shared/translations/pt-PT.json +3 -0
- package/src/shared/translations/sv-SE.json +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qite/tide-booking-component",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.55",
|
|
4
4
|
"description": "React Booking wizard & Booking product component for Tide",
|
|
5
5
|
"main": "build/build-cjs/index.js",
|
|
6
6
|
"types": "build/build-cjs/src/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@jsonurl/jsonurl": "^1.1.4",
|
|
30
30
|
"@popperjs/core": "^2.10.2",
|
|
31
|
-
"@qite/tide-client": "^1.1.
|
|
31
|
+
"@qite/tide-client": "^1.1.141",
|
|
32
32
|
"@reduxjs/toolkit": "^2.8.2",
|
|
33
33
|
"@rollup/plugin-commonjs": "^19.0.1",
|
|
34
34
|
"@rollup/plugin-json": "^4.1.0",
|
|
@@ -2,12 +2,13 @@ import React, { useEffect, useState } from 'react';
|
|
|
2
2
|
import LanguageSwitcher from '../components/LanguageSwitcher';
|
|
3
3
|
import Icon from '../components/icon';
|
|
4
4
|
import { NavbarProps, NavItem } from '../navbar/types';
|
|
5
|
+
import { getTranslations } from '../../shared/utils/localization-util';
|
|
5
6
|
|
|
6
7
|
const Navbar: React.FC<NavbarProps> = ({ currentPath, logo, topLinks, items, language, languages, onLanguageChange, onSearch }) => {
|
|
7
8
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
8
9
|
const [query, setQuery] = useState('');
|
|
9
10
|
const [activeMobileGroup, setActiveMobileGroup] = useState<string>();
|
|
10
|
-
|
|
11
|
+
const translations = getTranslations(language.code ?? 'en-GB');
|
|
11
12
|
const normalizePath = (path: string) => path.replace(/\/+$/, '');
|
|
12
13
|
|
|
13
14
|
useEffect(() => {
|
|
@@ -221,7 +222,7 @@ const Navbar: React.FC<NavbarProps> = ({ currentPath, logo, topLinks, items, lan
|
|
|
221
222
|
type="search"
|
|
222
223
|
value={query}
|
|
223
224
|
onChange={(e) => setQuery(e.target.value)}
|
|
224
|
-
placeholder=
|
|
225
|
+
placeholder={translations.NAVBAR.SEARCH}
|
|
225
226
|
autoComplete="off"
|
|
226
227
|
/>
|
|
227
228
|
<button type="button" className="nav__search__clear" aria-label="Clear search" onClick={() => setQuery('')}>
|
|
@@ -99,7 +99,6 @@ const QSMContainer: React.FC = () => {
|
|
|
99
99
|
|
|
100
100
|
// Filter out undefined fields before passing to addSearchFieldsToPayload
|
|
101
101
|
const searchFields = [departureAirport, destinationAirport, returnAirport, destination].filter((field): field is BaseFieldConfig => field !== undefined);
|
|
102
|
-
|
|
103
102
|
addSearchFieldsToPayload(payload, searchFields, qsmState);
|
|
104
103
|
onSubmit(payload);
|
|
105
104
|
console.log('Submitted QSM data:', payload);
|
|
@@ -219,40 +218,39 @@ const QSMContainer: React.FC = () => {
|
|
|
219
218
|
</button>
|
|
220
219
|
</div>
|
|
221
220
|
<div className="qsm__filter">
|
|
222
|
-
{qsmType === 'hotel' ||
|
|
223
|
-
|
|
224
|
-
<div className="radiobutton
|
|
225
|
-
<
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
<
|
|
241
|
-
<
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
</label>
|
|
253
|
-
</div>
|
|
221
|
+
{(qsmType === 'hotel' || qsmType === 'hotel-flight') && (
|
|
222
|
+
<div className="radiobutton-group qsm__filter__inputgroup">
|
|
223
|
+
<div className="radiobutton">
|
|
224
|
+
<label className="radiobutton__label">
|
|
225
|
+
<input
|
|
226
|
+
type="radio"
|
|
227
|
+
name="numberOfAccommodations"
|
|
228
|
+
// onChange={handleMainBookerChange}
|
|
229
|
+
// onBlur={formik.handleBlur}
|
|
230
|
+
value=""
|
|
231
|
+
checked={true}
|
|
232
|
+
readOnly
|
|
233
|
+
className="radiobutton__input"
|
|
234
|
+
/>
|
|
235
|
+
<span>{translations.QSM.ONE_ACCOMMODATION}</span>
|
|
236
|
+
</label>
|
|
237
|
+
</div>
|
|
238
|
+
<div className="radiobutton">
|
|
239
|
+
<label className="radiobutton__label">
|
|
240
|
+
<input
|
|
241
|
+
type="radio"
|
|
242
|
+
name="numberOfAccommodations"
|
|
243
|
+
// onChange={handleMainBookerChange}
|
|
244
|
+
// onBlur={formik.handleBlur}
|
|
245
|
+
value=""
|
|
246
|
+
className="radiobutton__input"
|
|
247
|
+
disabled={true}
|
|
248
|
+
/>
|
|
249
|
+
<span>{translations.QSM.MULTIPLE_ACCOMMODATIONS}</span>
|
|
250
|
+
</label>
|
|
254
251
|
</div>
|
|
255
|
-
|
|
252
|
+
</div>
|
|
253
|
+
)}
|
|
256
254
|
{qsmType === 'flight' && (
|
|
257
255
|
<div className="radiobutton-group qsm__filter__inputgroup">
|
|
258
256
|
{allowOneWay && (
|
|
@@ -44,7 +44,9 @@ const mapSearchResult = (searchResult: BookingPackageItem, cmsItem: any, languag
|
|
|
44
44
|
image: cmsItem?.content?.images?.thumbnailPicture?.url,
|
|
45
45
|
description: cmsItem?.content?.descriptions?.introductionTitle || '',
|
|
46
46
|
location:
|
|
47
|
-
searchResult.locationName
|
|
47
|
+
searchResult.locationName || searchResult.regionName
|
|
48
|
+
? `${searchResult.locationName || searchResult.regionName}${searchResult.countryName && `, ${searchResult.countryName}`}`
|
|
49
|
+
: cmsItem?.parentItem?.name || '',
|
|
48
50
|
price: formatPrice(searchResult.price, searchResult.currencyCode, languageCode),
|
|
49
51
|
ctaText: translations?.SRP.VIEW_DETAILS,
|
|
50
52
|
days: calculateNights(searchResult.stayFromDate, searchResult.stayToDate, translations),
|
|
@@ -2,7 +2,6 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
|
|
|
2
2
|
import { useDispatch, useSelector } from 'react-redux';
|
|
3
3
|
import { SearchResultsRootState } from '../../store/search-results-store';
|
|
4
4
|
import SearchResultsConfigurationContext from '../../search-results-configuration-context';
|
|
5
|
-
|
|
6
5
|
import {
|
|
7
6
|
resetFilters,
|
|
8
7
|
setSortKey,
|
|
@@ -13,10 +12,9 @@ import {
|
|
|
13
12
|
setEntry,
|
|
14
13
|
setFlyInIsOpen
|
|
15
14
|
} from '../../store/search-results-slice';
|
|
16
|
-
import { Filter,
|
|
15
|
+
import { Filter, SortByType } from '../../types';
|
|
17
16
|
import useMediaQuery from '../../../shared/utils/use-media-query-util';
|
|
18
17
|
import ItemPicker from '../item-picker';
|
|
19
|
-
|
|
20
18
|
import { TideClientConfig, details, detailsWL, getEntryLight, search } from '@qite/tide-client';
|
|
21
19
|
import {
|
|
22
20
|
BookingPackageDestination,
|
|
@@ -42,6 +40,7 @@ import FlightResults from '../flight/flight-results';
|
|
|
42
40
|
import { getTranslations } from '../../../shared/utils/localization-util';
|
|
43
41
|
import { FlightSearchProvider } from '../flight/flight-search-context';
|
|
44
42
|
import FlightResultsContainer from './flight-search-results';
|
|
43
|
+
import Filters from '../filters/filters';
|
|
45
44
|
|
|
46
45
|
const SearchResultsContainer: React.FC = () => {
|
|
47
46
|
const dispatch = useDispatch();
|
|
@@ -63,10 +62,11 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
63
62
|
|
|
64
63
|
const panelRef = useRef<HTMLDivElement | null>(null);
|
|
65
64
|
|
|
66
|
-
const
|
|
67
|
-
{
|
|
68
|
-
{
|
|
69
|
-
{
|
|
65
|
+
const sortByTypes: SortByType[] = [
|
|
66
|
+
{ direction: 'asc', label: 'price' } as SortByType,
|
|
67
|
+
{ direction: 'desc', label: 'price' } as SortByType,
|
|
68
|
+
{ direction: 'asc', label: 'departure' } as SortByType,
|
|
69
|
+
{ direction: 'desc', label: 'departure' } as SortByType
|
|
70
70
|
];
|
|
71
71
|
|
|
72
72
|
const handleFlyInToggle = (isOpen: boolean) => {
|
|
@@ -144,7 +144,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
144
144
|
return searchRequest;
|
|
145
145
|
};
|
|
146
146
|
|
|
147
|
-
const buildSearchFromQueryParams = (params: URLSearchParams): BookingPackageRequest<BookingPackageSearchRequest> => {
|
|
147
|
+
const buildSearchFromQueryParams = (params: URLSearchParams): BookingPackageRequest<BookingPackageSearchRequest> | null => {
|
|
148
148
|
let from = getDateFromParams(params, 'fromDate');
|
|
149
149
|
let to = getDateFromParams(params, 'toDate');
|
|
150
150
|
const rooms = getRoomsFromParams(params, 'rooms');
|
|
@@ -157,11 +157,9 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
157
157
|
|
|
158
158
|
// temp hardcoded params
|
|
159
159
|
if (!from || !to) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (!country && !region && !oord && !city) {
|
|
164
|
-
region = 1;
|
|
160
|
+
console.error('Missing fromDate or toDate in query params, using default values');
|
|
161
|
+
|
|
162
|
+
return null;
|
|
165
163
|
}
|
|
166
164
|
|
|
167
165
|
if (typeof window !== 'undefined') {
|
|
@@ -206,14 +204,14 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
206
204
|
toDate: to,
|
|
207
205
|
earliestFromOffset: 0,
|
|
208
206
|
latestToOffset: 0,
|
|
209
|
-
includeFlights: true,
|
|
210
|
-
regimeCodes:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
minPrice: filters.find((f) => f.property === 'price')?.selectedMin,
|
|
216
|
-
maxPrice: filters.find((f) => f.property === 'price')?.selectedMax,
|
|
207
|
+
includeFlights: context!.type === 'hotel-flight' ? true : false,
|
|
208
|
+
// regimeCodes:
|
|
209
|
+
// filters
|
|
210
|
+
// .find((f) => f.property === 'regime')
|
|
211
|
+
// ?.options?.filter((o) => o.isChecked)
|
|
212
|
+
// .flatMap((o) => o.value.toString()) || [],
|
|
213
|
+
// minPrice: filters.find((f) => f.property === 'price')?.selectedMin,
|
|
214
|
+
// maxPrice: filters.find((f) => f.property === 'price')?.selectedMax,
|
|
217
215
|
useExactDates: true,
|
|
218
216
|
onlyCachedResults: false,
|
|
219
217
|
includeAllAllotments: true,
|
|
@@ -290,7 +288,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
290
288
|
|
|
291
289
|
// seperate Search
|
|
292
290
|
useEffect(() => {
|
|
293
|
-
const
|
|
291
|
+
const runHotelSearch = async () => {
|
|
294
292
|
dispatch(setIsLoading(true));
|
|
295
293
|
try {
|
|
296
294
|
if (!context) {
|
|
@@ -315,7 +313,13 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
315
313
|
dispatch(setEntry({ entry: entryLight }));
|
|
316
314
|
searchRequest = buildSearchFromEntry(entryLight);
|
|
317
315
|
} else {
|
|
318
|
-
|
|
316
|
+
const rq = buildSearchFromQueryParams(params);
|
|
317
|
+
|
|
318
|
+
if (!rq) {
|
|
319
|
+
throw new Error('Invalid search parameters');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
searchRequest = rq;
|
|
319
323
|
}
|
|
320
324
|
|
|
321
325
|
const packageSearchResults = await search(config, searchRequest);
|
|
@@ -350,8 +354,8 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
350
354
|
};
|
|
351
355
|
|
|
352
356
|
if (!context?.showMockup) {
|
|
353
|
-
if (context?.type === 'hotel-flight') {
|
|
354
|
-
|
|
357
|
+
if (context?.type === 'hotel-flight' || context?.type === 'hotel') {
|
|
358
|
+
runHotelSearch();
|
|
355
359
|
}
|
|
356
360
|
}
|
|
357
361
|
}, [location.search, searchTrigger]);
|
|
@@ -393,7 +397,7 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
393
397
|
productCode: selectedItem.code,
|
|
394
398
|
fromDate: selectedItem.fromDate,
|
|
395
399
|
toDate: selectedItem.toDate,
|
|
396
|
-
includeFlights: true,
|
|
400
|
+
includeFlights: context!.type === 'hotel-flight' ? true : false,
|
|
397
401
|
includeHotels: true,
|
|
398
402
|
includePaxTypes: true,
|
|
399
403
|
checkExternalAvailability: true,
|
|
@@ -434,24 +438,26 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
434
438
|
<FlyIn srpType={context.type} isOpen={flyInIsOpen} setIsOpen={handleFlyInToggle} onPanelRef={(el) => (panelRef.current = el)} />
|
|
435
439
|
</FlightSearchProvider>
|
|
436
440
|
)}
|
|
437
|
-
{context.type === 'hotel-flight' && (
|
|
441
|
+
{(context.type === 'hotel-flight' || context.type === 'hotel' || context.type === 'roundTrip') && (
|
|
438
442
|
<>
|
|
439
|
-
{
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
443
|
+
{context.type != 'hotel-flight' && context.showFilters && (
|
|
444
|
+
<Filters
|
|
445
|
+
filters={filters}
|
|
446
|
+
isOpen={filtersOpen}
|
|
447
|
+
handleSetIsOpen={() => setFiltersOpen(!filtersOpen)}
|
|
448
|
+
handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
|
|
449
|
+
isLoading={isLoading}
|
|
450
|
+
/>
|
|
451
|
+
)}
|
|
452
|
+
{context.type === 'hotel-flight' && (
|
|
453
|
+
<Itinerary isOpen={itineraryOpen} handleSetIsOpen={() => setItineraryOpen(!itineraryOpen)} isLoading={isLoading} />
|
|
454
|
+
)}
|
|
449
455
|
{/* ---------------- Results ---------------- */}
|
|
450
456
|
<div className="search__results">
|
|
451
457
|
{isMobile && (
|
|
452
458
|
<div className="search__result-row">
|
|
453
459
|
<div className="search__results__actions">
|
|
454
|
-
{context.showFilters && (
|
|
460
|
+
{context.type != 'hotel-flight' && context.showFilters && (
|
|
455
461
|
<div className="cta cta--filter" onClick={() => setFiltersOpen(true)}>
|
|
456
462
|
<Icon name="ui-filter" className="mobile-filters-button__icon" height={16} />
|
|
457
463
|
{translations.SRP.FILTERS}
|
|
@@ -464,9 +470,9 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
464
470
|
</div>
|
|
465
471
|
)}
|
|
466
472
|
</div>
|
|
467
|
-
{
|
|
473
|
+
{sortByTypes && sortByTypes.length > 0 && (
|
|
468
474
|
<ItemPicker
|
|
469
|
-
items={
|
|
475
|
+
items={sortByTypes}
|
|
470
476
|
selection={sortKey || undefined}
|
|
471
477
|
label={translations.SRP.SORTBY}
|
|
472
478
|
placeholder={translations.SRP.SORTBY}
|
|
@@ -476,7 +482,6 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
476
482
|
)}
|
|
477
483
|
</div>
|
|
478
484
|
)}
|
|
479
|
-
|
|
480
485
|
<div className="search__result-row">
|
|
481
486
|
<span className="search__result-row-text">
|
|
482
487
|
{!isLoading && (
|
|
@@ -485,10 +490,10 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
485
490
|
</>
|
|
486
491
|
)}
|
|
487
492
|
</span>
|
|
488
|
-
{!isMobile &&
|
|
493
|
+
{!isMobile && sortByTypes && sortByTypes.length > 0 && (
|
|
489
494
|
<div className="search__result-row-filter">
|
|
490
495
|
<ItemPicker
|
|
491
|
-
items={
|
|
496
|
+
items={sortByTypes}
|
|
492
497
|
selection={sortKey || undefined}
|
|
493
498
|
label={translations.SRP.SORTBY}
|
|
494
499
|
placeholder={translations.SRP.SORTBY}
|
|
@@ -504,13 +509,13 @@ const SearchResultsContainer: React.FC = () => {
|
|
|
504
509
|
|
|
505
510
|
{context.showRoundTripResults && context.showMockup && <RoundTripResults />}
|
|
506
511
|
|
|
507
|
-
{context.showFlightResults && bookingPackageDetails?.outwardFlights && (
|
|
512
|
+
{context.type === 'hotel-flight' && context.showFlightResults && bookingPackageDetails?.outwardFlights && (
|
|
508
513
|
<FlightResults flights={bookingPackageDetails?.outwardFlights} isDeparture={true} />
|
|
509
514
|
)}
|
|
510
515
|
|
|
511
516
|
{context.showHotelAccommodationResults && <HotelAccommodationResults isLoading={isLoading} context={context} />}
|
|
512
517
|
|
|
513
|
-
{context.showFlightResults && bookingPackageDetails?.returnFlights && (
|
|
518
|
+
{context.type === 'hotel-flight' && context.showFlightResults && bookingPackageDetails?.returnFlights && (
|
|
514
519
|
<FlightResults flights={bookingPackageDetails?.returnFlights} isDeparture={false} />
|
|
515
520
|
)}
|
|
516
521
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
|
-
import { Filter, SearchResult, SearchResultsConfiguration
|
|
2
|
+
import { Filter, SearchResult, SearchResultsConfiguration } from '../../types';
|
|
3
3
|
import SearchResults from '../..';
|
|
4
4
|
import { Footer, Navbar } from '../../../../src';
|
|
5
5
|
import { TideLogo, language, languages, topLinks, navItems } from '../../../../src/content/navbar/placeholderData';
|