@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-cjs/index.js
CHANGED
|
@@ -11,11 +11,11 @@ var locale = require('date-fns/locale');
|
|
|
11
11
|
var reactPopper = require('react-popper');
|
|
12
12
|
var reactRedux = require('react-redux');
|
|
13
13
|
var toolkit = require('@reduxjs/toolkit');
|
|
14
|
+
var flat = require('flat');
|
|
14
15
|
var reactRouter = require('react-router');
|
|
15
16
|
require('react-dom');
|
|
16
17
|
var produce = require('immer');
|
|
17
18
|
var formik = require('formik');
|
|
18
|
-
var flat = require('flat');
|
|
19
19
|
var uuid = require('uuid');
|
|
20
20
|
|
|
21
21
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -56,8 +56,8 @@ function _mergeNamespaces(n, m) {
|
|
|
56
56
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
57
57
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
58
58
|
var JsonURL__default = /*#__PURE__*/_interopDefaultLegacy(JsonURL);
|
|
59
|
-
var produce__default = /*#__PURE__*/_interopDefaultLegacy(produce);
|
|
60
59
|
var flat__default = /*#__PURE__*/_interopDefaultLegacy(flat);
|
|
60
|
+
var produce__default = /*#__PURE__*/_interopDefaultLegacy(produce);
|
|
61
61
|
|
|
62
62
|
var STEPS$f = {
|
|
63
63
|
PERSONAL_DETAILS: "التفاصيل الشخصية",
|
|
@@ -153,7 +153,9 @@ var SHARED$f = {
|
|
|
153
153
|
ADULTS: "بالغون",
|
|
154
154
|
CHILDREN: "أطفال",
|
|
155
155
|
SELECT: "اختر",
|
|
156
|
-
SELECTED: "تم الاختيار"
|
|
156
|
+
SELECTED: "تم الاختيار",
|
|
157
|
+
BOOKED: "محجوز",
|
|
158
|
+
SAVE: "حفظ"
|
|
157
159
|
};
|
|
158
160
|
var SIDEBAR$f = {
|
|
159
161
|
OVERVIEW: "الملخص",
|
|
@@ -211,6 +213,21 @@ var TRAVELERS_FORM$f = {
|
|
|
211
213
|
FIRST_NAME: "الاسم الأول",
|
|
212
214
|
LAST_NAME: "اسم العائلة",
|
|
213
215
|
BIRTHDATE: "تاريخ الميلاد",
|
|
216
|
+
NICKNAME: "Nickname",
|
|
217
|
+
BIRTHPLACE: "Birthplace",
|
|
218
|
+
NATIONALITY: "Nationality",
|
|
219
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
220
|
+
TRAVELER_EMAIL: "Email",
|
|
221
|
+
TRAVELER_PHONE: "Phone",
|
|
222
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
223
|
+
PASSPORT_NUMBER: "Passport number",
|
|
224
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
225
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
226
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
227
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
228
|
+
HAS_INSURANCE: "Has insurance",
|
|
229
|
+
INSURANCE_NAME: "Insurance name",
|
|
230
|
+
INFO: "Additional information",
|
|
214
231
|
WEIGHT: "الوزن",
|
|
215
232
|
WEIGHT_UNIT_KG: "kg",
|
|
216
233
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -606,7 +623,9 @@ var SHARED$e = {
|
|
|
606
623
|
ADULTS: "Voksne",
|
|
607
624
|
CHILDREN: "Børn",
|
|
608
625
|
SELECT: "Vælg",
|
|
609
|
-
SELECTED: "Valgt"
|
|
626
|
+
SELECTED: "Valgt",
|
|
627
|
+
BOOKED: "Booket",
|
|
628
|
+
SAVE: "Gem"
|
|
610
629
|
};
|
|
611
630
|
var SIDEBAR$e = {
|
|
612
631
|
OVERVIEW: "Oversigt",
|
|
@@ -664,6 +683,21 @@ var TRAVELERS_FORM$e = {
|
|
|
664
683
|
FIRST_NAME: "Fornavn",
|
|
665
684
|
LAST_NAME: "Efternavn",
|
|
666
685
|
BIRTHDATE: "Fødselsdato",
|
|
686
|
+
NICKNAME: "Nickname",
|
|
687
|
+
BIRTHPLACE: "Birthplace",
|
|
688
|
+
NATIONALITY: "Nationality",
|
|
689
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
690
|
+
TRAVELER_EMAIL: "Email",
|
|
691
|
+
TRAVELER_PHONE: "Phone",
|
|
692
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
693
|
+
PASSPORT_NUMBER: "Passport number",
|
|
694
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
695
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
696
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
697
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
698
|
+
HAS_INSURANCE: "Has insurance",
|
|
699
|
+
INSURANCE_NAME: "Insurance name",
|
|
700
|
+
INFO: "Additional information",
|
|
667
701
|
WEIGHT: "Vægt",
|
|
668
702
|
WEIGHT_UNIT_KG: "kg",
|
|
669
703
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -1059,7 +1093,9 @@ var SHARED$d = {
|
|
|
1059
1093
|
ADULTS: "Erwachsene",
|
|
1060
1094
|
CHILDREN: "Kinder",
|
|
1061
1095
|
SELECT: "Auswählen",
|
|
1062
|
-
SELECTED: "Ausgewählt"
|
|
1096
|
+
SELECTED: "Ausgewählt",
|
|
1097
|
+
BOOKED: "Gebucht",
|
|
1098
|
+
SAVE: "Speichern"
|
|
1063
1099
|
};
|
|
1064
1100
|
var SIDEBAR$d = {
|
|
1065
1101
|
OVERVIEW: "Übersicht",
|
|
@@ -1117,6 +1153,21 @@ var TRAVELERS_FORM$d = {
|
|
|
1117
1153
|
FIRST_NAME: "Vorname",
|
|
1118
1154
|
LAST_NAME: "Nachname",
|
|
1119
1155
|
BIRTHDATE: "Geburtsdatum",
|
|
1156
|
+
NICKNAME: "Nickname",
|
|
1157
|
+
BIRTHPLACE: "Birthplace",
|
|
1158
|
+
NATIONALITY: "Nationality",
|
|
1159
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
1160
|
+
TRAVELER_EMAIL: "Email",
|
|
1161
|
+
TRAVELER_PHONE: "Phone",
|
|
1162
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
1163
|
+
PASSPORT_NUMBER: "Passport number",
|
|
1164
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
1165
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
1166
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
1167
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
1168
|
+
HAS_INSURANCE: "Has insurance",
|
|
1169
|
+
INSURANCE_NAME: "Insurance name",
|
|
1170
|
+
INFO: "Additional information",
|
|
1120
1171
|
WEIGHT: "Gewicht",
|
|
1121
1172
|
WEIGHT_UNIT_KG: "kg",
|
|
1122
1173
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -1512,7 +1563,9 @@ var SHARED$c = {
|
|
|
1512
1563
|
ADULTS: "Adults",
|
|
1513
1564
|
CHILDREN: "Children",
|
|
1514
1565
|
SELECT: "Select",
|
|
1515
|
-
SELECTED: "Selected"
|
|
1566
|
+
SELECTED: "Selected",
|
|
1567
|
+
BOOKED: "Booked",
|
|
1568
|
+
SAVE: "Save"
|
|
1516
1569
|
};
|
|
1517
1570
|
var SIDEBAR$c = {
|
|
1518
1571
|
OVERVIEW: "Summary",
|
|
@@ -1571,6 +1624,21 @@ var TRAVELERS_FORM$c = {
|
|
|
1571
1624
|
FIRST_NAME: "First name",
|
|
1572
1625
|
LAST_NAME: "Last name",
|
|
1573
1626
|
BIRTHDATE: "Date of birth",
|
|
1627
|
+
NICKNAME: "Nickname",
|
|
1628
|
+
BIRTHPLACE: "Birthplace",
|
|
1629
|
+
NATIONALITY: "Nationality",
|
|
1630
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
1631
|
+
TRAVELER_EMAIL: "Email",
|
|
1632
|
+
TRAVELER_PHONE: "Phone",
|
|
1633
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
1634
|
+
PASSPORT_NUMBER: "Passport number",
|
|
1635
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
1636
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
1637
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
1638
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
1639
|
+
HAS_INSURANCE: "Has insurance",
|
|
1640
|
+
INSURANCE_NAME: "Insurance name",
|
|
1641
|
+
INFO: "Additional information",
|
|
1574
1642
|
WEIGHT: "Weight",
|
|
1575
1643
|
WEIGHT_UNIT_KG: "kg",
|
|
1576
1644
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -1969,7 +2037,9 @@ var SHARED$b = {
|
|
|
1969
2037
|
ADULTS: "Adultos",
|
|
1970
2038
|
CHILDREN: "Niños",
|
|
1971
2039
|
SELECT: "Seleccionar",
|
|
1972
|
-
SELECTED: "Seleccionado"
|
|
2040
|
+
SELECTED: "Seleccionado",
|
|
2041
|
+
BOOKED: "Reservado",
|
|
2042
|
+
SAVE: "Guardar"
|
|
1973
2043
|
};
|
|
1974
2044
|
var SIDEBAR$b = {
|
|
1975
2045
|
OVERVIEW: "Resumen",
|
|
@@ -2027,6 +2097,21 @@ var TRAVELERS_FORM$b = {
|
|
|
2027
2097
|
FIRST_NAME: "Nombre",
|
|
2028
2098
|
LAST_NAME: "Apellido",
|
|
2029
2099
|
BIRTHDATE: "Fecha de nacimiento",
|
|
2100
|
+
NICKNAME: "Nickname",
|
|
2101
|
+
BIRTHPLACE: "Birthplace",
|
|
2102
|
+
NATIONALITY: "Nationality",
|
|
2103
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
2104
|
+
TRAVELER_EMAIL: "Email",
|
|
2105
|
+
TRAVELER_PHONE: "Phone",
|
|
2106
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
2107
|
+
PASSPORT_NUMBER: "Passport number",
|
|
2108
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
2109
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
2110
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
2111
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
2112
|
+
HAS_INSURANCE: "Has insurance",
|
|
2113
|
+
INSURANCE_NAME: "Insurance name",
|
|
2114
|
+
INFO: "Additional information",
|
|
2030
2115
|
WEIGHT: "Peso",
|
|
2031
2116
|
WEIGHT_UNIT_KG: "kg",
|
|
2032
2117
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -2422,7 +2507,9 @@ var SHARED$a = {
|
|
|
2422
2507
|
ADULTS: "Adultes",
|
|
2423
2508
|
CHILDREN: "Enfants",
|
|
2424
2509
|
SELECT: "Sélectionner",
|
|
2425
|
-
SELECTED: "Sélectionné"
|
|
2510
|
+
SELECTED: "Sélectionné",
|
|
2511
|
+
BOOKED: "Réservé",
|
|
2512
|
+
SAVE: "Enregistrer"
|
|
2426
2513
|
};
|
|
2427
2514
|
var SIDEBAR$a = {
|
|
2428
2515
|
OVERVIEW: "Aperçu",
|
|
@@ -2481,6 +2568,21 @@ var TRAVELERS_FORM$a = {
|
|
|
2481
2568
|
FIRST_NAME: "Prénom",
|
|
2482
2569
|
LAST_NAME: "Nom",
|
|
2483
2570
|
BIRTHDATE: "Date de naissance",
|
|
2571
|
+
NICKNAME: "Nickname",
|
|
2572
|
+
BIRTHPLACE: "Birthplace",
|
|
2573
|
+
NATIONALITY: "Nationality",
|
|
2574
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
2575
|
+
TRAVELER_EMAIL: "Email",
|
|
2576
|
+
TRAVELER_PHONE: "Phone",
|
|
2577
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
2578
|
+
PASSPORT_NUMBER: "Passport number",
|
|
2579
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
2580
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
2581
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
2582
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
2583
|
+
HAS_INSURANCE: "Has insurance",
|
|
2584
|
+
INSURANCE_NAME: "Insurance name",
|
|
2585
|
+
INFO: "Additional information",
|
|
2484
2586
|
WEIGHT: "Poids",
|
|
2485
2587
|
WEIGHT_UNIT_KG: "kg",
|
|
2486
2588
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -2879,7 +2981,9 @@ var SHARED$9 = {
|
|
|
2879
2981
|
ADULTS: "Adultes",
|
|
2880
2982
|
CHILDREN: "Enfants",
|
|
2881
2983
|
SELECT: "Sélectionner",
|
|
2882
|
-
SELECTED: "Sélectionné"
|
|
2984
|
+
SELECTED: "Sélectionné",
|
|
2985
|
+
BOOKED: "Réservé",
|
|
2986
|
+
SAVE: "Enregistrer"
|
|
2883
2987
|
};
|
|
2884
2988
|
var SIDEBAR$9 = {
|
|
2885
2989
|
OVERVIEW: "Résumé",
|
|
@@ -2937,6 +3041,21 @@ var TRAVELERS_FORM$9 = {
|
|
|
2937
3041
|
FIRST_NAME: "Prénom",
|
|
2938
3042
|
LAST_NAME: "Nom",
|
|
2939
3043
|
BIRTHDATE: "Date de naissance",
|
|
3044
|
+
NICKNAME: "Nickname",
|
|
3045
|
+
BIRTHPLACE: "Birthplace",
|
|
3046
|
+
NATIONALITY: "Nationality",
|
|
3047
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
3048
|
+
TRAVELER_EMAIL: "Email",
|
|
3049
|
+
TRAVELER_PHONE: "Phone",
|
|
3050
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
3051
|
+
PASSPORT_NUMBER: "Passport number",
|
|
3052
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
3053
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
3054
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
3055
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
3056
|
+
HAS_INSURANCE: "Has insurance",
|
|
3057
|
+
INSURANCE_NAME: "Insurance name",
|
|
3058
|
+
INFO: "Additional information",
|
|
2940
3059
|
WEIGHT: "Poids",
|
|
2941
3060
|
WEIGHT_UNIT_KG: "kg",
|
|
2942
3061
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -3332,7 +3451,9 @@ var SHARED$8 = {
|
|
|
3332
3451
|
ADULTS: "Fullorðnir",
|
|
3333
3452
|
CHILDREN: "Börn",
|
|
3334
3453
|
SELECT: "Velja",
|
|
3335
|
-
SELECTED: "Valið"
|
|
3454
|
+
SELECTED: "Valið",
|
|
3455
|
+
BOOKED: "Bókað",
|
|
3456
|
+
SAVE: "Vista"
|
|
3336
3457
|
};
|
|
3337
3458
|
var SIDEBAR$8 = {
|
|
3338
3459
|
OVERVIEW: "Yfirlit",
|
|
@@ -3390,6 +3511,21 @@ var TRAVELERS_FORM$8 = {
|
|
|
3390
3511
|
FIRST_NAME: "Fornafn",
|
|
3391
3512
|
LAST_NAME: "Eftirnafn",
|
|
3392
3513
|
BIRTHDATE: "Fæðingardagur",
|
|
3514
|
+
NICKNAME: "Nickname",
|
|
3515
|
+
BIRTHPLACE: "Birthplace",
|
|
3516
|
+
NATIONALITY: "Nationality",
|
|
3517
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
3518
|
+
TRAVELER_EMAIL: "Email",
|
|
3519
|
+
TRAVELER_PHONE: "Phone",
|
|
3520
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
3521
|
+
PASSPORT_NUMBER: "Passport number",
|
|
3522
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
3523
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
3524
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
3525
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
3526
|
+
HAS_INSURANCE: "Has insurance",
|
|
3527
|
+
INSURANCE_NAME: "Insurance name",
|
|
3528
|
+
INFO: "Additional information",
|
|
3393
3529
|
WEIGHT: "Þyngd",
|
|
3394
3530
|
WEIGHT_UNIT_KG: "kg",
|
|
3395
3531
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -3785,7 +3921,9 @@ var SHARED$7 = {
|
|
|
3785
3921
|
ADULTS: "Adulti",
|
|
3786
3922
|
CHILDREN: "Bambini",
|
|
3787
3923
|
SELECT: "Seleziona",
|
|
3788
|
-
SELECTED: "Selezionato"
|
|
3924
|
+
SELECTED: "Selezionato",
|
|
3925
|
+
BOOKED: "Prenotato",
|
|
3926
|
+
SAVE: "Salva"
|
|
3789
3927
|
};
|
|
3790
3928
|
var SIDEBAR$7 = {
|
|
3791
3929
|
OVERVIEW: "Riepilogo",
|
|
@@ -3843,6 +3981,21 @@ var TRAVELERS_FORM$7 = {
|
|
|
3843
3981
|
FIRST_NAME: "Nome",
|
|
3844
3982
|
LAST_NAME: "Cognome",
|
|
3845
3983
|
BIRTHDATE: "Data di nascita",
|
|
3984
|
+
NICKNAME: "Nickname",
|
|
3985
|
+
BIRTHPLACE: "Birthplace",
|
|
3986
|
+
NATIONALITY: "Nationality",
|
|
3987
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
3988
|
+
TRAVELER_EMAIL: "Email",
|
|
3989
|
+
TRAVELER_PHONE: "Phone",
|
|
3990
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
3991
|
+
PASSPORT_NUMBER: "Passport number",
|
|
3992
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
3993
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
3994
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
3995
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
3996
|
+
HAS_INSURANCE: "Has insurance",
|
|
3997
|
+
INSURANCE_NAME: "Insurance name",
|
|
3998
|
+
INFO: "Additional information",
|
|
3846
3999
|
WEIGHT: "Peso",
|
|
3847
4000
|
WEIGHT_UNIT_KG: "kg",
|
|
3848
4001
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -4238,7 +4391,9 @@ var SHARED$6 = {
|
|
|
4238
4391
|
ADULTS: "Volwassenen",
|
|
4239
4392
|
CHILDREN: "Kinderen",
|
|
4240
4393
|
SELECT: "Selecteer",
|
|
4241
|
-
SELECTED: "Geselecteerd"
|
|
4394
|
+
SELECTED: "Geselecteerd",
|
|
4395
|
+
BOOKED: "Geboekt",
|
|
4396
|
+
SAVE: "Opslaan"
|
|
4242
4397
|
};
|
|
4243
4398
|
var SIDEBAR$6 = {
|
|
4244
4399
|
OVERVIEW: "Overzicht",
|
|
@@ -4297,6 +4452,21 @@ var TRAVELERS_FORM$6 = {
|
|
|
4297
4452
|
FIRST_NAME: "Voornaam",
|
|
4298
4453
|
LAST_NAME: "Naam",
|
|
4299
4454
|
BIRTHDATE: "Geboortedatum",
|
|
4455
|
+
NICKNAME: "Nickname",
|
|
4456
|
+
BIRTHPLACE: "Birthplace",
|
|
4457
|
+
NATIONALITY: "Nationality",
|
|
4458
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
4459
|
+
TRAVELER_EMAIL: "Email",
|
|
4460
|
+
TRAVELER_PHONE: "Phone",
|
|
4461
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
4462
|
+
PASSPORT_NUMBER: "Passport number",
|
|
4463
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
4464
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
4465
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
4466
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
4467
|
+
HAS_INSURANCE: "Has insurance",
|
|
4468
|
+
INSURANCE_NAME: "Insurance name",
|
|
4469
|
+
INFO: "Additional information",
|
|
4300
4470
|
WEIGHT: "Gewicht",
|
|
4301
4471
|
WEIGHT_UNIT_KG: "kg",
|
|
4302
4472
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -4695,7 +4865,9 @@ var SHARED$5 = {
|
|
|
4695
4865
|
ADULTS: "Volwassenen",
|
|
4696
4866
|
CHILDREN: "Kinderen",
|
|
4697
4867
|
SELECT: "Selecteren",
|
|
4698
|
-
SELECTED: "Geselecteerd"
|
|
4868
|
+
SELECTED: "Geselecteerd",
|
|
4869
|
+
BOOKED: "Geboekt",
|
|
4870
|
+
SAVE: "Opslaan"
|
|
4699
4871
|
};
|
|
4700
4872
|
var SIDEBAR$5 = {
|
|
4701
4873
|
OVERVIEW: "Overzicht",
|
|
@@ -4753,6 +4925,21 @@ var TRAVELERS_FORM$5 = {
|
|
|
4753
4925
|
FIRST_NAME: "Voornaam",
|
|
4754
4926
|
LAST_NAME: "Achternaam",
|
|
4755
4927
|
BIRTHDATE: "Geboortedatum",
|
|
4928
|
+
NICKNAME: "Nickname",
|
|
4929
|
+
BIRTHPLACE: "Birthplace",
|
|
4930
|
+
NATIONALITY: "Nationality",
|
|
4931
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
4932
|
+
TRAVELER_EMAIL: "Email",
|
|
4933
|
+
TRAVELER_PHONE: "Phone",
|
|
4934
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
4935
|
+
PASSPORT_NUMBER: "Passport number",
|
|
4936
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
4937
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
4938
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
4939
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
4940
|
+
HAS_INSURANCE: "Has insurance",
|
|
4941
|
+
INSURANCE_NAME: "Insurance name",
|
|
4942
|
+
INFO: "Additional information",
|
|
4756
4943
|
WEIGHT: "Gewicht",
|
|
4757
4944
|
WEIGHT_UNIT_KG: "kg",
|
|
4758
4945
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -5148,7 +5335,9 @@ var SHARED$4 = {
|
|
|
5148
5335
|
ADULTS: "Voksne",
|
|
5149
5336
|
CHILDREN: "Barn",
|
|
5150
5337
|
SELECT: "Velg",
|
|
5151
|
-
SELECTED: "Valgt"
|
|
5338
|
+
SELECTED: "Valgt",
|
|
5339
|
+
BOOKED: "Booket",
|
|
5340
|
+
SAVE: "Lagre"
|
|
5152
5341
|
};
|
|
5153
5342
|
var SIDEBAR$4 = {
|
|
5154
5343
|
OVERVIEW: "Oversikt",
|
|
@@ -5206,6 +5395,21 @@ var TRAVELERS_FORM$4 = {
|
|
|
5206
5395
|
FIRST_NAME: "Fornavn",
|
|
5207
5396
|
LAST_NAME: "Etternavn",
|
|
5208
5397
|
BIRTHDATE: "Fødselsdato",
|
|
5398
|
+
NICKNAME: "Nickname",
|
|
5399
|
+
BIRTHPLACE: "Birthplace",
|
|
5400
|
+
NATIONALITY: "Nationality",
|
|
5401
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
5402
|
+
TRAVELER_EMAIL: "Email",
|
|
5403
|
+
TRAVELER_PHONE: "Phone",
|
|
5404
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
5405
|
+
PASSPORT_NUMBER: "Passport number",
|
|
5406
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
5407
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
5408
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
5409
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
5410
|
+
HAS_INSURANCE: "Has insurance",
|
|
5411
|
+
INSURANCE_NAME: "Insurance name",
|
|
5412
|
+
INFO: "Additional information",
|
|
5209
5413
|
WEIGHT: "Vekt",
|
|
5210
5414
|
WEIGHT_UNIT_KG: "kg",
|
|
5211
5415
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -5601,7 +5805,9 @@ var SHARED$3 = {
|
|
|
5601
5805
|
ADULTS: "Dorośli",
|
|
5602
5806
|
CHILDREN: "Dzieci",
|
|
5603
5807
|
SELECT: "Wybierz",
|
|
5604
|
-
SELECTED: "Wybrane"
|
|
5808
|
+
SELECTED: "Wybrane",
|
|
5809
|
+
BOOKED: "Zarezerwowane",
|
|
5810
|
+
SAVE: "Zapisz"
|
|
5605
5811
|
};
|
|
5606
5812
|
var SIDEBAR$3 = {
|
|
5607
5813
|
OVERVIEW: "Podsumowanie",
|
|
@@ -5659,6 +5865,21 @@ var TRAVELERS_FORM$3 = {
|
|
|
5659
5865
|
FIRST_NAME: "Imię",
|
|
5660
5866
|
LAST_NAME: "Nazwisko",
|
|
5661
5867
|
BIRTHDATE: "Data urodzenia",
|
|
5868
|
+
NICKNAME: "Nickname",
|
|
5869
|
+
BIRTHPLACE: "Birthplace",
|
|
5870
|
+
NATIONALITY: "Nationality",
|
|
5871
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
5872
|
+
TRAVELER_EMAIL: "Email",
|
|
5873
|
+
TRAVELER_PHONE: "Phone",
|
|
5874
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
5875
|
+
PASSPORT_NUMBER: "Passport number",
|
|
5876
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
5877
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
5878
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
5879
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
5880
|
+
HAS_INSURANCE: "Has insurance",
|
|
5881
|
+
INSURANCE_NAME: "Insurance name",
|
|
5882
|
+
INFO: "Additional information",
|
|
5662
5883
|
WEIGHT: "Waga",
|
|
5663
5884
|
WEIGHT_UNIT_KG: "kg",
|
|
5664
5885
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -6054,7 +6275,9 @@ var SHARED$2 = {
|
|
|
6054
6275
|
ADULTS: "Adultos",
|
|
6055
6276
|
CHILDREN: "Crianças",
|
|
6056
6277
|
SELECT: "Selecionar",
|
|
6057
|
-
SELECTED: "Selecionado"
|
|
6278
|
+
SELECTED: "Selecionado",
|
|
6279
|
+
BOOKED: "Reservado",
|
|
6280
|
+
SAVE: "Guardar"
|
|
6058
6281
|
};
|
|
6059
6282
|
var SIDEBAR$2 = {
|
|
6060
6283
|
OVERVIEW: "Resumo",
|
|
@@ -6112,6 +6335,21 @@ var TRAVELERS_FORM$2 = {
|
|
|
6112
6335
|
FIRST_NAME: "Nome",
|
|
6113
6336
|
LAST_NAME: "Apelido",
|
|
6114
6337
|
BIRTHDATE: "Data de nascimento",
|
|
6338
|
+
NICKNAME: "Nickname",
|
|
6339
|
+
BIRTHPLACE: "Birthplace",
|
|
6340
|
+
NATIONALITY: "Nationality",
|
|
6341
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
6342
|
+
TRAVELER_EMAIL: "Email",
|
|
6343
|
+
TRAVELER_PHONE: "Phone",
|
|
6344
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
6345
|
+
PASSPORT_NUMBER: "Passport number",
|
|
6346
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
6347
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
6348
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
6349
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
6350
|
+
HAS_INSURANCE: "Has insurance",
|
|
6351
|
+
INSURANCE_NAME: "Insurance name",
|
|
6352
|
+
INFO: "Additional information",
|
|
6115
6353
|
WEIGHT: "Peso",
|
|
6116
6354
|
WEIGHT_UNIT_KG: "kg",
|
|
6117
6355
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -6507,7 +6745,9 @@ var SHARED$1 = {
|
|
|
6507
6745
|
ADULTS: "Vuxna",
|
|
6508
6746
|
CHILDREN: "Barn",
|
|
6509
6747
|
SELECT: "Välj",
|
|
6510
|
-
SELECTED: "Vald"
|
|
6748
|
+
SELECTED: "Vald",
|
|
6749
|
+
BOOKED: "Bokad",
|
|
6750
|
+
SAVE: "Spara"
|
|
6511
6751
|
};
|
|
6512
6752
|
var SIDEBAR$1 = {
|
|
6513
6753
|
OVERVIEW: "Översikt",
|
|
@@ -6565,6 +6805,21 @@ var TRAVELERS_FORM$1 = {
|
|
|
6565
6805
|
FIRST_NAME: "Förnamn",
|
|
6566
6806
|
LAST_NAME: "Efternamn",
|
|
6567
6807
|
BIRTHDATE: "Födelsedatum",
|
|
6808
|
+
NICKNAME: "Nickname",
|
|
6809
|
+
BIRTHPLACE: "Birthplace",
|
|
6810
|
+
NATIONALITY: "Nationality",
|
|
6811
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
6812
|
+
TRAVELER_EMAIL: "Email",
|
|
6813
|
+
TRAVELER_PHONE: "Phone",
|
|
6814
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
6815
|
+
PASSPORT_NUMBER: "Passport number",
|
|
6816
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
6817
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
6818
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
6819
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
6820
|
+
HAS_INSURANCE: "Has insurance",
|
|
6821
|
+
INSURANCE_NAME: "Insurance name",
|
|
6822
|
+
INFO: "Additional information",
|
|
6568
6823
|
WEIGHT: "Vikt",
|
|
6569
6824
|
WEIGHT_UNIT_KG: "kg",
|
|
6570
6825
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -6960,7 +7215,9 @@ var SHARED = {
|
|
|
6960
7215
|
ADULTS: "大人",
|
|
6961
7216
|
CHILDREN: "子供",
|
|
6962
7217
|
SELECT: "選択",
|
|
6963
|
-
SELECTED: "選択済み"
|
|
7218
|
+
SELECTED: "選択済み",
|
|
7219
|
+
BOOKED: "予約済み",
|
|
7220
|
+
SAVE: "保存"
|
|
6964
7221
|
};
|
|
6965
7222
|
var SIDEBAR = {
|
|
6966
7223
|
OVERVIEW: "概要",
|
|
@@ -7018,6 +7275,21 @@ var TRAVELERS_FORM = {
|
|
|
7018
7275
|
FIRST_NAME: "名",
|
|
7019
7276
|
LAST_NAME: "姓",
|
|
7020
7277
|
BIRTHDATE: "生年月日",
|
|
7278
|
+
NICKNAME: "Nickname",
|
|
7279
|
+
BIRTHPLACE: "Birthplace",
|
|
7280
|
+
NATIONALITY: "Nationality",
|
|
7281
|
+
PREFERRED_LANGUAGE: "Preferred language",
|
|
7282
|
+
TRAVELER_EMAIL: "Email",
|
|
7283
|
+
TRAVELER_PHONE: "Phone",
|
|
7284
|
+
TRAVELER_MOBILE: "Mobile phone",
|
|
7285
|
+
PASSPORT_NUMBER: "Passport number",
|
|
7286
|
+
PASSPORT_ISSUE_DATE: "Passport issue date",
|
|
7287
|
+
PASSPORT_ISSUED_LOCATION: "Passport issued location",
|
|
7288
|
+
PASSPORT_EXPIRY_DATE: "Passport expiry date",
|
|
7289
|
+
EMERGENCY_NUMBER: "Emergency number",
|
|
7290
|
+
HAS_INSURANCE: "Has insurance",
|
|
7291
|
+
INSURANCE_NAME: "Insurance name",
|
|
7292
|
+
INFO: "Additional information",
|
|
7021
7293
|
WEIGHT: "体重",
|
|
7022
7294
|
WEIGHT_UNIT_KG: "kg",
|
|
7023
7295
|
WEIGHT_UNIT_LB: "lb",
|
|
@@ -15121,6 +15393,34 @@ var getContentDraft = function (config, signal) {
|
|
|
15121
15393
|
var apiKey = config.apiKey;
|
|
15122
15394
|
return get(url, apiKey, config.token, signal, true);
|
|
15123
15395
|
};
|
|
15396
|
+
/**
|
|
15397
|
+
* api/web/content/live/filtered
|
|
15398
|
+
* Gets filtered Live content
|
|
15399
|
+
* @param config
|
|
15400
|
+
* @param request
|
|
15401
|
+
* @param signal
|
|
15402
|
+
* @returns OK if succeeded.
|
|
15403
|
+
*/
|
|
15404
|
+
var getFilteredContentLive = function (config, request, signal) {
|
|
15405
|
+
var url = "" + config.host + ENDPOINT_LIVE + "/filtered";
|
|
15406
|
+
var apiKey = config.apiKey;
|
|
15407
|
+
var body = JSON.stringify(request);
|
|
15408
|
+
return post(url, apiKey, body, config.token, signal, true);
|
|
15409
|
+
};
|
|
15410
|
+
/**
|
|
15411
|
+
* api/web/content/draft/filtered
|
|
15412
|
+
* Gets filtered Draft (Internal) content
|
|
15413
|
+
* @param config
|
|
15414
|
+
* @param request
|
|
15415
|
+
* @param signal
|
|
15416
|
+
* @returns OK if succeeded.
|
|
15417
|
+
*/
|
|
15418
|
+
var getFilteredContentDraft = function (config, request, signal) {
|
|
15419
|
+
var url = "" + config.host + ENDPOINT_DRAFT + "/filtered";
|
|
15420
|
+
var apiKey = config.apiKey;
|
|
15421
|
+
var body = JSON.stringify(request);
|
|
15422
|
+
return post(url, apiKey, body, config.token, signal, true);
|
|
15423
|
+
};
|
|
15124
15424
|
/**
|
|
15125
15425
|
* api/web/content/live/by-property
|
|
15126
15426
|
* Gets Live content matching a property value (or values).
|
|
@@ -15248,6 +15548,7 @@ var ENDPOINT_TRAJECT = ENDPOINT$1 + "/traject";
|
|
|
15248
15548
|
var ENDPOINT_ENTRY = function (magicLinkCode) {
|
|
15249
15549
|
return ENDPOINT$1 + "/entry/" + magicLinkCode;
|
|
15250
15550
|
};
|
|
15551
|
+
var ENDPOINT_SAVE_ENTRY = ENDPOINT$1 + "/entry/save";
|
|
15251
15552
|
var startTransaction = function (config, signal) {
|
|
15252
15553
|
var apiKey = config.apiKey;
|
|
15253
15554
|
var url = "" + config.host + ENDPOINT_START_TRANSACTION;
|
|
@@ -15276,6 +15577,12 @@ var getEntry = function (config, magicLinkCode, signal) {
|
|
|
15276
15577
|
var url = "" + config.host + ENDPOINT_ENTRY(magicLinkCode);
|
|
15277
15578
|
return get(url, apiKey, config.token, signal, true);
|
|
15278
15579
|
};
|
|
15580
|
+
var savePackagingEntry = function (config, request, signal) {
|
|
15581
|
+
var url = "" + config.host + ENDPOINT_SAVE_ENTRY;
|
|
15582
|
+
var apiKey = config.apiKey;
|
|
15583
|
+
var body = JSON.stringify(request);
|
|
15584
|
+
return post(url, apiKey, body, config.token, signal, true);
|
|
15585
|
+
};
|
|
15279
15586
|
var getTrajectEntry = function (config, request, signal) {
|
|
15280
15587
|
var url = "" + config.host + ENDPOINT_TRAJECT;
|
|
15281
15588
|
var apiKey = config.apiKey;
|
|
@@ -15410,6 +15717,8 @@ exports.getEntryList = getEntryList;
|
|
|
15410
15717
|
exports.getEntryListv2 = getEntryListv2;
|
|
15411
15718
|
exports.getEntryStatus = getEntryStatus;
|
|
15412
15719
|
exports.getEntryTotals = getEntryTotals;
|
|
15720
|
+
exports.getFilteredContentDraft = getFilteredContentDraft;
|
|
15721
|
+
exports.getFilteredContentLive = getFilteredContentLive;
|
|
15413
15722
|
exports.getInvoiceList = getInvoiceList;
|
|
15414
15723
|
exports.getItinerary = getItinerary;
|
|
15415
15724
|
exports.getLocations = getLocations;
|
|
@@ -15430,6 +15739,7 @@ exports.print = print;
|
|
|
15430
15739
|
exports.readForm = readForm;
|
|
15431
15740
|
exports.repriceAndIssueTicket = repriceAndIssueTicket;
|
|
15432
15741
|
exports.resetPassword = resetPassword;
|
|
15742
|
+
exports.savePackagingEntry = savePackagingEntry;
|
|
15433
15743
|
exports.search = search;
|
|
15434
15744
|
exports.searchCountries = searchCountries;
|
|
15435
15745
|
exports.searchElastic = searchElastic;
|
|
@@ -18760,332 +19070,1160 @@ const SUMMARY_STEP = 5;
|
|
|
18760
19070
|
const CONFIRMATION_STEP = 6;
|
|
18761
19071
|
const ERROR_STEP = 7;
|
|
18762
19072
|
|
|
18763
|
-
const
|
|
18764
|
-
|
|
18765
|
-
|
|
18766
|
-
};
|
|
18767
|
-
const priceDetailsApi = {
|
|
18768
|
-
fetchPriceDetails: fetchPriceDetails$1
|
|
19073
|
+
const LabeledInput = ({ name, type, required, value, defaultValue, min, max, label, placeholder, extraClassName, hasError, onChange, onBlur }) => {
|
|
19074
|
+
return (React__default["default"].createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
|
|
19075
|
+
React__default["default"].createElement("span", { className: "form__label" }, lodash.compact([label, required && '*']).join(' ')),
|
|
19076
|
+
React__default["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 })));
|
|
18769
19077
|
};
|
|
18770
19078
|
|
|
18771
|
-
const
|
|
18772
|
-
return {
|
|
18773
|
-
|
|
18774
|
-
|
|
18775
|
-
|
|
18776
|
-
...opt,
|
|
18777
|
-
rooms: opt.isSelected ? updateRooms(opt.rooms, changedLines) : opt.rooms,
|
|
18778
|
-
groups: opt.isSelected ? updateBookingGroups(opt.groups, changedLines) : opt.groups,
|
|
18779
|
-
optionUnits: opt.isSelected ? updateOptionUnits(opt.optionUnits, changedLines) : opt.optionUnits,
|
|
18780
|
-
optionPax: opt.isSelected ? updateOptionPax(opt.optionPax, changedLines) : opt.optionPax
|
|
18781
|
-
};
|
|
18782
|
-
})
|
|
18783
|
-
};
|
|
18784
|
-
};
|
|
18785
|
-
// ROOMS
|
|
18786
|
-
const updateRooms = (rooms, changedLines) => {
|
|
18787
|
-
return rooms.map((room) => ({
|
|
18788
|
-
...room,
|
|
18789
|
-
options: room.options.map((option) => ({
|
|
18790
|
-
...option,
|
|
18791
|
-
price: changedLines.find((x) => x.entryLineGuid == option.entryLineGuid)?.price ?? option.price
|
|
18792
|
-
}))
|
|
18793
|
-
}));
|
|
18794
|
-
};
|
|
18795
|
-
// PAX
|
|
18796
|
-
const updateOptionPax = (pax, changedLines) => {
|
|
18797
|
-
return pax.map((p) => ({
|
|
18798
|
-
...p,
|
|
18799
|
-
groups: updatePaxGroups(p.groups, changedLines)
|
|
18800
|
-
}));
|
|
18801
|
-
};
|
|
18802
|
-
const updatePaxGroups = (groups, changedLines) => {
|
|
18803
|
-
return groups.map((g) => ({
|
|
18804
|
-
...g,
|
|
18805
|
-
options: g.options.map((o) => ({
|
|
18806
|
-
...o,
|
|
18807
|
-
groups: updatePaxGroups(o.groups, changedLines),
|
|
18808
|
-
line: {
|
|
18809
|
-
...o.line,
|
|
18810
|
-
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
18811
|
-
},
|
|
18812
|
-
alternatives: o.alternatives.map((a) => ({
|
|
18813
|
-
...a,
|
|
18814
|
-
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
18815
|
-
}))
|
|
18816
|
-
}))
|
|
18817
|
-
}));
|
|
18818
|
-
};
|
|
18819
|
-
// UNITS
|
|
18820
|
-
const updateOptionUnits = (units, changedLines) => {
|
|
18821
|
-
return units.map((u) => ({
|
|
18822
|
-
...u,
|
|
18823
|
-
groups: updateUnitGroups(u.groups, changedLines)
|
|
18824
|
-
}));
|
|
18825
|
-
};
|
|
18826
|
-
const updateUnitGroups = (groups, changedLines) => {
|
|
18827
|
-
return groups.map((g) => ({
|
|
18828
|
-
...g,
|
|
18829
|
-
options: g.options.map((o) => ({
|
|
18830
|
-
...o,
|
|
18831
|
-
groups: updateUnitGroups(o.groups, changedLines),
|
|
18832
|
-
pax: updateOptionPax(o.pax, changedLines),
|
|
18833
|
-
line: {
|
|
18834
|
-
...o.line,
|
|
18835
|
-
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
18836
|
-
},
|
|
18837
|
-
alternatives: o.alternatives.map((a) => ({
|
|
18838
|
-
...a,
|
|
18839
|
-
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
18840
|
-
}))
|
|
18841
|
-
}))
|
|
18842
|
-
}));
|
|
18843
|
-
};
|
|
18844
|
-
// BOOKING
|
|
18845
|
-
const updateBookingGroups = (groups, changedLines) => {
|
|
18846
|
-
return groups.map((g) => ({
|
|
18847
|
-
...g,
|
|
18848
|
-
options: g.options.map((o) => ({
|
|
18849
|
-
...o,
|
|
18850
|
-
groups: updateBookingGroups(o.groups, changedLines),
|
|
18851
|
-
units: updateOptionUnits(o.units, changedLines),
|
|
18852
|
-
pax: updateOptionPax(o.pax, changedLines),
|
|
18853
|
-
line: {
|
|
18854
|
-
...o.line,
|
|
18855
|
-
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
18856
|
-
},
|
|
18857
|
-
alternatives: o.alternatives.map((a) => ({
|
|
18858
|
-
...a,
|
|
18859
|
-
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
18860
|
-
}))
|
|
18861
|
-
}))
|
|
18862
|
-
}));
|
|
19079
|
+
const LabeledSelect = ({ name, id, required, value, defaultValue, label, extraClassName, extraDropdownClassName, hasError, options, onChange, onBlur }) => {
|
|
19080
|
+
return (React__default["default"].createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
|
|
19081
|
+
React__default["default"].createElement("span", { className: "form__label" }, lodash.compact([label, required && '*']).join(' ')),
|
|
19082
|
+
React__default["default"].createElement("div", { className: buildClassName(['dropdown', extraDropdownClassName]) },
|
|
19083
|
+
React__default["default"].createElement("select", { name: name, id: id, defaultValue: defaultValue, value: value, onBlur: onBlur, onChange: onChange }, options?.map((option) => (React__default["default"].createElement("option", { key: option.key, value: option.value }, option.label)))))));
|
|
18863
19084
|
};
|
|
18864
19085
|
|
|
18865
|
-
const
|
|
18866
|
-
|
|
18867
|
-
const
|
|
18868
|
-
|
|
18869
|
-
|
|
18870
|
-
|
|
18871
|
-
|
|
18872
|
-
|
|
18873
|
-
|
|
18874
|
-
|
|
18875
|
-
|
|
18876
|
-
|
|
18877
|
-
|
|
18878
|
-
|
|
18879
|
-
dispatch(setPackage(updatedPackageDetails));
|
|
19086
|
+
const normalize = (v) => (v == null ? '' : String(v));
|
|
19087
|
+
const parseCombined = (raw, countries) => {
|
|
19088
|
+
const value = normalize(raw).trim();
|
|
19089
|
+
if (!value)
|
|
19090
|
+
return { prefix: '', number: '' };
|
|
19091
|
+
// Try to match a known prefix at the start. Prefer longest match.
|
|
19092
|
+
const sorted = [...countries].sort((a, b) => b.phonePrefix.length - a.phonePrefix.length);
|
|
19093
|
+
const hit = sorted.find((c) => value.startsWith(c.phonePrefix));
|
|
19094
|
+
if (hit) {
|
|
19095
|
+
const rest = value
|
|
19096
|
+
.slice(hit.phonePrefix.length)
|
|
19097
|
+
.trim()
|
|
19098
|
+
.replace(/^[-\s]+/, '');
|
|
19099
|
+
return { prefix: hit.phonePrefix, number: rest };
|
|
18880
19100
|
}
|
|
18881
|
-
|
|
18882
|
-
});
|
|
18883
|
-
|
|
18884
|
-
|
|
18885
|
-
|
|
18886
|
-
|
|
18887
|
-
|
|
18888
|
-
|
|
18889
|
-
|
|
18890
|
-
|
|
18891
|
-
|
|
18892
|
-
|
|
18893
|
-
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
|
|
18897
|
-
|
|
18898
|
-
|
|
18899
|
-
|
|
18900
|
-
},
|
|
18901
|
-
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
|
|
18907
|
-
|
|
18908
|
-
}
|
|
18909
|
-
});
|
|
18910
|
-
builder.addCase(fetchPriceDetails.rejected, (state) => {
|
|
18911
|
-
state.isBusy = false;
|
|
19101
|
+
// Fallback: split on first space if it looks like a +prefix number
|
|
19102
|
+
const m = value.match(/^(\+\d{1,4})[\s-]*(.*)$/);
|
|
19103
|
+
if (m)
|
|
19104
|
+
return { prefix: m[1], number: m[2] };
|
|
19105
|
+
return { prefix: '', number: value };
|
|
19106
|
+
};
|
|
19107
|
+
const PhoneInput = ({ name, required, value, label, placeholder, extraClassName, hasError, countries, countryIso2, onChange, onBlur }) => {
|
|
19108
|
+
// Derive initial state from `value`
|
|
19109
|
+
const initialCountry = countries.find((c) => c.iso2 === countryIso2);
|
|
19110
|
+
const initial = React.useMemo(() => parseCombined(normalize(value), countries), [value, countries]);
|
|
19111
|
+
const [prefix, setPrefix] = React.useState(initial.prefix);
|
|
19112
|
+
const [number, setNumber] = React.useState(initial.number);
|
|
19113
|
+
// Keep state in sync if the parent changes `value`
|
|
19114
|
+
React.useEffect(() => {
|
|
19115
|
+
const parsed = !prefix && !number && initialCountry ? { prefix: initialCountry.phonePrefix, number: '' } : parseCombined(normalize(value), countries);
|
|
19116
|
+
if (parsed.prefix)
|
|
19117
|
+
setPrefix(parsed.prefix);
|
|
19118
|
+
if (parsed.number)
|
|
19119
|
+
setNumber(parsed.number);
|
|
19120
|
+
}, [value, countries, countryIso2]);
|
|
19121
|
+
const emitCombinedChange = (e, nextPrefix, nextNumber) => {
|
|
19122
|
+
// Combine with a space, unless the number already starts with a dash or space
|
|
19123
|
+
const combined = nextPrefix && nextNumber ? lodash.compact([nextPrefix, nextNumber]).join(' ') : null;
|
|
19124
|
+
onChange?.({
|
|
19125
|
+
...e,
|
|
19126
|
+
type: 'change',
|
|
19127
|
+
target: { name, value: combined },
|
|
19128
|
+
currentTarget: { name, value: combined }
|
|
18912
19129
|
});
|
|
18913
|
-
}
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
18917
|
-
const
|
|
18918
|
-
|
|
19130
|
+
};
|
|
19131
|
+
const handleCountryBlur = (e) => {
|
|
19132
|
+
onBlur?.(e);
|
|
19133
|
+
};
|
|
19134
|
+
const onCountryChange = (e) => {
|
|
19135
|
+
const next = e.target.value;
|
|
19136
|
+
setPrefix(next);
|
|
19137
|
+
emitCombinedChange(e, next, number);
|
|
19138
|
+
};
|
|
19139
|
+
const onPhoneChange = (e) => {
|
|
19140
|
+
const cleaned = e.target.value.replace(/[^\d\s-]/g, '');
|
|
19141
|
+
setNumber(cleaned);
|
|
19142
|
+
emitCombinedChange(e, prefix, cleaned);
|
|
19143
|
+
};
|
|
19144
|
+
const handleNumberBlur = (e) => {
|
|
19145
|
+
onBlur?.(e);
|
|
19146
|
+
};
|
|
19147
|
+
// Ensure the select shows a reasonable default when prefix is empty
|
|
19148
|
+
const selectValue = prefix || '';
|
|
19149
|
+
return (React__default["default"].createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
|
|
19150
|
+
label && React__default["default"].createElement("span", { className: "form__label" }, lodash.compact([label, required && '*']).join(' ')),
|
|
19151
|
+
React__default["default"].createElement("div", { className: "phone-input" },
|
|
19152
|
+
React__default["default"].createElement("div", { className: "dropdown" },
|
|
19153
|
+
React__default["default"].createElement("select", { "aria-label": label ? `${label} – country code` : 'Country calling code', name: `${name}__country`, value: selectValue, onBlur: handleCountryBlur, onChange: onCountryChange },
|
|
19154
|
+
React__default["default"].createElement("option", { value: "", disabled: true }),
|
|
19155
|
+
countries?.map((option) => (React__default["default"].createElement("option", { key: option.iso2, value: option.phonePrefix },
|
|
19156
|
+
option.name,
|
|
19157
|
+
" (",
|
|
19158
|
+
option.phonePrefix,
|
|
19159
|
+
")"))))),
|
|
19160
|
+
React__default["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 }),
|
|
19161
|
+
React__default["default"].createElement("input", { type: "hidden", name: name, value: lodash.compact([prefix, number]).join(' ') }))));
|
|
19162
|
+
};
|
|
18919
19163
|
|
|
18920
|
-
const
|
|
18921
|
-
|
|
18922
|
-
const
|
|
18923
|
-
|
|
18924
|
-
|
|
18925
|
-
|
|
18926
|
-
|
|
18927
|
-
|
|
18928
|
-
|
|
18929
|
-
|
|
18930
|
-
|
|
18931
|
-
|
|
18932
|
-
|
|
18933
|
-
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
const selectPackageFlights = (state) => ({
|
|
18937
|
-
outward: state.booking.package?.outwardFlights,
|
|
18938
|
-
return: state.booking.package?.returnFlights
|
|
18939
|
-
});
|
|
18940
|
-
const selectFlightMetaData = (state) => state.booking.package?.flightInfo.metaData;
|
|
18941
|
-
const selectActiveOption = (state) => state.booking.package?.options.find((x) => x.isSelected);
|
|
18942
|
-
const selectPackageAirlineGroups = toolkit.createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airlineGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
|
|
18943
|
-
const selectPackageAirportGroups = toolkit.createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airportGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
|
|
18944
|
-
const selectRoomOptionDepartureFlightsMetaData = toolkit.createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
|
|
18945
|
-
const roomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected).shift());
|
|
18946
|
-
return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
|
|
18947
|
-
});
|
|
18948
|
-
const selectRoomOptionReturnFlightsMetaData = toolkit.createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
|
|
18949
|
-
const selectedRoomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected));
|
|
18950
|
-
// check if there are return flights selected
|
|
18951
|
-
if (selectedRoomOptions?.some((ro) => ro.length > 1)) {
|
|
18952
|
-
const roomOptions = ativeOption?.rooms.map((r) => r.options
|
|
18953
|
-
.filter((o) => o.isSelected)
|
|
18954
|
-
.reverse()
|
|
18955
|
-
.shift());
|
|
18956
|
-
return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
|
|
18957
|
-
}
|
|
18958
|
-
return undefined;
|
|
18959
|
-
});
|
|
18960
|
-
const selectApiSettings = (state) => state.apiSettings;
|
|
18961
|
-
const selectIsUnavailable = (state) => state.booking.isUnavailable;
|
|
18962
|
-
const selectRequestRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.requestRooms;
|
|
18963
|
-
const selectOfficeId = (state) => state.booking.officeId;
|
|
18964
|
-
const selectLanguageCode = (state) => state.booking.languageCode;
|
|
18965
|
-
const selectCurrencyCode = (state) => state.booking.package?.currencyCode ?? 'EUR';
|
|
18966
|
-
const selectLanguage = (state) => state.booking.languageCode;
|
|
18967
|
-
const selectAllDynamicTranslations = (state) => state.booking.translations;
|
|
18968
|
-
const selectDynamicTranslations = toolkit.createSelector([selectAllDynamicTranslations, selectLanguage], (allDynamicTranslations, language) => {
|
|
18969
|
-
return allDynamicTranslations?.find((x) => x.language == language)?.value ?? {};
|
|
18970
|
-
});
|
|
18971
|
-
// Host override files are hand-maintained, and a null only ever blanks a key the component
|
|
18972
|
-
// then reads, so treat it like a missing key (lodash merge already skips undefined).
|
|
18973
|
-
const withoutNulls = (value) => lodash.isPlainObject(value)
|
|
18974
|
-
? lodash.mapValues(lodash.pickBy(value, (x) => x !== null), withoutNulls)
|
|
18975
|
-
: value;
|
|
18976
|
-
// getTranslations deep-merges the overrides over a clone of the built-in translations, so a
|
|
18977
|
-
// host override of a nested group (TRAVELERS_FORM.VALIDATION, TRAVELERS_FORM.COUNTRIES)
|
|
18978
|
-
// only replaces the keys it actually contains. Merging per section one level deep dropped
|
|
18979
|
-
// every other built-in key of such a group, which made those keys resolve to undefined and
|
|
18980
|
-
// crash format() in the consuming component.
|
|
18981
|
-
const selectTranslations = toolkit.createSelector([selectLanguage, selectDynamicTranslations], (language, dynamicTranslations) => getTranslations(language, lodash.isEmpty(dynamicTranslations) ? undefined : withoutNulls(dynamicTranslations)));
|
|
18982
|
-
const selectBookingOptions = (state) => state.booking.bookingOptions;
|
|
18983
|
-
const selectBookingType = (state) => state.booking.bookingType;
|
|
18984
|
-
const selectTagIds = (state) => state.booking.tagIds;
|
|
18985
|
-
const selectAgentAdressId = (state) => state.booking.agentAdressId;
|
|
18986
|
-
const selectProductAttributes = (state) => state.booking.productAttributes;
|
|
18987
|
-
const selectBookingAttributes = (state) => state.booking.bookingAttributes;
|
|
18988
|
-
const selectBookingNumber = (state) => state.booking.bookingNumber;
|
|
18989
|
-
const selectIsOption = (state) => state.booking.isOption;
|
|
18990
|
-
const selectBookingRooms = (state) => state.booking.bookingAttributes?.rooms;
|
|
18991
|
-
const selectBookingRemarks = (state) => state.booking.remarks;
|
|
18992
|
-
const selectVoucherCodes = (state) => state.booking.voucherCodes;
|
|
18993
|
-
const selectCalculateDeposit = (state) => state.booking.calculateDeposit;
|
|
18994
|
-
const selectShowCommission = (state) => state.booking.showCommission;
|
|
18995
|
-
const selectIsRetry = (state) => state.booking.isRetry;
|
|
18996
|
-
const selectStartDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.fromDate;
|
|
18997
|
-
const selectEndDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.toDate;
|
|
18998
|
-
const selectAgents = (state) => state.booking.agents;
|
|
18999
|
-
const selectCountries = (state) => state.booking.countries;
|
|
19000
|
-
const selectProductCode = (state) => state.booking.productAttributes?.productCode;
|
|
19001
|
-
const selectAccommodationCodes = (state) => {
|
|
19002
|
-
const accommodationCodes = [];
|
|
19003
|
-
state.booking.package?.options.forEach((o) => {
|
|
19004
|
-
o.rooms.forEach((r) => r.options.forEach((ro) => {
|
|
19005
|
-
if (!accommodationCodes.some((y) => y === ro.accommodationCode)) {
|
|
19006
|
-
accommodationCodes.push(ro.accommodationCode);
|
|
19007
|
-
}
|
|
19008
|
-
}));
|
|
19009
|
-
});
|
|
19010
|
-
return accommodationCodes;
|
|
19164
|
+
const hasVisibleError = (formik, key) => lodash.get(formik.errors, key) && lodash.get(formik.touched, key);
|
|
19165
|
+
|
|
19166
|
+
const GenderControl = ({ translations, value, formik, name }) => {
|
|
19167
|
+
return (React__default["default"].createElement("div", { className: buildClassName(['form__group', hasVisibleError(formik, name) && 'form__group--error']) },
|
|
19168
|
+
React__default["default"].createElement("label", { className: "form__label" },
|
|
19169
|
+
translations.TRAVELERS_FORM.GENDER_ID,
|
|
19170
|
+
" *"),
|
|
19171
|
+
React__default["default"].createElement("div", { className: "radiobutton-group" },
|
|
19172
|
+
React__default["default"].createElement("div", { className: "radiobutton" },
|
|
19173
|
+
React__default["default"].createElement("label", { className: "radiobutton__label" },
|
|
19174
|
+
React__default["default"].createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: "m", checked: value.gender === 'm' }),
|
|
19175
|
+
translations.TRAVELERS_FORM.MALE_GENDER)),
|
|
19176
|
+
React__default["default"].createElement("div", { className: "radiobutton" },
|
|
19177
|
+
React__default["default"].createElement("label", { className: "radiobutton__label" },
|
|
19178
|
+
React__default["default"].createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: "f", checked: value.gender === 'f' }),
|
|
19179
|
+
translations.TRAVELERS_FORM.FEMALE_GENDER)))));
|
|
19011
19180
|
};
|
|
19012
|
-
|
|
19013
|
-
const
|
|
19014
|
-
const
|
|
19015
|
-
const
|
|
19016
|
-
|
|
19017
|
-
|
|
19018
|
-
}
|
|
19019
|
-
const params = {};
|
|
19020
|
-
Object.entries(bookingAttributes).forEach(([key, value]) => {
|
|
19021
|
-
if (key === 'startDate' || key === 'endDate') {
|
|
19022
|
-
value = dateFns.format(dateFns.parseISO(value), 'yyyy-MM-dd');
|
|
19023
|
-
}
|
|
19024
|
-
if (key === 'rooms') {
|
|
19025
|
-
value = JsonURL__default["default"].stringify(value.map((room) => lodash.omit(room, ['children'])), {
|
|
19026
|
-
AQF: true
|
|
19027
|
-
});
|
|
19028
|
-
}
|
|
19029
|
-
if (key === 'allotmentIds' && !value.length) {
|
|
19030
|
-
value = undefined;
|
|
19031
|
-
}
|
|
19032
|
-
if (key === 'flight' && value) {
|
|
19033
|
-
var flightInfo = value;
|
|
19034
|
-
value = JsonURL__default["default"].stringify(flightInfo, { AQF: true });
|
|
19181
|
+
|
|
19182
|
+
const TypeAheadInput = ({ name, value, placeholder, options, onChange, onSelect, onClear }) => {
|
|
19183
|
+
const [showItems, setShowItems] = React.useState(false);
|
|
19184
|
+
const handleChange = (e) => {
|
|
19185
|
+
if (onChange) {
|
|
19186
|
+
onChange(e.target.value);
|
|
19035
19187
|
}
|
|
19036
|
-
|
|
19037
|
-
|
|
19188
|
+
};
|
|
19189
|
+
const handleClearClick = (e) => {
|
|
19190
|
+
if (onClear) {
|
|
19191
|
+
onClear();
|
|
19038
19192
|
}
|
|
19039
|
-
|
|
19040
|
-
|
|
19193
|
+
setShowItems(false);
|
|
19194
|
+
};
|
|
19195
|
+
return (React__default["default"].createElement("div", { className: "typeahead" },
|
|
19196
|
+
React__default["default"].createElement("div", { className: "typeahead__trigger typeahead__trigger--icon" },
|
|
19197
|
+
React__default["default"].createElement(Icon, { name: "ui-qsm-location" }),
|
|
19198
|
+
React__default["default"].createElement("input", { type: "text", className: "form__input", name: name, value: value, onChange: handleChange, placeholder: placeholder, required: true, autoComplete: "off", onKeyDown: (e) => {
|
|
19199
|
+
if (e.key === 'Tab' && options && onSelect) {
|
|
19200
|
+
onSelect(options[0].key);
|
|
19201
|
+
setShowItems(false);
|
|
19202
|
+
}
|
|
19203
|
+
}, onFocus: () => setShowItems(true) }),
|
|
19204
|
+
React__default["default"].createElement("button", { type: "button", className: "button button--clear", onClick: handleClearClick })),
|
|
19205
|
+
options && options.length > 0 && showItems && (React__default["default"].createElement("div", { className: "typeahead__options" }, (options ?? []).map((option) => {
|
|
19206
|
+
const matchIndex = typeof value !== 'undefined' ? option.text.indexOf(value) : 0;
|
|
19207
|
+
const prefix = option.text.slice(0, matchIndex);
|
|
19208
|
+
const highlight = option.text.slice(matchIndex, value?.length ?? 0);
|
|
19209
|
+
const suffix = option.text.slice(matchIndex);
|
|
19210
|
+
return (React__default["default"].createElement("div", { className: "typeahead__option", key: option.key },
|
|
19211
|
+
React__default["default"].createElement("div", { className: "typeahead__option-header" },
|
|
19212
|
+
React__default["default"].createElement("button", { onClick: () => {
|
|
19213
|
+
if (onSelect)
|
|
19214
|
+
onSelect(option.key);
|
|
19215
|
+
setShowItems(false);
|
|
19216
|
+
}, type: "button", className: "button button--plain" },
|
|
19217
|
+
prefix,
|
|
19218
|
+
React__default["default"].createElement("span", { className: "typeahead__option-highlight" }, highlight),
|
|
19219
|
+
suffix))));
|
|
19220
|
+
})))));
|
|
19041
19221
|
};
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
|
|
19222
|
+
|
|
19223
|
+
// A traveler is a baby when the age they were booked with is at or below the baby
|
|
19224
|
+
// boundary. Babies get their own label and birth date validation (TIDE-3269). Only
|
|
19225
|
+
// meaningful for the regular form: the compact form asks for an age instead of a birth
|
|
19226
|
+
// date, so it has nothing to validate and its own age input already states the age.
|
|
19227
|
+
function isBabyAge(age, maxBabyAge = BABY_MAX_AGE) {
|
|
19228
|
+
return typeof age === 'number' && age <= maxBabyAge;
|
|
19229
|
+
}
|
|
19230
|
+
// The native date input can hold values format() throws on (e.g. a 5+ digit year while typing), so never format an unvalidated birthDate
|
|
19231
|
+
function formatBirthDate$1(birthDate) {
|
|
19232
|
+
if (!birthDate)
|
|
19233
|
+
return '';
|
|
19234
|
+
const parsed = dateFns.parse(birthDate, 'yyyy-MM-dd', new Date());
|
|
19235
|
+
return dateFns.isValid(parsed) ? dateFns.format(parsed, 'dd-MM-yyyy') : '';
|
|
19236
|
+
}
|
|
19237
|
+
// A field can have separate "main-booker"/other-pax variants sharing the same identity
|
|
19238
|
+
// (customFieldConfigurationId for custom fields, fieldName for built-in fields).
|
|
19239
|
+
const MAIN_BOOKER_GROUP = 'main-booker';
|
|
19240
|
+
const isCustomPaxField = (field) => field.customFieldConfigurationId != null;
|
|
19241
|
+
function resolveApplicablePaxFields(fields, isMainBooker) {
|
|
19242
|
+
const variantsByKey = new Map();
|
|
19243
|
+
fields.forEach((field) => {
|
|
19244
|
+
const key = field.customFieldConfigurationId ?? field.fieldName;
|
|
19245
|
+
const variants = variantsByKey.get(key) ?? [];
|
|
19246
|
+
variants.push(field);
|
|
19247
|
+
variantsByKey.set(key, variants);
|
|
19248
|
+
});
|
|
19249
|
+
const applicableFields = [];
|
|
19250
|
+
variantsByKey.forEach((variants) => {
|
|
19251
|
+
const hasRoleSplit = variants.some((v) => v.group === MAIN_BOOKER_GROUP);
|
|
19252
|
+
if (!hasRoleSplit) {
|
|
19253
|
+
applicableFields.push(variants[0]);
|
|
19254
|
+
return;
|
|
19059
19255
|
}
|
|
19060
|
-
|
|
19061
|
-
|
|
19062
|
-
|
|
19063
|
-
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
const
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
|
|
19256
|
+
const roleMatch = variants.find((v) => (v.group === MAIN_BOOKER_GROUP) === isMainBooker);
|
|
19257
|
+
if (roleMatch)
|
|
19258
|
+
applicableFields.push(roleMatch);
|
|
19259
|
+
});
|
|
19260
|
+
return applicableFields;
|
|
19261
|
+
}
|
|
19262
|
+
function buildEmptyCustomFields(paxFields = []) {
|
|
19263
|
+
const uniqueIds = Array.from(new Set(paxFields.filter(isCustomPaxField).map((field) => field.customFieldConfigurationId)));
|
|
19264
|
+
return uniqueIds.map((customFieldConfigurationId) => ({ customFieldConfigurationId, value: '' }));
|
|
19265
|
+
}
|
|
19266
|
+
function getApplicablePaxCustomFields(paxFields = [], isMainBooker) {
|
|
19267
|
+
return resolveApplicablePaxFields(paxFields.filter(isCustomPaxField), isMainBooker);
|
|
19268
|
+
}
|
|
19269
|
+
function getApplicableBuiltInPaxFields(paxFields = [], isMainBooker) {
|
|
19270
|
+
return resolveApplicablePaxFields(paxFields.filter((f) => !isCustomPaxField(f)), isMainBooker);
|
|
19271
|
+
}
|
|
19272
|
+
function getBuiltInPaxField(paxFields = [], fieldName, isMainBooker) {
|
|
19273
|
+
return getApplicableBuiltInPaxFields(paxFields, isMainBooker).find((f) => f.fieldName === fieldName);
|
|
19274
|
+
}
|
|
19275
|
+
// fieldName -> path on `Traveler`, shared with validate-form.ts.
|
|
19276
|
+
const BUILT_IN_FIELD_PATHS = {
|
|
19277
|
+
gender: 'gender',
|
|
19278
|
+
firstName: 'firstName',
|
|
19279
|
+
lastName: 'lastName',
|
|
19280
|
+
dateOfBirth: 'birthDate',
|
|
19281
|
+
nickname: 'nickname',
|
|
19282
|
+
birthplace: 'birthplace',
|
|
19283
|
+
nationality: 'nationality',
|
|
19284
|
+
preferredLanguageId: 'preferredLanguageId',
|
|
19285
|
+
email: 'email',
|
|
19286
|
+
phone: 'phone',
|
|
19287
|
+
mobile: 'mobile',
|
|
19288
|
+
passportIssueDate: 'passportIssueDate',
|
|
19289
|
+
passportIssuedLocation: 'passportIssuedLocation',
|
|
19290
|
+
passportExpiryDate: 'passportExpiryDate',
|
|
19291
|
+
passportNumber: 'passportNumber',
|
|
19292
|
+
emergencyNumber: 'emergencyNumber',
|
|
19293
|
+
hasInsurance: 'hasInsurance',
|
|
19294
|
+
insuranceName: 'insuranceName',
|
|
19295
|
+
info: 'info',
|
|
19296
|
+
street: 'address.street',
|
|
19297
|
+
location: 'address.location',
|
|
19298
|
+
countryId: 'address.country',
|
|
19299
|
+
postalCode: 'address.postalCode',
|
|
19300
|
+
number: 'address.number'
|
|
19301
|
+
};
|
|
19302
|
+
// The 4 fields that always render/validate regardless of paxFields config (fallback behavior).
|
|
19303
|
+
const CORE_FIELD_NAMES = new Set(['gender', 'firstName', 'lastName', 'dateOfBirth']);
|
|
19304
|
+
const ADDRESS_FIELD_NAMES = ['street', 'location', 'countryId', 'postalCode', 'number'];
|
|
19305
|
+
// Shared by buildPax (new-booking) and applyTravelersFormValuesToEditablePackagingEntry
|
|
19306
|
+
// (edit-booking), now that PackagingEntryPax and BookingPackagePax have the same shape.
|
|
19307
|
+
function applyTravelerToPax(pax, traveler, mainBookerId) {
|
|
19071
19308
|
return {
|
|
19072
|
-
|
|
19073
|
-
|
|
19074
|
-
|
|
19075
|
-
|
|
19076
|
-
|
|
19077
|
-
|
|
19078
|
-
|
|
19079
|
-
|
|
19080
|
-
|
|
19309
|
+
...pax,
|
|
19310
|
+
firstName: traveler.firstName ?? '',
|
|
19311
|
+
lastName: traveler.lastName ?? '',
|
|
19312
|
+
dateOfBirth: traveler.birthDate || null,
|
|
19313
|
+
isMainBooker: mainBookerId != null ? traveler.id === mainBookerId : pax.isMainBooker,
|
|
19314
|
+
weight: traveler.weight ?? null,
|
|
19315
|
+
weightType: traveler.weightType ?? build.WeightType.kilograms,
|
|
19316
|
+
height: traveler.height ?? null,
|
|
19317
|
+
heightType: traveler.heightType ?? build.HeightType.centimeters,
|
|
19318
|
+
nickname: traveler.nickname,
|
|
19319
|
+
birthplace: traveler.birthplace,
|
|
19320
|
+
nationality: traveler.nationality,
|
|
19321
|
+
preferredLanguageId: traveler.preferredLanguageId,
|
|
19322
|
+
email: traveler.email,
|
|
19323
|
+
phone: traveler.phone,
|
|
19324
|
+
mobilePhone: traveler.mobile,
|
|
19325
|
+
emergencyNumber: traveler.emergencyNumber,
|
|
19326
|
+
passportNumber: traveler.passportNumber,
|
|
19327
|
+
passportIssueDate: traveler.passportIssueDate,
|
|
19328
|
+
passportIssuedLocation: traveler.passportIssuedLocation,
|
|
19329
|
+
passportExpiryDate: traveler.passportExpiryDate,
|
|
19330
|
+
hasInsurance: traveler.hasInsurance,
|
|
19331
|
+
insuranceName: traveler.insuranceName,
|
|
19332
|
+
info: traveler.info,
|
|
19333
|
+
address: buildTravelerAddress(traveler),
|
|
19334
|
+
customFields: traveler.customFields ?? []
|
|
19081
19335
|
};
|
|
19082
|
-
}
|
|
19083
|
-
|
|
19084
|
-
|
|
19336
|
+
}
|
|
19337
|
+
// name/email are required on the wire but aren't part of the per-traveler address sub-form -
|
|
19338
|
+
// derive them from the traveler's own name/email instead of asking twice.
|
|
19339
|
+
function buildTravelerAddress(traveler) {
|
|
19340
|
+
if (!traveler.address || !Object.values(traveler.address).some((v) => !!v))
|
|
19341
|
+
return undefined;
|
|
19085
19342
|
return {
|
|
19086
|
-
|
|
19087
|
-
|
|
19088
|
-
|
|
19343
|
+
name: `${traveler.firstName} ${traveler.lastName}`.trim(),
|
|
19344
|
+
street: traveler.address.street ?? '',
|
|
19345
|
+
number: traveler.address.number ?? '',
|
|
19346
|
+
postalCode: traveler.address.postalCode ?? '',
|
|
19347
|
+
location: traveler.address.location ?? '',
|
|
19348
|
+
country: traveler.address.country ?? '',
|
|
19349
|
+
email: traveler.email ?? ''
|
|
19350
|
+
};
|
|
19351
|
+
}
|
|
19352
|
+
// Always initialized (even when not shown) to keep Formik inputs controlled, matching weight/height.
|
|
19353
|
+
const EMPTY_BUILT_IN_FIELDS = {
|
|
19354
|
+
nickname: '',
|
|
19355
|
+
birthplace: '',
|
|
19356
|
+
nationality: '',
|
|
19357
|
+
preferredLanguageId: undefined,
|
|
19358
|
+
email: '',
|
|
19359
|
+
phone: '',
|
|
19360
|
+
mobile: '',
|
|
19361
|
+
passportNumber: '',
|
|
19362
|
+
passportIssueDate: '',
|
|
19363
|
+
passportIssuedLocation: '',
|
|
19364
|
+
passportExpiryDate: '',
|
|
19365
|
+
emergencyNumber: '',
|
|
19366
|
+
hasInsurance: false,
|
|
19367
|
+
insuranceName: '',
|
|
19368
|
+
info: '',
|
|
19369
|
+
address: { street: '', number: '', postalCode: '', location: '', country: '' }
|
|
19370
|
+
};
|
|
19371
|
+
function createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields) {
|
|
19372
|
+
if (isCompact) {
|
|
19373
|
+
return {
|
|
19374
|
+
id: traveler.id,
|
|
19375
|
+
firstName: personTranslation,
|
|
19376
|
+
lastName: `${followNumber.number++}`,
|
|
19377
|
+
birthDate: '',
|
|
19378
|
+
gender: '',
|
|
19379
|
+
// Keep a booked age of 0 instead of submitting and pricing the traveler as a 30 year
|
|
19380
|
+
// old, while still falling back for a missing or unusable age. `??` alone would let a
|
|
19381
|
+
// NaN (unparseable date of birth upstream) reach the age input and the booked pax.
|
|
19382
|
+
// See TIDE-3269.
|
|
19383
|
+
age: Number.isFinite(traveler.age) ? traveler.age : 30,
|
|
19384
|
+
// No isBaby here on purpose: the age below is editable and nothing revalidates it
|
|
19385
|
+
// in compact mode, so a stored flag would end up contradicting the entered age.
|
|
19386
|
+
weight: null,
|
|
19387
|
+
weightType: build.WeightType.kilograms,
|
|
19388
|
+
height: null,
|
|
19389
|
+
heightType: build.HeightType.centimeters,
|
|
19390
|
+
...EMPTY_BUILT_IN_FIELDS,
|
|
19391
|
+
customFields: buildEmptyCustomFields(paxFields)
|
|
19392
|
+
};
|
|
19393
|
+
}
|
|
19394
|
+
return {
|
|
19395
|
+
id: traveler.id,
|
|
19396
|
+
firstName: '',
|
|
19397
|
+
lastName: '',
|
|
19398
|
+
birthDate: '',
|
|
19399
|
+
gender: '',
|
|
19400
|
+
isBaby: isBabyAge(traveler.age, maxBabyAge),
|
|
19401
|
+
weight: null,
|
|
19402
|
+
weightType: build.WeightType.kilograms,
|
|
19403
|
+
height: null,
|
|
19404
|
+
heightType: build.HeightType.centimeters,
|
|
19405
|
+
...EMPTY_BUILT_IN_FIELDS,
|
|
19406
|
+
customFields: buildEmptyCustomFields(paxFields)
|
|
19407
|
+
};
|
|
19408
|
+
}
|
|
19409
|
+
function createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, personTranslation, isCompact, maxBabyAge, paxFields) {
|
|
19410
|
+
const followNumber = { number: 1 };
|
|
19411
|
+
const initialValues = {
|
|
19412
|
+
startDate,
|
|
19413
|
+
endDate,
|
|
19414
|
+
rooms: formRooms.map((room) => ({
|
|
19415
|
+
adults: room.adults.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields)),
|
|
19416
|
+
children: room.children.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields))
|
|
19417
|
+
})),
|
|
19418
|
+
mainBookerId: -1,
|
|
19419
|
+
street: '',
|
|
19420
|
+
houseNumber: '',
|
|
19421
|
+
box: '',
|
|
19422
|
+
zipCode: '',
|
|
19423
|
+
place: '',
|
|
19424
|
+
country: '',
|
|
19425
|
+
phone: '',
|
|
19426
|
+
email: '',
|
|
19427
|
+
emailConfirmation: '',
|
|
19428
|
+
travelAgentId: agentAdressId ?? 0,
|
|
19429
|
+
travelAgentName: ''
|
|
19430
|
+
};
|
|
19431
|
+
if (initialValues.rooms?.[0]?.adults?.[0]) {
|
|
19432
|
+
initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
|
|
19433
|
+
}
|
|
19434
|
+
return initialValues;
|
|
19435
|
+
}
|
|
19436
|
+
function mapPackagingEntryPaxToTraveler(roomTraveler) {
|
|
19437
|
+
return {
|
|
19438
|
+
weight: roomTraveler.weight ?? null,
|
|
19439
|
+
weightType: roomTraveler.weightType ?? build.WeightType.kilograms,
|
|
19440
|
+
height: roomTraveler.height ?? null,
|
|
19441
|
+
heightType: roomTraveler.heightType ?? build.HeightType.centimeters,
|
|
19442
|
+
nickname: roomTraveler.nickname ?? '',
|
|
19443
|
+
birthplace: roomTraveler.birthplace ?? '',
|
|
19444
|
+
nationality: roomTraveler.nationality ?? '',
|
|
19445
|
+
preferredLanguageId: roomTraveler.preferredLanguageId,
|
|
19446
|
+
email: roomTraveler.email ?? '',
|
|
19447
|
+
phone: roomTraveler.phone ?? '',
|
|
19448
|
+
mobile: roomTraveler.mobilePhone ?? '',
|
|
19449
|
+
passportNumber: roomTraveler.passportNumber ?? '',
|
|
19450
|
+
passportIssueDate: roomTraveler.passportIssueDate ?? '',
|
|
19451
|
+
passportIssuedLocation: roomTraveler.passportIssuedLocation ?? '',
|
|
19452
|
+
passportExpiryDate: roomTraveler.passportExpiryDate ?? '',
|
|
19453
|
+
emergencyNumber: roomTraveler.emergencyNumber ?? '',
|
|
19454
|
+
hasInsurance: roomTraveler.hasInsurance ?? false,
|
|
19455
|
+
insuranceName: roomTraveler.insuranceName ?? '',
|
|
19456
|
+
info: roomTraveler.info ?? '',
|
|
19457
|
+
address: roomTraveler.address
|
|
19458
|
+
? {
|
|
19459
|
+
street: roomTraveler.address.street ?? '',
|
|
19460
|
+
number: roomTraveler.address.number ?? '',
|
|
19461
|
+
postalCode: roomTraveler.address.postalCode ?? '',
|
|
19462
|
+
location: roomTraveler.address.location ?? '',
|
|
19463
|
+
country: roomTraveler.address.country ?? ''
|
|
19464
|
+
}
|
|
19465
|
+
: undefined,
|
|
19466
|
+
customFields: roomTraveler.customFields ?? []
|
|
19467
|
+
};
|
|
19468
|
+
}
|
|
19469
|
+
function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId) {
|
|
19470
|
+
const pax = editablePackagingEntry?.pax ?? [];
|
|
19471
|
+
const rooms = editablePackagingEntry.rooms.map((room) => {
|
|
19472
|
+
const roomPax = pax.filter((x) => room.paxIds.includes(x.id));
|
|
19473
|
+
const adults = roomPax.filter((x) => x.age >= 18);
|
|
19474
|
+
const children = roomPax.filter((x) => x.age < 18);
|
|
19475
|
+
return {
|
|
19476
|
+
adults: adults.map((roomTraveler) => {
|
|
19477
|
+
return {
|
|
19478
|
+
id: roomTraveler.id,
|
|
19479
|
+
firstName: roomTraveler.firstName ?? '',
|
|
19480
|
+
lastName: roomTraveler.lastName ?? '',
|
|
19481
|
+
birthDate: roomTraveler.dateOfBirth ? dateFns.format(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
|
|
19482
|
+
gender: '',
|
|
19483
|
+
...mapPackagingEntryPaxToTraveler(roomTraveler)
|
|
19484
|
+
};
|
|
19485
|
+
}),
|
|
19486
|
+
children: children.map((roomTraveler) => {
|
|
19487
|
+
return {
|
|
19488
|
+
id: roomTraveler.id,
|
|
19489
|
+
firstName: roomTraveler.firstName ?? '',
|
|
19490
|
+
lastName: roomTraveler.lastName ?? '',
|
|
19491
|
+
birthDate: roomTraveler.dateOfBirth ? dateFns.format(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
|
|
19492
|
+
gender: '',
|
|
19493
|
+
isBaby: isBabyAge(roomTraveler.age),
|
|
19494
|
+
...mapPackagingEntryPaxToTraveler(roomTraveler)
|
|
19495
|
+
};
|
|
19496
|
+
})
|
|
19497
|
+
};
|
|
19498
|
+
});
|
|
19499
|
+
const values = createInitialValuesFromRooms(rooms.map((room) => ({ adults: room.adults, children: room.children })), lodash.first(editablePackagingEntry?.lines)?.from, lodash.last(editablePackagingEntry?.lines)?.to, agentAdressId);
|
|
19500
|
+
values.rooms = rooms;
|
|
19501
|
+
values.mainBookerId = pax.find((x) => x.isMainBooker)?.id ?? rooms[0]?.adults?.[0]?.id ?? -1;
|
|
19502
|
+
const address = editablePackagingEntry?.address;
|
|
19503
|
+
values.street = address?.street ?? '';
|
|
19504
|
+
values.houseNumber = address?.houseNumber ?? '';
|
|
19505
|
+
values.box = address?.box ?? '';
|
|
19506
|
+
values.zipCode = address?.zipCode ?? '';
|
|
19507
|
+
values.place = address?.place ?? '';
|
|
19508
|
+
values.country = address?.country ?? '';
|
|
19509
|
+
values.phone = address?.phone ?? '';
|
|
19510
|
+
values.email = address?.email ?? '';
|
|
19511
|
+
values.emailConfirmation = address?.email ?? '';
|
|
19512
|
+
values.travelAgentId = address?.travelAgentId ?? agentAdressId ?? 0;
|
|
19513
|
+
return values;
|
|
19514
|
+
}
|
|
19515
|
+
function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry, values) {
|
|
19516
|
+
const travelers = values.rooms.flatMap((room) => [...room.adults, ...room.children]);
|
|
19517
|
+
// The backend treats the main booker's per-pax address as authoritative, so keep the
|
|
19518
|
+
// booking-level address in sync with it rather than sending two independent values.
|
|
19519
|
+
const mainBookerAddress = travelers.find((x) => x.id === values.mainBookerId)?.address;
|
|
19520
|
+
return {
|
|
19521
|
+
...editablePackagingEntry,
|
|
19522
|
+
pax: (editablePackagingEntry.pax ?? []).map((pax) => {
|
|
19523
|
+
const traveler = travelers.find((x) => x.id === pax.id);
|
|
19524
|
+
return traveler ? applyTravelerToPax(pax, traveler, values.mainBookerId) : pax;
|
|
19525
|
+
}),
|
|
19526
|
+
address: {
|
|
19527
|
+
...editablePackagingEntry.address,
|
|
19528
|
+
street: mainBookerAddress?.street || values.street,
|
|
19529
|
+
houseNumber: mainBookerAddress?.number || values.houseNumber,
|
|
19530
|
+
box: values.box,
|
|
19531
|
+
zipCode: mainBookerAddress?.postalCode || values.zipCode,
|
|
19532
|
+
place: mainBookerAddress?.location || values.place,
|
|
19533
|
+
country: mainBookerAddress?.country || values.country,
|
|
19534
|
+
travelAgentId: values.travelAgentId,
|
|
19535
|
+
phone: values.phone,
|
|
19536
|
+
email: values.email
|
|
19537
|
+
}
|
|
19538
|
+
};
|
|
19539
|
+
}
|
|
19540
|
+
const SharedTravelersForm = ({ formik, translations, travellersSettings, countries, agents, bookingType, agentAdressId, travelersFirstStep = false, isUnavailable = false, useCompactForm = false, showAllCountries = false, paxFields, showAgentSelection = false, initialShowAgents = false, renderPreviousButton, onBookingTypeChange }) => {
|
|
19541
|
+
const [showAgents, setShowAgents] = React.useState(initialShowAgents);
|
|
19542
|
+
const typeaheadAgents = React.useMemo(() => lodash.sortBy(agents?.map((agent) => ({
|
|
19543
|
+
key: `${agent.id}`,
|
|
19544
|
+
value: `${agent.name}${agent.postalCode || agent.location ? ` (${lodash.compact([agent.postalCode, agent.location]).join(' ')})` : ''}`,
|
|
19545
|
+
text: `${agent.name}${agent.postalCode || agent.location ? ` (${lodash.compact([agent.postalCode, agent.location]).join(' ')})` : ''}`
|
|
19546
|
+
})), 'value') ?? [], [agents]);
|
|
19547
|
+
const [filteredAgents, setFilteredAgents] = React.useState(typeaheadAgents);
|
|
19548
|
+
const flatErrors = flat__default["default"](formik.errors);
|
|
19549
|
+
const errorKeys = Object.keys(flatErrors).filter((key) => lodash.get(formik.touched, key));
|
|
19550
|
+
const hasVisibleError = (key) => lodash.get(formik.errors, key) && lodash.get(formik.touched, key);
|
|
19551
|
+
const mainBooker = formik.values.rooms
|
|
19552
|
+
.find((room) => room.adults.find((traveler) => traveler.id === formik.values.mainBookerId))
|
|
19553
|
+
?.adults.find((traveler) => traveler.id === formik.values.mainBookerId);
|
|
19554
|
+
const countryOptions = [
|
|
19555
|
+
{ key: 'empty', value: undefined, label: translations.TRAVELERS_FORM.SELECT_COUNTRY },
|
|
19556
|
+
...(showAllCountries
|
|
19557
|
+
? countries?.map((country) => ({ key: country.iso2, value: country.iso2, label: country.name })) ?? []
|
|
19558
|
+
: travellersSettings?.countries?.map((country) => ({ key: country.iso2, value: country.iso2, label: country.name })) ?? [
|
|
19559
|
+
{ key: 'be', value: 'be', label: translations.TRAVELERS_FORM.COUNTRIES.BELGIUM },
|
|
19560
|
+
{ key: 'nl', value: 'nl', label: translations.TRAVELERS_FORM.COUNTRIES.NETHERLANDS },
|
|
19561
|
+
{ key: 'fr', value: 'fr', label: translations.TRAVELERS_FORM.COUNTRIES.FRANCE }
|
|
19562
|
+
])
|
|
19563
|
+
];
|
|
19564
|
+
const handleMainBookerChange = (event) => {
|
|
19565
|
+
formik.setFieldValue('mainBookerId', parseInt(event.currentTarget.value, 10));
|
|
19566
|
+
};
|
|
19567
|
+
const handleAgentChange = (value) => {
|
|
19568
|
+
setFilteredAgents(typeaheadAgents.filter((x) => x.value.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) > -1));
|
|
19569
|
+
formik.setFieldValue('travelAgentName', value);
|
|
19570
|
+
};
|
|
19571
|
+
const handleAgentSelect = (key) => {
|
|
19572
|
+
const agent = typeaheadAgents.find((x) => x.key === key);
|
|
19573
|
+
formik.setValues({
|
|
19574
|
+
...formik.values,
|
|
19575
|
+
travelAgentId: Number(agent?.key),
|
|
19576
|
+
travelAgentName: agent?.value ?? ''
|
|
19577
|
+
});
|
|
19578
|
+
onBookingTypeChange?.(agentAdressId && agentAdressId !== 0 ? 'b2b' : 'b2b2c');
|
|
19579
|
+
};
|
|
19580
|
+
const handleAgentClear = () => {
|
|
19581
|
+
formik.setValues({ ...formik.values, travelAgentId: 0, travelAgentName: '' });
|
|
19582
|
+
onBookingTypeChange?.('b2c');
|
|
19583
|
+
};
|
|
19584
|
+
const toggleAgent = (value) => {
|
|
19585
|
+
setShowAgents(value);
|
|
19586
|
+
if (!value) {
|
|
19587
|
+
handleAgentClear();
|
|
19588
|
+
setFilteredAgents([]);
|
|
19589
|
+
}
|
|
19590
|
+
};
|
|
19591
|
+
const handleAddTraveler = (roomIndex) => {
|
|
19592
|
+
const rooms = [...formik.values.rooms];
|
|
19593
|
+
const newAdult = {
|
|
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
|
+
rooms[roomIndex] = { ...rooms[roomIndex], adults: [...rooms[roomIndex].adults, newAdult] };
|
|
19607
|
+
formik.setFieldValue('rooms', rooms);
|
|
19608
|
+
};
|
|
19609
|
+
const handleRemoveTraveler = (roomIndex, travelerIndex) => {
|
|
19610
|
+
const rooms = [...formik.values.rooms];
|
|
19611
|
+
const adults = [...rooms[roomIndex].adults];
|
|
19612
|
+
if (adults.length <= 1)
|
|
19613
|
+
return;
|
|
19614
|
+
adults.splice(travelerIndex, 1);
|
|
19615
|
+
rooms[roomIndex] = { ...rooms[roomIndex], adults };
|
|
19616
|
+
formik.setFieldValue('rooms', rooms);
|
|
19617
|
+
};
|
|
19618
|
+
const handleAddRoom = () => {
|
|
19619
|
+
const rooms = [...formik.values.rooms];
|
|
19620
|
+
rooms.push({
|
|
19621
|
+
adults: [
|
|
19622
|
+
{
|
|
19623
|
+
id: Date.now(),
|
|
19624
|
+
firstName: '',
|
|
19625
|
+
lastName: '',
|
|
19626
|
+
birthDate: '',
|
|
19627
|
+
gender: '',
|
|
19628
|
+
weight: null,
|
|
19629
|
+
weightType: build.WeightType.kilograms,
|
|
19630
|
+
height: null,
|
|
19631
|
+
heightType: build.HeightType.centimeters,
|
|
19632
|
+
...EMPTY_BUILT_IN_FIELDS,
|
|
19633
|
+
customFields: buildEmptyCustomFields(paxFields)
|
|
19634
|
+
}
|
|
19635
|
+
],
|
|
19636
|
+
children: []
|
|
19637
|
+
});
|
|
19638
|
+
formik.setFieldValue('rooms', rooms);
|
|
19639
|
+
};
|
|
19640
|
+
const handleRemoveRoom = (roomIndex) => {
|
|
19641
|
+
const rooms = [...formik.values.rooms];
|
|
19642
|
+
rooms.splice(roomIndex, 1);
|
|
19643
|
+
formik.setFieldValue('rooms', rooms);
|
|
19644
|
+
};
|
|
19645
|
+
const renderWeightControl = (namePrefix, value, isRequired) => (React__default["default"].createElement("div", { className: "form__row" },
|
|
19646
|
+
React__default["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 ?? '' }),
|
|
19647
|
+
React__default["default"].createElement(LabeledSelect, { extraClassName: "form__group--md-33", name: `${namePrefix}.weightType`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.weightType, options: [
|
|
19648
|
+
{ key: 'kg', value: build.WeightType.kilograms, label: translations.TRAVELERS_FORM.WEIGHT_UNIT_KG },
|
|
19649
|
+
{ key: 'lb', value: build.WeightType.pounds, label: translations.TRAVELERS_FORM.WEIGHT_UNIT_LB }
|
|
19650
|
+
] })));
|
|
19651
|
+
const renderHeightControl = (namePrefix, value, isRequired) => (React__default["default"].createElement("div", { className: "form__row" },
|
|
19652
|
+
React__default["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 ?? '' }),
|
|
19653
|
+
React__default["default"].createElement(LabeledSelect, { extraClassName: "form__group--md-33", name: `${namePrefix}.heightType`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.heightType, options: [
|
|
19654
|
+
{ key: 'cm', value: build.HeightType.centimeters, label: translations.TRAVELERS_FORM.HEIGHT_UNIT_CM },
|
|
19655
|
+
{ key: 'ftIn', value: build.HeightType.feetInches, label: translations.TRAVELERS_FORM.HEIGHT_UNIT_FT_IN }
|
|
19656
|
+
] })));
|
|
19657
|
+
const getCustomFieldControl = (field, value, name) => {
|
|
19658
|
+
const label = lodash.compact([field.fieldName, field.isRequired && '*']).join(' ');
|
|
19659
|
+
switch (field.dataType) {
|
|
19660
|
+
case build.CustomFieldDataType.bool:
|
|
19661
|
+
return (React__default["default"].createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
|
|
19662
|
+
React__default["default"].createElement("div", { className: "checkbox" },
|
|
19663
|
+
React__default["default"].createElement("label", { className: "checkbox__label" },
|
|
19664
|
+
React__default["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 }),
|
|
19665
|
+
label))));
|
|
19666
|
+
case build.CustomFieldDataType.date:
|
|
19667
|
+
return (React__default["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 }));
|
|
19668
|
+
case build.CustomFieldDataType.time:
|
|
19669
|
+
return (React__default["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 }));
|
|
19670
|
+
case build.CustomFieldDataType.numeric:
|
|
19671
|
+
return (React__default["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 }));
|
|
19672
|
+
case build.CustomFieldDataType.string:
|
|
19673
|
+
default:
|
|
19674
|
+
return (React__default["default"].createElement(LabeledInput, { hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
19675
|
+
}
|
|
19676
|
+
};
|
|
19677
|
+
const renderCustomFields = (travelerValues, namePrefix) => {
|
|
19678
|
+
if (!paxFields?.length)
|
|
19679
|
+
return null;
|
|
19680
|
+
const isMainBooker = travelerValues.id === formik.values.mainBookerId;
|
|
19681
|
+
const applicableFields = getApplicablePaxCustomFields(paxFields, isMainBooker);
|
|
19682
|
+
if (!applicableFields.length)
|
|
19683
|
+
return null;
|
|
19684
|
+
return (React__default["default"].createElement("div", { className: "travelers-form__custom-fields-grid" }, applicableFields.map((field) => {
|
|
19685
|
+
const fieldIndex = travelerValues.customFields?.findIndex((c) => c.customFieldConfigurationId === field.customFieldConfigurationId) ?? -1;
|
|
19686
|
+
if (fieldIndex < 0)
|
|
19687
|
+
return null;
|
|
19688
|
+
const name = `${namePrefix}.customFields[${fieldIndex}].value`;
|
|
19689
|
+
const value = travelerValues.customFields[fieldIndex].value;
|
|
19690
|
+
return (React__default["default"].createElement("div", { key: field.customFieldConfigurationId, style: { gridColumn: `span ${field.col || 12}` } }, getCustomFieldControl(field, value, name)));
|
|
19691
|
+
})));
|
|
19692
|
+
};
|
|
19693
|
+
// Fields with a dedicated control (gender, hasInsurance, countryId) aren't listed here.
|
|
19694
|
+
const BUILT_IN_FIELD_CONTROL_META = {
|
|
19695
|
+
firstName: { label: translations.TRAVELERS_FORM.FIRST_NAME },
|
|
19696
|
+
lastName: { label: translations.TRAVELERS_FORM.LAST_NAME },
|
|
19697
|
+
dateOfBirth: { type: 'date', label: translations.TRAVELERS_FORM.BIRTHDATE },
|
|
19698
|
+
nickname: { label: translations.TRAVELERS_FORM.NICKNAME },
|
|
19699
|
+
birthplace: { label: translations.TRAVELERS_FORM.BIRTHPLACE },
|
|
19700
|
+
nationality: { label: translations.TRAVELERS_FORM.NATIONALITY },
|
|
19701
|
+
preferredLanguageId: { type: 'number', label: translations.TRAVELERS_FORM.PREFERRED_LANGUAGE },
|
|
19702
|
+
email: { type: 'email', label: translations.TRAVELERS_FORM.TRAVELER_EMAIL },
|
|
19703
|
+
phone: { label: translations.TRAVELERS_FORM.TRAVELER_PHONE },
|
|
19704
|
+
mobile: { label: translations.TRAVELERS_FORM.TRAVELER_MOBILE },
|
|
19705
|
+
passportNumber: { label: translations.TRAVELERS_FORM.PASSPORT_NUMBER },
|
|
19706
|
+
passportIssueDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_ISSUE_DATE },
|
|
19707
|
+
passportIssuedLocation: { label: translations.TRAVELERS_FORM.PASSPORT_ISSUED_LOCATION },
|
|
19708
|
+
passportExpiryDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_EXPIRY_DATE },
|
|
19709
|
+
emergencyNumber: { label: translations.TRAVELERS_FORM.EMERGENCY_NUMBER },
|
|
19710
|
+
insuranceName: { label: translations.TRAVELERS_FORM.INSURANCE_NAME },
|
|
19711
|
+
info: { label: translations.TRAVELERS_FORM.INFO },
|
|
19712
|
+
street: { label: translations.TRAVELERS_FORM.STREET },
|
|
19713
|
+
location: { label: translations.TRAVELERS_FORM.CITY },
|
|
19714
|
+
postalCode: { label: translations.TRAVELERS_FORM.ZIPCODE },
|
|
19715
|
+
number: { label: translations.TRAVELERS_FORM.HOUSE_NUMBER }
|
|
19716
|
+
};
|
|
19717
|
+
const renderBuiltInFieldControl = (fieldName, isRequired, travelerValues, namePrefix) => {
|
|
19718
|
+
const path = BUILT_IN_FIELD_PATHS[fieldName] ?? fieldName;
|
|
19719
|
+
const name = `${namePrefix}.${path}`;
|
|
19720
|
+
const value = lodash.get(travelerValues, path);
|
|
19721
|
+
switch (fieldName) {
|
|
19722
|
+
case 'gender':
|
|
19723
|
+
return React__default["default"].createElement(GenderControl, { translations: translations, value: travelerValues, formik: formik, name: name });
|
|
19724
|
+
case 'hasInsurance':
|
|
19725
|
+
return (React__default["default"].createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
|
|
19726
|
+
React__default["default"].createElement("div", { className: "checkbox" },
|
|
19727
|
+
React__default["default"].createElement("label", { className: "checkbox__label" },
|
|
19728
|
+
React__default["default"].createElement("input", { type: "checkbox", className: "checkbox__input", checked: !!value, onChange: (e) => formik.setFieldValue(name, e.target.checked), onBlur: formik.handleBlur, name: name }),
|
|
19729
|
+
lodash.compact([translations.TRAVELERS_FORM.HAS_INSURANCE, isRequired && '*']).join(' ')))));
|
|
19730
|
+
case 'countryId':
|
|
19731
|
+
return (React__default["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 }));
|
|
19732
|
+
case 'weight':
|
|
19733
|
+
return renderWeightControl(namePrefix, travelerValues, isRequired);
|
|
19734
|
+
case 'height':
|
|
19735
|
+
return renderHeightControl(namePrefix, travelerValues, isRequired);
|
|
19736
|
+
default: {
|
|
19737
|
+
const meta = BUILT_IN_FIELD_CONTROL_META[fieldName] ?? { label: fieldName };
|
|
19738
|
+
return (React__default["default"].createElement(LabeledInput, { type: meta.type, hasError: hasVisibleError(name), label: meta.label, required: isRequired, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value ?? '' }));
|
|
19739
|
+
}
|
|
19740
|
+
}
|
|
19741
|
+
};
|
|
19742
|
+
const CORE_FIELD_DEFAULTS = {
|
|
19743
|
+
gender: { isRequired: true, col: 4 },
|
|
19744
|
+
firstName: { isRequired: true, col: 4 },
|
|
19745
|
+
lastName: { isRequired: true, col: 4 },
|
|
19746
|
+
dateOfBirth: { isRequired: true, col: 4 }
|
|
19747
|
+
};
|
|
19748
|
+
const resolveBuiltInField = (fieldName, travelerValues) => {
|
|
19749
|
+
const isMainBooker = travelerValues.id === formik.values.mainBookerId;
|
|
19750
|
+
const configured = getBuiltInPaxField(paxFields, fieldName, isMainBooker);
|
|
19751
|
+
const fallback = CORE_FIELD_DEFAULTS[fieldName];
|
|
19752
|
+
if (!configured && !fallback)
|
|
19753
|
+
return undefined;
|
|
19754
|
+
return { isRequired: configured?.isRequired ?? fallback.isRequired, col: configured?.col ?? fallback.col };
|
|
19755
|
+
};
|
|
19756
|
+
const renderBuiltInField = (fieldName, travelerValues, namePrefix) => {
|
|
19757
|
+
const resolved = resolveBuiltInField(fieldName, travelerValues);
|
|
19758
|
+
if (!resolved)
|
|
19759
|
+
return null;
|
|
19760
|
+
return (React__default["default"].createElement("div", { key: fieldName, style: { gridColumn: `span ${resolved.col || 12}` } }, renderBuiltInFieldControl(fieldName, resolved.isRequired, travelerValues, namePrefix)));
|
|
19761
|
+
};
|
|
19762
|
+
const renderTravelerAddressFields = (travelerValues, namePrefix) => {
|
|
19763
|
+
const fields = ADDRESS_FIELD_NAMES.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix)).filter(Boolean);
|
|
19764
|
+
if (!fields.length)
|
|
19765
|
+
return null;
|
|
19766
|
+
return React__default["default"].createElement("div", { className: "travelers-form__custom-fields-grid" }, fields);
|
|
19767
|
+
};
|
|
19768
|
+
const getControl = (type, value, name) => {
|
|
19769
|
+
switch (type) {
|
|
19770
|
+
case 'country':
|
|
19771
|
+
return (React__default["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 }));
|
|
19772
|
+
case 'phone':
|
|
19773
|
+
return (React__default["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 }));
|
|
19774
|
+
case 'email':
|
|
19775
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
19776
|
+
React__default["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 }),
|
|
19777
|
+
React__default["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 })));
|
|
19778
|
+
case 'street':
|
|
19779
|
+
return (React__default["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 }));
|
|
19780
|
+
case 'houseNumber':
|
|
19781
|
+
return (React__default["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 }));
|
|
19782
|
+
case 'box':
|
|
19783
|
+
return (React__default["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 }));
|
|
19784
|
+
case 'zipCode':
|
|
19785
|
+
return (React__default["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 }));
|
|
19786
|
+
case 'place':
|
|
19787
|
+
return (React__default["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 }));
|
|
19788
|
+
default:
|
|
19789
|
+
return null;
|
|
19790
|
+
}
|
|
19791
|
+
};
|
|
19792
|
+
const renderRoomLabel = (room) => lodash.compact([
|
|
19793
|
+
room.adults.length,
|
|
19794
|
+
room.adults.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
|
|
19795
|
+
room.adults.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
|
|
19796
|
+
room.adults?.length && room.children?.length && ', ',
|
|
19797
|
+
room.children.length,
|
|
19798
|
+
room.children.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
|
|
19799
|
+
room.children.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`
|
|
19800
|
+
]).join('');
|
|
19801
|
+
const renderTravelerFields = (travelerValues, namePrefix, isAdult, roomIndex, travelerIndex) => {
|
|
19802
|
+
if (useCompactForm) {
|
|
19803
|
+
return (React__default["default"].createElement("div", { className: "form__row" },
|
|
19804
|
+
React__default["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 })));
|
|
19805
|
+
}
|
|
19806
|
+
// 'birthDate' (the legacy formFields type string) is normalized to the paxFields catalog's
|
|
19807
|
+
// 'dateOfBirth' fieldName for config lookups.
|
|
19808
|
+
const baseFieldNames = (travellersSettings?.formFields?.length ? travellersSettings.formFields.map((field) => field.type) : ['gender', 'firstName', 'lastName', 'dateOfBirth']).map((fieldName) => (fieldName === 'birthDate' ? 'dateOfBirth' : fieldName));
|
|
19809
|
+
const isMainBooker = travelerValues.id === formik.values.mainBookerId;
|
|
19810
|
+
const extraFieldNames = getApplicableBuiltInPaxFields(paxFields, isMainBooker)
|
|
19811
|
+
.map((field) => field.fieldName)
|
|
19812
|
+
.filter((fieldName) => !baseFieldNames.includes(fieldName) && !ADDRESS_FIELD_NAMES.includes(fieldName));
|
|
19813
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
19814
|
+
React__default["default"].createElement("div", { className: "travelers-form__custom-fields-grid" }, [...baseFieldNames, ...extraFieldNames].map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix))),
|
|
19815
|
+
renderTravelerAddressFields(travelerValues, namePrefix),
|
|
19816
|
+
renderCustomFields(travelerValues, namePrefix),
|
|
19817
|
+
travelersFirstStep && isAdult && formik.values.rooms[roomIndex].adults.length > 1 && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveTraveler(roomIndex, travelerIndex) }, translations.TRAVELERS_FORM.REMOVE_TRAVELER))));
|
|
19818
|
+
};
|
|
19819
|
+
return (React__default["default"].createElement("form", { className: "form form__travelers", name: "booking--travellers", id: "booking--travellers", noValidate: true, onSubmit: formik.handleSubmit, onReset: formik.handleReset },
|
|
19820
|
+
React__default["default"].createElement("div", { className: "form__travelers__wrapper" },
|
|
19821
|
+
formik.values.rooms.map((room, roomIndex) => (React__default["default"].createElement("div", { key: roomIndex },
|
|
19822
|
+
formik.values.rooms.length > 1 && (React__default["default"].createElement("div", { className: "form__region" },
|
|
19823
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
19824
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" },
|
|
19825
|
+
translations.SHARED.ROOM,
|
|
19826
|
+
" ",
|
|
19827
|
+
roomIndex + 1),
|
|
19828
|
+
React__default["default"].createElement("p", { className: "form__region-label" }, renderRoomLabel(room))),
|
|
19829
|
+
!useCompactForm && travelersFirstStep && formik.values.rooms.length > 1 && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveRoom(roomIndex) }, "Verwijder reisgezelschap")))),
|
|
19830
|
+
room.adults.map((travelerValues, index) => (React__default["default"].createElement("div", { className: "form__region", key: travelerValues.id },
|
|
19831
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
19832
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" },
|
|
19833
|
+
translations.TRAVELERS_FORM.TRAVELER,
|
|
19834
|
+
" ",
|
|
19835
|
+
index + 1),
|
|
19836
|
+
React__default["default"].createElement("p", { className: "form__region-label" }, translations.TRAVELERS_FORM.ADULT),
|
|
19837
|
+
React__default["default"].createElement("div", { className: "radiobutton" },
|
|
19838
|
+
React__default["default"].createElement("label", { className: "radiobutton__label" },
|
|
19839
|
+
React__default["default"].createElement("input", { type: "radio", name: "mainBookerId", onChange: handleMainBookerChange, onBlur: formik.handleBlur, value: travelerValues.id, checked: formik.values.mainBookerId === travelerValues.id, className: "radiobutton__input" }),
|
|
19840
|
+
translations.TRAVELERS_FORM.MAIN_BOOKER))),
|
|
19841
|
+
renderTravelerFields(travelerValues, `rooms[${roomIndex}].adults[${index}]`, true, roomIndex, index)))),
|
|
19842
|
+
room.children.map((travelerValues, index) => (React__default["default"].createElement("div", { className: "form__region", key: travelerValues.id },
|
|
19843
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
19844
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" },
|
|
19845
|
+
translations.TRAVELERS_FORM.TRAVELER,
|
|
19846
|
+
" ",
|
|
19847
|
+
room.adults.length + index + 1),
|
|
19848
|
+
React__default["default"].createElement("p", { className: "form__region-label" }, travelerValues.isBaby ? translations.TRAVELERS_FORM.BABY : translations.TRAVELERS_FORM.CHILD)),
|
|
19849
|
+
renderTravelerFields(travelerValues, `rooms[${roomIndex}].children[${index}]`, false, roomIndex, index)))),
|
|
19850
|
+
!useCompactForm && travelersFirstStep && (React__default["default"].createElement("div", { className: "form__region" },
|
|
19851
|
+
React__default["default"].createElement("button", { type: "button", className: "cta cta--select", onClick: () => handleAddTraveler(roomIndex) }, translations.TRAVELERS_FORM.ADD_TRAVELER)))))),
|
|
19852
|
+
!useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default["default"].createElement("div", { className: "form__region" },
|
|
19853
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
19854
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
|
|
19855
|
+
React__default["default"].createElement("p", { className: "form__region-label" }, lodash.compact([lodash.compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
|
|
19856
|
+
travellersSettings?.mainBookerFormFields?.length ? (React__default["default"].createElement("div", { className: "main-booker-form__grid" }, travellersSettings.mainBookerFormFields.map((field, index) => (React__default["default"].createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, {}, field.type)))))) : (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
19857
|
+
React__default["default"].createElement("div", { className: "form__twocolumn" },
|
|
19858
|
+
React__default["default"].createElement("div", { className: "form__twocolumn-column" },
|
|
19859
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
19860
|
+
React__default["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 }),
|
|
19861
|
+
React__default["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 }),
|
|
19862
|
+
React__default["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 }))),
|
|
19863
|
+
React__default["default"].createElement("div", { className: "form__twocolumn-column" },
|
|
19864
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
19865
|
+
React__default["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 }),
|
|
19866
|
+
React__default["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 }),
|
|
19867
|
+
React__default["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 })))),
|
|
19868
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
19869
|
+
React__default["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 }),
|
|
19870
|
+
React__default["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 }),
|
|
19871
|
+
React__default["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["default"].createElement("div", { className: "form__region" },
|
|
19872
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
19873
|
+
React__default["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,
|
|
19874
|
+
!useCompactForm && showAgentSelection && (React__default["default"].createElement("div", { className: "form__region" },
|
|
19875
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
19876
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.BOOK_WITH_AGENT),
|
|
19877
|
+
React__default["default"].createElement("div", { className: "checkbox", id: "cbxChooseOffice" },
|
|
19878
|
+
React__default["default"].createElement("label", { className: "checkbox__label" },
|
|
19879
|
+
React__default["default"].createElement("input", { type: "checkbox", name: "booking--mainbooker", checked: showAgents, onChange: () => toggleAgent(!showAgents), className: "checkbox__input" }),
|
|
19880
|
+
translations.TRAVELERS_FORM.CHOOSE_OFFICE))),
|
|
19881
|
+
showAgents && (React__default["default"].createElement("div", { className: "form__row form__row--choose-office" },
|
|
19882
|
+
React__default["default"].createElement("div", { className: buildClassName(['form__group', 'form__group--icon', hasVisibleError('travelAgentId') && 'form__group--error']) },
|
|
19883
|
+
React__default["default"].createElement(TypeAheadInput, { value: formik.values.travelAgentName, options: filteredAgents, onChange: handleAgentChange, onSelect: handleAgentSelect, onClear: handleAgentClear, name: "travelAgentName", placeholder: translations.TRAVELERS_FORM.CHOOSE_AGENT_PLACEHOLDER }))))))),
|
|
19884
|
+
!useCompactForm && errorKeys.length > 0 && (React__default["default"].createElement("div", { className: "form__region form__region--errors" },
|
|
19885
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
19886
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
19887
|
+
React__default["default"].createElement("p", { className: "form__error-heading" },
|
|
19888
|
+
translations.TRAVELERS_FORM.VALIDATION_MESSAGE,
|
|
19889
|
+
":"),
|
|
19890
|
+
React__default["default"].createElement("ul", { className: "list" }, errorKeys.map((key) => (React__default["default"].createElement("li", { key: key }, lodash.get(flatErrors, key))))))))),
|
|
19891
|
+
travelersFirstStep && (React__default["default"].createElement("div", { className: "booking__navigator" },
|
|
19892
|
+
React__default["default"].createElement("button", { type: "button", className: "cta cta--select", onClick: handleAddRoom }, translations.TRAVELERS_FORM.ADD_ROOM))),
|
|
19893
|
+
React__default["default"].createElement("div", { className: "booking__navigator" },
|
|
19894
|
+
renderPreviousButton?.(),
|
|
19895
|
+
React__default["default"].createElement("button", { type: "submit", title: translations.STEPS.NEXT, className: 'cta' + (isUnavailable ? ' cta--disabled' : '') }, translations.STEPS.NEXT))));
|
|
19896
|
+
};
|
|
19897
|
+
|
|
19898
|
+
const fetchPriceDetails$1 = async (apiSettings, request, signal, languageCode) => {
|
|
19899
|
+
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
19900
|
+
return await build.priceDetails(tideClientConfig, request, signal, languageCode);
|
|
19901
|
+
};
|
|
19902
|
+
const priceDetailsApi = {
|
|
19903
|
+
fetchPriceDetails: fetchPriceDetails$1
|
|
19904
|
+
};
|
|
19905
|
+
|
|
19906
|
+
const updatePackageDetails = (packageDetails, changedLines) => {
|
|
19907
|
+
return {
|
|
19908
|
+
...packageDetails,
|
|
19909
|
+
options: packageDetails.options.map((opt) => {
|
|
19910
|
+
return {
|
|
19911
|
+
...opt,
|
|
19912
|
+
rooms: opt.isSelected ? updateRooms(opt.rooms, changedLines) : opt.rooms,
|
|
19913
|
+
groups: opt.isSelected ? updateBookingGroups(opt.groups, changedLines) : opt.groups,
|
|
19914
|
+
optionUnits: opt.isSelected ? updateOptionUnits(opt.optionUnits, changedLines) : opt.optionUnits,
|
|
19915
|
+
optionPax: opt.isSelected ? updateOptionPax(opt.optionPax, changedLines) : opt.optionPax
|
|
19916
|
+
};
|
|
19917
|
+
})
|
|
19918
|
+
};
|
|
19919
|
+
};
|
|
19920
|
+
// ROOMS
|
|
19921
|
+
const updateRooms = (rooms, changedLines) => {
|
|
19922
|
+
return rooms.map((room) => ({
|
|
19923
|
+
...room,
|
|
19924
|
+
options: room.options.map((option) => ({
|
|
19925
|
+
...option,
|
|
19926
|
+
price: changedLines.find((x) => x.entryLineGuid == option.entryLineGuid)?.price ?? option.price
|
|
19927
|
+
}))
|
|
19928
|
+
}));
|
|
19929
|
+
};
|
|
19930
|
+
// PAX
|
|
19931
|
+
const updateOptionPax = (pax, changedLines) => {
|
|
19932
|
+
return pax.map((p) => ({
|
|
19933
|
+
...p,
|
|
19934
|
+
groups: updatePaxGroups(p.groups, changedLines)
|
|
19935
|
+
}));
|
|
19936
|
+
};
|
|
19937
|
+
const updatePaxGroups = (groups, changedLines) => {
|
|
19938
|
+
return groups.map((g) => ({
|
|
19939
|
+
...g,
|
|
19940
|
+
options: g.options.map((o) => ({
|
|
19941
|
+
...o,
|
|
19942
|
+
groups: updatePaxGroups(o.groups, changedLines),
|
|
19943
|
+
line: {
|
|
19944
|
+
...o.line,
|
|
19945
|
+
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
19946
|
+
},
|
|
19947
|
+
alternatives: o.alternatives.map((a) => ({
|
|
19948
|
+
...a,
|
|
19949
|
+
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
19950
|
+
}))
|
|
19951
|
+
}))
|
|
19952
|
+
}));
|
|
19953
|
+
};
|
|
19954
|
+
// UNITS
|
|
19955
|
+
const updateOptionUnits = (units, changedLines) => {
|
|
19956
|
+
return units.map((u) => ({
|
|
19957
|
+
...u,
|
|
19958
|
+
groups: updateUnitGroups(u.groups, changedLines)
|
|
19959
|
+
}));
|
|
19960
|
+
};
|
|
19961
|
+
const updateUnitGroups = (groups, changedLines) => {
|
|
19962
|
+
return groups.map((g) => ({
|
|
19963
|
+
...g,
|
|
19964
|
+
options: g.options.map((o) => ({
|
|
19965
|
+
...o,
|
|
19966
|
+
groups: updateUnitGroups(o.groups, changedLines),
|
|
19967
|
+
pax: updateOptionPax(o.pax, changedLines),
|
|
19968
|
+
line: {
|
|
19969
|
+
...o.line,
|
|
19970
|
+
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
19971
|
+
},
|
|
19972
|
+
alternatives: o.alternatives.map((a) => ({
|
|
19973
|
+
...a,
|
|
19974
|
+
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
19975
|
+
}))
|
|
19976
|
+
}))
|
|
19977
|
+
}));
|
|
19978
|
+
};
|
|
19979
|
+
// BOOKING
|
|
19980
|
+
const updateBookingGroups = (groups, changedLines) => {
|
|
19981
|
+
return groups.map((g) => ({
|
|
19982
|
+
...g,
|
|
19983
|
+
options: g.options.map((o) => ({
|
|
19984
|
+
...o,
|
|
19985
|
+
groups: updateBookingGroups(o.groups, changedLines),
|
|
19986
|
+
units: updateOptionUnits(o.units, changedLines),
|
|
19987
|
+
pax: updateOptionPax(o.pax, changedLines),
|
|
19988
|
+
line: {
|
|
19989
|
+
...o.line,
|
|
19990
|
+
price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
|
|
19991
|
+
},
|
|
19992
|
+
alternatives: o.alternatives.map((a) => ({
|
|
19993
|
+
...a,
|
|
19994
|
+
price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
|
|
19995
|
+
}))
|
|
19996
|
+
}))
|
|
19997
|
+
}));
|
|
19998
|
+
};
|
|
19999
|
+
|
|
20000
|
+
const fetchPriceDetails = toolkit.createAsyncThunk('priceDetails/fetchPriceDetails', async (_, { dispatch, getState, signal }) => {
|
|
20001
|
+
const state = getState();
|
|
20002
|
+
const languageCode = selectLanguageCode(state);
|
|
20003
|
+
const request = selectBookingPackageBookRequest(state);
|
|
20004
|
+
if (!request) {
|
|
20005
|
+
throw Error('Product not available.');
|
|
20006
|
+
}
|
|
20007
|
+
dispatch(setFetchingPriceDetails(true));
|
|
20008
|
+
dispatch(resetPriceDetails());
|
|
20009
|
+
const priceDetails = await priceDetailsApi.fetchPriceDetails(state.apiSettings, request, signal, languageCode);
|
|
20010
|
+
dispatch(setFetchingPriceDetails(false));
|
|
20011
|
+
const packageDetails = selectPackageDetails(state);
|
|
20012
|
+
if (packageDetails) {
|
|
20013
|
+
const updatedPackageDetails = updatePackageDetails(packageDetails, priceDetails.changedLines);
|
|
20014
|
+
dispatch(setPackage(updatedPackageDetails));
|
|
20015
|
+
}
|
|
20016
|
+
return priceDetails;
|
|
20017
|
+
});
|
|
20018
|
+
const priceDetailsSlice = toolkit.createSlice({
|
|
20019
|
+
name: 'priceDetails',
|
|
20020
|
+
initialState: {
|
|
20021
|
+
priceDetails: [],
|
|
20022
|
+
notifications: [],
|
|
20023
|
+
isBusy: false
|
|
20024
|
+
},
|
|
20025
|
+
reducers: {
|
|
20026
|
+
setFetchingPriceDetails(state, action) {
|
|
20027
|
+
state.isBusy = action.payload;
|
|
20028
|
+
},
|
|
20029
|
+
setNotifications(state, action) {
|
|
20030
|
+
state.notifications = action.payload;
|
|
20031
|
+
},
|
|
20032
|
+
resetPriceDetails(state, _) {
|
|
20033
|
+
state.priceDetails = [];
|
|
20034
|
+
}
|
|
20035
|
+
},
|
|
20036
|
+
extraReducers: (builder) => {
|
|
20037
|
+
builder.addCase(fetchPriceDetails.fulfilled, (state, action) => {
|
|
20038
|
+
if (action.payload) {
|
|
20039
|
+
state.deposit = action.payload.deposit;
|
|
20040
|
+
state.commission = action.payload.commission;
|
|
20041
|
+
state.priceDetails = action.payload.details;
|
|
20042
|
+
state.notifications = action.payload.notifications;
|
|
20043
|
+
}
|
|
20044
|
+
});
|
|
20045
|
+
builder.addCase(fetchPriceDetails.rejected, (state) => {
|
|
20046
|
+
state.isBusy = false;
|
|
20047
|
+
});
|
|
20048
|
+
}
|
|
20049
|
+
});
|
|
20050
|
+
const { setFetchingPriceDetails } = priceDetailsSlice.actions;
|
|
20051
|
+
const { resetPriceDetails, setNotifications } = priceDetailsSlice.actions;
|
|
20052
|
+
const selectNotifications = (state) => state.priceDetails.notifications;
|
|
20053
|
+
var priceDetailsReducer = priceDetailsSlice.reducer;
|
|
20054
|
+
|
|
20055
|
+
const selectHasMounted = (state) => state.booking.hasMounted;
|
|
20056
|
+
const selectGeneratePaymentUrl = (state) => state.booking.generatePaymentUrl;
|
|
20057
|
+
const selectSkipPaymentWithAgent = (state) => state.booking.skipPaymentWithAgent;
|
|
20058
|
+
const selectIsFetchingProductOptions = (state) => state.booking.isBusy;
|
|
20059
|
+
const selectDepartureFlight = (state) => state.booking.package?.outwardFlights?.find((x) => x.isSelected);
|
|
20060
|
+
const selectReturnFlight = (state) => state.booking.package?.returnFlights?.find((x) => x.isSelected);
|
|
20061
|
+
const selectPackageRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.rooms;
|
|
20062
|
+
const selectIncludedServiceTypes = (state) => selectActiveOption(state)?.includedServiceTypes;
|
|
20063
|
+
const selectAvailabilities = (state) => state.booking.package?.options.find((x) => x.isSelected)?.availabilities;
|
|
20064
|
+
const selectPackageTags = (state) => state.booking.package?.tags;
|
|
20065
|
+
const selectIsOnRequest = (state) => state.booking.package?.options.find((x) => x.isSelected)?.isOnRequest;
|
|
20066
|
+
const selectPackageOptionUnits = (state) => state.booking.package?.options.find((x) => x.isSelected)?.optionUnits;
|
|
20067
|
+
const selectPackageOptionPax = (state) => state.booking.package?.options.find((x) => x.isSelected)?.optionPax;
|
|
20068
|
+
const selectPackageGroups = (state) => state.booking.package?.options.find((x) => x.isSelected)?.groups;
|
|
20069
|
+
const selectPackageDetails = (state) => state.booking.package;
|
|
20070
|
+
const selectPaxFields = (state) => state.booking.package?.paxFields ?? [];
|
|
20071
|
+
const selectPackageFlights = (state) => ({
|
|
20072
|
+
outward: state.booking.package?.outwardFlights,
|
|
20073
|
+
return: state.booking.package?.returnFlights
|
|
20074
|
+
});
|
|
20075
|
+
const selectFlightMetaData = (state) => state.booking.package?.flightInfo.metaData;
|
|
20076
|
+
const selectActiveOption = (state) => state.booking.package?.options.find((x) => x.isSelected);
|
|
20077
|
+
const selectPackageAirlineGroups = toolkit.createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airlineGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
|
|
20078
|
+
const selectPackageAirportGroups = toolkit.createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airportGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
|
|
20079
|
+
const selectRoomOptionDepartureFlightsMetaData = toolkit.createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
|
|
20080
|
+
const roomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected).shift());
|
|
20081
|
+
return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
|
|
20082
|
+
});
|
|
20083
|
+
const selectRoomOptionReturnFlightsMetaData = toolkit.createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
|
|
20084
|
+
const selectedRoomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected));
|
|
20085
|
+
// check if there are return flights selected
|
|
20086
|
+
if (selectedRoomOptions?.some((ro) => ro.length > 1)) {
|
|
20087
|
+
const roomOptions = ativeOption?.rooms.map((r) => r.options
|
|
20088
|
+
.filter((o) => o.isSelected)
|
|
20089
|
+
.reverse()
|
|
20090
|
+
.shift());
|
|
20091
|
+
return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
|
|
20092
|
+
}
|
|
20093
|
+
return undefined;
|
|
20094
|
+
});
|
|
20095
|
+
const selectApiSettings = (state) => state.apiSettings;
|
|
20096
|
+
const selectIsUnavailable = (state) => state.booking.isUnavailable;
|
|
20097
|
+
const selectRequestRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.requestRooms;
|
|
20098
|
+
const selectOfficeId = (state) => state.booking.officeId;
|
|
20099
|
+
const selectLanguageCode = (state) => state.booking.languageCode;
|
|
20100
|
+
const selectCurrencyCode = (state) => state.booking.package?.currencyCode ?? 'EUR';
|
|
20101
|
+
const selectLanguage = (state) => state.booking.languageCode;
|
|
20102
|
+
const selectAllDynamicTranslations = (state) => state.booking.translations;
|
|
20103
|
+
const selectDynamicTranslations = toolkit.createSelector([selectAllDynamicTranslations, selectLanguage], (allDynamicTranslations, language) => {
|
|
20104
|
+
return allDynamicTranslations?.find((x) => x.language == language)?.value ?? {};
|
|
20105
|
+
});
|
|
20106
|
+
// Host override files are hand-maintained, and a null only ever blanks a key the component
|
|
20107
|
+
// then reads, so treat it like a missing key (lodash merge already skips undefined).
|
|
20108
|
+
const withoutNulls = (value) => lodash.isPlainObject(value)
|
|
20109
|
+
? lodash.mapValues(lodash.pickBy(value, (x) => x !== null), withoutNulls)
|
|
20110
|
+
: value;
|
|
20111
|
+
// getTranslations deep-merges the overrides over a clone of the built-in translations, so a
|
|
20112
|
+
// host override of a nested group (TRAVELERS_FORM.VALIDATION, TRAVELERS_FORM.COUNTRIES)
|
|
20113
|
+
// only replaces the keys it actually contains. Merging per section one level deep dropped
|
|
20114
|
+
// every other built-in key of such a group, which made those keys resolve to undefined and
|
|
20115
|
+
// crash format() in the consuming component.
|
|
20116
|
+
const selectTranslations = toolkit.createSelector([selectLanguage, selectDynamicTranslations], (language, dynamicTranslations) => getTranslations(language, lodash.isEmpty(dynamicTranslations) ? undefined : withoutNulls(dynamicTranslations)));
|
|
20117
|
+
const selectBookingOptions = (state) => state.booking.bookingOptions;
|
|
20118
|
+
const selectBookingType = (state) => state.booking.bookingType;
|
|
20119
|
+
const selectTagIds = (state) => state.booking.tagIds;
|
|
20120
|
+
const selectAgentAdressId = (state) => state.booking.agentAdressId;
|
|
20121
|
+
const selectProductAttributes = (state) => state.booking.productAttributes;
|
|
20122
|
+
const selectBookingAttributes = (state) => state.booking.bookingAttributes;
|
|
20123
|
+
const selectBookingNumber = (state) => state.booking.bookingNumber;
|
|
20124
|
+
const selectIsOption = (state) => state.booking.isOption;
|
|
20125
|
+
const selectBookingRooms = (state) => state.booking.bookingAttributes?.rooms;
|
|
20126
|
+
const selectBookingRemarks = (state) => state.booking.remarks;
|
|
20127
|
+
const selectVoucherCodes = (state) => state.booking.voucherCodes;
|
|
20128
|
+
const selectCalculateDeposit = (state) => state.booking.calculateDeposit;
|
|
20129
|
+
const selectShowCommission = (state) => state.booking.showCommission;
|
|
20130
|
+
const selectIsRetry = (state) => state.booking.isRetry;
|
|
20131
|
+
const selectStartDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.fromDate;
|
|
20132
|
+
const selectEndDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.toDate;
|
|
20133
|
+
const selectAgents = (state) => state.booking.agents;
|
|
20134
|
+
const selectCountries = (state) => state.booking.countries;
|
|
20135
|
+
const selectProductCode = (state) => state.booking.productAttributes?.productCode;
|
|
20136
|
+
const selectAccommodationCodes = (state) => {
|
|
20137
|
+
const accommodationCodes = [];
|
|
20138
|
+
state.booking.package?.options.forEach((o) => {
|
|
20139
|
+
o.rooms.forEach((r) => r.options.forEach((ro) => {
|
|
20140
|
+
if (!accommodationCodes.some((y) => y === ro.accommodationCode)) {
|
|
20141
|
+
accommodationCodes.push(ro.accommodationCode);
|
|
20142
|
+
}
|
|
20143
|
+
}));
|
|
20144
|
+
});
|
|
20145
|
+
return accommodationCodes;
|
|
20146
|
+
};
|
|
20147
|
+
const selectAccommodationViews = (state) => state.booking.accommodationViews;
|
|
20148
|
+
const selectMappingInfo = (state) => state.booking.package?.options.find((x) => x.isSelected)?.mappingInfo;
|
|
20149
|
+
const selectBookingQuery = (state) => {
|
|
20150
|
+
const bookingAttributes = state.booking.bookingAttributes;
|
|
20151
|
+
if (!bookingAttributes) {
|
|
20152
|
+
return undefined;
|
|
20153
|
+
}
|
|
20154
|
+
const params = {};
|
|
20155
|
+
Object.entries(bookingAttributes).forEach(([key, value]) => {
|
|
20156
|
+
if (key === 'startDate' || key === 'endDate') {
|
|
20157
|
+
value = dateFns.format(dateFns.parseISO(value), 'yyyy-MM-dd');
|
|
20158
|
+
}
|
|
20159
|
+
if (key === 'rooms') {
|
|
20160
|
+
value = JsonURL__default["default"].stringify(value.map((room) => lodash.omit(room, ['children'])), {
|
|
20161
|
+
AQF: true
|
|
20162
|
+
});
|
|
20163
|
+
}
|
|
20164
|
+
if (key === 'allotmentIds' && !value.length) {
|
|
20165
|
+
value = undefined;
|
|
20166
|
+
}
|
|
20167
|
+
if (key === 'flight' && value) {
|
|
20168
|
+
var flightInfo = value;
|
|
20169
|
+
value = JsonURL__default["default"].stringify(flightInfo, { AQF: true });
|
|
20170
|
+
}
|
|
20171
|
+
if (value) {
|
|
20172
|
+
params[key] = value;
|
|
20173
|
+
}
|
|
20174
|
+
});
|
|
20175
|
+
return params;
|
|
20176
|
+
};
|
|
20177
|
+
const selectBookingQueryString = toolkit.createSelector(selectBookingQuery, (params) => {
|
|
20178
|
+
if (!params) {
|
|
20179
|
+
return undefined;
|
|
20180
|
+
}
|
|
20181
|
+
return Object.keys(params)
|
|
20182
|
+
.filter((key) => typeof params[key] !== 'undefined')
|
|
20183
|
+
.map((key) => `${key}=${params[key]}`)
|
|
20184
|
+
.join('&');
|
|
20185
|
+
});
|
|
20186
|
+
toolkit.createSelector(selectTravelersFormValues, (formValues) => formValues?.mainBookerId);
|
|
20187
|
+
const selectBookingPackagePax = toolkit.createSelector(selectTravelersFormValues, (formValues) => {
|
|
20188
|
+
var pax = [];
|
|
20189
|
+
formValues?.rooms.forEach((r) => r.adults.forEach((x) => {
|
|
20190
|
+
const adultPax = buildPax(x, formValues?.mainBookerId);
|
|
20191
|
+
if (adultPax.isMainBooker) {
|
|
20192
|
+
adultPax.mobilePhone = formValues?.phone;
|
|
20193
|
+
adultPax.email = formValues?.email;
|
|
20194
|
+
}
|
|
20195
|
+
pax.push(adultPax);
|
|
20196
|
+
}));
|
|
20197
|
+
formValues?.rooms.forEach((r) => r.children.forEach((x) => {
|
|
20198
|
+
pax.push(buildPax(x));
|
|
20199
|
+
}));
|
|
20200
|
+
return pax;
|
|
20201
|
+
});
|
|
20202
|
+
const selectBookingAddress = toolkit.createSelector(selectTravelersFormValues, selectBookingPackagePax, selectBookingType, (formValues, pax, bookingType) => {
|
|
20203
|
+
const mainBooker = pax.find((x) => x.isMainBooker);
|
|
20204
|
+
if (!mainBooker || bookingType == 'b2b')
|
|
20205
|
+
return undefined;
|
|
20206
|
+
// The backend treats the main booker's per-pax address as authoritative, so keep the
|
|
20207
|
+
// booking-level address in sync with it rather than sending two independent values.
|
|
20208
|
+
const mainBookerAddress = mainBooker.address;
|
|
20209
|
+
return {
|
|
20210
|
+
name: `${mainBooker.firstName} ${mainBooker.lastName}`,
|
|
20211
|
+
street: mainBookerAddress?.street || formValues?.street,
|
|
20212
|
+
number: mainBookerAddress?.number || formValues?.houseNumber,
|
|
20213
|
+
box: formValues?.box,
|
|
20214
|
+
postalCode: mainBookerAddress?.postalCode || formValues?.zipCode,
|
|
20215
|
+
location: mainBookerAddress?.location || formValues?.place,
|
|
20216
|
+
country: mainBookerAddress?.country || formValues?.country,
|
|
20217
|
+
mobilePhone: formValues?.phone,
|
|
20218
|
+
email: formValues?.email
|
|
20219
|
+
};
|
|
20220
|
+
});
|
|
20221
|
+
const selectBookingPackageRequest = toolkit.createSelector(selectOfficeId, selectAgentId, selectAgentAdressId, (officeId, agentId, agentAdressId) => {
|
|
20222
|
+
const agencyId = (agentId ?? agentAdressId ?? 0) > 0 ? agentId ?? agentAdressId : null;
|
|
20223
|
+
return {
|
|
20224
|
+
officeId: officeId,
|
|
20225
|
+
agentId: agencyId,
|
|
20226
|
+
payload: null
|
|
19089
20227
|
};
|
|
19090
20228
|
});
|
|
19091
20229
|
const selectBookingPackageBookRequest = toolkit.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) => {
|
|
@@ -19151,22 +20289,11 @@ const selectBookingPackageBookRequest = toolkit.createSelector(selectBookingPack
|
|
|
19151
20289
|
return bookingPackageRequest;
|
|
19152
20290
|
});
|
|
19153
20291
|
const selectTravelersFirstStep = (state) => state.booking.travelersFirstStep;
|
|
19154
|
-
const buildPax = (traveler, mainBookerId) => {
|
|
19155
|
-
|
|
19156
|
-
|
|
19157
|
-
|
|
19158
|
-
|
|
19159
|
-
lastName: traveler.lastName,
|
|
19160
|
-
dateOfBirth: traveler.birthDate,
|
|
19161
|
-
age: traveler.birthDate ? null : traveler.age,
|
|
19162
|
-
isMainBooker: traveler.id == mainBookerId,
|
|
19163
|
-
weight: traveler.weight ?? null,
|
|
19164
|
-
weightType: traveler.weightType ?? build.WeightType.kilograms,
|
|
19165
|
-
height: traveler.height ?? null,
|
|
19166
|
-
heightType: traveler.heightType ?? build.HeightType.centimeters,
|
|
19167
|
-
customFields: traveler.customFields ?? []
|
|
19168
|
-
};
|
|
19169
|
-
};
|
|
20292
|
+
const buildPax = (traveler, mainBookerId) => applyTravelerToPax({
|
|
20293
|
+
id: traveler.id,
|
|
20294
|
+
gender: parseGender(traveler.gender),
|
|
20295
|
+
age: traveler.birthDate ? null : traveler.age
|
|
20296
|
+
}, traveler, mainBookerId);
|
|
19170
20297
|
const parseGender = (gender) => {
|
|
19171
20298
|
switch (gender) {
|
|
19172
20299
|
case 'm':
|
|
@@ -19674,9 +20801,7 @@ const SettingsContext = React__default["default"].createContext({
|
|
|
19674
20801
|
travellers: {
|
|
19675
20802
|
pathSuffix: '/reizigers',
|
|
19676
20803
|
travelersFirstStep: false,
|
|
19677
|
-
showAllCountries: false
|
|
19678
|
-
showWeightField: false,
|
|
19679
|
-
showHeightField: false
|
|
20804
|
+
showAllCountries: false
|
|
19680
20805
|
},
|
|
19681
20806
|
summary: {
|
|
19682
20807
|
pathSuffix: '/samenvatting',
|
|
@@ -22753,1072 +23878,440 @@ const SummaryPerPaxOptionGroup = ({ group }) => {
|
|
|
22753
23878
|
opt.line.accommodationName,
|
|
22754
23879
|
!lodash.isNil(opt.line?.regimeName) && ', ',
|
|
22755
23880
|
opt.line.regimeName)),
|
|
22756
|
-
getDateText(opt.line.startDate),
|
|
22757
|
-
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
22758
|
-
React__default["default"].createElement("ul", { className: "list" }, !lodash.isEmpty(opt?.groups) &&
|
|
22759
|
-
opt?.groups.map((x) => {
|
|
22760
|
-
if (!x.options.some((y) => y.isSelected))
|
|
22761
|
-
return;
|
|
22762
|
-
return React__default["default"].createElement(SummaryPerPaxOptionGroup, { group: x });
|
|
22763
|
-
})))))));
|
|
22764
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null, group.title ? (React__default["default"].createElement("li", { className: "list__item" },
|
|
22765
|
-
React__default["default"].createElement("h6", null, group.title),
|
|
22766
|
-
React__default["default"].createElement("ul", { className: "list" }, renderOptions()))) : (React__default["default"].createElement(React__default["default"].Fragment, null, renderOptions()))));
|
|
22767
|
-
};
|
|
22768
|
-
|
|
22769
|
-
const SummaryBookingOptionPax = ({ pax }) => {
|
|
22770
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null, pax.groups.map((y, i) => {
|
|
22771
|
-
const paxOptions = y.options.filter((y) => y.isSelected);
|
|
22772
|
-
if (lodash.isEmpty(paxOptions))
|
|
22773
|
-
return;
|
|
22774
|
-
return React__default["default"].createElement(SummaryPerPaxOptionGroup, { key: i, group: y });
|
|
22775
|
-
})));
|
|
22776
|
-
};
|
|
22777
|
-
|
|
22778
|
-
const SummaryPerUnitOptionGroup = ({ group }) => {
|
|
22779
|
-
const groupOptions = group.options.filter((x) => x.isSelected);
|
|
22780
|
-
const renderOptions = () => (React__default["default"].createElement(React__default["default"].Fragment, null, groupOptions.map((opt) => (React__default["default"].createElement("li", { key: opt.line.entryLineGuid, className: "list__item" },
|
|
22781
|
-
opt.line.productName,
|
|
22782
|
-
React__default["default"].createElement("ul", null,
|
|
22783
|
-
React__default["default"].createElement("li", null,
|
|
22784
|
-
opt.line.accommodationName,
|
|
22785
|
-
!lodash.isNil(opt.line?.regimeName) && ', ',
|
|
22786
|
-
opt.line.regimeName)),
|
|
22787
|
-
getDateText(opt.line.startDate),
|
|
22788
|
-
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
22789
|
-
React__default["default"].createElement("ul", null,
|
|
22790
|
-
!lodash.isEmpty(opt?.groups) &&
|
|
22791
|
-
opt?.groups.map((x) => {
|
|
22792
|
-
if (!x.options.some((y) => y.isSelected))
|
|
22793
|
-
return;
|
|
22794
|
-
return React__default["default"].createElement(SummaryPerUnitOptionGroup, { group: x });
|
|
22795
|
-
}),
|
|
22796
|
-
!lodash.isEmpty(opt?.pax) && opt?.pax.map((x) => React__default["default"].createElement(SummaryBookingOptionPax, { pax: x }))))))));
|
|
22797
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null, group.title ? (React__default["default"].createElement("li", { className: "list__item" },
|
|
22798
|
-
React__default["default"].createElement("h6", null, group.title),
|
|
22799
|
-
React__default["default"].createElement("ul", { className: "list" }, renderOptions()))) : (React__default["default"].createElement(React__default["default"].Fragment, null, renderOptions()))));
|
|
22800
|
-
};
|
|
22801
|
-
|
|
22802
|
-
const SummaryBookingOptionUnit = ({ unit }) => {
|
|
22803
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null, unit.groups.map((y) => {
|
|
22804
|
-
const unitOptions = y.options.filter((y) => y.isSelected);
|
|
22805
|
-
if (lodash.isEmpty(unitOptions))
|
|
22806
|
-
return;
|
|
22807
|
-
return React__default["default"].createElement(SummaryPerUnitOptionGroup, { group: y });
|
|
22808
|
-
})));
|
|
22809
|
-
};
|
|
22810
|
-
|
|
22811
|
-
const SummaryFlight = ({ flightMetaData, header }) => {
|
|
22812
|
-
const translations = reactRedux.useSelector(selectTranslations);
|
|
22813
|
-
return (React__default["default"].createElement("li", null,
|
|
22814
|
-
React__default["default"].createElement("h6", null, header),
|
|
22815
|
-
parseFlightLines(flightMetaData)?.map((flightLine) => (React__default["default"].createElement("p", { key: flightLine.departureAirportIata },
|
|
22816
|
-
flightLine.departureAirportDescription,
|
|
22817
|
-
" (",
|
|
22818
|
-
flightLine.departureAirportIata,
|
|
22819
|
-
") > ",
|
|
22820
|
-
flightLine.arrivalAirportDescription,
|
|
22821
|
-
" (",
|
|
22822
|
-
flightLine.arrivalAirportIata,
|
|
22823
|
-
") ",
|
|
22824
|
-
' - ',
|
|
22825
|
-
flightLine.travelClass,
|
|
22826
|
-
" ",
|
|
22827
|
-
' - ',
|
|
22828
|
-
flightLine.airlineCode,
|
|
22829
|
-
flightLine.number,
|
|
22830
|
-
React__default["default"].createElement("br", null),
|
|
22831
|
-
getDateText(flightLine.departureDate),
|
|
22832
|
-
" ",
|
|
22833
|
-
flightLine.departureTime,
|
|
22834
|
-
" > ",
|
|
22835
|
-
getDateText(flightLine.arrivalDate),
|
|
22836
|
-
" ",
|
|
22837
|
-
flightLine.arrivalTime,
|
|
22838
|
-
React__default["default"].createElement("br", null),
|
|
22839
|
-
flightLine.airlineDescription))),
|
|
22840
|
-
flightMetaData.luggageIncluded && React__default["default"].createElement("p", null, translations.SIDEBAR.LUGGAGE_INCLUDED)));
|
|
22841
|
-
};
|
|
22842
|
-
|
|
22843
|
-
const SummaryPerBookingOptionGroup = ({ group }) => {
|
|
22844
|
-
const groupOptions = group.options.filter((x) => x.isSelected);
|
|
22845
|
-
const renderOptions = () => (React__default["default"].createElement(React__default["default"].Fragment, null, groupOptions.map((opt) => (React__default["default"].createElement("li", { key: opt.line.entryLineGuid, className: "list__item" },
|
|
22846
|
-
opt.line.productName,
|
|
22847
|
-
React__default["default"].createElement("ul", null,
|
|
22848
|
-
React__default["default"].createElement("li", null,
|
|
22849
|
-
opt.line.accommodationName,
|
|
22850
|
-
!lodash.isNil(opt.line?.regimeName) && ', ',
|
|
22851
|
-
opt.line.regimeName)),
|
|
22852
|
-
getDateText(opt.line.startDate),
|
|
22853
|
-
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
22854
|
-
React__default["default"].createElement("ul", null,
|
|
22855
|
-
!lodash.isEmpty(opt?.groups) &&
|
|
22856
|
-
opt?.groups.map((x) => {
|
|
22857
|
-
if (!x.options.some((y) => y.isSelected))
|
|
22858
|
-
return;
|
|
22859
|
-
return React__default["default"].createElement(SummaryPerBookingOptionGroup, { group: x });
|
|
22860
|
-
}),
|
|
22861
|
-
!lodash.isEmpty(opt?.units) && opt?.units.map((x) => React__default["default"].createElement(SummaryBookingOptionUnit, { unit: x })),
|
|
22862
|
-
!lodash.isEmpty(opt?.pax) && opt?.pax.map((x) => React__default["default"].createElement(SummaryBookingOptionPax, { pax: x }))))))));
|
|
22863
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null, group.title ? (React__default["default"].createElement("li", { className: "list__item" },
|
|
22864
|
-
React__default["default"].createElement("h6", null, group.title),
|
|
22865
|
-
React__default["default"].createElement("ul", { className: "list" }, renderOptions()))) : (React__default["default"].createElement(React__default["default"].Fragment, null, renderOptions()))));
|
|
22866
|
-
};
|
|
22867
|
-
|
|
22868
|
-
const Summary = () => {
|
|
22869
|
-
const dispatch = useAppDispatch();
|
|
22870
|
-
const settings = React.useContext(SettingsContext);
|
|
22871
|
-
const navigate = settings.skipRouter ? () => { } : reactRouter.useNavigate();
|
|
22872
|
-
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
22873
|
-
const [checkboxes, setCheckboxes] = React.useState(settings.summary?.checkboxes);
|
|
22874
|
-
const [remarks, setRemarks] = React.useState('');
|
|
22875
|
-
const [voucher, setVoucher] = React.useState({});
|
|
22876
|
-
const bookingQueryString = reactRedux.useSelector(selectBookingQueryString);
|
|
22877
|
-
const travelersFirstStep = reactRedux.useSelector(selectTravelersFirstStep);
|
|
22878
|
-
const travelerFormValues = reactRedux.useSelector(selectTravelersFormValues);
|
|
22879
|
-
const packageDetails = reactRedux.useSelector(selectPackageDetails);
|
|
22880
|
-
const activeOption = reactRedux.useSelector(selectActiveOption);
|
|
22881
|
-
const apiSettings = reactRedux.useSelector(selectApiSettings);
|
|
22882
|
-
const languageCode = reactRedux.useSelector(selectLanguageCode);
|
|
22883
|
-
const officeId = reactRedux.useSelector(selectOfficeId);
|
|
22884
|
-
const agentId = reactRedux.useSelector(selectAgentAdressId);
|
|
22885
|
-
const departureFlight = reactRedux.useSelector(selectDepartureFlight);
|
|
22886
|
-
const departureFlightMetaData = departureFlight?.flightMetaData ?? reactRedux.useSelector(selectRoomOptionDepartureFlightsMetaData)?.[0];
|
|
22887
|
-
const returnFlight = reactRedux.useSelector(selectReturnFlight);
|
|
22888
|
-
const returnFlightMetaData = returnFlight?.flightMetaData ?? reactRedux.useSelector(selectRoomOptionReturnFlightsMetaData)?.[0];
|
|
22889
|
-
if (!travelerFormValues) {
|
|
22890
|
-
if (settings.skipRouter) {
|
|
22891
|
-
dispatch(setCurrentStep$1(TRAVELERS_FORM_STEP));
|
|
22892
|
-
}
|
|
22893
|
-
else {
|
|
22894
|
-
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}?${bookingQueryString}`);
|
|
22895
|
-
}
|
|
22896
|
-
}
|
|
22897
|
-
const rooms = reactRedux.useSelector(selectRooms);
|
|
22898
|
-
const userValidated = reactRedux.useSelector(selectUserValidated);
|
|
22899
|
-
const notifications = reactRedux.useSelector(selectNotifications);
|
|
22900
|
-
const bookRequest = reactRedux.useSelector(selectBookingPackageBookRequest);
|
|
22901
|
-
React.useEffect(() => {
|
|
22902
|
-
// Every checkbox should be checked, or no checkboxes
|
|
22903
|
-
const checkboxesValidated = !lodash.isNil(checkboxes) ? checkboxes.every((checkbox) => checkbox.isSelected) : true;
|
|
22904
|
-
const notificationsValidated = !lodash.isNil(notifications) ? notifications.filter((x) => x.hasToBeConfirmed).every((checkbox) => checkbox.isConfirmed) : true;
|
|
22905
|
-
dispatch(setUserValidated(checkboxesValidated && notificationsValidated));
|
|
22906
|
-
}, [checkboxes, notifications]);
|
|
22907
|
-
const handleSubmit = async (e) => {
|
|
22908
|
-
e.preventDefault();
|
|
22909
|
-
const submitter = e.nativeEvent.submitter?.name;
|
|
22910
|
-
setIsSubmitting(true);
|
|
22911
|
-
if (typeof window !== 'undefined') {
|
|
22912
|
-
window.scrollTo(0, 0);
|
|
22913
|
-
}
|
|
22914
|
-
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
22915
|
-
if (!bookRequest || !tideClientConfig) {
|
|
22916
|
-
return;
|
|
22917
|
-
}
|
|
22918
|
-
if (bookRequest.payload.returnPaymentUrl) {
|
|
22919
|
-
if (typeof window !== 'undefined') {
|
|
22920
|
-
window.scrollTo(0, 0);
|
|
22921
|
-
if (settings.paymentRedirectUrl) {
|
|
22922
|
-
bookRequest.payload.redirectUrl = settings.paymentRedirectUrl;
|
|
22923
|
-
}
|
|
22924
|
-
else {
|
|
22925
|
-
const location = window.location;
|
|
22926
|
-
bookRequest.payload.redirectUrl = `${location.protocol}//${location.host}${settings.basePath ?? location.pathname}?${bookingQueryString}`;
|
|
22927
|
-
}
|
|
22928
|
-
}
|
|
22929
|
-
}
|
|
22930
|
-
try {
|
|
22931
|
-
if (submitter === 'option') {
|
|
22932
|
-
bookRequest.payload.status = build.EntryStatus.option;
|
|
22933
|
-
bookRequest.payload.customStatusId = settings.customOptionStatus;
|
|
22934
|
-
dispatch(setIsOption(true));
|
|
22935
|
-
}
|
|
22936
|
-
const bookingResponse = await build.book(tideClientConfig, bookRequest, undefined, languageCode);
|
|
22937
|
-
// Booking successfull
|
|
22938
|
-
dispatch(setBookingNumber$1(bookingResponse.number));
|
|
22939
|
-
if (bookingResponse.paymentUrl) {
|
|
22940
|
-
const event = new CustomEvent('tide-booking-payment-url', {
|
|
22941
|
-
detail: {
|
|
22942
|
-
paymentUrl: bookingResponse.paymentUrl,
|
|
22943
|
-
bookingNumber: bookingResponse.number
|
|
22944
|
-
},
|
|
22945
|
-
cancelable: true,
|
|
22946
|
-
bubbles: true
|
|
22947
|
-
});
|
|
22948
|
-
const target = typeof document !== 'undefined' ? document.getElementById('tide-booking') ?? window : window;
|
|
22949
|
-
const shouldAutoRedirect = target.dispatchEvent(event);
|
|
22950
|
-
if (shouldAutoRedirect) {
|
|
22951
|
-
window.location.href = bookingResponse.paymentUrl;
|
|
22952
|
-
}
|
|
22953
|
-
}
|
|
22954
|
-
else {
|
|
22955
|
-
if (settings.skipRouter) {
|
|
22956
|
-
dispatch(setCurrentStep$1(CONFIRMATION_STEP));
|
|
22957
|
-
}
|
|
22958
|
-
else {
|
|
22959
|
-
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.confirmation.pathSuffix}?${bookingQueryString}`);
|
|
22960
|
-
}
|
|
22961
|
-
}
|
|
22962
|
-
}
|
|
22963
|
-
catch (error) {
|
|
22964
|
-
if (settings.skipRouter) {
|
|
22965
|
-
dispatch(setCurrentStep$1(ERROR_STEP));
|
|
22966
|
-
}
|
|
22967
|
-
else {
|
|
22968
|
-
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.error.pathSuffix}?${bookingQueryString}`);
|
|
22969
|
-
}
|
|
22970
|
-
}
|
|
22971
|
-
finally {
|
|
22972
|
-
setIsSubmitting(false);
|
|
22973
|
-
}
|
|
22974
|
-
};
|
|
22975
|
-
const handleNotificationChange = (id, checked) => {
|
|
22976
|
-
const updatedNotifications = notifications.map((notification) => (notification.id === id ? { ...notification, isConfirmed: checked } : notification));
|
|
22977
|
-
dispatch(setNotifications(updatedNotifications));
|
|
22978
|
-
};
|
|
22979
|
-
const handleCheckboxChange = (id, checked) => {
|
|
22980
|
-
if (lodash.isNil(checkboxes)) {
|
|
22981
|
-
return;
|
|
22982
|
-
}
|
|
22983
|
-
const newCheckboxes = [...checkboxes];
|
|
22984
|
-
const index = lodash.findIndex(checkboxes, (checkbox) => checkbox.id === id);
|
|
22985
|
-
newCheckboxes[index].isSelected = !newCheckboxes[index].isSelected;
|
|
22986
|
-
setCheckboxes(newCheckboxes);
|
|
22987
|
-
};
|
|
22988
|
-
const handleRemarksChange = (text) => {
|
|
22989
|
-
dispatch(setBookingRemarks(text));
|
|
22990
|
-
setRemarks(text);
|
|
22991
|
-
};
|
|
22992
|
-
const handleValidateVoucher = async () => {
|
|
22993
|
-
if (!voucher?.code)
|
|
22994
|
-
return;
|
|
22995
|
-
const request = {
|
|
22996
|
-
officeId: officeId,
|
|
22997
|
-
agentId: agentId,
|
|
22998
|
-
payload: {
|
|
22999
|
-
code: voucher.code,
|
|
23000
|
-
otherCodes: bookRequest?.payload.voucherCodes ?? []
|
|
23001
|
-
}
|
|
23002
|
-
};
|
|
23003
|
-
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
23004
|
-
if (!tideClientConfig)
|
|
23005
|
-
return;
|
|
23006
|
-
const result = await build.validateVoucher(tideClientConfig, request);
|
|
23007
|
-
if (result) {
|
|
23008
|
-
setVoucher({
|
|
23009
|
-
...voucher,
|
|
23010
|
-
isValidated: true,
|
|
23011
|
-
isValid: result.isValid
|
|
23012
|
-
});
|
|
23013
|
-
}
|
|
23014
|
-
};
|
|
23015
|
-
const handleAddVoucher = (event) => {
|
|
23016
|
-
if (!voucher.isValid)
|
|
23017
|
-
return;
|
|
23018
|
-
dispatch(setVoucherCodes([...(bookRequest?.payload.voucherCodes ?? []), voucher.code ?? ''].filter((x) => x !== '')));
|
|
23019
|
-
dispatch(fetchPriceDetails());
|
|
23020
|
-
setVoucher({});
|
|
23021
|
-
};
|
|
23022
|
-
const handleRemoveVoucher = (code) => {
|
|
23023
|
-
dispatch(setVoucherCodes(bookRequest?.payload.voucherCodes?.filter((x) => x !== code) ?? []));
|
|
23024
|
-
dispatch(fetchPriceDetails());
|
|
23025
|
-
};
|
|
23026
|
-
const goPrevious = () => {
|
|
23027
|
-
dispatch(setCurrentStep$1(travelersFirstStep ? OPTIONS_FORM_STEP : TRAVELERS_FORM_STEP));
|
|
23028
|
-
};
|
|
23029
|
-
const translations = reactRedux.useSelector(selectTranslations);
|
|
23030
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23031
|
-
isSubmitting && (settings.loaderComponent || React__default["default"].createElement(Loader, null)),
|
|
23032
|
-
!isSubmitting && (React__default["default"].createElement("form", { className: "form", name: "booking--summary", id: "booking--summary", onSubmit: handleSubmit },
|
|
23033
|
-
React__default["default"].createElement("div", { className: "form__booking--summary" },
|
|
23034
|
-
React__default["default"].createElement("div", { className: "form__region" },
|
|
23035
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23036
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23037
|
-
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23038
|
-
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.PERSONAL_DETAILS)))),
|
|
23039
|
-
rooms.map((r, rIndex) => (React__default["default"].createElement("div", { className: "form__row", key: rIndex },
|
|
23040
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23041
|
-
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23042
|
-
React__default["default"].createElement("h5", { className: "form__region-heading" }, rooms.length > 1 ? `${translations.SHARED.ROOM} ${rIndex + 1}` : translations.ROOM_OPTIONS_FORM.TRAVELER_GROUP),
|
|
23043
|
-
React__default["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}: ${lodash.compact([
|
|
23044
|
-
r.adults.length,
|
|
23045
|
-
r.adults.length === 1 && ` ${translations.SUMMARY.ADULT}`,
|
|
23046
|
-
r.adults.length > 1 && ` ${translations.SUMMARY.ADULTS}`,
|
|
23047
|
-
r.adults && r.adults.length && r.children && r.children.length && ', ',
|
|
23048
|
-
r.children.length,
|
|
23049
|
-
r.children.length === 1 && ` ${translations.SUMMARY.CHILD}`,
|
|
23050
|
-
r.children.length > 1 && ` ${translations.SUMMARY.CHILDREN}`
|
|
23051
|
-
]).join('')}`))),
|
|
23052
|
-
[...r.adults, ...r.children].map((traveler) => {
|
|
23053
|
-
const isMainBooker = traveler.id === travelerFormValues?.mainBookerId;
|
|
23054
|
-
return (React__default["default"].createElement("div", { className: "form__group form__group--sm-50", key: traveler.id },
|
|
23055
|
-
React__default["default"].createElement("ul", { className: "list list--plain" },
|
|
23056
|
-
React__default["default"].createElement("li", { className: "list__item" },
|
|
23057
|
-
React__default["default"].createElement("strong", null,
|
|
23058
|
-
traveler.firstName,
|
|
23059
|
-
" ",
|
|
23060
|
-
traveler.lastName),
|
|
23061
|
-
' ',
|
|
23062
|
-
isMainBooker && React__default["default"].createElement("em", null,
|
|
23063
|
-
"(",
|
|
23064
|
-
translations.SUMMARY.MAIN_BOOKER,
|
|
23065
|
-
")")),
|
|
23066
|
-
React__default["default"].createElement("li", { className: "list__item" }, traveler.birthDate.split('-').reverse().join('/')),
|
|
23067
|
-
isMainBooker && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23068
|
-
travelerFormValues?.street && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23069
|
-
React__default["default"].createElement("li", { className: "list__item" }, `${travelerFormValues?.street} ${lodash.compact([
|
|
23070
|
-
travelerFormValues?.houseNumber,
|
|
23071
|
-
travelerFormValues?.box
|
|
23072
|
-
]).join(' ')}, ${travelerFormValues?.zipCode} ${travelerFormValues?.place}`))),
|
|
23073
|
-
travelerFormValues?.phone && React__default["default"].createElement("li", { className: "list__item" }, travelerFormValues?.phone),
|
|
23074
|
-
travelerFormValues?.email && React__default["default"].createElement("li", { className: "list__item" }, travelerFormValues?.email))))));
|
|
23075
|
-
}))))),
|
|
23076
|
-
React__default["default"].createElement("div", { className: "form__region" },
|
|
23077
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23078
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23079
|
-
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23080
|
-
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.OPTIONS)))),
|
|
23081
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23082
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23083
|
-
React__default["default"].createElement("ul", { className: "list list--booking-summary" }, activeOption?.serviceType == build.ServiceType.flight ? (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23084
|
-
departureFlightMetaData && React__default["default"].createElement(SummaryFlight, { flightMetaData: departureFlightMetaData, header: translations.SIDEBAR.DEPARTURE_FLIGHT }),
|
|
23085
|
-
returnFlightMetaData && React__default["default"].createElement(SummaryFlight, { flightMetaData: returnFlightMetaData, header: translations.SIDEBAR.ARRIVAL_FLIGHT }))) : (React__default["default"].createElement(React__default["default"].Fragment, null, activeOption?.rooms
|
|
23086
|
-
.flatMap((r) => r.options)
|
|
23087
|
-
.filter((x) => x.isSelected)
|
|
23088
|
-
.map((roomOption, roomOptionIndex) => (React__default["default"].createElement(React__default["default"].Fragment, { key: roomOptionIndex },
|
|
23089
|
-
React__default["default"].createElement("li", null,
|
|
23090
|
-
React__default["default"].createElement("h6", null, roomOption?.productName),
|
|
23091
|
-
React__default["default"].createElement("ul", null,
|
|
23092
|
-
React__default["default"].createElement("li", { className: "list__item" },
|
|
23093
|
-
roomOption?.accommodationName,
|
|
23094
|
-
!lodash.isNil(roomOption?.regimeName) && ', ',
|
|
23095
|
-
roomOption?.regimeName)),
|
|
23096
|
-
React__default["default"].createElement("p", null,
|
|
23097
|
-
"(",
|
|
23098
|
-
roomOption?.from === roomOption?.to ? (getDateText(roomOption?.from)) : (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23099
|
-
getDateText(roomOption?.from),
|
|
23100
|
-
" > ",
|
|
23101
|
-
getDateText(roomOption?.to))),
|
|
23102
|
-
")")),
|
|
23103
|
-
!lodash.isEmpty(activeOption?.groups) &&
|
|
23104
|
-
activeOption?.groups.map((x, i) => {
|
|
23105
|
-
if (!x.options.some((y) => y.isSelected))
|
|
23106
|
-
return;
|
|
23107
|
-
return React__default["default"].createElement(SummaryPerBookingOptionGroup, { key: i, group: x });
|
|
23108
|
-
}),
|
|
23109
|
-
!lodash.isEmpty(activeOption?.optionUnits) && activeOption?.optionUnits.map((x, i) => React__default["default"].createElement(SummaryBookingOptionUnit, { key: i, unit: x })),
|
|
23110
|
-
!lodash.isEmpty(activeOption?.optionPax) && activeOption?.optionPax.map((x, i) => React__default["default"].createElement(SummaryBookingOptionPax, { key: i, pax: x })),
|
|
23111
|
-
packageDetails?.outwardFlights &&
|
|
23112
|
-
packageDetails.outwardFlights
|
|
23113
|
-
.filter((x) => x.isSelected)
|
|
23114
|
-
.map((flight, i) => (React__default["default"].createElement(SummaryFlight, { key: i, flightMetaData: flight.flightMetaData, header: translations.SIDEBAR.DEPARTURE_FLIGHT }))),
|
|
23115
|
-
packageDetails?.returnFlights &&
|
|
23116
|
-
packageDetails.returnFlights
|
|
23117
|
-
.filter((x) => x.isSelected)
|
|
23118
|
-
.map((flight, i) => (React__default["default"].createElement(SummaryFlight, { key: i, flightMetaData: flight.flightMetaData, header: translations.SIDEBAR.ARRIVAL_FLIGHT })))))))))))),
|
|
23119
|
-
settings.enableVoucher && (React__default["default"].createElement("div", { className: "form__region" },
|
|
23120
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23121
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23122
|
-
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23123
|
-
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.VOUCHERS)))),
|
|
23124
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23125
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23126
|
-
React__default["default"].createElement("input", { type: "text", className: "form__input info-message__voucher__input", defaultValue: voucher.code, onChange: (e) => setVoucher({ code: e.target.value }) }),
|
|
23127
|
-
React__default["default"].createElement("button", { type: "button", className: buildClassName(['cta', !voucher.code && 'cta--disabled']), onClick: (e) => handleValidateVoucher() }, translations.SUMMARY.VOUCHER_VALIDATE))),
|
|
23128
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23129
|
-
React__default["default"].createElement("div", { className: "form__group info-message__voucher" },
|
|
23130
|
-
voucher.isValid && voucher.isValidated && (React__default["default"].createElement("div", { className: "info-message info-message__voucher__valid" },
|
|
23131
|
-
React__default["default"].createElement("span", null, translations.SUMMARY.VOUCHER_VALID),
|
|
23132
|
-
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: handleAddVoucher }, translations.SUMMARY.ADD_VOUCHER))),
|
|
23133
|
-
!voucher.isValid && voucher.isValidated && React__default["default"].createElement("div", { className: "info-message--error" }, translations.SUMMARY.VOUCHER_INVALID))),
|
|
23134
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23135
|
-
React__default["default"].createElement("ul", { className: "info-message__voucher" }, !lodash.isEmpty(bookRequest?.payload.voucherCodes) &&
|
|
23136
|
-
bookRequest?.payload.voucherCodes?.map((y, i) => (React__default["default"].createElement("li", { key: i },
|
|
23137
|
-
React__default["default"].createElement("div", { className: "info-message__voucher__list" },
|
|
23138
|
-
y,
|
|
23139
|
-
' ',
|
|
23140
|
-
React__default["default"].createElement("button", { type: "button", className: "cta--add-remove", onClick: (e) => handleRemoveVoucher(y) },
|
|
23141
|
-
React__default["default"].createElement(Icon, { height: 16, name: "ui-trashcan" })))))))))),
|
|
23142
|
-
!lodash.isEmpty(notifications) && (React__default["default"].createElement("div", { className: "form__region" },
|
|
23143
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23144
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23145
|
-
React__default["default"].createElement("div", { className: "info-message" },
|
|
23146
|
-
React__default["default"].createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
|
|
23147
|
-
React__default["default"].createElement("div", { className: "info-message__copy" },
|
|
23148
|
-
React__default["default"].createElement("h5", null, translations.SUMMARY.NOTIFICATIONS_TITLE),
|
|
23149
|
-
React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23150
|
-
lodash.uniqBy(notifications.filter((x) => !x.hasToBeConfirmed), 'id').map((notification) => (React__default["default"].createElement("span", { key: notification.id, className: "checkbox__label-text" },
|
|
23151
|
-
React__default["default"].createElement("strong", { className: "checkbox__label-text--title" }, notification.title),
|
|
23152
|
-
React__default["default"].createElement("span", { className: "checkbox__label-text--description" }, notification.description)))),
|
|
23153
|
-
lodash.uniqBy(notifications.filter((x) => x.hasToBeConfirmed), 'id').map((notification) => (React__default["default"].createElement("div", { className: "checkbox", key: notification.id },
|
|
23154
|
-
React__default["default"].createElement("label", { className: "checkbox__label" },
|
|
23155
|
-
React__default["default"].createElement("input", { type: "checkbox", className: "checkbox__input", checked: notification.isConfirmed, onChange: (e) => handleNotificationChange(notification.id, e.target.checked) }),
|
|
23156
|
-
React__default["default"].createElement("span", { className: "checkbox__label-text" },
|
|
23157
|
-
React__default["default"].createElement("strong", { className: "checkbox__label-text--title" }, notification.title),
|
|
23158
|
-
React__default["default"].createElement("span", { className: "checkbox__label-text--description" }, notification.description))))))))))))),
|
|
23159
|
-
React__default["default"].createElement("div", { className: "form__region" },
|
|
23160
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23161
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23162
|
-
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23163
|
-
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.REMARKS)))),
|
|
23164
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23165
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23166
|
-
React__default["default"].createElement("textarea", { className: "form__input", defaultValue: remarks, onChange: (e) => handleRemarksChange(e.target.value) })))),
|
|
23167
|
-
React__default["default"].createElement("div", { className: "form__region" },
|
|
23168
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23169
|
-
React__default["default"].createElement("div", { className: "form__group" },
|
|
23170
|
-
React__default["default"].createElement("div", { className: "info-message" },
|
|
23171
|
-
React__default["default"].createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
|
|
23172
|
-
React__default["default"].createElement("div", { className: "info-message__copy" },
|
|
23173
|
-
React__default["default"].createElement("h5", null, translations.SUMMARY.VALIDATE_TITLE),
|
|
23174
|
-
settings.customValidateText ? (React__default["default"].createElement("div", { dangerouslySetInnerHTML: {
|
|
23175
|
-
__html: settings.customValidateText
|
|
23176
|
-
} })) : (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23177
|
-
React__default["default"].createElement("p", null, settings.isOffer ? translations.SUMMARY.VALIDATE_TEXT_OFFER : translations.SUMMARY.VALIDATE_TEXT_BOOKING),
|
|
23178
|
-
settings.allowOption && React__default["default"].createElement("p", null, translations.SUMMARY.VALIDATE_TEXT_OPTION))),
|
|
23179
|
-
checkboxes &&
|
|
23180
|
-
checkboxes.map((checkbox) => (React__default["default"].createElement("div", { className: "checkbox", key: checkbox.id },
|
|
23181
|
-
React__default["default"].createElement("label", { className: "checkbox__label" },
|
|
23182
|
-
React__default["default"].createElement("input", { type: "checkbox", className: "checkbox__input", checked: checkbox.isSelected, onChange: (e) => handleCheckboxChange(checkbox.id, e.target.checked) }),
|
|
23183
|
-
React__default["default"].createElement("span", { className: "checkbox__label-text", dangerouslySetInnerHTML: {
|
|
23184
|
-
__html: checkbox.text
|
|
23185
|
-
} }))))))))))),
|
|
23186
|
-
React__default["default"].createElement("div", { className: "booking__navigator" },
|
|
23187
|
-
settings.skipRouter ? (React__default["default"].createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => goPrevious(), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : (React__default["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)),
|
|
23188
|
-
settings.allowOption && (React__default["default"].createElement("button", { title: translations.STEPS.SUBMIT_OPTION, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "option" }, translations.STEPS.SUBMIT_OPTION)),
|
|
23189
|
-
React__default["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))))));
|
|
23881
|
+
getDateText(opt.line.startDate),
|
|
23882
|
+
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
23883
|
+
React__default["default"].createElement("ul", { className: "list" }, !lodash.isEmpty(opt?.groups) &&
|
|
23884
|
+
opt?.groups.map((x) => {
|
|
23885
|
+
if (!x.options.some((y) => y.isSelected))
|
|
23886
|
+
return;
|
|
23887
|
+
return React__default["default"].createElement(SummaryPerPaxOptionGroup, { group: x });
|
|
23888
|
+
})))))));
|
|
23889
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null, group.title ? (React__default["default"].createElement("li", { className: "list__item" },
|
|
23890
|
+
React__default["default"].createElement("h6", null, group.title),
|
|
23891
|
+
React__default["default"].createElement("ul", { className: "list" }, renderOptions()))) : (React__default["default"].createElement(React__default["default"].Fragment, null, renderOptions()))));
|
|
23190
23892
|
};
|
|
23191
23893
|
|
|
23192
|
-
const
|
|
23193
|
-
return (React__default["default"].createElement("
|
|
23194
|
-
|
|
23195
|
-
|
|
23894
|
+
const SummaryBookingOptionPax = ({ pax }) => {
|
|
23895
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null, pax.groups.map((y, i) => {
|
|
23896
|
+
const paxOptions = y.options.filter((y) => y.isSelected);
|
|
23897
|
+
if (lodash.isEmpty(paxOptions))
|
|
23898
|
+
return;
|
|
23899
|
+
return React__default["default"].createElement(SummaryPerPaxOptionGroup, { key: i, group: y });
|
|
23900
|
+
})));
|
|
23196
23901
|
};
|
|
23197
23902
|
|
|
23198
|
-
const
|
|
23199
|
-
|
|
23200
|
-
|
|
23201
|
-
|
|
23202
|
-
|
|
23903
|
+
const SummaryPerUnitOptionGroup = ({ group }) => {
|
|
23904
|
+
const groupOptions = group.options.filter((x) => x.isSelected);
|
|
23905
|
+
const renderOptions = () => (React__default["default"].createElement(React__default["default"].Fragment, null, groupOptions.map((opt) => (React__default["default"].createElement("li", { key: opt.line.entryLineGuid, className: "list__item" },
|
|
23906
|
+
opt.line.productName,
|
|
23907
|
+
React__default["default"].createElement("ul", null,
|
|
23908
|
+
React__default["default"].createElement("li", null,
|
|
23909
|
+
opt.line.accommodationName,
|
|
23910
|
+
!lodash.isNil(opt.line?.regimeName) && ', ',
|
|
23911
|
+
opt.line.regimeName)),
|
|
23912
|
+
getDateText(opt.line.startDate),
|
|
23913
|
+
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
23914
|
+
React__default["default"].createElement("ul", null,
|
|
23915
|
+
!lodash.isEmpty(opt?.groups) &&
|
|
23916
|
+
opt?.groups.map((x) => {
|
|
23917
|
+
if (!x.options.some((y) => y.isSelected))
|
|
23918
|
+
return;
|
|
23919
|
+
return React__default["default"].createElement(SummaryPerUnitOptionGroup, { group: x });
|
|
23920
|
+
}),
|
|
23921
|
+
!lodash.isEmpty(opt?.pax) && opt?.pax.map((x) => React__default["default"].createElement(SummaryBookingOptionPax, { pax: x }))))))));
|
|
23922
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null, group.title ? (React__default["default"].createElement("li", { className: "list__item" },
|
|
23923
|
+
React__default["default"].createElement("h6", null, group.title),
|
|
23924
|
+
React__default["default"].createElement("ul", { className: "list" }, renderOptions()))) : (React__default["default"].createElement(React__default["default"].Fragment, null, renderOptions()))));
|
|
23203
23925
|
};
|
|
23204
23926
|
|
|
23205
|
-
const
|
|
23206
|
-
|
|
23207
|
-
|
|
23208
|
-
|
|
23209
|
-
|
|
23210
|
-
|
|
23211
|
-
|
|
23212
|
-
const hit = sorted.find((c) => value.startsWith(c.phonePrefix));
|
|
23213
|
-
if (hit) {
|
|
23214
|
-
const rest = value
|
|
23215
|
-
.slice(hit.phonePrefix.length)
|
|
23216
|
-
.trim()
|
|
23217
|
-
.replace(/^[-\s]+/, '');
|
|
23218
|
-
return { prefix: hit.phonePrefix, number: rest };
|
|
23219
|
-
}
|
|
23220
|
-
// Fallback: split on first space if it looks like a +prefix number
|
|
23221
|
-
const m = value.match(/^(\+\d{1,4})[\s-]*(.*)$/);
|
|
23222
|
-
if (m)
|
|
23223
|
-
return { prefix: m[1], number: m[2] };
|
|
23224
|
-
return { prefix: '', number: value };
|
|
23225
|
-
};
|
|
23226
|
-
const PhoneInput = ({ name, required, value, label, placeholder, extraClassName, hasError, countries, countryIso2, onChange, onBlur }) => {
|
|
23227
|
-
// Derive initial state from `value`
|
|
23228
|
-
const initialCountry = countries.find((c) => c.iso2 === countryIso2);
|
|
23229
|
-
const initial = React.useMemo(() => parseCombined(normalize(value), countries), [value, countries]);
|
|
23230
|
-
const [prefix, setPrefix] = React.useState(initial.prefix);
|
|
23231
|
-
const [number, setNumber] = React.useState(initial.number);
|
|
23232
|
-
// Keep state in sync if the parent changes `value`
|
|
23233
|
-
React.useEffect(() => {
|
|
23234
|
-
const parsed = !prefix && !number && initialCountry ? { prefix: initialCountry.phonePrefix, number: '' } : parseCombined(normalize(value), countries);
|
|
23235
|
-
if (parsed.prefix)
|
|
23236
|
-
setPrefix(parsed.prefix);
|
|
23237
|
-
if (parsed.number)
|
|
23238
|
-
setNumber(parsed.number);
|
|
23239
|
-
}, [value, countries, countryIso2]);
|
|
23240
|
-
const emitCombinedChange = (e, nextPrefix, nextNumber) => {
|
|
23241
|
-
// Combine with a space, unless the number already starts with a dash or space
|
|
23242
|
-
const combined = nextPrefix && nextNumber ? lodash.compact([nextPrefix, nextNumber]).join(' ') : null;
|
|
23243
|
-
onChange?.({
|
|
23244
|
-
...e,
|
|
23245
|
-
type: 'change',
|
|
23246
|
-
target: { name, value: combined },
|
|
23247
|
-
currentTarget: { name, value: combined }
|
|
23248
|
-
});
|
|
23249
|
-
};
|
|
23250
|
-
const handleCountryBlur = (e) => {
|
|
23251
|
-
onBlur?.(e);
|
|
23252
|
-
};
|
|
23253
|
-
const onCountryChange = (e) => {
|
|
23254
|
-
const next = e.target.value;
|
|
23255
|
-
setPrefix(next);
|
|
23256
|
-
emitCombinedChange(e, next, number);
|
|
23257
|
-
};
|
|
23258
|
-
const onPhoneChange = (e) => {
|
|
23259
|
-
const cleaned = e.target.value.replace(/[^\d\s-]/g, '');
|
|
23260
|
-
setNumber(cleaned);
|
|
23261
|
-
emitCombinedChange(e, prefix, cleaned);
|
|
23262
|
-
};
|
|
23263
|
-
const handleNumberBlur = (e) => {
|
|
23264
|
-
onBlur?.(e);
|
|
23265
|
-
};
|
|
23266
|
-
// Ensure the select shows a reasonable default when prefix is empty
|
|
23267
|
-
const selectValue = prefix || '';
|
|
23268
|
-
return (React__default["default"].createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
|
|
23269
|
-
label && React__default["default"].createElement("span", { className: "form__label" }, lodash.compact([label, required && '*']).join(' ')),
|
|
23270
|
-
React__default["default"].createElement("div", { className: "phone-input" },
|
|
23271
|
-
React__default["default"].createElement("div", { className: "dropdown" },
|
|
23272
|
-
React__default["default"].createElement("select", { "aria-label": label ? `${label} – country code` : 'Country calling code', name: `${name}__country`, value: selectValue, onBlur: handleCountryBlur, onChange: onCountryChange },
|
|
23273
|
-
React__default["default"].createElement("option", { value: "", disabled: true }),
|
|
23274
|
-
countries?.map((option) => (React__default["default"].createElement("option", { key: option.iso2, value: option.phonePrefix },
|
|
23275
|
-
option.name,
|
|
23276
|
-
" (",
|
|
23277
|
-
option.phonePrefix,
|
|
23278
|
-
")"))))),
|
|
23279
|
-
React__default["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 }),
|
|
23280
|
-
React__default["default"].createElement("input", { type: "hidden", name: name, value: lodash.compact([prefix, number]).join(' ') }))));
|
|
23927
|
+
const SummaryBookingOptionUnit = ({ unit }) => {
|
|
23928
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null, unit.groups.map((y) => {
|
|
23929
|
+
const unitOptions = y.options.filter((y) => y.isSelected);
|
|
23930
|
+
if (lodash.isEmpty(unitOptions))
|
|
23931
|
+
return;
|
|
23932
|
+
return React__default["default"].createElement(SummaryPerUnitOptionGroup, { group: y });
|
|
23933
|
+
})));
|
|
23281
23934
|
};
|
|
23282
23935
|
|
|
23283
|
-
const
|
|
23936
|
+
const SummaryFlight = ({ flightMetaData, header }) => {
|
|
23937
|
+
const translations = reactRedux.useSelector(selectTranslations);
|
|
23938
|
+
return (React__default["default"].createElement("li", null,
|
|
23939
|
+
React__default["default"].createElement("h6", null, header),
|
|
23940
|
+
parseFlightLines(flightMetaData)?.map((flightLine) => (React__default["default"].createElement("p", { key: flightLine.departureAirportIata },
|
|
23941
|
+
flightLine.departureAirportDescription,
|
|
23942
|
+
" (",
|
|
23943
|
+
flightLine.departureAirportIata,
|
|
23944
|
+
") > ",
|
|
23945
|
+
flightLine.arrivalAirportDescription,
|
|
23946
|
+
" (",
|
|
23947
|
+
flightLine.arrivalAirportIata,
|
|
23948
|
+
") ",
|
|
23949
|
+
' - ',
|
|
23950
|
+
flightLine.travelClass,
|
|
23951
|
+
" ",
|
|
23952
|
+
' - ',
|
|
23953
|
+
flightLine.airlineCode,
|
|
23954
|
+
flightLine.number,
|
|
23955
|
+
React__default["default"].createElement("br", null),
|
|
23956
|
+
getDateText(flightLine.departureDate),
|
|
23957
|
+
" ",
|
|
23958
|
+
flightLine.departureTime,
|
|
23959
|
+
" > ",
|
|
23960
|
+
getDateText(flightLine.arrivalDate),
|
|
23961
|
+
" ",
|
|
23962
|
+
flightLine.arrivalTime,
|
|
23963
|
+
React__default["default"].createElement("br", null),
|
|
23964
|
+
flightLine.airlineDescription))),
|
|
23965
|
+
flightMetaData.luggageIncluded && React__default["default"].createElement("p", null, translations.SIDEBAR.LUGGAGE_INCLUDED)));
|
|
23966
|
+
};
|
|
23284
23967
|
|
|
23285
|
-
const
|
|
23286
|
-
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
|
|
23291
|
-
|
|
23292
|
-
|
|
23293
|
-
|
|
23294
|
-
|
|
23295
|
-
|
|
23296
|
-
|
|
23297
|
-
|
|
23298
|
-
|
|
23968
|
+
const SummaryPerBookingOptionGroup = ({ group }) => {
|
|
23969
|
+
const groupOptions = group.options.filter((x) => x.isSelected);
|
|
23970
|
+
const renderOptions = () => (React__default["default"].createElement(React__default["default"].Fragment, null, groupOptions.map((opt) => (React__default["default"].createElement("li", { key: opt.line.entryLineGuid, className: "list__item" },
|
|
23971
|
+
opt.line.productName,
|
|
23972
|
+
React__default["default"].createElement("ul", null,
|
|
23973
|
+
React__default["default"].createElement("li", null,
|
|
23974
|
+
opt.line.accommodationName,
|
|
23975
|
+
!lodash.isNil(opt.line?.regimeName) && ', ',
|
|
23976
|
+
opt.line.regimeName)),
|
|
23977
|
+
getDateText(opt.line.startDate),
|
|
23978
|
+
opt.line.startDate != opt.line.endDate ? ` > ${getDateText(opt.line.endDate)}` : '',
|
|
23979
|
+
React__default["default"].createElement("ul", null,
|
|
23980
|
+
!lodash.isEmpty(opt?.groups) &&
|
|
23981
|
+
opt?.groups.map((x) => {
|
|
23982
|
+
if (!x.options.some((y) => y.isSelected))
|
|
23983
|
+
return;
|
|
23984
|
+
return React__default["default"].createElement(SummaryPerBookingOptionGroup, { group: x });
|
|
23985
|
+
}),
|
|
23986
|
+
!lodash.isEmpty(opt?.units) && opt?.units.map((x) => React__default["default"].createElement(SummaryBookingOptionUnit, { unit: x })),
|
|
23987
|
+
!lodash.isEmpty(opt?.pax) && opt?.pax.map((x) => React__default["default"].createElement(SummaryBookingOptionPax, { pax: x }))))))));
|
|
23988
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null, group.title ? (React__default["default"].createElement("li", { className: "list__item" },
|
|
23989
|
+
React__default["default"].createElement("h6", null, group.title),
|
|
23990
|
+
React__default["default"].createElement("ul", { className: "list" }, renderOptions()))) : (React__default["default"].createElement(React__default["default"].Fragment, null, renderOptions()))));
|
|
23299
23991
|
};
|
|
23300
23992
|
|
|
23301
|
-
const
|
|
23302
|
-
const
|
|
23303
|
-
const
|
|
23304
|
-
|
|
23305
|
-
|
|
23993
|
+
const Summary = () => {
|
|
23994
|
+
const dispatch = useAppDispatch();
|
|
23995
|
+
const settings = React.useContext(SettingsContext);
|
|
23996
|
+
const navigate = settings.skipRouter ? () => { } : reactRouter.useNavigate();
|
|
23997
|
+
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
23998
|
+
const [checkboxes, setCheckboxes] = React.useState(settings.summary?.checkboxes);
|
|
23999
|
+
const [remarks, setRemarks] = React.useState('');
|
|
24000
|
+
const [voucher, setVoucher] = React.useState({});
|
|
24001
|
+
const bookingQueryString = reactRedux.useSelector(selectBookingQueryString);
|
|
24002
|
+
const travelersFirstStep = reactRedux.useSelector(selectTravelersFirstStep);
|
|
24003
|
+
const travelerFormValues = reactRedux.useSelector(selectTravelersFormValues);
|
|
24004
|
+
const packageDetails = reactRedux.useSelector(selectPackageDetails);
|
|
24005
|
+
const activeOption = reactRedux.useSelector(selectActiveOption);
|
|
24006
|
+
const apiSettings = reactRedux.useSelector(selectApiSettings);
|
|
24007
|
+
const languageCode = reactRedux.useSelector(selectLanguageCode);
|
|
24008
|
+
const officeId = reactRedux.useSelector(selectOfficeId);
|
|
24009
|
+
const agentId = reactRedux.useSelector(selectAgentAdressId);
|
|
24010
|
+
const departureFlight = reactRedux.useSelector(selectDepartureFlight);
|
|
24011
|
+
const departureFlightMetaData = departureFlight?.flightMetaData ?? reactRedux.useSelector(selectRoomOptionDepartureFlightsMetaData)?.[0];
|
|
24012
|
+
const returnFlight = reactRedux.useSelector(selectReturnFlight);
|
|
24013
|
+
const returnFlightMetaData = returnFlight?.flightMetaData ?? reactRedux.useSelector(selectRoomOptionReturnFlightsMetaData)?.[0];
|
|
24014
|
+
if (!travelerFormValues) {
|
|
24015
|
+
if (settings.skipRouter) {
|
|
24016
|
+
dispatch(setCurrentStep$1(TRAVELERS_FORM_STEP));
|
|
23306
24017
|
}
|
|
23307
|
-
|
|
23308
|
-
|
|
23309
|
-
if (onClear) {
|
|
23310
|
-
onClear();
|
|
24018
|
+
else {
|
|
24019
|
+
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}?${bookingQueryString}`);
|
|
23311
24020
|
}
|
|
23312
|
-
|
|
23313
|
-
|
|
23314
|
-
|
|
23315
|
-
|
|
23316
|
-
|
|
23317
|
-
|
|
23318
|
-
|
|
23319
|
-
|
|
23320
|
-
|
|
23321
|
-
|
|
23322
|
-
|
|
23323
|
-
|
|
23324
|
-
|
|
23325
|
-
|
|
23326
|
-
|
|
23327
|
-
|
|
23328
|
-
|
|
23329
|
-
|
|
23330
|
-
|
|
23331
|
-
|
|
23332
|
-
if (onSelect)
|
|
23333
|
-
onSelect(option.key);
|
|
23334
|
-
setShowItems(false);
|
|
23335
|
-
}, type: "button", className: "button button--plain" },
|
|
23336
|
-
prefix,
|
|
23337
|
-
React__default["default"].createElement("span", { className: "typeahead__option-highlight" }, highlight),
|
|
23338
|
-
suffix))));
|
|
23339
|
-
})))));
|
|
23340
|
-
};
|
|
23341
|
-
|
|
23342
|
-
// A traveler is a baby when the age they were booked with is at or below the baby
|
|
23343
|
-
// boundary. Babies get their own label and birth date validation (TIDE-3269). Only
|
|
23344
|
-
// meaningful for the regular form: the compact form asks for an age instead of a birth
|
|
23345
|
-
// date, so it has nothing to validate and its own age input already states the age.
|
|
23346
|
-
function isBabyAge(age, maxBabyAge = BABY_MAX_AGE) {
|
|
23347
|
-
return typeof age === 'number' && age <= maxBabyAge;
|
|
23348
|
-
}
|
|
23349
|
-
// The native date input can hold values format() throws on (e.g. a 5+ digit year while typing), so never format an unvalidated birthDate
|
|
23350
|
-
function formatBirthDate$1(birthDate) {
|
|
23351
|
-
if (!birthDate)
|
|
23352
|
-
return '';
|
|
23353
|
-
const parsed = dateFns.parse(birthDate, 'yyyy-MM-dd', new Date());
|
|
23354
|
-
return dateFns.isValid(parsed) ? dateFns.format(parsed, 'dd-MM-yyyy') : '';
|
|
23355
|
-
}
|
|
23356
|
-
// A customFieldConfigurationId can have separate "main-booker"/other-pax variants; resolved per traveler below.
|
|
23357
|
-
const MAIN_BOOKER_GROUP = 'main-booker';
|
|
23358
|
-
function buildEmptyCustomFields(paxCustomFields = []) {
|
|
23359
|
-
const uniqueIds = Array.from(new Set(paxCustomFields.map((field) => field.customFieldConfigurationId)));
|
|
23360
|
-
return uniqueIds.map((customFieldConfigurationId) => ({ customFieldConfigurationId, value: '' }));
|
|
23361
|
-
}
|
|
23362
|
-
function getApplicablePaxCustomFields(paxCustomFields = [], isMainBooker) {
|
|
23363
|
-
const variantsById = new Map();
|
|
23364
|
-
paxCustomFields.forEach((field) => {
|
|
23365
|
-
const variants = variantsById.get(field.customFieldConfigurationId) ?? [];
|
|
23366
|
-
variants.push(field);
|
|
23367
|
-
variantsById.set(field.customFieldConfigurationId, variants);
|
|
23368
|
-
});
|
|
23369
|
-
const applicableFields = [];
|
|
23370
|
-
variantsById.forEach((variants) => {
|
|
23371
|
-
const hasRoleSplit = variants.some((v) => v.group === MAIN_BOOKER_GROUP);
|
|
23372
|
-
if (!hasRoleSplit) {
|
|
23373
|
-
applicableFields.push(variants[0]);
|
|
24021
|
+
}
|
|
24022
|
+
const rooms = reactRedux.useSelector(selectRooms);
|
|
24023
|
+
const userValidated = reactRedux.useSelector(selectUserValidated);
|
|
24024
|
+
const notifications = reactRedux.useSelector(selectNotifications);
|
|
24025
|
+
const bookRequest = reactRedux.useSelector(selectBookingPackageBookRequest);
|
|
24026
|
+
React.useEffect(() => {
|
|
24027
|
+
// Every checkbox should be checked, or no checkboxes
|
|
24028
|
+
const checkboxesValidated = !lodash.isNil(checkboxes) ? checkboxes.every((checkbox) => checkbox.isSelected) : true;
|
|
24029
|
+
const notificationsValidated = !lodash.isNil(notifications) ? notifications.filter((x) => x.hasToBeConfirmed).every((checkbox) => checkbox.isConfirmed) : true;
|
|
24030
|
+
dispatch(setUserValidated(checkboxesValidated && notificationsValidated));
|
|
24031
|
+
}, [checkboxes, notifications]);
|
|
24032
|
+
const handleSubmit = async (e) => {
|
|
24033
|
+
e.preventDefault();
|
|
24034
|
+
const submitter = e.nativeEvent.submitter?.name;
|
|
24035
|
+
setIsSubmitting(true);
|
|
24036
|
+
if (typeof window !== 'undefined') {
|
|
24037
|
+
window.scrollTo(0, 0);
|
|
24038
|
+
}
|
|
24039
|
+
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
24040
|
+
if (!bookRequest || !tideClientConfig) {
|
|
23374
24041
|
return;
|
|
23375
24042
|
}
|
|
23376
|
-
|
|
23377
|
-
|
|
23378
|
-
|
|
23379
|
-
|
|
23380
|
-
|
|
23381
|
-
}
|
|
23382
|
-
|
|
23383
|
-
|
|
23384
|
-
|
|
23385
|
-
|
|
23386
|
-
|
|
23387
|
-
lastName: `${followNumber.number++}`,
|
|
23388
|
-
birthDate: '',
|
|
23389
|
-
gender: '',
|
|
23390
|
-
// Keep a booked age of 0 instead of submitting and pricing the traveler as a 30 year
|
|
23391
|
-
// old, while still falling back for a missing or unusable age. `??` alone would let a
|
|
23392
|
-
// NaN (unparseable date of birth upstream) reach the age input and the booked pax.
|
|
23393
|
-
// See TIDE-3269.
|
|
23394
|
-
age: Number.isFinite(traveler.age) ? traveler.age : 30,
|
|
23395
|
-
// No isBaby here on purpose: the age below is editable and nothing revalidates it
|
|
23396
|
-
// in compact mode, so a stored flag would end up contradicting the entered age.
|
|
23397
|
-
weight: null,
|
|
23398
|
-
weightType: build.WeightType.kilograms,
|
|
23399
|
-
height: null,
|
|
23400
|
-
heightType: build.HeightType.centimeters,
|
|
23401
|
-
customFields: buildEmptyCustomFields(paxCustomFields)
|
|
23402
|
-
};
|
|
23403
|
-
}
|
|
23404
|
-
return {
|
|
23405
|
-
id: traveler.id,
|
|
23406
|
-
firstName: '',
|
|
23407
|
-
lastName: '',
|
|
23408
|
-
birthDate: '',
|
|
23409
|
-
gender: '',
|
|
23410
|
-
isBaby: isBabyAge(traveler.age, maxBabyAge),
|
|
23411
|
-
weight: null,
|
|
23412
|
-
weightType: build.WeightType.kilograms,
|
|
23413
|
-
height: null,
|
|
23414
|
-
heightType: build.HeightType.centimeters,
|
|
23415
|
-
customFields: buildEmptyCustomFields(paxCustomFields)
|
|
23416
|
-
};
|
|
23417
|
-
}
|
|
23418
|
-
function createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, personTranslation, isCompact, maxBabyAge, paxCustomFields) {
|
|
23419
|
-
const followNumber = { number: 1 };
|
|
23420
|
-
const initialValues = {
|
|
23421
|
-
startDate,
|
|
23422
|
-
endDate,
|
|
23423
|
-
rooms: formRooms.map((room) => ({
|
|
23424
|
-
adults: room.adults.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxCustomFields)),
|
|
23425
|
-
children: room.children.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxCustomFields))
|
|
23426
|
-
})),
|
|
23427
|
-
mainBookerId: -1,
|
|
23428
|
-
street: '',
|
|
23429
|
-
houseNumber: '',
|
|
23430
|
-
box: '',
|
|
23431
|
-
zipCode: '',
|
|
23432
|
-
place: '',
|
|
23433
|
-
country: '',
|
|
23434
|
-
phone: '',
|
|
23435
|
-
email: '',
|
|
23436
|
-
emailConfirmation: '',
|
|
23437
|
-
travelAgentId: agentAdressId ?? 0,
|
|
23438
|
-
travelAgentName: ''
|
|
23439
|
-
};
|
|
23440
|
-
if (initialValues.rooms?.[0]?.adults?.[0]) {
|
|
23441
|
-
initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
|
|
23442
|
-
}
|
|
23443
|
-
return initialValues;
|
|
23444
|
-
}
|
|
23445
|
-
function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId) {
|
|
23446
|
-
const pax = editablePackagingEntry?.pax ?? [];
|
|
23447
|
-
const rooms = editablePackagingEntry.rooms.map((room) => {
|
|
23448
|
-
const roomPax = pax.filter((x) => room.paxIds.includes(x.id));
|
|
23449
|
-
const adults = roomPax.filter((x) => x.age >= 18);
|
|
23450
|
-
const children = roomPax.filter((x) => x.age < 18);
|
|
23451
|
-
return {
|
|
23452
|
-
adults: adults.map((roomTraveler) => {
|
|
23453
|
-
return {
|
|
23454
|
-
id: roomTraveler.id,
|
|
23455
|
-
firstName: roomTraveler.firstName ?? '',
|
|
23456
|
-
lastName: roomTraveler.lastName ?? '',
|
|
23457
|
-
birthDate: roomTraveler.dateOfBirth ? dateFns.format(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
|
|
23458
|
-
gender: ''
|
|
23459
|
-
};
|
|
23460
|
-
}),
|
|
23461
|
-
children: children.map((roomTraveler) => {
|
|
23462
|
-
return {
|
|
23463
|
-
id: roomTraveler.id,
|
|
23464
|
-
firstName: roomTraveler.firstName ?? '',
|
|
23465
|
-
lastName: roomTraveler.lastName ?? '',
|
|
23466
|
-
birthDate: roomTraveler.dateOfBirth ? dateFns.format(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
|
|
23467
|
-
gender: '',
|
|
23468
|
-
isBaby: isBabyAge(roomTraveler.age)
|
|
23469
|
-
};
|
|
23470
|
-
})
|
|
23471
|
-
};
|
|
23472
|
-
});
|
|
23473
|
-
const values = createInitialValuesFromRooms(rooms.map((room) => ({ adults: room.adults, children: room.children })), lodash.first(editablePackagingEntry?.lines)?.from, lodash.last(editablePackagingEntry?.lines)?.to, agentAdressId);
|
|
23474
|
-
values.rooms = rooms;
|
|
23475
|
-
values.mainBookerId = pax.find((x) => x.isMainBooker)?.id ?? rooms[0]?.adults?.[0]?.id ?? -1;
|
|
23476
|
-
const address = editablePackagingEntry?.address;
|
|
23477
|
-
values.street = address?.street ?? '';
|
|
23478
|
-
values.houseNumber = address?.houseNumber ?? '';
|
|
23479
|
-
values.box = address?.box ?? '';
|
|
23480
|
-
values.zipCode = address?.zipCode ?? '';
|
|
23481
|
-
values.place = address?.place ?? '';
|
|
23482
|
-
values.country = address?.country ?? '';
|
|
23483
|
-
values.phone = address?.phone ?? '';
|
|
23484
|
-
values.email = address?.email ?? '';
|
|
23485
|
-
values.emailConfirmation = address?.email ?? '';
|
|
23486
|
-
values.travelAgentId = address?.travelAgentId ?? agentAdressId ?? 0;
|
|
23487
|
-
return values;
|
|
23488
|
-
}
|
|
23489
|
-
function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry, values) {
|
|
23490
|
-
const travelers = values.rooms.flatMap((room) => [...room.adults, ...room.children]);
|
|
23491
|
-
return {
|
|
23492
|
-
...editablePackagingEntry,
|
|
23493
|
-
pax: (editablePackagingEntry.pax ?? []).map((pax) => {
|
|
23494
|
-
const traveler = travelers.find((x) => x.id === pax.id);
|
|
23495
|
-
if (!traveler)
|
|
23496
|
-
return pax;
|
|
23497
|
-
return {
|
|
23498
|
-
...pax,
|
|
23499
|
-
firstName: traveler.firstName ?? '',
|
|
23500
|
-
lastName: traveler.lastName ?? '',
|
|
23501
|
-
dateOfBirth: traveler.birthDate || null,
|
|
23502
|
-
isMainBooker: traveler.id === values.mainBookerId
|
|
23503
|
-
};
|
|
23504
|
-
}),
|
|
23505
|
-
address: {
|
|
23506
|
-
...editablePackagingEntry.address,
|
|
23507
|
-
street: values.street,
|
|
23508
|
-
houseNumber: values.houseNumber,
|
|
23509
|
-
box: values.box,
|
|
23510
|
-
zipCode: values.zipCode,
|
|
23511
|
-
place: values.place,
|
|
23512
|
-
country: values.country,
|
|
23513
|
-
travelAgentId: values.travelAgentId,
|
|
23514
|
-
phone: values.phone,
|
|
23515
|
-
email: values.email
|
|
24043
|
+
if (bookRequest.payload.returnPaymentUrl) {
|
|
24044
|
+
if (typeof window !== 'undefined') {
|
|
24045
|
+
window.scrollTo(0, 0);
|
|
24046
|
+
if (settings.paymentRedirectUrl) {
|
|
24047
|
+
bookRequest.payload.redirectUrl = settings.paymentRedirectUrl;
|
|
24048
|
+
}
|
|
24049
|
+
else {
|
|
24050
|
+
const location = window.location;
|
|
24051
|
+
bookRequest.payload.redirectUrl = `${location.protocol}//${location.host}${settings.basePath ?? location.pathname}?${bookingQueryString}`;
|
|
24052
|
+
}
|
|
24053
|
+
}
|
|
23516
24054
|
}
|
|
23517
|
-
|
|
23518
|
-
|
|
23519
|
-
|
|
23520
|
-
|
|
23521
|
-
|
|
23522
|
-
|
|
23523
|
-
|
|
23524
|
-
|
|
23525
|
-
|
|
23526
|
-
|
|
23527
|
-
|
|
23528
|
-
|
|
23529
|
-
|
|
23530
|
-
|
|
23531
|
-
|
|
23532
|
-
|
|
23533
|
-
|
|
23534
|
-
|
|
23535
|
-
|
|
23536
|
-
|
|
23537
|
-
|
|
23538
|
-
|
|
23539
|
-
|
|
23540
|
-
|
|
23541
|
-
|
|
23542
|
-
|
|
23543
|
-
|
|
23544
|
-
|
|
23545
|
-
|
|
23546
|
-
|
|
23547
|
-
|
|
23548
|
-
|
|
23549
|
-
|
|
23550
|
-
|
|
23551
|
-
|
|
23552
|
-
|
|
23553
|
-
|
|
23554
|
-
|
|
23555
|
-
|
|
23556
|
-
|
|
23557
|
-
|
|
23558
|
-
|
|
23559
|
-
|
|
23560
|
-
formik.setValues({ ...formik.values, travelAgentId: 0, travelAgentName: '' });
|
|
23561
|
-
onBookingTypeChange?.('b2c');
|
|
23562
|
-
};
|
|
23563
|
-
const toggleAgent = (value) => {
|
|
23564
|
-
setShowAgents(value);
|
|
23565
|
-
if (!value) {
|
|
23566
|
-
handleAgentClear();
|
|
23567
|
-
setFilteredAgents([]);
|
|
24055
|
+
try {
|
|
24056
|
+
if (submitter === 'option') {
|
|
24057
|
+
bookRequest.payload.status = build.EntryStatus.option;
|
|
24058
|
+
bookRequest.payload.customStatusId = settings.customOptionStatus;
|
|
24059
|
+
dispatch(setIsOption(true));
|
|
24060
|
+
}
|
|
24061
|
+
const bookingResponse = await build.book(tideClientConfig, bookRequest, undefined, languageCode);
|
|
24062
|
+
// Booking successfull
|
|
24063
|
+
dispatch(setBookingNumber$1(bookingResponse.number));
|
|
24064
|
+
if (bookingResponse.paymentUrl) {
|
|
24065
|
+
const event = new CustomEvent('tide-booking-payment-url', {
|
|
24066
|
+
detail: {
|
|
24067
|
+
paymentUrl: bookingResponse.paymentUrl,
|
|
24068
|
+
bookingNumber: bookingResponse.number
|
|
24069
|
+
},
|
|
24070
|
+
cancelable: true,
|
|
24071
|
+
bubbles: true
|
|
24072
|
+
});
|
|
24073
|
+
const target = typeof document !== 'undefined' ? document.getElementById('tide-booking') ?? window : window;
|
|
24074
|
+
const shouldAutoRedirect = target.dispatchEvent(event);
|
|
24075
|
+
if (shouldAutoRedirect) {
|
|
24076
|
+
window.location.href = bookingResponse.paymentUrl;
|
|
24077
|
+
}
|
|
24078
|
+
}
|
|
24079
|
+
else {
|
|
24080
|
+
if (settings.skipRouter) {
|
|
24081
|
+
dispatch(setCurrentStep$1(CONFIRMATION_STEP));
|
|
24082
|
+
}
|
|
24083
|
+
else {
|
|
24084
|
+
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.confirmation.pathSuffix}?${bookingQueryString}`);
|
|
24085
|
+
}
|
|
24086
|
+
}
|
|
24087
|
+
}
|
|
24088
|
+
catch (error) {
|
|
24089
|
+
if (settings.skipRouter) {
|
|
24090
|
+
dispatch(setCurrentStep$1(ERROR_STEP));
|
|
24091
|
+
}
|
|
24092
|
+
else {
|
|
24093
|
+
navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.error.pathSuffix}?${bookingQueryString}`);
|
|
24094
|
+
}
|
|
24095
|
+
}
|
|
24096
|
+
finally {
|
|
24097
|
+
setIsSubmitting(false);
|
|
23568
24098
|
}
|
|
23569
24099
|
};
|
|
23570
|
-
const
|
|
23571
|
-
const
|
|
23572
|
-
|
|
23573
|
-
id: Date.now(),
|
|
23574
|
-
firstName: '',
|
|
23575
|
-
lastName: '',
|
|
23576
|
-
birthDate: '',
|
|
23577
|
-
gender: '',
|
|
23578
|
-
weight: null,
|
|
23579
|
-
weightType: build.WeightType.kilograms,
|
|
23580
|
-
height: null,
|
|
23581
|
-
heightType: build.HeightType.centimeters,
|
|
23582
|
-
customFields: buildEmptyCustomFields(paxCustomFields)
|
|
23583
|
-
};
|
|
23584
|
-
rooms[roomIndex] = { ...rooms[roomIndex], adults: [...rooms[roomIndex].adults, newAdult] };
|
|
23585
|
-
formik.setFieldValue('rooms', rooms);
|
|
24100
|
+
const handleNotificationChange = (id, checked) => {
|
|
24101
|
+
const updatedNotifications = notifications.map((notification) => (notification.id === id ? { ...notification, isConfirmed: checked } : notification));
|
|
24102
|
+
dispatch(setNotifications(updatedNotifications));
|
|
23586
24103
|
};
|
|
23587
|
-
const
|
|
23588
|
-
|
|
23589
|
-
const adults = [...rooms[roomIndex].adults];
|
|
23590
|
-
if (adults.length <= 1)
|
|
24104
|
+
const handleCheckboxChange = (id, checked) => {
|
|
24105
|
+
if (lodash.isNil(checkboxes)) {
|
|
23591
24106
|
return;
|
|
23592
|
-
|
|
23593
|
-
|
|
23594
|
-
|
|
23595
|
-
|
|
23596
|
-
|
|
23597
|
-
const rooms = [...formik.values.rooms];
|
|
23598
|
-
rooms.push({
|
|
23599
|
-
adults: [
|
|
23600
|
-
{
|
|
23601
|
-
id: Date.now(),
|
|
23602
|
-
firstName: '',
|
|
23603
|
-
lastName: '',
|
|
23604
|
-
birthDate: '',
|
|
23605
|
-
gender: '',
|
|
23606
|
-
weight: null,
|
|
23607
|
-
weightType: build.WeightType.kilograms,
|
|
23608
|
-
height: null,
|
|
23609
|
-
heightType: build.HeightType.centimeters,
|
|
23610
|
-
customFields: buildEmptyCustomFields(paxCustomFields)
|
|
23611
|
-
}
|
|
23612
|
-
],
|
|
23613
|
-
children: []
|
|
23614
|
-
});
|
|
23615
|
-
formik.setFieldValue('rooms', rooms);
|
|
24107
|
+
}
|
|
24108
|
+
const newCheckboxes = [...checkboxes];
|
|
24109
|
+
const index = lodash.findIndex(checkboxes, (checkbox) => checkbox.id === id);
|
|
24110
|
+
newCheckboxes[index].isSelected = !newCheckboxes[index].isSelected;
|
|
24111
|
+
setCheckboxes(newCheckboxes);
|
|
23616
24112
|
};
|
|
23617
|
-
const
|
|
23618
|
-
|
|
23619
|
-
|
|
23620
|
-
formik.setFieldValue('rooms', rooms);
|
|
24113
|
+
const handleRemarksChange = (text) => {
|
|
24114
|
+
dispatch(setBookingRemarks(text));
|
|
24115
|
+
setRemarks(text);
|
|
23621
24116
|
};
|
|
23622
|
-
const
|
|
23623
|
-
|
|
23624
|
-
|
|
23625
|
-
|
|
23626
|
-
|
|
23627
|
-
|
|
23628
|
-
|
|
23629
|
-
|
|
23630
|
-
|
|
23631
|
-
|
|
23632
|
-
|
|
23633
|
-
|
|
23634
|
-
|
|
23635
|
-
|
|
23636
|
-
|
|
23637
|
-
|
|
23638
|
-
|
|
23639
|
-
|
|
23640
|
-
|
|
23641
|
-
|
|
23642
|
-
|
|
23643
|
-
{ key: 'ftIn', value: build.HeightType.feetInches, label: translations.TRAVELERS_FORM.HEIGHT_UNIT_FT_IN }
|
|
23644
|
-
] })));
|
|
23645
|
-
const getCustomFieldControl = (field, value, name) => {
|
|
23646
|
-
const label = lodash.compact([field.fieldName, field.isRequired && '*']).join(' ');
|
|
23647
|
-
switch (field.dataType) {
|
|
23648
|
-
case build.CustomFieldDataType.bool:
|
|
23649
|
-
return (React__default["default"].createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
|
|
23650
|
-
React__default["default"].createElement("div", { className: "checkbox" },
|
|
23651
|
-
React__default["default"].createElement("label", { className: "checkbox__label" },
|
|
23652
|
-
React__default["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 }),
|
|
23653
|
-
label))));
|
|
23654
|
-
case build.CustomFieldDataType.date:
|
|
23655
|
-
return (React__default["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 }));
|
|
23656
|
-
case build.CustomFieldDataType.time:
|
|
23657
|
-
return (React__default["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 }));
|
|
23658
|
-
case build.CustomFieldDataType.numeric:
|
|
23659
|
-
return (React__default["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 }));
|
|
23660
|
-
case build.CustomFieldDataType.string:
|
|
23661
|
-
default:
|
|
23662
|
-
return (React__default["default"].createElement(LabeledInput, { hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
|
|
24117
|
+
const handleValidateVoucher = async () => {
|
|
24118
|
+
if (!voucher?.code)
|
|
24119
|
+
return;
|
|
24120
|
+
const request = {
|
|
24121
|
+
officeId: officeId,
|
|
24122
|
+
agentId: agentId,
|
|
24123
|
+
payload: {
|
|
24124
|
+
code: voucher.code,
|
|
24125
|
+
otherCodes: bookRequest?.payload.voucherCodes ?? []
|
|
24126
|
+
}
|
|
24127
|
+
};
|
|
24128
|
+
const tideClientConfig = buildTideClientConfig(apiSettings);
|
|
24129
|
+
if (!tideClientConfig)
|
|
24130
|
+
return;
|
|
24131
|
+
const result = await build.validateVoucher(tideClientConfig, request);
|
|
24132
|
+
if (result) {
|
|
24133
|
+
setVoucher({
|
|
24134
|
+
...voucher,
|
|
24135
|
+
isValidated: true,
|
|
24136
|
+
isValid: result.isValid
|
|
24137
|
+
});
|
|
23663
24138
|
}
|
|
23664
24139
|
};
|
|
23665
|
-
const
|
|
23666
|
-
if (!
|
|
23667
|
-
return
|
|
23668
|
-
|
|
23669
|
-
|
|
23670
|
-
|
|
23671
|
-
return null;
|
|
23672
|
-
return (React__default["default"].createElement("div", { className: "travelers-form__custom-fields-grid" }, applicableFields.map((field) => {
|
|
23673
|
-
const fieldIndex = travelerValues.customFields?.findIndex((c) => c.customFieldConfigurationId === field.customFieldConfigurationId) ?? -1;
|
|
23674
|
-
if (fieldIndex < 0)
|
|
23675
|
-
return null;
|
|
23676
|
-
const name = `${namePrefix}.customFields[${fieldIndex}].value`;
|
|
23677
|
-
const value = travelerValues.customFields[fieldIndex].value;
|
|
23678
|
-
return (React__default["default"].createElement("div", { key: field.customFieldConfigurationId, style: { gridColumn: `span ${field.col || 12}` } }, getCustomFieldControl(field, value, name)));
|
|
23679
|
-
})));
|
|
24140
|
+
const handleAddVoucher = (event) => {
|
|
24141
|
+
if (!voucher.isValid)
|
|
24142
|
+
return;
|
|
24143
|
+
dispatch(setVoucherCodes([...(bookRequest?.payload.voucherCodes ?? []), voucher.code ?? ''].filter((x) => x !== '')));
|
|
24144
|
+
dispatch(fetchPriceDetails());
|
|
24145
|
+
setVoucher({});
|
|
23680
24146
|
};
|
|
23681
|
-
const
|
|
23682
|
-
|
|
23683
|
-
|
|
23684
|
-
return React__default["default"].createElement(GenderControl, { translations: translations, value: value, formik: formik, name: name });
|
|
23685
|
-
case 'firstName':
|
|
23686
|
-
return (React__default["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 }));
|
|
23687
|
-
case 'lastName':
|
|
23688
|
-
return (React__default["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 }));
|
|
23689
|
-
case 'birthDate':
|
|
23690
|
-
return (React__default["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 }));
|
|
23691
|
-
case 'country':
|
|
23692
|
-
return (React__default["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 }));
|
|
23693
|
-
case 'phone':
|
|
23694
|
-
return (React__default["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 }));
|
|
23695
|
-
case 'email':
|
|
23696
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23697
|
-
React__default["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 }),
|
|
23698
|
-
React__default["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 })));
|
|
23699
|
-
case 'street':
|
|
23700
|
-
return (React__default["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 }));
|
|
23701
|
-
case 'houseNumber':
|
|
23702
|
-
return (React__default["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 }));
|
|
23703
|
-
case 'box':
|
|
23704
|
-
return (React__default["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 }));
|
|
23705
|
-
case 'zipCode':
|
|
23706
|
-
return (React__default["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 }));
|
|
23707
|
-
case 'place':
|
|
23708
|
-
return (React__default["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 }));
|
|
23709
|
-
default:
|
|
23710
|
-
return null;
|
|
23711
|
-
}
|
|
24147
|
+
const handleRemoveVoucher = (code) => {
|
|
24148
|
+
dispatch(setVoucherCodes(bookRequest?.payload.voucherCodes?.filter((x) => x !== code) ?? []));
|
|
24149
|
+
dispatch(fetchPriceDetails());
|
|
23712
24150
|
};
|
|
23713
|
-
const
|
|
23714
|
-
|
|
23715
|
-
room.adults.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
|
|
23716
|
-
room.adults.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
|
|
23717
|
-
room.adults?.length && room.children?.length && ', ',
|
|
23718
|
-
room.children.length,
|
|
23719
|
-
room.children.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
|
|
23720
|
-
room.children.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`
|
|
23721
|
-
]).join('');
|
|
23722
|
-
const renderTravelerFields = (travelerValues, namePrefix, isAdult, roomIndex, travelerIndex) => {
|
|
23723
|
-
if (useCompactForm) {
|
|
23724
|
-
return (React__default["default"].createElement("div", { className: "form__row" },
|
|
23725
|
-
React__default["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 })));
|
|
23726
|
-
}
|
|
23727
|
-
if (travellersSettings?.formFields?.length) {
|
|
23728
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23729
|
-
React__default["default"].createElement("div", { className: "travelers-form__grid" }, travellersSettings.formFields.map((field, index) => (React__default["default"].createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, travelerValues, `${namePrefix}.${field.type}`))))),
|
|
23730
|
-
showWeightField && renderWeightControl(namePrefix, travelerValues),
|
|
23731
|
-
showHeightField && renderHeightControl(namePrefix, travelerValues),
|
|
23732
|
-
renderCustomFields(travelerValues, namePrefix)));
|
|
23733
|
-
}
|
|
23734
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23735
|
-
React__default["default"].createElement("div", { className: "form__row" }, renderGenderControl(`${namePrefix}.gender`, travelerValues)),
|
|
23736
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23737
|
-
React__default["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 }),
|
|
23738
|
-
React__default["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 }),
|
|
23739
|
-
React__default["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 })),
|
|
23740
|
-
showWeightField && renderWeightControl(namePrefix, travelerValues),
|
|
23741
|
-
showHeightField && renderHeightControl(namePrefix, travelerValues),
|
|
23742
|
-
renderCustomFields(travelerValues, namePrefix),
|
|
23743
|
-
travelersFirstStep && isAdult && formik.values.rooms[roomIndex].adults.length > 1 && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveTraveler(roomIndex, travelerIndex) }, translations.TRAVELERS_FORM.REMOVE_TRAVELER))));
|
|
24151
|
+
const goPrevious = () => {
|
|
24152
|
+
dispatch(setCurrentStep$1(travelersFirstStep ? OPTIONS_FORM_STEP : TRAVELERS_FORM_STEP));
|
|
23744
24153
|
};
|
|
23745
|
-
|
|
23746
|
-
|
|
23747
|
-
|
|
23748
|
-
|
|
23749
|
-
|
|
23750
|
-
|
|
23751
|
-
translations.SHARED.ROOM,
|
|
23752
|
-
" ",
|
|
23753
|
-
roomIndex + 1),
|
|
23754
|
-
React__default["default"].createElement("p", { className: "form__region-label" }, renderRoomLabel(room))),
|
|
23755
|
-
!useCompactForm && travelersFirstStep && formik.values.rooms.length > 1 && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveRoom(roomIndex) }, "Verwijder reisgezelschap")))),
|
|
23756
|
-
room.adults.map((travelerValues, index) => (React__default["default"].createElement("div", { className: "form__region", key: travelerValues.id },
|
|
23757
|
-
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23758
|
-
React__default["default"].createElement("h5", { className: "form__region-heading" },
|
|
23759
|
-
translations.TRAVELERS_FORM.TRAVELER,
|
|
23760
|
-
" ",
|
|
23761
|
-
index + 1),
|
|
23762
|
-
React__default["default"].createElement("p", { className: "form__region-label" }, translations.TRAVELERS_FORM.ADULT),
|
|
23763
|
-
React__default["default"].createElement("div", { className: "radiobutton" },
|
|
23764
|
-
React__default["default"].createElement("label", { className: "radiobutton__label" },
|
|
23765
|
-
React__default["default"].createElement("input", { type: "radio", name: "mainBookerId", onChange: handleMainBookerChange, onBlur: formik.handleBlur, value: travelerValues.id, checked: formik.values.mainBookerId === travelerValues.id, className: "radiobutton__input" }),
|
|
23766
|
-
translations.TRAVELERS_FORM.MAIN_BOOKER))),
|
|
23767
|
-
renderTravelerFields(travelerValues, `rooms[${roomIndex}].adults[${index}]`, true, roomIndex, index)))),
|
|
23768
|
-
room.children.map((travelerValues, index) => (React__default["default"].createElement("div", { className: "form__region", key: travelerValues.id },
|
|
23769
|
-
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23770
|
-
React__default["default"].createElement("h5", { className: "form__region-heading" },
|
|
23771
|
-
translations.TRAVELERS_FORM.TRAVELER,
|
|
23772
|
-
" ",
|
|
23773
|
-
room.adults.length + index + 1),
|
|
23774
|
-
React__default["default"].createElement("p", { className: "form__region-label" }, travelerValues.isBaby ? translations.TRAVELERS_FORM.BABY : translations.TRAVELERS_FORM.CHILD)),
|
|
23775
|
-
renderTravelerFields(travelerValues, `rooms[${roomIndex}].children[${index}]`, false, roomIndex, index)))),
|
|
23776
|
-
!useCompactForm && travelersFirstStep && (React__default["default"].createElement("div", { className: "form__region" },
|
|
23777
|
-
React__default["default"].createElement("button", { type: "button", className: "cta cta--select", onClick: () => handleAddTraveler(roomIndex) }, translations.TRAVELERS_FORM.ADD_TRAVELER)))))),
|
|
23778
|
-
!useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default["default"].createElement("div", { className: "form__region" },
|
|
23779
|
-
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23780
|
-
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
|
|
23781
|
-
React__default["default"].createElement("p", { className: "form__region-label" }, lodash.compact([lodash.compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
|
|
23782
|
-
travellersSettings?.mainBookerFormFields?.length ? (React__default["default"].createElement("div", { className: "main-booker-form__grid" }, travellersSettings.mainBookerFormFields.map((field, index) => (React__default["default"].createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, {}, field.type)))))) : (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23783
|
-
React__default["default"].createElement("div", { className: "form__twocolumn" },
|
|
23784
|
-
React__default["default"].createElement("div", { className: "form__twocolumn-column" },
|
|
23785
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23786
|
-
React__default["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 }),
|
|
23787
|
-
React__default["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 }),
|
|
23788
|
-
React__default["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 }))),
|
|
23789
|
-
React__default["default"].createElement("div", { className: "form__twocolumn-column" },
|
|
23790
|
-
React__default["default"].createElement("div", { className: "form__row" },
|
|
23791
|
-
React__default["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 }),
|
|
23792
|
-
React__default["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 }),
|
|
23793
|
-
React__default["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 })))),
|
|
24154
|
+
const translations = reactRedux.useSelector(selectTranslations);
|
|
24155
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
24156
|
+
isSubmitting && (settings.loaderComponent || React__default["default"].createElement(Loader, null)),
|
|
24157
|
+
!isSubmitting && (React__default["default"].createElement("form", { className: "form", name: "booking--summary", id: "booking--summary", onSubmit: handleSubmit },
|
|
24158
|
+
React__default["default"].createElement("div", { className: "form__booking--summary" },
|
|
24159
|
+
React__default["default"].createElement("div", { className: "form__region" },
|
|
23794
24160
|
React__default["default"].createElement("div", { className: "form__row" },
|
|
23795
|
-
React__default["default"].createElement(
|
|
23796
|
-
|
|
23797
|
-
|
|
23798
|
-
|
|
23799
|
-
|
|
23800
|
-
|
|
23801
|
-
|
|
23802
|
-
|
|
23803
|
-
|
|
23804
|
-
|
|
23805
|
-
|
|
23806
|
-
|
|
23807
|
-
|
|
23808
|
-
|
|
23809
|
-
|
|
23810
|
-
|
|
23811
|
-
|
|
23812
|
-
|
|
23813
|
-
|
|
23814
|
-
|
|
23815
|
-
|
|
23816
|
-
|
|
23817
|
-
|
|
23818
|
-
|
|
23819
|
-
|
|
23820
|
-
|
|
23821
|
-
|
|
24161
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24162
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
24163
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.PERSONAL_DETAILS)))),
|
|
24164
|
+
rooms.map((r, rIndex) => (React__default["default"].createElement("div", { className: "form__row", key: rIndex },
|
|
24165
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24166
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
24167
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" }, rooms.length > 1 ? `${translations.SHARED.ROOM} ${rIndex + 1}` : translations.ROOM_OPTIONS_FORM.TRAVELER_GROUP),
|
|
24168
|
+
React__default["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}: ${lodash.compact([
|
|
24169
|
+
r.adults.length,
|
|
24170
|
+
r.adults.length === 1 && ` ${translations.SUMMARY.ADULT}`,
|
|
24171
|
+
r.adults.length > 1 && ` ${translations.SUMMARY.ADULTS}`,
|
|
24172
|
+
r.adults && r.adults.length && r.children && r.children.length && ', ',
|
|
24173
|
+
r.children.length,
|
|
24174
|
+
r.children.length === 1 && ` ${translations.SUMMARY.CHILD}`,
|
|
24175
|
+
r.children.length > 1 && ` ${translations.SUMMARY.CHILDREN}`
|
|
24176
|
+
]).join('')}`))),
|
|
24177
|
+
[...r.adults, ...r.children].map((traveler) => {
|
|
24178
|
+
const isMainBooker = traveler.id === travelerFormValues?.mainBookerId;
|
|
24179
|
+
return (React__default["default"].createElement("div", { className: "form__group form__group--sm-50", key: traveler.id },
|
|
24180
|
+
React__default["default"].createElement("ul", { className: "list list--plain" },
|
|
24181
|
+
React__default["default"].createElement("li", { className: "list__item" },
|
|
24182
|
+
React__default["default"].createElement("strong", null,
|
|
24183
|
+
traveler.firstName,
|
|
24184
|
+
" ",
|
|
24185
|
+
traveler.lastName),
|
|
24186
|
+
' ',
|
|
24187
|
+
isMainBooker && React__default["default"].createElement("em", null,
|
|
24188
|
+
"(",
|
|
24189
|
+
translations.SUMMARY.MAIN_BOOKER,
|
|
24190
|
+
")")),
|
|
24191
|
+
React__default["default"].createElement("li", { className: "list__item" }, traveler.birthDate.split('-').reverse().join('/')),
|
|
24192
|
+
isMainBooker && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
24193
|
+
travelerFormValues?.street && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
24194
|
+
React__default["default"].createElement("li", { className: "list__item" }, `${travelerFormValues?.street} ${lodash.compact([
|
|
24195
|
+
travelerFormValues?.houseNumber,
|
|
24196
|
+
travelerFormValues?.box
|
|
24197
|
+
]).join(' ')}, ${travelerFormValues?.zipCode} ${travelerFormValues?.place}`))),
|
|
24198
|
+
travelerFormValues?.phone && React__default["default"].createElement("li", { className: "list__item" }, travelerFormValues?.phone),
|
|
24199
|
+
travelerFormValues?.email && React__default["default"].createElement("li", { className: "list__item" }, travelerFormValues?.email))))));
|
|
24200
|
+
}))))),
|
|
24201
|
+
React__default["default"].createElement("div", { className: "form__region" },
|
|
24202
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24203
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24204
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
24205
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.OPTIONS)))),
|
|
24206
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24207
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24208
|
+
React__default["default"].createElement("ul", { className: "list list--booking-summary" }, activeOption?.serviceType == build.ServiceType.flight ? (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
24209
|
+
departureFlightMetaData && React__default["default"].createElement(SummaryFlight, { flightMetaData: departureFlightMetaData, header: translations.SIDEBAR.DEPARTURE_FLIGHT }),
|
|
24210
|
+
returnFlightMetaData && React__default["default"].createElement(SummaryFlight, { flightMetaData: returnFlightMetaData, header: translations.SIDEBAR.ARRIVAL_FLIGHT }))) : (React__default["default"].createElement(React__default["default"].Fragment, null, activeOption?.rooms
|
|
24211
|
+
.flatMap((r) => r.options)
|
|
24212
|
+
.filter((x) => x.isSelected)
|
|
24213
|
+
.map((roomOption, roomOptionIndex) => (React__default["default"].createElement(React__default["default"].Fragment, { key: roomOptionIndex },
|
|
24214
|
+
React__default["default"].createElement("li", null,
|
|
24215
|
+
React__default["default"].createElement("h6", null, roomOption?.productName),
|
|
24216
|
+
React__default["default"].createElement("ul", null,
|
|
24217
|
+
React__default["default"].createElement("li", { className: "list__item" },
|
|
24218
|
+
roomOption?.accommodationName,
|
|
24219
|
+
!lodash.isNil(roomOption?.regimeName) && ', ',
|
|
24220
|
+
roomOption?.regimeName)),
|
|
24221
|
+
React__default["default"].createElement("p", null,
|
|
24222
|
+
"(",
|
|
24223
|
+
roomOption?.from === roomOption?.to ? (getDateText(roomOption?.from)) : (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
24224
|
+
getDateText(roomOption?.from),
|
|
24225
|
+
" > ",
|
|
24226
|
+
getDateText(roomOption?.to))),
|
|
24227
|
+
")")),
|
|
24228
|
+
!lodash.isEmpty(activeOption?.groups) &&
|
|
24229
|
+
activeOption?.groups.map((x, i) => {
|
|
24230
|
+
if (!x.options.some((y) => y.isSelected))
|
|
24231
|
+
return;
|
|
24232
|
+
return React__default["default"].createElement(SummaryPerBookingOptionGroup, { key: i, group: x });
|
|
24233
|
+
}),
|
|
24234
|
+
!lodash.isEmpty(activeOption?.optionUnits) && activeOption?.optionUnits.map((x, i) => React__default["default"].createElement(SummaryBookingOptionUnit, { key: i, unit: x })),
|
|
24235
|
+
!lodash.isEmpty(activeOption?.optionPax) && activeOption?.optionPax.map((x, i) => React__default["default"].createElement(SummaryBookingOptionPax, { key: i, pax: x })),
|
|
24236
|
+
packageDetails?.outwardFlights &&
|
|
24237
|
+
packageDetails.outwardFlights
|
|
24238
|
+
.filter((x) => x.isSelected)
|
|
24239
|
+
.map((flight, i) => (React__default["default"].createElement(SummaryFlight, { key: i, flightMetaData: flight.flightMetaData, header: translations.SIDEBAR.DEPARTURE_FLIGHT }))),
|
|
24240
|
+
packageDetails?.returnFlights &&
|
|
24241
|
+
packageDetails.returnFlights
|
|
24242
|
+
.filter((x) => x.isSelected)
|
|
24243
|
+
.map((flight, i) => (React__default["default"].createElement(SummaryFlight, { key: i, flightMetaData: flight.flightMetaData, header: translations.SIDEBAR.ARRIVAL_FLIGHT })))))))))))),
|
|
24244
|
+
settings.enableVoucher && (React__default["default"].createElement("div", { className: "form__region" },
|
|
24245
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24246
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24247
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
24248
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.VOUCHERS)))),
|
|
24249
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24250
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24251
|
+
React__default["default"].createElement("input", { type: "text", className: "form__input info-message__voucher__input", defaultValue: voucher.code, onChange: (e) => setVoucher({ code: e.target.value }) }),
|
|
24252
|
+
React__default["default"].createElement("button", { type: "button", className: buildClassName(['cta', !voucher.code && 'cta--disabled']), onClick: (e) => handleValidateVoucher() }, translations.SUMMARY.VOUCHER_VALIDATE))),
|
|
24253
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24254
|
+
React__default["default"].createElement("div", { className: "form__group info-message__voucher" },
|
|
24255
|
+
voucher.isValid && voucher.isValidated && (React__default["default"].createElement("div", { className: "info-message info-message__voucher__valid" },
|
|
24256
|
+
React__default["default"].createElement("span", null, translations.SUMMARY.VOUCHER_VALID),
|
|
24257
|
+
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: handleAddVoucher }, translations.SUMMARY.ADD_VOUCHER))),
|
|
24258
|
+
!voucher.isValid && voucher.isValidated && React__default["default"].createElement("div", { className: "info-message--error" }, translations.SUMMARY.VOUCHER_INVALID))),
|
|
24259
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24260
|
+
React__default["default"].createElement("ul", { className: "info-message__voucher" }, !lodash.isEmpty(bookRequest?.payload.voucherCodes) &&
|
|
24261
|
+
bookRequest?.payload.voucherCodes?.map((y, i) => (React__default["default"].createElement("li", { key: i },
|
|
24262
|
+
React__default["default"].createElement("div", { className: "info-message__voucher__list" },
|
|
24263
|
+
y,
|
|
24264
|
+
' ',
|
|
24265
|
+
React__default["default"].createElement("button", { type: "button", className: "cta--add-remove", onClick: (e) => handleRemoveVoucher(y) },
|
|
24266
|
+
React__default["default"].createElement(Icon, { height: 16, name: "ui-trashcan" })))))))))),
|
|
24267
|
+
!lodash.isEmpty(notifications) && (React__default["default"].createElement("div", { className: "form__region" },
|
|
24268
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24269
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24270
|
+
React__default["default"].createElement("div", { className: "info-message" },
|
|
24271
|
+
React__default["default"].createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
|
|
24272
|
+
React__default["default"].createElement("div", { className: "info-message__copy" },
|
|
24273
|
+
React__default["default"].createElement("h5", null, translations.SUMMARY.NOTIFICATIONS_TITLE),
|
|
24274
|
+
React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
24275
|
+
lodash.uniqBy(notifications.filter((x) => !x.hasToBeConfirmed), 'id').map((notification) => (React__default["default"].createElement("span", { key: notification.id, className: "checkbox__label-text" },
|
|
24276
|
+
React__default["default"].createElement("strong", { className: "checkbox__label-text--title" }, notification.title),
|
|
24277
|
+
React__default["default"].createElement("span", { className: "checkbox__label-text--description" }, notification.description)))),
|
|
24278
|
+
lodash.uniqBy(notifications.filter((x) => x.hasToBeConfirmed), 'id').map((notification) => (React__default["default"].createElement("div", { className: "checkbox", key: notification.id },
|
|
24279
|
+
React__default["default"].createElement("label", { className: "checkbox__label" },
|
|
24280
|
+
React__default["default"].createElement("input", { type: "checkbox", className: "checkbox__input", checked: notification.isConfirmed, onChange: (e) => handleNotificationChange(notification.id, e.target.checked) }),
|
|
24281
|
+
React__default["default"].createElement("span", { className: "checkbox__label-text" },
|
|
24282
|
+
React__default["default"].createElement("strong", { className: "checkbox__label-text--title" }, notification.title),
|
|
24283
|
+
React__default["default"].createElement("span", { className: "checkbox__label-text--description" }, notification.description))))))))))))),
|
|
24284
|
+
React__default["default"].createElement("div", { className: "form__region" },
|
|
24285
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24286
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24287
|
+
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
24288
|
+
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.SUMMARY.REMARKS)))),
|
|
24289
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24290
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24291
|
+
React__default["default"].createElement("textarea", { className: "form__input", defaultValue: remarks, onChange: (e) => handleRemarksChange(e.target.value) })))),
|
|
24292
|
+
React__default["default"].createElement("div", { className: "form__region" },
|
|
24293
|
+
React__default["default"].createElement("div", { className: "form__row" },
|
|
24294
|
+
React__default["default"].createElement("div", { className: "form__group" },
|
|
24295
|
+
React__default["default"].createElement("div", { className: "info-message" },
|
|
24296
|
+
React__default["default"].createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
|
|
24297
|
+
React__default["default"].createElement("div", { className: "info-message__copy" },
|
|
24298
|
+
React__default["default"].createElement("h5", null, translations.SUMMARY.VALIDATE_TITLE),
|
|
24299
|
+
settings.customValidateText ? (React__default["default"].createElement("div", { dangerouslySetInnerHTML: {
|
|
24300
|
+
__html: settings.customValidateText
|
|
24301
|
+
} })) : (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
24302
|
+
React__default["default"].createElement("p", null, settings.isOffer ? translations.SUMMARY.VALIDATE_TEXT_OFFER : translations.SUMMARY.VALIDATE_TEXT_BOOKING),
|
|
24303
|
+
settings.allowOption && React__default["default"].createElement("p", null, translations.SUMMARY.VALIDATE_TEXT_OPTION))),
|
|
24304
|
+
checkboxes &&
|
|
24305
|
+
checkboxes.map((checkbox) => (React__default["default"].createElement("div", { className: "checkbox", key: checkbox.id },
|
|
24306
|
+
React__default["default"].createElement("label", { className: "checkbox__label" },
|
|
24307
|
+
React__default["default"].createElement("input", { type: "checkbox", className: "checkbox__input", checked: checkbox.isSelected, onChange: (e) => handleCheckboxChange(checkbox.id, e.target.checked) }),
|
|
24308
|
+
React__default["default"].createElement("span", { className: "checkbox__label-text", dangerouslySetInnerHTML: {
|
|
24309
|
+
__html: checkbox.text
|
|
24310
|
+
} }))))))))))),
|
|
24311
|
+
React__default["default"].createElement("div", { className: "booking__navigator" },
|
|
24312
|
+
settings.skipRouter ? (React__default["default"].createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => goPrevious(), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : (React__default["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)),
|
|
24313
|
+
settings.allowOption && (React__default["default"].createElement("button", { title: translations.STEPS.SUBMIT_OPTION, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "option" }, translations.STEPS.SUBMIT_OPTION)),
|
|
24314
|
+
React__default["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))))));
|
|
23822
24315
|
};
|
|
23823
24316
|
|
|
23824
24317
|
function isValidEmail(email) {
|
|
@@ -23842,7 +24335,7 @@ function getAge(birthDateText, startDateText) {
|
|
|
23842
24335
|
}
|
|
23843
24336
|
return age;
|
|
23844
24337
|
}
|
|
23845
|
-
const validateForm$1 = (values, agentRequired, bookingType, translations, formFields, mainBookerFormFields, maxChildAge = CHILD_MAX_AGE, maxBabyAge = BABY_MAX_AGE,
|
|
24338
|
+
const validateForm$1 = (values, agentRequired, bookingType, translations, formFields, mainBookerFormFields, maxChildAge = CHILD_MAX_AGE, maxBabyAge = BABY_MAX_AGE, paxFields = []) => {
|
|
23846
24339
|
const errors = {};
|
|
23847
24340
|
const isFormFieldPresent = (type) => {
|
|
23848
24341
|
return formFields?.some((f) => f.type === type) ?? true;
|
|
@@ -23880,7 +24373,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
23880
24373
|
};
|
|
23881
24374
|
const validateRequiredCustomFields = (traveler, path, room, pax) => {
|
|
23882
24375
|
const isMainBooker = traveler.id === values.mainBookerId;
|
|
23883
|
-
const requiredFields = getApplicablePaxCustomFields(
|
|
24376
|
+
const requiredFields = getApplicablePaxCustomFields(paxFields, isMainBooker).filter((f) => f.isRequired);
|
|
23884
24377
|
requiredFields.forEach((field) => {
|
|
23885
24378
|
const fieldIndex = traveler.customFields?.findIndex((c) => c.customFieldConfigurationId === field.customFieldConfigurationId) ?? -1;
|
|
23886
24379
|
if (fieldIndex < 0)
|
|
@@ -23890,6 +24383,19 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
23890
24383
|
}
|
|
23891
24384
|
});
|
|
23892
24385
|
};
|
|
24386
|
+
// Excludes the 4 core fields, which are already validated unconditionally below.
|
|
24387
|
+
const validateRequiredBuiltInFields = (traveler, path, room, pax) => {
|
|
24388
|
+
const isMainBooker = traveler.id === values.mainBookerId;
|
|
24389
|
+
const requiredFields = getApplicableBuiltInPaxFields(paxFields, isMainBooker).filter((f) => f.isRequired && !CORE_FIELD_NAMES.has(f.fieldName));
|
|
24390
|
+
requiredFields.forEach((field) => {
|
|
24391
|
+
const fieldPath = BUILT_IN_FIELD_PATHS[field.fieldName];
|
|
24392
|
+
if (!fieldPath)
|
|
24393
|
+
return;
|
|
24394
|
+
if (lodash.isEmpty(lodash.get(traveler, fieldPath))) {
|
|
24395
|
+
lodash.set(errors, `${path}.${fieldPath}`, formatTravelerField(room, pax, field.fieldName));
|
|
24396
|
+
}
|
|
24397
|
+
});
|
|
24398
|
+
};
|
|
23893
24399
|
values.rooms.forEach((r, rIndex) => r.adults.forEach((adult, index) => {
|
|
23894
24400
|
if (lodash.isEmpty(adult.gender) && isFormFieldPresent('gender')) {
|
|
23895
24401
|
lodash.set(errors, `rooms[${rIndex}].adults[${index}].gender`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.GENDER));
|
|
@@ -23923,6 +24429,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
23923
24429
|
}
|
|
23924
24430
|
}
|
|
23925
24431
|
validateRequiredCustomFields(adult, `rooms[${rIndex}].adults[${index}]`, rIndex + 1, index + 1);
|
|
24432
|
+
validateRequiredBuiltInFields(adult, `rooms[${rIndex}].adults[${index}]`, rIndex + 1, index + 1);
|
|
23926
24433
|
}));
|
|
23927
24434
|
values.rooms.forEach((r, rIndex) => r.children.forEach((child, index) => {
|
|
23928
24435
|
if (lodash.isEmpty(child.gender) && isFormFieldPresent('gender')) {
|
|
@@ -23965,6 +24472,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
23965
24472
|
}
|
|
23966
24473
|
}
|
|
23967
24474
|
validateRequiredCustomFields(child, `rooms[${rIndex}].children[${index}]`, rIndex + 1, r.adults.length + index + 1);
|
|
24475
|
+
validateRequiredBuiltInFields(child, `rooms[${rIndex}].children[${index}]`, rIndex + 1, r.adults.length + index + 1);
|
|
23968
24476
|
}));
|
|
23969
24477
|
if (values.mainBookerId < 0) {
|
|
23970
24478
|
errors.mainBookerId = translations.TRAVELERS_FORM.VALIDATION.NO_MAIN_BOOKER_SELECTED;
|
|
@@ -24032,15 +24540,13 @@ const TravelersForm = () => {
|
|
|
24032
24540
|
const bookingAttributes = reactRedux.useSelector(selectBookingAttributes);
|
|
24033
24541
|
const hasMounted = reactRedux.useSelector(selectHasMounted);
|
|
24034
24542
|
const countries = reactRedux.useSelector(selectCountries);
|
|
24035
|
-
const
|
|
24543
|
+
const paxFields = reactRedux.useSelector(selectPaxFields);
|
|
24036
24544
|
const inFlight = React.useRef(false);
|
|
24037
24545
|
const pendingRefetch = React.useRef(false);
|
|
24038
24546
|
const useCompactForm = !!settings.travellers.compactForm && !!settings.agentAdressId;
|
|
24039
24547
|
const showAllCountries = !!settings.travellers.showAllCountries;
|
|
24040
|
-
const showWeightField = !!settings.travellers.showWeightField;
|
|
24041
|
-
const showHeightField = !!settings.travellers.showHeightField;
|
|
24042
24548
|
const initialValues = reactRedux.useSelector(selectTravelersFormValues) ??
|
|
24043
|
-
createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm, settings.maxBabyAge,
|
|
24549
|
+
createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm, settings.maxBabyAge, paxFields);
|
|
24044
24550
|
const [showAgentSelection, setShowAgentSelection] = React.useState(!settings.agentAdressId && !settings.hideAgentSelection);
|
|
24045
24551
|
const formik$1 = formik.useFormik({
|
|
24046
24552
|
initialValues,
|
|
@@ -24050,7 +24556,7 @@ const TravelersForm = () => {
|
|
|
24050
24556
|
// The travel dates are captured into initialValues once and then persisted in
|
|
24051
24557
|
// redux, so validating against the values would use the dates of whichever
|
|
24052
24558
|
// package option was selected first. Age checks need the current ones.
|
|
24053
|
-
{ ...values, startDate, endDate }, settings.agentRequired, bookingType, translations, settings.travellers.formFields, settings.travellers.mainBookerFormFields, settings.maxChildAge, settings.maxBabyAge,
|
|
24559
|
+
{ ...values, startDate, endDate }, settings.agentRequired, bookingType, translations, settings.travellers.formFields, settings.travellers.mainBookerFormFields, settings.maxChildAge, settings.maxBabyAge, paxFields),
|
|
24054
24560
|
onSubmit: (values) => {
|
|
24055
24561
|
dispatch(setFormValues(values));
|
|
24056
24562
|
if (useCompactForm) {
|
|
@@ -24133,7 +24639,7 @@ const TravelersForm = () => {
|
|
|
24133
24639
|
dispatch(setFormValues(formValues));
|
|
24134
24640
|
setShowAgentSelection(false);
|
|
24135
24641
|
}, [agents, settings.affiliateSlug]);
|
|
24136
|
-
return (React__default["default"].createElement(SharedTravelersForm, { formik: formik$1, translations: translations, travellersSettings: settings.travellers, countries: countries, agents: agents, bookingType: bookingType, agentAdressId: agentAdressId, travelersFirstStep: travelersFirstStep, isUnavailable: isUnavailable, useCompactForm: useCompactForm, showAllCountries: showAllCountries,
|
|
24642
|
+
return (React__default["default"].createElement(SharedTravelersForm, { formik: formik$1, 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["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["default"].createElement(Link, { to: `${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.options.pathSuffix}?${bookingQueryString}`, title: translations.STEPS.PREVIOUS, className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : null }));
|
|
24137
24643
|
};
|
|
24138
24644
|
|
|
24139
24645
|
const Booking = ({ productCode, productName, thumbnailUrl }) => {
|
|
@@ -28280,6 +28786,22 @@ const getPackagingRequestRoomsFromBookingRooms = (rooms) => {
|
|
|
28280
28786
|
});
|
|
28281
28787
|
};
|
|
28282
28788
|
|
|
28789
|
+
// Administrative service lines (fees, insurances, reductions, ...) live on the entry but say
|
|
28790
|
+
// nothing about the journey itself, so the itinerary never draws them.
|
|
28791
|
+
const HIDDEN_ITINERARY_SERVICE_TYPES = new Set([
|
|
28792
|
+
build.ServiceType.insurance,
|
|
28793
|
+
build.ServiceType.extraService,
|
|
28794
|
+
build.ServiceType.serviceFee,
|
|
28795
|
+
build.ServiceType.gift,
|
|
28796
|
+
build.ServiceType.reduction,
|
|
28797
|
+
build.ServiceType.fee,
|
|
28798
|
+
build.ServiceType.visum,
|
|
28799
|
+
build.ServiceType.voucher,
|
|
28800
|
+
build.ServiceType.specialServices
|
|
28801
|
+
]);
|
|
28802
|
+
const isMeaningfulItineraryLine = (line) => {
|
|
28803
|
+
return !HIDDEN_ITINERARY_SERVICE_TYPES.has(line.serviceType ?? -1);
|
|
28804
|
+
};
|
|
28283
28805
|
const getFlightLines = (flight) => {
|
|
28284
28806
|
return flight?.flightInformation?.flightLines ?? [];
|
|
28285
28807
|
};
|
|
@@ -28734,6 +29256,8 @@ const applyResultToLine = (line, result, roomIndex = 0) => {
|
|
|
28734
29256
|
isChanged: true
|
|
28735
29257
|
};
|
|
28736
29258
|
};
|
|
29259
|
+
const buildNodeSelectionLines = (item, result, bookedMode) => bookedMode && matchesCode(result, item.node.code ?? '') ? item.lines : applyResultToLines(item.lines, result);
|
|
29260
|
+
const buildFlightSelectionLine = (item, flight, bookedMode) => bookedMode && flight.outwardGuid === item.line.guid ? item.line : applyFlightToLine(item.line, flight);
|
|
28737
29261
|
const toDateOnlyUtcString = (value) => {
|
|
28738
29262
|
const date = new Date(value);
|
|
28739
29263
|
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
|
|
@@ -28791,11 +29315,21 @@ const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
|
28791
29315
|
* mapper gave them. This swaps in the guid of whatever each line resolved onto, leaving the
|
|
28792
29316
|
* lines the traveller added themselves alone — those were built from a search result and already
|
|
28793
29317
|
* carry the right one.
|
|
29318
|
+
*
|
|
29319
|
+
* A booked entry (the traject was rebuilt from a magic-link entry) is the other way around: its
|
|
29320
|
+
* lines live in the dossier under their own guids, and only a line the traveller actually swapped
|
|
29321
|
+
* (isChanged) exists in the search cache. Swapping an untouched line's guid would orphan it —
|
|
29322
|
+
* the backend drops the dossier line and finds nothing to add — so those keep theirs.
|
|
28794
29323
|
*/
|
|
28795
29324
|
const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightAvailability) => {
|
|
28796
29325
|
const cachedGuids = new Map();
|
|
29326
|
+
const bookedMode = !!trajectEntry.entry.magicLink;
|
|
29327
|
+
const editableByGuid = new Map((entry.lines ?? []).map((line) => [line.guid, line]));
|
|
29328
|
+
const keepsOwnGuid = (guid) => bookedMode && !editableByGuid.get(guid)?.isChanged;
|
|
28797
29329
|
getTrajectNodesWithLines(trajectEntry).forEach((item) => {
|
|
28798
29330
|
if (isTrajectFlightNode(item.node)) {
|
|
29331
|
+
if (keepsOwnGuid(item.line.guid))
|
|
29332
|
+
return;
|
|
28799
29333
|
// A flight search caches the outward line under the guid it reports as outwardGuid.
|
|
28800
29334
|
const guid = flightAvailability[item.line.guid]?.selectedGuid;
|
|
28801
29335
|
if (guid)
|
|
@@ -28808,6 +29342,8 @@ const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightA
|
|
|
28808
29342
|
return;
|
|
28809
29343
|
// Room i took option i when the result was stamped on, so it takes option i here too.
|
|
28810
29344
|
item.lines.forEach((line, index) => {
|
|
29345
|
+
if (keepsOwnGuid(line.guid))
|
|
29346
|
+
return;
|
|
28811
29347
|
const guid = getOptionForRoom(result, index)?.guid;
|
|
28812
29348
|
if (guid)
|
|
28813
29349
|
cachedGuids.set(line.guid, guid);
|
|
@@ -28871,7 +29407,7 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
|
|
|
28871
29407
|
return { node, lines };
|
|
28872
29408
|
});
|
|
28873
29409
|
const claimed = new Set(nodes.flatMap((item) => item.lines.map((line) => line.guid)));
|
|
28874
|
-
const extras = (packagingEntry.lines ?? []).filter((line) => !claimed.has(line.guid));
|
|
29410
|
+
const extras = (packagingEntry.lines ?? []).filter((line) => !claimed.has(line.guid)).filter(isMeaningfulItineraryLine);
|
|
28875
29411
|
if (!extras.length)
|
|
28876
29412
|
return nodes;
|
|
28877
29413
|
const dayOrderOf = (date) => trajectEntry.traject.days.find((day) => dateFns.isSameDay(new Date(day.date), new Date(date)))?.order ??
|
|
@@ -29048,6 +29584,195 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
|
|
|
29048
29584
|
})));
|
|
29049
29585
|
};
|
|
29050
29586
|
|
|
29587
|
+
/**
|
|
29588
|
+
* A booked entry opened through its magic link knows nothing about the traject it may once have
|
|
29589
|
+
* been composed from — the dossier only keeps the lines. To give it the same day-by-day services
|
|
29590
|
+
* screen a traject gets, the traject structure is rebuilt from those lines: every booked service
|
|
29591
|
+
* becomes a node whose one "alternative" is the booked product itself, and the days span the trip.
|
|
29592
|
+
*
|
|
29593
|
+
* The synthesized response keeps the entry untouched (magic link included), which is also how the
|
|
29594
|
+
* rest of the component tells this mode apart from a real traject: see isBookedEntryTraject.
|
|
29595
|
+
*/
|
|
29596
|
+
const isBookedEntryTraject = (trajectEntry) => !!trajectEntry?.entry?.magicLink;
|
|
29597
|
+
const NODE_SERVICE_TYPES = new Set([ACCOMMODATION_SERVICE_TYPE, EXCURSION_SERVICE_TYPE, FLIGHT_SERVICE_TYPE]);
|
|
29598
|
+
/**
|
|
29599
|
+
* A room or option line joins its parent's node; a flight line never does — an outward and its
|
|
29600
|
+
* return are separate legs of the trip even though the return points at the outward as parent.
|
|
29601
|
+
*/
|
|
29602
|
+
const groupNodeLines = (lines) => {
|
|
29603
|
+
const groups = [];
|
|
29604
|
+
const groupByGuid = new Map();
|
|
29605
|
+
lines.forEach((line) => {
|
|
29606
|
+
const parentGroup = line.serviceType !== FLIGHT_SERVICE_TYPE && line.parentGuid ? groupByGuid.get(line.parentGuid) : undefined;
|
|
29607
|
+
if (parentGroup) {
|
|
29608
|
+
parentGroup.push(line);
|
|
29609
|
+
return;
|
|
29610
|
+
}
|
|
29611
|
+
const group = [line];
|
|
29612
|
+
groups.push(group);
|
|
29613
|
+
groupByGuid.set(line.guid, group);
|
|
29614
|
+
});
|
|
29615
|
+
return groups;
|
|
29616
|
+
};
|
|
29617
|
+
const buildBookedTrajectEntry = (entry) => {
|
|
29618
|
+
const lines = (entry.lines ?? []).filter((line) => NODE_SERVICE_TYPES.has(line.serviceType));
|
|
29619
|
+
const froms = lines.map((line) => new Date(line.from).getTime());
|
|
29620
|
+
const tos = lines.map((line) => new Date(line.to).getTime());
|
|
29621
|
+
const start = froms.length ? new Date(Math.min(...froms)) : new Date();
|
|
29622
|
+
const end = tos.length ? new Date(Math.max(...tos)) : start;
|
|
29623
|
+
const dayCount = Math.max(dateFns.differenceInCalendarDays(end, start), 0) + 1;
|
|
29624
|
+
const days = Array.from({ length: dayCount }, (_, order) => ({
|
|
29625
|
+
order,
|
|
29626
|
+
name: '',
|
|
29627
|
+
date: toDateOnlyString(dateFns.addDays(start, order))
|
|
29628
|
+
}));
|
|
29629
|
+
const nodes = groupNodeLines(lines).map((groupLines, index) => {
|
|
29630
|
+
const line = groupLines[0];
|
|
29631
|
+
const flightLines = line.flightInformation?.flightLines ?? [];
|
|
29632
|
+
return {
|
|
29633
|
+
lineGuid: line.guid,
|
|
29634
|
+
lineGuids: groupLines.map((x) => x.guid),
|
|
29635
|
+
nodeId: index + 1,
|
|
29636
|
+
dayOrder: Math.max(dateFns.differenceInCalendarDays(new Date(line.from), start), 0),
|
|
29637
|
+
order: line.order,
|
|
29638
|
+
name: line.productName,
|
|
29639
|
+
serviceType: line.serviceType,
|
|
29640
|
+
trajectNodeType: REGULAR_TRAJECT_NODE_TYPE,
|
|
29641
|
+
requirementType: 0,
|
|
29642
|
+
contentSource: 0,
|
|
29643
|
+
code: line.productCode,
|
|
29644
|
+
preferredAccommodationCode: line.productCode,
|
|
29645
|
+
preferredAccommodationName: line.productName,
|
|
29646
|
+
alternatives: [],
|
|
29647
|
+
departureAirportCode: lodash.first(flightLines)?.departureAirportCode ?? null,
|
|
29648
|
+
arrivalAirportCode: lodash.last(flightLines)?.arrivalAirportCode ?? null,
|
|
29649
|
+
duration: 0,
|
|
29650
|
+
durationType: 0,
|
|
29651
|
+
from: line.from,
|
|
29652
|
+
to: line.to
|
|
29653
|
+
};
|
|
29654
|
+
});
|
|
29655
|
+
return {
|
|
29656
|
+
entry,
|
|
29657
|
+
traject: {
|
|
29658
|
+
id: 0,
|
|
29659
|
+
name: entry.dossierNumber ?? '',
|
|
29660
|
+
imageUrl: null,
|
|
29661
|
+
startDate: days[0]?.date ?? toDateOnlyString(start),
|
|
29662
|
+
endDate: lodash.last(days)?.date ?? toDateOnlyString(end),
|
|
29663
|
+
durationInDays: days.length,
|
|
29664
|
+
includeGroupHotelAlternatives: false,
|
|
29665
|
+
days
|
|
29666
|
+
},
|
|
29667
|
+
nodes
|
|
29668
|
+
};
|
|
29669
|
+
};
|
|
29670
|
+
/**
|
|
29671
|
+
* The card for a booked service when no search result carries it any more (sold out, delisted).
|
|
29672
|
+
* Rendered from the line, so the traveller still sees what they booked; price 0 makes the card
|
|
29673
|
+
* leave its price out — the paid price lives in the price details, not on the line.
|
|
29674
|
+
*/
|
|
29675
|
+
const buildBookedNodeResult = (node, lines) => {
|
|
29676
|
+
const line = lines[0];
|
|
29677
|
+
return {
|
|
29678
|
+
code: line.productCode,
|
|
29679
|
+
name: line.productName,
|
|
29680
|
+
serviceType: line.serviceType,
|
|
29681
|
+
countryId: line.country?.id ?? null,
|
|
29682
|
+
countryName: line.country?.name ?? '',
|
|
29683
|
+
regionId: line.region?.id ?? null,
|
|
29684
|
+
regionName: line.region?.name ?? '',
|
|
29685
|
+
oordId: line.oord?.id ?? null,
|
|
29686
|
+
oordName: line.oord?.name ?? '',
|
|
29687
|
+
locationId: line.location?.id ?? null,
|
|
29688
|
+
locationName: line.location?.name ?? '',
|
|
29689
|
+
latitude: line.latitude ?? null,
|
|
29690
|
+
longitude: line.longitude ?? null,
|
|
29691
|
+
price: 0,
|
|
29692
|
+
averagePricePerPerson: 0,
|
|
29693
|
+
originalPrice: 0,
|
|
29694
|
+
originalAveragePricePerPerson: 0,
|
|
29695
|
+
currencyCode: 'EUR',
|
|
29696
|
+
fromDate: line.from,
|
|
29697
|
+
toDate: line.to,
|
|
29698
|
+
contents: '',
|
|
29699
|
+
rooms: lines.map((roomLine) => ({
|
|
29700
|
+
options: [
|
|
29701
|
+
{
|
|
29702
|
+
price: 0,
|
|
29703
|
+
originalPrice: 0,
|
|
29704
|
+
accommodationCode: roomLine.accommodationCode ?? '',
|
|
29705
|
+
accommodationName: roomLine.accommodationName ?? '',
|
|
29706
|
+
regimeCode: roomLine.regimeCode ?? '',
|
|
29707
|
+
regimeName: roomLine.regimeName ?? '',
|
|
29708
|
+
isSelected: true,
|
|
29709
|
+
guid: roomLine.guid,
|
|
29710
|
+
paxIds: (roomLine.pax ?? []).map((pax) => pax.paxId)
|
|
29711
|
+
}
|
|
29712
|
+
]
|
|
29713
|
+
}))
|
|
29714
|
+
};
|
|
29715
|
+
};
|
|
29716
|
+
/**
|
|
29717
|
+
* The flight search API serializes these as ISO strings, whatever the type declaration says, and
|
|
29718
|
+
* the store must stay serializable — so the synthesized segments carry the same string form.
|
|
29719
|
+
*/
|
|
29720
|
+
const toDateTime = (date, time) => `${toDateOnlyString(date)}T${time || '00:00:00'}`;
|
|
29721
|
+
/** The booked flight as a flight result, so the card that shows it is the card the search results use. */
|
|
29722
|
+
const buildBookedFlightResult = (line) => {
|
|
29723
|
+
const flightLines = line.flightInformation?.flightLines ?? [];
|
|
29724
|
+
const segments = flightLines.map((flightLine, index) => ({
|
|
29725
|
+
order: index,
|
|
29726
|
+
flightNumber: flightLine.flightNumber,
|
|
29727
|
+
operatingFlightNumber: flightLine.operatingFlightNumber ?? flightLine.flightNumber,
|
|
29728
|
+
marketingAirlineCode: flightLine.airlineCode,
|
|
29729
|
+
marketingAirlineName: flightLine.airlineDescription,
|
|
29730
|
+
operatingAirlineCode: flightLine.operatingAirlineCode ?? flightLine.airlineCode,
|
|
29731
|
+
operatingAirlineName: flightLine.operatingAirlineDescription ?? flightLine.airlineDescription,
|
|
29732
|
+
departureAirportCode: flightLine.departureAirportCode,
|
|
29733
|
+
departureAirportName: flightLine.departureAirportDescription,
|
|
29734
|
+
arrivalAirportCode: flightLine.arrivalAirportCode,
|
|
29735
|
+
arrivalAirportName: flightLine.arrivalAirportDescription,
|
|
29736
|
+
departureDateTime: toDateTime(flightLine.departureDate, flightLine.departureTime),
|
|
29737
|
+
arrivalDateTime: toDateTime(flightLine.arrivalDate, flightLine.arrivalTime),
|
|
29738
|
+
bookingClassCode: '',
|
|
29739
|
+
travelClass: 0,
|
|
29740
|
+
durationInTicks: flightLine.durationInTicks ?? 0
|
|
29741
|
+
}));
|
|
29742
|
+
const firstSegment = lodash.first(segments);
|
|
29743
|
+
const lastSegment = lodash.last(segments);
|
|
29744
|
+
// .NET ticks are 100ns, so a millisecond is 10 000 of them.
|
|
29745
|
+
const durationInTicks = firstSegment && lastSegment ? (new Date(lastSegment.arrivalDateTime).getTime() - new Date(firstSegment.departureDateTime).getTime()) * 10_000 : 0;
|
|
29746
|
+
return {
|
|
29747
|
+
code: line.productCode,
|
|
29748
|
+
name: line.productName,
|
|
29749
|
+
serviceType: line.serviceType,
|
|
29750
|
+
countryName: '',
|
|
29751
|
+
regionName: '',
|
|
29752
|
+
oordName: '',
|
|
29753
|
+
locationName: '',
|
|
29754
|
+
price: 0,
|
|
29755
|
+
averagePricePerPerson: 0,
|
|
29756
|
+
originalPrice: 0,
|
|
29757
|
+
originalAveragePricePerPerson: 0,
|
|
29758
|
+
currencyCode: 'EUR',
|
|
29759
|
+
fromDate: line.from,
|
|
29760
|
+
toDate: line.to,
|
|
29761
|
+
flightRouteId: line.guid,
|
|
29762
|
+
airlineCode: firstSegment?.marketingAirlineCode ?? '',
|
|
29763
|
+
airlineName: firstSegment?.marketingAirlineName ?? '',
|
|
29764
|
+
isLuggageIncluded: false,
|
|
29765
|
+
luggageInfo: '',
|
|
29766
|
+
outwardGuid: line.guid,
|
|
29767
|
+
outward: { code: line.productCode, fareType: 0, durationInTicks, segments },
|
|
29768
|
+
returnGuid: '',
|
|
29769
|
+
return: { code: '', fareType: 0, durationInTicks: 0, segments: [] },
|
|
29770
|
+
source: 0,
|
|
29771
|
+
provider: '',
|
|
29772
|
+
paxes: []
|
|
29773
|
+
};
|
|
29774
|
+
};
|
|
29775
|
+
|
|
29051
29776
|
const getSegmentIcon = (segment) => {
|
|
29052
29777
|
switch (segment.serviceType) {
|
|
29053
29778
|
case 3:
|
|
@@ -29087,14 +29812,14 @@ const SERVICE_TYPE_PRIORITY = {
|
|
|
29087
29812
|
const getServiceTypePriority = (serviceType) => {
|
|
29088
29813
|
return SERVICE_TYPE_PRIORITY[serviceType ?? -1] ?? 2;
|
|
29089
29814
|
};
|
|
29090
|
-
const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation }) => {
|
|
29815
|
+
const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation, onSaveEntry }) => {
|
|
29091
29816
|
const context = React.useContext(SearchResultsConfigurationContext);
|
|
29092
29817
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
29093
29818
|
const { editablePackagingEntry, priceDetails, trajectItineraryView } = reactRedux.useSelector((state) => state.searchResults);
|
|
29094
29819
|
const dispatch = reactRedux.useDispatch();
|
|
29095
29820
|
const packagingEntry = editablePackagingEntry ?? context?.packagingEntry;
|
|
29096
29821
|
const sortedLines = React.useMemo(() => {
|
|
29097
|
-
return
|
|
29822
|
+
return (packagingEntry?.lines ?? []).filter(isMeaningfulItineraryLine).sort((a, b) => {
|
|
29098
29823
|
const dateA = getDateOnlyTime(a.from);
|
|
29099
29824
|
const dateB = getDateOnlyTime(b.from);
|
|
29100
29825
|
if (dateA !== dateB) {
|
|
@@ -29165,7 +29890,7 @@ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation })
|
|
|
29165
29890
|
" ",
|
|
29166
29891
|
translations.SRP.TOTAL,
|
|
29167
29892
|
")"))),
|
|
29168
|
-
React__default["default"].createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM),
|
|
29893
|
+
isBookedEntryTraject(context?.trajectEntry) ? (React__default["default"].createElement("button", { className: "cta", onClick: onSaveEntry, disabled: !(packagingEntry?.lines ?? []).some((line) => line.isChanged) }, translations.SHARED.SAVE)) : (React__default["default"].createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM)),
|
|
29169
29894
|
!!context?.trajectEntry && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleTrajectView(!trajectItineraryView) }, trajectItineraryView ? translations.SRP.SHOW_SERVICES : translations.SRP.VIEW_FULL_ITINERARY))))),
|
|
29170
29895
|
React__default["default"].createElement("div", { className: "search__filter__itinerary" },
|
|
29171
29896
|
React__default["default"].createElement("p", null, translations.SRP.DAY_BY_DAY),
|
|
@@ -31222,7 +31947,7 @@ const selectSelectedCombinationFlight = toolkit.createSelector([selectPackagingF
|
|
|
31222
31947
|
return (packagingFlightResults.find((flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey && getFlightKey(flight.return.segments) === selectedReturnKey) ?? null);
|
|
31223
31948
|
});
|
|
31224
31949
|
|
|
31225
|
-
const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward, showSelectedState, currentSelectedPrice, price }) => {
|
|
31950
|
+
const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward, showSelectedState, currentSelectedPrice, price, selectLabel, selectedLabel }) => {
|
|
31226
31951
|
const context = React.useContext(SearchResultsConfigurationContext);
|
|
31227
31952
|
const language = context?.languageCode ?? 'en-GB';
|
|
31228
31953
|
const translations = getTranslations(language);
|
|
@@ -31247,7 +31972,7 @@ const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward
|
|
|
31247
31972
|
priceDifference > 0 ? '+' : '-',
|
|
31248
31973
|
"\u00A0",
|
|
31249
31974
|
formatPrice$3(Math.abs(priceDifference), 'EUR', context?.languageCode ?? 'en-GB'))))),
|
|
31250
|
-
React__default["default"].createElement("button", { type: "button", className: `cta ${selectedGuid === guid ? 'cta--selected' : 'cta--select'}`, onClick: () => onSelect?.() }, selectedGuid === guid ?
|
|
31975
|
+
React__default["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)))),
|
|
31251
31976
|
React__default["default"].createElement("div", { className: "flight__flight" },
|
|
31252
31977
|
React__default["default"].createElement("div", { className: "flight__flight__container" },
|
|
31253
31978
|
React__default["default"].createElement("div", { className: "flight__flight__wrapper" },
|
|
@@ -31881,7 +32606,7 @@ const TrajectNodeCard = ({ node, result, isSelected, languageCode, translations,
|
|
|
31881
32606
|
const image = candidate?.imageUrl ?? null;
|
|
31882
32607
|
const description = toPlainText(candidate?.description);
|
|
31883
32608
|
const title = candidate?.name ?? result.name;
|
|
31884
|
-
const priceBlock = (React__default["default"].createElement("div", { className: "search__result-card__price__wrapper" },
|
|
32609
|
+
const priceBlock = result.price > 0 && (React__default["default"].createElement("div", { className: "search__result-card__price__wrapper" },
|
|
31885
32610
|
React__default["default"].createElement("span", { className: "search__result-card__price__label" }, translations?.SHARED.TOTAL_PRICE),
|
|
31886
32611
|
React__default["default"].createElement("span", { className: "search__result-card__price" }, price)));
|
|
31887
32612
|
const canEditOptions = isSelected && !!onEditOptions && (result.rooms ?? []).some((room) => (room.options ?? []).length > 1);
|
|
@@ -31934,6 +32659,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
|
|
|
31934
32659
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
31935
32660
|
const { trajectNodeAvailability, trajectEditLineGuid } = reactRedux.useSelector((state) => state.searchResults);
|
|
31936
32661
|
const trajectEntry = context?.trajectEntry;
|
|
32662
|
+
const bookedMode = isBookedEntryTraject(trajectEntry);
|
|
31937
32663
|
const item = React.useMemo(() => {
|
|
31938
32664
|
if (!trajectEntry || !trajectEditLineGuid)
|
|
31939
32665
|
return null;
|
|
@@ -31953,7 +32679,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
|
|
|
31953
32679
|
if (!result)
|
|
31954
32680
|
return;
|
|
31955
32681
|
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
|
|
31956
|
-
|
|
32682
|
+
buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
31957
32683
|
dispatch(setTrajectEditLineGuid(null));
|
|
31958
32684
|
dispatch(setFlyInIsOpen(false));
|
|
31959
32685
|
};
|
|
@@ -31966,7 +32692,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
|
|
|
31966
32692
|
ordered.length,
|
|
31967
32693
|
"\u00A0",
|
|
31968
32694
|
translations.SRP.TOTAL_RESULTS_LABEL)),
|
|
31969
|
-
ordered.length === 0 ? (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default["default"].createElement("div", { className: "search__results__cards" }, ordered.map((result) => (React__default["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 })))))));
|
|
32695
|
+
ordered.length === 0 ? (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default["default"].createElement("div", { className: "search__results__cards" }, ordered.map((result) => (React__default["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 })))))));
|
|
31970
32696
|
};
|
|
31971
32697
|
|
|
31972
32698
|
/**
|
|
@@ -32028,6 +32754,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
32028
32754
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
32029
32755
|
const { trajectNodeAvailability, trajectDaySuggestions, trajectActivitiesDayOrder, editablePackagingEntry } = reactRedux.useSelector((state) => state.searchResults);
|
|
32030
32756
|
const trajectEntry = context?.trajectEntry;
|
|
32757
|
+
const bookedMode = isBookedEntryTraject(trajectEntry);
|
|
32031
32758
|
const items = React.useMemo(() => {
|
|
32032
32759
|
if (!trajectEntry || trajectActivitiesDayOrder === null)
|
|
32033
32760
|
return [];
|
|
@@ -32060,7 +32787,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
32060
32787
|
if (!item)
|
|
32061
32788
|
return;
|
|
32062
32789
|
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code: result.code }));
|
|
32063
|
-
|
|
32790
|
+
buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
32064
32791
|
dispatch(setTrajectActivitiesDayOrder(null));
|
|
32065
32792
|
dispatch(setFlyInIsOpen(false));
|
|
32066
32793
|
};
|
|
@@ -32076,7 +32803,8 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
|
|
|
32076
32803
|
cards.length === 0 ? (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default["default"].createElement("div", { className: "search__results__cards" }, cards.map((card) => {
|
|
32077
32804
|
const { result, item } = card;
|
|
32078
32805
|
const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedLines(result).length > 0;
|
|
32079
|
-
|
|
32806
|
+
const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
|
|
32807
|
+
return (React__default["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 }));
|
|
32080
32808
|
})))));
|
|
32081
32809
|
};
|
|
32082
32810
|
|
|
@@ -33686,6 +34414,10 @@ const getUniqueItems = (items = []) => {
|
|
|
33686
34414
|
return true;
|
|
33687
34415
|
});
|
|
33688
34416
|
};
|
|
34417
|
+
const isMeaningfulItem = (item, lines) => {
|
|
34418
|
+
const line = lines.find((l) => l.guid === item.itemGuid);
|
|
34419
|
+
return !line || isMeaningfulItineraryLine(line);
|
|
34420
|
+
};
|
|
33689
34421
|
const findAccommodationForDay = (nodes, currentDay) => {
|
|
33690
34422
|
for (const node of nodes ?? []) {
|
|
33691
34423
|
const { startDay } = getNodeDayRange(node);
|
|
@@ -33767,7 +34499,7 @@ const buildItineraryHtml = (itinerary, translations, lines) => {
|
|
|
33767
34499
|
const { startDay } = getNodeDayRange(node);
|
|
33768
34500
|
const day = node.startDate ? dateFns.format(node.startDate, 'd') : null;
|
|
33769
34501
|
const month = node.startDate ? dateFns.format(node.startDate, 'MMM') : null;
|
|
33770
|
-
const uniqueItems = getUniqueItems(node.items ?? []);
|
|
34502
|
+
const uniqueItems = getUniqueItems(node.items ?? []).filter((item) => isMeaningfulItem(item, lines));
|
|
33771
34503
|
const hasItems = uniqueItems.length > 0;
|
|
33772
34504
|
const hasAccommodationInCurrentNode = uniqueItems.some(isAccommodationItem);
|
|
33773
34505
|
const activeAccommodation = findAccommodationForDay(allNodes, startDay);
|
|
@@ -33811,11 +34543,12 @@ const buildItineraryHtml = (itinerary, translations, lines) => {
|
|
|
33811
34543
|
`;
|
|
33812
34544
|
})
|
|
33813
34545
|
.join('');
|
|
33814
|
-
const
|
|
34546
|
+
const defaultItems = getUniqueItems(itinerary.defaultItems ?? []).filter((item) => isMeaningfulItem(item, lines));
|
|
34547
|
+
const defaultItemsHtml = defaultItems.length > 0
|
|
33815
34548
|
? `
|
|
33816
34549
|
<section class="itinerary-default-items">
|
|
33817
34550
|
<h2 class="itinerary-default-items__title">Algemene info</h2>
|
|
33818
|
-
${
|
|
34551
|
+
${defaultItems
|
|
33819
34552
|
.map((item) => `
|
|
33820
34553
|
<article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
|
|
33821
34554
|
${hasVisibleContent(item.contents)
|
|
@@ -34474,7 +35207,7 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
34474
35207
|
const formik$1 = formik.useFormik({
|
|
34475
35208
|
initialValues,
|
|
34476
35209
|
enableReinitialize: true,
|
|
34477
|
-
validate: (values) => validateForm$1(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields),
|
|
35210
|
+
validate: (values) => validateForm$1(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields, undefined, undefined, editablePackagingEntry?.paxFields ?? []),
|
|
34478
35211
|
onSubmit: (values) => {
|
|
34479
35212
|
if (!editablePackagingEntry)
|
|
34480
35213
|
return;
|
|
@@ -34559,7 +35292,7 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
34559
35292
|
".\u00A0",
|
|
34560
35293
|
stepLabels[step])) },
|
|
34561
35294
|
isConfirmationPage && isLoading && React__default["default"].createElement(Spinner, { label: translations.SUMMARY.PROCESS_BOOKING }),
|
|
34562
|
-
currentStep === 0 && (React__default["default"].createElement(SharedTravelersForm, { formik: formik$1, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false })),
|
|
35295
|
+
currentStep === 0 && (React__default["default"].createElement(SharedTravelersForm, { formik: formik$1, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false, paxFields: editablePackagingEntry?.paxFields ?? [] })),
|
|
34563
35296
|
currentStep === 1 && (React__default["default"].createElement(SharedSummary, { translations: translations, travelerFormValues: formik$1.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["default"].createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => dispatch(setCurrentStep(0)), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) })),
|
|
34564
35297
|
currentStep === 2 && (React__default["default"].createElement(SharedConfirmation, { bookingNumber: bookingNumber ?? editablePackagingEntry?.dossierNumber ?? '', isOption: false, isOffer: false, translations: translations.CONFIRMATION })),
|
|
34565
35298
|
currentStep === 3 && React__default["default"].createElement("div", null))),
|
|
@@ -34623,6 +35356,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34623
35356
|
const locale = getLocale(context?.languageCode ?? 'en-GB');
|
|
34624
35357
|
const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry } = reactRedux.useSelector((state) => state.searchResults);
|
|
34625
35358
|
const trajectEntry = context?.trajectEntry;
|
|
35359
|
+
const bookedMode = isBookedEntryTraject(trajectEntry);
|
|
34626
35360
|
const hideShowMoreResults = !!context?.hideShowMoreResults;
|
|
34627
35361
|
const loadDayActivitiesOnDemand = !!context?.loadDayActivitiesOnDemand;
|
|
34628
35362
|
const showNonPreferredHotels = !!context?.showNonPreferredHotels;
|
|
@@ -34679,7 +35413,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34679
35413
|
if (!result)
|
|
34680
35414
|
return;
|
|
34681
35415
|
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
|
|
34682
|
-
|
|
35416
|
+
buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
34683
35417
|
};
|
|
34684
35418
|
/** The remaining legs for a flight node open in the fly-in, as the regular flight results do. */
|
|
34685
35419
|
const handleShowMoreFlights = (item) => {
|
|
@@ -34767,7 +35501,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34767
35501
|
node.preferredAccommodationName,
|
|
34768
35502
|
" \u2014 ",
|
|
34769
35503
|
translations.SRP.NO_RESULTS))),
|
|
34770
|
-
React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured, ...fill].map((result) => (React__default["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 })))),
|
|
35504
|
+
React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured, ...fill].map((result) => (React__default["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 })))),
|
|
34771
35505
|
remaining > 0 && !hideShowMoreResults && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
34772
35506
|
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
|
|
34773
35507
|
translations.SRP.SHOW_MORE,
|
|
@@ -34777,7 +35511,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34777
35511
|
};
|
|
34778
35512
|
const handleSelectFlight = (item, flight) => {
|
|
34779
35513
|
dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
|
|
34780
|
-
dispatch(updateEditableEntryLine(
|
|
35514
|
+
dispatch(updateEditableEntryLine(buildFlightSelectionLine(item, flight, bookedMode)));
|
|
34781
35515
|
};
|
|
34782
35516
|
const renderFlightNode = (item) => {
|
|
34783
35517
|
const { node, line } = item;
|
|
@@ -34803,7 +35537,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34803
35537
|
status === 'unavailable' && React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
|
|
34804
35538
|
status === 'resolved' && selected && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
34805
35539
|
React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--extended" },
|
|
34806
|
-
React__default["default"].createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price }),
|
|
35540
|
+
React__default["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 }),
|
|
34807
35541
|
visible.map((result) => (React__default["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) })))),
|
|
34808
35542
|
others.length > 2 && !hideShowMoreResults && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
34809
35543
|
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreFlights(item) },
|
|
@@ -34887,7 +35621,8 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34887
35621
|
*/
|
|
34888
35622
|
const renderActivityCard = ({ result, item }) => {
|
|
34889
35623
|
const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedExcursionLines(result).length > 0;
|
|
34890
|
-
|
|
35624
|
+
const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
|
|
35625
|
+
return (React__default["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 }));
|
|
34891
35626
|
};
|
|
34892
35627
|
if (isLoading)
|
|
34893
35628
|
return React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
|
|
@@ -34931,6 +35666,7 @@ const useTrajectAvailability = () => {
|
|
|
34931
35666
|
const controller = new AbortController();
|
|
34932
35667
|
dispatch(resetTrajectAvailability());
|
|
34933
35668
|
dispatch(setTrajectResolving(true));
|
|
35669
|
+
const bookedMode = isBookedEntryTraject(trajectEntry);
|
|
34934
35670
|
const config = {
|
|
34935
35671
|
host: context.tideConnection.host,
|
|
34936
35672
|
apiKey: context.tideConnection.apiKey
|
|
@@ -34992,6 +35728,17 @@ const useTrajectAvailability = () => {
|
|
|
34992
35728
|
});
|
|
34993
35729
|
const configuredCodes = new Set(configuredResults.map((x) => x.code));
|
|
34994
35730
|
const destinationResults = areaResults.filter((x) => !configuredCodes.has(x.code));
|
|
35731
|
+
if (bookedMode) {
|
|
35732
|
+
const results = [...configuredResults, ...destinationResults];
|
|
35733
|
+
let booked = results.find((x) => matchesCode(x, item.node.code ?? '')) ?? null;
|
|
35734
|
+
// Not searchable any more (sold out, delisted) — drawn from the line instead.
|
|
35735
|
+
if (!booked) {
|
|
35736
|
+
booked = buildBookedNodeResult(item.node, item.lines);
|
|
35737
|
+
results.unshift(booked);
|
|
35738
|
+
}
|
|
35739
|
+
dispatch(setTrajectNodeAvailability({ lineGuid, results, selectedCode: booked.code, preferredUnavailable: false }));
|
|
35740
|
+
return [];
|
|
35741
|
+
}
|
|
34995
35742
|
const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
|
|
34996
35743
|
const preferredUnavailable = configuredResults.length
|
|
34997
35744
|
? !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code))
|
|
@@ -35014,6 +35761,11 @@ const useTrajectAvailability = () => {
|
|
|
35014
35761
|
if (controller.signal.aborted)
|
|
35015
35762
|
return [];
|
|
35016
35763
|
console.error('Failed to resolve traject node availability', item.node.name, error);
|
|
35764
|
+
if (bookedMode) {
|
|
35765
|
+
const booked = buildBookedNodeResult(item.node, item.lines);
|
|
35766
|
+
dispatch(setTrajectNodeAvailability({ lineGuid, results: [booked], selectedCode: booked.code, preferredUnavailable: false }));
|
|
35767
|
+
return [];
|
|
35768
|
+
}
|
|
35017
35769
|
dispatch(setTrajectNodeAvailability({ lineGuid, results: [], selectedCode: null, preferredUnavailable: false }));
|
|
35018
35770
|
return item.lines.map((x) => x.guid);
|
|
35019
35771
|
}
|
|
@@ -35021,6 +35773,11 @@ const useTrajectAvailability = () => {
|
|
|
35021
35773
|
const resolveFlightNode = async (item) => {
|
|
35022
35774
|
const lineGuid = item.line.guid;
|
|
35023
35775
|
if (!item.node.departureAirportCode || !item.node.arrivalAirportCode) {
|
|
35776
|
+
if (bookedMode) {
|
|
35777
|
+
const booked = buildBookedFlightResult(item.line);
|
|
35778
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked], selectedGuid: booked.outwardGuid }));
|
|
35779
|
+
return [];
|
|
35780
|
+
}
|
|
35024
35781
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
35025
35782
|
return item.lines.map((x) => x.guid);
|
|
35026
35783
|
}
|
|
@@ -35029,6 +35786,11 @@ const useTrajectAvailability = () => {
|
|
|
35029
35786
|
const flights = (await build.searchPackagingFlights(config, buildTrajectFlightRequest(item, searchContext, flightPax), controller.signal)) ?? [];
|
|
35030
35787
|
if (controller.signal.aborted)
|
|
35031
35788
|
return [];
|
|
35789
|
+
if (bookedMode) {
|
|
35790
|
+
const booked = buildBookedFlightResult(item.line);
|
|
35791
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked, ...flights], selectedGuid: booked.outwardGuid }));
|
|
35792
|
+
return [];
|
|
35793
|
+
}
|
|
35032
35794
|
const picked = pickCheapestFlight(flights);
|
|
35033
35795
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: flights, selectedGuid: picked?.outwardGuid ?? null }));
|
|
35034
35796
|
if (!picked)
|
|
@@ -35040,6 +35802,11 @@ const useTrajectAvailability = () => {
|
|
|
35040
35802
|
if (controller.signal.aborted)
|
|
35041
35803
|
return [];
|
|
35042
35804
|
console.error('Failed to resolve traject flight', item.node.name, error);
|
|
35805
|
+
if (bookedMode) {
|
|
35806
|
+
const booked = buildBookedFlightResult(item.line);
|
|
35807
|
+
dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked], selectedGuid: booked.outwardGuid }));
|
|
35808
|
+
return [];
|
|
35809
|
+
}
|
|
35043
35810
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
35044
35811
|
return item.lines.map((x) => x.guid);
|
|
35045
35812
|
}
|
|
@@ -35077,6 +35844,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35077
35844
|
const [detailsIsLoading, setDetailsIsLoading] = React.useState(false);
|
|
35078
35845
|
const [pricesAreLoading, setPricesAreLoading] = React.useState(false);
|
|
35079
35846
|
const [itineraryIsLoading, setItineraryIsLoading] = React.useState(false);
|
|
35847
|
+
const [entrySaving, setEntrySaving] = React.useState(false);
|
|
35080
35848
|
const [itineraryOpen, setItineraryOpen] = React.useState(false);
|
|
35081
35849
|
const [isBookingConfirmation, setIsBookingConfirmation] = React.useState(false);
|
|
35082
35850
|
const [selectedAccommodationSeed, setSelectedAccommodationSeed] = React.useState(null);
|
|
@@ -35833,6 +36601,31 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35833
36601
|
React.useEffect(() => {
|
|
35834
36602
|
setInitialFiltersSet(false);
|
|
35835
36603
|
}, [activeSearchSeed]);
|
|
36604
|
+
const handleSaveEntry = async () => {
|
|
36605
|
+
if (!context || !bookableEntry || entrySaving)
|
|
36606
|
+
return;
|
|
36607
|
+
setEntrySaving(true);
|
|
36608
|
+
try {
|
|
36609
|
+
const config = {
|
|
36610
|
+
host: context.tideConnection.host,
|
|
36611
|
+
apiKey: context.tideConnection.apiKey
|
|
36612
|
+
};
|
|
36613
|
+
const request = {
|
|
36614
|
+
language: context.languageCode ?? 'en-GB',
|
|
36615
|
+
officeId: context.tideConnection.officeId,
|
|
36616
|
+
catalogueId: context.searchConfiguration.defaultCatalogueId ?? lodash.first(context?.tideConnection?.catalogueIds) ?? 1,
|
|
36617
|
+
agentId: context.agentId,
|
|
36618
|
+
payload: bookableEntry
|
|
36619
|
+
};
|
|
36620
|
+
await build.savePackagingEntry(config, request);
|
|
36621
|
+
if (typeof window !== 'undefined')
|
|
36622
|
+
window.location.reload();
|
|
36623
|
+
}
|
|
36624
|
+
catch (err) {
|
|
36625
|
+
console.error('Failed to save the entry', err);
|
|
36626
|
+
setEntrySaving(false);
|
|
36627
|
+
}
|
|
36628
|
+
};
|
|
35836
36629
|
React.useEffect(() => {
|
|
35837
36630
|
const fetchPriceDetails = async () => {
|
|
35838
36631
|
if (!context || !editablePackagingEntry || lodash.isEmpty(editablePackagingEntry.lines))
|
|
@@ -36217,11 +37010,18 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
36217
37010
|
const id = paxId++;
|
|
36218
37011
|
pax.push({
|
|
36219
37012
|
id,
|
|
37013
|
+
guid: '',
|
|
36220
37014
|
firstName: _.firstName || '',
|
|
36221
37015
|
lastName: _.lastName || '',
|
|
36222
|
-
dateOfBirth: _.dateOfBirth ||
|
|
36223
|
-
age: _.age ||
|
|
36224
|
-
isMainBooker: roomIndex === 0 && paxIndex === 0
|
|
37016
|
+
dateOfBirth: _.dateOfBirth || undefined,
|
|
37017
|
+
age: _.age || undefined,
|
|
37018
|
+
isMainBooker: roomIndex === 0 && paxIndex === 0,
|
|
37019
|
+
email: '',
|
|
37020
|
+
weight: null,
|
|
37021
|
+
weightType: build.WeightType.kilograms,
|
|
37022
|
+
height: null,
|
|
37023
|
+
heightType: build.HeightType.centimeters,
|
|
37024
|
+
customFields: []
|
|
36225
37025
|
});
|
|
36226
37026
|
return id;
|
|
36227
37027
|
});
|
|
@@ -36241,6 +37041,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
36241
37041
|
depositAmount: 0,
|
|
36242
37042
|
pax,
|
|
36243
37043
|
rooms,
|
|
37044
|
+
paxFields: [],
|
|
36244
37045
|
lines: [],
|
|
36245
37046
|
address: {}
|
|
36246
37047
|
};
|
|
@@ -36260,7 +37061,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
36260
37061
|
context.searchConfiguration.qsmType != build.PortalQsmType.AccommodationAndFlight && context.showFilters && (React__default["default"].createElement(Filters, { initialFilters: initialFilters, filters: filters, isOpen: filtersOpen, handleSetIsOpen: () => setFiltersOpen(!filtersOpen),
|
|
36261
37062
|
// handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
|
|
36262
37063
|
isLoading: isLoading, setFilters: (filters) => dispatch(setFilters(filters)), resetFilters: (filters) => dispatch(resetFilters(filters)) })),
|
|
36263
|
-
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default["default"].createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving, onEditAccommodation: handleEditAccommodation })),
|
|
37064
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default["default"].createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving || entrySaving, onEditAccommodation: handleEditAccommodation, onSaveEntry: handleSaveEntry })),
|
|
36264
37065
|
React__default["default"].createElement("div", { className: "search__results" },
|
|
36265
37066
|
isMobile && (React__default["default"].createElement("div", { className: "search__result-row" },
|
|
36266
37067
|
React__default["default"].createElement("div", { className: "search__results__actions" },
|
|
@@ -36348,8 +37149,15 @@ const createSearchResultsStore = () => toolkit.configureStore({
|
|
|
36348
37149
|
|
|
36349
37150
|
const SearchResults = ({ configuration, onBookingStarted }) => {
|
|
36350
37151
|
const store = React__default["default"].useMemo(() => createSearchResultsStore(), []);
|
|
37152
|
+
// A booked entry opened through its magic link gets the traject services screen by carrying a
|
|
37153
|
+
// traject rebuilt from its own lines. The magic link on the entry is what marks the mode.
|
|
37154
|
+
const effectiveConfiguration = React__default["default"].useMemo(() => {
|
|
37155
|
+
if (!configuration.allowBookedEntryChanges || configuration.trajectEntry || !configuration.packagingEntry?.magicLink)
|
|
37156
|
+
return configuration;
|
|
37157
|
+
return { ...configuration, trajectEntry: buildBookedTrajectEntry(configuration.packagingEntry) };
|
|
37158
|
+
}, [configuration]);
|
|
36351
37159
|
return (React__default["default"].createElement(reactRedux.Provider, { store: store },
|
|
36352
|
-
React__default["default"].createElement(SearchResultsConfigurationContext.Provider, { value:
|
|
37160
|
+
React__default["default"].createElement(SearchResultsConfigurationContext.Provider, { value: effectiveConfiguration },
|
|
36353
37161
|
React__default["default"].createElement(SearchResultsContainer, { onBookingStarted: onBookingStarted }))));
|
|
36354
37162
|
};
|
|
36355
37163
|
|