@qite/tide-components 1.0.12 → 1.0.13-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/build-cjs/index.js +2228 -1420
- package/build/build-cjs/src/booking-wizard/features/booking/selectors.d.ts +1 -1
- package/build/build-cjs/src/booking-wizard/features/travelers-form/validate-form.d.ts +2 -2
- package/build/build-cjs/src/booking-wizard/types.d.ts +23 -2
- package/build/build-cjs/src/search-results/components/flight/flight-selection/independent-flight-option.d.ts +2 -0
- package/build/build-cjs/src/search-results/components/itinerary/index.d.ts +1 -0
- package/build/build-cjs/src/search-results/components/itinerary/itinerary-utils.d.ts +1 -0
- package/build/build-cjs/src/search-results/types.d.ts +8 -0
- package/build/build-cjs/src/search-results/utils/booked-entry-utils.d.ts +20 -0
- package/build/build-cjs/src/search-results/utils/traject-utils.d.ts +7 -0
- package/build/build-cjs/src/shared/booking/travelers-form.d.ts +13 -8
- package/build/build-esm/index.js +2232 -1424
- package/build/build-esm/src/booking-wizard/features/booking/selectors.d.ts +1 -1
- package/build/build-esm/src/booking-wizard/features/travelers-form/validate-form.d.ts +2 -2
- package/build/build-esm/src/booking-wizard/types.d.ts +23 -2
- package/build/build-esm/src/search-results/components/flight/flight-selection/independent-flight-option.d.ts +2 -0
- package/build/build-esm/src/search-results/components/itinerary/index.d.ts +1 -0
- package/build/build-esm/src/search-results/components/itinerary/itinerary-utils.d.ts +1 -0
- package/build/build-esm/src/search-results/types.d.ts +8 -0
- package/build/build-esm/src/search-results/utils/booked-entry-utils.d.ts +20 -0
- package/build/build-esm/src/search-results/utils/traject-utils.d.ts +7 -0
- package/build/build-esm/src/shared/booking/travelers-form.d.ts +13 -8
- package/package.json +2 -2
- package/styles/components/_slider.scss +0 -8
package/build/build-esm/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default, { useLayoutEffect as useLayoutEffect$1, useEffect, useContext, useState, useRef,
|
|
3
|
+
import React__default, { useLayoutEffect as useLayoutEffect$1, useEffect, useContext, useState, useRef, useMemo, useCallback } from 'react';
|
|
4
4
|
import JsonURL from '@jsonurl/jsonurl';
|
|
5
|
-
import { format as format$2, isToday, getDate, startOfWeek, startOfMonth, endOfWeek, addWeeks, endOfMonth, eachDayOfInterval, getYear, getMonth, getISOWeek, getISODay, isSameMonth, startOfDay, isAfter, isSameDay, isEqual, isWithinInterval, endOfDay, isBefore, differenceInCalendarDays, addMonths, addDays, formatISO, addYears, differenceInYears,
|
|
6
|
-
import { merge, cloneDeep, isNil, isArray as isArray$1, compact, isEmpty as isEmpty$1, range, chunk, isFunction as isFunction$1, clamp, now, omit, isPlainObject as isPlainObject$1, mapValues, pickBy,
|
|
5
|
+
import { format as format$2, isToday, getDate, startOfWeek, startOfMonth, endOfWeek, addWeeks, endOfMonth, eachDayOfInterval, getYear, getMonth, getISOWeek, getISODay, isSameMonth, startOfDay, isAfter, isSameDay, isEqual, isWithinInterval, endOfDay, isBefore, differenceInCalendarDays, addMonths, addDays, formatISO, addYears, differenceInYears, parse, isValid, parseISO, differenceInMinutes, startOfToday } from 'date-fns';
|
|
6
|
+
import { merge, cloneDeep, isNil, isArray as isArray$1, compact, isEmpty as isEmpty$1, range, chunk, isFunction as isFunction$1, clamp, now, omit, get, last, first, sortBy, isPlainObject as isPlainObject$1, mapValues, pickBy, orderBy, uniq, uniqBy, sum, findIndex as findIndex$1, set, isEqual as isEqual$1, groupBy, minBy, concat, flatMap } from 'lodash';
|
|
7
7
|
import { arSA, da, de, enGB, es, fr, is, it, nl, nb, pl, pt, sv, ja, enUS } from 'date-fns/locale';
|
|
8
8
|
import { usePopper } from 'react-popper';
|
|
9
9
|
import { useSelector, useDispatch, Provider } from 'react-redux';
|
|
10
10
|
import { createSlice, createSelector, createAsyncThunk, configureStore } from '@reduxjs/toolkit';
|
|
11
|
+
import flat from 'flat';
|
|
11
12
|
import { UNSAFE_NavigationContext, useHref, useNavigate, useLocation, useResolvedPath, createPath, UNSAFE_DataRouterStateContext, UNSAFE_useRouteId, UNSAFE_RouteContext, UNSAFE_DataRouterContext, Routes, Route } from 'react-router';
|
|
12
13
|
import 'react-dom';
|
|
13
14
|
import produce from 'immer';
|
|
14
15
|
import { useFormik } from 'formik';
|
|
15
|
-
import flat from 'flat';
|
|
16
16
|
import { v4 } from 'uuid';
|
|
17
17
|
|
|
18
18
|
function _mergeNamespaces(n, m) {
|
|
@@ -124,7 +124,9 @@ var SHARED$f = {
|
|
|
124
124
|
ADULTS: "بالغون",
|
|
125
125
|
CHILDREN: "أطفال",
|
|
126
126
|
SELECT: "اختر",
|
|
127
|
-
SELECTED: "تم الاختيار"
|
|
127
|
+
SELECTED: "تم الاختيار",
|
|
128
|
+
BOOKED: "محجوز",
|
|
129
|
+
SAVE: "حفظ"
|
|
128
130
|
};
|
|
129
131
|
var SIDEBAR$f = {
|
|
130
132
|
OVERVIEW: "الملخص",
|
|
@@ -182,6 +184,21 @@ var TRAVELERS_FORM$f = {
|
|
|
182
184
|
FIRST_NAME: "الاسم الأول",
|
|
183
185
|
LAST_NAME: "اسم العائلة",
|
|
184
186
|
BIRTHDATE: "تاريخ الميلاد",
|
|
187
|
+
NICKNAME: "Nickname",
|
|
188
|
+
BIRTHPLACE: "Birthplace",
|
|
189
|
+
NATIONALITY: "Nationality",
|
|
190
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
191
|
+
TRAVELER_EMAIL: "Email",
|
|
192
|
+
TRAVELER_PHONE: "Phone",
|
|
193
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
194
|
+
PASSPORT_NUMBER: "Passport number",
|
|
195
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
196
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
197
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
198
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
199
|
+
HAS_INSURANCE: "Has insurance",
|
|
200
|
+
INSURANCE_NAME: "Insurance name",
|
|
201
|
+
INFO: "Additional information",
|
|
185
202
|
WEIGHT: "الوزن",
|
|
186
203
|
WEIGHT_UNIT_KG: "kg",
|
|
187
204
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -577,7 +594,9 @@ var SHARED$e = {
|
|
|
577
594
|
ADULTS: "Voksne",
|
|
578
595
|
CHILDREN: "Børn",
|
|
579
596
|
SELECT: "Vælg",
|
|
580
|
-
SELECTED: "Valgt"
|
|
597
|
+
SELECTED: "Valgt",
|
|
598
|
+
BOOKED: "Booket",
|
|
599
|
+
SAVE: "Gem"
|
|
581
600
|
};
|
|
582
601
|
var SIDEBAR$e = {
|
|
583
602
|
OVERVIEW: "Oversigt",
|
|
@@ -635,6 +654,21 @@ var TRAVELERS_FORM$e = {
|
|
|
635
654
|
FIRST_NAME: "Fornavn",
|
|
636
655
|
LAST_NAME: "Efternavn",
|
|
637
656
|
BIRTHDATE: "Fødselsdato",
|
|
657
|
+
NICKNAME: "Nickname",
|
|
658
|
+
BIRTHPLACE: "Birthplace",
|
|
659
|
+
NATIONALITY: "Nationality",
|
|
660
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
661
|
+
TRAVELER_EMAIL: "Email",
|
|
662
|
+
TRAVELER_PHONE: "Phone",
|
|
663
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
664
|
+
PASSPORT_NUMBER: "Passport number",
|
|
665
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
666
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
667
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
668
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
669
|
+
HAS_INSURANCE: "Has insurance",
|
|
670
|
+
INSURANCE_NAME: "Insurance name",
|
|
671
|
+
INFO: "Additional information",
|
|
638
672
|
WEIGHT: "Vægt",
|
|
639
673
|
WEIGHT_UNIT_KG: "kg",
|
|
640
674
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -1030,7 +1064,9 @@ var SHARED$d = {
|
|
|
1030
1064
|
ADULTS: "Erwachsene",
|
|
1031
1065
|
CHILDREN: "Kinder",
|
|
1032
1066
|
SELECT: "Auswählen",
|
|
1033
|
-
SELECTED: "Ausgewählt"
|
|
1067
|
+
SELECTED: "Ausgewählt",
|
|
1068
|
+
BOOKED: "Gebucht",
|
|
1069
|
+
SAVE: "Speichern"
|
|
1034
1070
|
};
|
|
1035
1071
|
var SIDEBAR$d = {
|
|
1036
1072
|
OVERVIEW: "Übersicht",
|
|
@@ -1088,6 +1124,21 @@ var TRAVELERS_FORM$d = {
|
|
|
1088
1124
|
FIRST_NAME: "Vorname",
|
|
1089
1125
|
LAST_NAME: "Nachname",
|
|
1090
1126
|
BIRTHDATE: "Geburtsdatum",
|
|
1127
|
+
NICKNAME: "Nickname",
|
|
1128
|
+
BIRTHPLACE: "Birthplace",
|
|
1129
|
+
NATIONALITY: "Nationality",
|
|
1130
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
1131
|
+
TRAVELER_EMAIL: "Email",
|
|
1132
|
+
TRAVELER_PHONE: "Phone",
|
|
1133
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
1134
|
+
PASSPORT_NUMBER: "Passport number",
|
|
1135
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
1136
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
1137
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
1138
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
1139
|
+
HAS_INSURANCE: "Has insurance",
|
|
1140
|
+
INSURANCE_NAME: "Insurance name",
|
|
1141
|
+
INFO: "Additional information",
|
|
1091
1142
|
WEIGHT: "Gewicht",
|
|
1092
1143
|
WEIGHT_UNIT_KG: "kg",
|
|
1093
1144
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -1483,7 +1534,9 @@ var SHARED$c = {
|
|
|
1483
1534
|
ADULTS: "Adults",
|
|
1484
1535
|
CHILDREN: "Children",
|
|
1485
1536
|
SELECT: "Select",
|
|
1486
|
-
SELECTED: "Selected"
|
|
1537
|
+
SELECTED: "Selected",
|
|
1538
|
+
BOOKED: "Booked",
|
|
1539
|
+
SAVE: "Save"
|
|
1487
1540
|
};
|
|
1488
1541
|
var SIDEBAR$c = {
|
|
1489
1542
|
OVERVIEW: "Summary",
|
|
@@ -1542,6 +1595,21 @@ var TRAVELERS_FORM$c = {
|
|
|
1542
1595
|
FIRST_NAME: "First name",
|
|
1543
1596
|
LAST_NAME: "Last name",
|
|
1544
1597
|
BIRTHDATE: "Date of birth",
|
|
1598
|
+
NICKNAME: "Nickname",
|
|
1599
|
+
BIRTHPLACE: "Birthplace",
|
|
1600
|
+
NATIONALITY: "Nationality",
|
|
1601
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
1602
|
+
TRAVELER_EMAIL: "Email",
|
|
1603
|
+
TRAVELER_PHONE: "Phone",
|
|
1604
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
1605
|
+
PASSPORT_NUMBER: "Passport number",
|
|
1606
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
1607
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
1608
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
1609
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
1610
|
+
HAS_INSURANCE: "Has insurance",
|
|
1611
|
+
INSURANCE_NAME: "Insurance name",
|
|
1612
|
+
INFO: "Additional information",
|
|
1545
1613
|
WEIGHT: "Weight",
|
|
1546
1614
|
WEIGHT_UNIT_KG: "kg",
|
|
1547
1615
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -1940,7 +2008,9 @@ var SHARED$b = {
|
|
|
1940
2008
|
ADULTS: "Adultos",
|
|
1941
2009
|
CHILDREN: "Niños",
|
|
1942
2010
|
SELECT: "Seleccionar",
|
|
1943
|
-
SELECTED: "Seleccionado"
|
|
2011
|
+
SELECTED: "Seleccionado",
|
|
2012
|
+
BOOKED: "Reservado",
|
|
2013
|
+
SAVE: "Guardar"
|
|
1944
2014
|
};
|
|
1945
2015
|
var SIDEBAR$b = {
|
|
1946
2016
|
OVERVIEW: "Resumen",
|
|
@@ -1998,6 +2068,21 @@ var TRAVELERS_FORM$b = {
|
|
|
1998
2068
|
FIRST_NAME: "Nombre",
|
|
1999
2069
|
LAST_NAME: "Apellido",
|
|
2000
2070
|
BIRTHDATE: "Fecha de nacimiento",
|
|
2071
|
+
NICKNAME: "Nickname",
|
|
2072
|
+
BIRTHPLACE: "Birthplace",
|
|
2073
|
+
NATIONALITY: "Nationality",
|
|
2074
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
2075
|
+
TRAVELER_EMAIL: "Email",
|
|
2076
|
+
TRAVELER_PHONE: "Phone",
|
|
2077
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
2078
|
+
PASSPORT_NUMBER: "Passport number",
|
|
2079
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
2080
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
2081
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
2082
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
2083
|
+
HAS_INSURANCE: "Has insurance",
|
|
2084
|
+
INSURANCE_NAME: "Insurance name",
|
|
2085
|
+
INFO: "Additional information",
|
|
2001
2086
|
WEIGHT: "Peso",
|
|
2002
2087
|
WEIGHT_UNIT_KG: "kg",
|
|
2003
2088
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -2393,7 +2478,9 @@ var SHARED$a = {
|
|
|
2393
2478
|
ADULTS: "Adultes",
|
|
2394
2479
|
CHILDREN: "Enfants",
|
|
2395
2480
|
SELECT: "Sélectionner",
|
|
2396
|
-
SELECTED: "Sélectionné"
|
|
2481
|
+
SELECTED: "Sélectionné",
|
|
2482
|
+
BOOKED: "Réservé",
|
|
2483
|
+
SAVE: "Enregistrer"
|
|
2397
2484
|
};
|
|
2398
2485
|
var SIDEBAR$a = {
|
|
2399
2486
|
OVERVIEW: "Aperçu",
|
|
@@ -2452,6 +2539,21 @@ var TRAVELERS_FORM$a = {
|
|
|
2452
2539
|
FIRST_NAME: "Prénom",
|
|
2453
2540
|
LAST_NAME: "Nom",
|
|
2454
2541
|
BIRTHDATE: "Date de naissance",
|
|
2542
|
+
NICKNAME: "Nickname",
|
|
2543
|
+
BIRTHPLACE: "Birthplace",
|
|
2544
|
+
NATIONALITY: "Nationality",
|
|
2545
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
2546
|
+
TRAVELER_EMAIL: "Email",
|
|
2547
|
+
TRAVELER_PHONE: "Phone",
|
|
2548
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
2549
|
+
PASSPORT_NUMBER: "Passport number",
|
|
2550
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
2551
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
2552
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
2553
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
2554
|
+
HAS_INSURANCE: "Has insurance",
|
|
2555
|
+
INSURANCE_NAME: "Insurance name",
|
|
2556
|
+
INFO: "Additional information",
|
|
2455
2557
|
WEIGHT: "Poids",
|
|
2456
2558
|
WEIGHT_UNIT_KG: "kg",
|
|
2457
2559
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -2850,7 +2952,9 @@ var SHARED$9 = {
|
|
|
2850
2952
|
ADULTS: "Adultes",
|
|
2851
2953
|
CHILDREN: "Enfants",
|
|
2852
2954
|
SELECT: "Sélectionner",
|
|
2853
|
-
SELECTED: "Sélectionné"
|
|
2955
|
+
SELECTED: "Sélectionné",
|
|
2956
|
+
BOOKED: "Réservé",
|
|
2957
|
+
SAVE: "Enregistrer"
|
|
2854
2958
|
};
|
|
2855
2959
|
var SIDEBAR$9 = {
|
|
2856
2960
|
OVERVIEW: "Résumé",
|
|
@@ -2908,6 +3012,21 @@ var TRAVELERS_FORM$9 = {
|
|
|
2908
3012
|
FIRST_NAME: "Prénom",
|
|
2909
3013
|
LAST_NAME: "Nom",
|
|
2910
3014
|
BIRTHDATE: "Date de naissance",
|
|
3015
|
+
NICKNAME: "Nickname",
|
|
3016
|
+
BIRTHPLACE: "Birthplace",
|
|
3017
|
+
NATIONALITY: "Nationality",
|
|
3018
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
3019
|
+
TRAVELER_EMAIL: "Email",
|
|
3020
|
+
TRAVELER_PHONE: "Phone",
|
|
3021
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
3022
|
+
PASSPORT_NUMBER: "Passport number",
|
|
3023
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
3024
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
3025
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
3026
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
3027
|
+
HAS_INSURANCE: "Has insurance",
|
|
3028
|
+
INSURANCE_NAME: "Insurance name",
|
|
3029
|
+
INFO: "Additional information",
|
|
2911
3030
|
WEIGHT: "Poids",
|
|
2912
3031
|
WEIGHT_UNIT_KG: "kg",
|
|
2913
3032
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -3303,7 +3422,9 @@ var SHARED$8 = {
|
|
|
3303
3422
|
ADULTS: "Fullorðnir",
|
|
3304
3423
|
CHILDREN: "Börn",
|
|
3305
3424
|
SELECT: "Velja",
|
|
3306
|
-
SELECTED: "Valið"
|
|
3425
|
+
SELECTED: "Valið",
|
|
3426
|
+
BOOKED: "Bókað",
|
|
3427
|
+
SAVE: "Vista"
|
|
3307
3428
|
};
|
|
3308
3429
|
var SIDEBAR$8 = {
|
|
3309
3430
|
OVERVIEW: "Yfirlit",
|
|
@@ -3361,6 +3482,21 @@ var TRAVELERS_FORM$8 = {
|
|
|
3361
3482
|
FIRST_NAME: "Fornafn",
|
|
3362
3483
|
LAST_NAME: "Eftirnafn",
|
|
3363
3484
|
BIRTHDATE: "Fæðingardagur",
|
|
3485
|
+
NICKNAME: "Nickname",
|
|
3486
|
+
BIRTHPLACE: "Birthplace",
|
|
3487
|
+
NATIONALITY: "Nationality",
|
|
3488
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
3489
|
+
TRAVELER_EMAIL: "Email",
|
|
3490
|
+
TRAVELER_PHONE: "Phone",
|
|
3491
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
3492
|
+
PASSPORT_NUMBER: "Passport number",
|
|
3493
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
3494
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
3495
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
3496
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
3497
|
+
HAS_INSURANCE: "Has insurance",
|
|
3498
|
+
INSURANCE_NAME: "Insurance name",
|
|
3499
|
+
INFO: "Additional information",
|
|
3364
3500
|
WEIGHT: "Þyngd",
|
|
3365
3501
|
WEIGHT_UNIT_KG: "kg",
|
|
3366
3502
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -3756,7 +3892,9 @@ var SHARED$7 = {
|
|
|
3756
3892
|
ADULTS: "Adulti",
|
|
3757
3893
|
CHILDREN: "Bambini",
|
|
3758
3894
|
SELECT: "Seleziona",
|
|
3759
|
-
SELECTED: "Selezionato"
|
|
3895
|
+
SELECTED: "Selezionato",
|
|
3896
|
+
BOOKED: "Prenotato",
|
|
3897
|
+
SAVE: "Salva"
|
|
3760
3898
|
};
|
|
3761
3899
|
var SIDEBAR$7 = {
|
|
3762
3900
|
OVERVIEW: "Riepilogo",
|
|
@@ -3814,6 +3952,21 @@ var TRAVELERS_FORM$7 = {
|
|
|
3814
3952
|
FIRST_NAME: "Nome",
|
|
3815
3953
|
LAST_NAME: "Cognome",
|
|
3816
3954
|
BIRTHDATE: "Data di nascita",
|
|
3955
|
+
NICKNAME: "Nickname",
|
|
3956
|
+
BIRTHPLACE: "Birthplace",
|
|
3957
|
+
NATIONALITY: "Nationality",
|
|
3958
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
3959
|
+
TRAVELER_EMAIL: "Email",
|
|
3960
|
+
TRAVELER_PHONE: "Phone",
|
|
3961
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
3962
|
+
PASSPORT_NUMBER: "Passport number",
|
|
3963
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
3964
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
3965
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
3966
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
3967
|
+
HAS_INSURANCE: "Has insurance",
|
|
3968
|
+
INSURANCE_NAME: "Insurance name",
|
|
3969
|
+
INFO: "Additional information",
|
|
3817
3970
|
WEIGHT: "Peso",
|
|
3818
3971
|
WEIGHT_UNIT_KG: "kg",
|
|
3819
3972
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -4209,7 +4362,9 @@ var SHARED$6 = {
|
|
|
4209
4362
|
ADULTS: "Volwassenen",
|
|
4210
4363
|
CHILDREN: "Kinderen",
|
|
4211
4364
|
SELECT: "Selecteer",
|
|
4212
|
-
SELECTED: "Geselecteerd"
|
|
4365
|
+
SELECTED: "Geselecteerd",
|
|
4366
|
+
BOOKED: "Geboekt",
|
|
4367
|
+
SAVE: "Opslaan"
|
|
4213
4368
|
};
|
|
4214
4369
|
var SIDEBAR$6 = {
|
|
4215
4370
|
OVERVIEW: "Overzicht",
|
|
@@ -4268,6 +4423,21 @@ var TRAVELERS_FORM$6 = {
|
|
|
4268
4423
|
FIRST_NAME: "Voornaam",
|
|
4269
4424
|
LAST_NAME: "Naam",
|
|
4270
4425
|
BIRTHDATE: "Geboortedatum",
|
|
4426
|
+
NICKNAME: "Nickname",
|
|
4427
|
+
BIRTHPLACE: "Birthplace",
|
|
4428
|
+
NATIONALITY: "Nationality",
|
|
4429
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
4430
|
+
TRAVELER_EMAIL: "Email",
|
|
4431
|
+
TRAVELER_PHONE: "Phone",
|
|
4432
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
4433
|
+
PASSPORT_NUMBER: "Passport number",
|
|
4434
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
4435
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
4436
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
4437
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
4438
|
+
HAS_INSURANCE: "Has insurance",
|
|
4439
|
+
INSURANCE_NAME: "Insurance name",
|
|
4440
|
+
INFO: "Additional information",
|
|
4271
4441
|
WEIGHT: "Gewicht",
|
|
4272
4442
|
WEIGHT_UNIT_KG: "kg",
|
|
4273
4443
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -4666,7 +4836,9 @@ var SHARED$5 = {
|
|
|
4666
4836
|
ADULTS: "Volwassenen",
|
|
4667
4837
|
CHILDREN: "Kinderen",
|
|
4668
4838
|
SELECT: "Selecteren",
|
|
4669
|
-
SELECTED: "Geselecteerd"
|
|
4839
|
+
SELECTED: "Geselecteerd",
|
|
4840
|
+
BOOKED: "Geboekt",
|
|
4841
|
+
SAVE: "Opslaan"
|
|
4670
4842
|
};
|
|
4671
4843
|
var SIDEBAR$5 = {
|
|
4672
4844
|
OVERVIEW: "Overzicht",
|
|
@@ -4724,6 +4896,21 @@ var TRAVELERS_FORM$5 = {
|
|
|
4724
4896
|
FIRST_NAME: "Voornaam",
|
|
4725
4897
|
LAST_NAME: "Achternaam",
|
|
4726
4898
|
BIRTHDATE: "Geboortedatum",
|
|
4899
|
+
NICKNAME: "Nickname",
|
|
4900
|
+
BIRTHPLACE: "Birthplace",
|
|
4901
|
+
NATIONALITY: "Nationality",
|
|
4902
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
4903
|
+
TRAVELER_EMAIL: "Email",
|
|
4904
|
+
TRAVELER_PHONE: "Phone",
|
|
4905
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
4906
|
+
PASSPORT_NUMBER: "Passport number",
|
|
4907
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
4908
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
4909
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
4910
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
4911
|
+
HAS_INSURANCE: "Has insurance",
|
|
4912
|
+
INSURANCE_NAME: "Insurance name",
|
|
4913
|
+
INFO: "Additional information",
|
|
4727
4914
|
WEIGHT: "Gewicht",
|
|
4728
4915
|
WEIGHT_UNIT_KG: "kg",
|
|
4729
4916
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -5119,7 +5306,9 @@ var SHARED$4 = {
|
|
|
5119
5306
|
ADULTS: "Voksne",
|
|
5120
5307
|
CHILDREN: "Barn",
|
|
5121
5308
|
SELECT: "Velg",
|
|
5122
|
-
SELECTED: "Valgt"
|
|
5309
|
+
SELECTED: "Valgt",
|
|
5310
|
+
BOOKED: "Booket",
|
|
5311
|
+
SAVE: "Lagre"
|
|
5123
5312
|
};
|
|
5124
5313
|
var SIDEBAR$4 = {
|
|
5125
5314
|
OVERVIEW: "Oversikt",
|
|
@@ -5177,6 +5366,21 @@ var TRAVELERS_FORM$4 = {
|
|
|
5177
5366
|
FIRST_NAME: "Fornavn",
|
|
5178
5367
|
LAST_NAME: "Etternavn",
|
|
5179
5368
|
BIRTHDATE: "Fødselsdato",
|
|
5369
|
+
NICKNAME: "Nickname",
|
|
5370
|
+
BIRTHPLACE: "Birthplace",
|
|
5371
|
+
NATIONALITY: "Nationality",
|
|
5372
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
5373
|
+
TRAVELER_EMAIL: "Email",
|
|
5374
|
+
TRAVELER_PHONE: "Phone",
|
|
5375
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
5376
|
+
PASSPORT_NUMBER: "Passport number",
|
|
5377
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
5378
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
5379
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
5380
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
5381
|
+
HAS_INSURANCE: "Has insurance",
|
|
5382
|
+
INSURANCE_NAME: "Insurance name",
|
|
5383
|
+
INFO: "Additional information",
|
|
5180
5384
|
WEIGHT: "Vekt",
|
|
5181
5385
|
WEIGHT_UNIT_KG: "kg",
|
|
5182
5386
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -5572,7 +5776,9 @@ var SHARED$3 = {
|
|
|
5572
5776
|
ADULTS: "Dorośli",
|
|
5573
5777
|
CHILDREN: "Dzieci",
|
|
5574
5778
|
SELECT: "Wybierz",
|
|
5575
|
-
SELECTED: "Wybrane"
|
|
5779
|
+
SELECTED: "Wybrane",
|
|
5780
|
+
BOOKED: "Zarezerwowane",
|
|
5781
|
+
SAVE: "Zapisz"
|
|
5576
5782
|
};
|
|
5577
5783
|
var SIDEBAR$3 = {
|
|
5578
5784
|
OVERVIEW: "Podsumowanie",
|
|
@@ -5630,6 +5836,21 @@ var TRAVELERS_FORM$3 = {
|
|
|
5630
5836
|
FIRST_NAME: "Imię",
|
|
5631
5837
|
LAST_NAME: "Nazwisko",
|
|
5632
5838
|
BIRTHDATE: "Data urodzenia",
|
|
5839
|
+
NICKNAME: "Nickname",
|
|
5840
|
+
BIRTHPLACE: "Birthplace",
|
|
5841
|
+
NATIONALITY: "Nationality",
|
|
5842
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
5843
|
+
TRAVELER_EMAIL: "Email",
|
|
5844
|
+
TRAVELER_PHONE: "Phone",
|
|
5845
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
5846
|
+
PASSPORT_NUMBER: "Passport number",
|
|
5847
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
5848
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
5849
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
5850
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
5851
|
+
HAS_INSURANCE: "Has insurance",
|
|
5852
|
+
INSURANCE_NAME: "Insurance name",
|
|
5853
|
+
INFO: "Additional information",
|
|
5633
5854
|
WEIGHT: "Waga",
|
|
5634
5855
|
WEIGHT_UNIT_KG: "kg",
|
|
5635
5856
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -6025,7 +6246,9 @@ var SHARED$2 = {
|
|
|
6025
6246
|
ADULTS: "Adultos",
|
|
6026
6247
|
CHILDREN: "Crianças",
|
|
6027
6248
|
SELECT: "Selecionar",
|
|
6028
|
-
SELECTED: "Selecionado"
|
|
6249
|
+
SELECTED: "Selecionado",
|
|
6250
|
+
BOOKED: "Reservado",
|
|
6251
|
+
SAVE: "Guardar"
|
|
6029
6252
|
};
|
|
6030
6253
|
var SIDEBAR$2 = {
|
|
6031
6254
|
OVERVIEW: "Resumo",
|
|
@@ -6083,6 +6306,21 @@ var TRAVELERS_FORM$2 = {
|
|
|
6083
6306
|
FIRST_NAME: "Nome",
|
|
6084
6307
|
LAST_NAME: "Apelido",
|
|
6085
6308
|
BIRTHDATE: "Data de nascimento",
|
|
6309
|
+
NICKNAME: "Nickname",
|
|
6310
|
+
BIRTHPLACE: "Birthplace",
|
|
6311
|
+
NATIONALITY: "Nationality",
|
|
6312
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
6313
|
+
TRAVELER_EMAIL: "Email",
|
|
6314
|
+
TRAVELER_PHONE: "Phone",
|
|
6315
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
6316
|
+
PASSPORT_NUMBER: "Passport number",
|
|
6317
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
6318
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
6319
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
6320
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
6321
|
+
HAS_INSURANCE: "Has insurance",
|
|
6322
|
+
INSURANCE_NAME: "Insurance name",
|
|
6323
|
+
INFO: "Additional information",
|
|
6086
6324
|
WEIGHT: "Peso",
|
|
6087
6325
|
WEIGHT_UNIT_KG: "kg",
|
|
6088
6326
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -6478,7 +6716,9 @@ var SHARED$1 = {
|
|
|
6478
6716
|
ADULTS: "Vuxna",
|
|
6479
6717
|
CHILDREN: "Barn",
|
|
6480
6718
|
SELECT: "Välj",
|
|
6481
|
-
SELECTED: "Vald"
|
|
6719
|
+
SELECTED: "Vald",
|
|
6720
|
+
BOOKED: "Bokad",
|
|
6721
|
+
SAVE: "Spara"
|
|
6482
6722
|
};
|
|
6483
6723
|
var SIDEBAR$1 = {
|
|
6484
6724
|
OVERVIEW: "Översikt",
|
|
@@ -6536,6 +6776,21 @@ var TRAVELERS_FORM$1 = {
|
|
|
6536
6776
|
FIRST_NAME: "Förnamn",
|
|
6537
6777
|
LAST_NAME: "Efternamn",
|
|
6538
6778
|
BIRTHDATE: "Födelsedatum",
|
|
6779
|
+
NICKNAME: "Nickname",
|
|
6780
|
+
BIRTHPLACE: "Birthplace",
|
|
6781
|
+
NATIONALITY: "Nationality",
|
|
6782
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
6783
|
+
TRAVELER_EMAIL: "Email",
|
|
6784
|
+
TRAVELER_PHONE: "Phone",
|
|
6785
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
6786
|
+
PASSPORT_NUMBER: "Passport number",
|
|
6787
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
6788
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
6789
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
6790
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
6791
|
+
HAS_INSURANCE: "Has insurance",
|
|
6792
|
+
INSURANCE_NAME: "Insurance name",
|
|
6793
|
+
INFO: "Additional information",
|
|
6539
6794
|
WEIGHT: "Vikt",
|
|
6540
6795
|
WEIGHT_UNIT_KG: "kg",
|
|
6541
6796
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -6931,7 +7186,9 @@ var SHARED = {
|
|
|
6931
7186
|
ADULTS: "大人",
|
|
6932
7187
|
CHILDREN: "子供",
|
|
6933
7188
|
SELECT: "選択",
|
|
6934
|
-
SELECTED: "選択済み"
|
|
7189
|
+
SELECTED: "選択済み",
|
|
7190
|
+
BOOKED: "予約済み",
|
|
7191
|
+
SAVE: "保存"
|
|
6935
7192
|
};
|
|
6936
7193
|
var SIDEBAR = {
|
|
6937
7194
|
OVERVIEW: "概要",
|
|
@@ -6989,6 +7246,21 @@ var TRAVELERS_FORM = {
|
|
|
6989
7246
|
FIRST_NAME: "名",
|
|
6990
7247
|
LAST_NAME: "姓",
|
|
6991
7248
|
BIRTHDATE: "生年月日",
|
|
7249
|
+
NICKNAME: "Nickname",
|
|
7250
|
+
BIRTHPLACE: "Birthplace",
|
|
7251
|
+
NATIONALITY: "Nationality",
|
|
7252
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
7253
|
+
TRAVELER_EMAIL: "Email",
|
|
7254
|
+
TRAVELER_PHONE: "Phone",
|
|
7255
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
7256
|
+
PASSPORT_NUMBER: "Passport number",
|
|
7257
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
7258
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
7259
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
7260
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
7261
|
+
HAS_INSURANCE: "Has insurance",
|
|
7262
|
+
INSURANCE_NAME: "Insurance name",
|
|
7263
|
+
INFO: "Additional information",
|
|
6992
7264
|
WEIGHT: "体重",
|
|
6993
7265
|
WEIGHT_UNIT_KG: "kg",
|
|
6994
7266
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -15092,6 +15364,34 @@ var getContentDraft = function (config, signal) {
|
|
|
15092
15364
|
var apiKey = config.apiKey;
|
|
15093
15365
|
return get(url, apiKey, config.token, signal, true);
|
|
15094
15366
|
};
|
|
15367
|
+
/**
|
|
15368
|
+
* api/web/content/live/filtered
|
|
15369
|
+
* Gets filtered Live content
|
|
15370
|
+
* @param config
|
|
15371
|
+
* @param request
|
|
15372
|
+
* @param signal
|
|
15373
|
+
* @returns OK if succeeded.
|
|
15374
|
+
*/
|
|
15375
|
+
var getFilteredContentLive = function (config, request, signal) {
|
|
15376
|
+
var url = "" + config.host + ENDPOINT_LIVE + "/filtered";
|
|
15377
|
+
var apiKey = config.apiKey;
|
|
15378
|
+
var body = JSON.stringify(request);
|
|
15379
|
+
return post(url, apiKey, body, config.token, signal, true);
|
|
15380
|
+
};
|
|
15381
|
+
/**
|
|
15382
|
+
* api/web/content/draft/filtered
|
|
15383
|
+
* Gets filtered Draft (Internal) content
|
|
15384
|
+
* @param config
|
|
15385
|
+
* @param request
|
|
15386
|
+
* @param signal
|
|
15387
|
+
* @returns OK if succeeded.
|
|
15388
|
+
*/
|
|
15389
|
+
var getFilteredContentDraft = function (config, request, signal) {
|
|
15390
|
+
var url = "" + config.host + ENDPOINT_DRAFT + "/filtered";
|
|
15391
|
+
var apiKey = config.apiKey;
|
|
15392
|
+
var body = JSON.stringify(request);
|
|
15393
|
+
return post(url, apiKey, body, config.token, signal, true);
|
|
15394
|
+
};
|
|
15095
15395
|
/**
|
|
15096
15396
|
* api/web/content/live/by-property
|
|
15097
15397
|
* Gets Live content matching a property value (or values).
|
|
@@ -15219,6 +15519,7 @@ var ENDPOINT_TRAJECT = ENDPOINT$1 + "/traject";
|
|
|
15219
15519
|
var ENDPOINT_ENTRY = function (magicLinkCode) {
|
|
15220
15520
|
return ENDPOINT$1 + "/entry/" + magicLinkCode;
|
|
15221
15521
|
};
|
|
15522
|
+
var ENDPOINT_SAVE_ENTRY = ENDPOINT$1 + "/entry/save";
|
|
15222
15523
|
var startTransaction = function (config, signal) {
|
|
15223
15524
|
var apiKey = config.apiKey;
|
|
15224
15525
|
var url = "" + config.host + ENDPOINT_START_TRANSACTION;
|
|
@@ -15247,6 +15548,12 @@ var getEntry = function (config, magicLinkCode, signal) {
|
|
|
15247
15548
|
var url = "" + config.host + ENDPOINT_ENTRY(magicLinkCode);
|
|
15248
15549
|
return get(url, apiKey, config.token, signal, true);
|
|
15249
15550
|
};
|
|
15551
|
+
var savePackagingEntry = function (config, request, signal) {
|
|
15552
|
+
var url = "" + config.host + ENDPOINT_SAVE_ENTRY;
|
|
15553
|
+
var apiKey = config.apiKey;
|
|
15554
|
+
var body = JSON.stringify(request);
|
|
15555
|
+
return post(url, apiKey, body, config.token, signal, true);
|
|
15556
|
+
};
|
|
15250
15557
|
var getTrajectEntry = function (config, request, signal) {
|
|
15251
15558
|
var url = "" + config.host + ENDPOINT_TRAJECT;
|
|
15252
15559
|
var apiKey = config.apiKey;
|
|
@@ -15381,6 +15688,8 @@ exports.getEntryList = getEntryList;
|
|
|
15381
15688
|
exports.getEntryListv2 = getEntryListv2;
|
|
15382
15689
|
exports.getEntryStatus = getEntryStatus;
|
|
15383
15690
|
exports.getEntryTotals = getEntryTotals;
|
|
15691
|
+
exports.getFilteredContentDraft = getFilteredContentDraft;
|
|
15692
|
+
exports.getFilteredContentLive = getFilteredContentLive;
|
|
15384
15693
|
exports.getInvoiceList = getInvoiceList;
|
|
15385
15694
|
exports.getItinerary = getItinerary;
|
|
15386
15695
|
exports.getLocations = getLocations;
|
|
@@ -15401,6 +15710,7 @@ exports.print = print;
|
|
|
15401
15710
|
exports.readForm = readForm;
|
|
15402
15711
|
exports.repriceAndIssueTicket = repriceAndIssueTicket;
|
|
15403
15712
|
exports.resetPassword = resetPassword;
|
|
15713
|
+
exports.savePackagingEntry = savePackagingEntry;
|
|
15404
15714
|
exports.search = search;
|
|
15405
15715
|
exports.searchCountries = searchCountries;
|
|
15406
15716
|
exports.searchElastic = searchElastic;
|
|
@@ -18731,335 +19041,1163 @@ const SUMMARY_STEP = 5;
|
|
|
18731
19041
|
const CONFIRMATION_STEP = 6;
|
|
18732
19042
|
const ERROR_STEP = 7;
|
|
18733
19043
|
|
|
18734
|
-
const
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
};
|
|
18738
|
-
const priceDetailsApi = {
|
|
18739
|
-
fetchPriceDetails: fetchPriceDetails$1
|
|
19044
|
+
const LabeledInput = ({ name, type, required, value, defaultValue, min, max, label, placeholder, extraClassName, hasError, onChange, onBlur }) => {
|
|
19045
|
+
return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
|
|
19046
|
+
React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
|
|
19047
|
+
React__default.createElement("input", { name: name, type: type ?? 'text', required: required, className: "form__input", min: min, max: max, placeholder: placeholder, onChange: onChange, onBlur: onBlur, value: value, defaultValue: defaultValue })));
|
|
18740
19048
|
};
|
|
18741
19049
|
|
|
18742
|
-
const
|
|
18743
|
-
return {
|
|
18744
|
-
|
|
18745
|
-
|
|
18746
|
-
|
|
18747
|
-
...opt,
|
|
18748
|
-
rooms: opt.isSelected ? updateRooms(opt.rooms, changedLines) : opt.rooms,
|
|
18749
|
-
groups: opt.isSelected ? updateBookingGroups(opt.groups, changedLines) : opt.groups,
|
|
18750
|
-
optionUnits: opt.isSelected ? updateOptionUnits(opt.optionUnits, changedLines) : opt.optionUnits,
|
|
18751
|
-
optionPax: opt.isSelected ? updateOptionPax(opt.optionPax, changedLines) : opt.optionPax
|
|
18752
|
-
};
|
|
18753
|
-
})
|
|
18754
|
-
};
|
|
18755
|
-
};
|
|
18756
|
-
// ROOMS
|
|
18757
|
-
const updateRooms = (rooms, changedLines) => {
|
|
18758
|
-
return rooms.map((room) => ({
|
|
18759
|
-
...room,
|
|
18760
|
-
options: room.options.map((option) => ({
|
|
18761
|
-
...option,
|
|
18762
|
-
price: changedLines.find((x) => x.entryLineGuid == option.entryLineGuid)?.price ?? option.price
|
|
18763
|
-
}))
|
|
18764
|
-
}));
|
|
18765
|
-
};
|
|
18766
|
-
// PAX
|
|
18767
|
-
const updateOptionPax = (pax, changedLines) => {
|
|
18768
|
-
return pax.map((p) => ({
|
|
18769
|
-
...p,
|
|
18770
|
-
groups: updatePaxGroups(p.groups, changedLines)
|
|
18771
|
-
}));
|
|
18772
|
-
};
|
|
18773
|
-
const updatePaxGroups = (groups, changedLines) => {
|
|
18774
|
-
return groups.map((g) => ({
|
|
18775
|
-
...g,
|
|
18776
|
-
options: g.options.map((o) => ({
|
|
18777
|
-
...o,
|
|
18778
|
-
groups: updatePaxGroups(o.groups, changedLines),
|
|
18779
|
-
line: {
|
|
18780
|
-
...o.line,
|
|
18781
|
-
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
18782
|
-
},
|
|
18783
|
-
alternatives: o.alternatives.map((a) => ({
|
|
18784
|
-
...a,
|
|
18785
|
-
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
18786
|
-
}))
|
|
18787
|
-
}))
|
|
18788
|
-
}));
|
|
18789
|
-
};
|
|
18790
|
-
// UNITS
|
|
18791
|
-
const updateOptionUnits = (units, changedLines) => {
|
|
18792
|
-
return units.map((u) => ({
|
|
18793
|
-
...u,
|
|
18794
|
-
groups: updateUnitGroups(u.groups, changedLines)
|
|
18795
|
-
}));
|
|
18796
|
-
};
|
|
18797
|
-
const updateUnitGroups = (groups, changedLines) => {
|
|
18798
|
-
return groups.map((g) => ({
|
|
18799
|
-
...g,
|
|
18800
|
-
options: g.options.map((o) => ({
|
|
18801
|
-
...o,
|
|
18802
|
-
groups: updateUnitGroups(o.groups, changedLines),
|
|
18803
|
-
pax: updateOptionPax(o.pax, changedLines),
|
|
18804
|
-
line: {
|
|
18805
|
-
...o.line,
|
|
18806
|
-
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
18807
|
-
},
|
|
18808
|
-
alternatives: o.alternatives.map((a) => ({
|
|
18809
|
-
...a,
|
|
18810
|
-
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
18811
|
-
}))
|
|
18812
|
-
}))
|
|
18813
|
-
}));
|
|
18814
|
-
};
|
|
18815
|
-
// BOOKING
|
|
18816
|
-
const updateBookingGroups = (groups, changedLines) => {
|
|
18817
|
-
return groups.map((g) => ({
|
|
18818
|
-
...g,
|
|
18819
|
-
options: g.options.map((o) => ({
|
|
18820
|
-
...o,
|
|
18821
|
-
groups: updateBookingGroups(o.groups, changedLines),
|
|
18822
|
-
units: updateOptionUnits(o.units, changedLines),
|
|
18823
|
-
pax: updateOptionPax(o.pax, changedLines),
|
|
18824
|
-
line: {
|
|
18825
|
-
...o.line,
|
|
18826
|
-
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
18827
|
-
},
|
|
18828
|
-
alternatives: o.alternatives.map((a) => ({
|
|
18829
|
-
...a,
|
|
18830
|
-
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
18831
|
-
}))
|
|
18832
|
-
}))
|
|
18833
|
-
}));
|
|
19050
|
+
const LabeledSelect = ({ name, id, required, value, defaultValue, label, extraClassName, extraDropdownClassName, hasError, options, onChange, onBlur }) => {
|
|
19051
|
+
return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
|
|
19052
|
+
React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
|
|
19053
|
+
React__default.createElement("div", { className: buildClassName(['dropdown', extraDropdownClassName]) },
|
|
19054
|
+
React__default.createElement("select", { name: name, id: id, defaultValue: defaultValue, value: value, onBlur: onBlur, onChange: onChange }, options?.map((option) => (React__default.createElement("option", { key: option.key, value: option.value }, option.label)))))));
|
|
18834
19055
|
};
|
|
18835
19056
|
|
|
18836
|
-
const
|
|
18837
|
-
|
|
18838
|
-
const
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
|
|
18843
|
-
|
|
18844
|
-
|
|
18845
|
-
|
|
18846
|
-
|
|
18847
|
-
|
|
18848
|
-
|
|
18849
|
-
|
|
18850
|
-
dispatch(setPackage(updatedPackageDetails));
|
|
19057
|
+
const normalize = (v) => (v == null ? '' : String(v));
|
|
19058
|
+
const parseCombined = (raw, countries) => {
|
|
19059
|
+
const value = normalize(raw).trim();
|
|
19060
|
+
if (!value)
|
|
19061
|
+
return { prefix: '', number: '' };
|
|
19062
|
+
// Try to match a known prefix at the start. Prefer longest match.
|
|
19063
|
+
const sorted = [...countries].sort((a, b) => b.phonePrefix.length - a.phonePrefix.length);
|
|
19064
|
+
const hit = sorted.find((c) => value.startsWith(c.phonePrefix));
|
|
19065
|
+
if (hit) {
|
|
19066
|
+
const rest = value
|
|
19067
|
+
.slice(hit.phonePrefix.length)
|
|
19068
|
+
.trim()
|
|
19069
|
+
.replace(/^[-\s]+/, '');
|
|
19070
|
+
return { prefix: hit.phonePrefix, number: rest };
|
|
18851
19071
|
}
|
|
18852
|
-
|
|
18853
|
-
});
|
|
18854
|
-
|
|
18855
|
-
|
|
18856
|
-
|
|
18857
|
-
|
|
18858
|
-
|
|
18859
|
-
|
|
18860
|
-
|
|
18861
|
-
|
|
18862
|
-
|
|
18863
|
-
|
|
18864
|
-
|
|
18865
|
-
|
|
18866
|
-
|
|
18867
|
-
|
|
18868
|
-
|
|
18869
|
-
|
|
18870
|
-
|
|
18871
|
-
},
|
|
18872
|
-
|
|
18873
|
-
|
|
18874
|
-
|
|
18875
|
-
|
|
18876
|
-
|
|
18877
|
-
|
|
18878
|
-
|
|
18879
|
-
}
|
|
18880
|
-
});
|
|
18881
|
-
builder.addCase(fetchPriceDetails.rejected, (state) => {
|
|
18882
|
-
state.isBusy = false;
|
|
19072
|
+
// Fallback: split on first space if it looks like a +prefix number
|
|
19073
|
+
const m = value.match(/^(\+\d{1,4})[\s-]*(.*)$/);
|
|
19074
|
+
if (m)
|
|
19075
|
+
return { prefix: m[1], number: m[2] };
|
|
19076
|
+
return { prefix: '', number: value };
|
|
19077
|
+
};
|
|
19078
|
+
const PhoneInput = ({ name, required, value, label, placeholder, extraClassName, hasError, countries, countryIso2, onChange, onBlur }) => {
|
|
19079
|
+
// Derive initial state from `value`
|
|
19080
|
+
const initialCountry = countries.find((c) => c.iso2 === countryIso2);
|
|
19081
|
+
const initial = useMemo(() => parseCombined(normalize(value), countries), [value, countries]);
|
|
19082
|
+
const [prefix, setPrefix] = useState(initial.prefix);
|
|
19083
|
+
const [number, setNumber] = useState(initial.number);
|
|
19084
|
+
// Keep state in sync if the parent changes `value`
|
|
19085
|
+
useEffect(() => {
|
|
19086
|
+
const parsed = !prefix && !number && initialCountry ? { prefix: initialCountry.phonePrefix, number: '' } : parseCombined(normalize(value), countries);
|
|
19087
|
+
if (parsed.prefix)
|
|
19088
|
+
setPrefix(parsed.prefix);
|
|
19089
|
+
if (parsed.number)
|
|
19090
|
+
setNumber(parsed.number);
|
|
19091
|
+
}, [value, countries, countryIso2]);
|
|
19092
|
+
const emitCombinedChange = (e, nextPrefix, nextNumber) => {
|
|
19093
|
+
// Combine with a space, unless the number already starts with a dash or space
|
|
19094
|
+
const combined = nextPrefix && nextNumber ? compact([nextPrefix, nextNumber]).join(' ') : null;
|
|
19095
|
+
onChange?.({
|
|
19096
|
+
...e,
|
|
19097
|
+
type: 'change',
|
|
19098
|
+
target: { name, value: combined },
|
|
19099
|
+
currentTarget: { name, value: combined }
|
|
18883
19100
|
});
|
|
18884
|
-
}
|
|
18885
|
-
|
|
18886
|
-
|
|
18887
|
-
|
|
18888
|
-
const
|
|
18889
|
-
|
|
19101
|
+
};
|
|
19102
|
+
const handleCountryBlur = (e) => {
|
|
19103
|
+
onBlur?.(e);
|
|
19104
|
+
};
|
|
19105
|
+
const onCountryChange = (e) => {
|
|
19106
|
+
const next = e.target.value;
|
|
19107
|
+
setPrefix(next);
|
|
19108
|
+
emitCombinedChange(e, next, number);
|
|
19109
|
+
};
|
|
19110
|
+
const onPhoneChange = (e) => {
|
|
19111
|
+
const cleaned = e.target.value.replace(/[^\d\s-]/g, '');
|
|
19112
|
+
setNumber(cleaned);
|
|
19113
|
+
emitCombinedChange(e, prefix, cleaned);
|
|
19114
|
+
};
|
|
19115
|
+
const handleNumberBlur = (e) => {
|
|
19116
|
+
onBlur?.(e);
|
|
19117
|
+
};
|
|
19118
|
+
// Ensure the select shows a reasonable default when prefix is empty
|
|
19119
|
+
const selectValue = prefix || '';
|
|
19120
|
+
return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
|
|
19121
|
+
label && React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
|
|
19122
|
+
React__default.createElement("div", { className: "phone-input" },
|
|
19123
|
+
React__default.createElement("div", { className: "dropdown" },
|
|
19124
|
+
React__default.createElement("select", { "aria-label": label ? `${label} – country code` : 'Country calling code', name: `${name}__country`, value: selectValue, onBlur: handleCountryBlur, onChange: onCountryChange },
|
|
19125
|
+
React__default.createElement("option", { value: "", disabled: true }),
|
|
19126
|
+
countries?.map((option) => (React__default.createElement("option", { key: option.iso2, value: option.phonePrefix },
|
|
19127
|
+
option.name,
|
|
19128
|
+
" (",
|
|
19129
|
+
option.phonePrefix,
|
|
19130
|
+
")"))))),
|
|
19131
|
+
React__default.createElement("input", { "aria-label": label ? `${label} – number` : 'Phone number', name: `${name}__number`, type: "tel", inputMode: "tel", required: required, className: "form__input", placeholder: placeholder, onChange: onPhoneChange, onBlur: handleNumberBlur, value: number }),
|
|
19132
|
+
React__default.createElement("input", { type: "hidden", name: name, value: compact([prefix, number]).join(' ') }))));
|
|
19133
|
+
};
|
|
18890
19134
|
|
|
18891
|
-
const
|
|
18892
|
-
|
|
18893
|
-
const
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
|
|
18897
|
-
|
|
18898
|
-
|
|
18899
|
-
|
|
18900
|
-
|
|
18901
|
-
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
|
|
18907
|
-
const selectPackageFlights = (state) => ({
|
|
18908
|
-
outward: state.booking.package?.outwardFlights,
|
|
18909
|
-
return: state.booking.package?.returnFlights
|
|
18910
|
-
});
|
|
18911
|
-
const selectFlightMetaData = (state) => state.booking.package?.flightInfo.metaData;
|
|
18912
|
-
const selectActiveOption = (state) => state.booking.package?.options.find((x) => x.isSelected);
|
|
18913
|
-
const selectPackageAirlineGroups = createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airlineGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
|
|
18914
|
-
const selectPackageAirportGroups = createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airportGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
|
|
18915
|
-
const selectRoomOptionDepartureFlightsMetaData = createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
|
|
18916
|
-
const roomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected).shift());
|
|
18917
|
-
return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
|
|
18918
|
-
});
|
|
18919
|
-
const selectRoomOptionReturnFlightsMetaData = createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
|
|
18920
|
-
const selectedRoomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected));
|
|
18921
|
-
// check if there are return flights selected
|
|
18922
|
-
if (selectedRoomOptions?.some((ro) => ro.length > 1)) {
|
|
18923
|
-
const roomOptions = ativeOption?.rooms.map((r) => r.options
|
|
18924
|
-
.filter((o) => o.isSelected)
|
|
18925
|
-
.reverse()
|
|
18926
|
-
.shift());
|
|
18927
|
-
return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
|
|
18928
|
-
}
|
|
18929
|
-
return undefined;
|
|
18930
|
-
});
|
|
18931
|
-
const selectApiSettings = (state) => state.apiSettings;
|
|
18932
|
-
const selectIsUnavailable = (state) => state.booking.isUnavailable;
|
|
18933
|
-
const selectRequestRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.requestRooms;
|
|
18934
|
-
const selectOfficeId = (state) => state.booking.officeId;
|
|
18935
|
-
const selectLanguageCode = (state) => state.booking.languageCode;
|
|
18936
|
-
const selectCurrencyCode = (state) => state.booking.package?.currencyCode ?? 'EUR';
|
|
18937
|
-
const selectLanguage = (state) => state.booking.languageCode;
|
|
18938
|
-
const selectAllDynamicTranslations = (state) => state.booking.translations;
|
|
18939
|
-
const selectDynamicTranslations = createSelector([selectAllDynamicTranslations, selectLanguage], (allDynamicTranslations, language) => {
|
|
18940
|
-
return allDynamicTranslations?.find((x) => x.language == language)?.value ?? {};
|
|
18941
|
-
});
|
|
18942
|
-
// Host override files are hand-maintained, and a null only ever blanks a key the component
|
|
18943
|
-
// then reads, so treat it like a missing key (lodash merge already skips undefined).
|
|
18944
|
-
const withoutNulls = (value) => isPlainObject$1(value)
|
|
18945
|
-
? mapValues(pickBy(value, (x) => x !== null), withoutNulls)
|
|
18946
|
-
: value;
|
|
18947
|
-
// getTranslations deep-merges the overrides over a clone of the built-in translations, so a
|
|
18948
|
-
// host override of a nested group (TRAVELERS_FORM.VALIDATION, TRAVELERS_FORM.COUNTRIES)
|
|
18949
|
-
// only replaces the keys it actually contains. Merging per section one level deep dropped
|
|
18950
|
-
// every other built-in key of such a group, which made those keys resolve to undefined and
|
|
18951
|
-
// crash format() in the consuming component.
|
|
18952
|
-
const selectTranslations = createSelector([selectLanguage, selectDynamicTranslations], (language, dynamicTranslations) => getTranslations(language, isEmpty$1(dynamicTranslations) ? undefined : withoutNulls(dynamicTranslations)));
|
|
18953
|
-
const selectBookingOptions = (state) => state.booking.bookingOptions;
|
|
18954
|
-
const selectBookingType = (state) => state.booking.bookingType;
|
|
18955
|
-
const selectTagIds = (state) => state.booking.tagIds;
|
|
18956
|
-
const selectAgentAdressId = (state) => state.booking.agentAdressId;
|
|
18957
|
-
const selectProductAttributes = (state) => state.booking.productAttributes;
|
|
18958
|
-
const selectBookingAttributes = (state) => state.booking.bookingAttributes;
|
|
18959
|
-
const selectBookingNumber = (state) => state.booking.bookingNumber;
|
|
18960
|
-
const selectIsOption = (state) => state.booking.isOption;
|
|
18961
|
-
const selectBookingRooms = (state) => state.booking.bookingAttributes?.rooms;
|
|
18962
|
-
const selectBookingRemarks = (state) => state.booking.remarks;
|
|
18963
|
-
const selectVoucherCodes = (state) => state.booking.voucherCodes;
|
|
18964
|
-
const selectCalculateDeposit = (state) => state.booking.calculateDeposit;
|
|
18965
|
-
const selectShowCommission = (state) => state.booking.showCommission;
|
|
18966
|
-
const selectIsRetry = (state) => state.booking.isRetry;
|
|
18967
|
-
const selectStartDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.fromDate;
|
|
18968
|
-
const selectEndDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.toDate;
|
|
18969
|
-
const selectAgents = (state) => state.booking.agents;
|
|
18970
|
-
const selectCountries = (state) => state.booking.countries;
|
|
18971
|
-
const selectProductCode = (state) => state.booking.productAttributes?.productCode;
|
|
18972
|
-
const selectAccommodationCodes = (state) => {
|
|
18973
|
-
const accommodationCodes = [];
|
|
18974
|
-
state.booking.package?.options.forEach((o) => {
|
|
18975
|
-
o.rooms.forEach((r) => r.options.forEach((ro) => {
|
|
18976
|
-
if (!accommodationCodes.some((y) => y === ro.accommodationCode)) {
|
|
18977
|
-
accommodationCodes.push(ro.accommodationCode);
|
|
18978
|
-
}
|
|
18979
|
-
}));
|
|
18980
|
-
});
|
|
18981
|
-
return accommodationCodes;
|
|
19135
|
+
const hasVisibleError = (formik, key) => get(formik.errors, key) && get(formik.touched, key);
|
|
19136
|
+
|
|
19137
|
+
const GenderControl = ({ translations, value, formik, name }) => {
|
|
19138
|
+
return (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(formik, name) && 'form__group--error']) },
|
|
19139
|
+
React__default.createElement("label", { className: "form__label" },
|
|
19140
|
+
translations.TRAVELERS_FORM.GENDER_ID,
|
|
19141
|
+
" *"),
|
|
19142
|
+
React__default.createElement("div", { className: "radiobutton-group" },
|
|
19143
|
+
React__default.createElement("div", { className: "radiobutton" },
|
|
19144
|
+
React__default.createElement("label", { className: "radiobutton__label" },
|
|
19145
|
+
React__default.createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: "m", checked: value.gender === 'm' }),
|
|
19146
|
+
translations.TRAVELERS_FORM.MALE_GENDER)),
|
|
19147
|
+
React__default.createElement("div", { className: "radiobutton" },
|
|
19148
|
+
React__default.createElement("label", { className: "radiobutton__label" },
|
|
19149
|
+
React__default.createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: "f", checked: value.gender === 'f' }),
|
|
19150
|
+
translations.TRAVELERS_FORM.FEMALE_GENDER)))));
|
|
18982
19151
|
};
|
|
18983
|
-
|
|
18984
|
-
const
|
|
18985
|
-
const
|
|
18986
|
-
const
|
|
18987
|
-
|
|
18988
|
-
|
|
18989
|
-
}
|
|
18990
|
-
const params = {};
|
|
18991
|
-
Object.entries(bookingAttributes).forEach(([key, value]) => {
|
|
18992
|
-
if (key === 'startDate' || key === 'endDate') {
|
|
18993
|
-
value = format$2(parseISO(value), 'yyyy-MM-dd');
|
|
18994
|
-
}
|
|
18995
|
-
if (key === 'rooms') {
|
|
18996
|
-
value = JsonURL.stringify(value.map((room) => omit(room, ['children'])), {
|
|
18997
|
-
AQF: true
|
|
18998
|
-
});
|
|
18999
|
-
}
|
|
19000
|
-
if (key === 'allotmentIds' && !value.length) {
|
|
19001
|
-
value = undefined;
|
|
19002
|
-
}
|
|
19003
|
-
if (key === 'flight' && value) {
|
|
19004
|
-
var flightInfo = value;
|
|
19005
|
-
value = JsonURL.stringify(flightInfo, { AQF: true });
|
|
19152
|
+
|
|
19153
|
+
const TypeAheadInput = ({ name, value, placeholder, options, onChange, onSelect, onClear }) => {
|
|
19154
|
+
const [showItems, setShowItems] = useState(false);
|
|
19155
|
+
const handleChange = (e) => {
|
|
19156
|
+
if (onChange) {
|
|
19157
|
+
onChange(e.target.value);
|
|
19006
19158
|
}
|
|
19007
|
-
|
|
19008
|
-
|
|
19159
|
+
};
|
|
19160
|
+
const handleClearClick = (e) => {
|
|
19161
|
+
if (onClear) {
|
|
19162
|
+
onClear();
|
|
19009
19163
|
}
|
|
19010
|
-
|
|
19011
|
-
|
|
19164
|
+
setShowItems(false);
|
|
19165
|
+
};
|
|
19166
|
+
return (React__default.createElement("div", { className: "typeahead" },
|
|
19167
|
+
React__default.createElement("div", { className: "typeahead__trigger typeahead__trigger--icon" },
|
|
19168
|
+
React__default.createElement(Icon, { name: "ui-qsm-location" }),
|
|
19169
|
+
React__default.createElement("input", { type: "text", className: "form__input", name: name, value: value, onChange: handleChange, placeholder: placeholder, required: true, autoComplete: "off", onKeyDown: (e) => {
|
|
19170
|
+
if (e.key === 'Tab' && options && onSelect) {
|
|
19171
|
+
onSelect(options[0].key);
|
|
19172
|
+
setShowItems(false);
|
|
19173
|
+
}
|
|
19174
|
+
}, onFocus: () => setShowItems(true) }),
|
|
19175
|
+
React__default.createElement("button", { type: "button", className: "button button--clear", onClick: handleClearClick })),
|
|
19176
|
+
options && options.length > 0 && showItems && (React__default.createElement("div", { className: "typeahead__options" }, (options ?? []).map((option) => {
|
|
19177
|
+
const matchIndex = typeof value !== 'undefined' ? option.text.indexOf(value) : 0;
|
|
19178
|
+
const prefix = option.text.slice(0, matchIndex);
|
|
19179
|
+
const highlight = option.text.slice(matchIndex, value?.length ?? 0);
|
|
19180
|
+
const suffix = option.text.slice(matchIndex);
|
|
19181
|
+
return (React__default.createElement("div", { className: "typeahead__option", key: option.key },
|
|
19182
|
+
React__default.createElement("div", { className: "typeahead__option-header" },
|
|
19183
|
+
React__default.createElement("button", { onClick: () => {
|
|
19184
|
+
if (onSelect)
|
|
19185
|
+
onSelect(option.key);
|
|
19186
|
+
setShowItems(false);
|
|
19187
|
+
}, type: "button", className: "button button--plain" },
|
|
19188
|
+
prefix,
|
|
19189
|
+
React__default.createElement("span", { className: "typeahead__option-highlight" }, highlight),
|
|
19190
|
+
suffix))));
|
|
19191
|
+
})))));
|
|
19012
19192
|
};
|
|
19013
|
-
|
|
19014
|
-
|
|
19015
|
-
|
|
19016
|
-
|
|
19017
|
-
|
|
19018
|
-
|
|
19019
|
-
|
|
19020
|
-
|
|
19021
|
-
|
|
19022
|
-
|
|
19023
|
-
|
|
19024
|
-
|
|
19025
|
-
|
|
19026
|
-
|
|
19027
|
-
|
|
19028
|
-
|
|
19029
|
-
|
|
19193
|
+
|
|
19194
|
+
// A traveler is a baby when the age they were booked with is at or below the baby
|
|
19195
|
+
// boundary. Babies get their own label and birth date validation (TIDE-3269). Only
|
|
19196
|
+
// meaningful for the regular form: the compact form asks for an age instead of a birth
|
|
19197
|
+
// date, so it has nothing to validate and its own age input already states the age.
|
|
19198
|
+
function isBabyAge(age, maxBabyAge = BABY_MAX_AGE) {
|
|
19199
|
+
return typeof age === 'number' && age <= maxBabyAge;
|
|
19200
|
+
}
|
|
19201
|
+
// The native date input can hold values format() throws on (e.g. a 5+ digit year while typing), so never format an unvalidated birthDate
|
|
19202
|
+
function formatBirthDate$1(birthDate) {
|
|
19203
|
+
if (!birthDate)
|
|
19204
|
+
return '';
|
|
19205
|
+
const parsed = parse(birthDate, 'yyyy-MM-dd', new Date());
|
|
19206
|
+
return isValid(parsed) ? format$2(parsed, 'dd-MM-yyyy') : '';
|
|
19207
|
+
}
|
|
19208
|
+
// A field can have separate "main-booker"/other-pax variants sharing the same identity
|
|
19209
|
+
// (customFieldConfigurationId for custom fields, fieldName for built-in fields).
|
|
19210
|
+
const MAIN_BOOKER_GROUP = 'main-booker';
|
|
19211
|
+
const isCustomPaxField = (field) => field.customFieldConfigurationId != null;
|
|
19212
|
+
function resolveApplicablePaxFields(fields, isMainBooker) {
|
|
19213
|
+
const variantsByKey = new Map();
|
|
19214
|
+
fields.forEach((field) => {
|
|
19215
|
+
const key = field.customFieldConfigurationId ?? field.fieldName;
|
|
19216
|
+
const variants = variantsByKey.get(key) ?? [];
|
|
19217
|
+
variants.push(field);
|
|
19218
|
+
variantsByKey.set(key, variants);
|
|
19219
|
+
});
|
|
19220
|
+
const applicableFields = [];
|
|
19221
|
+
variantsByKey.forEach((variants) => {
|
|
19222
|
+
const hasRoleSplit = variants.some((v) => v.group === MAIN_BOOKER_GROUP);
|
|
19223
|
+
if (!hasRoleSplit) {
|
|
19224
|
+
applicableFields.push(variants[0]);
|
|
19225
|
+
return;
|
|
19030
19226
|
}
|
|
19031
|
-
|
|
19032
|
-
|
|
19033
|
-
|
|
19034
|
-
|
|
19035
|
-
|
|
19036
|
-
|
|
19037
|
-
|
|
19038
|
-
const
|
|
19039
|
-
|
|
19040
|
-
|
|
19041
|
-
|
|
19227
|
+
const roleMatch = variants.find((v) => (v.group === MAIN_BOOKER_GROUP) === isMainBooker);
|
|
19228
|
+
if (roleMatch)
|
|
19229
|
+
applicableFields.push(roleMatch);
|
|
19230
|
+
});
|
|
19231
|
+
return applicableFields;
|
|
19232
|
+
}
|
|
19233
|
+
function buildEmptyCustomFields(paxFields = []) {
|
|
19234
|
+
const uniqueIds = Array.from(new Set(paxFields.filter(isCustomPaxField).map((field) => field.customFieldConfigurationId)));
|
|
19235
|
+
return uniqueIds.map((customFieldConfigurationId) => ({ customFieldConfigurationId, value: '' }));
|
|
19236
|
+
}
|
|
19237
|
+
function getApplicablePaxCustomFields(paxFields = [], isMainBooker) {
|
|
19238
|
+
return resolveApplicablePaxFields(paxFields.filter(isCustomPaxField), isMainBooker);
|
|
19239
|
+
}
|
|
19240
|
+
function getApplicableBuiltInPaxFields(paxFields = [], isMainBooker) {
|
|
19241
|
+
return resolveApplicablePaxFields(paxFields.filter((f) => !isCustomPaxField(f)), isMainBooker);
|
|
19242
|
+
}
|
|
19243
|
+
function getBuiltInPaxField(paxFields = [], fieldName, isMainBooker) {
|
|
19244
|
+
return getApplicableBuiltInPaxFields(paxFields, isMainBooker).find((f) => f.fieldName === fieldName);
|
|
19245
|
+
}
|
|
19246
|
+
// fieldName -> path on `Traveler`, shared with validate-form.ts.
|
|
19247
|
+
const BUILT_IN_FIELD_PATHS = {
|
|
19248
|
+
gender: 'gender',
|
|
19249
|
+
firstName: 'firstName',
|
|
19250
|
+
lastName: 'lastName',
|
|
19251
|
+
dateOfBirth: 'birthDate',
|
|
19252
|
+
nickname: 'nickname',
|
|
19253
|
+
birthplace: 'birthplace',
|
|
19254
|
+
nationality: 'nationality',
|
|
19255
|
+
preferredLanguageId: 'preferredLanguageId',
|
|
19256
|
+
email: 'email',
|
|
19257
|
+
phone: 'phone',
|
|
19258
|
+
mobile: 'mobile',
|
|
19259
|
+
passportIssueDate: 'passportIssueDate',
|
|
19260
|
+
passportIssuedLocation: 'passportIssuedLocation',
|
|
19261
|
+
passportExpiryDate: 'passportExpiryDate',
|
|
19262
|
+
passportNumber: 'passportNumber',
|
|
19263
|
+
emergencyNumber: 'emergencyNumber',
|
|
19264
|
+
hasInsurance: 'hasInsurance',
|
|
19265
|
+
insuranceName: 'insuranceName',
|
|
19266
|
+
info: 'info',
|
|
19267
|
+
street: 'address.street',
|
|
19268
|
+
location: 'address.location',
|
|
19269
|
+
countryId: 'address.country',
|
|
19270
|
+
postalCode: 'address.postalCode',
|
|
19271
|
+
number: 'address.number'
|
|
19272
|
+
};
|
|
19273
|
+
// The 4 fields that always render/validate regardless of paxFields config (fallback behavior).
|
|
19274
|
+
const CORE_FIELD_NAMES = new Set(['gender', 'firstName', 'lastName', 'dateOfBirth']);
|
|
19275
|
+
const ADDRESS_FIELD_NAMES = ['street', 'location', 'countryId', 'postalCode', 'number'];
|
|
19276
|
+
// Shared by buildPax (new-booking) and applyTravelersFormValuesToEditablePackagingEntry
|
|
19277
|
+
// (edit-booking), now that PackagingEntryPax and BookingPackagePax have the same shape.
|
|
19278
|
+
function applyTravelerToPax(pax, traveler, mainBookerId) {
|
|
19042
19279
|
return {
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19280
|
+
...pax,
|
|
19281
|
+
firstName: traveler.firstName ?? '',
|
|
19282
|
+
lastName: traveler.lastName ?? '',
|
|
19283
|
+
dateOfBirth: traveler.birthDate || null,
|
|
19284
|
+
isMainBooker: mainBookerId != null ? traveler.id === mainBookerId : pax.isMainBooker,
|
|
19285
|
+
weight: traveler.weight ?? null,
|
|
19286
|
+
weightType: traveler.weightType ?? build.WeightType.kilograms,
|
|
19287
|
+
height: traveler.height ?? null,
|
|
19288
|
+
heightType: traveler.heightType ?? build.HeightType.centimeters,
|
|
19289
|
+
nickname: traveler.nickname,
|
|
19290
|
+
birthplace: traveler.birthplace,
|
|
19291
|
+
nationality: traveler.nationality,
|
|
19292
|
+
preferredLanguageId: traveler.preferredLanguageId,
|
|
19293
|
+
email: traveler.email,
|
|
19294
|
+
phone: traveler.phone,
|
|
19295
|
+
mobilePhone: traveler.mobile,
|
|
19296
|
+
emergencyNumber: traveler.emergencyNumber,
|
|
19297
|
+
passportNumber: traveler.passportNumber,
|
|
19298
|
+
passportIssueDate: traveler.passportIssueDate,
|
|
19299
|
+
passportIssuedLocation: traveler.passportIssuedLocation,
|
|
19300
|
+
passportExpiryDate: traveler.passportExpiryDate,
|
|
19301
|
+
hasInsurance: traveler.hasInsurance,
|
|
19302
|
+
insuranceName: traveler.insuranceName,
|
|
19303
|
+
info: traveler.info,
|
|
19304
|
+
address: buildTravelerAddress(traveler),
|
|
19305
|
+
customFields: traveler.customFields ?? []
|
|
19052
19306
|
};
|
|
19053
|
-
}
|
|
19054
|
-
|
|
19055
|
-
|
|
19307
|
+
}
|
|
19308
|
+
// name/email are required on the wire but aren't part of the per-traveler address sub-form -
|
|
19309
|
+
// derive them from the traveler's own name/email instead of asking twice.
|
|
19310
|
+
function buildTravelerAddress(traveler) {
|
|
19311
|
+
if (!traveler.address || !Object.values(traveler.address).some((v) => !!v))
|
|
19312
|
+
return undefined;
|
|
19056
19313
|
return {
|
|
19057
|
-
|
|
19058
|
-
|
|
19059
|
-
|
|
19314
|
+
name: `${traveler.firstName} ${traveler.lastName}`.trim(),
|
|
19315
|
+
street: traveler.address.street ?? '',
|
|
19316
|
+
number: traveler.address.number ?? '',
|
|
19317
|
+
postalCode: traveler.address.postalCode ?? '',
|
|
19318
|
+
location: traveler.address.location ?? '',
|
|
19319
|
+
country: traveler.address.country ?? '',
|
|
19320
|
+
email: traveler.email ?? ''
|
|
19060
19321
|
};
|
|
19061
|
-
}
|
|
19062
|
-
|
|
19322
|
+
}
|
|
19323
|
+
// Always initialized (even when not shown) to keep Formik inputs controlled, matching weight/height.
|
|
19324
|
+
const EMPTY_BUILT_IN_FIELDS = {
|
|
19325
|
+
nickname: '',
|
|
19326
|
+
birthplace: '',
|
|
19327
|
+
nationality: '',
|
|
19328
|
+
preferredLanguageId: undefined,
|
|
19329
|
+
email: '',
|
|
19330
|
+
phone: '',
|
|
19331
|
+
mobile: '',
|
|
19332
|
+
passportNumber: '',
|
|
19333
|
+
passportIssueDate: '',
|
|
19334
|
+
passportIssuedLocation: '',
|
|
19335
|
+
passportExpiryDate: '',
|
|
19336
|
+
emergencyNumber: '',
|
|
19337
|
+
hasInsurance: false,
|
|
19338
|
+
insuranceName: '',
|
|
19339
|
+
info: '',
|
|
19340
|
+
address: { street: '', number: '', postalCode: '', location: '', country: '' }
|
|
19341
|
+
};
|
|
19342
|
+
function createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields) {
|
|
19343
|
+
if (isCompact) {
|
|
19344
|
+
return {
|
|
19345
|
+
id: traveler.id,
|
|
19346
|
+
firstName: personTranslation,
|
|
19347
|
+
lastName: `${followNumber.number++}`,
|
|
19348
|
+
birthDate: '',
|
|
19349
|
+
gender: '',
|
|
19350
|
+
// Keep a booked age of 0 instead of submitting and pricing the traveler as a 30 year
|
|
19351
|
+
// old, while still falling back for a missing or unusable age. `??` alone would let a
|
|
19352
|
+
// NaN (unparseable date of birth upstream) reach the age input and the booked pax.
|
|
19353
|
+
// See TIDE-3269.
|
|
19354
|
+
age: Number.isFinite(traveler.age) ? traveler.age : 30,
|
|
19355
|
+
// No isBaby here on purpose: the age below is editable and nothing revalidates it
|
|
19356
|
+
// in compact mode, so a stored flag would end up contradicting the entered age.
|
|
19357
|
+
weight: null,
|
|
19358
|
+
weightType: build.WeightType.kilograms,
|
|
19359
|
+
height: null,
|
|
19360
|
+
heightType: build.HeightType.centimeters,
|
|
19361
|
+
...EMPTY_BUILT_IN_FIELDS,
|
|
19362
|
+
customFields: buildEmptyCustomFields(paxFields)
|
|
19363
|
+
};
|
|
19364
|
+
}
|
|
19365
|
+
return {
|
|
19366
|
+
id: traveler.id,
|
|
19367
|
+
firstName: '',
|
|
19368
|
+
lastName: '',
|
|
19369
|
+
birthDate: '',
|
|
19370
|
+
gender: '',
|
|
19371
|
+
isBaby: isBabyAge(traveler.age, maxBabyAge),
|
|
19372
|
+
weight: null,
|
|
19373
|
+
weightType: build.WeightType.kilograms,
|
|
19374
|
+
height: null,
|
|
19375
|
+
heightType: build.HeightType.centimeters,
|
|
19376
|
+
...EMPTY_BUILT_IN_FIELDS,
|
|
19377
|
+
customFields: buildEmptyCustomFields(paxFields)
|
|
19378
|
+
};
|
|
19379
|
+
}
|
|
19380
|
+
function createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, personTranslation, isCompact, maxBabyAge, paxFields) {
|
|
19381
|
+
const followNumber = { number: 1 };
|
|
19382
|
+
const initialValues = {
|
|
19383
|
+
startDate,
|
|
19384
|
+
endDate,
|
|
19385
|
+
rooms: formRooms.map((room) => ({
|
|
19386
|
+
adults: room.adults.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields)),
|
|
19387
|
+
children: room.children.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields))
|
|
19388
|
+
})),
|
|
19389
|
+
mainBookerId: -1,
|
|
19390
|
+
street: '',
|
|
19391
|
+
houseNumber: '',
|
|
19392
|
+
box: '',
|
|
19393
|
+
zipCode: '',
|
|
19394
|
+
place: '',
|
|
19395
|
+
country: '',
|
|
19396
|
+
phone: '',
|
|
19397
|
+
email: '',
|
|
19398
|
+
emailConfirmation: '',
|
|
19399
|
+
travelAgentId: agentAdressId ?? 0,
|
|
19400
|
+
travelAgentName: ''
|
|
19401
|
+
};
|
|
19402
|
+
if (initialValues.rooms?.[0]?.adults?.[0]) {
|
|
19403
|
+
initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
|
|
19404
|
+
}
|
|
19405
|
+
return initialValues;
|
|
19406
|
+
}
|
|
19407
|
+
function mapPackagingEntryPaxToTraveler(roomTraveler) {
|
|
19408
|
+
return {
|
|
19409
|
+
weight: roomTraveler.weight ?? null,
|
|
19410
|
+
weightType: roomTraveler.weightType ?? build.WeightType.kilograms,
|
|
19411
|
+
height: roomTraveler.height ?? null,
|
|
19412
|
+
heightType: roomTraveler.heightType ?? build.HeightType.centimeters,
|
|
19413
|
+
nickname: roomTraveler.nickname ?? '',
|
|
19414
|
+
birthplace: roomTraveler.birthplace ?? '',
|
|
19415
|
+
nationality: roomTraveler.nationality ?? '',
|
|
19416
|
+
preferredLanguageId: roomTraveler.preferredLanguageId,
|
|
19417
|
+
email: roomTraveler.email ?? '',
|
|
19418
|
+
phone: roomTraveler.phone ?? '',
|
|
19419
|
+
mobile: roomTraveler.mobilePhone ?? '',
|
|
19420
|
+
passportNumber: roomTraveler.passportNumber ?? '',
|
|
19421
|
+
passportIssueDate: roomTraveler.passportIssueDate ?? '',
|
|
19422
|
+
passportIssuedLocation: roomTraveler.passportIssuedLocation ?? '',
|
|
19423
|
+
passportExpiryDate: roomTraveler.passportExpiryDate ?? '',
|
|
19424
|
+
emergencyNumber: roomTraveler.emergencyNumber ?? '',
|
|
19425
|
+
hasInsurance: roomTraveler.hasInsurance ?? false,
|
|
19426
|
+
insuranceName: roomTraveler.insuranceName ?? '',
|
|
19427
|
+
info: roomTraveler.info ?? '',
|
|
19428
|
+
address: roomTraveler.address
|
|
19429
|
+
? {
|
|
19430
|
+
street: roomTraveler.address.street ?? '',
|
|
19431
|
+
number: roomTraveler.address.number ?? '',
|
|
19432
|
+
postalCode: roomTraveler.address.postalCode ?? '',
|
|
19433
|
+
location: roomTraveler.address.location ?? '',
|
|
19434
|
+
country: roomTraveler.address.country ?? ''
|
|
19435
|
+
}
|
|
19436
|
+
: undefined,
|
|
19437
|
+
customFields: roomTraveler.customFields ?? []
|
|
19438
|
+
};
|
|
19439
|
+
}
|
|
19440
|
+
function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId) {
|
|
19441
|
+
const pax = editablePackagingEntry?.pax ?? [];
|
|
19442
|
+
const rooms = editablePackagingEntry.rooms.map((room) => {
|
|
19443
|
+
const roomPax = pax.filter((x) => room.paxIds.includes(x.id));
|
|
19444
|
+
const adults = roomPax.filter((x) => x.age >= 18);
|
|
19445
|
+
const children = roomPax.filter((x) => x.age < 18);
|
|
19446
|
+
return {
|
|
19447
|
+
adults: adults.map((roomTraveler) => {
|
|
19448
|
+
return {
|
|
19449
|
+
id: roomTraveler.id,
|
|
19450
|
+
firstName: roomTraveler.firstName ?? '',
|
|
19451
|
+
lastName: roomTraveler.lastName ?? '',
|
|
19452
|
+
birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
|
|
19453
|
+
gender: '',
|
|
19454
|
+
...mapPackagingEntryPaxToTraveler(roomTraveler)
|
|
19455
|
+
};
|
|
19456
|
+
}),
|
|
19457
|
+
children: children.map((roomTraveler) => {
|
|
19458
|
+
return {
|
|
19459
|
+
id: roomTraveler.id,
|
|
19460
|
+
firstName: roomTraveler.firstName ?? '',
|
|
19461
|
+
lastName: roomTraveler.lastName ?? '',
|
|
19462
|
+
birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
|
|
19463
|
+
gender: '',
|
|
19464
|
+
isBaby: isBabyAge(roomTraveler.age),
|
|
19465
|
+
...mapPackagingEntryPaxToTraveler(roomTraveler)
|
|
19466
|
+
};
|
|
19467
|
+
})
|
|
19468
|
+
};
|
|
19469
|
+
});
|
|
19470
|
+
const values = createInitialValuesFromRooms(rooms.map((room) => ({ adults: room.adults, children: room.children })), first(editablePackagingEntry?.lines)?.from, last(editablePackagingEntry?.lines)?.to, agentAdressId);
|
|
19471
|
+
values.rooms = rooms;
|
|
19472
|
+
values.mainBookerId = pax.find((x) => x.isMainBooker)?.id ?? rooms[0]?.adults?.[0]?.id ?? -1;
|
|
19473
|
+
const address = editablePackagingEntry?.address;
|
|
19474
|
+
values.street = address?.street ?? '';
|
|
19475
|
+
values.houseNumber = address?.houseNumber ?? '';
|
|
19476
|
+
values.box = address?.box ?? '';
|
|
19477
|
+
values.zipCode = address?.zipCode ?? '';
|
|
19478
|
+
values.place = address?.place ?? '';
|
|
19479
|
+
values.country = address?.country ?? '';
|
|
19480
|
+
values.phone = address?.phone ?? '';
|
|
19481
|
+
values.email = address?.email ?? '';
|
|
19482
|
+
values.emailConfirmation = address?.email ?? '';
|
|
19483
|
+
values.travelAgentId = address?.travelAgentId ?? agentAdressId ?? 0;
|
|
19484
|
+
return values;
|
|
19485
|
+
}
|
|
19486
|
+
function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry, values) {
|
|
19487
|
+
const travelers = values.rooms.flatMap((room) => [...room.adults, ...room.children]);
|
|
19488
|
+
// The backend treats the main booker's per-pax address as authoritative, so keep the
|
|
19489
|
+
// booking-level address in sync with it rather than sending two independent values.
|
|
19490
|
+
const mainBookerAddress = travelers.find((x) => x.id === values.mainBookerId)?.address;
|
|
19491
|
+
return {
|
|
19492
|
+
...editablePackagingEntry,
|
|
19493
|
+
pax: (editablePackagingEntry.pax ?? []).map((pax) => {
|
|
19494
|
+
const traveler = travelers.find((x) => x.id === pax.id);
|
|
19495
|
+
return traveler ? applyTravelerToPax(pax, traveler, values.mainBookerId) : pax;
|
|
19496
|
+
}),
|
|
19497
|
+
address: {
|
|
19498
|
+
...editablePackagingEntry.address,
|
|
19499
|
+
street: mainBookerAddress?.street || values.street,
|
|
19500
|
+
houseNumber: mainBookerAddress?.number || values.houseNumber,
|
|
19501
|
+
box: values.box,
|
|
19502
|
+
zipCode: mainBookerAddress?.postalCode || values.zipCode,
|
|
19503
|
+
place: mainBookerAddress?.location || values.place,
|
|
19504
|
+
country: mainBookerAddress?.country || values.country,
|
|
19505
|
+
travelAgentId: values.travelAgentId,
|
|
19506
|
+
phone: values.phone,
|
|
19507
|
+
email: values.email
|
|
19508
|
+
}
|
|
19509
|
+
};
|
|
19510
|
+
}
|
|
19511
|
+
const SharedTravelersForm = ({ formik, translations, travellersSettings, countries, agents, bookingType, agentAdressId, travelersFirstStep = false, isUnavailable = false, useCompactForm = false, showAllCountries = false, paxFields, showAgentSelection = false, initialShowAgents = false, renderPreviousButton, onBookingTypeChange }) => {
|
|
19512
|
+
const [showAgents, setShowAgents] = useState(initialShowAgents);
|
|
19513
|
+
const typeaheadAgents = useMemo(() => sortBy(agents?.map((agent) => ({
|
|
19514
|
+
key: `${agent.id}`,
|
|
19515
|
+
value: `${agent.name}${agent.postalCode || agent.location ? ` (${compact([agent.postalCode, agent.location]).join(' ')})` : ''}`,
|
|
19516
|
+
text: `${agent.name}${agent.postalCode || agent.location ? ` (${compact([agent.postalCode, agent.location]).join(' ')})` : ''}`
|
|
19517
|
+
})), 'value') ?? [], [agents]);
|
|
19518
|
+
const [filteredAgents, setFilteredAgents] = useState(typeaheadAgents);
|
|
19519
|
+
const flatErrors = flat(formik.errors);
|
|
19520
|
+
const errorKeys = Object.keys(flatErrors).filter((key) => get(formik.touched, key));
|
|
19521
|
+
const hasVisibleError = (key) => get(formik.errors, key) && get(formik.touched, key);
|
|
19522
|
+
const mainBooker = formik.values.rooms
|
|
19523
|
+
.find((room) => room.adults.find((traveler) => traveler.id === formik.values.mainBookerId))
|
|
19524
|
+
?.adults.find((traveler) => traveler.id === formik.values.mainBookerId);
|
|
19525
|
+
const countryOptions = [
|
|
19526
|
+
{ key: 'empty', value: undefined, label: translations.TRAVELERS_FORM.SELECT_COUNTRY },
|
|
19527
|
+
...(showAllCountries
|
|
19528
|
+
? countries?.map((country) => ({ key: country.iso2, value: country.iso2, label: country.name })) ?? []
|
|
19529
|
+
: travellersSettings?.countries?.map((country) => ({ key: country.iso2, value: country.iso2, label: country.name })) ?? [
|
|
19530
|
+
{ key: 'be', value: 'be', label: translations.TRAVELERS_FORM.COUNTRIES.BELGIUM },
|
|
19531
|
+
{ key: 'nl', value: 'nl', label: translations.TRAVELERS_FORM.COUNTRIES.NETHERLANDS },
|
|
19532
|
+
{ key: 'fr', value: 'fr', label: translations.TRAVELERS_FORM.COUNTRIES.FRANCE }
|
|
19533
|
+
])
|
|
19534
|
+
];
|
|
19535
|
+
const handleMainBookerChange = (event) => {
|
|
19536
|
+
formik.setFieldValue('mainBookerId', parseInt(event.currentTarget.value, 10));
|
|
19537
|
+
};
|
|
19538
|
+
const handleAgentChange = (value) => {
|
|
19539
|
+
setFilteredAgents(typeaheadAgents.filter((x) => x.value.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) > -1));
|
|
19540
|
+
formik.setFieldValue('travelAgentName', value);
|
|
19541
|
+
};
|
|
19542
|
+
const handleAgentSelect = (key) => {
|
|
19543
|
+
const agent = typeaheadAgents.find((x) => x.key === key);
|
|
19544
|
+
formik.setValues({
|
|
19545
|
+
...formik.values,
|
|
19546
|
+
travelAgentId: Number(agent?.key),
|
|
19547
|
+
travelAgentName: agent?.value ?? ''
|
|
19548
|
+
});
|
|
19549
|
+
onBookingTypeChange?.(agentAdressId && agentAdressId !== 0 ? 'b2b' : 'b2b2c');
|
|
19550
|
+
};
|
|
19551
|
+
const handleAgentClear = () => {
|
|
19552
|
+
formik.setValues({ ...formik.values, travelAgentId: 0, travelAgentName: '' });
|
|
19553
|
+
onBookingTypeChange?.('b2c');
|
|
19554
|
+
};
|
|
19555
|
+
const toggleAgent = (value) => {
|
|
19556
|
+
setShowAgents(value);
|
|
19557
|
+
if (!value) {
|
|
19558
|
+
handleAgentClear();
|
|
19559
|
+
setFilteredAgents([]);
|
|
19560
|
+
}
|
|
19561
|
+
};
|
|
19562
|
+
const handleAddTraveler = (roomIndex) => {
|
|
19563
|
+
const rooms = [...formik.values.rooms];
|
|
19564
|
+
const newAdult = {
|
|
19565
|
+
id: Date.now(),
|
|
19566
|
+
firstName: '',
|
|
19567
|
+
lastName: '',
|
|
19568
|
+
birthDate: '',
|
|
19569
|
+
gender: '',
|
|
19570
|
+
weight: null,
|
|
19571
|
+
weightType: build.WeightType.kilograms,
|
|
19572
|
+
height: null,
|
|
19573
|
+
heightType: build.HeightType.centimeters,
|
|
19574
|
+
...EMPTY_BUILT_IN_FIELDS,
|
|
19575
|
+
customFields: buildEmptyCustomFields(paxFields)
|
|
19576
|
+
};
|
|
19577
|
+
rooms[roomIndex] = { ...rooms[roomIndex], adults: [...rooms[roomIndex].adults, newAdult] };
|
|
19578
|
+
formik.setFieldValue('rooms', rooms);
|
|
19579
|
+
};
|
|
19580
|
+
const handleRemoveTraveler = (roomIndex, travelerIndex) => {
|
|
19581
|
+
const rooms = [...formik.values.rooms];
|
|
19582
|
+
const adults = [...rooms[roomIndex].adults];
|
|
19583
|
+
if (adults.length <= 1)
|
|
19584
|
+
return;
|
|
19585
|
+
adults.splice(travelerIndex, 1);
|
|
19586
|
+
rooms[roomIndex] = { ...rooms[roomIndex], adults };
|
|
19587
|
+
formik.setFieldValue('rooms', rooms);
|
|
19588
|
+
};
|
|
19589
|
+
const handleAddRoom = () => {
|
|
19590
|
+
const rooms = [...formik.values.rooms];
|
|
19591
|
+
rooms.push({
|
|
19592
|
+
adults: [
|
|
19593
|
+
{
|
|
19594
|
+
id: Date.now(),
|
|
19595
|
+
firstName: '',
|
|
19596
|
+
lastName: '',
|
|
19597
|
+
birthDate: '',
|
|
19598
|
+
gender: '',
|
|
19599
|
+
weight: null,
|
|
19600
|
+
weightType: build.WeightType.kilograms,
|
|
19601
|
+
height: null,
|
|
19602
|
+
heightType: build.HeightType.centimeters,
|
|
19603
|
+
...EMPTY_BUILT_IN_FIELDS,
|
|
19604
|
+
customFields: buildEmptyCustomFields(paxFields)
|
|
19605
|
+
}
|
|
19606
|
+
],
|
|
19607
|
+
children: []
|
|
19608
|
+
});
|
|
19609
|
+
formik.setFieldValue('rooms', rooms);
|
|
19610
|
+
};
|
|
19611
|
+
const handleRemoveRoom = (roomIndex) => {
|
|
19612
|
+
const rooms = [...formik.values.rooms];
|
|
19613
|
+
rooms.splice(roomIndex, 1);
|
|
19614
|
+
formik.setFieldValue('rooms', rooms);
|
|
19615
|
+
};
|
|
19616
|
+
const renderWeightControl = (namePrefix, value, isRequired) => (React__default.createElement("div", { className: "form__row" },
|
|
19617
|
+
React__default.createElement(LabeledInput, { type: "number", min: 0, hasError: hasVisibleError(`${namePrefix}.weight`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.WEIGHT, required: isRequired, name: `${namePrefix}.weight`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.weight ?? '' }),
|
|
19618
|
+
React__default.createElement(LabeledSelect, { extraClassName: "form__group--md-33", name: `${namePrefix}.weightType`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.weightType, options: [
|
|
19619
|
+
{ key: 'kg', value: build.WeightType.kilograms, label: translations.TRAVELERS_FORM.WEIGHT_UNIT_KG },
|
|
19620
|
+
{ key: 'lb', value: build.WeightType.pounds, label: translations.TRAVELERS_FORM.WEIGHT_UNIT_LB }
|
|
19621
|
+
] })));
|
|
19622
|
+
const renderHeightControl = (namePrefix, value, isRequired) => (React__default.createElement("div", { className: "form__row" },
|
|
19623
|
+
React__default.createElement(LabeledInput, { type: "number", min: 0, hasError: hasVisibleError(`${namePrefix}.height`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.HEIGHT, required: isRequired, name: `${namePrefix}.height`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.height ?? '' }),
|
|
19624
|
+
React__default.createElement(LabeledSelect, { extraClassName: "form__group--md-33", name: `${namePrefix}.heightType`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.heightType, options: [
|
|
19625
|
+
{ key: 'cm', value: build.HeightType.centimeters, label: translations.TRAVELERS_FORM.HEIGHT_UNIT_CM },
|
|
19626
|
+
{ key: 'ftIn', value: build.HeightType.feetInches, label: translations.TRAVELERS_FORM.HEIGHT_UNIT_FT_IN }
|
|
19627
|
+
] })));
|
|
19628
|
+
const getCustomFieldControl = (field, value, name) => {
|
|
19629
|
+
const label = compact([field.fieldName, field.isRequired && '*']).join(' ');
|
|
19630
|
+
switch (field.dataType) {
|
|
19631
|
+
case build.CustomFieldDataType.bool:
|
|
19632
|
+
return (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
|
|
19633
|
+
React__default.createElement("div", { className: "checkbox" },
|
|
19634
|
+
React__default.createElement("label", { className: "checkbox__label" },
|
|
19635
|
+
React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: value === 'true', onChange: (e) => formik.setFieldValue(name, e.target.checked ? 'true' : 'false'), onBlur: formik.handleBlur, name: name }),
|
|
19636
|
+
label))));
|
|
19637
|
+
case build.CustomFieldDataType.date:
|
|
19638
|
+
return (React__default.createElement(LabeledInput, { type: "date", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
19639
|
+
case build.CustomFieldDataType.time:
|
|
19640
|
+
return (React__default.createElement(LabeledInput, { type: "time", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
19641
|
+
case build.CustomFieldDataType.numeric:
|
|
19642
|
+
return (React__default.createElement(LabeledInput, { type: "number", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
19643
|
+
case build.CustomFieldDataType.string:
|
|
19644
|
+
default:
|
|
19645
|
+
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
19646
|
+
}
|
|
19647
|
+
};
|
|
19648
|
+
const renderCustomFields = (travelerValues, namePrefix) => {
|
|
19649
|
+
if (!paxFields?.length)
|
|
19650
|
+
return null;
|
|
19651
|
+
const isMainBooker = travelerValues.id === formik.values.mainBookerId;
|
|
19652
|
+
const applicableFields = getApplicablePaxCustomFields(paxFields, isMainBooker);
|
|
19653
|
+
if (!applicableFields.length)
|
|
19654
|
+
return null;
|
|
19655
|
+
return (React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, applicableFields.map((field) => {
|
|
19656
|
+
const fieldIndex = travelerValues.customFields?.findIndex((c) => c.customFieldConfigurationId === field.customFieldConfigurationId) ?? -1;
|
|
19657
|
+
if (fieldIndex < 0)
|
|
19658
|
+
return null;
|
|
19659
|
+
const name = `${namePrefix}.customFields[${fieldIndex}].value`;
|
|
19660
|
+
const value = travelerValues.customFields[fieldIndex].value;
|
|
19661
|
+
return (React__default.createElement("div", { key: field.customFieldConfigurationId, style: { gridColumn: `span ${field.col || 12}` } }, getCustomFieldControl(field, value, name)));
|
|
19662
|
+
})));
|
|
19663
|
+
};
|
|
19664
|
+
// Fields with a dedicated control (gender, hasInsurance, countryId) aren't listed here.
|
|
19665
|
+
const BUILT_IN_FIELD_CONTROL_META = {
|
|
19666
|
+
firstName: { label: translations.TRAVELERS_FORM.FIRST_NAME },
|
|
19667
|
+
lastName: { label: translations.TRAVELERS_FORM.LAST_NAME },
|
|
19668
|
+
dateOfBirth: { type: 'date', label: translations.TRAVELERS_FORM.BIRTHDATE },
|
|
19669
|
+
nickname: { label: translations.TRAVELERS_FORM.NICKNAME },
|
|
19670
|
+
birthplace: { label: translations.TRAVELERS_FORM.BIRTHPLACE },
|
|
19671
|
+
nationality: { label: translations.TRAVELERS_FORM.NATIONALITY },
|
|
19672
|
+
preferredLanguageId: { type: 'number', label: translations.TRAVELERS_FORM.PREFERRED_LANGUAGE },
|
|
19673
|
+
email: { type: 'email', label: translations.TRAVELERS_FORM.TRAVELER_EMAIL },
|
|
19674
|
+
phone: { label: translations.TRAVELERS_FORM.TRAVELER_PHONE },
|
|
19675
|
+
mobile: { label: translations.TRAVELERS_FORM.TRAVELER_MOBILE },
|
|
19676
|
+
passportNumber: { label: translations.TRAVELERS_FORM.PASSPORT_NUMBER },
|
|
19677
|
+
passportIssueDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_ISSUE_DATE },
|
|
19678
|
+
passportIssuedLocation: { label: translations.TRAVELERS_FORM.PASSPORT_ISSUED_LOCATION },
|
|
19679
|
+
passportExpiryDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_EXPIRY_DATE },
|
|
19680
|
+
emergencyNumber: { label: translations.TRAVELERS_FORM.EMERGENCY_NUMBER },
|
|
19681
|
+
insuranceName: { label: translations.TRAVELERS_FORM.INSURANCE_NAME },
|
|
19682
|
+
info: { label: translations.TRAVELERS_FORM.INFO },
|
|
19683
|
+
street: { label: translations.TRAVELERS_FORM.STREET },
|
|
19684
|
+
location: { label: translations.TRAVELERS_FORM.CITY },
|
|
19685
|
+
postalCode: { label: translations.TRAVELERS_FORM.ZIPCODE },
|
|
19686
|
+
number: { label: translations.TRAVELERS_FORM.HOUSE_NUMBER }
|
|
19687
|
+
};
|
|
19688
|
+
const renderBuiltInFieldControl = (fieldName, isRequired, travelerValues, namePrefix) => {
|
|
19689
|
+
const path = BUILT_IN_FIELD_PATHS[fieldName] ?? fieldName;
|
|
19690
|
+
const name = `${namePrefix}.${path}`;
|
|
19691
|
+
const value = get(travelerValues, path);
|
|
19692
|
+
switch (fieldName) {
|
|
19693
|
+
case 'gender':
|
|
19694
|
+
return React__default.createElement(GenderControl, { translations: translations, value: travelerValues, formik: formik, name: name });
|
|
19695
|
+
case 'hasInsurance':
|
|
19696
|
+
return (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
|
|
19697
|
+
React__default.createElement("div", { className: "checkbox" },
|
|
19698
|
+
React__default.createElement("label", { className: "checkbox__label" },
|
|
19699
|
+
React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: !!value, onChange: (e) => formik.setFieldValue(name, e.target.checked), onBlur: formik.handleBlur, name: name }),
|
|
19700
|
+
compact([translations.TRAVELERS_FORM.HAS_INSURANCE, isRequired && '*']).join(' ')))));
|
|
19701
|
+
case 'countryId':
|
|
19702
|
+
return (React__default.createElement(LabeledSelect, { hasError: hasVisibleError(name), label: translations.TRAVELERS_FORM.COUNTRY, required: isRequired, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value, options: countryOptions }));
|
|
19703
|
+
case 'weight':
|
|
19704
|
+
return renderWeightControl(namePrefix, travelerValues, isRequired);
|
|
19705
|
+
case 'height':
|
|
19706
|
+
return renderHeightControl(namePrefix, travelerValues, isRequired);
|
|
19707
|
+
default: {
|
|
19708
|
+
const meta = BUILT_IN_FIELD_CONTROL_META[fieldName] ?? { label: fieldName };
|
|
19709
|
+
return (React__default.createElement(LabeledInput, { type: meta.type, hasError: hasVisibleError(name), label: meta.label, required: isRequired, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value ?? '' }));
|
|
19710
|
+
}
|
|
19711
|
+
}
|
|
19712
|
+
};
|
|
19713
|
+
const CORE_FIELD_DEFAULTS = {
|
|
19714
|
+
gender: { isRequired: true, col: 4 },
|
|
19715
|
+
firstName: { isRequired: true, col: 4 },
|
|
19716
|
+
lastName: { isRequired: true, col: 4 },
|
|
19717
|
+
dateOfBirth: { isRequired: true, col: 4 }
|
|
19718
|
+
};
|
|
19719
|
+
const resolveBuiltInField = (fieldName, travelerValues) => {
|
|
19720
|
+
const isMainBooker = travelerValues.id === formik.values.mainBookerId;
|
|
19721
|
+
const configured = getBuiltInPaxField(paxFields, fieldName, isMainBooker);
|
|
19722
|
+
const fallback = CORE_FIELD_DEFAULTS[fieldName];
|
|
19723
|
+
if (!configured && !fallback)
|
|
19724
|
+
return undefined;
|
|
19725
|
+
return { isRequired: configured?.isRequired ?? fallback.isRequired, col: configured?.col ?? fallback.col };
|
|
19726
|
+
};
|
|
19727
|
+
const renderBuiltInField = (fieldName, travelerValues, namePrefix) => {
|
|
19728
|
+
const resolved = resolveBuiltInField(fieldName, travelerValues);
|
|
19729
|
+
if (!resolved)
|
|
19730
|
+
return null;
|
|
19731
|
+
return (React__default.createElement("div", { key: fieldName, style: { gridColumn: `span ${resolved.col || 12}` } }, renderBuiltInFieldControl(fieldName, resolved.isRequired, travelerValues, namePrefix)));
|
|
19732
|
+
};
|
|
19733
|
+
const renderTravelerAddressFields = (travelerValues, namePrefix) => {
|
|
19734
|
+
const fields = ADDRESS_FIELD_NAMES.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix)).filter(Boolean);
|
|
19735
|
+
if (!fields.length)
|
|
19736
|
+
return null;
|
|
19737
|
+
return React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, fields);
|
|
19738
|
+
};
|
|
19739
|
+
const getControl = (type, value, name) => {
|
|
19740
|
+
switch (type) {
|
|
19741
|
+
case 'country':
|
|
19742
|
+
return (React__default.createElement(LabeledSelect, { hasError: hasVisibleError('country'), label: translations.TRAVELERS_FORM.COUNTRY, required: true, name: "country", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.country, options: countryOptions }));
|
|
19743
|
+
case 'phone':
|
|
19744
|
+
return (React__default.createElement(PhoneInput, { countries: travellersSettings?.countries ?? [], countryIso2: formik.values.country, hasError: hasVisibleError('phone'), label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }));
|
|
19745
|
+
case 'email':
|
|
19746
|
+
return (React__default.createElement(React__default.Fragment, null,
|
|
19747
|
+
React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
|
|
19748
|
+
React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })));
|
|
19749
|
+
case 'street':
|
|
19750
|
+
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('street'), extraClassName: "form__group--50 form__group--sm-60", label: translations.TRAVELERS_FORM.STREET, required: true, name: "street", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.street }));
|
|
19751
|
+
case 'houseNumber':
|
|
19752
|
+
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('houseNumber'), extraClassName: "form__group--30 form__group--sm-20", label: translations.TRAVELERS_FORM.HOUSE_NUMBER, required: true, name: "houseNumber", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.houseNumber }));
|
|
19753
|
+
case 'box':
|
|
19754
|
+
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('box'), extraClassName: "form__group--20", label: translations.TRAVELERS_FORM.POST_BOX, name: "box", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.box }));
|
|
19755
|
+
case 'zipCode':
|
|
19756
|
+
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('zipCode'), extraClassName: "form__group--40 form__group--sm-20", label: translations.TRAVELERS_FORM.ZIPCODE, required: true, name: "zipCode", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.zipCode }));
|
|
19757
|
+
case 'place':
|
|
19758
|
+
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('place'), extraClassName: "form__group--60 form__group--sm-40", label: translations.TRAVELERS_FORM.CITY, required: true, name: "place", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.place }));
|
|
19759
|
+
default:
|
|
19760
|
+
return null;
|
|
19761
|
+
}
|
|
19762
|
+
};
|
|
19763
|
+
const renderRoomLabel = (room) => compact([
|
|
19764
|
+
room.adults.length,
|
|
19765
|
+
room.adults.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
|
|
19766
|
+
room.adults.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
|
|
19767
|
+
room.adults?.length && room.children?.length && ', ',
|
|
19768
|
+
room.children.length,
|
|
19769
|
+
room.children.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
|
|
19770
|
+
room.children.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`
|
|
19771
|
+
]).join('');
|
|
19772
|
+
const renderTravelerFields = (travelerValues, namePrefix, isAdult, roomIndex, travelerIndex) => {
|
|
19773
|
+
if (useCompactForm) {
|
|
19774
|
+
return (React__default.createElement("div", { className: "form__row" },
|
|
19775
|
+
React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.age`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.AGE, required: true, name: `${namePrefix}.age`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.age })));
|
|
19776
|
+
}
|
|
19777
|
+
// 'birthDate' (the legacy formFields type string) is normalized to the paxFields catalog's
|
|
19778
|
+
// 'dateOfBirth' fieldName for config lookups.
|
|
19779
|
+
const baseFieldNames = (travellersSettings?.formFields?.length ? travellersSettings.formFields.map((field) => field.type) : ['gender', 'firstName', 'lastName', 'dateOfBirth']).map((fieldName) => (fieldName === 'birthDate' ? 'dateOfBirth' : fieldName));
|
|
19780
|
+
const isMainBooker = travelerValues.id === formik.values.mainBookerId;
|
|
19781
|
+
const extraFieldNames = getApplicableBuiltInPaxFields(paxFields, isMainBooker)
|
|
19782
|
+
.map((field) => field.fieldName)
|
|
19783
|
+
.filter((fieldName) => !baseFieldNames.includes(fieldName) && !ADDRESS_FIELD_NAMES.includes(fieldName));
|
|
19784
|
+
return (React__default.createElement(React__default.Fragment, null,
|
|
19785
|
+
React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, [...baseFieldNames, ...extraFieldNames].map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix))),
|
|
19786
|
+
renderTravelerAddressFields(travelerValues, namePrefix),
|
|
19787
|
+
renderCustomFields(travelerValues, namePrefix),
|
|
19788
|
+
travelersFirstStep && isAdult && formik.values.rooms[roomIndex].adults.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveTraveler(roomIndex, travelerIndex) }, translations.TRAVELERS_FORM.REMOVE_TRAVELER))));
|
|
19789
|
+
};
|
|
19790
|
+
return (React__default.createElement("form", { className: "form form__travelers", name: "booking--travellers", id: "booking--travellers", noValidate: true, onSubmit: formik.handleSubmit, onReset: formik.handleReset },
|
|
19791
|
+
React__default.createElement("div", { className: "form__travelers__wrapper" },
|
|
19792
|
+
formik.values.rooms.map((room, roomIndex) => (React__default.createElement("div", { key: roomIndex },
|
|
19793
|
+
formik.values.rooms.length > 1 && (React__default.createElement("div", { className: "form__region" },
|
|
19794
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
19795
|
+
React__default.createElement("h5", { className: "form__region-heading" },
|
|
19796
|
+
translations.SHARED.ROOM,
|
|
19797
|
+
" ",
|
|
19798
|
+
roomIndex + 1),
|
|
19799
|
+
React__default.createElement("p", { className: "form__region-label" }, renderRoomLabel(room))),
|
|
19800
|
+
!useCompactForm && travelersFirstStep && formik.values.rooms.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveRoom(roomIndex) }, "Verwijder reisgezelschap")))),
|
|
19801
|
+
room.adults.map((travelerValues, index) => (React__default.createElement("div", { className: "form__region", key: travelerValues.id },
|
|
19802
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
19803
|
+
React__default.createElement("h5", { className: "form__region-heading" },
|
|
19804
|
+
translations.TRAVELERS_FORM.TRAVELER,
|
|
19805
|
+
" ",
|
|
19806
|
+
index + 1),
|
|
19807
|
+
React__default.createElement("p", { className: "form__region-label" }, translations.TRAVELERS_FORM.ADULT),
|
|
19808
|
+
React__default.createElement("div", { className: "radiobutton" },
|
|
19809
|
+
React__default.createElement("label", { className: "radiobutton__label" },
|
|
19810
|
+
React__default.createElement("input", { type: "radio", name: "mainBookerId", onChange: handleMainBookerChange, onBlur: formik.handleBlur, value: travelerValues.id, checked: formik.values.mainBookerId === travelerValues.id, className: "radiobutton__input" }),
|
|
19811
|
+
translations.TRAVELERS_FORM.MAIN_BOOKER))),
|
|
19812
|
+
renderTravelerFields(travelerValues, `rooms[${roomIndex}].adults[${index}]`, true, roomIndex, index)))),
|
|
19813
|
+
room.children.map((travelerValues, index) => (React__default.createElement("div", { className: "form__region", key: travelerValues.id },
|
|
19814
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
19815
|
+
React__default.createElement("h5", { className: "form__region-heading" },
|
|
19816
|
+
translations.TRAVELERS_FORM.TRAVELER,
|
|
19817
|
+
" ",
|
|
19818
|
+
room.adults.length + index + 1),
|
|
19819
|
+
React__default.createElement("p", { className: "form__region-label" }, travelerValues.isBaby ? translations.TRAVELERS_FORM.BABY : translations.TRAVELERS_FORM.CHILD)),
|
|
19820
|
+
renderTravelerFields(travelerValues, `rooms[${roomIndex}].children[${index}]`, false, roomIndex, index)))),
|
|
19821
|
+
!useCompactForm && travelersFirstStep && (React__default.createElement("div", { className: "form__region" },
|
|
19822
|
+
React__default.createElement("button", { type: "button", className: "cta cta--select", onClick: () => handleAddTraveler(roomIndex) }, translations.TRAVELERS_FORM.ADD_TRAVELER)))))),
|
|
19823
|
+
!useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default.createElement("div", { className: "form__region" },
|
|
19824
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
19825
|
+
React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
|
|
19826
|
+
React__default.createElement("p", { className: "form__region-label" }, compact([compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
|
|
19827
|
+
travellersSettings?.mainBookerFormFields?.length ? (React__default.createElement("div", { className: "main-booker-form__grid" }, travellersSettings.mainBookerFormFields.map((field, index) => (React__default.createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, {}, field.type)))))) : (React__default.createElement(React__default.Fragment, null,
|
|
19828
|
+
React__default.createElement("div", { className: "form__twocolumn" },
|
|
19829
|
+
React__default.createElement("div", { className: "form__twocolumn-column" },
|
|
19830
|
+
React__default.createElement("div", { className: "form__row" },
|
|
19831
|
+
React__default.createElement(LabeledInput, { hasError: hasVisibleError('street'), extraClassName: "form__group--50 form__group--sm-60", label: translations.TRAVELERS_FORM.STREET, required: true, name: "street", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.street }),
|
|
19832
|
+
React__default.createElement(LabeledInput, { hasError: hasVisibleError('houseNumber'), extraClassName: "form__group--30 form__group--sm-20", label: translations.TRAVELERS_FORM.HOUSE_NUMBER, required: true, name: "houseNumber", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.houseNumber }),
|
|
19833
|
+
React__default.createElement(LabeledInput, { hasError: hasVisibleError('box'), extraClassName: "form__group--20", label: translations.TRAVELERS_FORM.POST_BOX, name: "box", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.box }))),
|
|
19834
|
+
React__default.createElement("div", { className: "form__twocolumn-column" },
|
|
19835
|
+
React__default.createElement("div", { className: "form__row" },
|
|
19836
|
+
React__default.createElement(LabeledInput, { hasError: hasVisibleError('zipCode'), extraClassName: "form__group--40 form__group--sm-20", label: translations.TRAVELERS_FORM.ZIPCODE, required: true, name: "zipCode", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.zipCode }),
|
|
19837
|
+
React__default.createElement(LabeledInput, { hasError: hasVisibleError('place'), extraClassName: "form__group--60 form__group--sm-40", label: translations.TRAVELERS_FORM.CITY, required: true, name: "place", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.place }),
|
|
19838
|
+
React__default.createElement(LabeledSelect, { hasError: hasVisibleError('country'), extraClassName: "form__group--sm-40", label: translations.TRAVELERS_FORM.COUNTRY, required: true, name: "country", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.country, options: countryOptions })))),
|
|
19839
|
+
React__default.createElement("div", { className: "form__row" },
|
|
19840
|
+
React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }),
|
|
19841
|
+
React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
|
|
19842
|
+
React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })))))) : !useCompactForm ? (React__default.createElement("div", { className: "form__region" },
|
|
19843
|
+
React__default.createElement("div", { className: "form__row" },
|
|
19844
|
+
React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone })))) : null,
|
|
19845
|
+
!useCompactForm && showAgentSelection && (React__default.createElement("div", { className: "form__region" },
|
|
19846
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
19847
|
+
React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.BOOK_WITH_AGENT),
|
|
19848
|
+
React__default.createElement("div", { className: "checkbox", id: "cbxChooseOffice" },
|
|
19849
|
+
React__default.createElement("label", { className: "checkbox__label" },
|
|
19850
|
+
React__default.createElement("input", { type: "checkbox", name: "booking--mainbooker", checked: showAgents, onChange: () => toggleAgent(!showAgents), className: "checkbox__input" }),
|
|
19851
|
+
translations.TRAVELERS_FORM.CHOOSE_OFFICE))),
|
|
19852
|
+
showAgents && (React__default.createElement("div", { className: "form__row form__row--choose-office" },
|
|
19853
|
+
React__default.createElement("div", { className: buildClassName(['form__group', 'form__group--icon', hasVisibleError('travelAgentId') && 'form__group--error']) },
|
|
19854
|
+
React__default.createElement(TypeAheadInput, { value: formik.values.travelAgentName, options: filteredAgents, onChange: handleAgentChange, onSelect: handleAgentSelect, onClear: handleAgentClear, name: "travelAgentName", placeholder: translations.TRAVELERS_FORM.CHOOSE_AGENT_PLACEHOLDER }))))))),
|
|
19855
|
+
!useCompactForm && errorKeys.length > 0 && (React__default.createElement("div", { className: "form__region form__region--errors" },
|
|
19856
|
+
React__default.createElement("div", { className: "form__row" },
|
|
19857
|
+
React__default.createElement("div", { className: "form__group" },
|
|
19858
|
+
React__default.createElement("p", { className: "form__error-heading" },
|
|
19859
|
+
translations.TRAVELERS_FORM.VALIDATION_MESSAGE,
|
|
19860
|
+
":"),
|
|
19861
|
+
React__default.createElement("ul", { className: "list" }, errorKeys.map((key) => (React__default.createElement("li", { key: key }, get(flatErrors, key))))))))),
|
|
19862
|
+
travelersFirstStep && (React__default.createElement("div", { className: "booking__navigator" },
|
|
19863
|
+
React__default.createElement("button", { type: "button", className: "cta cta--select", onClick: handleAddRoom }, translations.TRAVELERS_FORM.ADD_ROOM))),
|
|
19864
|
+
React__default.createElement("div", { className: "booking__navigator" },
|
|
19865
|
+
renderPreviousButton?.(),
|
|
19866
|
+
React__default.createElement("button", { type: "submit", title: translations.STEPS.NEXT, className: 'cta' + (isUnavailable ? ' cta--disabled' : '') }, translations.STEPS.NEXT))));
|
|
19867
|
+
};
|
|
19868
|
+
|
|
19869
|
+
const fetchPriceDetails$1 = async (apiSettings, request, signal, languageCode) => {
|
|
19870
|
+
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
19871
|
+
return await build.priceDetails(tideClientConfig, request, signal, languageCode);
|
|
19872
|
+
};
|
|
19873
|
+
const priceDetailsApi = {
|
|
19874
|
+
fetchPriceDetails: fetchPriceDetails$1
|
|
19875
|
+
};
|
|
19876
|
+
|
|
19877
|
+
const updatePackageDetails = (packageDetails, changedLines) => {
|
|
19878
|
+
return {
|
|
19879
|
+
...packageDetails,
|
|
19880
|
+
options: packageDetails.options.map((opt) => {
|
|
19881
|
+
return {
|
|
19882
|
+
...opt,
|
|
19883
|
+
rooms: opt.isSelected ? updateRooms(opt.rooms, changedLines) : opt.rooms,
|
|
19884
|
+
groups: opt.isSelected ? updateBookingGroups(opt.groups, changedLines) : opt.groups,
|
|
19885
|
+
optionUnits: opt.isSelected ? updateOptionUnits(opt.optionUnits, changedLines) : opt.optionUnits,
|
|
19886
|
+
optionPax: opt.isSelected ? updateOptionPax(opt.optionPax, changedLines) : opt.optionPax
|
|
19887
|
+
};
|
|
19888
|
+
})
|
|
19889
|
+
};
|
|
19890
|
+
};
|
|
19891
|
+
// ROOMS
|
|
19892
|
+
const updateRooms = (rooms, changedLines) => {
|
|
19893
|
+
return rooms.map((room) => ({
|
|
19894
|
+
...room,
|
|
19895
|
+
options: room.options.map((option) => ({
|
|
19896
|
+
...option,
|
|
19897
|
+
price: changedLines.find((x) => x.entryLineGuid == option.entryLineGuid)?.price ?? option.price
|
|
19898
|
+
}))
|
|
19899
|
+
}));
|
|
19900
|
+
};
|
|
19901
|
+
// PAX
|
|
19902
|
+
const updateOptionPax = (pax, changedLines) => {
|
|
19903
|
+
return pax.map((p) => ({
|
|
19904
|
+
...p,
|
|
19905
|
+
groups: updatePaxGroups(p.groups, changedLines)
|
|
19906
|
+
}));
|
|
19907
|
+
};
|
|
19908
|
+
const updatePaxGroups = (groups, changedLines) => {
|
|
19909
|
+
return groups.map((g) => ({
|
|
19910
|
+
...g,
|
|
19911
|
+
options: g.options.map((o) => ({
|
|
19912
|
+
...o,
|
|
19913
|
+
groups: updatePaxGroups(o.groups, changedLines),
|
|
19914
|
+
line: {
|
|
19915
|
+
...o.line,
|
|
19916
|
+
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
19917
|
+
},
|
|
19918
|
+
alternatives: o.alternatives.map((a) => ({
|
|
19919
|
+
...a,
|
|
19920
|
+
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
19921
|
+
}))
|
|
19922
|
+
}))
|
|
19923
|
+
}));
|
|
19924
|
+
};
|
|
19925
|
+
// UNITS
|
|
19926
|
+
const updateOptionUnits = (units, changedLines) => {
|
|
19927
|
+
return units.map((u) => ({
|
|
19928
|
+
...u,
|
|
19929
|
+
groups: updateUnitGroups(u.groups, changedLines)
|
|
19930
|
+
}));
|
|
19931
|
+
};
|
|
19932
|
+
const updateUnitGroups = (groups, changedLines) => {
|
|
19933
|
+
return groups.map((g) => ({
|
|
19934
|
+
...g,
|
|
19935
|
+
options: g.options.map((o) => ({
|
|
19936
|
+
...o,
|
|
19937
|
+
groups: updateUnitGroups(o.groups, changedLines),
|
|
19938
|
+
pax: updateOptionPax(o.pax, changedLines),
|
|
19939
|
+
line: {
|
|
19940
|
+
...o.line,
|
|
19941
|
+
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
19942
|
+
},
|
|
19943
|
+
alternatives: o.alternatives.map((a) => ({
|
|
19944
|
+
...a,
|
|
19945
|
+
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
19946
|
+
}))
|
|
19947
|
+
}))
|
|
19948
|
+
}));
|
|
19949
|
+
};
|
|
19950
|
+
// BOOKING
|
|
19951
|
+
const updateBookingGroups = (groups, changedLines) => {
|
|
19952
|
+
return groups.map((g) => ({
|
|
19953
|
+
...g,
|
|
19954
|
+
options: g.options.map((o) => ({
|
|
19955
|
+
...o,
|
|
19956
|
+
groups: updateBookingGroups(o.groups, changedLines),
|
|
19957
|
+
units: updateOptionUnits(o.units, changedLines),
|
|
19958
|
+
pax: updateOptionPax(o.pax, changedLines),
|
|
19959
|
+
line: {
|
|
19960
|
+
...o.line,
|
|
19961
|
+
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
19962
|
+
},
|
|
19963
|
+
alternatives: o.alternatives.map((a) => ({
|
|
19964
|
+
...a,
|
|
19965
|
+
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
19966
|
+
}))
|
|
19967
|
+
}))
|
|
19968
|
+
}));
|
|
19969
|
+
};
|
|
19970
|
+
|
|
19971
|
+
const fetchPriceDetails = createAsyncThunk('priceDetails/fetchPriceDetails', async (_, { dispatch, getState, signal }) => {
|
|
19972
|
+
const state = getState();
|
|
19973
|
+
const languageCode = selectLanguageCode(state);
|
|
19974
|
+
const request = selectBookingPackageBookRequest(state);
|
|
19975
|
+
if (!request) {
|
|
19976
|
+
throw Error('Product not available.');
|
|
19977
|
+
}
|
|
19978
|
+
dispatch(setFetchingPriceDetails(true));
|
|
19979
|
+
dispatch(resetPriceDetails());
|
|
19980
|
+
const priceDetails = await priceDetailsApi.fetchPriceDetails(state.apiSettings, request, signal, languageCode);
|
|
19981
|
+
dispatch(setFetchingPriceDetails(false));
|
|
19982
|
+
const packageDetails = selectPackageDetails(state);
|
|
19983
|
+
if (packageDetails) {
|
|
19984
|
+
const updatedPackageDetails = updatePackageDetails(packageDetails, priceDetails.changedLines);
|
|
19985
|
+
dispatch(setPackage(updatedPackageDetails));
|
|
19986
|
+
}
|
|
19987
|
+
return priceDetails;
|
|
19988
|
+
});
|
|
19989
|
+
const priceDetailsSlice = createSlice({
|
|
19990
|
+
name: 'priceDetails',
|
|
19991
|
+
initialState: {
|
|
19992
|
+
priceDetails: [],
|
|
19993
|
+
notifications: [],
|
|
19994
|
+
isBusy: false
|
|
19995
|
+
},
|
|
19996
|
+
reducers: {
|
|
19997
|
+
setFetchingPriceDetails(state, action) {
|
|
19998
|
+
state.isBusy = action.payload;
|
|
19999
|
+
},
|
|
20000
|
+
setNotifications(state, action) {
|
|
20001
|
+
state.notifications = action.payload;
|
|
20002
|
+
},
|
|
20003
|
+
resetPriceDetails(state, _) {
|
|
20004
|
+
state.priceDetails = [];
|
|
20005
|
+
}
|
|
20006
|
+
},
|
|
20007
|
+
extraReducers: (builder) => {
|
|
20008
|
+
builder.addCase(fetchPriceDetails.fulfilled, (state, action) => {
|
|
20009
|
+
if (action.payload) {
|
|
20010
|
+
state.deposit = action.payload.deposit;
|
|
20011
|
+
state.commission = action.payload.commission;
|
|
20012
|
+
state.priceDetails = action.payload.details;
|
|
20013
|
+
state.notifications = action.payload.notifications;
|
|
20014
|
+
}
|
|
20015
|
+
});
|
|
20016
|
+
builder.addCase(fetchPriceDetails.rejected, (state) => {
|
|
20017
|
+
state.isBusy = false;
|
|
20018
|
+
});
|
|
20019
|
+
}
|
|
20020
|
+
});
|
|
20021
|
+
const { setFetchingPriceDetails } = priceDetailsSlice.actions;
|
|
20022
|
+
const { resetPriceDetails, setNotifications } = priceDetailsSlice.actions;
|
|
20023
|
+
const selectNotifications = (state) => state.priceDetails.notifications;
|
|
20024
|
+
var priceDetailsReducer = priceDetailsSlice.reducer;
|
|
20025
|
+
|
|
20026
|
+
const selectHasMounted = (state) => state.booking.hasMounted;
|
|
20027
|
+
const selectGeneratePaymentUrl = (state) => state.booking.generatePaymentUrl;
|
|
20028
|
+
const selectSkipPaymentWithAgent = (state) => state.booking.skipPaymentWithAgent;
|
|
20029
|
+
const selectIsFetchingProductOptions = (state) => state.booking.isBusy;
|
|
20030
|
+
const selectDepartureFlight = (state) => state.booking.package?.outwardFlights?.find((x) => x.isSelected);
|
|
20031
|
+
const selectReturnFlight = (state) => state.booking.package?.returnFlights?.find((x) => x.isSelected);
|
|
20032
|
+
const selectPackageRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.rooms;
|
|
20033
|
+
const selectIncludedServiceTypes = (state) => selectActiveOption(state)?.includedServiceTypes;
|
|
20034
|
+
const selectAvailabilities = (state) => state.booking.package?.options.find((x) => x.isSelected)?.availabilities;
|
|
20035
|
+
const selectPackageTags = (state) => state.booking.package?.tags;
|
|
20036
|
+
const selectIsOnRequest = (state) => state.booking.package?.options.find((x) => x.isSelected)?.isOnRequest;
|
|
20037
|
+
const selectPackageOptionUnits = (state) => state.booking.package?.options.find((x) => x.isSelected)?.optionUnits;
|
|
20038
|
+
const selectPackageOptionPax = (state) => state.booking.package?.options.find((x) => x.isSelected)?.optionPax;
|
|
20039
|
+
const selectPackageGroups = (state) => state.booking.package?.options.find((x) => x.isSelected)?.groups;
|
|
20040
|
+
const selectPackageDetails = (state) => state.booking.package;
|
|
20041
|
+
const selectPaxFields = (state) => state.booking.package?.paxFields ?? [];
|
|
20042
|
+
const selectPackageFlights = (state) => ({
|
|
20043
|
+
outward: state.booking.package?.outwardFlights,
|
|
20044
|
+
return: state.booking.package?.returnFlights
|
|
20045
|
+
});
|
|
20046
|
+
const selectFlightMetaData = (state) => state.booking.package?.flightInfo.metaData;
|
|
20047
|
+
const selectActiveOption = (state) => state.booking.package?.options.find((x) => x.isSelected);
|
|
20048
|
+
const selectPackageAirlineGroups = createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airlineGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
|
|
20049
|
+
const selectPackageAirportGroups = createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airportGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
|
|
20050
|
+
const selectRoomOptionDepartureFlightsMetaData = createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
|
|
20051
|
+
const roomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected).shift());
|
|
20052
|
+
return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
|
|
20053
|
+
});
|
|
20054
|
+
const selectRoomOptionReturnFlightsMetaData = createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
|
|
20055
|
+
const selectedRoomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected));
|
|
20056
|
+
// check if there are return flights selected
|
|
20057
|
+
if (selectedRoomOptions?.some((ro) => ro.length > 1)) {
|
|
20058
|
+
const roomOptions = ativeOption?.rooms.map((r) => r.options
|
|
20059
|
+
.filter((o) => o.isSelected)
|
|
20060
|
+
.reverse()
|
|
20061
|
+
.shift());
|
|
20062
|
+
return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
|
|
20063
|
+
}
|
|
20064
|
+
return undefined;
|
|
20065
|
+
});
|
|
20066
|
+
const selectApiSettings = (state) => state.apiSettings;
|
|
20067
|
+
const selectIsUnavailable = (state) => state.booking.isUnavailable;
|
|
20068
|
+
const selectRequestRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.requestRooms;
|
|
20069
|
+
const selectOfficeId = (state) => state.booking.officeId;
|
|
20070
|
+
const selectLanguageCode = (state) => state.booking.languageCode;
|
|
20071
|
+
const selectCurrencyCode = (state) => state.booking.package?.currencyCode ?? 'EUR';
|
|
20072
|
+
const selectLanguage = (state) => state.booking.languageCode;
|
|
20073
|
+
const selectAllDynamicTranslations = (state) => state.booking.translations;
|
|
20074
|
+
const selectDynamicTranslations = createSelector([selectAllDynamicTranslations, selectLanguage], (allDynamicTranslations, language) => {
|
|
20075
|
+
return allDynamicTranslations?.find((x) => x.language == language)?.value ?? {};
|
|
20076
|
+
});
|
|
20077
|
+
// Host override files are hand-maintained, and a null only ever blanks a key the component
|
|
20078
|
+
// then reads, so treat it like a missing key (lodash merge already skips undefined).
|
|
20079
|
+
const withoutNulls = (value) => isPlainObject$1(value)
|
|
20080
|
+
? mapValues(pickBy(value, (x) => x !== null), withoutNulls)
|
|
20081
|
+
: value;
|
|
20082
|
+
// getTranslations deep-merges the overrides over a clone of the built-in translations, so a
|
|
20083
|
+
// host override of a nested group (TRAVELERS_FORM.VALIDATION, TRAVELERS_FORM.COUNTRIES)
|
|
20084
|
+
// only replaces the keys it actually contains. Merging per section one level deep dropped
|
|
20085
|
+
// every other built-in key of such a group, which made those keys resolve to undefined and
|
|
20086
|
+
// crash format() in the consuming component.
|
|
20087
|
+
const selectTranslations = createSelector([selectLanguage, selectDynamicTranslations], (language, dynamicTranslations) => getTranslations(language, isEmpty$1(dynamicTranslations) ? undefined : withoutNulls(dynamicTranslations)));
|
|
20088
|
+
const selectBookingOptions = (state) => state.booking.bookingOptions;
|
|
20089
|
+
const selectBookingType = (state) => state.booking.bookingType;
|
|
20090
|
+
const selectTagIds = (state) => state.booking.tagIds;
|
|
20091
|
+
const selectAgentAdressId = (state) => state.booking.agentAdressId;
|
|
20092
|
+
const selectProductAttributes = (state) => state.booking.productAttributes;
|
|
20093
|
+
const selectBookingAttributes = (state) => state.booking.bookingAttributes;
|
|
20094
|
+
const selectBookingNumber = (state) => state.booking.bookingNumber;
|
|
20095
|
+
const selectIsOption = (state) => state.booking.isOption;
|
|
20096
|
+
const selectBookingRooms = (state) => state.booking.bookingAttributes?.rooms;
|
|
20097
|
+
const selectBookingRemarks = (state) => state.booking.remarks;
|
|
20098
|
+
const selectVoucherCodes = (state) => state.booking.voucherCodes;
|
|
20099
|
+
const selectCalculateDeposit = (state) => state.booking.calculateDeposit;
|
|
20100
|
+
const selectShowCommission = (state) => state.booking.showCommission;
|
|
20101
|
+
const selectIsRetry = (state) => state.booking.isRetry;
|
|
20102
|
+
const selectStartDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.fromDate;
|
|
20103
|
+
const selectEndDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.toDate;
|
|
20104
|
+
const selectAgents = (state) => state.booking.agents;
|
|
20105
|
+
const selectCountries = (state) => state.booking.countries;
|
|
20106
|
+
const selectProductCode = (state) => state.booking.productAttributes?.productCode;
|
|
20107
|
+
const selectAccommodationCodes = (state) => {
|
|
20108
|
+
const accommodationCodes = [];
|
|
20109
|
+
state.booking.package?.options.forEach((o) => {
|
|
20110
|
+
o.rooms.forEach((r) => r.options.forEach((ro) => {
|
|
20111
|
+
if (!accommodationCodes.some((y) => y === ro.accommodationCode)) {
|
|
20112
|
+
accommodationCodes.push(ro.accommodationCode);
|
|
20113
|
+
}
|
|
20114
|
+
}));
|
|
20115
|
+
});
|
|
20116
|
+
return accommodationCodes;
|
|
20117
|
+
};
|
|
20118
|
+
const selectAccommodationViews = (state) => state.booking.accommodationViews;
|
|
20119
|
+
const selectMappingInfo = (state) => state.booking.package?.options.find((x) => x.isSelected)?.mappingInfo;
|
|
20120
|
+
const selectBookingQuery = (state) => {
|
|
20121
|
+
const bookingAttributes = state.booking.bookingAttributes;
|
|
20122
|
+
if (!bookingAttributes) {
|
|
20123
|
+
return undefined;
|
|
20124
|
+
}
|
|
20125
|
+
const params = {};
|
|
20126
|
+
Object.entries(bookingAttributes).forEach(([key, value]) => {
|
|
20127
|
+
if (key === 'startDate' || key === 'endDate') {
|
|
20128
|
+
value = format$2(parseISO(value), 'yyyy-MM-dd');
|
|
20129
|
+
}
|
|
20130
|
+
if (key === 'rooms') {
|
|
20131
|
+
value = JsonURL.stringify(value.map((room) => omit(room, ['children'])), {
|
|
20132
|
+
AQF: true
|
|
20133
|
+
});
|
|
20134
|
+
}
|
|
20135
|
+
if (key === 'allotmentIds' && !value.length) {
|
|
20136
|
+
value = undefined;
|
|
20137
|
+
}
|
|
20138
|
+
if (key === 'flight' && value) {
|
|
20139
|
+
var flightInfo = value;
|
|
20140
|
+
value = JsonURL.stringify(flightInfo, { AQF: true });
|
|
20141
|
+
}
|
|
20142
|
+
if (value) {
|
|
20143
|
+
params[key] = value;
|
|
20144
|
+
}
|
|
20145
|
+
});
|
|
20146
|
+
return params;
|
|
20147
|
+
};
|
|
20148
|
+
const selectBookingQueryString = createSelector(selectBookingQuery, (params) => {
|
|
20149
|
+
if (!params) {
|
|
20150
|
+
return undefined;
|
|
20151
|
+
}
|
|
20152
|
+
return Object.keys(params)
|
|
20153
|
+
.filter((key) => typeof params[key] !== 'undefined')
|
|
20154
|
+
.map((key) => `${key}=${params[key]}`)
|
|
20155
|
+
.join('&');
|
|
20156
|
+
});
|
|
20157
|
+
createSelector(selectTravelersFormValues, (formValues) => formValues?.mainBookerId);
|
|
20158
|
+
const selectBookingPackagePax = createSelector(selectTravelersFormValues, (formValues) => {
|
|
20159
|
+
var pax = [];
|
|
20160
|
+
formValues?.rooms.forEach((r) => r.adults.forEach((x) => {
|
|
20161
|
+
const adultPax = buildPax(x, formValues?.mainBookerId);
|
|
20162
|
+
if (adultPax.isMainBooker) {
|
|
20163
|
+
adultPax.mobilePhone = formValues?.phone;
|
|
20164
|
+
adultPax.email = formValues?.email;
|
|
20165
|
+
}
|
|
20166
|
+
pax.push(adultPax);
|
|
20167
|
+
}));
|
|
20168
|
+
formValues?.rooms.forEach((r) => r.children.forEach((x) => {
|
|
20169
|
+
pax.push(buildPax(x));
|
|
20170
|
+
}));
|
|
20171
|
+
return pax;
|
|
20172
|
+
});
|
|
20173
|
+
const selectBookingAddress = createSelector(selectTravelersFormValues, selectBookingPackagePax, selectBookingType, (formValues, pax, bookingType) => {
|
|
20174
|
+
const mainBooker = pax.find((x) => x.isMainBooker);
|
|
20175
|
+
if (!mainBooker || bookingType == 'b2b')
|
|
20176
|
+
return undefined;
|
|
20177
|
+
// The backend treats the main booker's per-pax address as authoritative, so keep the
|
|
20178
|
+
// booking-level address in sync with it rather than sending two independent values.
|
|
20179
|
+
const mainBookerAddress = mainBooker.address;
|
|
20180
|
+
return {
|
|
20181
|
+
name: `${mainBooker.firstName} ${mainBooker.lastName}`,
|
|
20182
|
+
street: mainBookerAddress?.street || formValues?.street,
|
|
20183
|
+
number: mainBookerAddress?.number || formValues?.houseNumber,
|
|
20184
|
+
box: formValues?.box,
|
|
20185
|
+
postalCode: mainBookerAddress?.postalCode || formValues?.zipCode,
|
|
20186
|
+
location: mainBookerAddress?.location || formValues?.place,
|
|
20187
|
+
country: mainBookerAddress?.country || formValues?.country,
|
|
20188
|
+
mobilePhone: formValues?.phone,
|
|
20189
|
+
email: formValues?.email
|
|
20190
|
+
};
|
|
20191
|
+
});
|
|
20192
|
+
const selectBookingPackageRequest = createSelector(selectOfficeId, selectAgentId, selectAgentAdressId, (officeId, agentId, agentAdressId) => {
|
|
20193
|
+
const agencyId = (agentId ?? agentAdressId ?? 0) > 0 ? agentId ?? agentAdressId : null;
|
|
20194
|
+
return {
|
|
20195
|
+
officeId: officeId,
|
|
20196
|
+
agentId: agencyId,
|
|
20197
|
+
payload: null
|
|
20198
|
+
};
|
|
20199
|
+
});
|
|
20200
|
+
const selectBookingPackageBookRequest = createSelector(selectBookingPackageRequest, selectBookingOptions, selectBookingType, selectBookingPackagePax, selectBookingAddress, selectPackageDetails, selectCalculateDeposit, selectShowCommission, selectAgentId, selectGeneratePaymentUrl, selectSkipPaymentWithAgent, selectNotifications, selectTagIds, selectBookingRemarks, selectVoucherCodes, (bookingPackageRequest, bookingOptions, bookingType, pax, address, packageDetails, calculateDeposit, showCommission, agentId, generatePaymentUrl, skipPaymentWithAgent, notifications, tagIds, remarks, voucherCodes) => {
|
|
19063
20201
|
if (!packageDetails)
|
|
19064
20202
|
return null;
|
|
19065
20203
|
let returnPaymentUrl = false;
|
|
@@ -19122,22 +20260,11 @@ const selectBookingPackageBookRequest = createSelector(selectBookingPackageReque
|
|
|
19122
20260
|
return bookingPackageRequest;
|
|
19123
20261
|
});
|
|
19124
20262
|
const selectTravelersFirstStep = (state) => state.booking.travelersFirstStep;
|
|
19125
|
-
const buildPax = (traveler, mainBookerId) => {
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19130
|
-
lastName: traveler.lastName,
|
|
19131
|
-
dateOfBirth: traveler.birthDate,
|
|
19132
|
-
age: traveler.birthDate ? null : traveler.age,
|
|
19133
|
-
isMainBooker: traveler.id == mainBookerId,
|
|
19134
|
-
weight: traveler.weight ?? null,
|
|
19135
|
-
weightType: traveler.weightType ?? build.WeightType.kilograms,
|
|
19136
|
-
height: traveler.height ?? null,
|
|
19137
|
-
heightType: traveler.heightType ?? build.HeightType.centimeters,
|
|
19138
|
-
customFields: traveler.customFields ?? []
|
|
19139
|
-
};
|
|
19140
|
-
};
|
|
20263
|
+
const buildPax = (traveler, mainBookerId) => applyTravelerToPax({
|
|
20264
|
+
id: traveler.id,
|
|
20265
|
+
gender: parseGender(traveler.gender),
|
|
20266
|
+
age: traveler.birthDate ? null : traveler.age
|
|
20267
|
+
}, traveler, mainBookerId);
|
|
19141
20268
|
const parseGender = (gender) => {
|
|
19142
20269
|
switch (gender) {
|
|
19143
20270
|
case 'm':
|
|
@@ -19645,9 +20772,7 @@ const SettingsContext = React__default.createContext({
|
|
|
19645
20772
|
travellers: {
|
|
19646
20773
|
pathSuffix: '/reizigers',
|
|
19647
20774
|
travelersFirstStep: false,
|
|
19648
|
-
showAllCountries: false
|
|
19649
|
-
showWeightField: false,
|
|
19650
|
-
showHeightField: false
|
|
20775
|
+
showAllCountries: false
|
|
19651
20776
|
},
|
|
19652
20777
|
summary: {
|
|
19653
20778
|
pathSuffix: '/samenvatting',
|
|
@@ -22724,1072 +23849,440 @@ const SummaryPerPaxOptionGroup = ({ group }) => {
|
|
|
22724
23849
|
opt.line.accommodationName,
|
|
22725
23850
|
!isNil(opt.line?.regimeName) && ', ',
|
|
22726
23851
|
opt.line.regimeName)),
|
|
22727
|
-
getDateText(opt.line.startDate),
|
|
22728
|
-
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
22729
|
-
React__default.createElement("ul", { className: "list" }, !isEmpty$1(opt?.groups) &&
|
|
22730
|
-
opt?.groups.map((x) => {
|
|
22731
|
-
if (!x.options.some((y) => y.isSelected))
|
|
22732
|
-
return;
|
|
22733
|
-
return React__default.createElement(SummaryPerPaxOptionGroup, { group: x });
|
|
22734
|
-
})))))));
|
|
22735
|
-
return (React__default.createElement(React__default.Fragment, null, group.title ? (React__default.createElement("li", { className: "list__item" },
|
|
22736
|
-
React__default.createElement("h6", null, group.title),
|
|
22737
|
-
React__default.createElement("ul", { className: "list" }, renderOptions()))) : (React__default.createElement(React__default.Fragment, null, renderOptions()))));
|
|
22738
|
-
};
|
|
22739
|
-
|
|
22740
|
-
const SummaryBookingOptionPax = ({ pax }) => {
|
|
22741
|
-
return (React__default.createElement(React__default.Fragment, null, pax.groups.map((y, i) => {
|
|
22742
|
-
const paxOptions = y.options.filter((y) => y.isSelected);
|
|
22743
|
-
if (isEmpty$1(paxOptions))
|
|
22744
|
-
return;
|
|
22745
|
-
return React__default.createElement(SummaryPerPaxOptionGroup, { key: i, group: y });
|
|
22746
|
-
})));
|
|
22747
|
-
};
|
|
22748
|
-
|
|
22749
|
-
const SummaryPerUnitOptionGroup = ({ group }) => {
|
|
22750
|
-
const groupOptions = group.options.filter((x) => x.isSelected);
|
|
22751
|
-
const renderOptions = () => (React__default.createElement(React__default.Fragment, null, groupOptions.map((opt) => (React__default.createElement("li", { key: opt.line.entryLineGuid, className: "list__item" },
|
|
22752
|
-
opt.line.productName,
|
|
22753
|
-
React__default.createElement("ul", null,
|
|
22754
|
-
React__default.createElement("li", null,
|
|
22755
|
-
opt.line.accommodationName,
|
|
22756
|
-
!isNil(opt.line?.regimeName) && ', ',
|
|
22757
|
-
opt.line.regimeName)),
|
|
22758
|
-
getDateText(opt.line.startDate),
|
|
22759
|
-
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
22760
|
-
React__default.createElement("ul", null,
|
|
22761
|
-
!isEmpty$1(opt?.groups) &&
|
|
22762
|
-
opt?.groups.map((x) => {
|
|
22763
|
-
if (!x.options.some((y) => y.isSelected))
|
|
22764
|
-
return;
|
|
22765
|
-
return React__default.createElement(SummaryPerUnitOptionGroup, { group: x });
|
|
22766
|
-
}),
|
|
22767
|
-
!isEmpty$1(opt?.pax) && opt?.pax.map((x) => React__default.createElement(SummaryBookingOptionPax, { pax: x }))))))));
|
|
22768
|
-
return (React__default.createElement(React__default.Fragment, null, group.title ? (React__default.createElement("li", { className: "list__item" },
|
|
22769
|
-
React__default.createElement("h6", null, group.title),
|
|
22770
|
-
React__default.createElement("ul", { className: "list" }, renderOptions()))) : (React__default.createElement(React__default.Fragment, null, renderOptions()))));
|
|
22771
|
-
};
|
|
22772
|
-
|
|
22773
|
-
const SummaryBookingOptionUnit = ({ unit }) => {
|
|
22774
|
-
return (React__default.createElement(React__default.Fragment, null, unit.groups.map((y) => {
|
|
22775
|
-
const unitOptions = y.options.filter((y) => y.isSelected);
|
|
22776
|
-
if (isEmpty$1(unitOptions))
|
|
22777
|
-
return;
|
|
22778
|
-
return React__default.createElement(SummaryPerUnitOptionGroup, { group: y });
|
|
22779
|
-
})));
|
|
22780
|
-
};
|
|
22781
|
-
|
|
22782
|
-
const SummaryFlight = ({ flightMetaData, header }) => {
|
|
22783
|
-
const translations = useSelector(selectTranslations);
|
|
22784
|
-
return (React__default.createElement("li", null,
|
|
22785
|
-
React__default.createElement("h6", null, header),
|
|
22786
|
-
parseFlightLines(flightMetaData)?.map((flightLine) => (React__default.createElement("p", { key: flightLine.departureAirportIata },
|
|
22787
|
-
flightLine.departureAirportDescription,
|
|
22788
|
-
" (",
|
|
22789
|
-
flightLine.departureAirportIata,
|
|
22790
|
-
") > ",
|
|
22791
|
-
flightLine.arrivalAirportDescription,
|
|
22792
|
-
" (",
|
|
22793
|
-
flightLine.arrivalAirportIata,
|
|
22794
|
-
") ",
|
|
22795
|
-
' - ',
|
|
22796
|
-
flightLine.travelClass,
|
|
22797
|
-
" ",
|
|
22798
|
-
' - ',
|
|
22799
|
-
flightLine.airlineCode,
|
|
22800
|
-
flightLine.number,
|
|
22801
|
-
React__default.createElement("br", null),
|
|
22802
|
-
getDateText(flightLine.departureDate),
|
|
22803
|
-
" ",
|
|
22804
|
-
flightLine.departureTime,
|
|
22805
|
-
" > ",
|
|
22806
|
-
getDateText(flightLine.arrivalDate),
|
|
22807
|
-
" ",
|
|
22808
|
-
flightLine.arrivalTime,
|
|
22809
|
-
React__default.createElement("br", null),
|
|
22810
|
-
flightLine.airlineDescription))),
|
|
22811
|
-
flightMetaData.luggageIncluded && React__default.createElement("p", null, translations.SIDEBAR.LUGGAGE_INCLUDED)));
|
|
22812
|
-
};
|
|
22813
|
-
|
|
22814
|
-
const SummaryPerBookingOptionGroup = ({ group }) => {
|
|
22815
|
-
const groupOptions = group.options.filter((x) => x.isSelected);
|
|
22816
|
-
const renderOptions = () => (React__default.createElement(React__default.Fragment, null, groupOptions.map((opt) => (React__default.createElement("li", { key: opt.line.entryLineGuid, className: "list__item" },
|
|
22817
|
-
opt.line.productName,
|
|
22818
|
-
React__default.createElement("ul", null,
|
|
22819
|
-
React__default.createElement("li", null,
|
|
22820
|
-
opt.line.accommodationName,
|
|
22821
|
-
!isNil(opt.line?.regimeName) && ', ',
|
|
22822
|
-
opt.line.regimeName)),
|
|
22823
|
-
getDateText(opt.line.startDate),
|
|
22824
|
-
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
22825
|
-
React__default.createElement("ul", null,
|
|
22826
|
-
!isEmpty$1(opt?.groups) &&
|
|
22827
|
-
opt?.groups.map((x) => {
|
|
22828
|
-
if (!x.options.some((y) => y.isSelected))
|
|
22829
|
-
return;
|
|
22830
|
-
return React__default.createElement(SummaryPerBookingOptionGroup, { group: x });
|
|
22831
|
-
}),
|
|
22832
|
-
!isEmpty$1(opt?.units) && opt?.units.map((x) => React__default.createElement(SummaryBookingOptionUnit, { unit: x })),
|
|
22833
|
-
!isEmpty$1(opt?.pax) && opt?.pax.map((x) => React__default.createElement(SummaryBookingOptionPax, { pax: x }))))))));
|
|
22834
|
-
return (React__default.createElement(React__default.Fragment, null, group.title ? (React__default.createElement("li", { className: "list__item" },
|
|
22835
|
-
React__default.createElement("h6", null, group.title),
|
|
22836
|
-
React__default.createElement("ul", { className: "list" }, renderOptions()))) : (React__default.createElement(React__default.Fragment, null, renderOptions()))));
|
|
22837
|
-
};
|
|
22838
|
-
|
|
22839
|
-
const Summary = () => {
|
|
22840
|
-
const dispatch = useAppDispatch();
|
|
22841
|
-
const settings = useContext(SettingsContext);
|
|
22842
|
-
const navigate = settings.skipRouter ? () => { } : useNavigate();
|
|
22843
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
22844
|
-
const [checkboxes, setCheckboxes] = useState(settings.summary?.checkboxes);
|
|
22845
|
-
const [remarks, setRemarks] = useState('');
|
|
22846
|
-
const [voucher, setVoucher] = useState({});
|
|
22847
|
-
const bookingQueryString = useSelector(selectBookingQueryString);
|
|
22848
|
-
const travelersFirstStep = useSelector(selectTravelersFirstStep);
|
|
22849
|
-
const travelerFormValues = useSelector(selectTravelersFormValues);
|
|
22850
|
-
const packageDetails = useSelector(selectPackageDetails);
|
|
22851
|
-
const activeOption = useSelector(selectActiveOption);
|
|
22852
|
-
const apiSettings = useSelector(selectApiSettings);
|
|
22853
|
-
const languageCode = useSelector(selectLanguageCode);
|
|
22854
|
-
const officeId = useSelector(selectOfficeId);
|
|
22855
|
-
const agentId = useSelector(selectAgentAdressId);
|
|
22856
|
-
const departureFlight = useSelector(selectDepartureFlight);
|
|
22857
|
-
const departureFlightMetaData = departureFlight?.flightMetaData ?? useSelector(selectRoomOptionDepartureFlightsMetaData)?.[0];
|
|
22858
|
-
const returnFlight = useSelector(selectReturnFlight);
|
|
22859
|
-
const returnFlightMetaData = returnFlight?.flightMetaData ?? useSelector(selectRoomOptionReturnFlightsMetaData)?.[0];
|
|
22860
|
-
if (!travelerFormValues) {
|
|
22861
|
-
if (settings.skipRouter) {
|
|
22862
|
-
dispatch(setCurrentStep$1(TRAVELERS_FORM_STEP));
|
|
22863
|
-
}
|
|
22864
|
-
else {
|
|
22865
|
-
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}?${bookingQueryString}`);
|
|
22866
|
-
}
|
|
22867
|
-
}
|
|
22868
|
-
const rooms = useSelector(selectRooms);
|
|
22869
|
-
const userValidated = useSelector(selectUserValidated);
|
|
22870
|
-
const notifications = useSelector(selectNotifications);
|
|
22871
|
-
const bookRequest = useSelector(selectBookingPackageBookRequest);
|
|
22872
|
-
useEffect(() => {
|
|
22873
|
-
// Every checkbox should be checked, or no checkboxes
|
|
22874
|
-
const checkboxesValidated = !isNil(checkboxes) ? checkboxes.every((checkbox) => checkbox.isSelected) : true;
|
|
22875
|
-
const notificationsValidated = !isNil(notifications) ? notifications.filter((x) => x.hasToBeConfirmed).every((checkbox) => checkbox.isConfirmed) : true;
|
|
22876
|
-
dispatch(setUserValidated(checkboxesValidated && notificationsValidated));
|
|
22877
|
-
}, [checkboxes, notifications]);
|
|
22878
|
-
const handleSubmit = async (e) => {
|
|
22879
|
-
e.preventDefault();
|
|
22880
|
-
const submitter = e.nativeEvent.submitter?.name;
|
|
22881
|
-
setIsSubmitting(true);
|
|
22882
|
-
if (typeof window !== 'undefined') {
|
|
22883
|
-
window.scrollTo(0, 0);
|
|
22884
|
-
}
|
|
22885
|
-
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
22886
|
-
if (!bookRequest || !tideClientConfig) {
|
|
22887
|
-
return;
|
|
22888
|
-
}
|
|
22889
|
-
if (bookRequest.payload.returnPaymentUrl) {
|
|
22890
|
-
if (typeof window !== 'undefined') {
|
|
22891
|
-
window.scrollTo(0, 0);
|
|
22892
|
-
if (settings.paymentRedirectUrl) {
|
|
22893
|
-
bookRequest.payload.redirectUrl = settings.paymentRedirectUrl;
|
|
22894
|
-
}
|
|
22895
|
-
else {
|
|
22896
|
-
const location = window.location;
|
|
22897
|
-
bookRequest.payload.redirectUrl = `${location.protocol}//${location.host}${settings.basePath ?? location.pathname}?${bookingQueryString}`;
|
|
22898
|
-
}
|
|
22899
|
-
}
|
|
22900
|
-
}
|
|
22901
|
-
try {
|
|
22902
|
-
if (submitter === 'option') {
|
|
22903
|
-
bookRequest.payload.status = build.EntryStatus.option;
|
|
22904
|
-
bookRequest.payload.customStatusId = settings.customOptionStatus;
|
|
22905
|
-
dispatch(setIsOption(true));
|
|
22906
|
-
}
|
|
22907
|
-
const bookingResponse = await build.book(tideClientConfig, bookRequest, undefined, languageCode);
|
|
22908
|
-
// Booking successfull
|
|
22909
|
-
dispatch(setBookingNumber$1(bookingResponse.number));
|
|
22910
|
-
if (bookingResponse.paymentUrl) {
|
|
22911
|
-
const event = new CustomEvent('tide-booking-payment-url', {
|
|
22912
|
-
detail: {
|
|
22913
|
-
paymentUrl: bookingResponse.paymentUrl,
|
|
22914
|
-
bookingNumber: bookingResponse.number
|
|
22915
|
-
},
|
|
22916
|
-
cancelable: true,
|
|
22917
|
-
bubbles: true
|
|
22918
|
-
});
|
|
22919
|
-
const target = typeof document !== 'undefined' ? document.getElementById('tide-booking') ?? window : window;
|
|
22920
|
-
const shouldAutoRedirect = target.dispatchEvent(event);
|
|
22921
|
-
if (shouldAutoRedirect) {
|
|
22922
|
-
window.location.href = bookingResponse.paymentUrl;
|
|
22923
|
-
}
|
|
22924
|
-
}
|
|
22925
|
-
else {
|
|
22926
|
-
if (settings.skipRouter) {
|
|
22927
|
-
dispatch(setCurrentStep$1(CONFIRMATION_STEP));
|
|
22928
|
-
}
|
|
22929
|
-
else {
|
|
22930
|
-
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.confirmation.pathSuffix}?${bookingQueryString}`);
|
|
22931
|
-
}
|
|
22932
|
-
}
|
|
22933
|
-
}
|
|
22934
|
-
catch (error) {
|
|
22935
|
-
if (settings.skipRouter) {
|
|
22936
|
-
dispatch(setCurrentStep$1(ERROR_STEP));
|
|
22937
|
-
}
|
|
22938
|
-
else {
|
|
22939
|
-
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.error.pathSuffix}?${bookingQueryString}`);
|
|
22940
|
-
}
|
|
22941
|
-
}
|
|
22942
|
-
finally {
|
|
22943
|
-
setIsSubmitting(false);
|
|
22944
|
-
}
|
|
22945
|
-
};
|
|
22946
|
-
const handleNotificationChange = (id, checked) => {
|
|
22947
|
-
const updatedNotifications = notifications.map((notification) => (notification.id === id ? { ...notification, isConfirmed: checked } : notification));
|
|
22948
|
-
dispatch(setNotifications(updatedNotifications));
|
|
22949
|
-
};
|
|
22950
|
-
const handleCheckboxChange = (id, checked) => {
|
|
22951
|
-
if (isNil(checkboxes)) {
|
|
22952
|
-
return;
|
|
22953
|
-
}
|
|
22954
|
-
const newCheckboxes = [...checkboxes];
|
|
22955
|
-
const index = findIndex$1(checkboxes, (checkbox) => checkbox.id === id);
|
|
22956
|
-
newCheckboxes[index].isSelected = !newCheckboxes[index].isSelected;
|
|
22957
|
-
setCheckboxes(newCheckboxes);
|
|
22958
|
-
};
|
|
22959
|
-
const handleRemarksChange = (text) => {
|
|
22960
|
-
dispatch(setBookingRemarks(text));
|
|
22961
|
-
setRemarks(text);
|
|
22962
|
-
};
|
|
22963
|
-
const handleValidateVoucher = async () => {
|
|
22964
|
-
if (!voucher?.code)
|
|
22965
|
-
return;
|
|
22966
|
-
const request = {
|
|
22967
|
-
officeId: officeId,
|
|
22968
|
-
agentId: agentId,
|
|
22969
|
-
payload: {
|
|
22970
|
-
code: voucher.code,
|
|
22971
|
-
otherCodes: bookRequest?.payload.voucherCodes ?? []
|
|
22972
|
-
}
|
|
22973
|
-
};
|
|
22974
|
-
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
22975
|
-
if (!tideClientConfig)
|
|
22976
|
-
return;
|
|
22977
|
-
const result = await build.validateVoucher(tideClientConfig, request);
|
|
22978
|
-
if (result) {
|
|
22979
|
-
setVoucher({
|
|
22980
|
-
...voucher,
|
|
22981
|
-
isValidated: true,
|
|
22982
|
-
isValid: result.isValid
|
|
22983
|
-
});
|
|
22984
|
-
}
|
|
22985
|
-
};
|
|
22986
|
-
const handleAddVoucher = (event) => {
|
|
22987
|
-
if (!voucher.isValid)
|
|
22988
|
-
return;
|
|
22989
|
-
dispatch(setVoucherCodes([...(bookRequest?.payload.voucherCodes ?? []), voucher.code ?? ''].filter((x) => x !== '')));
|
|
22990
|
-
dispatch(fetchPriceDetails());
|
|
22991
|
-
setVoucher({});
|
|
22992
|
-
};
|
|
22993
|
-
const handleRemoveVoucher = (code) => {
|
|
22994
|
-
dispatch(setVoucherCodes(bookRequest?.payload.voucherCodes?.filter((x) => x !== code) ?? []));
|
|
22995
|
-
dispatch(fetchPriceDetails());
|
|
22996
|
-
};
|
|
22997
|
-
const goPrevious = () => {
|
|
22998
|
-
dispatch(setCurrentStep$1(travelersFirstStep ? OPTIONS_FORM_STEP : TRAVELERS_FORM_STEP));
|
|
22999
|
-
};
|
|
23000
|
-
const translations = useSelector(selectTranslations);
|
|
23001
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
23002
|
-
isSubmitting && (settings.loaderComponent || React__default.createElement(Loader, null)),
|
|
23003
|
-
!isSubmitting && (React__default.createElement("form", { className: "form", name: "booking--summary", id: "booking--summary", onSubmit: handleSubmit },
|
|
23004
|
-
React__default.createElement("div", { className: "form__booking--summary" },
|
|
23005
|
-
React__default.createElement("div", { className: "form__region" },
|
|
23006
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23007
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23008
|
-
React__default.createElement("div", { className: "form__region-header" },
|
|
23009
|
-
React__default.createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.PERSONAL_DETAILS)))),
|
|
23010
|
-
rooms.map((r, rIndex) => (React__default.createElement("div", { className: "form__row", key: rIndex },
|
|
23011
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23012
|
-
React__default.createElement("div", { className: "form__region-header" },
|
|
23013
|
-
React__default.createElement("h5", { className: "form__region-heading" }, rooms.length > 1 ? `${translations.SHARED.ROOM} ${rIndex + 1}` : translations.ROOM_OPTIONS_FORM.TRAVELER_GROUP),
|
|
23014
|
-
React__default.createElement("p", { className: "form__region-label" }, `${r.adults.length + r.children.length} ${r.adults.length + r.children.length === 1 ? translations.SUMMARY.TRAVELER : translations.SUMMARY.TRAVELERS}: ${compact([
|
|
23015
|
-
r.adults.length,
|
|
23016
|
-
r.adults.length === 1 && ` ${translations.SUMMARY.ADULT}`,
|
|
23017
|
-
r.adults.length > 1 && ` ${translations.SUMMARY.ADULTS}`,
|
|
23018
|
-
r.adults && r.adults.length && r.children && r.children.length && ', ',
|
|
23019
|
-
r.children.length,
|
|
23020
|
-
r.children.length === 1 && ` ${translations.SUMMARY.CHILD}`,
|
|
23021
|
-
r.children.length > 1 && ` ${translations.SUMMARY.CHILDREN}`
|
|
23022
|
-
]).join('')}`))),
|
|
23023
|
-
[...r.adults, ...r.children].map((traveler) => {
|
|
23024
|
-
const isMainBooker = traveler.id === travelerFormValues?.mainBookerId;
|
|
23025
|
-
return (React__default.createElement("div", { className: "form__group form__group--sm-50", key: traveler.id },
|
|
23026
|
-
React__default.createElement("ul", { className: "list list--plain" },
|
|
23027
|
-
React__default.createElement("li", { className: "list__item" },
|
|
23028
|
-
React__default.createElement("strong", null,
|
|
23029
|
-
traveler.firstName,
|
|
23030
|
-
" ",
|
|
23031
|
-
traveler.lastName),
|
|
23032
|
-
' ',
|
|
23033
|
-
isMainBooker && React__default.createElement("em", null,
|
|
23034
|
-
"(",
|
|
23035
|
-
translations.SUMMARY.MAIN_BOOKER,
|
|
23036
|
-
")")),
|
|
23037
|
-
React__default.createElement("li", { className: "list__item" }, traveler.birthDate.split('-').reverse().join('/')),
|
|
23038
|
-
isMainBooker && (React__default.createElement(React__default.Fragment, null,
|
|
23039
|
-
travelerFormValues?.street && (React__default.createElement(React__default.Fragment, null,
|
|
23040
|
-
React__default.createElement("li", { className: "list__item" }, `${travelerFormValues?.street} ${compact([
|
|
23041
|
-
travelerFormValues?.houseNumber,
|
|
23042
|
-
travelerFormValues?.box
|
|
23043
|
-
]).join(' ')}, ${travelerFormValues?.zipCode} ${travelerFormValues?.place}`))),
|
|
23044
|
-
travelerFormValues?.phone && React__default.createElement("li", { className: "list__item" }, travelerFormValues?.phone),
|
|
23045
|
-
travelerFormValues?.email && React__default.createElement("li", { className: "list__item" }, travelerFormValues?.email))))));
|
|
23046
|
-
}))))),
|
|
23047
|
-
React__default.createElement("div", { className: "form__region" },
|
|
23048
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23049
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23050
|
-
React__default.createElement("div", { className: "form__region-header" },
|
|
23051
|
-
React__default.createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.OPTIONS)))),
|
|
23052
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23053
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23054
|
-
React__default.createElement("ul", { className: "list list--booking-summary" }, activeOption?.serviceType == build.ServiceType.flight ? (React__default.createElement(React__default.Fragment, null,
|
|
23055
|
-
departureFlightMetaData && React__default.createElement(SummaryFlight, { flightMetaData: departureFlightMetaData, header: translations.SIDEBAR.DEPARTURE_FLIGHT }),
|
|
23056
|
-
returnFlightMetaData && React__default.createElement(SummaryFlight, { flightMetaData: returnFlightMetaData, header: translations.SIDEBAR.ARRIVAL_FLIGHT }))) : (React__default.createElement(React__default.Fragment, null, activeOption?.rooms
|
|
23057
|
-
.flatMap((r) => r.options)
|
|
23058
|
-
.filter((x) => x.isSelected)
|
|
23059
|
-
.map((roomOption, roomOptionIndex) => (React__default.createElement(React__default.Fragment, { key: roomOptionIndex },
|
|
23060
|
-
React__default.createElement("li", null,
|
|
23061
|
-
React__default.createElement("h6", null, roomOption?.productName),
|
|
23062
|
-
React__default.createElement("ul", null,
|
|
23063
|
-
React__default.createElement("li", { className: "list__item" },
|
|
23064
|
-
roomOption?.accommodationName,
|
|
23065
|
-
!isNil(roomOption?.regimeName) && ', ',
|
|
23066
|
-
roomOption?.regimeName)),
|
|
23067
|
-
React__default.createElement("p", null,
|
|
23068
|
-
"(",
|
|
23069
|
-
roomOption?.from === roomOption?.to ? (getDateText(roomOption?.from)) : (React__default.createElement(React__default.Fragment, null,
|
|
23070
|
-
getDateText(roomOption?.from),
|
|
23071
|
-
" > ",
|
|
23072
|
-
getDateText(roomOption?.to))),
|
|
23073
|
-
")")),
|
|
23074
|
-
!isEmpty$1(activeOption?.groups) &&
|
|
23075
|
-
activeOption?.groups.map((x, i) => {
|
|
23076
|
-
if (!x.options.some((y) => y.isSelected))
|
|
23077
|
-
return;
|
|
23078
|
-
return React__default.createElement(SummaryPerBookingOptionGroup, { key: i, group: x });
|
|
23079
|
-
}),
|
|
23080
|
-
!isEmpty$1(activeOption?.optionUnits) && activeOption?.optionUnits.map((x, i) => React__default.createElement(SummaryBookingOptionUnit, { key: i, unit: x })),
|
|
23081
|
-
!isEmpty$1(activeOption?.optionPax) && activeOption?.optionPax.map((x, i) => React__default.createElement(SummaryBookingOptionPax, { key: i, pax: x })),
|
|
23082
|
-
packageDetails?.outwardFlights &&
|
|
23083
|
-
packageDetails.outwardFlights
|
|
23084
|
-
.filter((x) => x.isSelected)
|
|
23085
|
-
.map((flight, i) => (React__default.createElement(SummaryFlight, { key: i, flightMetaData: flight.flightMetaData, header: translations.SIDEBAR.DEPARTURE_FLIGHT }))),
|
|
23086
|
-
packageDetails?.returnFlights &&
|
|
23087
|
-
packageDetails.returnFlights
|
|
23088
|
-
.filter((x) => x.isSelected)
|
|
23089
|
-
.map((flight, i) => (React__default.createElement(SummaryFlight, { key: i, flightMetaData: flight.flightMetaData, header: translations.SIDEBAR.ARRIVAL_FLIGHT })))))))))))),
|
|
23090
|
-
settings.enableVoucher && (React__default.createElement("div", { className: "form__region" },
|
|
23091
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23092
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23093
|
-
React__default.createElement("div", { className: "form__region-header" },
|
|
23094
|
-
React__default.createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.VOUCHERS)))),
|
|
23095
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23096
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23097
|
-
React__default.createElement("input", { type: "text", className: "form__input info-message__voucher__input", defaultValue: voucher.code, onChange: (e) => setVoucher({ code: e.target.value }) }),
|
|
23098
|
-
React__default.createElement("button", { type: "button", className: buildClassName(['cta', !voucher.code && 'cta--disabled']), onClick: (e) => handleValidateVoucher() }, translations.SUMMARY.VOUCHER_VALIDATE))),
|
|
23099
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23100
|
-
React__default.createElement("div", { className: "form__group info-message__voucher" },
|
|
23101
|
-
voucher.isValid && voucher.isValidated && (React__default.createElement("div", { className: "info-message info-message__voucher__valid" },
|
|
23102
|
-
React__default.createElement("span", null, translations.SUMMARY.VOUCHER_VALID),
|
|
23103
|
-
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: handleAddVoucher }, translations.SUMMARY.ADD_VOUCHER))),
|
|
23104
|
-
!voucher.isValid && voucher.isValidated && React__default.createElement("div", { className: "info-message--error" }, translations.SUMMARY.VOUCHER_INVALID))),
|
|
23105
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23106
|
-
React__default.createElement("ul", { className: "info-message__voucher" }, !isEmpty$1(bookRequest?.payload.voucherCodes) &&
|
|
23107
|
-
bookRequest?.payload.voucherCodes?.map((y, i) => (React__default.createElement("li", { key: i },
|
|
23108
|
-
React__default.createElement("div", { className: "info-message__voucher__list" },
|
|
23109
|
-
y,
|
|
23110
|
-
' ',
|
|
23111
|
-
React__default.createElement("button", { type: "button", className: "cta--add-remove", onClick: (e) => handleRemoveVoucher(y) },
|
|
23112
|
-
React__default.createElement(Icon, { height: 16, name: "ui-trashcan" })))))))))),
|
|
23113
|
-
!isEmpty$1(notifications) && (React__default.createElement("div", { className: "form__region" },
|
|
23114
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23115
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23116
|
-
React__default.createElement("div", { className: "info-message" },
|
|
23117
|
-
React__default.createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
|
|
23118
|
-
React__default.createElement("div", { className: "info-message__copy" },
|
|
23119
|
-
React__default.createElement("h5", null, translations.SUMMARY.NOTIFICATIONS_TITLE),
|
|
23120
|
-
React__default.createElement(React__default.Fragment, null,
|
|
23121
|
-
uniqBy(notifications.filter((x) => !x.hasToBeConfirmed), 'id').map((notification) => (React__default.createElement("span", { key: notification.id, className: "checkbox__label-text" },
|
|
23122
|
-
React__default.createElement("strong", { className: "checkbox__label-text--title" }, notification.title),
|
|
23123
|
-
React__default.createElement("span", { className: "checkbox__label-text--description" }, notification.description)))),
|
|
23124
|
-
uniqBy(notifications.filter((x) => x.hasToBeConfirmed), 'id').map((notification) => (React__default.createElement("div", { className: "checkbox", key: notification.id },
|
|
23125
|
-
React__default.createElement("label", { className: "checkbox__label" },
|
|
23126
|
-
React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: notification.isConfirmed, onChange: (e) => handleNotificationChange(notification.id, e.target.checked) }),
|
|
23127
|
-
React__default.createElement("span", { className: "checkbox__label-text" },
|
|
23128
|
-
React__default.createElement("strong", { className: "checkbox__label-text--title" }, notification.title),
|
|
23129
|
-
React__default.createElement("span", { className: "checkbox__label-text--description" }, notification.description))))))))))))),
|
|
23130
|
-
React__default.createElement("div", { className: "form__region" },
|
|
23131
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23132
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23133
|
-
React__default.createElement("div", { className: "form__region-header" },
|
|
23134
|
-
React__default.createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.REMARKS)))),
|
|
23135
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23136
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23137
|
-
React__default.createElement("textarea", { className: "form__input", defaultValue: remarks, onChange: (e) => handleRemarksChange(e.target.value) })))),
|
|
23138
|
-
React__default.createElement("div", { className: "form__region" },
|
|
23139
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23140
|
-
React__default.createElement("div", { className: "form__group" },
|
|
23141
|
-
React__default.createElement("div", { className: "info-message" },
|
|
23142
|
-
React__default.createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
|
|
23143
|
-
React__default.createElement("div", { className: "info-message__copy" },
|
|
23144
|
-
React__default.createElement("h5", null, translations.SUMMARY.VALIDATE_TITLE),
|
|
23145
|
-
settings.customValidateText ? (React__default.createElement("div", { dangerouslySetInnerHTML: {
|
|
23146
|
-
__html: settings.customValidateText
|
|
23147
|
-
} })) : (React__default.createElement(React__default.Fragment, null,
|
|
23148
|
-
React__default.createElement("p", null, settings.isOffer ? translations.SUMMARY.VALIDATE_TEXT_OFFER : translations.SUMMARY.VALIDATE_TEXT_BOOKING),
|
|
23149
|
-
settings.allowOption && React__default.createElement("p", null, translations.SUMMARY.VALIDATE_TEXT_OPTION))),
|
|
23150
|
-
checkboxes &&
|
|
23151
|
-
checkboxes.map((checkbox) => (React__default.createElement("div", { className: "checkbox", key: checkbox.id },
|
|
23152
|
-
React__default.createElement("label", { className: "checkbox__label" },
|
|
23153
|
-
React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: checkbox.isSelected, onChange: (e) => handleCheckboxChange(checkbox.id, e.target.checked) }),
|
|
23154
|
-
React__default.createElement("span", { className: "checkbox__label-text", dangerouslySetInnerHTML: {
|
|
23155
|
-
__html: checkbox.text
|
|
23156
|
-
} }))))))))))),
|
|
23157
|
-
React__default.createElement("div", { className: "booking__navigator" },
|
|
23158
|
-
settings.skipRouter ? (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => goPrevious(), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : (React__default.createElement(Link, { to: `${!settings.skipBasePathInRouting ? settings.basePath : ''}${travelersFirstStep ? settings.options.pathSuffix : settings.travellers.pathSuffix}?${bookingQueryString}`, title: translations.STEPS.PREVIOUS, className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)),
|
|
23159
|
-
settings.allowOption && (React__default.createElement("button", { title: translations.STEPS.SUBMIT_OPTION, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "option" }, translations.STEPS.SUBMIT_OPTION)),
|
|
23160
|
-
React__default.createElement("button", { title: settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "default" }, settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING))))));
|
|
23852
|
+
getDateText(opt.line.startDate),
|
|
23853
|
+
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
23854
|
+
React__default.createElement("ul", { className: "list" }, !isEmpty$1(opt?.groups) &&
|
|
23855
|
+
opt?.groups.map((x) => {
|
|
23856
|
+
if (!x.options.some((y) => y.isSelected))
|
|
23857
|
+
return;
|
|
23858
|
+
return React__default.createElement(SummaryPerPaxOptionGroup, { group: x });
|
|
23859
|
+
})))))));
|
|
23860
|
+
return (React__default.createElement(React__default.Fragment, null, group.title ? (React__default.createElement("li", { className: "list__item" },
|
|
23861
|
+
React__default.createElement("h6", null, group.title),
|
|
23862
|
+
React__default.createElement("ul", { className: "list" }, renderOptions()))) : (React__default.createElement(React__default.Fragment, null, renderOptions()))));
|
|
23161
23863
|
};
|
|
23162
23864
|
|
|
23163
|
-
const
|
|
23164
|
-
return (React__default.createElement(
|
|
23165
|
-
|
|
23166
|
-
|
|
23865
|
+
const SummaryBookingOptionPax = ({ pax }) => {
|
|
23866
|
+
return (React__default.createElement(React__default.Fragment, null, pax.groups.map((y, i) => {
|
|
23867
|
+
const paxOptions = y.options.filter((y) => y.isSelected);
|
|
23868
|
+
if (isEmpty$1(paxOptions))
|
|
23869
|
+
return;
|
|
23870
|
+
return React__default.createElement(SummaryPerPaxOptionGroup, { key: i, group: y });
|
|
23871
|
+
})));
|
|
23167
23872
|
};
|
|
23168
23873
|
|
|
23169
|
-
const
|
|
23170
|
-
|
|
23171
|
-
|
|
23172
|
-
|
|
23173
|
-
|
|
23874
|
+
const SummaryPerUnitOptionGroup = ({ group }) => {
|
|
23875
|
+
const groupOptions = group.options.filter((x) => x.isSelected);
|
|
23876
|
+
const renderOptions = () => (React__default.createElement(React__default.Fragment, null, groupOptions.map((opt) => (React__default.createElement("li", { key: opt.line.entryLineGuid, className: "list__item" },
|
|
23877
|
+
opt.line.productName,
|
|
23878
|
+
React__default.createElement("ul", null,
|
|
23879
|
+
React__default.createElement("li", null,
|
|
23880
|
+
opt.line.accommodationName,
|
|
23881
|
+
!isNil(opt.line?.regimeName) && ', ',
|
|
23882
|
+
opt.line.regimeName)),
|
|
23883
|
+
getDateText(opt.line.startDate),
|
|
23884
|
+
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
23885
|
+
React__default.createElement("ul", null,
|
|
23886
|
+
!isEmpty$1(opt?.groups) &&
|
|
23887
|
+
opt?.groups.map((x) => {
|
|
23888
|
+
if (!x.options.some((y) => y.isSelected))
|
|
23889
|
+
return;
|
|
23890
|
+
return React__default.createElement(SummaryPerUnitOptionGroup, { group: x });
|
|
23891
|
+
}),
|
|
23892
|
+
!isEmpty$1(opt?.pax) && opt?.pax.map((x) => React__default.createElement(SummaryBookingOptionPax, { pax: x }))))))));
|
|
23893
|
+
return (React__default.createElement(React__default.Fragment, null, group.title ? (React__default.createElement("li", { className: "list__item" },
|
|
23894
|
+
React__default.createElement("h6", null, group.title),
|
|
23895
|
+
React__default.createElement("ul", { className: "list" }, renderOptions()))) : (React__default.createElement(React__default.Fragment, null, renderOptions()))));
|
|
23174
23896
|
};
|
|
23175
23897
|
|
|
23176
|
-
const
|
|
23177
|
-
|
|
23178
|
-
|
|
23179
|
-
|
|
23180
|
-
|
|
23181
|
-
|
|
23182
|
-
|
|
23183
|
-
const hit = sorted.find((c) => value.startsWith(c.phonePrefix));
|
|
23184
|
-
if (hit) {
|
|
23185
|
-
const rest = value
|
|
23186
|
-
.slice(hit.phonePrefix.length)
|
|
23187
|
-
.trim()
|
|
23188
|
-
.replace(/^[-\s]+/, '');
|
|
23189
|
-
return { prefix: hit.phonePrefix, number: rest };
|
|
23190
|
-
}
|
|
23191
|
-
// Fallback: split on first space if it looks like a +prefix number
|
|
23192
|
-
const m = value.match(/^(\+\d{1,4})[\s-]*(.*)$/);
|
|
23193
|
-
if (m)
|
|
23194
|
-
return { prefix: m[1], number: m[2] };
|
|
23195
|
-
return { prefix: '', number: value };
|
|
23196
|
-
};
|
|
23197
|
-
const PhoneInput = ({ name, required, value, label, placeholder, extraClassName, hasError, countries, countryIso2, onChange, onBlur }) => {
|
|
23198
|
-
// Derive initial state from `value`
|
|
23199
|
-
const initialCountry = countries.find((c) => c.iso2 === countryIso2);
|
|
23200
|
-
const initial = useMemo(() => parseCombined(normalize(value), countries), [value, countries]);
|
|
23201
|
-
const [prefix, setPrefix] = useState(initial.prefix);
|
|
23202
|
-
const [number, setNumber] = useState(initial.number);
|
|
23203
|
-
// Keep state in sync if the parent changes `value`
|
|
23204
|
-
useEffect(() => {
|
|
23205
|
-
const parsed = !prefix && !number && initialCountry ? { prefix: initialCountry.phonePrefix, number: '' } : parseCombined(normalize(value), countries);
|
|
23206
|
-
if (parsed.prefix)
|
|
23207
|
-
setPrefix(parsed.prefix);
|
|
23208
|
-
if (parsed.number)
|
|
23209
|
-
setNumber(parsed.number);
|
|
23210
|
-
}, [value, countries, countryIso2]);
|
|
23211
|
-
const emitCombinedChange = (e, nextPrefix, nextNumber) => {
|
|
23212
|
-
// Combine with a space, unless the number already starts with a dash or space
|
|
23213
|
-
const combined = nextPrefix && nextNumber ? compact([nextPrefix, nextNumber]).join(' ') : null;
|
|
23214
|
-
onChange?.({
|
|
23215
|
-
...e,
|
|
23216
|
-
type: 'change',
|
|
23217
|
-
target: { name, value: combined },
|
|
23218
|
-
currentTarget: { name, value: combined }
|
|
23219
|
-
});
|
|
23220
|
-
};
|
|
23221
|
-
const handleCountryBlur = (e) => {
|
|
23222
|
-
onBlur?.(e);
|
|
23223
|
-
};
|
|
23224
|
-
const onCountryChange = (e) => {
|
|
23225
|
-
const next = e.target.value;
|
|
23226
|
-
setPrefix(next);
|
|
23227
|
-
emitCombinedChange(e, next, number);
|
|
23228
|
-
};
|
|
23229
|
-
const onPhoneChange = (e) => {
|
|
23230
|
-
const cleaned = e.target.value.replace(/[^\d\s-]/g, '');
|
|
23231
|
-
setNumber(cleaned);
|
|
23232
|
-
emitCombinedChange(e, prefix, cleaned);
|
|
23233
|
-
};
|
|
23234
|
-
const handleNumberBlur = (e) => {
|
|
23235
|
-
onBlur?.(e);
|
|
23236
|
-
};
|
|
23237
|
-
// Ensure the select shows a reasonable default when prefix is empty
|
|
23238
|
-
const selectValue = prefix || '';
|
|
23239
|
-
return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
|
|
23240
|
-
label && React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
|
|
23241
|
-
React__default.createElement("div", { className: "phone-input" },
|
|
23242
|
-
React__default.createElement("div", { className: "dropdown" },
|
|
23243
|
-
React__default.createElement("select", { "aria-label": label ? `${label} – country code` : 'Country calling code', name: `${name}__country`, value: selectValue, onBlur: handleCountryBlur, onChange: onCountryChange },
|
|
23244
|
-
React__default.createElement("option", { value: "", disabled: true }),
|
|
23245
|
-
countries?.map((option) => (React__default.createElement("option", { key: option.iso2, value: option.phonePrefix },
|
|
23246
|
-
option.name,
|
|
23247
|
-
" (",
|
|
23248
|
-
option.phonePrefix,
|
|
23249
|
-
")"))))),
|
|
23250
|
-
React__default.createElement("input", { "aria-label": label ? `${label} – number` : 'Phone number', name: `${name}__number`, type: "tel", inputMode: "tel", required: required, className: "form__input", placeholder: placeholder, onChange: onPhoneChange, onBlur: handleNumberBlur, value: number }),
|
|
23251
|
-
React__default.createElement("input", { type: "hidden", name: name, value: compact([prefix, number]).join(' ') }))));
|
|
23898
|
+
const SummaryBookingOptionUnit = ({ unit }) => {
|
|
23899
|
+
return (React__default.createElement(React__default.Fragment, null, unit.groups.map((y) => {
|
|
23900
|
+
const unitOptions = y.options.filter((y) => y.isSelected);
|
|
23901
|
+
if (isEmpty$1(unitOptions))
|
|
23902
|
+
return;
|
|
23903
|
+
return React__default.createElement(SummaryPerUnitOptionGroup, { group: y });
|
|
23904
|
+
})));
|
|
23252
23905
|
};
|
|
23253
23906
|
|
|
23254
|
-
const
|
|
23907
|
+
const SummaryFlight = ({ flightMetaData, header }) => {
|
|
23908
|
+
const translations = useSelector(selectTranslations);
|
|
23909
|
+
return (React__default.createElement("li", null,
|
|
23910
|
+
React__default.createElement("h6", null, header),
|
|
23911
|
+
parseFlightLines(flightMetaData)?.map((flightLine) => (React__default.createElement("p", { key: flightLine.departureAirportIata },
|
|
23912
|
+
flightLine.departureAirportDescription,
|
|
23913
|
+
" (",
|
|
23914
|
+
flightLine.departureAirportIata,
|
|
23915
|
+
") > ",
|
|
23916
|
+
flightLine.arrivalAirportDescription,
|
|
23917
|
+
" (",
|
|
23918
|
+
flightLine.arrivalAirportIata,
|
|
23919
|
+
") ",
|
|
23920
|
+
' - ',
|
|
23921
|
+
flightLine.travelClass,
|
|
23922
|
+
" ",
|
|
23923
|
+
' - ',
|
|
23924
|
+
flightLine.airlineCode,
|
|
23925
|
+
flightLine.number,
|
|
23926
|
+
React__default.createElement("br", null),
|
|
23927
|
+
getDateText(flightLine.departureDate),
|
|
23928
|
+
" ",
|
|
23929
|
+
flightLine.departureTime,
|
|
23930
|
+
" > ",
|
|
23931
|
+
getDateText(flightLine.arrivalDate),
|
|
23932
|
+
" ",
|
|
23933
|
+
flightLine.arrivalTime,
|
|
23934
|
+
React__default.createElement("br", null),
|
|
23935
|
+
flightLine.airlineDescription))),
|
|
23936
|
+
flightMetaData.luggageIncluded && React__default.createElement("p", null, translations.SIDEBAR.LUGGAGE_INCLUDED)));
|
|
23937
|
+
};
|
|
23255
23938
|
|
|
23256
|
-
const
|
|
23257
|
-
|
|
23258
|
-
|
|
23259
|
-
|
|
23260
|
-
|
|
23261
|
-
|
|
23262
|
-
|
|
23263
|
-
|
|
23264
|
-
|
|
23265
|
-
|
|
23266
|
-
|
|
23267
|
-
|
|
23268
|
-
|
|
23269
|
-
|
|
23939
|
+
const SummaryPerBookingOptionGroup = ({ group }) => {
|
|
23940
|
+
const groupOptions = group.options.filter((x) => x.isSelected);
|
|
23941
|
+
const renderOptions = () => (React__default.createElement(React__default.Fragment, null, groupOptions.map((opt) => (React__default.createElement("li", { key: opt.line.entryLineGuid, className: "list__item" },
|
|
23942
|
+
opt.line.productName,
|
|
23943
|
+
React__default.createElement("ul", null,
|
|
23944
|
+
React__default.createElement("li", null,
|
|
23945
|
+
opt.line.accommodationName,
|
|
23946
|
+
!isNil(opt.line?.regimeName) && ', ',
|
|
23947
|
+
opt.line.regimeName)),
|
|
23948
|
+
getDateText(opt.line.startDate),
|
|
23949
|
+
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
23950
|
+
React__default.createElement("ul", null,
|
|
23951
|
+
!isEmpty$1(opt?.groups) &&
|
|
23952
|
+
opt?.groups.map((x) => {
|
|
23953
|
+
if (!x.options.some((y) => y.isSelected))
|
|
23954
|
+
return;
|
|
23955
|
+
return React__default.createElement(SummaryPerBookingOptionGroup, { group: x });
|
|
23956
|
+
}),
|
|
23957
|
+
!isEmpty$1(opt?.units) && opt?.units.map((x) => React__default.createElement(SummaryBookingOptionUnit, { unit: x })),
|
|
23958
|
+
!isEmpty$1(opt?.pax) && opt?.pax.map((x) => React__default.createElement(SummaryBookingOptionPax, { pax: x }))))))));
|
|
23959
|
+
return (React__default.createElement(React__default.Fragment, null, group.title ? (React__default.createElement("li", { className: "list__item" },
|
|
23960
|
+
React__default.createElement("h6", null, group.title),
|
|
23961
|
+
React__default.createElement("ul", { className: "list" }, renderOptions()))) : (React__default.createElement(React__default.Fragment, null, renderOptions()))));
|
|
23270
23962
|
};
|
|
23271
23963
|
|
|
23272
|
-
const
|
|
23273
|
-
const
|
|
23274
|
-
const
|
|
23275
|
-
|
|
23276
|
-
|
|
23964
|
+
const Summary = () => {
|
|
23965
|
+
const dispatch = useAppDispatch();
|
|
23966
|
+
const settings = useContext(SettingsContext);
|
|
23967
|
+
const navigate = settings.skipRouter ? () => { } : useNavigate();
|
|
23968
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
23969
|
+
const [checkboxes, setCheckboxes] = useState(settings.summary?.checkboxes);
|
|
23970
|
+
const [remarks, setRemarks] = useState('');
|
|
23971
|
+
const [voucher, setVoucher] = useState({});
|
|
23972
|
+
const bookingQueryString = useSelector(selectBookingQueryString);
|
|
23973
|
+
const travelersFirstStep = useSelector(selectTravelersFirstStep);
|
|
23974
|
+
const travelerFormValues = useSelector(selectTravelersFormValues);
|
|
23975
|
+
const packageDetails = useSelector(selectPackageDetails);
|
|
23976
|
+
const activeOption = useSelector(selectActiveOption);
|
|
23977
|
+
const apiSettings = useSelector(selectApiSettings);
|
|
23978
|
+
const languageCode = useSelector(selectLanguageCode);
|
|
23979
|
+
const officeId = useSelector(selectOfficeId);
|
|
23980
|
+
const agentId = useSelector(selectAgentAdressId);
|
|
23981
|
+
const departureFlight = useSelector(selectDepartureFlight);
|
|
23982
|
+
const departureFlightMetaData = departureFlight?.flightMetaData ?? useSelector(selectRoomOptionDepartureFlightsMetaData)?.[0];
|
|
23983
|
+
const returnFlight = useSelector(selectReturnFlight);
|
|
23984
|
+
const returnFlightMetaData = returnFlight?.flightMetaData ?? useSelector(selectRoomOptionReturnFlightsMetaData)?.[0];
|
|
23985
|
+
if (!travelerFormValues) {
|
|
23986
|
+
if (settings.skipRouter) {
|
|
23987
|
+
dispatch(setCurrentStep$1(TRAVELERS_FORM_STEP));
|
|
23277
23988
|
}
|
|
23278
|
-
|
|
23279
|
-
|
|
23280
|
-
if (onClear) {
|
|
23281
|
-
onClear();
|
|
23989
|
+
else {
|
|
23990
|
+
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}?${bookingQueryString}`);
|
|
23282
23991
|
}
|
|
23283
|
-
|
|
23284
|
-
|
|
23285
|
-
|
|
23286
|
-
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
|
|
23291
|
-
|
|
23292
|
-
|
|
23293
|
-
|
|
23294
|
-
|
|
23295
|
-
|
|
23296
|
-
|
|
23297
|
-
|
|
23298
|
-
|
|
23299
|
-
|
|
23300
|
-
|
|
23301
|
-
|
|
23302
|
-
|
|
23303
|
-
if (onSelect)
|
|
23304
|
-
onSelect(option.key);
|
|
23305
|
-
setShowItems(false);
|
|
23306
|
-
}, type: "button", className: "button button--plain" },
|
|
23307
|
-
prefix,
|
|
23308
|
-
React__default.createElement("span", { className: "typeahead__option-highlight" }, highlight),
|
|
23309
|
-
suffix))));
|
|
23310
|
-
})))));
|
|
23311
|
-
};
|
|
23312
|
-
|
|
23313
|
-
// A traveler is a baby when the age they were booked with is at or below the baby
|
|
23314
|
-
// boundary. Babies get their own label and birth date validation (TIDE-3269). Only
|
|
23315
|
-
// meaningful for the regular form: the compact form asks for an age instead of a birth
|
|
23316
|
-
// date, so it has nothing to validate and its own age input already states the age.
|
|
23317
|
-
function isBabyAge(age, maxBabyAge = BABY_MAX_AGE) {
|
|
23318
|
-
return typeof age === 'number' && age <= maxBabyAge;
|
|
23319
|
-
}
|
|
23320
|
-
// The native date input can hold values format() throws on (e.g. a 5+ digit year while typing), so never format an unvalidated birthDate
|
|
23321
|
-
function formatBirthDate$1(birthDate) {
|
|
23322
|
-
if (!birthDate)
|
|
23323
|
-
return '';
|
|
23324
|
-
const parsed = parse(birthDate, 'yyyy-MM-dd', new Date());
|
|
23325
|
-
return isValid(parsed) ? format$2(parsed, 'dd-MM-yyyy') : '';
|
|
23326
|
-
}
|
|
23327
|
-
// A customFieldConfigurationId can have separate "main-booker"/other-pax variants; resolved per traveler below.
|
|
23328
|
-
const MAIN_BOOKER_GROUP = 'main-booker';
|
|
23329
|
-
function buildEmptyCustomFields(paxCustomFields = []) {
|
|
23330
|
-
const uniqueIds = Array.from(new Set(paxCustomFields.map((field) => field.customFieldConfigurationId)));
|
|
23331
|
-
return uniqueIds.map((customFieldConfigurationId) => ({ customFieldConfigurationId, value: '' }));
|
|
23332
|
-
}
|
|
23333
|
-
function getApplicablePaxCustomFields(paxCustomFields = [], isMainBooker) {
|
|
23334
|
-
const variantsById = new Map();
|
|
23335
|
-
paxCustomFields.forEach((field) => {
|
|
23336
|
-
const variants = variantsById.get(field.customFieldConfigurationId) ?? [];
|
|
23337
|
-
variants.push(field);
|
|
23338
|
-
variantsById.set(field.customFieldConfigurationId, variants);
|
|
23339
|
-
});
|
|
23340
|
-
const applicableFields = [];
|
|
23341
|
-
variantsById.forEach((variants) => {
|
|
23342
|
-
const hasRoleSplit = variants.some((v) => v.group === MAIN_BOOKER_GROUP);
|
|
23343
|
-
if (!hasRoleSplit) {
|
|
23344
|
-
applicableFields.push(variants[0]);
|
|
23992
|
+
}
|
|
23993
|
+
const rooms = useSelector(selectRooms);
|
|
23994
|
+
const userValidated = useSelector(selectUserValidated);
|
|
23995
|
+
const notifications = useSelector(selectNotifications);
|
|
23996
|
+
const bookRequest = useSelector(selectBookingPackageBookRequest);
|
|
23997
|
+
useEffect(() => {
|
|
23998
|
+
// Every checkbox should be checked, or no checkboxes
|
|
23999
|
+
const checkboxesValidated = !isNil(checkboxes) ? checkboxes.every((checkbox) => checkbox.isSelected) : true;
|
|
24000
|
+
const notificationsValidated = !isNil(notifications) ? notifications.filter((x) => x.hasToBeConfirmed).every((checkbox) => checkbox.isConfirmed) : true;
|
|
24001
|
+
dispatch(setUserValidated(checkboxesValidated && notificationsValidated));
|
|
24002
|
+
}, [checkboxes, notifications]);
|
|
24003
|
+
const handleSubmit = async (e) => {
|
|
24004
|
+
e.preventDefault();
|
|
24005
|
+
const submitter = e.nativeEvent.submitter?.name;
|
|
24006
|
+
setIsSubmitting(true);
|
|
24007
|
+
if (typeof window !== 'undefined') {
|
|
24008
|
+
window.scrollTo(0, 0);
|
|
24009
|
+
}
|
|
24010
|
+
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
24011
|
+
if (!bookRequest || !tideClientConfig) {
|
|
23345
24012
|
return;
|
|
23346
24013
|
}
|
|
23347
|
-
|
|
23348
|
-
|
|
23349
|
-
|
|
23350
|
-
|
|
23351
|
-
|
|
23352
|
-
}
|
|
23353
|
-
|
|
23354
|
-
|
|
23355
|
-
|
|
23356
|
-
|
|
23357
|
-
|
|
23358
|
-
lastName: `${followNumber.number++}`,
|
|
23359
|
-
birthDate: '',
|
|
23360
|
-
gender: '',
|
|
23361
|
-
// Keep a booked age of 0 instead of submitting and pricing the traveler as a 30 year
|
|
23362
|
-
// old, while still falling back for a missing or unusable age. `??` alone would let a
|
|
23363
|
-
// NaN (unparseable date of birth upstream) reach the age input and the booked pax.
|
|
23364
|
-
// See TIDE-3269.
|
|
23365
|
-
age: Number.isFinite(traveler.age) ? traveler.age : 30,
|
|
23366
|
-
// No isBaby here on purpose: the age below is editable and nothing revalidates it
|
|
23367
|
-
// in compact mode, so a stored flag would end up contradicting the entered age.
|
|
23368
|
-
weight: null,
|
|
23369
|
-
weightType: build.WeightType.kilograms,
|
|
23370
|
-
height: null,
|
|
23371
|
-
heightType: build.HeightType.centimeters,
|
|
23372
|
-
customFields: buildEmptyCustomFields(paxCustomFields)
|
|
23373
|
-
};
|
|
23374
|
-
}
|
|
23375
|
-
return {
|
|
23376
|
-
id: traveler.id,
|
|
23377
|
-
firstName: '',
|
|
23378
|
-
lastName: '',
|
|
23379
|
-
birthDate: '',
|
|
23380
|
-
gender: '',
|
|
23381
|
-
isBaby: isBabyAge(traveler.age, maxBabyAge),
|
|
23382
|
-
weight: null,
|
|
23383
|
-
weightType: build.WeightType.kilograms,
|
|
23384
|
-
height: null,
|
|
23385
|
-
heightType: build.HeightType.centimeters,
|
|
23386
|
-
customFields: buildEmptyCustomFields(paxCustomFields)
|
|
23387
|
-
};
|
|
23388
|
-
}
|
|
23389
|
-
function createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, personTranslation, isCompact, maxBabyAge, paxCustomFields) {
|
|
23390
|
-
const followNumber = { number: 1 };
|
|
23391
|
-
const initialValues = {
|
|
23392
|
-
startDate,
|
|
23393
|
-
endDate,
|
|
23394
|
-
rooms: formRooms.map((room) => ({
|
|
23395
|
-
adults: room.adults.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxCustomFields)),
|
|
23396
|
-
children: room.children.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxCustomFields))
|
|
23397
|
-
})),
|
|
23398
|
-
mainBookerId: -1,
|
|
23399
|
-
street: '',
|
|
23400
|
-
houseNumber: '',
|
|
23401
|
-
box: '',
|
|
23402
|
-
zipCode: '',
|
|
23403
|
-
place: '',
|
|
23404
|
-
country: '',
|
|
23405
|
-
phone: '',
|
|
23406
|
-
email: '',
|
|
23407
|
-
emailConfirmation: '',
|
|
23408
|
-
travelAgentId: agentAdressId ?? 0,
|
|
23409
|
-
travelAgentName: ''
|
|
23410
|
-
};
|
|
23411
|
-
if (initialValues.rooms?.[0]?.adults?.[0]) {
|
|
23412
|
-
initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
|
|
23413
|
-
}
|
|
23414
|
-
return initialValues;
|
|
23415
|
-
}
|
|
23416
|
-
function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId) {
|
|
23417
|
-
const pax = editablePackagingEntry?.pax ?? [];
|
|
23418
|
-
const rooms = editablePackagingEntry.rooms.map((room) => {
|
|
23419
|
-
const roomPax = pax.filter((x) => room.paxIds.includes(x.id));
|
|
23420
|
-
const adults = roomPax.filter((x) => x.age >= 18);
|
|
23421
|
-
const children = roomPax.filter((x) => x.age < 18);
|
|
23422
|
-
return {
|
|
23423
|
-
adults: adults.map((roomTraveler) => {
|
|
23424
|
-
return {
|
|
23425
|
-
id: roomTraveler.id,
|
|
23426
|
-
firstName: roomTraveler.firstName ?? '',
|
|
23427
|
-
lastName: roomTraveler.lastName ?? '',
|
|
23428
|
-
birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
|
|
23429
|
-
gender: ''
|
|
23430
|
-
};
|
|
23431
|
-
}),
|
|
23432
|
-
children: children.map((roomTraveler) => {
|
|
23433
|
-
return {
|
|
23434
|
-
id: roomTraveler.id,
|
|
23435
|
-
firstName: roomTraveler.firstName ?? '',
|
|
23436
|
-
lastName: roomTraveler.lastName ?? '',
|
|
23437
|
-
birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
|
|
23438
|
-
gender: '',
|
|
23439
|
-
isBaby: isBabyAge(roomTraveler.age)
|
|
23440
|
-
};
|
|
23441
|
-
})
|
|
23442
|
-
};
|
|
23443
|
-
});
|
|
23444
|
-
const values = createInitialValuesFromRooms(rooms.map((room) => ({ adults: room.adults, children: room.children })), first(editablePackagingEntry?.lines)?.from, last(editablePackagingEntry?.lines)?.to, agentAdressId);
|
|
23445
|
-
values.rooms = rooms;
|
|
23446
|
-
values.mainBookerId = pax.find((x) => x.isMainBooker)?.id ?? rooms[0]?.adults?.[0]?.id ?? -1;
|
|
23447
|
-
const address = editablePackagingEntry?.address;
|
|
23448
|
-
values.street = address?.street ?? '';
|
|
23449
|
-
values.houseNumber = address?.houseNumber ?? '';
|
|
23450
|
-
values.box = address?.box ?? '';
|
|
23451
|
-
values.zipCode = address?.zipCode ?? '';
|
|
23452
|
-
values.place = address?.place ?? '';
|
|
23453
|
-
values.country = address?.country ?? '';
|
|
23454
|
-
values.phone = address?.phone ?? '';
|
|
23455
|
-
values.email = address?.email ?? '';
|
|
23456
|
-
values.emailConfirmation = address?.email ?? '';
|
|
23457
|
-
values.travelAgentId = address?.travelAgentId ?? agentAdressId ?? 0;
|
|
23458
|
-
return values;
|
|
23459
|
-
}
|
|
23460
|
-
function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry, values) {
|
|
23461
|
-
const travelers = values.rooms.flatMap((room) => [...room.adults, ...room.children]);
|
|
23462
|
-
return {
|
|
23463
|
-
...editablePackagingEntry,
|
|
23464
|
-
pax: (editablePackagingEntry.pax ?? []).map((pax) => {
|
|
23465
|
-
const traveler = travelers.find((x) => x.id === pax.id);
|
|
23466
|
-
if (!traveler)
|
|
23467
|
-
return pax;
|
|
23468
|
-
return {
|
|
23469
|
-
...pax,
|
|
23470
|
-
firstName: traveler.firstName ?? '',
|
|
23471
|
-
lastName: traveler.lastName ?? '',
|
|
23472
|
-
dateOfBirth: traveler.birthDate || null,
|
|
23473
|
-
isMainBooker: traveler.id === values.mainBookerId
|
|
23474
|
-
};
|
|
23475
|
-
}),
|
|
23476
|
-
address: {
|
|
23477
|
-
...editablePackagingEntry.address,
|
|
23478
|
-
street: values.street,
|
|
23479
|
-
houseNumber: values.houseNumber,
|
|
23480
|
-
box: values.box,
|
|
23481
|
-
zipCode: values.zipCode,
|
|
23482
|
-
place: values.place,
|
|
23483
|
-
country: values.country,
|
|
23484
|
-
travelAgentId: values.travelAgentId,
|
|
23485
|
-
phone: values.phone,
|
|
23486
|
-
email: values.email
|
|
24014
|
+
if (bookRequest.payload.returnPaymentUrl) {
|
|
24015
|
+
if (typeof window !== 'undefined') {
|
|
24016
|
+
window.scrollTo(0, 0);
|
|
24017
|
+
if (settings.paymentRedirectUrl) {
|
|
24018
|
+
bookRequest.payload.redirectUrl = settings.paymentRedirectUrl;
|
|
24019
|
+
}
|
|
24020
|
+
else {
|
|
24021
|
+
const location = window.location;
|
|
24022
|
+
bookRequest.payload.redirectUrl = `${location.protocol}//${location.host}${settings.basePath ?? location.pathname}?${bookingQueryString}`;
|
|
24023
|
+
}
|
|
24024
|
+
}
|
|
23487
24025
|
}
|
|
23488
|
-
|
|
23489
|
-
|
|
23490
|
-
|
|
23491
|
-
|
|
23492
|
-
|
|
23493
|
-
|
|
23494
|
-
|
|
23495
|
-
|
|
23496
|
-
|
|
23497
|
-
|
|
23498
|
-
|
|
23499
|
-
|
|
23500
|
-
|
|
23501
|
-
|
|
23502
|
-
|
|
23503
|
-
|
|
23504
|
-
|
|
23505
|
-
|
|
23506
|
-
|
|
23507
|
-
|
|
23508
|
-
|
|
23509
|
-
|
|
23510
|
-
|
|
23511
|
-
|
|
23512
|
-
|
|
23513
|
-
|
|
23514
|
-
|
|
23515
|
-
|
|
23516
|
-
|
|
23517
|
-
|
|
23518
|
-
|
|
23519
|
-
|
|
23520
|
-
|
|
23521
|
-
|
|
23522
|
-
|
|
23523
|
-
|
|
23524
|
-
|
|
23525
|
-
|
|
23526
|
-
|
|
23527
|
-
|
|
23528
|
-
|
|
23529
|
-
|
|
23530
|
-
|
|
23531
|
-
formik.setValues({ ...formik.values, travelAgentId: 0, travelAgentName: '' });
|
|
23532
|
-
onBookingTypeChange?.('b2c');
|
|
23533
|
-
};
|
|
23534
|
-
const toggleAgent = (value) => {
|
|
23535
|
-
setShowAgents(value);
|
|
23536
|
-
if (!value) {
|
|
23537
|
-
handleAgentClear();
|
|
23538
|
-
setFilteredAgents([]);
|
|
24026
|
+
try {
|
|
24027
|
+
if (submitter === 'option') {
|
|
24028
|
+
bookRequest.payload.status = build.EntryStatus.option;
|
|
24029
|
+
bookRequest.payload.customStatusId = settings.customOptionStatus;
|
|
24030
|
+
dispatch(setIsOption(true));
|
|
24031
|
+
}
|
|
24032
|
+
const bookingResponse = await build.book(tideClientConfig, bookRequest, undefined, languageCode);
|
|
24033
|
+
// Booking successfull
|
|
24034
|
+
dispatch(setBookingNumber$1(bookingResponse.number));
|
|
24035
|
+
if (bookingResponse.paymentUrl) {
|
|
24036
|
+
const event = new CustomEvent('tide-booking-payment-url', {
|
|
24037
|
+
detail: {
|
|
24038
|
+
paymentUrl: bookingResponse.paymentUrl,
|
|
24039
|
+
bookingNumber: bookingResponse.number
|
|
24040
|
+
},
|
|
24041
|
+
cancelable: true,
|
|
24042
|
+
bubbles: true
|
|
24043
|
+
});
|
|
24044
|
+
const target = typeof document !== 'undefined' ? document.getElementById('tide-booking') ?? window : window;
|
|
24045
|
+
const shouldAutoRedirect = target.dispatchEvent(event);
|
|
24046
|
+
if (shouldAutoRedirect) {
|
|
24047
|
+
window.location.href = bookingResponse.paymentUrl;
|
|
24048
|
+
}
|
|
24049
|
+
}
|
|
24050
|
+
else {
|
|
24051
|
+
if (settings.skipRouter) {
|
|
24052
|
+
dispatch(setCurrentStep$1(CONFIRMATION_STEP));
|
|
24053
|
+
}
|
|
24054
|
+
else {
|
|
24055
|
+
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.confirmation.pathSuffix}?${bookingQueryString}`);
|
|
24056
|
+
}
|
|
24057
|
+
}
|
|
24058
|
+
}
|
|
24059
|
+
catch (error) {
|
|
24060
|
+
if (settings.skipRouter) {
|
|
24061
|
+
dispatch(setCurrentStep$1(ERROR_STEP));
|
|
24062
|
+
}
|
|
24063
|
+
else {
|
|
24064
|
+
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.error.pathSuffix}?${bookingQueryString}`);
|
|
24065
|
+
}
|
|
24066
|
+
}
|
|
24067
|
+
finally {
|
|
24068
|
+
setIsSubmitting(false);
|
|
23539
24069
|
}
|
|
23540
24070
|
};
|
|
23541
|
-
const
|
|
23542
|
-
const
|
|
23543
|
-
|
|
23544
|
-
id: Date.now(),
|
|
23545
|
-
firstName: '',
|
|
23546
|
-
lastName: '',
|
|
23547
|
-
birthDate: '',
|
|
23548
|
-
gender: '',
|
|
23549
|
-
weight: null,
|
|
23550
|
-
weightType: build.WeightType.kilograms,
|
|
23551
|
-
height: null,
|
|
23552
|
-
heightType: build.HeightType.centimeters,
|
|
23553
|
-
customFields: buildEmptyCustomFields(paxCustomFields)
|
|
23554
|
-
};
|
|
23555
|
-
rooms[roomIndex] = { ...rooms[roomIndex], adults: [...rooms[roomIndex].adults, newAdult] };
|
|
23556
|
-
formik.setFieldValue('rooms', rooms);
|
|
24071
|
+
const handleNotificationChange = (id, checked) => {
|
|
24072
|
+
const updatedNotifications = notifications.map((notification) => (notification.id === id ? { ...notification, isConfirmed: checked } : notification));
|
|
24073
|
+
dispatch(setNotifications(updatedNotifications));
|
|
23557
24074
|
};
|
|
23558
|
-
const
|
|
23559
|
-
|
|
23560
|
-
const adults = [...rooms[roomIndex].adults];
|
|
23561
|
-
if (adults.length <= 1)
|
|
24075
|
+
const handleCheckboxChange = (id, checked) => {
|
|
24076
|
+
if (isNil(checkboxes)) {
|
|
23562
24077
|
return;
|
|
23563
|
-
|
|
23564
|
-
|
|
23565
|
-
|
|
23566
|
-
|
|
23567
|
-
|
|
23568
|
-
const rooms = [...formik.values.rooms];
|
|
23569
|
-
rooms.push({
|
|
23570
|
-
adults: [
|
|
23571
|
-
{
|
|
23572
|
-
id: Date.now(),
|
|
23573
|
-
firstName: '',
|
|
23574
|
-
lastName: '',
|
|
23575
|
-
birthDate: '',
|
|
23576
|
-
gender: '',
|
|
23577
|
-
weight: null,
|
|
23578
|
-
weightType: build.WeightType.kilograms,
|
|
23579
|
-
height: null,
|
|
23580
|
-
heightType: build.HeightType.centimeters,
|
|
23581
|
-
customFields: buildEmptyCustomFields(paxCustomFields)
|
|
23582
|
-
}
|
|
23583
|
-
],
|
|
23584
|
-
children: []
|
|
23585
|
-
});
|
|
23586
|
-
formik.setFieldValue('rooms', rooms);
|
|
24078
|
+
}
|
|
24079
|
+
const newCheckboxes = [...checkboxes];
|
|
24080
|
+
const index = findIndex$1(checkboxes, (checkbox) => checkbox.id === id);
|
|
24081
|
+
newCheckboxes[index].isSelected = !newCheckboxes[index].isSelected;
|
|
24082
|
+
setCheckboxes(newCheckboxes);
|
|
23587
24083
|
};
|
|
23588
|
-
const
|
|
23589
|
-
|
|
23590
|
-
|
|
23591
|
-
formik.setFieldValue('rooms', rooms);
|
|
24084
|
+
const handleRemarksChange = (text) => {
|
|
24085
|
+
dispatch(setBookingRemarks(text));
|
|
24086
|
+
setRemarks(text);
|
|
23592
24087
|
};
|
|
23593
|
-
const
|
|
23594
|
-
|
|
23595
|
-
|
|
23596
|
-
|
|
23597
|
-
|
|
23598
|
-
|
|
23599
|
-
|
|
23600
|
-
|
|
23601
|
-
|
|
23602
|
-
|
|
23603
|
-
|
|
23604
|
-
|
|
23605
|
-
|
|
23606
|
-
|
|
23607
|
-
|
|
23608
|
-
|
|
23609
|
-
|
|
23610
|
-
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
|
|
23614
|
-
{ key: 'ftIn', value: build.HeightType.feetInches, label: translations.TRAVELERS_FORM.HEIGHT_UNIT_FT_IN }
|
|
23615
|
-
] })));
|
|
23616
|
-
const getCustomFieldControl = (field, value, name) => {
|
|
23617
|
-
const label = compact([field.fieldName, field.isRequired && '*']).join(' ');
|
|
23618
|
-
switch (field.dataType) {
|
|
23619
|
-
case build.CustomFieldDataType.bool:
|
|
23620
|
-
return (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
|
|
23621
|
-
React__default.createElement("div", { className: "checkbox" },
|
|
23622
|
-
React__default.createElement("label", { className: "checkbox__label" },
|
|
23623
|
-
React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: value === 'true', onChange: (e) => formik.setFieldValue(name, e.target.checked ? 'true' : 'false'), onBlur: formik.handleBlur, name: name }),
|
|
23624
|
-
label))));
|
|
23625
|
-
case build.CustomFieldDataType.date:
|
|
23626
|
-
return (React__default.createElement(LabeledInput, { type: "date", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
23627
|
-
case build.CustomFieldDataType.time:
|
|
23628
|
-
return (React__default.createElement(LabeledInput, { type: "time", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
23629
|
-
case build.CustomFieldDataType.numeric:
|
|
23630
|
-
return (React__default.createElement(LabeledInput, { type: "number", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
23631
|
-
case build.CustomFieldDataType.string:
|
|
23632
|
-
default:
|
|
23633
|
-
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
24088
|
+
const handleValidateVoucher = async () => {
|
|
24089
|
+
if (!voucher?.code)
|
|
24090
|
+
return;
|
|
24091
|
+
const request = {
|
|
24092
|
+
officeId: officeId,
|
|
24093
|
+
agentId: agentId,
|
|
24094
|
+
payload: {
|
|
24095
|
+
code: voucher.code,
|
|
24096
|
+
otherCodes: bookRequest?.payload.voucherCodes ?? []
|
|
24097
|
+
}
|
|
24098
|
+
};
|
|
24099
|
+
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
24100
|
+
if (!tideClientConfig)
|
|
24101
|
+
return;
|
|
24102
|
+
const result = await build.validateVoucher(tideClientConfig, request);
|
|
24103
|
+
if (result) {
|
|
24104
|
+
setVoucher({
|
|
24105
|
+
...voucher,
|
|
24106
|
+
isValidated: true,
|
|
24107
|
+
isValid: result.isValid
|
|
24108
|
+
});
|
|
23634
24109
|
}
|
|
23635
24110
|
};
|
|
23636
|
-
const
|
|
23637
|
-
if (!
|
|
23638
|
-
return
|
|
23639
|
-
|
|
23640
|
-
|
|
23641
|
-
|
|
23642
|
-
return null;
|
|
23643
|
-
return (React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, applicableFields.map((field) => {
|
|
23644
|
-
const fieldIndex = travelerValues.customFields?.findIndex((c) => c.customFieldConfigurationId === field.customFieldConfigurationId) ?? -1;
|
|
23645
|
-
if (fieldIndex < 0)
|
|
23646
|
-
return null;
|
|
23647
|
-
const name = `${namePrefix}.customFields[${fieldIndex}].value`;
|
|
23648
|
-
const value = travelerValues.customFields[fieldIndex].value;
|
|
23649
|
-
return (React__default.createElement("div", { key: field.customFieldConfigurationId, style: { gridColumn: `span ${field.col || 12}` } }, getCustomFieldControl(field, value, name)));
|
|
23650
|
-
})));
|
|
24111
|
+
const handleAddVoucher = (event) => {
|
|
24112
|
+
if (!voucher.isValid)
|
|
24113
|
+
return;
|
|
24114
|
+
dispatch(setVoucherCodes([...(bookRequest?.payload.voucherCodes ?? []), voucher.code ?? ''].filter((x) => x !== '')));
|
|
24115
|
+
dispatch(fetchPriceDetails());
|
|
24116
|
+
setVoucher({});
|
|
23651
24117
|
};
|
|
23652
|
-
const
|
|
23653
|
-
|
|
23654
|
-
|
|
23655
|
-
return React__default.createElement(GenderControl, { translations: translations, value: value, formik: formik, name: name });
|
|
23656
|
-
case 'firstName':
|
|
23657
|
-
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError(name), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.FIRST_NAME, required: true, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.firstName }));
|
|
23658
|
-
case 'lastName':
|
|
23659
|
-
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError(name), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.LAST_NAME, required: true, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.lastName }));
|
|
23660
|
-
case 'birthDate':
|
|
23661
|
-
return (React__default.createElement(LabeledInput, { type: "date", hasError: hasVisibleError(name), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.BIRTHDATE, required: true, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.birthDate }));
|
|
23662
|
-
case 'country':
|
|
23663
|
-
return (React__default.createElement(LabeledSelect, { hasError: hasVisibleError('country'), label: translations.TRAVELERS_FORM.COUNTRY, required: true, name: "country", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.country, options: countryOptions }));
|
|
23664
|
-
case 'phone':
|
|
23665
|
-
return (React__default.createElement(PhoneInput, { countries: travellersSettings?.countries ?? [], countryIso2: formik.values.country, hasError: hasVisibleError('phone'), label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }));
|
|
23666
|
-
case 'email':
|
|
23667
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
23668
|
-
React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
|
|
23669
|
-
React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })));
|
|
23670
|
-
case 'street':
|
|
23671
|
-
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('street'), extraClassName: "form__group--50 form__group--sm-60", label: translations.TRAVELERS_FORM.STREET, required: true, name: "street", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.street }));
|
|
23672
|
-
case 'houseNumber':
|
|
23673
|
-
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('houseNumber'), extraClassName: "form__group--30 form__group--sm-20", label: translations.TRAVELERS_FORM.HOUSE_NUMBER, required: true, name: "houseNumber", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.houseNumber }));
|
|
23674
|
-
case 'box':
|
|
23675
|
-
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('box'), extraClassName: "form__group--20", label: translations.TRAVELERS_FORM.POST_BOX, name: "box", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.box }));
|
|
23676
|
-
case 'zipCode':
|
|
23677
|
-
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('zipCode'), extraClassName: "form__group--40 form__group--sm-20", label: translations.TRAVELERS_FORM.ZIPCODE, required: true, name: "zipCode", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.zipCode }));
|
|
23678
|
-
case 'place':
|
|
23679
|
-
return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('place'), extraClassName: "form__group--60 form__group--sm-40", label: translations.TRAVELERS_FORM.CITY, required: true, name: "place", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.place }));
|
|
23680
|
-
default:
|
|
23681
|
-
return null;
|
|
23682
|
-
}
|
|
24118
|
+
const handleRemoveVoucher = (code) => {
|
|
24119
|
+
dispatch(setVoucherCodes(bookRequest?.payload.voucherCodes?.filter((x) => x !== code) ?? []));
|
|
24120
|
+
dispatch(fetchPriceDetails());
|
|
23683
24121
|
};
|
|
23684
|
-
const
|
|
23685
|
-
|
|
23686
|
-
room.adults.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
|
|
23687
|
-
room.adults.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
|
|
23688
|
-
room.adults?.length && room.children?.length && ', ',
|
|
23689
|
-
room.children.length,
|
|
23690
|
-
room.children.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
|
|
23691
|
-
room.children.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`
|
|
23692
|
-
]).join('');
|
|
23693
|
-
const renderTravelerFields = (travelerValues, namePrefix, isAdult, roomIndex, travelerIndex) => {
|
|
23694
|
-
if (useCompactForm) {
|
|
23695
|
-
return (React__default.createElement("div", { className: "form__row" },
|
|
23696
|
-
React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.age`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.AGE, required: true, name: `${namePrefix}.age`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.age })));
|
|
23697
|
-
}
|
|
23698
|
-
if (travellersSettings?.formFields?.length) {
|
|
23699
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
23700
|
-
React__default.createElement("div", { className: "travelers-form__grid" }, travellersSettings.formFields.map((field, index) => (React__default.createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, travelerValues, `${namePrefix}.${field.type}`))))),
|
|
23701
|
-
showWeightField && renderWeightControl(namePrefix, travelerValues),
|
|
23702
|
-
showHeightField && renderHeightControl(namePrefix, travelerValues),
|
|
23703
|
-
renderCustomFields(travelerValues, namePrefix)));
|
|
23704
|
-
}
|
|
23705
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
23706
|
-
React__default.createElement("div", { className: "form__row" }, renderGenderControl(`${namePrefix}.gender`, travelerValues)),
|
|
23707
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23708
|
-
React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.firstName`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.FIRST_NAME, required: true, name: `${namePrefix}.firstName`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.firstName }),
|
|
23709
|
-
React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.lastName`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.LAST_NAME, required: true, name: `${namePrefix}.lastName`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.lastName }),
|
|
23710
|
-
React__default.createElement(LabeledInput, { type: "date", hasError: hasVisibleError(`${namePrefix}.birthDate`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.BIRTHDATE, required: true, name: `${namePrefix}.birthDate`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.birthDate })),
|
|
23711
|
-
showWeightField && renderWeightControl(namePrefix, travelerValues),
|
|
23712
|
-
showHeightField && renderHeightControl(namePrefix, travelerValues),
|
|
23713
|
-
renderCustomFields(travelerValues, namePrefix),
|
|
23714
|
-
travelersFirstStep && isAdult && formik.values.rooms[roomIndex].adults.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveTraveler(roomIndex, travelerIndex) }, translations.TRAVELERS_FORM.REMOVE_TRAVELER))));
|
|
24122
|
+
const goPrevious = () => {
|
|
24123
|
+
dispatch(setCurrentStep$1(travelersFirstStep ? OPTIONS_FORM_STEP : TRAVELERS_FORM_STEP));
|
|
23715
24124
|
};
|
|
23716
|
-
|
|
23717
|
-
|
|
23718
|
-
|
|
23719
|
-
|
|
23720
|
-
|
|
23721
|
-
|
|
23722
|
-
translations.SHARED.ROOM,
|
|
23723
|
-
" ",
|
|
23724
|
-
roomIndex + 1),
|
|
23725
|
-
React__default.createElement("p", { className: "form__region-label" }, renderRoomLabel(room))),
|
|
23726
|
-
!useCompactForm && travelersFirstStep && formik.values.rooms.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveRoom(roomIndex) }, "Verwijder reisgezelschap")))),
|
|
23727
|
-
room.adults.map((travelerValues, index) => (React__default.createElement("div", { className: "form__region", key: travelerValues.id },
|
|
23728
|
-
React__default.createElement("div", { className: "form__region-header" },
|
|
23729
|
-
React__default.createElement("h5", { className: "form__region-heading" },
|
|
23730
|
-
translations.TRAVELERS_FORM.TRAVELER,
|
|
23731
|
-
" ",
|
|
23732
|
-
index + 1),
|
|
23733
|
-
React__default.createElement("p", { className: "form__region-label" }, translations.TRAVELERS_FORM.ADULT),
|
|
23734
|
-
React__default.createElement("div", { className: "radiobutton" },
|
|
23735
|
-
React__default.createElement("label", { className: "radiobutton__label" },
|
|
23736
|
-
React__default.createElement("input", { type: "radio", name: "mainBookerId", onChange: handleMainBookerChange, onBlur: formik.handleBlur, value: travelerValues.id, checked: formik.values.mainBookerId === travelerValues.id, className: "radiobutton__input" }),
|
|
23737
|
-
translations.TRAVELERS_FORM.MAIN_BOOKER))),
|
|
23738
|
-
renderTravelerFields(travelerValues, `rooms[${roomIndex}].adults[${index}]`, true, roomIndex, index)))),
|
|
23739
|
-
room.children.map((travelerValues, index) => (React__default.createElement("div", { className: "form__region", key: travelerValues.id },
|
|
23740
|
-
React__default.createElement("div", { className: "form__region-header" },
|
|
23741
|
-
React__default.createElement("h5", { className: "form__region-heading" },
|
|
23742
|
-
translations.TRAVELERS_FORM.TRAVELER,
|
|
23743
|
-
" ",
|
|
23744
|
-
room.adults.length + index + 1),
|
|
23745
|
-
React__default.createElement("p", { className: "form__region-label" }, travelerValues.isBaby ? translations.TRAVELERS_FORM.BABY : translations.TRAVELERS_FORM.CHILD)),
|
|
23746
|
-
renderTravelerFields(travelerValues, `rooms[${roomIndex}].children[${index}]`, false, roomIndex, index)))),
|
|
23747
|
-
!useCompactForm && travelersFirstStep && (React__default.createElement("div", { className: "form__region" },
|
|
23748
|
-
React__default.createElement("button", { type: "button", className: "cta cta--select", onClick: () => handleAddTraveler(roomIndex) }, translations.TRAVELERS_FORM.ADD_TRAVELER)))))),
|
|
23749
|
-
!useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default.createElement("div", { className: "form__region" },
|
|
23750
|
-
React__default.createElement("div", { className: "form__region-header" },
|
|
23751
|
-
React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
|
|
23752
|
-
React__default.createElement("p", { className: "form__region-label" }, compact([compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
|
|
23753
|
-
travellersSettings?.mainBookerFormFields?.length ? (React__default.createElement("div", { className: "main-booker-form__grid" }, travellersSettings.mainBookerFormFields.map((field, index) => (React__default.createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, {}, field.type)))))) : (React__default.createElement(React__default.Fragment, null,
|
|
23754
|
-
React__default.createElement("div", { className: "form__twocolumn" },
|
|
23755
|
-
React__default.createElement("div", { className: "form__twocolumn-column" },
|
|
23756
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23757
|
-
React__default.createElement(LabeledInput, { hasError: hasVisibleError('street'), extraClassName: "form__group--50 form__group--sm-60", label: translations.TRAVELERS_FORM.STREET, required: true, name: "street", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.street }),
|
|
23758
|
-
React__default.createElement(LabeledInput, { hasError: hasVisibleError('houseNumber'), extraClassName: "form__group--30 form__group--sm-20", label: translations.TRAVELERS_FORM.HOUSE_NUMBER, required: true, name: "houseNumber", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.houseNumber }),
|
|
23759
|
-
React__default.createElement(LabeledInput, { hasError: hasVisibleError('box'), extraClassName: "form__group--20", label: translations.TRAVELERS_FORM.POST_BOX, name: "box", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.box }))),
|
|
23760
|
-
React__default.createElement("div", { className: "form__twocolumn-column" },
|
|
23761
|
-
React__default.createElement("div", { className: "form__row" },
|
|
23762
|
-
React__default.createElement(LabeledInput, { hasError: hasVisibleError('zipCode'), extraClassName: "form__group--40 form__group--sm-20", label: translations.TRAVELERS_FORM.ZIPCODE, required: true, name: "zipCode", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.zipCode }),
|
|
23763
|
-
React__default.createElement(LabeledInput, { hasError: hasVisibleError('place'), extraClassName: "form__group--60 form__group--sm-40", label: translations.TRAVELERS_FORM.CITY, required: true, name: "place", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.place }),
|
|
23764
|
-
React__default.createElement(LabeledSelect, { hasError: hasVisibleError('country'), extraClassName: "form__group--sm-40", label: translations.TRAVELERS_FORM.COUNTRY, required: true, name: "country", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.country, options: countryOptions })))),
|
|
24125
|
+
const translations = useSelector(selectTranslations);
|
|
24126
|
+
return (React__default.createElement(React__default.Fragment, null,
|
|
24127
|
+
isSubmitting && (settings.loaderComponent || React__default.createElement(Loader, null)),
|
|
24128
|
+
!isSubmitting && (React__default.createElement("form", { className: "form", name: "booking--summary", id: "booking--summary", onSubmit: handleSubmit },
|
|
24129
|
+
React__default.createElement("div", { className: "form__booking--summary" },
|
|
24130
|
+
React__default.createElement("div", { className: "form__region" },
|
|
23765
24131
|
React__default.createElement("div", { className: "form__row" },
|
|
23766
|
-
React__default.createElement(
|
|
23767
|
-
|
|
23768
|
-
|
|
23769
|
-
|
|
23770
|
-
|
|
23771
|
-
|
|
23772
|
-
|
|
23773
|
-
|
|
23774
|
-
|
|
23775
|
-
|
|
23776
|
-
|
|
23777
|
-
|
|
23778
|
-
|
|
23779
|
-
|
|
23780
|
-
|
|
23781
|
-
|
|
23782
|
-
|
|
23783
|
-
|
|
23784
|
-
|
|
23785
|
-
|
|
23786
|
-
|
|
23787
|
-
|
|
23788
|
-
|
|
23789
|
-
|
|
23790
|
-
|
|
23791
|
-
|
|
23792
|
-
|
|
24132
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24133
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
24134
|
+
React__default.createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.PERSONAL_DETAILS)))),
|
|
24135
|
+
rooms.map((r, rIndex) => (React__default.createElement("div", { className: "form__row", key: rIndex },
|
|
24136
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24137
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
24138
|
+
React__default.createElement("h5", { className: "form__region-heading" }, rooms.length > 1 ? `${translations.SHARED.ROOM} ${rIndex + 1}` : translations.ROOM_OPTIONS_FORM.TRAVELER_GROUP),
|
|
24139
|
+
React__default.createElement("p", { className: "form__region-label" }, `${r.adults.length + r.children.length} ${r.adults.length + r.children.length === 1 ? translations.SUMMARY.TRAVELER : translations.SUMMARY.TRAVELERS}: ${compact([
|
|
24140
|
+
r.adults.length,
|
|
24141
|
+
r.adults.length === 1 && ` ${translations.SUMMARY.ADULT}`,
|
|
24142
|
+
r.adults.length > 1 && ` ${translations.SUMMARY.ADULTS}`,
|
|
24143
|
+
r.adults && r.adults.length && r.children && r.children.length && ', ',
|
|
24144
|
+
r.children.length,
|
|
24145
|
+
r.children.length === 1 && ` ${translations.SUMMARY.CHILD}`,
|
|
24146
|
+
r.children.length > 1 && ` ${translations.SUMMARY.CHILDREN}`
|
|
24147
|
+
]).join('')}`))),
|
|
24148
|
+
[...r.adults, ...r.children].map((traveler) => {
|
|
24149
|
+
const isMainBooker = traveler.id === travelerFormValues?.mainBookerId;
|
|
24150
|
+
return (React__default.createElement("div", { className: "form__group form__group--sm-50", key: traveler.id },
|
|
24151
|
+
React__default.createElement("ul", { className: "list list--plain" },
|
|
24152
|
+
React__default.createElement("li", { className: "list__item" },
|
|
24153
|
+
React__default.createElement("strong", null,
|
|
24154
|
+
traveler.firstName,
|
|
24155
|
+
" ",
|
|
24156
|
+
traveler.lastName),
|
|
24157
|
+
' ',
|
|
24158
|
+
isMainBooker && React__default.createElement("em", null,
|
|
24159
|
+
"(",
|
|
24160
|
+
translations.SUMMARY.MAIN_BOOKER,
|
|
24161
|
+
")")),
|
|
24162
|
+
React__default.createElement("li", { className: "list__item" }, traveler.birthDate.split('-').reverse().join('/')),
|
|
24163
|
+
isMainBooker && (React__default.createElement(React__default.Fragment, null,
|
|
24164
|
+
travelerFormValues?.street && (React__default.createElement(React__default.Fragment, null,
|
|
24165
|
+
React__default.createElement("li", { className: "list__item" }, `${travelerFormValues?.street} ${compact([
|
|
24166
|
+
travelerFormValues?.houseNumber,
|
|
24167
|
+
travelerFormValues?.box
|
|
24168
|
+
]).join(' ')}, ${travelerFormValues?.zipCode} ${travelerFormValues?.place}`))),
|
|
24169
|
+
travelerFormValues?.phone && React__default.createElement("li", { className: "list__item" }, travelerFormValues?.phone),
|
|
24170
|
+
travelerFormValues?.email && React__default.createElement("li", { className: "list__item" }, travelerFormValues?.email))))));
|
|
24171
|
+
}))))),
|
|
24172
|
+
React__default.createElement("div", { className: "form__region" },
|
|
24173
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24174
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24175
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
24176
|
+
React__default.createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.OPTIONS)))),
|
|
24177
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24178
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24179
|
+
React__default.createElement("ul", { className: "list list--booking-summary" }, activeOption?.serviceType == build.ServiceType.flight ? (React__default.createElement(React__default.Fragment, null,
|
|
24180
|
+
departureFlightMetaData && React__default.createElement(SummaryFlight, { flightMetaData: departureFlightMetaData, header: translations.SIDEBAR.DEPARTURE_FLIGHT }),
|
|
24181
|
+
returnFlightMetaData && React__default.createElement(SummaryFlight, { flightMetaData: returnFlightMetaData, header: translations.SIDEBAR.ARRIVAL_FLIGHT }))) : (React__default.createElement(React__default.Fragment, null, activeOption?.rooms
|
|
24182
|
+
.flatMap((r) => r.options)
|
|
24183
|
+
.filter((x) => x.isSelected)
|
|
24184
|
+
.map((roomOption, roomOptionIndex) => (React__default.createElement(React__default.Fragment, { key: roomOptionIndex },
|
|
24185
|
+
React__default.createElement("li", null,
|
|
24186
|
+
React__default.createElement("h6", null, roomOption?.productName),
|
|
24187
|
+
React__default.createElement("ul", null,
|
|
24188
|
+
React__default.createElement("li", { className: "list__item" },
|
|
24189
|
+
roomOption?.accommodationName,
|
|
24190
|
+
!isNil(roomOption?.regimeName) && ', ',
|
|
24191
|
+
roomOption?.regimeName)),
|
|
24192
|
+
React__default.createElement("p", null,
|
|
24193
|
+
"(",
|
|
24194
|
+
roomOption?.from === roomOption?.to ? (getDateText(roomOption?.from)) : (React__default.createElement(React__default.Fragment, null,
|
|
24195
|
+
getDateText(roomOption?.from),
|
|
24196
|
+
" > ",
|
|
24197
|
+
getDateText(roomOption?.to))),
|
|
24198
|
+
")")),
|
|
24199
|
+
!isEmpty$1(activeOption?.groups) &&
|
|
24200
|
+
activeOption?.groups.map((x, i) => {
|
|
24201
|
+
if (!x.options.some((y) => y.isSelected))
|
|
24202
|
+
return;
|
|
24203
|
+
return React__default.createElement(SummaryPerBookingOptionGroup, { key: i, group: x });
|
|
24204
|
+
}),
|
|
24205
|
+
!isEmpty$1(activeOption?.optionUnits) && activeOption?.optionUnits.map((x, i) => React__default.createElement(SummaryBookingOptionUnit, { key: i, unit: x })),
|
|
24206
|
+
!isEmpty$1(activeOption?.optionPax) && activeOption?.optionPax.map((x, i) => React__default.createElement(SummaryBookingOptionPax, { key: i, pax: x })),
|
|
24207
|
+
packageDetails?.outwardFlights &&
|
|
24208
|
+
packageDetails.outwardFlights
|
|
24209
|
+
.filter((x) => x.isSelected)
|
|
24210
|
+
.map((flight, i) => (React__default.createElement(SummaryFlight, { key: i, flightMetaData: flight.flightMetaData, header: translations.SIDEBAR.DEPARTURE_FLIGHT }))),
|
|
24211
|
+
packageDetails?.returnFlights &&
|
|
24212
|
+
packageDetails.returnFlights
|
|
24213
|
+
.filter((x) => x.isSelected)
|
|
24214
|
+
.map((flight, i) => (React__default.createElement(SummaryFlight, { key: i, flightMetaData: flight.flightMetaData, header: translations.SIDEBAR.ARRIVAL_FLIGHT })))))))))))),
|
|
24215
|
+
settings.enableVoucher && (React__default.createElement("div", { className: "form__region" },
|
|
24216
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24217
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24218
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
24219
|
+
React__default.createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.VOUCHERS)))),
|
|
24220
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24221
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24222
|
+
React__default.createElement("input", { type: "text", className: "form__input info-message__voucher__input", defaultValue: voucher.code, onChange: (e) => setVoucher({ code: e.target.value }) }),
|
|
24223
|
+
React__default.createElement("button", { type: "button", className: buildClassName(['cta', !voucher.code && 'cta--disabled']), onClick: (e) => handleValidateVoucher() }, translations.SUMMARY.VOUCHER_VALIDATE))),
|
|
24224
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24225
|
+
React__default.createElement("div", { className: "form__group info-message__voucher" },
|
|
24226
|
+
voucher.isValid && voucher.isValidated && (React__default.createElement("div", { className: "info-message info-message__voucher__valid" },
|
|
24227
|
+
React__default.createElement("span", null, translations.SUMMARY.VOUCHER_VALID),
|
|
24228
|
+
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: handleAddVoucher }, translations.SUMMARY.ADD_VOUCHER))),
|
|
24229
|
+
!voucher.isValid && voucher.isValidated && React__default.createElement("div", { className: "info-message--error" }, translations.SUMMARY.VOUCHER_INVALID))),
|
|
24230
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24231
|
+
React__default.createElement("ul", { className: "info-message__voucher" }, !isEmpty$1(bookRequest?.payload.voucherCodes) &&
|
|
24232
|
+
bookRequest?.payload.voucherCodes?.map((y, i) => (React__default.createElement("li", { key: i },
|
|
24233
|
+
React__default.createElement("div", { className: "info-message__voucher__list" },
|
|
24234
|
+
y,
|
|
24235
|
+
' ',
|
|
24236
|
+
React__default.createElement("button", { type: "button", className: "cta--add-remove", onClick: (e) => handleRemoveVoucher(y) },
|
|
24237
|
+
React__default.createElement(Icon, { height: 16, name: "ui-trashcan" })))))))))),
|
|
24238
|
+
!isEmpty$1(notifications) && (React__default.createElement("div", { className: "form__region" },
|
|
24239
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24240
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24241
|
+
React__default.createElement("div", { className: "info-message" },
|
|
24242
|
+
React__default.createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
|
|
24243
|
+
React__default.createElement("div", { className: "info-message__copy" },
|
|
24244
|
+
React__default.createElement("h5", null, translations.SUMMARY.NOTIFICATIONS_TITLE),
|
|
24245
|
+
React__default.createElement(React__default.Fragment, null,
|
|
24246
|
+
uniqBy(notifications.filter((x) => !x.hasToBeConfirmed), 'id').map((notification) => (React__default.createElement("span", { key: notification.id, className: "checkbox__label-text" },
|
|
24247
|
+
React__default.createElement("strong", { className: "checkbox__label-text--title" }, notification.title),
|
|
24248
|
+
React__default.createElement("span", { className: "checkbox__label-text--description" }, notification.description)))),
|
|
24249
|
+
uniqBy(notifications.filter((x) => x.hasToBeConfirmed), 'id').map((notification) => (React__default.createElement("div", { className: "checkbox", key: notification.id },
|
|
24250
|
+
React__default.createElement("label", { className: "checkbox__label" },
|
|
24251
|
+
React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: notification.isConfirmed, onChange: (e) => handleNotificationChange(notification.id, e.target.checked) }),
|
|
24252
|
+
React__default.createElement("span", { className: "checkbox__label-text" },
|
|
24253
|
+
React__default.createElement("strong", { className: "checkbox__label-text--title" }, notification.title),
|
|
24254
|
+
React__default.createElement("span", { className: "checkbox__label-text--description" }, notification.description))))))))))))),
|
|
24255
|
+
React__default.createElement("div", { className: "form__region" },
|
|
24256
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24257
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24258
|
+
React__default.createElement("div", { className: "form__region-header" },
|
|
24259
|
+
React__default.createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.REMARKS)))),
|
|
24260
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24261
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24262
|
+
React__default.createElement("textarea", { className: "form__input", defaultValue: remarks, onChange: (e) => handleRemarksChange(e.target.value) })))),
|
|
24263
|
+
React__default.createElement("div", { className: "form__region" },
|
|
24264
|
+
React__default.createElement("div", { className: "form__row" },
|
|
24265
|
+
React__default.createElement("div", { className: "form__group" },
|
|
24266
|
+
React__default.createElement("div", { className: "info-message" },
|
|
24267
|
+
React__default.createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
|
|
24268
|
+
React__default.createElement("div", { className: "info-message__copy" },
|
|
24269
|
+
React__default.createElement("h5", null, translations.SUMMARY.VALIDATE_TITLE),
|
|
24270
|
+
settings.customValidateText ? (React__default.createElement("div", { dangerouslySetInnerHTML: {
|
|
24271
|
+
__html: settings.customValidateText
|
|
24272
|
+
} })) : (React__default.createElement(React__default.Fragment, null,
|
|
24273
|
+
React__default.createElement("p", null, settings.isOffer ? translations.SUMMARY.VALIDATE_TEXT_OFFER : translations.SUMMARY.VALIDATE_TEXT_BOOKING),
|
|
24274
|
+
settings.allowOption && React__default.createElement("p", null, translations.SUMMARY.VALIDATE_TEXT_OPTION))),
|
|
24275
|
+
checkboxes &&
|
|
24276
|
+
checkboxes.map((checkbox) => (React__default.createElement("div", { className: "checkbox", key: checkbox.id },
|
|
24277
|
+
React__default.createElement("label", { className: "checkbox__label" },
|
|
24278
|
+
React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: checkbox.isSelected, onChange: (e) => handleCheckboxChange(checkbox.id, e.target.checked) }),
|
|
24279
|
+
React__default.createElement("span", { className: "checkbox__label-text", dangerouslySetInnerHTML: {
|
|
24280
|
+
__html: checkbox.text
|
|
24281
|
+
} }))))))))))),
|
|
24282
|
+
React__default.createElement("div", { className: "booking__navigator" },
|
|
24283
|
+
settings.skipRouter ? (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => goPrevious(), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : (React__default.createElement(Link, { to: `${!settings.skipBasePathInRouting ? settings.basePath : ''}${travelersFirstStep ? settings.options.pathSuffix : settings.travellers.pathSuffix}?${bookingQueryString}`, title: translations.STEPS.PREVIOUS, className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)),
|
|
24284
|
+
settings.allowOption && (React__default.createElement("button", { title: translations.STEPS.SUBMIT_OPTION, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "option" }, translations.STEPS.SUBMIT_OPTION)),
|
|
24285
|
+
React__default.createElement("button", { title: settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "default" }, settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING))))));
|
|
23793
24286
|
};
|
|
23794
24287
|
|
|
23795
24288
|
function isValidEmail(email) {
|
|
@@ -23813,7 +24306,7 @@ function getAge(birthDateText, startDateText) {
|
|
|
23813
24306
|
}
|
|
23814
24307
|
return age;
|
|
23815
24308
|
}
|
|
23816
|
-
const validateForm$1 = (values, agentRequired, bookingType, translations, formFields, mainBookerFormFields, maxChildAge = CHILD_MAX_AGE, maxBabyAge = BABY_MAX_AGE,
|
|
24309
|
+
const validateForm$1 = (values, agentRequired, bookingType, translations, formFields, mainBookerFormFields, maxChildAge = CHILD_MAX_AGE, maxBabyAge = BABY_MAX_AGE, paxFields = []) => {
|
|
23817
24310
|
const errors = {};
|
|
23818
24311
|
const isFormFieldPresent = (type) => {
|
|
23819
24312
|
return formFields?.some((f) => f.type === type) ?? true;
|
|
@@ -23851,7 +24344,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
23851
24344
|
};
|
|
23852
24345
|
const validateRequiredCustomFields = (traveler, path, room, pax) => {
|
|
23853
24346
|
const isMainBooker = traveler.id === values.mainBookerId;
|
|
23854
|
-
const requiredFields = getApplicablePaxCustomFields(
|
|
24347
|
+
const requiredFields = getApplicablePaxCustomFields(paxFields, isMainBooker).filter((f) => f.isRequired);
|
|
23855
24348
|
requiredFields.forEach((field) => {
|
|
23856
24349
|
const fieldIndex = traveler.customFields?.findIndex((c) => c.customFieldConfigurationId === field.customFieldConfigurationId) ?? -1;
|
|
23857
24350
|
if (fieldIndex < 0)
|
|
@@ -23861,6 +24354,19 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
23861
24354
|
}
|
|
23862
24355
|
});
|
|
23863
24356
|
};
|
|
24357
|
+
// Excludes the 4 core fields, which are already validated unconditionally below.
|
|
24358
|
+
const validateRequiredBuiltInFields = (traveler, path, room, pax) => {
|
|
24359
|
+
const isMainBooker = traveler.id === values.mainBookerId;
|
|
24360
|
+
const requiredFields = getApplicableBuiltInPaxFields(paxFields, isMainBooker).filter((f) => f.isRequired && !CORE_FIELD_NAMES.has(f.fieldName));
|
|
24361
|
+
requiredFields.forEach((field) => {
|
|
24362
|
+
const fieldPath = BUILT_IN_FIELD_PATHS[field.fieldName];
|
|
24363
|
+
if (!fieldPath)
|
|
24364
|
+
return;
|
|
24365
|
+
if (isEmpty$1(get(traveler, fieldPath))) {
|
|
24366
|
+
set(errors, `${path}.${fieldPath}`, formatTravelerField(room, pax, field.fieldName));
|
|
24367
|
+
}
|
|
24368
|
+
});
|
|
24369
|
+
};
|
|
23864
24370
|
values.rooms.forEach((r, rIndex) => r.adults.forEach((adult, index) => {
|
|
23865
24371
|
if (isEmpty$1(adult.gender) && isFormFieldPresent('gender')) {
|
|
23866
24372
|
set(errors, `rooms[${rIndex}].adults[${index}].gender`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.GENDER));
|
|
@@ -23894,6 +24400,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
23894
24400
|
}
|
|
23895
24401
|
}
|
|
23896
24402
|
validateRequiredCustomFields(adult, `rooms[${rIndex}].adults[${index}]`, rIndex + 1, index + 1);
|
|
24403
|
+
validateRequiredBuiltInFields(adult, `rooms[${rIndex}].adults[${index}]`, rIndex + 1, index + 1);
|
|
23897
24404
|
}));
|
|
23898
24405
|
values.rooms.forEach((r, rIndex) => r.children.forEach((child, index) => {
|
|
23899
24406
|
if (isEmpty$1(child.gender) && isFormFieldPresent('gender')) {
|
|
@@ -23936,6 +24443,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
23936
24443
|
}
|
|
23937
24444
|
}
|
|
23938
24445
|
validateRequiredCustomFields(child, `rooms[${rIndex}].children[${index}]`, rIndex + 1, r.adults.length + index + 1);
|
|
24446
|
+
validateRequiredBuiltInFields(child, `rooms[${rIndex}].children[${index}]`, rIndex + 1, r.adults.length + index + 1);
|
|
23939
24447
|
}));
|
|
23940
24448
|
if (values.mainBookerId < 0) {
|
|
23941
24449
|
errors.mainBookerId = translations.TRAVELERS_FORM.VALIDATION.NO_MAIN_BOOKER_SELECTED;
|
|
@@ -24003,15 +24511,13 @@ const TravelersForm = () => {
|
|
|
24003
24511
|
const bookingAttributes = useSelector(selectBookingAttributes);
|
|
24004
24512
|
const hasMounted = useSelector(selectHasMounted);
|
|
24005
24513
|
const countries = useSelector(selectCountries);
|
|
24006
|
-
const
|
|
24514
|
+
const paxFields = useSelector(selectPaxFields);
|
|
24007
24515
|
const inFlight = useRef(false);
|
|
24008
24516
|
const pendingRefetch = useRef(false);
|
|
24009
24517
|
const useCompactForm = !!settings.travellers.compactForm && !!settings.agentAdressId;
|
|
24010
24518
|
const showAllCountries = !!settings.travellers.showAllCountries;
|
|
24011
|
-
const showWeightField = !!settings.travellers.showWeightField;
|
|
24012
|
-
const showHeightField = !!settings.travellers.showHeightField;
|
|
24013
24519
|
const initialValues = useSelector(selectTravelersFormValues) ??
|
|
24014
|
-
createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm, settings.maxBabyAge,
|
|
24520
|
+
createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm, settings.maxBabyAge, paxFields);
|
|
24015
24521
|
const [showAgentSelection, setShowAgentSelection] = useState(!settings.agentAdressId && !settings.hideAgentSelection);
|
|
24016
24522
|
const formik = useFormik({
|
|
24017
24523
|
initialValues,
|
|
@@ -24021,7 +24527,7 @@ const TravelersForm = () => {
|
|
|
24021
24527
|
// The travel dates are captured into initialValues once and then persisted in
|
|
24022
24528
|
// redux, so validating against the values would use the dates of whichever
|
|
24023
24529
|
// package option was selected first. Age checks need the current ones.
|
|
24024
|
-
{ ...values, startDate, endDate }, settings.agentRequired, bookingType, translations, settings.travellers.formFields, settings.travellers.mainBookerFormFields, settings.maxChildAge, settings.maxBabyAge,
|
|
24530
|
+
{ ...values, startDate, endDate }, settings.agentRequired, bookingType, translations, settings.travellers.formFields, settings.travellers.mainBookerFormFields, settings.maxChildAge, settings.maxBabyAge, paxFields),
|
|
24025
24531
|
onSubmit: (values) => {
|
|
24026
24532
|
dispatch(setFormValues(values));
|
|
24027
24533
|
if (useCompactForm) {
|
|
@@ -24104,7 +24610,7 @@ const TravelersForm = () => {
|
|
|
24104
24610
|
dispatch(setFormValues(formValues));
|
|
24105
24611
|
setShowAgentSelection(false);
|
|
24106
24612
|
}, [agents, settings.affiliateSlug]);
|
|
24107
|
-
return (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: settings.travellers, countries: countries, agents: agents, bookingType: bookingType, agentAdressId: agentAdressId, travelersFirstStep: travelersFirstStep, isUnavailable: isUnavailable, useCompactForm: useCompactForm, showAllCountries: showAllCountries,
|
|
24613
|
+
return (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: settings.travellers, countries: countries, agents: agents, bookingType: bookingType, agentAdressId: agentAdressId, travelersFirstStep: travelersFirstStep, isUnavailable: isUnavailable, useCompactForm: useCompactForm, showAllCountries: showAllCountries, paxFields: paxFields, showAgentSelection: showAgentSelection, initialShowAgents: settings.agentRequired ?? false, onBookingTypeChange: (nextBookingType) => dispatch(setBookingType(nextBookingType)), renderPreviousButton: () => !travelersFirstStep && settings.skipRouter ? (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => dispatch(setCurrentStep$1(OPTIONS_FORM_STEP)), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : !travelersFirstStep ? (React__default.createElement(Link, { to: `${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.options.pathSuffix}?${bookingQueryString}`, title: translations.STEPS.PREVIOUS, className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : null }));
|
|
24108
24614
|
};
|
|
24109
24615
|
|
|
24110
24616
|
const Booking = ({ productCode, productName, thumbnailUrl }) => {
|
|
@@ -28251,6 +28757,22 @@ const getPackagingRequestRoomsFromBookingRooms = (rooms) => {
|
|
|
28251
28757
|
});
|
|
28252
28758
|
};
|
|
28253
28759
|
|
|
28760
|
+
// Administrative service lines (fees, insurances, reductions, ...) live on the entry but say
|
|
28761
|
+
// nothing about the journey itself, so the itinerary never draws them.
|
|
28762
|
+
const HIDDEN_ITINERARY_SERVICE_TYPES = new Set([
|
|
28763
|
+
build.ServiceType.insurance,
|
|
28764
|
+
build.ServiceType.extraService,
|
|
28765
|
+
build.ServiceType.serviceFee,
|
|
28766
|
+
build.ServiceType.gift,
|
|
28767
|
+
build.ServiceType.reduction,
|
|
28768
|
+
build.ServiceType.fee,
|
|
28769
|
+
build.ServiceType.visum,
|
|
28770
|
+
build.ServiceType.voucher,
|
|
28771
|
+
build.ServiceType.specialServices
|
|
28772
|
+
]);
|
|
28773
|
+
const isMeaningfulItineraryLine = (line) => {
|
|
28774
|
+
return !HIDDEN_ITINERARY_SERVICE_TYPES.has(line.serviceType ?? -1);
|
|
28775
|
+
};
|
|
28254
28776
|
const getFlightLines = (flight) => {
|
|
28255
28777
|
return flight?.flightInformation?.flightLines ?? [];
|
|
28256
28778
|
};
|
|
@@ -28705,6 +29227,8 @@ const applyResultToLine = (line, result, roomIndex = 0) => {
|
|
|
28705
29227
|
isChanged: true
|
|
28706
29228
|
};
|
|
28707
29229
|
};
|
|
29230
|
+
const buildNodeSelectionLines = (item, result, bookedMode) => bookedMode && matchesCode(result, item.node.code ?? '') ? item.lines : applyResultToLines(item.lines, result);
|
|
29231
|
+
const buildFlightSelectionLine = (item, flight, bookedMode) => bookedMode && flight.outwardGuid === item.line.guid ? item.line : applyFlightToLine(item.line, flight);
|
|
28708
29232
|
const toDateOnlyUtcString = (value) => {
|
|
28709
29233
|
const date = new Date(value);
|
|
28710
29234
|
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
|
|
@@ -28762,11 +29286,21 @@ const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
|
28762
29286
|
* mapper gave them. This swaps in the guid of whatever each line resolved onto, leaving the
|
|
28763
29287
|
* lines the traveller added themselves alone — those were built from a search result and already
|
|
28764
29288
|
* carry the right one.
|
|
29289
|
+
*
|
|
29290
|
+
* A booked entry (the traject was rebuilt from a magic-link entry) is the other way around: its
|
|
29291
|
+
* lines live in the dossier under their own guids, and only a line the traveller actually swapped
|
|
29292
|
+
* (isChanged) exists in the search cache. Swapping an untouched line's guid would orphan it —
|
|
29293
|
+
* the backend drops the dossier line and finds nothing to add — so those keep theirs.
|
|
28765
29294
|
*/
|
|
28766
29295
|
const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightAvailability) => {
|
|
28767
29296
|
const cachedGuids = new Map();
|
|
29297
|
+
const bookedMode = !!trajectEntry.entry.magicLink;
|
|
29298
|
+
const editableByGuid = new Map((entry.lines ?? []).map((line) => [line.guid, line]));
|
|
29299
|
+
const keepsOwnGuid = (guid) => bookedMode && !editableByGuid.get(guid)?.isChanged;
|
|
28768
29300
|
getTrajectNodesWithLines(trajectEntry).forEach((item) => {
|
|
28769
29301
|
if (isTrajectFlightNode(item.node)) {
|
|
29302
|
+
if (keepsOwnGuid(item.line.guid))
|
|
29303
|
+
return;
|
|
28770
29304
|
// A flight search caches the outward line under the guid it reports as outwardGuid.
|
|
28771
29305
|
const guid = flightAvailability[item.line.guid]?.selectedGuid;
|
|
28772
29306
|
if (guid)
|
|
@@ -28779,6 +29313,8 @@ const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightA
|
|
|
28779
29313
|
return;
|
|
28780
29314
|
// Room i took option i when the result was stamped on, so it takes option i here too.
|
|
28781
29315
|
item.lines.forEach((line, index) => {
|
|
29316
|
+
if (keepsOwnGuid(line.guid))
|
|
29317
|
+
return;
|
|
28782
29318
|
const guid = getOptionForRoom(result, index)?.guid;
|
|
28783
29319
|
if (guid)
|
|
28784
29320
|
cachedGuids.set(line.guid, guid);
|
|
@@ -28842,7 +29378,7 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
|
|
|
28842
29378
|
return { node, lines };
|
|
28843
29379
|
});
|
|
28844
29380
|
const claimed = new Set(nodes.flatMap((item) => item.lines.map((line) => line.guid)));
|
|
28845
|
-
const extras = (packagingEntry.lines ?? []).filter((line) => !claimed.has(line.guid));
|
|
29381
|
+
const extras = (packagingEntry.lines ?? []).filter((line) => !claimed.has(line.guid)).filter(isMeaningfulItineraryLine);
|
|
28846
29382
|
if (!extras.length)
|
|
28847
29383
|
return nodes;
|
|
28848
29384
|
const dayOrderOf = (date) => trajectEntry.traject.days.find((day) => isSameDay(new Date(day.date), new Date(date)))?.order ??
|
|
@@ -29019,6 +29555,195 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
|
|
|
29019
29555
|
})));
|
|
29020
29556
|
};
|
|
29021
29557
|
|
|
29558
|
+
/**
|
|
29559
|
+
* A booked entry opened through its magic link knows nothing about the traject it may once have
|
|
29560
|
+
* been composed from — the dossier only keeps the lines. To give it the same day-by-day services
|
|
29561
|
+
* screen a traject gets, the traject structure is rebuilt from those lines: every booked service
|
|
29562
|
+
* becomes a node whose one "alternative" is the booked product itself, and the days span the trip.
|
|
29563
|
+
*
|
|
29564
|
+
* The synthesized response keeps the entry untouched (magic link included), which is also how the
|
|
29565
|
+
* rest of the component tells this mode apart from a real traject: see isBookedEntryTraject.
|
|
29566
|
+
*/
|
|
29567
|
+
const isBookedEntryTraject = (trajectEntry) => !!trajectEntry?.entry?.magicLink;
|
|
29568
|
+
const NODE_SERVICE_TYPES = new Set([ACCOMMODATION_SERVICE_TYPE, EXCURSION_SERVICE_TYPE, FLIGHT_SERVICE_TYPE]);
|
|
29569
|
+
/**
|
|
29570
|
+
* A room or option line joins its parent's node; a flight line never does — an outward and its
|
|
29571
|
+
* return are separate legs of the trip even though the return points at the outward as parent.
|
|
29572
|
+
*/
|
|
29573
|
+
const groupNodeLines = (lines) => {
|
|
29574
|
+
const groups = [];
|
|
29575
|
+
const groupByGuid = new Map();
|
|
29576
|
+
lines.forEach((line) => {
|
|
29577
|
+
const parentGroup = line.serviceType !== FLIGHT_SERVICE_TYPE && line.parentGuid ? groupByGuid.get(line.parentGuid) : undefined;
|
|
29578
|
+
if (parentGroup) {
|
|
29579
|
+
parentGroup.push(line);
|
|
29580
|
+
return;
|
|
29581
|
+
}
|
|
29582
|
+
const group = [line];
|
|
29583
|
+
groups.push(group);
|
|
29584
|
+
groupByGuid.set(line.guid, group);
|
|
29585
|
+
});
|
|
29586
|
+
return groups;
|
|
29587
|
+
};
|
|
29588
|
+
const buildBookedTrajectEntry = (entry) => {
|
|
29589
|
+
const lines = (entry.lines ?? []).filter((line) => NODE_SERVICE_TYPES.has(line.serviceType));
|
|
29590
|
+
const froms = lines.map((line) => new Date(line.from).getTime());
|
|
29591
|
+
const tos = lines.map((line) => new Date(line.to).getTime());
|
|
29592
|
+
const start = froms.length ? new Date(Math.min(...froms)) : new Date();
|
|
29593
|
+
const end = tos.length ? new Date(Math.max(...tos)) : start;
|
|
29594
|
+
const dayCount = Math.max(differenceInCalendarDays(end, start), 0) + 1;
|
|
29595
|
+
const days = Array.from({ length: dayCount }, (_, order) => ({
|
|
29596
|
+
order,
|
|
29597
|
+
name: '',
|
|
29598
|
+
date: toDateOnlyString(addDays(start, order))
|
|
29599
|
+
}));
|
|
29600
|
+
const nodes = groupNodeLines(lines).map((groupLines, index) => {
|
|
29601
|
+
const line = groupLines[0];
|
|
29602
|
+
const flightLines = line.flightInformation?.flightLines ?? [];
|
|
29603
|
+
return {
|
|
29604
|
+
lineGuid: line.guid,
|
|
29605
|
+
lineGuids: groupLines.map((x) => x.guid),
|
|
29606
|
+
nodeId: index + 1,
|
|
29607
|
+
dayOrder: Math.max(differenceInCalendarDays(new Date(line.from), start), 0),
|
|
29608
|
+
order: line.order,
|
|
29609
|
+
name: line.productName,
|
|
29610
|
+
serviceType: line.serviceType,
|
|
29611
|
+
trajectNodeType: REGULAR_TRAJECT_NODE_TYPE,
|
|
29612
|
+
requirementType: 0,
|
|
29613
|
+
contentSource: 0,
|
|
29614
|
+
code: line.productCode,
|
|
29615
|
+
preferredAccommodationCode: line.productCode,
|
|
29616
|
+
preferredAccommodationName: line.productName,
|
|
29617
|
+
alternatives: [],
|
|
29618
|
+
departureAirportCode: first(flightLines)?.departureAirportCode ?? null,
|
|
29619
|
+
arrivalAirportCode: last(flightLines)?.arrivalAirportCode ?? null,
|
|
29620
|
+
duration: 0,
|
|
29621
|
+
durationType: 0,
|
|
29622
|
+
from: line.from,
|
|
29623
|
+
to: line.to
|
|
29624
|
+
};
|
|
29625
|
+
});
|
|
29626
|
+
return {
|
|
29627
|
+
entry,
|
|
29628
|
+
traject: {
|
|
29629
|
+
id: 0,
|
|
29630
|
+
name: entry.dossierNumber ?? '',
|
|
29631
|
+
imageUrl: null,
|
|
29632
|
+
startDate: days[0]?.date ?? toDateOnlyString(start),
|
|
29633
|
+
endDate: last(days)?.date ?? toDateOnlyString(end),
|
|
29634
|
+
durationInDays: days.length,
|
|
29635
|
+
includeGroupHotelAlternatives: false,
|
|
29636
|
+
days
|
|
29637
|
+
},
|
|
29638
|
+
nodes
|
|
29639
|
+
};
|
|
29640
|
+
};
|
|
29641
|
+
/**
|
|
29642
|
+
* The card for a booked service when no search result carries it any more (sold out, delisted).
|
|
29643
|
+
* Rendered from the line, so the traveller still sees what they booked; price 0 makes the card
|
|
29644
|
+
* leave its price out — the paid price lives in the price details, not on the line.
|
|
29645
|
+
*/
|
|
29646
|
+
const buildBookedNodeResult = (node, lines) => {
|
|
29647
|
+
const line = lines[0];
|
|
29648
|
+
return {
|
|
29649
|
+
code: line.productCode,
|
|
29650
|
+
name: line.productName,
|
|
29651
|
+
serviceType: line.serviceType,
|
|
29652
|
+
countryId: line.country?.id ?? null,
|
|
29653
|
+
countryName: line.country?.name ?? '',
|
|
29654
|
+
regionId: line.region?.id ?? null,
|
|
29655
|
+
regionName: line.region?.name ?? '',
|
|
29656
|
+
oordId: line.oord?.id ?? null,
|
|
29657
|
+
oordName: line.oord?.name ?? '',
|
|
29658
|
+
locationId: line.location?.id ?? null,
|
|
29659
|
+
locationName: line.location?.name ?? '',
|
|
29660
|
+
latitude: line.latitude ?? null,
|
|
29661
|
+
longitude: line.longitude ?? null,
|
|
29662
|
+
price: 0,
|
|
29663
|
+
averagePricePerPerson: 0,
|
|
29664
|
+
originalPrice: 0,
|
|
29665
|
+
originalAveragePricePerPerson: 0,
|
|
29666
|
+
currencyCode: 'EUR',
|
|
29667
|
+
fromDate: line.from,
|
|
29668
|
+
toDate: line.to,
|
|
29669
|
+
contents: '',
|
|
29670
|
+
rooms: lines.map((roomLine) => ({
|
|
29671
|
+
options: [
|
|
29672
|
+
{
|
|
29673
|
+
price: 0,
|
|
29674
|
+
originalPrice: 0,
|
|
29675
|
+
accommodationCode: roomLine.accommodationCode ?? '',
|
|
29676
|
+
accommodationName: roomLine.accommodationName ?? '',
|
|
29677
|
+
regimeCode: roomLine.regimeCode ?? '',
|
|
29678
|
+
regimeName: roomLine.regimeName ?? '',
|
|
29679
|
+
isSelected: true,
|
|
29680
|
+
guid: roomLine.guid,
|
|
29681
|
+
paxIds: (roomLine.pax ?? []).map((pax) => pax.paxId)
|
|
29682
|
+
}
|
|
29683
|
+
]
|
|
29684
|
+
}))
|
|
29685
|
+
};
|
|
29686
|
+
};
|
|
29687
|
+
/**
|
|
29688
|
+
* The flight search API serializes these as ISO strings, whatever the type declaration says, and
|
|
29689
|
+
* the store must stay serializable — so the synthesized segments carry the same string form.
|
|
29690
|
+
*/
|
|
29691
|
+
const toDateTime = (date, time) => `${toDateOnlyString(date)}T${time || '00:00:00'}`;
|
|
29692
|
+
/** The booked flight as a flight result, so the card that shows it is the card the search results use. */
|
|
29693
|
+
const buildBookedFlightResult = (line) => {
|
|
29694
|
+
const flightLines = line.flightInformation?.flightLines ?? [];
|
|
29695
|
+
const segments = flightLines.map((flightLine, index) => ({
|
|
29696
|
+
order: index,
|
|
29697
|
+
flightNumber: flightLine.flightNumber,
|
|
29698
|
+
operatingFlightNumber: flightLine.operatingFlightNumber ?? flightLine.flightNumber,
|
|
29699
|
+
marketingAirlineCode: flightLine.airlineCode,
|
|
29700
|
+
marketingAirlineName: flightLine.airlineDescription,
|
|
29701
|
+
operatingAirlineCode: flightLine.operatingAirlineCode ?? flightLine.airlineCode,
|
|
29702
|
+
operatingAirlineName: flightLine.operatingAirlineDescription ?? flightLine.airlineDescription,
|
|
29703
|
+
departureAirportCode: flightLine.departureAirportCode,
|
|
29704
|
+
departureAirportName: flightLine.departureAirportDescription,
|
|
29705
|
+
arrivalAirportCode: flightLine.arrivalAirportCode,
|
|
29706
|
+
arrivalAirportName: flightLine.arrivalAirportDescription,
|
|
29707
|
+
departureDateTime: toDateTime(flightLine.departureDate, flightLine.departureTime),
|
|
29708
|
+
arrivalDateTime: toDateTime(flightLine.arrivalDate, flightLine.arrivalTime),
|
|
29709
|
+
bookingClassCode: '',
|
|
29710
|
+
travelClass: 0,
|
|
29711
|
+
durationInTicks: flightLine.durationInTicks ?? 0
|
|
29712
|
+
}));
|
|
29713
|
+
const firstSegment = first(segments);
|
|
29714
|
+
const lastSegment = last(segments);
|
|
29715
|
+
// .NET ticks are 100ns, so a millisecond is 10 000 of them.
|
|
29716
|
+
const durationInTicks = firstSegment && lastSegment ? (new Date(lastSegment.arrivalDateTime).getTime() - new Date(firstSegment.departureDateTime).getTime()) * 10_000 : 0;
|
|
29717
|
+
return {
|
|
29718
|
+
code: line.productCode,
|
|
29719
|
+
name: line.productName,
|
|
29720
|
+
serviceType: line.serviceType,
|
|
29721
|
+
countryName: '',
|
|
29722
|
+
regionName: '',
|
|
29723
|
+
oordName: '',
|
|
29724
|
+
locationName: '',
|
|
29725
|
+
price: 0,
|
|
29726
|
+
averagePricePerPerson: 0,
|
|
29727
|
+
originalPrice: 0,
|
|
29728
|
+
originalAveragePricePerPerson: 0,
|
|
29729
|
+
currencyCode: 'EUR',
|
|
29730
|
+
fromDate: line.from,
|
|
29731
|
+
toDate: line.to,
|
|
29732
|
+
flightRouteId: line.guid,
|
|
29733
|
+
airlineCode: firstSegment?.marketingAirlineCode ?? '',
|
|
29734
|
+
airlineName: firstSegment?.marketingAirlineName ?? '',
|
|
29735
|
+
isLuggageIncluded: false,
|
|
29736
|
+
luggageInfo: '',
|
|
29737
|
+
outwardGuid: line.guid,
|
|
29738
|
+
outward: { code: line.productCode, fareType: 0, durationInTicks, segments },
|
|
29739
|
+
returnGuid: '',
|
|
29740
|
+
return: { code: '', fareType: 0, durationInTicks: 0, segments: [] },
|
|
29741
|
+
source: 0,
|
|
29742
|
+
provider: '',
|
|
29743
|
+
paxes: []
|
|
29744
|
+
};
|
|
29745
|
+
};
|
|
29746
|
+
|
|
29022
29747
|
const getSegmentIcon = (segment) => {
|
|
29023
29748
|
switch (segment.serviceType) {
|
|
29024
29749
|
case 3:
|
|
@@ -29058,14 +29783,14 @@ const SERVICE_TYPE_PRIORITY = {
|
|
|
29058
29783
|
const getServiceTypePriority = (serviceType) => {
|
|
29059
29784
|
return SERVICE_TYPE_PRIORITY[serviceType ?? -1] ?? 2;
|
|
29060
29785
|
};
|
|
29061
|
-
const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation }) => {
|
|
29786
|
+
const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation, onSaveEntry }) => {
|
|
29062
29787
|
const context = useContext(SearchResultsConfigurationContext);
|
|
29063
29788
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
29064
29789
|
const { editablePackagingEntry, priceDetails, trajectItineraryView } = useSelector((state) => state.searchResults);
|
|
29065
29790
|
const dispatch = useDispatch();
|
|
29066
29791
|
const packagingEntry = editablePackagingEntry ?? context?.packagingEntry;
|
|
29067
29792
|
const sortedLines = useMemo(() => {
|
|
29068
|
-
return
|
|
29793
|
+
return (packagingEntry?.lines ?? []).filter(isMeaningfulItineraryLine).sort((a, b) => {
|
|
29069
29794
|
const dateA = getDateOnlyTime(a.from);
|
|
29070
29795
|
const dateB = getDateOnlyTime(b.from);
|
|
29071
29796
|
if (dateA !== dateB) {
|
|
@@ -29136,7 +29861,7 @@ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation })
|
|
|
29136
29861
|
" ",
|
|
29137
29862
|
translations.SRP.TOTAL,
|
|
29138
29863
|
")"))),
|
|
29139
|
-
React__default.createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM),
|
|
29864
|
+
isBookedEntryTraject(context?.trajectEntry) ? (React__default.createElement("button", { className: "cta", onClick: onSaveEntry, disabled: !(packagingEntry?.lines ?? []).some((line) => line.isChanged) }, translations.SHARED.SAVE)) : (React__default.createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM)),
|
|
29140
29865
|
!!context?.trajectEntry && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleTrajectView(!trajectItineraryView) }, trajectItineraryView ? translations.SRP.SHOW_SERVICES : translations.SRP.VIEW_FULL_ITINERARY))))),
|
|
29141
29866
|
React__default.createElement("div", { className: "search__filter__itinerary" },
|
|
29142
29867
|
React__default.createElement("p", null, translations.SRP.DAY_BY_DAY),
|
|
@@ -31193,7 +31918,7 @@ const selectSelectedCombinationFlight = createSelector([selectPackagingFlightRes
|
|
|
31193
31918
|
return (packagingFlightResults.find((flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey && getFlightKey(flight.return.segments) === selectedReturnKey) ?? null);
|
|
31194
31919
|
});
|
|
31195
31920
|
|
|
31196
|
-
const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward, showSelectedState, currentSelectedPrice, price }) => {
|
|
31921
|
+
const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward, showSelectedState, currentSelectedPrice, price, selectLabel, selectedLabel }) => {
|
|
31197
31922
|
const context = useContext(SearchResultsConfigurationContext);
|
|
31198
31923
|
const language = context?.languageCode ?? 'en-GB';
|
|
31199
31924
|
const translations = getTranslations(language);
|
|
@@ -31218,7 +31943,7 @@ const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward
|
|
|
31218
31943
|
priceDifference > 0 ? '+' : '-',
|
|
31219
31944
|
"\u00A0",
|
|
31220
31945
|
formatPrice$3(Math.abs(priceDifference), 'EUR', context?.languageCode ?? 'en-GB'))))),
|
|
31221
|
-
React__default.createElement("button", { type: "button", className: `cta ${selectedGuid === guid ? 'cta--selected' : 'cta--select'}`, onClick: () => onSelect?.() }, selectedGuid === guid ?
|
|
31946
|
+
React__default.createElement("button", { type: "button", className: `cta ${selectedGuid === guid ? 'cta--selected' : 'cta--select'}`, onClick: () => onSelect?.() }, selectedGuid === guid ? selectedLabel ?? translations.SHARED.SELECTED : selectLabel ?? translations.SHARED.SELECT)))),
|
|
31222
31947
|
React__default.createElement("div", { className: "flight__flight" },
|
|
31223
31948
|
React__default.createElement("div", { className: "flight__flight__container" },
|
|
31224
31949
|
React__default.createElement("div", { className: "flight__flight__wrapper" },
|
|
@@ -31852,7 +32577,7 @@ const TrajectNodeCard = ({ node, result, isSelected, languageCode, translations,
|
|
|
31852
32577
|
const image = candidate?.imageUrl ?? null;
|
|
31853
32578
|
const description = toPlainText(candidate?.description);
|
|
31854
32579
|
const title = candidate?.name ?? result.name;
|
|
31855
|
-
const priceBlock = (React__default.createElement("div", { className: "search__result-card__price__wrapper" },
|
|
32580
|
+
const priceBlock = result.price > 0 && (React__default.createElement("div", { className: "search__result-card__price__wrapper" },
|
|
31856
32581
|
React__default.createElement("span", { className: "search__result-card__price__label" }, translations?.SHARED.TOTAL_PRICE),
|
|
31857
32582
|
React__default.createElement("span", { className: "search__result-card__price" }, price)));
|
|
31858
32583
|
const canEditOptions = isSelected && !!onEditOptions && (result.rooms ?? []).some((room) => (room.options ?? []).length > 1);
|
|
@@ -31905,6 +32630,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
|
|
|
31905
32630
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
31906
32631
|
const { trajectNodeAvailability, trajectEditLineGuid } = useSelector((state) => state.searchResults);
|
|
31907
32632
|
const trajectEntry = context?.trajectEntry;
|
|
32633
|
+
const bookedMode = isBookedEntryTraject(trajectEntry);
|
|
31908
32634
|
const item = useMemo(() => {
|
|
31909
32635
|
if (!trajectEntry || !trajectEditLineGuid)
|
|
31910
32636
|
return null;
|
|
@@ -31924,7 +32650,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
|
|
|
31924
32650
|
if (!result)
|
|
31925
32651
|
return;
|
|
31926
32652
|
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
|
|
31927
|
-
|
|
32653
|
+
buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
31928
32654
|
dispatch(setTrajectEditLineGuid(null));
|
|
31929
32655
|
dispatch(setFlyInIsOpen(false));
|
|
31930
32656
|
};
|
|
@@ -31937,7 +32663,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
|
|
|
31937
32663
|
ordered.length,
|
|
31938
32664
|
"\u00A0",
|
|
31939
32665
|
translations.SRP.TOTAL_RESULTS_LABEL)),
|
|
31940
|
-
ordered.length === 0 ? (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default.createElement("div", { className: "search__results__cards" }, ordered.map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: item.node, result: result, isSelected: result.code === availability?.selectedCode, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(result.code), showNights: item.node.serviceType === ACCOMMODATION_SERVICE_TYPE })))))));
|
|
32666
|
+
ordered.length === 0 ? (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default.createElement("div", { className: "search__results__cards" }, ordered.map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: item.node, result: result, isSelected: result.code === availability?.selectedCode, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(result.code), showNights: item.node.serviceType === ACCOMMODATION_SERVICE_TYPE, selectedLabel: bookedMode && matchesCode(result, item.node.code ?? '') ? translations.SHARED.BOOKED : undefined })))))));
|
|
31941
32667
|
};
|
|
31942
32668
|
|
|
31943
32669
|
/**
|
|
@@ -31999,6 +32725,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
31999
32725
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
32000
32726
|
const { trajectNodeAvailability, trajectDaySuggestions, trajectActivitiesDayOrder, editablePackagingEntry } = useSelector((state) => state.searchResults);
|
|
32001
32727
|
const trajectEntry = context?.trajectEntry;
|
|
32728
|
+
const bookedMode = isBookedEntryTraject(trajectEntry);
|
|
32002
32729
|
const items = useMemo(() => {
|
|
32003
32730
|
if (!trajectEntry || trajectActivitiesDayOrder === null)
|
|
32004
32731
|
return [];
|
|
@@ -32031,7 +32758,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
32031
32758
|
if (!item)
|
|
32032
32759
|
return;
|
|
32033
32760
|
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code: result.code }));
|
|
32034
|
-
|
|
32761
|
+
buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
32035
32762
|
dispatch(setTrajectActivitiesDayOrder(null));
|
|
32036
32763
|
dispatch(setFlyInIsOpen(false));
|
|
32037
32764
|
};
|
|
@@ -32047,7 +32774,8 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
32047
32774
|
cards.length === 0 ? (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default.createElement("div", { className: "search__results__cards" }, cards.map((card) => {
|
|
32048
32775
|
const { result, item } = card;
|
|
32049
32776
|
const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedLines(result).length > 0;
|
|
32050
|
-
|
|
32777
|
+
const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
|
|
32778
|
+
return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(card) : handleToggle(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
|
|
32051
32779
|
})))));
|
|
32052
32780
|
};
|
|
32053
32781
|
|
|
@@ -33657,6 +34385,10 @@ const getUniqueItems = (items = []) => {
|
|
|
33657
34385
|
return true;
|
|
33658
34386
|
});
|
|
33659
34387
|
};
|
|
34388
|
+
const isMeaningfulItem = (item, lines) => {
|
|
34389
|
+
const line = lines.find((l) => l.guid === item.itemGuid);
|
|
34390
|
+
return !line || isMeaningfulItineraryLine(line);
|
|
34391
|
+
};
|
|
33660
34392
|
const findAccommodationForDay = (nodes, currentDay) => {
|
|
33661
34393
|
for (const node of nodes ?? []) {
|
|
33662
34394
|
const { startDay } = getNodeDayRange(node);
|
|
@@ -33738,7 +34470,7 @@ const buildItineraryHtml = (itinerary, translations, lines) => {
|
|
|
33738
34470
|
const { startDay } = getNodeDayRange(node);
|
|
33739
34471
|
const day = node.startDate ? format$2(node.startDate, 'd') : null;
|
|
33740
34472
|
const month = node.startDate ? format$2(node.startDate, 'MMM') : null;
|
|
33741
|
-
const uniqueItems = getUniqueItems(node.items ?? []);
|
|
34473
|
+
const uniqueItems = getUniqueItems(node.items ?? []).filter((item) => isMeaningfulItem(item, lines));
|
|
33742
34474
|
const hasItems = uniqueItems.length > 0;
|
|
33743
34475
|
const hasAccommodationInCurrentNode = uniqueItems.some(isAccommodationItem);
|
|
33744
34476
|
const activeAccommodation = findAccommodationForDay(allNodes, startDay);
|
|
@@ -33782,11 +34514,12 @@ const buildItineraryHtml = (itinerary, translations, lines) => {
|
|
|
33782
34514
|
`;
|
|
33783
34515
|
})
|
|
33784
34516
|
.join('');
|
|
33785
|
-
const
|
|
34517
|
+
const defaultItems = getUniqueItems(itinerary.defaultItems ?? []).filter((item) => isMeaningfulItem(item, lines));
|
|
34518
|
+
const defaultItemsHtml = defaultItems.length > 0
|
|
33786
34519
|
? `
|
|
33787
34520
|
<section class="itinerary-default-items">
|
|
33788
34521
|
<h2 class="itinerary-default-items__title">Algemene info</h2>
|
|
33789
|
-
${
|
|
34522
|
+
${defaultItems
|
|
33790
34523
|
.map((item) => `
|
|
33791
34524
|
<article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
|
|
33792
34525
|
${hasVisibleContent(item.contents)
|
|
@@ -34445,7 +35178,7 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
34445
35178
|
const formik = useFormik({
|
|
34446
35179
|
initialValues,
|
|
34447
35180
|
enableReinitialize: true,
|
|
34448
|
-
validate: (values) => validateForm$1(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields),
|
|
35181
|
+
validate: (values) => validateForm$1(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields, undefined, undefined, editablePackagingEntry?.paxFields ?? []),
|
|
34449
35182
|
onSubmit: (values) => {
|
|
34450
35183
|
if (!editablePackagingEntry)
|
|
34451
35184
|
return;
|
|
@@ -34530,7 +35263,7 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
34530
35263
|
".\u00A0",
|
|
34531
35264
|
stepLabels[step])) },
|
|
34532
35265
|
isConfirmationPage && isLoading && React__default.createElement(Spinner, { label: translations.SUMMARY.PROCESS_BOOKING }),
|
|
34533
|
-
currentStep === 0 && (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false })),
|
|
35266
|
+
currentStep === 0 && (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false, paxFields: editablePackagingEntry?.paxFields ?? [] })),
|
|
34534
35267
|
currentStep === 1 && (React__default.createElement(SharedSummary, { translations: translations, travelerFormValues: formik.values, isSubmitting: isSubmitting, skipPayment: !context.generatePaymentUrl, userValidated: userValidated, remarks: remarks, enableVoucher: false, allowOption: false, isOffer: false, onUserValidatedChange: setUserValidated, onRemarksChange: setRemarks, onSubmit: handleSummarySubmit, renderOptions: () => renderEditablePackagingEntrySummaryOptions(editablePackagingEntry, priceDetails, translations, selectedPackagingAccoResult?.currencyCode), renderPreviousButton: () => (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => dispatch(setCurrentStep(0)), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) })),
|
|
34535
35268
|
currentStep === 2 && (React__default.createElement(SharedConfirmation, { bookingNumber: bookingNumber ?? editablePackagingEntry?.dossierNumber ?? '', isOption: false, isOffer: false, translations: translations.CONFIRMATION })),
|
|
34536
35269
|
currentStep === 3 && React__default.createElement("div", null))),
|
|
@@ -34594,6 +35327,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34594
35327
|
const locale = getLocale(context?.languageCode ?? 'en-GB');
|
|
34595
35328
|
const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry } = useSelector((state) => state.searchResults);
|
|
34596
35329
|
const trajectEntry = context?.trajectEntry;
|
|
35330
|
+
const bookedMode = isBookedEntryTraject(trajectEntry);
|
|
34597
35331
|
const hideShowMoreResults = !!context?.hideShowMoreResults;
|
|
34598
35332
|
const loadDayActivitiesOnDemand = !!context?.loadDayActivitiesOnDemand;
|
|
34599
35333
|
const showNonPreferredHotels = !!context?.showNonPreferredHotels;
|
|
@@ -34650,7 +35384,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34650
35384
|
if (!result)
|
|
34651
35385
|
return;
|
|
34652
35386
|
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
|
|
34653
|
-
|
|
35387
|
+
buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
34654
35388
|
};
|
|
34655
35389
|
/** The remaining legs for a flight node open in the fly-in, as the regular flight results do. */
|
|
34656
35390
|
const handleShowMoreFlights = (item) => {
|
|
@@ -34738,7 +35472,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34738
35472
|
node.preferredAccommodationName,
|
|
34739
35473
|
" \u2014 ",
|
|
34740
35474
|
translations.SRP.NO_RESULTS))),
|
|
34741
|
-
React__default.createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured, ...fill].map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE })))),
|
|
35475
|
+
React__default.createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured, ...fill].map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE, selectedLabel: bookedMode && matchesCode(result, node.code ?? '') ? translations.SHARED.BOOKED : undefined })))),
|
|
34742
35476
|
remaining > 0 && !hideShowMoreResults && (React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
34743
35477
|
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
|
|
34744
35478
|
translations.SRP.SHOW_MORE,
|
|
@@ -34748,7 +35482,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34748
35482
|
};
|
|
34749
35483
|
const handleSelectFlight = (item, flight) => {
|
|
34750
35484
|
dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
|
|
34751
|
-
dispatch(updateEditableEntryLine(
|
|
35485
|
+
dispatch(updateEditableEntryLine(buildFlightSelectionLine(item, flight, bookedMode)));
|
|
34752
35486
|
};
|
|
34753
35487
|
const renderFlightNode = (item) => {
|
|
34754
35488
|
const { node, line } = item;
|
|
@@ -34774,7 +35508,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34774
35508
|
status === 'unavailable' && React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
|
|
34775
35509
|
status === 'resolved' && selected && (React__default.createElement(React__default.Fragment, null,
|
|
34776
35510
|
React__default.createElement("div", { className: "search__results__cards search__results__cards--extended" },
|
|
34777
|
-
React__default.createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price }),
|
|
35511
|
+
React__default.createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price, selectedLabel: bookedMode && selected.outwardGuid === line.guid ? translations.SHARED.BOOKED : undefined }),
|
|
34778
35512
|
visible.map((result) => (React__default.createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected.price, onSelect: () => handleSelectFlight(item, result) })))),
|
|
34779
35513
|
others.length > 2 && !hideShowMoreResults && (React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
34780
35514
|
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreFlights(item) },
|
|
@@ -34858,7 +35592,8 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34858
35592
|
*/
|
|
34859
35593
|
const renderActivityCard = ({ result, item }) => {
|
|
34860
35594
|
const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedExcursionLines(result).length > 0;
|
|
34861
|
-
|
|
35595
|
+
const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
|
|
35596
|
+
return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(item, result.code) : handleToggleActivity(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
|
|
34862
35597
|
};
|
|
34863
35598
|
if (isLoading)
|
|
34864
35599
|
return React__default.createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
|
|
@@ -34902,6 +35637,7 @@ const useTrajectAvailability = () => {
|
|
|
34902
35637
|
const controller = new AbortController();
|
|
34903
35638
|
dispatch(resetTrajectAvailability());
|
|
34904
35639
|
dispatch(setTrajectResolving(true));
|
|
35640
|
+
const bookedMode = isBookedEntryTraject(trajectEntry);
|
|
34905
35641
|
const config = {
|
|
34906
35642
|
host: context.tideConnection.host,
|
|
34907
35643
|
apiKey: context.tideConnection.apiKey
|
|
@@ -34963,6 +35699,17 @@ const useTrajectAvailability = () => {
|
|
|
34963
35699
|
});
|
|
34964
35700
|
const configuredCodes = new Set(configuredResults.map((x) => x.code));
|
|
34965
35701
|
const destinationResults = areaResults.filter((x) => !configuredCodes.has(x.code));
|
|
35702
|
+
if (bookedMode) {
|
|
35703
|
+
const results = [...configuredResults, ...destinationResults];
|
|
35704
|
+
let booked = results.find((x) => matchesCode(x, item.node.code ?? '')) ?? null;
|
|
35705
|
+
// Not searchable any more (sold out, delisted) — drawn from the line instead.
|
|
35706
|
+
if (!booked) {
|
|
35707
|
+
booked = buildBookedNodeResult(item.node, item.lines);
|
|
35708
|
+
results.unshift(booked);
|
|
35709
|
+
}
|
|
35710
|
+
dispatch(setTrajectNodeAvailability({ lineGuid, results, selectedCode: booked.code, preferredUnavailable: false }));
|
|
35711
|
+
return [];
|
|
35712
|
+
}
|
|
34966
35713
|
const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
|
|
34967
35714
|
const preferredUnavailable = configuredResults.length
|
|
34968
35715
|
? !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code))
|
|
@@ -34985,6 +35732,11 @@ const useTrajectAvailability = () => {
|
|
|
34985
35732
|
if (controller.signal.aborted)
|
|
34986
35733
|
return [];
|
|
34987
35734
|
console.error('Failed to resolve traject node availability', item.node.name, error);
|
|
35735
|
+
if (bookedMode) {
|
|
35736
|
+
const booked = buildBookedNodeResult(item.node, item.lines);
|
|
35737
|
+
dispatch(setTrajectNodeAvailability({ lineGuid, results: [booked], selectedCode: booked.code, preferredUnavailable: false }));
|
|
35738
|
+
return [];
|
|
35739
|
+
}
|
|
34988
35740
|
dispatch(setTrajectNodeAvailability({ lineGuid, results: [], selectedCode: null, preferredUnavailable: false }));
|
|
34989
35741
|
return item.lines.map((x) => x.guid);
|
|
34990
35742
|
}
|
|
@@ -34992,6 +35744,11 @@ const useTrajectAvailability = () => {
|
|
|
34992
35744
|
const resolveFlightNode = async (item) => {
|
|
34993
35745
|
const lineGuid = item.line.guid;
|
|
34994
35746
|
if (!item.node.departureAirportCode || !item.node.arrivalAirportCode) {
|
|
35747
|
+
if (bookedMode) {
|
|
35748
|
+
const booked = buildBookedFlightResult(item.line);
|
|
35749
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked], selectedGuid: booked.outwardGuid }));
|
|
35750
|
+
return [];
|
|
35751
|
+
}
|
|
34995
35752
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
34996
35753
|
return item.lines.map((x) => x.guid);
|
|
34997
35754
|
}
|
|
@@ -35000,6 +35757,11 @@ const useTrajectAvailability = () => {
|
|
|
35000
35757
|
const flights = (await build.searchPackagingFlights(config, buildTrajectFlightRequest(item, searchContext, flightPax), controller.signal)) ?? [];
|
|
35001
35758
|
if (controller.signal.aborted)
|
|
35002
35759
|
return [];
|
|
35760
|
+
if (bookedMode) {
|
|
35761
|
+
const booked = buildBookedFlightResult(item.line);
|
|
35762
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked, ...flights], selectedGuid: booked.outwardGuid }));
|
|
35763
|
+
return [];
|
|
35764
|
+
}
|
|
35003
35765
|
const picked = pickCheapestFlight(flights);
|
|
35004
35766
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: flights, selectedGuid: picked?.outwardGuid ?? null }));
|
|
35005
35767
|
if (!picked)
|
|
@@ -35011,6 +35773,11 @@ const useTrajectAvailability = () => {
|
|
|
35011
35773
|
if (controller.signal.aborted)
|
|
35012
35774
|
return [];
|
|
35013
35775
|
console.error('Failed to resolve traject flight', item.node.name, error);
|
|
35776
|
+
if (bookedMode) {
|
|
35777
|
+
const booked = buildBookedFlightResult(item.line);
|
|
35778
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked], selectedGuid: booked.outwardGuid }));
|
|
35779
|
+
return [];
|
|
35780
|
+
}
|
|
35014
35781
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
35015
35782
|
return item.lines.map((x) => x.guid);
|
|
35016
35783
|
}
|
|
@@ -35048,6 +35815,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35048
35815
|
const [detailsIsLoading, setDetailsIsLoading] = useState(false);
|
|
35049
35816
|
const [pricesAreLoading, setPricesAreLoading] = useState(false);
|
|
35050
35817
|
const [itineraryIsLoading, setItineraryIsLoading] = useState(false);
|
|
35818
|
+
const [entrySaving, setEntrySaving] = useState(false);
|
|
35051
35819
|
const [itineraryOpen, setItineraryOpen] = useState(false);
|
|
35052
35820
|
const [isBookingConfirmation, setIsBookingConfirmation] = useState(false);
|
|
35053
35821
|
const [selectedAccommodationSeed, setSelectedAccommodationSeed] = useState(null);
|
|
@@ -35804,6 +36572,31 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35804
36572
|
useEffect(() => {
|
|
35805
36573
|
setInitialFiltersSet(false);
|
|
35806
36574
|
}, [activeSearchSeed]);
|
|
36575
|
+
const handleSaveEntry = async () => {
|
|
36576
|
+
if (!context || !bookableEntry || entrySaving)
|
|
36577
|
+
return;
|
|
36578
|
+
setEntrySaving(true);
|
|
36579
|
+
try {
|
|
36580
|
+
const config = {
|
|
36581
|
+
host: context.tideConnection.host,
|
|
36582
|
+
apiKey: context.tideConnection.apiKey
|
|
36583
|
+
};
|
|
36584
|
+
const request = {
|
|
36585
|
+
language: context.languageCode ?? 'en-GB',
|
|
36586
|
+
officeId: context.tideConnection.officeId,
|
|
36587
|
+
catalogueId: context.searchConfiguration.defaultCatalogueId ?? first(context?.tideConnection?.catalogueIds) ?? 1,
|
|
36588
|
+
agentId: context.agentId,
|
|
36589
|
+
payload: bookableEntry
|
|
36590
|
+
};
|
|
36591
|
+
await build.savePackagingEntry(config, request);
|
|
36592
|
+
if (typeof window !== 'undefined')
|
|
36593
|
+
window.location.reload();
|
|
36594
|
+
}
|
|
36595
|
+
catch (err) {
|
|
36596
|
+
console.error('Failed to save the entry', err);
|
|
36597
|
+
setEntrySaving(false);
|
|
36598
|
+
}
|
|
36599
|
+
};
|
|
35807
36600
|
useEffect(() => {
|
|
35808
36601
|
const fetchPriceDetails = async () => {
|
|
35809
36602
|
if (!context || !editablePackagingEntry || isEmpty$1(editablePackagingEntry.lines))
|
|
@@ -36188,11 +36981,18 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
36188
36981
|
const id = paxId++;
|
|
36189
36982
|
pax.push({
|
|
36190
36983
|
id,
|
|
36984
|
+
guid: '',
|
|
36191
36985
|
firstName: _.firstName || '',
|
|
36192
36986
|
lastName: _.lastName || '',
|
|
36193
|
-
dateOfBirth: _.dateOfBirth ||
|
|
36194
|
-
age: _.age ||
|
|
36195
|
-
isMainBooker: roomIndex === 0 && paxIndex === 0
|
|
36987
|
+
dateOfBirth: _.dateOfBirth || undefined,
|
|
36988
|
+
age: _.age || undefined,
|
|
36989
|
+
isMainBooker: roomIndex === 0 && paxIndex === 0,
|
|
36990
|
+
email: '',
|
|
36991
|
+
weight: null,
|
|
36992
|
+
weightType: build.WeightType.kilograms,
|
|
36993
|
+
height: null,
|
|
36994
|
+
heightType: build.HeightType.centimeters,
|
|
36995
|
+
customFields: []
|
|
36196
36996
|
});
|
|
36197
36997
|
return id;
|
|
36198
36998
|
});
|
|
@@ -36212,6 +37012,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
36212
37012
|
depositAmount: 0,
|
|
36213
37013
|
pax,
|
|
36214
37014
|
rooms,
|
|
37015
|
+
paxFields: [],
|
|
36215
37016
|
lines: [],
|
|
36216
37017
|
address: {}
|
|
36217
37018
|
};
|
|
@@ -36231,7 +37032,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
36231
37032
|
context.searchConfiguration.qsmType != build.PortalQsmType.AccommodationAndFlight && context.showFilters && (React__default.createElement(Filters, { initialFilters: initialFilters, filters: filters, isOpen: filtersOpen, handleSetIsOpen: () => setFiltersOpen(!filtersOpen),
|
|
36232
37033
|
// handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
|
|
36233
37034
|
isLoading: isLoading, setFilters: (filters) => dispatch(setFilters(filters)), resetFilters: (filters) => dispatch(resetFilters(filters)) })),
|
|
36234
|
-
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default.createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving, onEditAccommodation: handleEditAccommodation })),
|
|
37035
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default.createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving || entrySaving, onEditAccommodation: handleEditAccommodation, onSaveEntry: handleSaveEntry })),
|
|
36235
37036
|
React__default.createElement("div", { className: "search__results" },
|
|
36236
37037
|
isMobile && (React__default.createElement("div", { className: "search__result-row" },
|
|
36237
37038
|
React__default.createElement("div", { className: "search__results__actions" },
|
|
@@ -36319,8 +37120,15 @@ const createSearchResultsStore = () => configureStore({
|
|
|
36319
37120
|
|
|
36320
37121
|
const SearchResults = ({ configuration, onBookingStarted }) => {
|
|
36321
37122
|
const store = React__default.useMemo(() => createSearchResultsStore(), []);
|
|
37123
|
+
// A booked entry opened through its magic link gets the traject services screen by carrying a
|
|
37124
|
+
// traject rebuilt from its own lines. The magic link on the entry is what marks the mode.
|
|
37125
|
+
const effectiveConfiguration = React__default.useMemo(() => {
|
|
37126
|
+
if (!configuration.allowBookedEntryChanges || configuration.trajectEntry || !configuration.packagingEntry?.magicLink)
|
|
37127
|
+
return configuration;
|
|
37128
|
+
return { ...configuration, trajectEntry: buildBookedTrajectEntry(configuration.packagingEntry) };
|
|
37129
|
+
}, [configuration]);
|
|
36322
37130
|
return (React__default.createElement(Provider, { store: store },
|
|
36323
|
-
React__default.createElement(SearchResultsConfigurationContext.Provider, { value:
|
|
37131
|
+
React__default.createElement(SearchResultsConfigurationContext.Provider, { value: effectiveConfiguration },
|
|
36324
37132
|
React__default.createElement(SearchResultsContainer, { onBookingStarted: onBookingStarted }))));
|
|
36325
37133
|
};
|
|
36326
37134
|
|