@qite/tide-booking-component 1.2.4 → 1.2.5

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 (137) hide show
  1. package/.vs/ProjectSettings.json +3 -3
  2. package/.vs/VSWorkspaceState.json +5 -5
  3. package/README.md +8 -8
  4. package/build/build-cjs/booking-wizard/features/flight-options/flight-option-flight.d.ts +1 -1
  5. package/build/build-cjs/booking-wizard/features/flight-options/flight-option.d.ts +1 -1
  6. package/build/build-cjs/booking-wizard/types.d.ts +6 -0
  7. package/build/build-cjs/index.js +1200 -713
  8. package/build/build-cjs/shared/utils/localization-util.d.ts +1 -0
  9. package/build/build-esm/booking-wizard/features/flight-options/flight-option-flight.d.ts +1 -1
  10. package/build/build-esm/booking-wizard/features/flight-options/flight-option.d.ts +1 -1
  11. package/build/build-esm/booking-wizard/types.d.ts +6 -0
  12. package/build/build-esm/index.js +1201 -714
  13. package/build/build-esm/shared/utils/localization-util.d.ts +1 -0
  14. package/package.json +75 -77
  15. package/rollup.config.js +23 -23
  16. package/src/booking-product/components/age-select.tsx +35 -41
  17. package/src/booking-product/components/amount-input.tsx +78 -64
  18. package/src/booking-product/components/date-range-picker/calendar-day.tsx +58 -54
  19. package/src/booking-product/components/date-range-picker/calendar.tsx +178 -176
  20. package/src/booking-product/components/date-range-picker/index.tsx +196 -181
  21. package/src/booking-product/components/dates.tsx +136 -132
  22. package/src/booking-product/components/footer.tsx +69 -70
  23. package/src/booking-product/components/header.tsx +79 -68
  24. package/src/booking-product/components/icon.tsx +251 -208
  25. package/src/booking-product/components/product.tsx +314 -281
  26. package/src/booking-product/components/rating.tsx +21 -21
  27. package/src/booking-product/components/rooms.tsx +195 -180
  28. package/src/booking-product/index.tsx +30 -30
  29. package/src/booking-product/settings-context.ts +14 -14
  30. package/src/booking-product/types.ts +28 -28
  31. package/src/booking-product/utils/api.ts +25 -25
  32. package/src/booking-product/utils/price.ts +29 -27
  33. package/src/booking-wizard/api-settings-slice.ts +24 -24
  34. package/src/booking-wizard/components/icon.tsx +508 -309
  35. package/src/booking-wizard/components/labeled-input.tsx +64 -64
  36. package/src/booking-wizard/components/labeled-select.tsx +69 -69
  37. package/src/booking-wizard/components/message.tsx +34 -34
  38. package/src/booking-wizard/components/multi-range-filter.tsx +113 -113
  39. package/src/booking-wizard/components/product-card.tsx +37 -37
  40. package/src/booking-wizard/components/step-indicator.tsx +51 -51
  41. package/src/booking-wizard/components/step-route.tsx +27 -27
  42. package/src/booking-wizard/declarations.d.ts +4 -4
  43. package/src/booking-wizard/features/booking/api.ts +49 -45
  44. package/src/booking-wizard/features/booking/booking-self-contained.tsx +384 -357
  45. package/src/booking-wizard/features/booking/booking-slice.ts +662 -603
  46. package/src/booking-wizard/features/booking/booking.tsx +356 -349
  47. package/src/booking-wizard/features/booking/constants.ts +16 -16
  48. package/src/booking-wizard/features/booking/selectors.ts +441 -418
  49. package/src/booking-wizard/features/confirmation/confirmation.tsx +97 -94
  50. package/src/booking-wizard/features/error/error.tsx +78 -75
  51. package/src/booking-wizard/features/flight-options/flight-filter.tsx +432 -357
  52. package/src/booking-wizard/features/flight-options/flight-option-flight.tsx +385 -353
  53. package/src/booking-wizard/features/flight-options/flight-option-modal.tsx +229 -214
  54. package/src/booking-wizard/features/flight-options/flight-option.tsx +81 -66
  55. package/src/booking-wizard/features/flight-options/flight-utils.ts +516 -401
  56. package/src/booking-wizard/features/flight-options/index.tsx +196 -177
  57. package/src/booking-wizard/features/price-details/price-details-api.ts +24 -24
  58. package/src/booking-wizard/features/price-details/price-details-slice.ts +178 -171
  59. package/src/booking-wizard/features/price-details/util.ts +155 -155
  60. package/src/booking-wizard/features/product-options/no-options.tsx +21 -21
  61. package/src/booking-wizard/features/product-options/none-option.tsx +120 -120
  62. package/src/booking-wizard/features/product-options/option-booking-airline-group.tsx +64 -66
  63. package/src/booking-wizard/features/product-options/option-booking-group.tsx +216 -210
  64. package/src/booking-wizard/features/product-options/option-item.tsx +317 -318
  65. package/src/booking-wizard/features/product-options/option-pax-card.tsx +201 -188
  66. package/src/booking-wizard/features/product-options/option-pax-group.tsx +175 -169
  67. package/src/booking-wizard/features/product-options/option-room.tsx +321 -314
  68. package/src/booking-wizard/features/product-options/option-unit-group.tsx +198 -192
  69. package/src/booking-wizard/features/product-options/option-units-card.tsx +185 -174
  70. package/src/booking-wizard/features/product-options/options-form.tsx +459 -437
  71. package/src/booking-wizard/features/room-options/index.tsx +187 -172
  72. package/src/booking-wizard/features/room-options/room-utils.ts +190 -143
  73. package/src/booking-wizard/features/room-options/room.tsx +160 -124
  74. package/src/booking-wizard/features/room-options/traveler-rooms.tsx +75 -63
  75. package/src/booking-wizard/features/sidebar/index.tsx +76 -76
  76. package/src/booking-wizard/features/sidebar/sidebar-flight.tsx +68 -68
  77. package/src/booking-wizard/features/sidebar/sidebar-util.ts +177 -177
  78. package/src/booking-wizard/features/sidebar/sidebar.tsx +364 -346
  79. package/src/booking-wizard/features/summary/summary-booking-option-pax.tsx +25 -25
  80. package/src/booking-wizard/features/summary/summary-booking-option-unit.tsx +25 -25
  81. package/src/booking-wizard/features/summary/summary-flight.tsx +39 -39
  82. package/src/booking-wizard/features/summary/summary-per-booking-option-group.tsx +69 -57
  83. package/src/booking-wizard/features/summary/summary-per-pax-option-group.tsx +63 -51
  84. package/src/booking-wizard/features/summary/summary-per-unit-option-group.tsx +66 -54
  85. package/src/booking-wizard/features/summary/summary-slice.ts +28 -28
  86. package/src/booking-wizard/features/summary/summary.tsx +674 -643
  87. package/src/booking-wizard/features/travelers-form/travelers-form-slice.ts +164 -164
  88. package/src/booking-wizard/features/travelers-form/travelers-form.tsx +754 -755
  89. package/src/booking-wizard/features/travelers-form/type-ahead-input.tsx +101 -101
  90. package/src/booking-wizard/features/travelers-form/validate-form.ts +245 -245
  91. package/src/booking-wizard/index.tsx +36 -36
  92. package/src/booking-wizard/settings-context.ts +60 -60
  93. package/src/booking-wizard/store.ts +31 -31
  94. package/src/booking-wizard/types.ts +276 -271
  95. package/src/index.ts +4 -5
  96. package/src/shared/components/loader.tsx +16 -16
  97. package/src/shared/translations/en-GB.json +232 -0
  98. package/src/shared/translations/fr-BE.json +233 -233
  99. package/src/shared/translations/nl-BE.json +232 -232
  100. package/src/shared/types.ts +4 -4
  101. package/src/shared/utils/class-util.ts +9 -9
  102. package/src/shared/utils/localization-util.ts +62 -56
  103. package/src/shared/utils/query-string-util.ts +119 -116
  104. package/src/shared/utils/tide-api-utils.ts +36 -36
  105. package/styles/booking-product-variables.scss +394 -288
  106. package/styles/booking-product.scss +446 -440
  107. package/styles/booking-wizard-variables.scss +871 -530
  108. package/styles/booking-wizard.scss +59 -26
  109. package/styles/components/_animations.scss +39 -39
  110. package/styles/components/_base.scss +107 -106
  111. package/styles/components/_booking.scss +879 -1409
  112. package/styles/components/_button.scss +238 -185
  113. package/styles/components/_checkbox.scss +219 -215
  114. package/styles/components/_cta.scss +208 -133
  115. package/styles/components/_date-list.scss +41 -0
  116. package/styles/components/_date-range-picker.scss +225 -225
  117. package/styles/components/_decrement-increment.scss +35 -37
  118. package/styles/components/_dropdown.scss +72 -74
  119. package/styles/components/_flight-option.scss +1429 -1389
  120. package/styles/components/_form.scss +1583 -394
  121. package/styles/components/_info-message.scss +71 -0
  122. package/styles/components/_input.scss +25 -0
  123. package/styles/components/_list.scss +187 -82
  124. package/styles/components/_loader.scss +72 -71
  125. package/styles/components/_mixins.scss +550 -530
  126. package/styles/components/_placeholders.scss +166 -166
  127. package/styles/components/_pricing-summary.scss +155 -117
  128. package/styles/components/_qsm.scss +17 -20
  129. package/styles/components/_radiobutton.scss +170 -0
  130. package/styles/components/_select-wrapper.scss +80 -66
  131. package/styles/components/_spinner.scss +29 -0
  132. package/styles/components/_step-indicators.scss +168 -160
  133. package/styles/components/_table.scss +81 -81
  134. package/styles/components/_tree.scss +530 -540
  135. package/styles/components/_typeahead.scss +281 -0
  136. package/styles/components/_variables.scss +89 -89
  137. package/tsconfig.json +24 -24
@@ -1,357 +1,432 @@
1
- import React, { useState, useEffect, useRef } from "react";
2
- import { useSelector } from "react-redux";
3
- import { buildClassName } from "../../../shared/utils/class-util";
4
- import Icon from "../../components/icon";
5
- import MultiRangeFilter from "../../components/multi-range-filter";
6
- import { FlightFilterOptions } from "../../types";
7
- import { selectTranslations } from "../booking/selectors";
8
- import { formatMinutes } from "./flight-utils";
9
-
10
- interface FlightFilterProps {
11
- filterOptions: FlightFilterOptions;
12
- resultCount: number;
13
-
14
- applyFilter: (options: FlightFilterOptions) => void;
15
- }
16
-
17
- const FlightFilter: React.FC<FlightFilterProps> = ({
18
- filterOptions,
19
- resultCount,
20
- applyFilter
21
- }) => {
22
- const translations = useSelector(selectTranslations);
23
-
24
- const [filtersVisible, setFiltersVisible] = useState<boolean>(false);
25
- const filterRef = useRef<HTMLDivElement>(null);
26
-
27
- useEffect(() => {
28
- function handleClickOutside(event: MouseEvent) {
29
- if (filterRef.current && !filterRef.current.contains(event.target as Node)) {
30
- setFiltersVisible(false);
31
- }
32
- }
33
- document.addEventListener("mousedown", handleClickOutside);
34
- return () => {
35
- document.removeEventListener("mousedown", handleClickOutside);
36
- };
37
- }, []);
38
-
39
- const updateAirportFilter = (code: string) => {
40
- const updatedFilterOptions = {
41
- ...filterOptions,
42
- airports: filterOptions.airports.map(x => {
43
- if (x.value !== code) return x;
44
-
45
- return {
46
- ...x,
47
- isSelected: !x.isSelected
48
- }
49
- })
50
- };
51
-
52
- applyFilter(updatedFilterOptions);
53
- }
54
-
55
- const updateAirlineFilter = (code: string) => {
56
- const updatedFilterOptions = {
57
- ...filterOptions,
58
- airlines: filterOptions.airlines.map(x => {
59
- if (x.value !== code) return x;
60
-
61
- return {
62
- ...x,
63
- isSelected: !x.isSelected
64
- }
65
- })
66
- };
67
-
68
- applyFilter(updatedFilterOptions);
69
- }
70
-
71
- const updateStopsFilter = (count: string) => {
72
- const updatedFilterOptions = {
73
- ...filterOptions,
74
- numberOfStops: filterOptions.numberOfStops.map(x => {
75
- if (x.value !== count) return x;
76
-
77
- return {
78
- ...x,
79
- isSelected: !x.isSelected
80
- }
81
- })
82
- };
83
-
84
- applyFilter(updatedFilterOptions);
85
- }
86
-
87
- const updateOutwardDeparture = (period: string) => {
88
- const updatedFilterOptions = {
89
- ...filterOptions,
90
- outward: {
91
- ...filterOptions.outward,
92
- departurePeriod: filterOptions.outward.departurePeriod.map(x => {
93
- if (x.value !== period) return x;
94
-
95
- return {
96
- ...x,
97
- isSelected: !x.isSelected
98
- }
99
- })
100
- }
101
- };
102
-
103
- applyFilter(updatedFilterOptions);
104
- }
105
-
106
- const updateOutwardTravelDuration = (min: number, max: number) => {
107
- const updatedFilterOptions = {
108
- ...filterOptions,
109
- outward: {
110
- ...filterOptions.outward,
111
- travelDuration: {
112
- ...filterOptions.outward.travelDuration,
113
- selectedMin: min,
114
- selectedMax: max
115
- }
116
- }
117
- };
118
-
119
- applyFilter(updatedFilterOptions);
120
- }
121
-
122
- const updateOutwardChangeDuration = (min: number, max: number) => {
123
- const updatedFilterOptions = {
124
- ...filterOptions,
125
- outward: {
126
- ...filterOptions.outward,
127
- changeDuration: {
128
- ...filterOptions.outward.changeDuration,
129
- selectedMin: min,
130
- selectedMax: max
131
- }
132
- }
133
- };
134
-
135
- applyFilter(updatedFilterOptions);
136
- }
137
-
138
- const updateReturnDeparture = (period: string) => {
139
- const updatedFilterOptions = {
140
- ...filterOptions,
141
- return: {
142
- ...filterOptions.return,
143
- departurePeriod: filterOptions.return.departurePeriod.map(x => {
144
- if (x.value !== period) return x;
145
-
146
- return {
147
- ...x,
148
- isSelected: !x.isSelected
149
- }
150
- })
151
- }
152
- };
153
-
154
- applyFilter(updatedFilterOptions);
155
- }
156
-
157
- const updateReturnTravelDuration = (min: number, max: number) => {
158
- const updatedFilterOptions = {
159
- ...filterOptions,
160
- return: {
161
- ...filterOptions.return,
162
- travelDuration: {
163
- ...filterOptions.return.travelDuration,
164
- selectedMin: min,
165
- selectedMax: max
166
- }
167
- }
168
- };
169
-
170
- applyFilter(updatedFilterOptions);
171
- }
172
-
173
- const updateReturnChangeDuration = (min: number, max: number) => {
174
- const updatedFilterOptions = {
175
- ...filterOptions,
176
- return: {
177
- ...filterOptions.return,
178
- changeDuration: {
179
- ...filterOptions.return.changeDuration,
180
- selectedMin: min,
181
- selectedMax: max
182
- }
183
- }
184
- };
185
-
186
- applyFilter(updatedFilterOptions);
187
- }
188
-
189
- return (
190
- <>
191
- <button type="button" className="cta cta--filter" onClick={() => setFiltersVisible(!filtersVisible)}>
192
- <Icon name="ui-filter" width={11} height={10} />
193
- <span>{translations.FLIGHTS_FORM.FILTER_OPTIONS}</span>
194
- {filtersVisible}
195
- </button>
196
-
197
- <div ref={filterRef} className={buildClassName(["flight__filter", filtersVisible && "flight__filter--active"])}>
198
- <div className="flight__filter__header">
199
- <div className="flight__filter__header__title">
200
- <h3>{translations.FLIGHTS_FORM.FILTER_OPTIONS}</h3>
201
- <p>{translations.FLIGHTS_FORM.FLIGHTS_FOUND_1} <strong>{resultCount} {translations.FLIGHTS_FORM.FLIGHTS_FOUND_2}</strong> {translations.FLIGHTS_FORM.FLIGHTS_FOUND_3}</p>
202
- </div>
203
- </div>
204
- <div className="flight__filter__body">
205
- <div className="flight__filter__group">
206
- <div className="flight__filter__group__title">
207
- {translations.FLIGHTS_FORM.AIRLINES}
208
- </div>
209
- <div className="flight__filter__group__wrapper">
210
- {filterOptions.airlines.map((option, k) => (
211
- <div className="tree" key={k}>
212
- <div className="checkbox flight__filter__checkbox">
213
- <label htmlFor={'airline_' + option.value} className="checkbox__label">
214
- <input type="checkbox" id={'airline_' + option.value} className="checkbox__input checkbox__input--parent"
215
- onClick={() => updateAirlineFilter(option.value)} />
216
- <span className="radiobutton__label-text">
217
- {option.label} {option.count > 0 && (<span className="amount">({option.count})</span>)}
218
- </span>
219
- </label>
220
- </div>
221
- </div>
222
- ))}
223
- </div>
224
- </div>
225
- <div className="flight__filter__group">
226
- <div className="flight__filter__group__title">
227
- {translations.FLIGHTS_FORM.AIRPORTS}
228
- </div>
229
- <div className="flight__filter__group__wrapper">
230
- {filterOptions.airports.map((option, k) => (
231
- <div className="tree" key={k}>
232
- <div className="checkbox flight__filter__checkbox">
233
- <label htmlFor={'airport_' + option.value} className="checkbox__label">
234
- <input type="checkbox" id={'airport_' + option.value} className="checkbox__input checkbox__input--parent"
235
- onClick={() => updateAirportFilter(option.value)} />
236
- <span className="radiobutton__label-text">
237
- {option.label} {option.count > 0 && (<span className="amount">({option.count})</span>)}
238
- </span>
239
- </label>
240
- </div>
241
- </div>
242
- ))}
243
- </div>
244
- </div>
245
- <div className="flight__filter__group">
246
- <div className="flight__filter__group__title">
247
- {translations.FLIGHTS_FORM.NUMBER_OF_STOPS}
248
- </div>
249
- <div className="flight__filter__group__wrapper">
250
- {filterOptions.numberOfStops.map((option, k) => (
251
- <div className="tree" key={k}>
252
- <div className="checkbox flight__filter__checkbox">
253
- <label htmlFor={'stops_' + option.value} className="checkbox__label">
254
- <input type="checkbox" id={'stops_' + option.value} className="checkbox__input checkbox__input--parent"
255
- onClick={() => updateStopsFilter(option.value)} />
256
- <span className="radiobutton__label-text">
257
- {option.label} {option.count > 0 && (<span className="amount">({option.count})</span>)}
258
- </span>
259
- </label>
260
- </div>
261
- </div>
262
- ))}
263
- </div>
264
- </div>
265
- <div className="flight__filter__group">
266
- <div className="flight__filter__group__title">
267
- {translations.FLIGHTS_FORM.FLIGHT_OUTWARD}
268
- </div>
269
- <div className="flight__filter__group__wrapper">
270
- <p>{translations.FLIGHTS_FORM.DEPARTURE_TIME}</p>
271
- {filterOptions.outward.departurePeriod.map((option, k) => (
272
- <div className="tree" key={k}>
273
- <div className="checkbox flight__filter__checkbox">
274
- <label htmlFor={'outward_time_' + option.value} className="checkbox__label">
275
- <input type="checkbox" id={'outward_time_' + option.value} className="checkbox__input checkbox__input--parent"
276
- onClick={() => updateOutwardDeparture(option.value)} />
277
- <span className="radiobutton__label-text">
278
- {option.label} {option.count > 0 && (<span className="amount">({option.count})</span>)}
279
- </span>
280
- </label>
281
- </div>
282
- </div>
283
- ))}
284
- </div>
285
- <div className="flight__filter__group__wrapper">
286
- <p>{translations.FLIGHTS_FORM.TRAVEL_DURATION}</p>
287
- <MultiRangeFilter
288
- min={filterOptions.outward.travelDuration.min}
289
- max={filterOptions.outward.travelDuration.max}
290
- selectedMin={filterOptions.outward.travelDuration.selectedMin}
291
- selectedMax={filterOptions.outward.travelDuration.selectedMax}
292
- valueFormatter={formatMinutes}
293
- onChange={updateOutwardTravelDuration}
294
- />
295
- </div>
296
- <div className="flight__filter__group__wrapper">
297
- <p>{translations.FLIGHTS_FORM.CHANGE_TIME}</p>
298
- <MultiRangeFilter
299
- min={filterOptions.outward.changeDuration.min}
300
- max={filterOptions.outward.changeDuration.max}
301
- selectedMin={filterOptions.outward.changeDuration.selectedMin}
302
- selectedMax={filterOptions.outward.changeDuration.selectedMax}
303
- valueFormatter={formatMinutes}
304
- onChange={updateOutwardChangeDuration}
305
- />
306
- </div>
307
- </div>
308
- <div className="flight__filter__group">
309
- <div className="flight__filter__group__title">
310
- {translations.FLIGHTS_FORM.FLIGHT_RETURN}
311
- </div>
312
- <div className="flight__filter__group__wrapper">
313
- <p>{translations.FLIGHTS_FORM.DEPARTURE_TIME}</p>
314
- {filterOptions.return.departurePeriod.map((option, k) => (
315
- <div className="tree" key={k}>
316
- <div className="checkbox flight__filter__checkbox">
317
- <label htmlFor={'return_time_' + option.value} className="checkbox__label">
318
- <input type="checkbox" id={'return_time_' + option.value} className="checkbox__input checkbox__input--parent"
319
- onClick={() => updateReturnDeparture(option.value)} />
320
- <span className="radiobutton__label-text">
321
- {option.label} {option.count > 0 && (<span className="amount">({option.count})</span>)}
322
- </span>
323
- </label>
324
- </div>
325
- </div>
326
- ))}
327
- </div>
328
- <div className="flight__filter__group__wrapper">
329
- <p>{translations.FLIGHTS_FORM.TRAVEL_DURATION}</p>
330
- <MultiRangeFilter
331
- min={filterOptions.return.travelDuration.min}
332
- max={filterOptions.return.travelDuration.max}
333
- selectedMin={filterOptions.return.travelDuration.selectedMin}
334
- selectedMax={filterOptions.return.travelDuration.selectedMax}
335
- valueFormatter={formatMinutes}
336
- onChange={updateReturnTravelDuration}
337
- />
338
- </div>
339
- <div className="flight__filter__group__wrapper">
340
- <p>{translations.FLIGHTS_FORM.CHANGE_TIME}</p>
341
- <MultiRangeFilter
342
- min={filterOptions.return.changeDuration.min}
343
- max={filterOptions.return.changeDuration.max}
344
- selectedMin={filterOptions.return.changeDuration.selectedMin}
345
- selectedMax={filterOptions.return.changeDuration.selectedMax}
346
- valueFormatter={formatMinutes}
347
- onChange={updateReturnChangeDuration}
348
- />
349
- </div>
350
- </div>
351
- </div>
352
- </div>
353
- </>
354
- )
355
- }
356
-
357
- export default FlightFilter;
1
+ import React, { useState, useEffect, useRef } from "react";
2
+ import { useSelector } from "react-redux";
3
+ import { buildClassName } from "../../../shared/utils/class-util";
4
+ import Icon from "../../components/icon";
5
+ import MultiRangeFilter from "../../components/multi-range-filter";
6
+ import { FlightFilterOptions } from "../../types";
7
+ import { selectTranslations } from "../booking/selectors";
8
+ import { formatMinutes } from "./flight-utils";
9
+
10
+ interface FlightFilterProps {
11
+ filterOptions: FlightFilterOptions;
12
+ resultCount: number;
13
+
14
+ applyFilter: (options: FlightFilterOptions) => void;
15
+ }
16
+
17
+ const FlightFilter: React.FC<FlightFilterProps> = ({
18
+ filterOptions,
19
+ resultCount,
20
+ applyFilter,
21
+ }) => {
22
+ const translations = useSelector(selectTranslations);
23
+
24
+ const [filtersVisible, setFiltersVisible] = useState<boolean>(false);
25
+ const filterRef = useRef<HTMLDivElement>(null);
26
+
27
+ useEffect(() => {
28
+ function handleClickOutside(event: MouseEvent) {
29
+ if (
30
+ filterRef.current &&
31
+ !filterRef.current.contains(event.target as Node)
32
+ ) {
33
+ setFiltersVisible(false);
34
+ }
35
+ }
36
+ document.addEventListener("mousedown", handleClickOutside);
37
+ return () => {
38
+ document.removeEventListener("mousedown", handleClickOutside);
39
+ };
40
+ }, []);
41
+
42
+ const updateAirportFilter = (code: string) => {
43
+ const updatedFilterOptions = {
44
+ ...filterOptions,
45
+ airports: filterOptions.airports.map((x) => {
46
+ if (x.value !== code) return x;
47
+
48
+ return {
49
+ ...x,
50
+ isSelected: !x.isSelected,
51
+ };
52
+ }),
53
+ };
54
+
55
+ applyFilter(updatedFilterOptions);
56
+ };
57
+
58
+ const updateAirlineFilter = (code: string) => {
59
+ const updatedFilterOptions = {
60
+ ...filterOptions,
61
+ airlines: filterOptions.airlines.map((x) => {
62
+ if (x.value !== code) return x;
63
+
64
+ return {
65
+ ...x,
66
+ isSelected: !x.isSelected,
67
+ };
68
+ }),
69
+ };
70
+
71
+ applyFilter(updatedFilterOptions);
72
+ };
73
+
74
+ const updateStopsFilter = (count: string) => {
75
+ const updatedFilterOptions = {
76
+ ...filterOptions,
77
+ numberOfStops: filterOptions.numberOfStops.map((x) => {
78
+ if (x.value !== count) return x;
79
+
80
+ return {
81
+ ...x,
82
+ isSelected: !x.isSelected,
83
+ };
84
+ }),
85
+ };
86
+
87
+ applyFilter(updatedFilterOptions);
88
+ };
89
+
90
+ const updateOutwardDeparture = (period: string) => {
91
+ const updatedFilterOptions = {
92
+ ...filterOptions,
93
+ outward: {
94
+ ...filterOptions.outward,
95
+ departurePeriod: filterOptions.outward.departurePeriod.map((x) => {
96
+ if (x.value !== period) return x;
97
+
98
+ return {
99
+ ...x,
100
+ isSelected: !x.isSelected,
101
+ };
102
+ }),
103
+ },
104
+ };
105
+
106
+ applyFilter(updatedFilterOptions);
107
+ };
108
+
109
+ const updateOutwardTravelDuration = (min: number, max: number) => {
110
+ const updatedFilterOptions = {
111
+ ...filterOptions,
112
+ outward: {
113
+ ...filterOptions.outward,
114
+ travelDuration: {
115
+ ...filterOptions.outward.travelDuration,
116
+ selectedMin: min,
117
+ selectedMax: max,
118
+ },
119
+ },
120
+ };
121
+
122
+ applyFilter(updatedFilterOptions);
123
+ };
124
+
125
+ const updateOutwardChangeDuration = (min: number, max: number) => {
126
+ const updatedFilterOptions = {
127
+ ...filterOptions,
128
+ outward: {
129
+ ...filterOptions.outward,
130
+ changeDuration: {
131
+ ...filterOptions.outward.changeDuration,
132
+ selectedMin: min,
133
+ selectedMax: max,
134
+ },
135
+ },
136
+ };
137
+
138
+ applyFilter(updatedFilterOptions);
139
+ };
140
+
141
+ const updateReturnDeparture = (period: string) => {
142
+ const updatedFilterOptions = {
143
+ ...filterOptions,
144
+ return: {
145
+ ...filterOptions.return,
146
+ departurePeriod: filterOptions.return.departurePeriod.map((x) => {
147
+ if (x.value !== period) return x;
148
+
149
+ return {
150
+ ...x,
151
+ isSelected: !x.isSelected,
152
+ };
153
+ }),
154
+ },
155
+ };
156
+
157
+ applyFilter(updatedFilterOptions);
158
+ };
159
+
160
+ const updateReturnTravelDuration = (min: number, max: number) => {
161
+ const updatedFilterOptions = {
162
+ ...filterOptions,
163
+ return: {
164
+ ...filterOptions.return,
165
+ travelDuration: {
166
+ ...filterOptions.return.travelDuration,
167
+ selectedMin: min,
168
+ selectedMax: max,
169
+ },
170
+ },
171
+ };
172
+
173
+ applyFilter(updatedFilterOptions);
174
+ };
175
+
176
+ const updateReturnChangeDuration = (min: number, max: number) => {
177
+ const updatedFilterOptions = {
178
+ ...filterOptions,
179
+ return: {
180
+ ...filterOptions.return,
181
+ changeDuration: {
182
+ ...filterOptions.return.changeDuration,
183
+ selectedMin: min,
184
+ selectedMax: max,
185
+ },
186
+ },
187
+ };
188
+
189
+ applyFilter(updatedFilterOptions);
190
+ };
191
+
192
+ return (
193
+ <>
194
+ <button
195
+ type="button"
196
+ className="cta cta--filter"
197
+ onClick={() => setFiltersVisible(!filtersVisible)}
198
+ >
199
+ <Icon name="ui-filter" width={11} height={10} />
200
+ <span>{translations.FLIGHTS_FORM.FILTER_OPTIONS}</span>
201
+ </button>
202
+
203
+ <div
204
+ ref={filterRef}
205
+ className={buildClassName([
206
+ "flight__filter",
207
+ filtersVisible && "flight__filter--active",
208
+ ])}
209
+ >
210
+ <div className="flight__filter__header">
211
+ <div className="flight__filter__header__title">
212
+ <h3>{translations.FLIGHTS_FORM.FILTER_OPTIONS}</h3>
213
+ <p>
214
+ {translations.FLIGHTS_FORM.FLIGHTS_FOUND_1}{" "}
215
+ <strong>
216
+ {resultCount} {translations.FLIGHTS_FORM.FLIGHTS_FOUND_2}
217
+ </strong>{" "}
218
+ {translations.FLIGHTS_FORM.FLIGHTS_FOUND_3}
219
+ </p>
220
+ </div>
221
+ <button
222
+ type="button"
223
+ className="cta cta--close"
224
+ onClick={() => setFiltersVisible(false)}
225
+ >
226
+ <Icon name="ui-close" width={25} height={25} />
227
+ </button>
228
+ </div>
229
+ <div className="flight__filter__body">
230
+ <div className="flight__filter__group">
231
+ <div className="flight__filter__group__title">
232
+ {translations.FLIGHTS_FORM.AIRLINES}
233
+ </div>
234
+ <div className="flight__filter__group__wrapper">
235
+ {filterOptions.airlines.map((option, k) => (
236
+ <div className="tree" key={k}>
237
+ <div className="checkbox flight__filter__checkbox">
238
+ <label
239
+ htmlFor={"airline_" + option.value}
240
+ className="checkbox__label"
241
+ >
242
+ <input
243
+ type="checkbox"
244
+ id={"airline_" + option.value}
245
+ className="checkbox__input checkbox__input--parent"
246
+ onClick={() => updateAirlineFilter(option.value)}
247
+ />
248
+ <span className="radiobutton__label-text">
249
+ {option.label}{" "}
250
+ {option.count > 0 && (
251
+ <span className="amount">({option.count})</span>
252
+ )}
253
+ </span>
254
+ </label>
255
+ </div>
256
+ </div>
257
+ ))}
258
+ </div>
259
+ </div>
260
+ <div className="flight__filter__group">
261
+ <div className="flight__filter__group__title">
262
+ {translations.FLIGHTS_FORM.AIRPORTS}
263
+ </div>
264
+ <div className="flight__filter__group__wrapper">
265
+ {filterOptions.airports.map((option, k) => (
266
+ <div className="tree" key={k}>
267
+ <div className="checkbox flight__filter__checkbox">
268
+ <label
269
+ htmlFor={"airport_" + option.value}
270
+ className="checkbox__label"
271
+ >
272
+ <input
273
+ type="checkbox"
274
+ id={"airport_" + option.value}
275
+ className="checkbox__input checkbox__input--parent"
276
+ onClick={() => updateAirportFilter(option.value)}
277
+ />
278
+ <span className="radiobutton__label-text">
279
+ {option.label}{" "}
280
+ {option.count > 0 && (
281
+ <span className="amount">({option.count})</span>
282
+ )}
283
+ </span>
284
+ </label>
285
+ </div>
286
+ </div>
287
+ ))}
288
+ </div>
289
+ </div>
290
+ <div className="flight__filter__group">
291
+ <div className="flight__filter__group__title">
292
+ {translations.FLIGHTS_FORM.NUMBER_OF_STOPS}
293
+ </div>
294
+ <div className="flight__filter__group__wrapper">
295
+ {filterOptions.numberOfStops.map((option, k) => (
296
+ <div className="tree" key={k}>
297
+ <div className="checkbox flight__filter__checkbox">
298
+ <label
299
+ htmlFor={"stops_" + option.value}
300
+ className="checkbox__label"
301
+ >
302
+ <input
303
+ type="checkbox"
304
+ id={"stops_" + option.value}
305
+ className="checkbox__input checkbox__input--parent"
306
+ onClick={() => updateStopsFilter(option.value)}
307
+ />
308
+ <span className="radiobutton__label-text">
309
+ {option.label}{" "}
310
+ {option.count > 0 && (
311
+ <span className="amount">({option.count})</span>
312
+ )}
313
+ </span>
314
+ </label>
315
+ </div>
316
+ </div>
317
+ ))}
318
+ </div>
319
+ </div>
320
+ <div className="flight__filter__group">
321
+ <div className="flight__filter__group__title">
322
+ {translations.FLIGHTS_FORM.FLIGHT_OUTWARD}
323
+ </div>
324
+ <div className="flight__filter__group__wrapper">
325
+ <p>{translations.FLIGHTS_FORM.DEPARTURE_TIME}</p>
326
+ {filterOptions.outward.departurePeriod.map((option, k) => (
327
+ <div className="tree" key={k}>
328
+ <div className="checkbox flight__filter__checkbox">
329
+ <label
330
+ htmlFor={"outward_time_" + option.value}
331
+ className="checkbox__label"
332
+ >
333
+ <input
334
+ type="checkbox"
335
+ id={"outward_time_" + option.value}
336
+ className="checkbox__input checkbox__input--parent"
337
+ onClick={() => updateOutwardDeparture(option.value)}
338
+ />
339
+ <span className="radiobutton__label-text">
340
+ {option.label}{" "}
341
+ {option.count > 0 && (
342
+ <span className="amount">({option.count})</span>
343
+ )}
344
+ </span>
345
+ </label>
346
+ </div>
347
+ </div>
348
+ ))}
349
+ </div>
350
+ <div className="flight__filter__group__wrapper">
351
+ <p>{translations.FLIGHTS_FORM.TRAVEL_DURATION}</p>
352
+ <MultiRangeFilter
353
+ min={filterOptions.outward.travelDuration.min}
354
+ max={filterOptions.outward.travelDuration.max}
355
+ selectedMin={filterOptions.outward.travelDuration.selectedMin}
356
+ selectedMax={filterOptions.outward.travelDuration.selectedMax}
357
+ valueFormatter={formatMinutes}
358
+ onChange={updateOutwardTravelDuration}
359
+ />
360
+ </div>
361
+ <div className="flight__filter__group__wrapper">
362
+ <p>{translations.FLIGHTS_FORM.CHANGE_TIME}</p>
363
+ <MultiRangeFilter
364
+ min={filterOptions.outward.changeDuration.min}
365
+ max={filterOptions.outward.changeDuration.max}
366
+ selectedMin={filterOptions.outward.changeDuration.selectedMin}
367
+ selectedMax={filterOptions.outward.changeDuration.selectedMax}
368
+ valueFormatter={formatMinutes}
369
+ onChange={updateOutwardChangeDuration}
370
+ />
371
+ </div>
372
+ </div>
373
+ <div className="flight__filter__group">
374
+ <div className="flight__filter__group__title">
375
+ {translations.FLIGHTS_FORM.FLIGHT_RETURN}
376
+ </div>
377
+ <div className="flight__filter__group__wrapper">
378
+ <p>{translations.FLIGHTS_FORM.DEPARTURE_TIME}</p>
379
+ {filterOptions.return.departurePeriod.map((option, k) => (
380
+ <div className="tree" key={k}>
381
+ <div className="checkbox flight__filter__checkbox">
382
+ <label
383
+ htmlFor={"return_time_" + option.value}
384
+ className="checkbox__label"
385
+ >
386
+ <input
387
+ type="checkbox"
388
+ id={"return_time_" + option.value}
389
+ className="checkbox__input checkbox__input--parent"
390
+ onClick={() => updateReturnDeparture(option.value)}
391
+ />
392
+ <span className="radiobutton__label-text">
393
+ {option.label}{" "}
394
+ {option.count > 0 && (
395
+ <span className="amount">({option.count})</span>
396
+ )}
397
+ </span>
398
+ </label>
399
+ </div>
400
+ </div>
401
+ ))}
402
+ </div>
403
+ <div className="flight__filter__group__wrapper">
404
+ <p>{translations.FLIGHTS_FORM.TRAVEL_DURATION}</p>
405
+ <MultiRangeFilter
406
+ min={filterOptions.return.travelDuration.min}
407
+ max={filterOptions.return.travelDuration.max}
408
+ selectedMin={filterOptions.return.travelDuration.selectedMin}
409
+ selectedMax={filterOptions.return.travelDuration.selectedMax}
410
+ valueFormatter={formatMinutes}
411
+ onChange={updateReturnTravelDuration}
412
+ />
413
+ </div>
414
+ <div className="flight__filter__group__wrapper">
415
+ <p>{translations.FLIGHTS_FORM.CHANGE_TIME}</p>
416
+ <MultiRangeFilter
417
+ min={filterOptions.return.changeDuration.min}
418
+ max={filterOptions.return.changeDuration.max}
419
+ selectedMin={filterOptions.return.changeDuration.selectedMin}
420
+ selectedMax={filterOptions.return.changeDuration.selectedMax}
421
+ valueFormatter={formatMinutes}
422
+ onChange={updateReturnChangeDuration}
423
+ />
424
+ </div>
425
+ </div>
426
+ </div>
427
+ </div>
428
+ </>
429
+ );
430
+ };
431
+
432
+ export default FlightFilter;