@qite/tide-booking-component 1.3.4 → 1.3.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 (33) hide show
  1. package/build/build-cjs/booking-wizard/features/sidebar/sidebar-util.d.ts +3 -3
  2. package/build/build-cjs/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +5 -5
  3. package/build/build-cjs/booking-wizard/types.d.ts +6 -0
  4. package/build/build-cjs/index.js +223 -147
  5. package/build/build-cjs/shared/utils/localization-util.d.ts +2 -0
  6. package/build/build-esm/booking-wizard/features/sidebar/sidebar-util.d.ts +3 -3
  7. package/build/build-esm/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +5 -5
  8. package/build/build-esm/booking-wizard/types.d.ts +6 -0
  9. package/build/build-esm/index.js +223 -147
  10. package/build/build-esm/shared/utils/localization-util.d.ts +2 -0
  11. package/package.json +75 -75
  12. package/src/booking-wizard/components/print-offer-button.tsx +63 -63
  13. package/src/booking-wizard/features/booking/booking-self-contained.tsx +389 -389
  14. package/src/booking-wizard/features/booking/booking-slice.ts +663 -663
  15. package/src/booking-wizard/features/booking/booking.tsx +361 -361
  16. package/src/booking-wizard/features/flight-options/flight-utils.ts +522 -522
  17. package/src/booking-wizard/features/product-options/options-form.tsx +481 -481
  18. package/src/booking-wizard/features/sidebar/sidebar-util.ts +177 -177
  19. package/src/booking-wizard/features/summary/summary-booking-option-pax.tsx +25 -25
  20. package/src/booking-wizard/features/summary/summary.tsx +674 -674
  21. package/src/booking-wizard/features/travelers-form/travelers-form-slice.ts +164 -164
  22. package/src/booking-wizard/features/travelers-form/travelers-form.tsx +888 -754
  23. package/src/booking-wizard/settings-context.ts +62 -62
  24. package/src/booking-wizard/types.ts +286 -279
  25. package/src/booking-wizard/use-offer-printer.ts +117 -117
  26. package/src/shared/translations/en-GB.json +239 -237
  27. package/src/shared/translations/fr-BE.json +239 -238
  28. package/src/shared/translations/nl-BE.json +239 -237
  29. package/src/shared/utils/tide-api-utils.ts +36 -36
  30. package/styles/booking-wizard-variables.scss +873 -873
  31. package/styles/components/_booking.scss +879 -879
  32. package/styles/components/_dropdown.scss +72 -72
  33. package/styles/components/_form.scss +1583 -1583
@@ -1,481 +1,481 @@
1
- import React, { useContext, useEffect } from "react";
2
-
3
- import {
4
- AirlineBookingPackageOption,
5
- AirportBookingPackageOption,
6
- BookingAirlineGroup,
7
- BookingAirportGroup,
8
- BookingOptionGroup,
9
- BookingOptionPax,
10
- BookingOptionUnit,
11
- BookingPackageFlight,
12
- Pax,
13
- PerBookingPackageOption,
14
- } from "@qite/tide-client/build/types";
15
- import { Link, navigate } from "@reach/router";
16
- import { isEmpty } from "lodash";
17
- import { useSelector } from "react-redux";
18
- import { buildClassName } from "../../../shared/utils/class-util";
19
- import SettingsContext from "../../settings-context";
20
- import { useAppDispatch } from "../../store";
21
- import {
22
- setCurrentStep,
23
- setPackage,
24
- setPackageAirlineGroups,
25
- setPackageAirportGroups,
26
- setPackageGroups,
27
- setPackageOptionPax,
28
- setPackageOptionUnits,
29
- setPackageRooms,
30
- setTagIds,
31
- } from "../booking/booking-slice";
32
- import {
33
- FLIGHT_OPTIONS_FORM_STEP,
34
- ROOM_OPTIONS_FORM_STEP,
35
- TRAVELERS_FORM_STEP,
36
- } from "../booking/constants";
37
- import {
38
- selectAvailabilities,
39
- selectBookingPackagePax,
40
- selectBookingQueryString,
41
- selectIsFetchingProductOptions,
42
- selectPackageAirlineGroups,
43
- selectPackageAirportGroups,
44
- selectPackageDetails,
45
- selectPackageGroups,
46
- selectPackageOptionPax,
47
- selectPackageOptionUnits,
48
- selectPackageRooms,
49
- selectPackageTags,
50
- selectRequestRooms,
51
- selectTagIds,
52
- selectTranslations,
53
- } from "../booking/selectors";
54
- import { fetchPriceDetails } from "../price-details/price-details-slice";
55
- import { updatePackageRooms } from "../room-options/room-utils";
56
- import NoOptions from "./no-options";
57
- import OptionBookingAirlineGroup from "./option-booking-airline-group";
58
- import OptionBookingGroup from "./option-booking-group";
59
- import OptionPaxCard from "./option-pax-card";
60
- import OptionRoom from "./option-room";
61
- import OptionUnitsCard from "./option-units-card";
62
- import PrintOfferButton from "../../components/print-offer-button";
63
-
64
- interface OptionsFormProps {}
65
-
66
- const OptionsForm: React.FC<OptionsFormProps> = () => {
67
- const settings = useContext(SettingsContext);
68
- const { token } = settings;
69
- const translations = useSelector(selectTranslations);
70
- const dispatch = useAppDispatch();
71
- const packageDetails = useSelector(selectPackageDetails);
72
- const requestRooms = useSelector(selectRequestRooms);
73
- const requestRoomsPax = requestRooms?.flatMap((x) => x.pax);
74
- const bookingQueryString = useSelector(selectBookingQueryString);
75
- const isLoading = useSelector(selectIsFetchingProductOptions);
76
-
77
- const groups = useSelector(selectPackageGroups);
78
- const airlineGroups = useSelector(selectPackageAirlineGroups);
79
- const airportGroups = useSelector(selectPackageAirportGroups);
80
- const optionUnits = useSelector(selectPackageOptionUnits);
81
- const optionPax = useSelector(selectPackageOptionPax);
82
- const availabilities = useSelector(selectAvailabilities);
83
-
84
- // ROOMS
85
- const showRoomOptions = settings.roomOptions.isHidden;
86
- const packageRooms = useSelector(selectPackageRooms);
87
- const pax = useSelector(selectBookingPackagePax);
88
-
89
- const getRoomPax = (index: number) => {
90
- var room = requestRooms?.find((x) => x.index == index);
91
- var bookingPackagePax = pax.filter((x) =>
92
- room?.pax.some((y) => y.id == x.id)
93
- );
94
- return bookingPackagePax.length > 0 ? bookingPackagePax : room?.pax ?? [];
95
- };
96
-
97
- const handleOnRoomChange = (
98
- index: number,
99
- accommodationCode: string,
100
- regimeCode: string | null
101
- ) => {
102
- if (!packageRooms) return;
103
-
104
- const updatedPackageRooms = updatePackageRooms(
105
- packageRooms,
106
- index,
107
- accommodationCode,
108
- regimeCode,
109
- availabilities!
110
- );
111
-
112
- dispatch(setPackageRooms(updatedPackageRooms));
113
- dispatch(fetchPriceDetails());
114
- };
115
-
116
- const getPax = () => {
117
- if (!packageDetails) return undefined;
118
- const selectedOption =
119
- packageDetails.options.find((o) => o.isSelected) ??
120
- packageDetails.options[0];
121
- return selectedOption?.requestRooms.flatMap((r) => r.pax) as Pax[];
122
- };
123
-
124
- // TAGS
125
- const packageTags = settings.hideTags ? [] : useSelector(selectPackageTags);
126
- let tagIds = useSelector(selectTagIds) ?? [];
127
-
128
- const handleSubmit: React.FormEventHandler<HTMLFormElement> = (e) => {
129
- if (settings.skipRouter) {
130
- dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
131
- } else {
132
- navigate(
133
- `${settings.basePath}${settings.travellers.pathSuffix}?${bookingQueryString}`
134
- );
135
- }
136
-
137
- e.preventDefault();
138
- };
139
-
140
- const handleOnPaxChange = (pax: BookingOptionPax[]) => {
141
- dispatch(setPackageOptionPax(pax));
142
- dispatch(fetchPriceDetails());
143
- };
144
-
145
- const handleOnUnitsChange = (units: BookingOptionUnit[]) => {
146
- dispatch(setPackageOptionUnits(units));
147
- dispatch(fetchPriceDetails());
148
- };
149
-
150
- const handleOnGroupChange = (
151
- group: BookingOptionGroup<PerBookingPackageOption>
152
- ) => {
153
- if (groups) {
154
- const updatedGroups = groups?.map((g) =>
155
- g.name === group.name ? group : g
156
- );
157
-
158
- dispatch(setPackageGroups(updatedGroups));
159
- dispatch(fetchPriceDetails());
160
- }
161
- };
162
-
163
- const handleOnAirlineGroupChange = (
164
- group: BookingAirlineGroup<AirlineBookingPackageOption>
165
- ) => {
166
- if (airlineGroups) {
167
- const updatedGroups = airlineGroups.map((g) =>
168
- g.label === group.label ? group : g
169
- );
170
-
171
- dispatch(setPackageAirlineGroups(updatedGroups));
172
- dispatch(fetchPriceDetails());
173
- }
174
- };
175
-
176
- const handleOnAirportGroupChange = (
177
- group: BookingAirportGroup<AirportBookingPackageOption>
178
- ) => {
179
- if (airportGroups) {
180
- const updatedGroups = airportGroups.map((g) =>
181
- g.label === group.label ? group : g
182
- );
183
-
184
- dispatch(setPackageAirportGroups(updatedGroups));
185
- dispatch(fetchPriceDetails());
186
- }
187
- };
188
-
189
- const handleOnTagChange = (id: number, checked: boolean) => {
190
- let updatedTags = [...tagIds];
191
- if (checked) {
192
- if (!updatedTags?.includes(id)) {
193
- updatedTags?.push(id);
194
- }
195
- } else {
196
- updatedTags = updatedTags?.filter((x) => x != id);
197
- }
198
-
199
- dispatch(setTagIds(updatedTags));
200
- dispatch(fetchPriceDetails());
201
- };
202
-
203
- useEffect(() => {
204
- if (
205
- packageDetails &&
206
- settings.roomOptions.isHidden &&
207
- settings.flightOptions.isHidden
208
- ) {
209
- const params = new URLSearchParams(location.search);
210
-
211
- const outwardFlight = params.get("outwardflight") ?? undefined;
212
- const returnFlight = params.get("returnflight") ?? undefined;
213
- if (outwardFlight && returnFlight) {
214
- const desiredOutwardFlight = packageDetails.outwardFlights.find(
215
- (x) => x.entryLineGuid == outwardFlight
216
- );
217
- const desiredReturnFlight = packageDetails.returnFlights.find(
218
- (x) => x.entryLineGuid == returnFlight
219
- );
220
- if (desiredOutwardFlight && desiredReturnFlight) {
221
- dispatch(
222
- setPackage({
223
- ...packageDetails,
224
- outwardFlights: packageDetails.outwardFlights.map((flight) => {
225
- return {
226
- ...flight,
227
- isSelected:
228
- flight.entryLineGuid == desiredOutwardFlight.entryLineGuid
229
- ? true
230
- : false,
231
- } as BookingPackageFlight;
232
- }),
233
- returnFlights: packageDetails.returnFlights.map((flight) => {
234
- return {
235
- ...flight,
236
- isSelected:
237
- flight.entryLineGuid == desiredReturnFlight.entryLineGuid
238
- ? true
239
- : false,
240
- } as BookingPackageFlight;
241
- }),
242
- })
243
- );
244
- }
245
- }
246
- }
247
- dispatch(fetchPriceDetails());
248
- }, []);
249
-
250
- const goPrevious = () => {
251
- if (settings.roomOptions.isHidden) {
252
- dispatch(setCurrentStep(FLIGHT_OPTIONS_FORM_STEP));
253
- } else {
254
- dispatch(setCurrentStep(ROOM_OPTIONS_FORM_STEP));
255
- }
256
- };
257
-
258
- const previousUrl = settings.roomOptions.isHidden
259
- ? `${settings.basePath}${settings.flightOptions.pathSuffix}?${bookingQueryString}`
260
- : `${settings.basePath}${settings.roomOptions.pathSuffix}?${bookingQueryString}`;
261
- const hasPrevious =
262
- !settings.roomOptions.isHidden || !settings.flightOptions.isHidden;
263
- const showPackageTagsOrRoomoptions =
264
- showRoomOptions || (packageTags && !isEmpty(packageTags));
265
-
266
- return (
267
- <>
268
- <form
269
- className="form"
270
- name="booking--options"
271
- id="booking--options"
272
- noValidate
273
- onSubmit={handleSubmit}
274
- >
275
- {isLoading && settings.loaderComponent}
276
- {!isLoading && (
277
- <div className="form__region">
278
- {showPackageTagsOrRoomoptions && (
279
- <div className="form__group">
280
- <div className="booking-card">
281
- <div className="booking-card__body">
282
- <div
283
- className={buildClassName([
284
- "booking-card__group",
285
- "booking-card__group--package",
286
- ])}
287
- >
288
- {showRoomOptions && (
289
- <span className="booking-card__tag">
290
- {translations.OPTIONS_FORM.PACKAGE}
291
- </span>
292
- )}
293
- <div className="booking-card__group-body">
294
- {showRoomOptions && (
295
- <table className="table table--striped">
296
- <tbody>
297
- {packageRooms &&
298
- packageRooms.map((room) => (
299
- <OptionRoom
300
- key={room.index}
301
- packageRoom={room}
302
- pax={getRoomPax(room.index)}
303
- optionPax={optionPax}
304
- onRoomChange={handleOnRoomChange}
305
- />
306
- ))}
307
- </tbody>
308
- </table>
309
- )}
310
- {packageTags && !isEmpty(packageTags) && (
311
- <div className="booking-card__tag-translations">
312
- {packageTags.map((tag, index) => (
313
- <label
314
- key={index}
315
- htmlFor={`tag-translation-${index}-${tag.title}`}
316
- className="checkbox__label tag-translation"
317
- >
318
- <div className="tag-translation-input__container">
319
- <input
320
- type="checkbox"
321
- id={`tag-translation-${index}-${tag.title}`}
322
- name={`tag-translation-${index}-${tag.title}`}
323
- className="checkbox__input"
324
- checked={tagIds?.includes(tag.id)}
325
- onChange={(e) =>
326
- handleOnTagChange(
327
- tag.id,
328
- e.target.checked
329
- )
330
- }
331
- />
332
- </div>
333
- <span className="tag-translation__title">
334
- {tag.title}
335
- </span>
336
- &nbsp;
337
- <span className="tag-translation__description">
338
- {tag.description}
339
- </span>
340
- </label>
341
- ))}
342
- </div>
343
- )}
344
- </div>
345
- </div>
346
- </div>
347
- </div>
348
- </div>
349
- )}
350
- {optionUnits && !isEmpty(optionUnits) && (
351
- <div className="form__group">
352
- <div className="booking-card">
353
- <div className="booking-card__header">
354
- <h2 className="booking-card__header-heading">
355
- {translations.OPTIONS_FORM.PER_UNIT_TITLE}
356
- </h2>
357
- </div>
358
- <div className="booking-card__body">
359
- <OptionUnitsCard
360
- units={optionUnits}
361
- onUnitsChange={handleOnUnitsChange}
362
- />
363
- </div>
364
- </div>
365
- </div>
366
- )}
367
-
368
- {optionPax && !isEmpty(optionPax) && (
369
- <div className="form__group">
370
- <div className="booking-card">
371
- <div className="booking-card__header">
372
- <h2 className="booking-card__header-heading">
373
- {translations.OPTIONS_FORM.PER_PAX_TITLE}
374
- </h2>
375
- </div>
376
- <div className="booking-card__body">
377
- <OptionPaxCard
378
- pax={optionPax}
379
- onPaxChange={handleOnPaxChange}
380
- requestRoomsPax={requestRoomsPax}
381
- />
382
- </div>
383
- </div>
384
- </div>
385
- )}
386
-
387
- {groups && !isEmpty(groups) && (
388
- <div className="form__group">
389
- <div className="booking-card">
390
- <div className="booking-card__header">
391
- <h2 className="booking-card__header-heading">
392
- {translations.OPTIONS_FORM.PER_BOOKING_TITLE}
393
- </h2>
394
- </div>
395
- <div className="booking-card__body">
396
- <div className="booking-card__group booking-card__group--active">
397
- {groups.map((group, i) => (
398
- <OptionBookingGroup
399
- key={`${group.name}_${i}`}
400
- group={group}
401
- firstClassName={"booking-card__group-body"}
402
- secondClassName={"booking-card__group-heading"}
403
- parentId={`booking_${group.name}`}
404
- onGroupChange={handleOnGroupChange}
405
- />
406
- ))}
407
- {airlineGroups?.map((group, i) => (
408
- <OptionBookingAirlineGroup
409
- key={`${group.label}_${i}`}
410
- airGroup={group}
411
- onGroupChange={handleOnAirlineGroupChange}
412
- />
413
- ))}
414
- {airportGroups?.map((group, i) => (
415
- <OptionBookingAirlineGroup
416
- key={`${group.label}_${i}`}
417
- airGroup={group}
418
- onGroupChange={handleOnAirportGroupChange}
419
- />
420
- ))}
421
- </div>
422
- </div>
423
- </div>
424
- </div>
425
- )}
426
-
427
- {isEmpty(groups) && isEmpty(optionUnits) && isEmpty(optionPax) && (
428
- <NoOptions />
429
- )}
430
- </div>
431
- )}
432
- <div className="booking__navigator">
433
- {hasPrevious && (
434
- <>
435
- {settings.skipRouter ? (
436
- <button
437
- type="button"
438
- title={translations.STEPS.PREVIOUS}
439
- onClick={() => goPrevious()}
440
- className="cta cta--secondary"
441
- >
442
- {translations.STEPS.PREVIOUS}
443
- </button>
444
- ) : (
445
- <Link
446
- to={previousUrl}
447
- title={translations.STEPS.PREVIOUS}
448
- className="cta cta--secondary"
449
- >
450
- {translations.STEPS.PREVIOUS}
451
- </Link>
452
- )}
453
- </>
454
- )}
455
- {token && settings.options.reportPrintActionId && (
456
- <PrintOfferButton
457
- bookingPackage={packageDetails}
458
- getPax={getPax}
459
- tagIds={tagIds}
460
- printActionId={settings.options.reportPrintActionId}
461
- labelIdle={translations.PRINT_OFFER_BUTTON.LABEL_IDLE}
462
- labelCreating={translations.PRINT_OFFER_BUTTON.LABEL_CREATING}
463
- labelPrinting={translations.PRINT_OFFER_BUTTON.LABEL_PRINTING}
464
- className="cta spinner-button"
465
- />
466
- )}
467
- <button
468
- type="submit"
469
- title={translations.STEPS.NEXT}
470
- disabled={isLoading}
471
- className={buildClassName(["cta", isLoading && "cta--disabled"])}
472
- >
473
- {translations.STEPS.NEXT}
474
- </button>
475
- </div>
476
- </form>
477
- </>
478
- );
479
- };
480
-
481
- export default OptionsForm;
1
+ import React, { useContext, useEffect } from "react";
2
+
3
+ import {
4
+ AirlineBookingPackageOption,
5
+ AirportBookingPackageOption,
6
+ BookingAirlineGroup,
7
+ BookingAirportGroup,
8
+ BookingOptionGroup,
9
+ BookingOptionPax,
10
+ BookingOptionUnit,
11
+ BookingPackageFlight,
12
+ Pax,
13
+ PerBookingPackageOption,
14
+ } from "@qite/tide-client/build/types";
15
+ import { Link, navigate } from "@reach/router";
16
+ import { isEmpty } from "lodash";
17
+ import { useSelector } from "react-redux";
18
+ import { buildClassName } from "../../../shared/utils/class-util";
19
+ import SettingsContext from "../../settings-context";
20
+ import { useAppDispatch } from "../../store";
21
+ import {
22
+ setCurrentStep,
23
+ setPackage,
24
+ setPackageAirlineGroups,
25
+ setPackageAirportGroups,
26
+ setPackageGroups,
27
+ setPackageOptionPax,
28
+ setPackageOptionUnits,
29
+ setPackageRooms,
30
+ setTagIds,
31
+ } from "../booking/booking-slice";
32
+ import {
33
+ FLIGHT_OPTIONS_FORM_STEP,
34
+ ROOM_OPTIONS_FORM_STEP,
35
+ TRAVELERS_FORM_STEP,
36
+ } from "../booking/constants";
37
+ import {
38
+ selectAvailabilities,
39
+ selectBookingPackagePax,
40
+ selectBookingQueryString,
41
+ selectIsFetchingProductOptions,
42
+ selectPackageAirlineGroups,
43
+ selectPackageAirportGroups,
44
+ selectPackageDetails,
45
+ selectPackageGroups,
46
+ selectPackageOptionPax,
47
+ selectPackageOptionUnits,
48
+ selectPackageRooms,
49
+ selectPackageTags,
50
+ selectRequestRooms,
51
+ selectTagIds,
52
+ selectTranslations,
53
+ } from "../booking/selectors";
54
+ import { fetchPriceDetails } from "../price-details/price-details-slice";
55
+ import { updatePackageRooms } from "../room-options/room-utils";
56
+ import NoOptions from "./no-options";
57
+ import OptionBookingAirlineGroup from "./option-booking-airline-group";
58
+ import OptionBookingGroup from "./option-booking-group";
59
+ import OptionPaxCard from "./option-pax-card";
60
+ import OptionRoom from "./option-room";
61
+ import OptionUnitsCard from "./option-units-card";
62
+ import PrintOfferButton from "../../components/print-offer-button";
63
+
64
+ interface OptionsFormProps {}
65
+
66
+ const OptionsForm: React.FC<OptionsFormProps> = () => {
67
+ const settings = useContext(SettingsContext);
68
+ const { token } = settings;
69
+ const translations = useSelector(selectTranslations);
70
+ const dispatch = useAppDispatch();
71
+ const packageDetails = useSelector(selectPackageDetails);
72
+ const requestRooms = useSelector(selectRequestRooms);
73
+ const requestRoomsPax = requestRooms?.flatMap((x) => x.pax);
74
+ const bookingQueryString = useSelector(selectBookingQueryString);
75
+ const isLoading = useSelector(selectIsFetchingProductOptions);
76
+
77
+ const groups = useSelector(selectPackageGroups);
78
+ const airlineGroups = useSelector(selectPackageAirlineGroups);
79
+ const airportGroups = useSelector(selectPackageAirportGroups);
80
+ const optionUnits = useSelector(selectPackageOptionUnits);
81
+ const optionPax = useSelector(selectPackageOptionPax);
82
+ const availabilities = useSelector(selectAvailabilities);
83
+
84
+ // ROOMS
85
+ const showRoomOptions = settings.roomOptions.isHidden;
86
+ const packageRooms = useSelector(selectPackageRooms);
87
+ const pax = useSelector(selectBookingPackagePax);
88
+
89
+ const getRoomPax = (index: number) => {
90
+ var room = requestRooms?.find((x) => x.index == index);
91
+ var bookingPackagePax = pax.filter((x) =>
92
+ room?.pax.some((y) => y.id == x.id)
93
+ );
94
+ return bookingPackagePax.length > 0 ? bookingPackagePax : room?.pax ?? [];
95
+ };
96
+
97
+ const handleOnRoomChange = (
98
+ index: number,
99
+ accommodationCode: string,
100
+ regimeCode: string | null
101
+ ) => {
102
+ if (!packageRooms) return;
103
+
104
+ const updatedPackageRooms = updatePackageRooms(
105
+ packageRooms,
106
+ index,
107
+ accommodationCode,
108
+ regimeCode,
109
+ availabilities!
110
+ );
111
+
112
+ dispatch(setPackageRooms(updatedPackageRooms));
113
+ dispatch(fetchPriceDetails());
114
+ };
115
+
116
+ const getPax = () => {
117
+ if (!packageDetails) return undefined;
118
+ const selectedOption =
119
+ packageDetails.options.find((o) => o.isSelected) ??
120
+ packageDetails.options[0];
121
+ return selectedOption?.requestRooms.flatMap((r) => r.pax) as Pax[];
122
+ };
123
+
124
+ // TAGS
125
+ const packageTags = settings.hideTags ? [] : useSelector(selectPackageTags);
126
+ let tagIds = useSelector(selectTagIds) ?? [];
127
+
128
+ const handleSubmit: React.FormEventHandler<HTMLFormElement> = (e) => {
129
+ if (settings.skipRouter) {
130
+ dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
131
+ } else {
132
+ navigate(
133
+ `${settings.basePath}${settings.travellers.pathSuffix}?${bookingQueryString}`
134
+ );
135
+ }
136
+
137
+ e.preventDefault();
138
+ };
139
+
140
+ const handleOnPaxChange = (pax: BookingOptionPax[]) => {
141
+ dispatch(setPackageOptionPax(pax));
142
+ dispatch(fetchPriceDetails());
143
+ };
144
+
145
+ const handleOnUnitsChange = (units: BookingOptionUnit[]) => {
146
+ dispatch(setPackageOptionUnits(units));
147
+ dispatch(fetchPriceDetails());
148
+ };
149
+
150
+ const handleOnGroupChange = (
151
+ group: BookingOptionGroup<PerBookingPackageOption>
152
+ ) => {
153
+ if (groups) {
154
+ const updatedGroups = groups?.map((g) =>
155
+ g.name === group.name ? group : g
156
+ );
157
+
158
+ dispatch(setPackageGroups(updatedGroups));
159
+ dispatch(fetchPriceDetails());
160
+ }
161
+ };
162
+
163
+ const handleOnAirlineGroupChange = (
164
+ group: BookingAirlineGroup<AirlineBookingPackageOption>
165
+ ) => {
166
+ if (airlineGroups) {
167
+ const updatedGroups = airlineGroups.map((g) =>
168
+ g.label === group.label ? group : g
169
+ );
170
+
171
+ dispatch(setPackageAirlineGroups(updatedGroups));
172
+ dispatch(fetchPriceDetails());
173
+ }
174
+ };
175
+
176
+ const handleOnAirportGroupChange = (
177
+ group: BookingAirportGroup<AirportBookingPackageOption>
178
+ ) => {
179
+ if (airportGroups) {
180
+ const updatedGroups = airportGroups.map((g) =>
181
+ g.label === group.label ? group : g
182
+ );
183
+
184
+ dispatch(setPackageAirportGroups(updatedGroups));
185
+ dispatch(fetchPriceDetails());
186
+ }
187
+ };
188
+
189
+ const handleOnTagChange = (id: number, checked: boolean) => {
190
+ let updatedTags = [...tagIds];
191
+ if (checked) {
192
+ if (!updatedTags?.includes(id)) {
193
+ updatedTags?.push(id);
194
+ }
195
+ } else {
196
+ updatedTags = updatedTags?.filter((x) => x != id);
197
+ }
198
+
199
+ dispatch(setTagIds(updatedTags));
200
+ dispatch(fetchPriceDetails());
201
+ };
202
+
203
+ useEffect(() => {
204
+ if (
205
+ packageDetails &&
206
+ settings.roomOptions.isHidden &&
207
+ settings.flightOptions.isHidden
208
+ ) {
209
+ const params = new URLSearchParams(location.search);
210
+
211
+ const outwardFlight = params.get("outwardflight") ?? undefined;
212
+ const returnFlight = params.get("returnflight") ?? undefined;
213
+ if (outwardFlight && returnFlight) {
214
+ const desiredOutwardFlight = packageDetails.outwardFlights.find(
215
+ (x) => x.entryLineGuid == outwardFlight
216
+ );
217
+ const desiredReturnFlight = packageDetails.returnFlights.find(
218
+ (x) => x.entryLineGuid == returnFlight
219
+ );
220
+ if (desiredOutwardFlight && desiredReturnFlight) {
221
+ dispatch(
222
+ setPackage({
223
+ ...packageDetails,
224
+ outwardFlights: packageDetails.outwardFlights.map((flight) => {
225
+ return {
226
+ ...flight,
227
+ isSelected:
228
+ flight.entryLineGuid == desiredOutwardFlight.entryLineGuid
229
+ ? true
230
+ : false,
231
+ } as BookingPackageFlight;
232
+ }),
233
+ returnFlights: packageDetails.returnFlights.map((flight) => {
234
+ return {
235
+ ...flight,
236
+ isSelected:
237
+ flight.entryLineGuid == desiredReturnFlight.entryLineGuid
238
+ ? true
239
+ : false,
240
+ } as BookingPackageFlight;
241
+ }),
242
+ })
243
+ );
244
+ }
245
+ }
246
+ }
247
+ dispatch(fetchPriceDetails());
248
+ }, []);
249
+
250
+ const goPrevious = () => {
251
+ if (settings.roomOptions.isHidden) {
252
+ dispatch(setCurrentStep(FLIGHT_OPTIONS_FORM_STEP));
253
+ } else {
254
+ dispatch(setCurrentStep(ROOM_OPTIONS_FORM_STEP));
255
+ }
256
+ };
257
+
258
+ const previousUrl = settings.roomOptions.isHidden
259
+ ? `${settings.basePath}${settings.flightOptions.pathSuffix}?${bookingQueryString}`
260
+ : `${settings.basePath}${settings.roomOptions.pathSuffix}?${bookingQueryString}`;
261
+ const hasPrevious =
262
+ !settings.roomOptions.isHidden || !settings.flightOptions.isHidden;
263
+ const showPackageTagsOrRoomoptions =
264
+ showRoomOptions || (packageTags && !isEmpty(packageTags));
265
+
266
+ return (
267
+ <>
268
+ <form
269
+ className="form"
270
+ name="booking--options"
271
+ id="booking--options"
272
+ noValidate
273
+ onSubmit={handleSubmit}
274
+ >
275
+ {isLoading && settings.loaderComponent}
276
+ {!isLoading && (
277
+ <div className="form__region">
278
+ {showPackageTagsOrRoomoptions && (
279
+ <div className="form__group">
280
+ <div className="booking-card">
281
+ <div className="booking-card__body">
282
+ <div
283
+ className={buildClassName([
284
+ "booking-card__group",
285
+ "booking-card__group--package",
286
+ ])}
287
+ >
288
+ {showRoomOptions && (
289
+ <span className="booking-card__tag">
290
+ {translations.OPTIONS_FORM.PACKAGE}
291
+ </span>
292
+ )}
293
+ <div className="booking-card__group-body">
294
+ {showRoomOptions && (
295
+ <table className="table table--striped">
296
+ <tbody>
297
+ {packageRooms &&
298
+ packageRooms.map((room) => (
299
+ <OptionRoom
300
+ key={room.index}
301
+ packageRoom={room}
302
+ pax={getRoomPax(room.index)}
303
+ optionPax={optionPax}
304
+ onRoomChange={handleOnRoomChange}
305
+ />
306
+ ))}
307
+ </tbody>
308
+ </table>
309
+ )}
310
+ {packageTags && !isEmpty(packageTags) && (
311
+ <div className="booking-card__tag-translations">
312
+ {packageTags.map((tag, index) => (
313
+ <label
314
+ key={index}
315
+ htmlFor={`tag-translation-${index}-${tag.title}`}
316
+ className="checkbox__label tag-translation"
317
+ >
318
+ <div className="tag-translation-input__container">
319
+ <input
320
+ type="checkbox"
321
+ id={`tag-translation-${index}-${tag.title}`}
322
+ name={`tag-translation-${index}-${tag.title}`}
323
+ className="checkbox__input"
324
+ checked={tagIds?.includes(tag.id)}
325
+ onChange={(e) =>
326
+ handleOnTagChange(
327
+ tag.id,
328
+ e.target.checked
329
+ )
330
+ }
331
+ />
332
+ </div>
333
+ <span className="tag-translation__title">
334
+ {tag.title}
335
+ </span>
336
+ &nbsp;
337
+ <span className="tag-translation__description">
338
+ {tag.description}
339
+ </span>
340
+ </label>
341
+ ))}
342
+ </div>
343
+ )}
344
+ </div>
345
+ </div>
346
+ </div>
347
+ </div>
348
+ </div>
349
+ )}
350
+ {optionUnits && !isEmpty(optionUnits) && (
351
+ <div className="form__group">
352
+ <div className="booking-card">
353
+ <div className="booking-card__header">
354
+ <h2 className="booking-card__header-heading">
355
+ {translations.OPTIONS_FORM.PER_UNIT_TITLE}
356
+ </h2>
357
+ </div>
358
+ <div className="booking-card__body">
359
+ <OptionUnitsCard
360
+ units={optionUnits}
361
+ onUnitsChange={handleOnUnitsChange}
362
+ />
363
+ </div>
364
+ </div>
365
+ </div>
366
+ )}
367
+
368
+ {optionPax && !isEmpty(optionPax) && (
369
+ <div className="form__group">
370
+ <div className="booking-card">
371
+ <div className="booking-card__header">
372
+ <h2 className="booking-card__header-heading">
373
+ {translations.OPTIONS_FORM.PER_PAX_TITLE}
374
+ </h2>
375
+ </div>
376
+ <div className="booking-card__body">
377
+ <OptionPaxCard
378
+ pax={optionPax}
379
+ onPaxChange={handleOnPaxChange}
380
+ requestRoomsPax={requestRoomsPax}
381
+ />
382
+ </div>
383
+ </div>
384
+ </div>
385
+ )}
386
+
387
+ {groups && !isEmpty(groups) && (
388
+ <div className="form__group">
389
+ <div className="booking-card">
390
+ <div className="booking-card__header">
391
+ <h2 className="booking-card__header-heading">
392
+ {translations.OPTIONS_FORM.PER_BOOKING_TITLE}
393
+ </h2>
394
+ </div>
395
+ <div className="booking-card__body">
396
+ <div className="booking-card__group booking-card__group--active">
397
+ {groups.map((group, i) => (
398
+ <OptionBookingGroup
399
+ key={`${group.name}_${i}`}
400
+ group={group}
401
+ firstClassName={"booking-card__group-body"}
402
+ secondClassName={"booking-card__group-heading"}
403
+ parentId={`booking_${group.name}`}
404
+ onGroupChange={handleOnGroupChange}
405
+ />
406
+ ))}
407
+ {airlineGroups?.map((group, i) => (
408
+ <OptionBookingAirlineGroup
409
+ key={`${group.label}_${i}`}
410
+ airGroup={group}
411
+ onGroupChange={handleOnAirlineGroupChange}
412
+ />
413
+ ))}
414
+ {airportGroups?.map((group, i) => (
415
+ <OptionBookingAirlineGroup
416
+ key={`${group.label}_${i}`}
417
+ airGroup={group}
418
+ onGroupChange={handleOnAirportGroupChange}
419
+ />
420
+ ))}
421
+ </div>
422
+ </div>
423
+ </div>
424
+ </div>
425
+ )}
426
+
427
+ {isEmpty(groups) && isEmpty(optionUnits) && isEmpty(optionPax) && (
428
+ <NoOptions />
429
+ )}
430
+ </div>
431
+ )}
432
+ <div className="booking__navigator">
433
+ {hasPrevious && (
434
+ <>
435
+ {settings.skipRouter ? (
436
+ <button
437
+ type="button"
438
+ title={translations.STEPS.PREVIOUS}
439
+ onClick={() => goPrevious()}
440
+ className="cta cta--secondary"
441
+ >
442
+ {translations.STEPS.PREVIOUS}
443
+ </button>
444
+ ) : (
445
+ <Link
446
+ to={previousUrl}
447
+ title={translations.STEPS.PREVIOUS}
448
+ className="cta cta--secondary"
449
+ >
450
+ {translations.STEPS.PREVIOUS}
451
+ </Link>
452
+ )}
453
+ </>
454
+ )}
455
+ {token && settings.options.reportPrintActionId && (
456
+ <PrintOfferButton
457
+ bookingPackage={packageDetails}
458
+ getPax={getPax}
459
+ tagIds={tagIds}
460
+ printActionId={settings.options.reportPrintActionId}
461
+ labelIdle={translations.PRINT_OFFER_BUTTON.LABEL_IDLE}
462
+ labelCreating={translations.PRINT_OFFER_BUTTON.LABEL_CREATING}
463
+ labelPrinting={translations.PRINT_OFFER_BUTTON.LABEL_PRINTING}
464
+ className="cta spinner-button"
465
+ />
466
+ )}
467
+ <button
468
+ type="submit"
469
+ title={translations.STEPS.NEXT}
470
+ disabled={isLoading}
471
+ className={buildClassName(["cta", isLoading && "cta--disabled"])}
472
+ >
473
+ {translations.STEPS.NEXT}
474
+ </button>
475
+ </div>
476
+ </form>
477
+ </>
478
+ );
479
+ };
480
+
481
+ export default OptionsForm;