@qite/tide-booking-component 1.4.29 → 1.4.31

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 (43) hide show
  1. package/build/build-cjs/index.js +621 -2822
  2. package/build/build-cjs/search-results/store/search-results-slice.d.ts +6 -3
  3. package/build/build-cjs/search-results/types.d.ts +9 -12
  4. package/build/build-esm/index.js +617 -2625
  5. package/build/build-esm/search-results/store/search-results-slice.d.ts +6 -3
  6. package/build/build-esm/search-results/types.d.ts +9 -12
  7. package/package.json +2 -3
  8. package/src/booking-product/components/dates.tsx +9 -4
  9. package/src/booking-wizard/components/step-indicator.tsx +11 -2
  10. package/src/booking-wizard/features/booking/booking-slice.ts +27 -2
  11. package/src/booking-wizard/features/booking/booking.tsx +32 -15
  12. package/src/booking-wizard/features/booking/selectors.ts +6 -0
  13. package/src/booking-wizard/features/flight-options/index.tsx +27 -3
  14. package/src/booking-wizard/features/product-options/option-room.tsx +1 -1
  15. package/src/booking-wizard/features/product-options/options-form.tsx +14 -4
  16. package/src/booking-wizard/features/room-options/room.tsx +1 -1
  17. package/src/booking-wizard/features/sidebar/index.tsx +4 -1
  18. package/src/booking-wizard/features/sidebar/sidebar-util.ts +1 -3
  19. package/src/booking-wizard/features/sidebar/sidebar.tsx +112 -104
  20. package/src/booking-wizard/features/travelers-form/travelers-form-slice.ts +1 -0
  21. package/src/booking-wizard/features/travelers-form/travelers-form.tsx +146 -10
  22. package/src/booking-wizard/settings-context.ts +2 -1
  23. package/src/booking-wizard/types.ts +1 -0
  24. package/src/qsm/components/search-input-group/index.tsx +17 -8
  25. package/src/search-results/components/hotel/hotel-accommodation-results.tsx +78 -83
  26. package/src/search-results/components/hotel/hotel-card.tsx +54 -24
  27. package/src/search-results/components/icon.tsx +13 -0
  28. package/src/search-results/components/item-picker/index.tsx +5 -7
  29. package/src/search-results/components/search-results-container/search-results-container.tsx +72 -117
  30. package/src/search-results/components/tab-views/index.tsx +22 -3
  31. package/src/search-results/features/flights/flight-search-results-self-contained.tsx +0 -13
  32. package/src/search-results/features/hotels/hotel-flight-search-results-self-contained.tsx +1 -8
  33. package/src/search-results/features/hotels/hotel-search-results-self-contained.tsx +1 -14
  34. package/src/search-results/features/roundtrips/roundtrip-search-results-self-contained.tsx +1 -9
  35. package/src/search-results/store/search-results-slice.ts +11 -4
  36. package/src/search-results/types.ts +11 -16
  37. package/src/shared/translations/en-GB.json +5 -1
  38. package/src/shared/translations/fr-BE.json +5 -1
  39. package/src/shared/translations/nl-BE.json +5 -1
  40. package/styles/components/_form.scss +51 -2
  41. package/styles/components/_passenger-picker.scss +3 -2
  42. package/styles/components/_qsm.scss +1 -1
  43. package/styles/qsm/_qsm.scss +67 -6
@@ -1,14 +1,16 @@
1
- import { Filter, SearchResult } from '../types';
1
+ import { Filter } from '../types';
2
+ import { BookingPackageItem } from '@qite/tide-client/build/types';
2
3
  export interface SearchResultsState {
3
- results: SearchResult[];
4
+ results: BookingPackageItem[];
4
5
  isLoading: boolean;
5
6
  filters: Filter[];
6
7
  sortKey: string | null;
8
+ activeTab: string | null;
7
9
  currentPage: number;
8
10
  }
9
11
  export declare const setResults: import('@reduxjs/toolkit').ActionCreatorWithPayload<
10
12
  {
11
- results: any[];
13
+ results: BookingPackageItem[];
12
14
  },
13
15
  'searchResults/setResults'
14
16
  >,
@@ -16,6 +18,7 @@ export declare const setResults: import('@reduxjs/toolkit').ActionCreatorWithPay
16
18
  setFilters: import('@reduxjs/toolkit').ActionCreatorWithPayload<Filter[], 'searchResults/setFilters'>,
17
19
  resetFilters: import('@reduxjs/toolkit').ActionCreatorWithPayload<Filter[], 'searchResults/resetFilters'>,
18
20
  setSortKey: import('@reduxjs/toolkit').ActionCreatorWithPayload<string | null, 'searchResults/setSortKey'>,
21
+ setActiveTab: import('@reduxjs/toolkit').ActionCreatorWithPayload<string | null, 'searchResults/setActiveTab'>,
19
22
  setCurrentPage: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, 'searchResults/setCurrentPage'>,
20
23
  resetSearchState: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<'searchResults/resetSearchState'>;
21
24
  declare const _default: import('redux').Reducer<SearchResultsState, import('redux').AnyAction>;
@@ -19,8 +19,6 @@ export interface SearchResultsConfiguration {
19
19
  showCustomCards?: boolean;
20
20
  customCardRenderer?: (result: SearchResult) => ReactNode;
21
21
  onResultClick?: (id: string) => void;
22
- sortingOptions?: SortingOption[];
23
- onSortChange?: (sortKey: string) => void;
24
22
  showMapView?: boolean;
25
23
  noResultsLabel?: string;
26
24
  isLoading?: boolean;
@@ -38,6 +36,7 @@ export interface SearchResultsConfiguration {
38
36
  loading?: string;
39
37
  searchResultCTA?: string;
40
38
  };
39
+ cmsHotelData?: any[];
41
40
  }
42
41
  export type FilterType = 'checkbox' | 'toggle' | 'slider' | 'star-rating';
43
42
  export type FilterProperty = 'regime' | 'max-duration' | 'price' | 'rating' | 'theme';
@@ -59,15 +58,6 @@ export interface Filter {
59
58
  selectedMax?: number;
60
59
  selectedRating?: number;
61
60
  }
62
- export interface Sort {
63
- label: string;
64
- icon?: ReactNode;
65
- }
66
- export interface SortingOption {
67
- key: 'price-asc' | 'price-desc' | 'duration-asc' | 'duration-desc' | 'rating-asc' | 'rating-desc';
68
- label: string;
69
- icon?: ReactNode;
70
- }
71
61
  export interface PaginationConfig {
72
62
  totalResults: number;
73
63
  currentPage: number;
@@ -81,9 +71,11 @@ export interface BaseSearchResult {
81
71
  description?: string;
82
72
  location?: string;
83
73
  tags?: Tag[];
84
- price: string;
74
+ price: string | number;
85
75
  ctaText: string;
86
76
  stars?: number;
77
+ accommodation?: string;
78
+ regime?: string;
87
79
  }
88
80
  export interface HotelResult extends BaseSearchResult {
89
81
  type: 'hotel';
@@ -121,3 +113,8 @@ export interface TravelClass {
121
113
  label: string;
122
114
  icon?: ReactNode;
123
115
  }
116
+ export interface SortingOption {
117
+ key: 'price-asc' | 'price-desc' | 'departure-date' | 'duration-asc' | 'duration-desc' | 'rating-asc' | 'rating-desc';
118
+ label: string;
119
+ icon?: ReactNode;
120
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qite/tide-booking-component",
3
- "version": "1.4.29",
3
+ "version": "1.4.31",
4
4
  "description": "React Booking wizard & Booking product component for Tide",
5
5
  "main": "build/build-cjs/index.js",
6
6
  "module": "build/build-esm/index.js",
@@ -27,7 +27,7 @@
27
27
  "devDependencies": {
28
28
  "@jsonurl/jsonurl": "^1.1.4",
29
29
  "@popperjs/core": "^2.10.2",
30
- "@qite/tide-client": "^1.1.75",
30
+ "@qite/tide-client": "^1.1.123",
31
31
  "@reach/router": "^1.3.4",
32
32
  "@reduxjs/toolkit": "^1.6.0",
33
33
  "@rollup/plugin-commonjs": "^19.0.1",
@@ -72,7 +72,6 @@
72
72
  "uuid": "^8.3.2"
73
73
  },
74
74
  "dependencies": {
75
- "@qite/tide-client": "^1.1.122",
76
75
  "react-html-comment": "^2.0.16"
77
76
  }
78
77
  }
@@ -17,15 +17,20 @@ interface DatesProps {
17
17
  const Dates: React.FC<DatesProps> = ({ value, duration, onChange }) => {
18
18
  const { language } = useContext(SettingsContext);
19
19
  const translations = getTranslations(language);
20
- const mql = typeof window !== 'undefined' ? window.matchMedia('(min-width: 1200px)') : undefined;
20
+ const mql = typeof window !== 'undefined' ? window.matchMedia('(min-width: 992px)') : undefined;
21
+ const mqm = typeof window !== 'undefined' ? window.matchMedia('(min-width: 768px)') : undefined;
21
22
 
22
23
  const [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>(null);
23
24
  const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
24
25
  const [panelActive, setPanelActive] = useState<boolean>(false);
25
26
 
26
27
  const { styles, attributes } = usePopper(referenceElement, popperElement, {
27
- placement: 'top',
28
+ placement: mql?.matches ? 'top' : 'bottom',
28
29
  modifiers: [
30
+ {
31
+ name: 'flip',
32
+ enabled: false
33
+ },
29
34
  {
30
35
  name: 'offset',
31
36
  options: {
@@ -100,9 +105,9 @@ const Dates: React.FC<DatesProps> = ({ value, duration, onChange }) => {
100
105
  className={buildClassName([
101
106
  'qsm__panel qsm__panel--bordered qsm__panel--dates-pricing',
102
107
  panelActive && 'qsm__panel--active',
103
- !mql?.matches && 'qsm__panel--mobile'
108
+ !mqm?.matches && 'qsm__panel--mobile'
104
109
  ])}
105
- style={mql?.matches ? styles.popper : undefined}
110
+ style={mqm?.matches ? styles.popper : undefined}
106
111
  {...attributes.popper}>
107
112
  <DateRangePicker
108
113
  fromDate={value?.fromDate}
@@ -1,7 +1,7 @@
1
1
  import React, { useContext } from 'react';
2
2
  import { useSelector } from 'react-redux';
3
3
  import { buildClassName } from '../../shared/utils/class-util';
4
- import { selectTranslations } from '../features/booking/selectors';
4
+ import { selectTranslations, selectTravelersFirstStep } from '../features/booking/selectors';
5
5
  import SettingsContext from '../settings-context';
6
6
 
7
7
  interface StepIndicatorsProps {
@@ -10,9 +10,15 @@ interface StepIndicatorsProps {
10
10
 
11
11
  const StepIndicators: React.FC<StepIndicatorsProps> = ({ currentStep }) => {
12
12
  const { flightOptions, roomOptions } = useContext(SettingsContext);
13
+
13
14
  const translations = useSelector(selectTranslations);
15
+ const travelersFirstStep = useSelector(selectTravelersFirstStep);
14
16
 
15
17
  const allSteps = [];
18
+
19
+ if (travelersFirstStep) {
20
+ allSteps.push(translations.STEPS.PERSONAL_DETAILS);
21
+ }
16
22
  if (!flightOptions.isHidden) {
17
23
  allSteps.push(translations.STEPS.FLIGHT_OPTIONS);
18
24
  }
@@ -21,7 +27,10 @@ const StepIndicators: React.FC<StepIndicatorsProps> = ({ currentStep }) => {
21
27
  }
22
28
 
23
29
  allSteps.push(translations.STEPS.EXTRA_OPTIONS);
24
- allSteps.push(translations.STEPS.PERSONAL_DETAILS);
30
+
31
+ if (!travelersFirstStep) {
32
+ allSteps.push(translations.STEPS.PERSONAL_DETAILS);
33
+ }
25
34
  allSteps.push(translations.STEPS.SUMMARY);
26
35
  allSteps.push(translations.STEPS.CONFIRMATION);
27
36
 
@@ -64,6 +64,9 @@ export interface BookingState {
64
64
  accommodationViewId?: number;
65
65
  accommodationViews?: { [key: string]: string };
66
66
  isOption?: boolean;
67
+ travelersFirstStep: boolean;
68
+ isFetching?: boolean;
69
+ hasMounted: boolean;
67
70
  }
68
71
 
69
72
  const initialState: BookingState = {
@@ -99,7 +102,10 @@ const initialState: BookingState = {
99
102
  tagIds: [],
100
103
  agentAdressId: undefined,
101
104
  currentStep: OPTIONS_FORM_STEP,
102
- translations: undefined
105
+ translations: undefined,
106
+ travelersFirstStep: false,
107
+ isFetching: false,
108
+ hasMounted: false
103
109
  };
104
110
 
105
111
  export const fetchPackage = createAsyncThunk('booking/fetchPackage', async (_, { dispatch }) => {
@@ -333,6 +339,12 @@ const bookingSlice = createSlice({
333
339
  name: 'booking',
334
340
  initialState,
335
341
  reducers: {
342
+ setHasMounted(state, action: PayloadAction<boolean>) {
343
+ state.hasMounted = action.payload;
344
+ },
345
+ setIsFetching(state, action: PayloadAction<boolean>) {
346
+ state.isFetching = action.payload;
347
+ },
336
348
  setOfficeId(state, action: PayloadAction<number>) {
337
349
  state.officeId = action.payload;
338
350
  },
@@ -429,6 +441,12 @@ const bookingSlice = createSlice({
429
441
  },
430
442
  setIsOption(state, action: PayloadAction<boolean>) {
431
443
  state.isOption = action.payload;
444
+ },
445
+ setTravelersFirstStep(state, action: PayloadAction<boolean>) {
446
+ state.travelersFirstStep = action.payload;
447
+ },
448
+ setIsUnavailable(state, action: PayloadAction<boolean>) {
449
+ state.isUnavailable = action.payload;
432
450
  }
433
451
  },
434
452
  extraReducers: (builder) => {
@@ -443,9 +461,12 @@ const bookingSlice = createSlice({
443
461
 
444
462
  if (!action.payload.payload) {
445
463
  state.isUnavailable = true;
464
+ /* state.package = undefined; */
446
465
  return;
447
466
  }
448
467
 
468
+ state.isUnavailable = false;
469
+
449
470
  const bookingRooms = state.bookingAttributes?.rooms;
450
471
  const flight = state.bookingAttributes?.flight;
451
472
  const packageDetails = action.payload.payload;
@@ -562,6 +583,8 @@ export const {
562
583
  setBookingNumber,
563
584
  setIsRetry,
564
585
  setFetchingPackage,
586
+ setIsFetching,
587
+ setHasMounted,
565
588
  setPackage,
566
589
  setPackageRooms,
567
590
  setPackageOptionPax,
@@ -578,7 +601,9 @@ export const {
578
601
  setPackageAirportGroups,
579
602
  setFlights,
580
603
  setAccommodationViewId,
581
- setIsOption
604
+ setIsOption,
605
+ setTravelersFirstStep,
606
+ setIsUnavailable
582
607
  } = bookingSlice.actions;
583
608
 
584
609
  export default bookingSlice.reducer;
@@ -20,13 +20,15 @@ import {
20
20
  setCalculateDeposit,
21
21
  setGeneratePaymentUrl,
22
22
  setIsRetry,
23
+ setIsUnavailable,
23
24
  setLanguageCode,
24
25
  setOfficeId,
25
26
  setPackage,
26
27
  setProductAttributes,
27
28
  setSkipPayment,
28
29
  setTagIds,
29
- setTranslations
30
+ setTranslations,
31
+ setTravelersFirstStep
30
32
  } from './booking-slice';
31
33
 
32
34
  import { isEqual, isNil } from 'lodash';
@@ -51,7 +53,8 @@ import {
51
53
  selectIsUnavailable,
52
54
  selectPackageDetails,
53
55
  selectProductAttributes,
54
- selectTranslations
56
+ selectTranslations,
57
+ selectTravelersFirstStep
55
58
  } from './selectors';
56
59
 
57
60
  interface BookingProps {
@@ -95,8 +98,9 @@ const Booking: React.FC<BookingProps> = ({ productCode, productName, thumbnailUr
95
98
  const bookingNumber = useSelector(selectBookingNumber);
96
99
  const isRetry = useSelector(selectIsRetry);
97
100
  const packageDetails = useSelector(selectPackageDetails);
98
- const isUnvailable = useSelector(selectIsUnavailable);
101
+ const isUnavailable = useSelector(selectIsUnavailable);
99
102
  const translations = useSelector(selectTranslations);
103
+ const travelersFirstStep = useSelector(selectTravelersFirstStep);
100
104
 
101
105
  useEffect(() => {
102
106
  return () => {
@@ -116,7 +120,18 @@ const Booking: React.FC<BookingProps> = ({ productCode, productName, thumbnailUr
116
120
  const startDate = getDateFromParams(params, 'startDate');
117
121
  const endDate = getDateFromParams(params, 'endDate');
118
122
  const catalogueId = getNumberFromParams(params, 'catalogueId') ?? getNumberFromParams(params, 'catalog');
119
- const rooms = getRoomsFromParams(params, 'rooms');
123
+
124
+ let rooms = getRoomsFromParams(params, 'rooms');
125
+
126
+ if (!rooms || !rooms.length) {
127
+ dispatch(setTravelersFirstStep(true));
128
+ rooms = [{ adults: 2, children: 0, childAges: [] }];
129
+ }
130
+
131
+ if (travellers.travelersFirstStep === true) {
132
+ dispatch(setTravelersFirstStep(true));
133
+ }
134
+
120
135
  const flight = getFlightsFromParams(params, 'flight');
121
136
  const flightRouteId = getStringFromParams(params, 'flightRouteId');
122
137
  const vendorConfigurationId = getNumberFromParams(params, 'vendorConfigurationId');
@@ -169,6 +184,7 @@ const Booking: React.FC<BookingProps> = ({ productCode, productName, thumbnailUr
169
184
  // Retried
170
185
  dispatch(setIsRetry(false));
171
186
 
187
+ dispatch(setIsUnavailable(false));
172
188
  // Fetch data
173
189
  const promise = dispatch(fetchPackage());
174
190
  return () => {
@@ -235,7 +251,7 @@ const Booking: React.FC<BookingProps> = ({ productCode, productName, thumbnailUr
235
251
  return () => {
236
252
  promise.abort();
237
253
  };
238
- }, [productAttributes, bookingAttributes, rooms, bookingNumber, packageDetails]);
254
+ }, [productAttributes]);
239
255
 
240
256
  let numberIndex = 1;
241
257
 
@@ -246,30 +262,31 @@ const Booking: React.FC<BookingProps> = ({ productCode, productName, thumbnailUr
246
262
  <div className="booking__content">
247
263
  <div className="booking__panel">
248
264
  <Router basepath={basePath}>
265
+ {travelersFirstStep && (
266
+ <StepRoute path={'/'} number={numberIndex++} title={translations.STEPS.PERSONAL_DETAILS} component={<TravelersForm />} />
267
+ )}
249
268
  {!flightOptions.isHidden && flightOptions.pathSuffix && (
250
- <StepRoute
251
- path={flightOptions.pathSuffix}
252
- number={numberIndex++}
253
- title={translations.STEPS.FLIGHT_OPTIONS}
254
- component={<FlightOptionsForm />}
255
- />
269
+ <StepRoute path={'/'} number={numberIndex++} title={translations.STEPS.FLIGHT_OPTIONS} component={<FlightOptionsForm />} />
256
270
  )}
257
271
  {!roomOptions.isHidden && roomOptions.pathSuffix && (
258
272
  <StepRoute path={roomOptions.pathSuffix} number={numberIndex++} title={translations.STEPS.ROOM_OPTIONS} component={<RoomOptionsForm />} />
259
273
  )}
260
274
  <StepRoute path={options.pathSuffix} number={numberIndex++} title={translations.STEPS.EXTRA_OPTIONS} component={<OptionsForm />} />
261
- <StepRoute path={travellers.pathSuffix} number={numberIndex++} title={translations.STEPS.PERSONAL_DETAILS} component={<TravelersForm />} />
275
+ {!travelersFirstStep && (
276
+ <StepRoute path={travellers.pathSuffix} number={numberIndex++} title={translations.STEPS.PERSONAL_DETAILS} component={<TravelersForm />} />
277
+ )}
262
278
  <StepRoute path={summary.pathSuffix} number={numberIndex++} title={translations.STEPS.SUMMARY} component={<Summary />} />
263
279
  <StepRoute path={confirmation.pathSuffix} number={numberIndex++} title={translations.STEPS.CONFIRMATION} component={<Confirmation />} />
264
280
  <StepRoute path={error.pathSuffix} number={numberIndex++} title={translations.STEPS.ERROR} component={<Error />} />
265
281
  </Router>
266
282
  </div>
267
283
  <div className="backdrop" id="backdrop"></div>
268
- {packageDetails && <Sidebar productName={productName} thumbnailUrl={thumbnailUrl} />}
284
+ <Sidebar productName={productName} thumbnailUrl={thumbnailUrl} />
269
285
  </div>
270
286
  </div>
271
287
  )}
272
- {!packageDetails && !bookingNumber && !isUnvailable && (
288
+
289
+ {!packageDetails && !bookingNumber && !isUnavailable && (
273
290
  <div className="booking">
274
291
  <div className="booking__loader">
275
292
  {loaderComponent}
@@ -279,7 +296,7 @@ const Booking: React.FC<BookingProps> = ({ productCode, productName, thumbnailUr
279
296
  </div>
280
297
  </div>
281
298
  )}
282
- {isUnvailable && (
299
+ {isUnavailable && !travelersFirstStep && (
283
300
  <div className="booking">
284
301
  <div className="booking__loader">
285
302
  <p className="booking__loader-text">{translations.MAIN.PRODUCT_UNAVAILABLE}</p>
@@ -10,6 +10,10 @@ import { FlightInfo, Room, Traveler } from '../../types';
10
10
  import { selectNotifications } from '../price-details/price-details-slice';
11
11
  import { selectAgentId, selectTravelersFormValues } from '../travelers-form/travelers-form-slice';
12
12
 
13
+ export const selectHasMounted = (state: RootState) => state.booking.hasMounted;
14
+
15
+ export const selectIsFetching = (state: RootState) => state.booking.isFetching;
16
+
13
17
  export const selectCurrentStep = (state: RootState) => state.booking.currentStep;
14
18
 
15
19
  export const selectGeneratePaymentUrl = (state: RootState) => state.booking.generatePaymentUrl;
@@ -373,6 +377,8 @@ export const selectBookingPackageBookRequest = createSelector(
373
377
  }
374
378
  );
375
379
 
380
+ export const selectTravelersFirstStep = (state: any) => state.booking.travelersFirstStep;
381
+
376
382
  const buildPax = (traveler: Traveler, mainBookerId?: number) => {
377
383
  return {
378
384
  id: traveler.id,
@@ -1,7 +1,7 @@
1
1
  import React, { useContext, useEffect, useState } from 'react';
2
2
 
3
3
  import { BookingPackageFlight } from '@qite/tide-client/build/types';
4
- import { navigate } from '@reach/router';
4
+ import { Link, navigate } from '@reach/router';
5
5
  import { isEmpty } from 'lodash';
6
6
  import { useSelector } from 'react-redux';
7
7
  import { buildClassName } from '../../../shared/utils/class-util';
@@ -9,8 +9,15 @@ import SettingsContext from '../../settings-context';
9
9
  import { useAppDispatch } from '../../store';
10
10
  import { FlightFilterOptions, GroupedFlights } from '../../types';
11
11
  import { setCurrentStep, setFlights, setPackage } from '../booking/booking-slice';
12
- import { ROOM_OPTIONS_FORM_STEP } from '../booking/constants';
13
- import { selectBookingQueryString, selectIsFetchingProductOptions, selectPackageDetails, selectPackageFlights, selectTranslations } from '../booking/selectors';
12
+ import { ROOM_OPTIONS_FORM_STEP, TRAVELERS_FORM_STEP } from '../booking/constants';
13
+ import {
14
+ selectBookingQueryString,
15
+ selectIsFetchingProductOptions,
16
+ selectPackageDetails,
17
+ selectPackageFlights,
18
+ selectTranslations,
19
+ selectTravelersFirstStep
20
+ } from '../booking/selectors';
14
21
  import { fetchPriceDetails } from '../price-details/price-details-slice';
15
22
  import FlightFilter from './flight-filter';
16
23
  import FlightOption from './flight-option';
@@ -28,6 +35,7 @@ const FlightOptionsForm: React.FC<FlightOptionsFormProps> = () => {
28
35
  const bookingQueryString = useSelector(selectBookingQueryString);
29
36
  const isLoading = useSelector(selectIsFetchingProductOptions);
30
37
  const flights = useSelector(selectPackageFlights);
38
+ const travelersFirstStep = useSelector(selectTravelersFirstStep);
31
39
 
32
40
  const [filterOptions, setFilterOptions] = useState<FlightFilterOptions | undefined>();
33
41
  const [flightGroups, setFlightGroups] = useState<GroupedFlights[]>([]);
@@ -92,6 +100,10 @@ const FlightOptionsForm: React.FC<FlightOptionsFormProps> = () => {
92
100
  const filteredGroups = filterGroupedFlights(flightGroups, filterOptions);
93
101
  const resultCount = filteredGroups.length;
94
102
 
103
+ const goPrevious = () => {
104
+ dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
105
+ };
106
+
95
107
  return (
96
108
  <>
97
109
  <FlightOptionModal />
@@ -129,6 +141,18 @@ const FlightOptionsForm: React.FC<FlightOptionsFormProps> = () => {
129
141
  )}
130
142
  </div>
131
143
  <div className="booking__navigator">
144
+ {travelersFirstStep && settings.skipRouter ? (
145
+ <button type="button" title={translations.STEPS.PREVIOUS} onClick={() => goPrevious()} className="cta cta--secondary">
146
+ {translations.STEPS.PREVIOUS}
147
+ </button>
148
+ ) : travelersFirstStep ? (
149
+ <Link
150
+ to={`${settings.basePath}${settings.travellers.pathSuffix}?${bookingQueryString}`}
151
+ title={translations.STEPS.PREVIOUS}
152
+ className="cta cta--secondary">
153
+ {translations.STEPS.PREVIOUS}
154
+ </Link>
155
+ ) : null}
132
156
  <button type="submit" title={translations.STEPS.NEXT} disabled={isLoading} className={buildClassName(['cta', isLoading && 'cta--disabled'])}>
133
157
  {translations.STEPS.NEXT}
134
158
  </button>
@@ -32,7 +32,7 @@ const OptionRoom: React.FC<OptionRoomProps> = ({ packageRoom, pax, optionPax, on
32
32
  if (selectedOption) {
33
33
  startDate = getDateText(selectedOption.from, true) ?? '';
34
34
  endDate = getDateText(selectedOption.to, true) ?? '';
35
- daysAndNightsText = getDatePeriodText(selectedOption.from, selectedOption.to) ?? '';
35
+ daysAndNightsText = getDatePeriodText(translations, selectedOption.from, selectedOption.to) ?? '';
36
36
 
37
37
  const productAttributes = useSelector(selectProductAttributes);
38
38
  productName = productAttributes?.productName ?? '';
@@ -29,7 +29,7 @@ import {
29
29
  setPackageRooms,
30
30
  setTagIds
31
31
  } from '../booking/booking-slice';
32
- import { FLIGHT_OPTIONS_FORM_STEP, ROOM_OPTIONS_FORM_STEP, TRAVELERS_FORM_STEP } from '../booking/constants';
32
+ import { FLIGHT_OPTIONS_FORM_STEP, ROOM_OPTIONS_FORM_STEP, SUMMARY_STEP, TRAVELERS_FORM_STEP } from '../booking/constants';
33
33
  import {
34
34
  selectAvailabilities,
35
35
  selectBookingPackagePax,
@@ -46,7 +46,8 @@ import {
46
46
  selectPackageTags,
47
47
  selectRequestRooms,
48
48
  selectTagIds,
49
- selectTranslations
49
+ selectTranslations,
50
+ selectTravelersFirstStep
50
51
  } from '../booking/selectors';
51
52
  import { fetchPriceDetails } from '../price-details/price-details-slice';
52
53
  import { updatePackageRooms } from '../room-options/room-utils';
@@ -78,6 +79,7 @@ const OptionsForm: React.FC<OptionsFormProps> = () => {
78
79
  const optionPax = useSelector(selectPackageOptionPax);
79
80
  const availabilities = useSelector(selectAvailabilities);
80
81
  const includedServiceTypes = useSelector(selectIncludedServiceTypes);
82
+ const travelersFirstStep = useSelector(selectTravelersFirstStep);
81
83
 
82
84
  // ROOMS
83
85
  const showRoomOptions = settings.options.showRoomOptions ?? settings.roomOptions.isHidden;
@@ -111,9 +113,17 @@ const OptionsForm: React.FC<OptionsFormProps> = () => {
111
113
 
112
114
  const handleSubmit: React.FormEventHandler<HTMLFormElement> = (e) => {
113
115
  if (settings.skipRouter) {
114
- dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
116
+ if (travelersFirstStep) {
117
+ dispatch(setCurrentStep(SUMMARY_STEP));
118
+ } else {
119
+ dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
120
+ }
115
121
  } else {
116
- navigate(`${settings.basePath}${settings.travellers.pathSuffix}?${bookingQueryString}`);
122
+ if (travelersFirstStep) {
123
+ navigate(`${settings.basePath}${settings.summary.pathSuffix}?${bookingQueryString}`);
124
+ } else {
125
+ navigate(`${settings.basePath}${settings.travellers.pathSuffix}?${bookingQueryString}`);
126
+ }
117
127
  }
118
128
 
119
129
  e.preventDefault();
@@ -86,7 +86,7 @@ const RoomOption: React.FC<RoomOptionProps> = ({ room, hasAlternatives, selected
86
86
  <p className="form__room__dates">
87
87
  {getDateText(room.from)} - {getDateText(room.to)}
88
88
  </p>
89
- <span className="form__room__days">{getDatePeriodText(room.from, room.to)}</span>
89
+ <span className="form__room__days">{getDatePeriodText(translations, room.from, room.to)}</span>
90
90
  </div>
91
91
  <div className="form__room__footer__bottom">
92
92
  {selectedRoomPrice != undefined && (
@@ -3,6 +3,8 @@ import {
3
3
  selectIncludedServiceTypes,
4
4
  selectIsFetchingProductOptions,
5
5
  selectIsOnRequest,
6
+ selectIsUnavailable,
7
+ selectPackageDetails,
6
8
  selectPackageRooms,
7
9
  selectReturnFlight,
8
10
  selectRoomOptionDepartureFlightsMetaData,
@@ -44,7 +46,7 @@ const SidebarContainer: React.FC<SidebarProps> = ({ productName, thumbnailUrl })
44
46
  const isFetchingPriceDetails = useSelector(selectIsFetchingPriceDetails);
45
47
  const accommodations = useSelector(selectPackageRooms);
46
48
  const includedServiceTypes = useSelector(selectIncludedServiceTypes);
47
-
49
+ const isUnavailable = useSelector(selectIsUnavailable) || false;
48
50
  const isLoading = isFetchingProductOptions || isFetchingPriceDetails;
49
51
 
50
52
  return (
@@ -68,6 +70,7 @@ const SidebarContainer: React.FC<SidebarProps> = ({ productName, thumbnailUrl })
68
70
  headerComponent={sidebarHeaderComponent ?? undefined}
69
71
  footerComponent={sidebarFooterComponent ?? undefined}
70
72
  loaderComponent={loaderComponent ?? undefined}
73
+ isUnavailable={isUnavailable}
71
74
  />
72
75
  );
73
76
  };
@@ -35,13 +35,11 @@ export const getDateText = (date: string | undefined, hideYear?: boolean): strin
35
35
  }
36
36
  };
37
37
 
38
- export const getDatePeriodText = (from?: string, to?: string, nightsOnly?: boolean) => {
38
+ export const getDatePeriodText = (translations: Record<string, any>, from?: string, to?: string, nightsOnly?: boolean) => {
39
39
  if (!from || !to) {
40
40
  return undefined;
41
41
  }
42
42
 
43
- const translations = useSelector(selectTranslations);
44
-
45
43
  try {
46
44
  const fromDate = parseISO(from);
47
45
  const toDate = parseISO(to);