@qite/tide-booking-component 1.4.70 → 1.4.71

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 (40) hide show
  1. package/build/build-cjs/index.js +717 -616
  2. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +2 -2
  3. package/build/build-cjs/src/shared/components/flyin/accommodation-flyin.d.ts +8 -0
  4. package/build/build-cjs/src/shared/components/flyin/flights-flyin.d.ts +7 -0
  5. package/build/build-cjs/src/shared/components/{flyin.d.ts → flyin/flyin.d.ts} +3 -2
  6. package/build/build-cjs/src/shared/utils/localization-util.d.ts +1 -0
  7. package/build/build-esm/index.js +703 -612
  8. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +2 -2
  9. package/build/build-esm/src/shared/components/flyin/accommodation-flyin.d.ts +8 -0
  10. package/build/build-esm/src/shared/components/flyin/flights-flyin.d.ts +7 -0
  11. package/build/build-esm/src/shared/components/{flyin.d.ts → flyin/flyin.d.ts} +3 -2
  12. package/build/build-esm/src/shared/utils/localization-util.d.ts +1 -0
  13. package/package.json +2 -2
  14. package/src/qsm/components/QSMContainer/qsm-container.tsx +13 -1
  15. package/src/search-results/components/group-tour/group-tour-card.tsx +15 -1
  16. package/src/search-results/components/hotel/hotel-card.tsx +11 -8
  17. package/src/search-results/components/search-results-container/search-results-container.tsx +32 -12
  18. package/src/search-results/store/search-results-slice.ts +5 -5
  19. package/src/shared/components/flyin/accommodation-flyin.tsx +40 -0
  20. package/src/shared/components/flyin/flights-flyin.tsx +499 -0
  21. package/src/shared/components/flyin/flyin.tsx +79 -0
  22. package/src/shared/translations/ar-SA.json +2 -1
  23. package/src/shared/translations/da-DK.json +2 -1
  24. package/src/shared/translations/de-DE.json +2 -1
  25. package/src/shared/translations/en-GB.json +2 -1
  26. package/src/shared/translations/es-ES.json +2 -1
  27. package/src/shared/translations/fr-BE.json +2 -1
  28. package/src/shared/translations/fr-FR.json +2 -1
  29. package/src/shared/translations/is-IS.json +2 -1
  30. package/src/shared/translations/it-IT.json +2 -1
  31. package/src/shared/translations/ja-JP.json +2 -1
  32. package/src/shared/translations/nl-BE.json +2 -1
  33. package/src/shared/translations/nl-NL.json +2 -1
  34. package/src/shared/translations/no-NO.json +2 -1
  35. package/src/shared/translations/pl-PL.json +2 -1
  36. package/src/shared/translations/pt-PT.json +2 -1
  37. package/src/shared/translations/sv-SE.json +2 -1
  38. package/src/shared/utils/localization-util.ts +1 -1
  39. package/styles/components/_flyin.scss +10 -0
  40. package/src/shared/components/flyin.tsx +0 -547
@@ -3,7 +3,7 @@ import { BookingPackage, BookingPackageItem, EntryLight } from '@qite/tide-clien
3
3
  export interface SearchResultsState {
4
4
  results: BookingPackageItem[];
5
5
  filteredResults: BookingPackageItem[];
6
- selectedHotelId: number | null;
6
+ selectedSearchResultId: number | null;
7
7
  selectedFlight: ExtendedFlightSearchResponseItem | null;
8
8
  selectedFlightDetails: ExtendedFlightSearchResponseItem | null;
9
9
  bookingPackageDetails: BookingPackage | null;
@@ -17,7 +17,7 @@ export interface SearchResultsState {
17
17
  }
18
18
  export declare const setResults: import('@reduxjs/toolkit').ActionCreatorWithPayload<BookingPackageItem[], 'searchResults/setResults'>,
19
19
  setFilteredResults: import('@reduxjs/toolkit').ActionCreatorWithPayload<BookingPackageItem[], 'searchResults/setFilteredResults'>,
20
- setSelectedHotel: import('@reduxjs/toolkit').ActionCreatorWithPayload<number | null, 'searchResults/setSelectedHotel'>,
20
+ setSelectedSearchResult: import('@reduxjs/toolkit').ActionCreatorWithPayload<number | null, 'searchResults/setSelectedSearchResult'>,
21
21
  setSelectedFlight: import('@reduxjs/toolkit').ActionCreatorWithPayload<ExtendedFlightSearchResponseItem | null, 'searchResults/setSelectedFlight'>,
22
22
  setSelectedFlightDetails: import('@reduxjs/toolkit').ActionCreatorWithPayload<
23
23
  ExtendedFlightSearchResponseItem | null,
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ type AccommodationFlyInProps = {
3
+ isLoading: boolean;
4
+ isOpen: boolean;
5
+ setIsOpen: (open: boolean) => void;
6
+ };
7
+ declare const AccommodationFlyIn: React.FC<AccommodationFlyInProps>;
8
+ export default AccommodationFlyIn;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ type FlightsFlyInProps = {
3
+ isOpen: boolean;
4
+ setIsOpen: (open: boolean) => void;
5
+ };
6
+ declare const FlightsFlyIn: React.FC<FlightsFlyInProps>;
7
+ export default FlightsFlyIn;
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import { SRPType } from '../types';
2
+ import { SRPType } from '../../types';
3
3
  type FlyInProps = {
4
- srpType?: SRPType;
4
+ title: string;
5
+ srpType: SRPType;
5
6
  isOpen: boolean;
6
7
  setIsOpen: (open: boolean) => void;
7
8
  className?: string;
@@ -55,6 +55,7 @@ export declare const getTranslations: (language: string) => {
55
55
  FLIGHTS_FOUND_1: string;
56
56
  FLIGHTS_FOUND_2: string;
57
57
  FLIGHTS_FOUND_3: string;
58
+ SELECT_YOUR_FARE: string;
58
59
  };
59
60
  PRODUCT: {
60
61
  STAY_INCLUDED: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qite/tide-booking-component",
3
- "version": "1.4.70",
3
+ "version": "1.4.71",
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",
@@ -29,7 +29,7 @@
29
29
  "devDependencies": {
30
30
  "@jsonurl/jsonurl": "^1.1.4",
31
31
  "@popperjs/core": "^2.10.2",
32
- "@qite/tide-client": "^1.1.141",
32
+ "@qite/tide-client": "^1.1.143",
33
33
  "@reduxjs/toolkit": "^2.8.2",
34
34
  "@rollup/plugin-commonjs": "^19.0.1",
35
35
  "@rollup/plugin-json": "^4.1.0",
@@ -12,7 +12,7 @@ import TravelClassPicker from '../travel-class-picker';
12
12
  import TravelTypePicker from '../travel-type-picker';
13
13
  import Icon from '../icon';
14
14
  import TravelNationalityPicker from '../travel-nationality-picker';
15
- import { addDays, addMonths } from 'date-fns';
15
+ import { addDays, addMonths, addYears } from 'date-fns';
16
16
  import { DateRange } from '../../../booking-product/types';
17
17
  import { QSMState, setFromDate, setSelectedQsmType, setToDate, setTripType } from '../../store/qsm-slice';
18
18
  import { BaseFieldConfig, DoubleFieldConfig } from '../../types';
@@ -74,6 +74,18 @@ const QSMContainer: React.FC = () => {
74
74
 
75
75
  const handleQsmTypeChange = (value: SRPType) => {
76
76
  dispatch(setSelectedQsmType(value));
77
+
78
+ if (value === 'groupTour') {
79
+ handleDateChange({
80
+ fromDate: new Date(fromDate ?? Date.now()),
81
+ toDate: addYears(new Date(fromDate ?? Date.now()), 1)
82
+ });
83
+ } else {
84
+ handleDateChange({
85
+ fromDate: new Date(fromDate ?? Date.now()),
86
+ toDate: addDays(new Date(fromDate ?? Date.now()), 7)
87
+ });
88
+ }
77
89
  };
78
90
 
79
91
  const handleSubmit = () => {
@@ -3,6 +3,9 @@ import Icon from '../icon';
3
3
  import { BookingPackageItem } from '@qite/tide-client';
4
4
  import { format } from 'date-fns';
5
5
  import { calculateDays, calculateNights, formatPrice, getTranslations } from '../../../shared/utils/localization-util';
6
+ import { SearchResultsRootState } from '../../store/search-results-store';
7
+ import { useDispatch, useSelector } from 'react-redux';
8
+ import { setSelectedSearchResult } from '../../store/search-results-slice';
6
9
 
7
10
  interface GroupTourCardProps {
8
11
  result: BookingPackageItem;
@@ -10,13 +13,19 @@ interface GroupTourCardProps {
10
13
  }
11
14
 
12
15
  const GroupTourCard: React.FC<GroupTourCardProps> = ({ result, languageCode }) => {
16
+ const dispatch = useDispatch();
13
17
  const translations = getTranslations(languageCode ?? 'en-GB');
18
+ const { selectedSearchResultId } = useSelector((state: SearchResultsRootState) => state.searchResults);
14
19
 
15
20
  const genders = result.allotment?.travellerGenders || [];
16
21
  const maleCount = genders.filter((g) => g === 0).length;
17
22
  const femaleCount = genders.filter((g) => g === 1).length;
18
23
  const otherCount = genders.filter((g) => g === 2).length;
19
24
 
25
+ const handleChange = (productId: number) => {
26
+ dispatch(setSelectedSearchResult(productId));
27
+ };
28
+
20
29
  return (
21
30
  <div className="search__result-card">
22
31
  <div className="search__result-card__allotment">
@@ -76,7 +85,12 @@ const GroupTourCard: React.FC<GroupTourCardProps> = ({ result, languageCode }) =
76
85
  </div>
77
86
  {/* <div className="search__result-card__allotment__price__info">Gelieve € 450,00 zakgeld mee te nemen</div> */}
78
87
  </div>
79
- <button className="cta cta--select">Bekijk reis</button>
88
+ <button
89
+ type="button"
90
+ className={`cta ${selectedSearchResultId === result.productId ? 'cta--selected' : 'cta--select'}`}
91
+ onClick={() => handleChange(result.productId)}>
92
+ {selectedSearchResultId === result.productId ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT}
93
+ </button>
80
94
  </div>
81
95
  </div>
82
96
  </div>
@@ -3,7 +3,7 @@ import { HotelResult } from '../../types';
3
3
  import Icon from '../icon';
4
4
  import { useDispatch, useSelector } from 'react-redux';
5
5
  import { SearchResultsRootState } from '../../store/search-results-store';
6
- import { setSelectedHotel } from '../../store/search-results-slice';
6
+ import { setSelectedSearchResult } from '../../store/search-results-slice';
7
7
 
8
8
  interface HotelCardProps {
9
9
  result: HotelResult;
@@ -12,10 +12,10 @@ interface HotelCardProps {
12
12
 
13
13
  const HotelCard: React.FC<HotelCardProps> = ({ result, translations }) => {
14
14
  const dispatch = useDispatch();
15
- const { selectedHotelId } = useSelector((state: SearchResultsRootState) => state.searchResults);
15
+ const { selectedSearchResultId } = useSelector((state: SearchResultsRootState) => state.searchResults);
16
16
 
17
- const handleChange = (hotelProductId: number) => {
18
- dispatch(setSelectedHotel(hotelProductId));
17
+ const handleChange = (productId: number) => {
18
+ dispatch(setSelectedSearchResult(productId));
19
19
  };
20
20
 
21
21
  return (
@@ -71,12 +71,15 @@ const HotelCard: React.FC<HotelCardProps> = ({ result, translations }) => {
71
71
  <p className="search__result-card__description">{result.description}</p>
72
72
  </div>
73
73
  <div className="search__result-card__footer">
74
- <button type="button" className={`cta ${selectedHotelId === result.id ? 'cta--selected' : 'cta--select'}`} onClick={() => handleChange(result.id)}>
75
- {selectedHotelId === result.id ? 'Selected' : 'Select'}
74
+ <button
75
+ type="button"
76
+ className={`cta ${selectedSearchResultId === result.id ? 'cta--selected' : 'cta--select'}`}
77
+ onClick={() => handleChange(result.id)}>
78
+ {selectedSearchResultId === result.id ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT}
76
79
  </button>
77
- <button type="button" className="cta cta--select" onClick={() => console.log('Clicked on customCard with id:', result.id)}>
80
+ {/* <button type="button" className="cta cta--select" onClick={() => console.log('Clicked on customCard with id:', result.id)}>
78
81
  {translations?.SRP.VIEW_DETAILS}
79
- </button>
82
+ </button> */}
80
83
  </div>
81
84
  </div>
82
85
  </div>
@@ -7,7 +7,7 @@ import {
7
7
  setSortKey,
8
8
  setResults,
9
9
  setIsLoading,
10
- setSelectedHotel,
10
+ setSelectedSearchResult,
11
11
  setBookingPackageDetails,
12
12
  setEntry,
13
13
  setFlyInIsOpen,
@@ -33,7 +33,7 @@ import { Room } from '../../../booking-wizard/types';
33
33
  import Icon from '../icon';
34
34
  import Itinerary from '../itinerary';
35
35
  import TabViews from '../tab-views';
36
- import FlyIn from '../../../shared/components/flyin';
36
+ import FlyIn from '../../../shared/components/flyin/flyin';
37
37
  import HotelAccommodationResults from '../hotel/hotel-accommodation-results';
38
38
  import RoundTripResults from '../round-trip/round-trip-results';
39
39
  import { enrichFiltersWithResults } from '../filters/utility';
@@ -51,7 +51,7 @@ const SearchResultsContainer: React.FC = () => {
51
51
  const context = useContext(SearchResultsConfigurationContext);
52
52
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
53
53
 
54
- const { results, filteredResults, bookingPackageDetails, entry, isLoading, filters, sortKey, selectedHotelId, flyInIsOpen } = useSelector(
54
+ const { results, filteredResults, bookingPackageDetails, entry, isLoading, filters, sortKey, selectedSearchResultId, flyInIsOpen } = useSelector(
55
55
  (state: SearchResultsRootState) => state.searchResults
56
56
  );
57
57
 
@@ -222,6 +222,8 @@ const SearchResultsContainer: React.FC = () => {
222
222
  }
223
223
  };
224
224
 
225
+ console.log('Built search request from query params', searchRequest);
226
+
225
227
  return searchRequest;
226
228
  };
227
229
 
@@ -268,7 +270,7 @@ const SearchResultsContainer: React.FC = () => {
268
270
  var room = { index: i, pax: [] } as BookingPackageRequestRoom;
269
271
  range(0, x.adults).forEach(() => {
270
272
  room.pax.push({
271
- age: 30
273
+ age: Math.floor(Math.random() * 100)
272
274
  } as BookingPackagePax);
273
275
  });
274
276
  x.childAges.forEach((x) => {
@@ -343,10 +345,12 @@ const SearchResultsContainer: React.FC = () => {
343
345
  const matching = packageSearchResults.find((r) => r.productId === entry?.id);
344
346
 
345
347
  if (matching) {
346
- dispatch(setSelectedHotel(matching.productId));
348
+ dispatch(setSelectedSearchResult(matching.productId));
347
349
  }
348
350
  } else {
349
- dispatch(setSelectedHotel(packageSearchResults[0]?.productId));
351
+ if (context.type === 'hotel-flight') {
352
+ dispatch(setSelectedSearchResult(packageSearchResults[0]?.productId));
353
+ }
350
354
  }
351
355
  }
352
356
 
@@ -367,7 +371,11 @@ const SearchResultsContainer: React.FC = () => {
367
371
  // Seperate detailsCall
368
372
  useEffect(() => {
369
373
  const fetchPackageDetails = async () => {
370
- if (!selectedHotelId || !context) return;
374
+ if (!selectedSearchResultId || !context) return;
375
+
376
+ if (context?.type === 'hotel' || context?.type === 'groupTour') {
377
+ handleFlyInToggle(true);
378
+ }
371
379
 
372
380
  try {
373
381
  const config: TideClientConfig = {
@@ -375,7 +383,7 @@ const SearchResultsContainer: React.FC = () => {
375
383
  apiKey: context.tideConnection.apiKey
376
384
  };
377
385
 
378
- const selectedItem = results.find((r) => r.productId === selectedHotelId);
386
+ const selectedItem = results.find((r) => r.productId === selectedSearchResultId);
379
387
  if (!selectedItem) {
380
388
  // TODO: handle this case better, show an error message to the user
381
389
  return;
@@ -429,7 +437,7 @@ const SearchResultsContainer: React.FC = () => {
429
437
  };
430
438
 
431
439
  fetchPackageDetails();
432
- }, [selectedHotelId]);
440
+ }, [selectedSearchResultId]);
433
441
 
434
442
  useEffect(() => {
435
443
  const filteredResults = applyFilters(results, filters);
@@ -444,7 +452,13 @@ const SearchResultsContainer: React.FC = () => {
444
452
  {context.type === 'flight' && (
445
453
  <FlightSearchProvider tideConnection={context.tideConnection}>
446
454
  <FlightResultsContainer isMobile={isMobile} />
447
- <FlyIn srpType={context.type} isOpen={flyInIsOpen} setIsOpen={handleFlyInToggle} onPanelRef={(el) => (panelRef.current = el)} />
455
+ <FlyIn
456
+ title="Select your fare"
457
+ srpType={context.type}
458
+ isOpen={flyInIsOpen}
459
+ setIsOpen={handleFlyInToggle}
460
+ onPanelRef={(el) => (panelRef.current = el)}
461
+ />
448
462
  </FlightSearchProvider>
449
463
  )}
450
464
  {(context.type === 'hotel-flight' || context.type === 'hotel' || context.type === 'groupTour' || context.type === 'roundTrip') && (
@@ -532,10 +546,16 @@ const SearchResultsContainer: React.FC = () => {
532
546
  )}
533
547
  </div>
534
548
  </div>
549
+ {/* <button onClick={() => handleFlyInToggle(!flyInIsOpen)}>Toggle FlyIn</button> */}
550
+ <FlyIn
551
+ title={`${translations.SRP.SELECT} ${translations.SRP.ACCOMMODATION}`}
552
+ srpType={context.type}
553
+ isOpen={flyInIsOpen}
554
+ setIsOpen={handleFlyInToggle}
555
+ onPanelRef={(el) => (panelRef.current = el)}
556
+ />
535
557
  </>
536
558
  )}
537
- {/* <button onClick={() => handleFlyInToggle(!flyInIsOpen)}>Toggle FlyIn</button>
538
- <FlyIn srpType={context.type} isOpen={flyInIsOpen} setIsOpen={handleFlyInToggle} onPanelRef={(el) => (panelRef.current = el)} /> */}
539
559
  </div>
540
560
  </div>
541
561
  )}
@@ -5,7 +5,7 @@ import { BookingPackage, BookingPackageItem, EntryLight } from '@qite/tide-clien
5
5
  export interface SearchResultsState {
6
6
  results: BookingPackageItem[];
7
7
  filteredResults: BookingPackageItem[];
8
- selectedHotelId: number | null;
8
+ selectedSearchResultId: number | null;
9
9
  selectedFlight: ExtendedFlightSearchResponseItem | null;
10
10
  selectedFlightDetails: ExtendedFlightSearchResponseItem | null;
11
11
  bookingPackageDetails: BookingPackage | null;
@@ -21,7 +21,7 @@ export interface SearchResultsState {
21
21
  const initialState: SearchResultsState = {
22
22
  results: [],
23
23
  filteredResults: [],
24
- selectedHotelId: null,
24
+ selectedSearchResultId: null,
25
25
  selectedFlight: null,
26
26
  selectedFlightDetails: null,
27
27
  bookingPackageDetails: null,
@@ -44,8 +44,8 @@ const searchResultsSlice = createSlice({
44
44
  setFilteredResults(state, action: PayloadAction<BookingPackageItem[]>) {
45
45
  state.filteredResults = action.payload;
46
46
  },
47
- setSelectedHotel(state, action: PayloadAction<number | null>) {
48
- state.selectedHotelId = action.payload;
47
+ setSelectedSearchResult(state, action: PayloadAction<number | null>) {
48
+ state.selectedSearchResultId = action.payload;
49
49
  },
50
50
  setSelectedFlight(state, action: PayloadAction<ExtendedFlightSearchResponseItem | null>) {
51
51
  state.selectedFlight = action.payload;
@@ -115,7 +115,7 @@ const searchResultsSlice = createSlice({
115
115
  export const {
116
116
  setResults,
117
117
  setFilteredResults,
118
- setSelectedHotel,
118
+ setSelectedSearchResult,
119
119
  setSelectedFlight,
120
120
  setSelectedFlightDetails,
121
121
  setBookingPackageDetails,
@@ -0,0 +1,40 @@
1
+ import React, { useContext } from 'react';
2
+ import { useSelector } from 'react-redux';
3
+ import { SearchResultsRootState } from '../../../search-results/store/search-results-store';
4
+ import Spinner from '../../../search-results/components/spinner/spinner';
5
+ import SearchResultsConfigurationContext from '../../../search-results/search-results-configuration-context';
6
+ import { getTranslations } from '../../utils/localization-util';
7
+
8
+ type AccommodationFlyInProps = {
9
+ isLoading: boolean;
10
+ isOpen: boolean;
11
+ setIsOpen: (open: boolean) => void;
12
+ };
13
+
14
+ const AccommodationFlyIn: React.FC<AccommodationFlyInProps> = ({ isLoading, isOpen, setIsOpen }) => {
15
+ const context = useContext(SearchResultsConfigurationContext);
16
+ const language = context?.languageCode ?? 'en-GB';
17
+ const translations = getTranslations(language);
18
+
19
+ const { selectedSearchResultId } = useSelector((state: SearchResultsRootState) => state.searchResults);
20
+
21
+ // TODO: go to booking page?
22
+ const handleConfirm = () => {
23
+ if (isOpen) {
24
+ setIsOpen(false);
25
+ }
26
+ };
27
+
28
+ return (
29
+ <>
30
+ <div className="flyin__content">
31
+ TODO
32
+ {/* {isLoading && (
33
+ <Spinner />
34
+ )} */}
35
+ </div>
36
+ </>
37
+ );
38
+ };
39
+
40
+ export default AccommodationFlyIn;