@qite/tide-components 1.0.10 → 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.
Files changed (93) hide show
  1. package/build/build-cjs/index.js +2386 -1305
  2. package/build/build-cjs/src/booking-wizard/features/booking/selectors.d.ts +1 -0
  3. package/build/build-cjs/src/booking-wizard/features/travelers-form/validate-form.d.ts +2 -1
  4. package/build/build-cjs/src/booking-wizard/types.d.ts +29 -1
  5. package/build/build-cjs/src/search-results/components/flight/flight-selection/independent-flight-option.d.ts +2 -0
  6. package/build/build-cjs/src/search-results/components/itinerary/index.d.ts +1 -0
  7. package/build/build-cjs/src/search-results/components/itinerary/itinerary-utils.d.ts +1 -0
  8. package/build/build-cjs/src/search-results/types.d.ts +8 -0
  9. package/build/build-cjs/src/search-results/utils/booked-entry-utils.d.ts +20 -0
  10. package/build/build-cjs/src/search-results/utils/traject-utils.d.ts +7 -0
  11. package/build/build-cjs/src/shared/booking/travelers-form.d.ts +13 -3
  12. package/build/build-esm/index.js +2390 -1309
  13. package/build/build-esm/src/booking-wizard/features/booking/selectors.d.ts +1 -0
  14. package/build/build-esm/src/booking-wizard/features/travelers-form/validate-form.d.ts +2 -1
  15. package/build/build-esm/src/booking-wizard/types.d.ts +29 -1
  16. package/build/build-esm/src/search-results/components/flight/flight-selection/independent-flight-option.d.ts +2 -0
  17. package/build/build-esm/src/search-results/components/itinerary/index.d.ts +1 -0
  18. package/build/build-esm/src/search-results/components/itinerary/itinerary-utils.d.ts +1 -0
  19. package/build/build-esm/src/search-results/types.d.ts +8 -0
  20. package/build/build-esm/src/search-results/utils/booked-entry-utils.d.ts +20 -0
  21. package/build/build-esm/src/search-results/utils/traject-utils.d.ts +7 -0
  22. package/build/build-esm/src/shared/booking/travelers-form.d.ts +13 -3
  23. package/package.json +2 -2
  24. package/styles/abstracts/_mixins.scss +74 -74
  25. package/styles/abstracts/_variables.scss +57 -57
  26. package/styles/base/_fonts.scss +2 -2
  27. package/styles/base/_normalize.scss +227 -227
  28. package/styles/base/_typography.scss +35 -35
  29. package/styles/booking-joker-variables.scss +596 -596
  30. package/styles/booking-product-variables.scss +330 -330
  31. package/styles/booking-product.scss +438 -438
  32. package/styles/booking-qsm-variables.scss +501 -501
  33. package/styles/booking-qsm.scss +52 -52
  34. package/styles/booking-search-results-variables.scss +734 -734
  35. package/styles/booking-search-results.scss +53 -53
  36. package/styles/booking-wizard-variables.scss +603 -603
  37. package/styles/booking-wizard.scss +61 -61
  38. package/styles/components/_accordion.scss +67 -67
  39. package/styles/components/_animations.scss +39 -39
  40. package/styles/components/_base.scss +107 -107
  41. package/styles/components/_booking.scss +906 -906
  42. package/styles/components/_breadcrumb.scss +92 -92
  43. package/styles/components/_button.scss +238 -238
  44. package/styles/components/_checkbox.scss +230 -230
  45. package/styles/components/_contact.scss +255 -255
  46. package/styles/components/_content.scss +336 -336
  47. package/styles/components/_cta.scss +238 -238
  48. package/styles/components/_date-list.scss +41 -41
  49. package/styles/components/_date-range-picker.scss +223 -223
  50. package/styles/components/_decrement-increment.scss +35 -35
  51. package/styles/components/_dropdown.scss +77 -77
  52. package/styles/components/_error.scss +50 -50
  53. package/styles/components/_faq.scss +30 -30
  54. package/styles/components/_flight-option.scss +1432 -1432
  55. package/styles/components/_flyin.scss +830 -830
  56. package/styles/components/_footer.scss +135 -135
  57. package/styles/components/_form.scss +1704 -1693
  58. package/styles/components/_gallery.scss +317 -317
  59. package/styles/components/_header.scss +113 -113
  60. package/styles/components/_image-with-text.scss +206 -206
  61. package/styles/components/_img-slider.scss +175 -175
  62. package/styles/components/_info-message.scss +75 -75
  63. package/styles/components/_input.scss +35 -35
  64. package/styles/components/_list.scss +185 -185
  65. package/styles/components/_loader.scss +152 -152
  66. package/styles/components/_login.scss +140 -140
  67. package/styles/components/_map-view.scss +1100 -1100
  68. package/styles/components/_mixins.scss +579 -579
  69. package/styles/components/_navbar.scss +765 -765
  70. package/styles/components/_passenger-picker.scss +306 -306
  71. package/styles/components/_phone-input.scss +8 -8
  72. package/styles/components/_placeholders.scss +165 -165
  73. package/styles/components/_pricing-summary.scss +163 -163
  74. package/styles/components/_qsm.scss +17 -17
  75. package/styles/components/_radiobutton.scss +170 -170
  76. package/styles/components/_search.scss +2197 -2197
  77. package/styles/components/_select-wrapper.scss +81 -81
  78. package/styles/components/_slider.scss +120 -128
  79. package/styles/components/_spinner.scss +29 -29
  80. package/styles/components/_step-indicators.scss +187 -187
  81. package/styles/components/_table.scss +81 -81
  82. package/styles/components/_tide-form.scss +578 -578
  83. package/styles/components/_tree.scss +648 -648
  84. package/styles/components/_typeahead.scss +275 -275
  85. package/styles/components/_variables.scss +89 -89
  86. package/styles/content-blocks-variables.scss +543 -543
  87. package/styles/content-blocks.scss +66 -66
  88. package/styles/font.scss +2 -2
  89. package/styles/qsm/_calendar.scss +274 -274
  90. package/styles/qsm/_qsm.scss +1097 -1097
  91. package/styles/search.scss +1200 -1200
  92. package/styles/tide-form-variables.scss +275 -275
  93. package/styles/tide-form.scss +56 -56
@@ -1,18 +1,18 @@
1
1
  /* eslint-disable */
2
2
  import * as React from 'react';
3
- import React__default, { useLayoutEffect as useLayoutEffect$1, useEffect, useContext, useState, useRef, useCallback, useMemo } from 'react';
3
+ import React__default, { useLayoutEffect as useLayoutEffect$1, useEffect, useContext, useState, useRef, useMemo, useCallback } from 'react';
4
4
  import JsonURL from '@jsonurl/jsonurl';
5
- import { format as format$2, isToday, getDate, startOfWeek, startOfMonth, endOfWeek, addWeeks, endOfMonth, eachDayOfInterval, getYear, getMonth, getISOWeek, getISODay, isSameMonth, startOfDay, isAfter, isSameDay, isEqual, isWithinInterval, endOfDay, isBefore, differenceInCalendarDays, addMonths, addDays, formatISO, addYears, differenceInYears, parseISO, differenceInMinutes, isValid, parse, startOfToday } from 'date-fns';
6
- import { merge, cloneDeep, isNil, isArray as isArray$1, compact, isEmpty as isEmpty$1, range, chunk, isFunction as isFunction$1, clamp, now, omit, isPlainObject as isPlainObject$1, mapValues, pickBy, first, orderBy, uniq, uniqBy, sortBy, sum, last, findIndex as findIndex$1, set, get, isEqual as isEqual$1, groupBy, minBy, concat, flatMap } from 'lodash';
5
+ import { format as format$2, isToday, getDate, startOfWeek, startOfMonth, endOfWeek, addWeeks, endOfMonth, eachDayOfInterval, getYear, getMonth, getISOWeek, getISODay, isSameMonth, startOfDay, isAfter, isSameDay, isEqual, isWithinInterval, endOfDay, isBefore, differenceInCalendarDays, addMonths, addDays, formatISO, addYears, differenceInYears, parse, isValid, parseISO, differenceInMinutes, startOfToday } from 'date-fns';
6
+ import { merge, cloneDeep, isNil, isArray as isArray$1, compact, isEmpty as isEmpty$1, range, chunk, isFunction as isFunction$1, clamp, now, omit, get, last, first, sortBy, isPlainObject as isPlainObject$1, mapValues, pickBy, orderBy, uniq, uniqBy, sum, findIndex as findIndex$1, set, isEqual as isEqual$1, groupBy, minBy, concat, flatMap } from 'lodash';
7
7
  import { arSA, da, de, enGB, es, fr, is, it, nl, nb, pl, pt, sv, ja, enUS } from 'date-fns/locale';
8
8
  import { usePopper } from 'react-popper';
9
9
  import { useSelector, useDispatch, Provider } from 'react-redux';
10
10
  import { createSlice, createSelector, createAsyncThunk, configureStore } from '@reduxjs/toolkit';
11
+ import flat from 'flat';
11
12
  import { UNSAFE_NavigationContext, useHref, useNavigate, useLocation, useResolvedPath, createPath, UNSAFE_DataRouterStateContext, UNSAFE_useRouteId, UNSAFE_RouteContext, UNSAFE_DataRouterContext, Routes, Route } from 'react-router';
12
13
  import 'react-dom';
13
14
  import produce from 'immer';
14
15
  import { useFormik } from 'formik';
15
- import flat from 'flat';
16
16
  import { v4 } from 'uuid';
17
17
 
18
18
  function _mergeNamespaces(n, m) {
@@ -124,7 +124,9 @@ var SHARED$f = {
124
124
  ADULTS: "بالغون",
125
125
  CHILDREN: "أطفال",
126
126
  SELECT: "اختر",
127
- SELECTED: "تم الاختيار"
127
+ SELECTED: "تم الاختيار",
128
+ BOOKED: "محجوز",
129
+ SAVE: "حفظ"
128
130
  };
129
131
  var SIDEBAR$f = {
130
132
  OVERVIEW: "الملخص",
@@ -182,6 +184,27 @@ var TRAVELERS_FORM$f = {
182
184
  FIRST_NAME: "الاسم الأول",
183
185
  LAST_NAME: "اسم العائلة",
184
186
  BIRTHDATE: "تاريخ الميلاد",
187
+ NICKNAME: "Nickname",
188
+ BIRTHPLACE: "Birthplace",
189
+ NATIONALITY: "Nationality",
190
+ PREFERRED_LANGUAGE: "Preferred language",
191
+ TRAVELER_EMAIL: "Email",
192
+ TRAVELER_PHONE: "Phone",
193
+ TRAVELER_MOBILE: "Mobile phone",
194
+ PASSPORT_NUMBER: "Passport number",
195
+ PASSPORT_ISSUE_DATE: "Passport issue date",
196
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
197
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
198
+ EMERGENCY_NUMBER: "Emergency number",
199
+ HAS_INSURANCE: "Has insurance",
200
+ INSURANCE_NAME: "Insurance name",
201
+ INFO: "Additional information",
202
+ WEIGHT: "الوزن",
203
+ WEIGHT_UNIT_KG: "kg",
204
+ WEIGHT_UNIT_LB: "lb",
205
+ HEIGHT: "الطول",
206
+ HEIGHT_UNIT_CM: "cm",
207
+ HEIGHT_UNIT_FT_IN: "ft/in",
185
208
  STREET: "الشارع",
186
209
  STREET_PLACEHOLDER: "اسم الشارع",
187
210
  HOUSE_NUMBER: "رقم المنزل",
@@ -571,7 +594,9 @@ var SHARED$e = {
571
594
  ADULTS: "Voksne",
572
595
  CHILDREN: "Børn",
573
596
  SELECT: "Vælg",
574
- SELECTED: "Valgt"
597
+ SELECTED: "Valgt",
598
+ BOOKED: "Booket",
599
+ SAVE: "Gem"
575
600
  };
576
601
  var SIDEBAR$e = {
577
602
  OVERVIEW: "Oversigt",
@@ -629,6 +654,27 @@ var TRAVELERS_FORM$e = {
629
654
  FIRST_NAME: "Fornavn",
630
655
  LAST_NAME: "Efternavn",
631
656
  BIRTHDATE: "Fødselsdato",
657
+ NICKNAME: "Nickname",
658
+ BIRTHPLACE: "Birthplace",
659
+ NATIONALITY: "Nationality",
660
+ PREFERRED_LANGUAGE: "Preferred language",
661
+ TRAVELER_EMAIL: "Email",
662
+ TRAVELER_PHONE: "Phone",
663
+ TRAVELER_MOBILE: "Mobile phone",
664
+ PASSPORT_NUMBER: "Passport number",
665
+ PASSPORT_ISSUE_DATE: "Passport issue date",
666
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
667
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
668
+ EMERGENCY_NUMBER: "Emergency number",
669
+ HAS_INSURANCE: "Has insurance",
670
+ INSURANCE_NAME: "Insurance name",
671
+ INFO: "Additional information",
672
+ WEIGHT: "Vægt",
673
+ WEIGHT_UNIT_KG: "kg",
674
+ WEIGHT_UNIT_LB: "lb",
675
+ HEIGHT: "Højde",
676
+ HEIGHT_UNIT_CM: "cm",
677
+ HEIGHT_UNIT_FT_IN: "ft/in",
632
678
  STREET: "Gade",
633
679
  STREET_PLACEHOLDER: "Din gade",
634
680
  HOUSE_NUMBER: "Husnummer",
@@ -1018,7 +1064,9 @@ var SHARED$d = {
1018
1064
  ADULTS: "Erwachsene",
1019
1065
  CHILDREN: "Kinder",
1020
1066
  SELECT: "Auswählen",
1021
- SELECTED: "Ausgewählt"
1067
+ SELECTED: "Ausgewählt",
1068
+ BOOKED: "Gebucht",
1069
+ SAVE: "Speichern"
1022
1070
  };
1023
1071
  var SIDEBAR$d = {
1024
1072
  OVERVIEW: "Übersicht",
@@ -1076,6 +1124,27 @@ var TRAVELERS_FORM$d = {
1076
1124
  FIRST_NAME: "Vorname",
1077
1125
  LAST_NAME: "Nachname",
1078
1126
  BIRTHDATE: "Geburtsdatum",
1127
+ NICKNAME: "Nickname",
1128
+ BIRTHPLACE: "Birthplace",
1129
+ NATIONALITY: "Nationality",
1130
+ PREFERRED_LANGUAGE: "Preferred language",
1131
+ TRAVELER_EMAIL: "Email",
1132
+ TRAVELER_PHONE: "Phone",
1133
+ TRAVELER_MOBILE: "Mobile phone",
1134
+ PASSPORT_NUMBER: "Passport number",
1135
+ PASSPORT_ISSUE_DATE: "Passport issue date",
1136
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
1137
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
1138
+ EMERGENCY_NUMBER: "Emergency number",
1139
+ HAS_INSURANCE: "Has insurance",
1140
+ INSURANCE_NAME: "Insurance name",
1141
+ INFO: "Additional information",
1142
+ WEIGHT: "Gewicht",
1143
+ WEIGHT_UNIT_KG: "kg",
1144
+ WEIGHT_UNIT_LB: "lb",
1145
+ HEIGHT: "Größe",
1146
+ HEIGHT_UNIT_CM: "cm",
1147
+ HEIGHT_UNIT_FT_IN: "ft/in",
1079
1148
  STREET: "Straße",
1080
1149
  STREET_PLACEHOLDER: "Ihre Straße",
1081
1150
  HOUSE_NUMBER: "Hausnummer",
@@ -1465,7 +1534,9 @@ var SHARED$c = {
1465
1534
  ADULTS: "Adults",
1466
1535
  CHILDREN: "Children",
1467
1536
  SELECT: "Select",
1468
- SELECTED: "Selected"
1537
+ SELECTED: "Selected",
1538
+ BOOKED: "Booked",
1539
+ SAVE: "Save"
1469
1540
  };
1470
1541
  var SIDEBAR$c = {
1471
1542
  OVERVIEW: "Summary",
@@ -1524,6 +1595,27 @@ var TRAVELERS_FORM$c = {
1524
1595
  FIRST_NAME: "First name",
1525
1596
  LAST_NAME: "Last name",
1526
1597
  BIRTHDATE: "Date of birth",
1598
+ NICKNAME: "Nickname",
1599
+ BIRTHPLACE: "Birthplace",
1600
+ NATIONALITY: "Nationality",
1601
+ PREFERRED_LANGUAGE: "Preferred language",
1602
+ TRAVELER_EMAIL: "Email",
1603
+ TRAVELER_PHONE: "Phone",
1604
+ TRAVELER_MOBILE: "Mobile phone",
1605
+ PASSPORT_NUMBER: "Passport number",
1606
+ PASSPORT_ISSUE_DATE: "Passport issue date",
1607
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
1608
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
1609
+ EMERGENCY_NUMBER: "Emergency number",
1610
+ HAS_INSURANCE: "Has insurance",
1611
+ INSURANCE_NAME: "Insurance name",
1612
+ INFO: "Additional information",
1613
+ WEIGHT: "Weight",
1614
+ WEIGHT_UNIT_KG: "kg",
1615
+ WEIGHT_UNIT_LB: "lb",
1616
+ HEIGHT: "Height",
1617
+ HEIGHT_UNIT_CM: "cm",
1618
+ HEIGHT_UNIT_FT_IN: "ft/in",
1527
1619
  STREET: "Street",
1528
1620
  STREET_PLACEHOLDER: "Your street",
1529
1621
  HOUSE_NUMBER: "House number",
@@ -1916,7 +2008,9 @@ var SHARED$b = {
1916
2008
  ADULTS: "Adultos",
1917
2009
  CHILDREN: "Niños",
1918
2010
  SELECT: "Seleccionar",
1919
- SELECTED: "Seleccionado"
2011
+ SELECTED: "Seleccionado",
2012
+ BOOKED: "Reservado",
2013
+ SAVE: "Guardar"
1920
2014
  };
1921
2015
  var SIDEBAR$b = {
1922
2016
  OVERVIEW: "Resumen",
@@ -1974,6 +2068,27 @@ var TRAVELERS_FORM$b = {
1974
2068
  FIRST_NAME: "Nombre",
1975
2069
  LAST_NAME: "Apellido",
1976
2070
  BIRTHDATE: "Fecha de nacimiento",
2071
+ NICKNAME: "Nickname",
2072
+ BIRTHPLACE: "Birthplace",
2073
+ NATIONALITY: "Nationality",
2074
+ PREFERRED_LANGUAGE: "Preferred language",
2075
+ TRAVELER_EMAIL: "Email",
2076
+ TRAVELER_PHONE: "Phone",
2077
+ TRAVELER_MOBILE: "Mobile phone",
2078
+ PASSPORT_NUMBER: "Passport number",
2079
+ PASSPORT_ISSUE_DATE: "Passport issue date",
2080
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
2081
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
2082
+ EMERGENCY_NUMBER: "Emergency number",
2083
+ HAS_INSURANCE: "Has insurance",
2084
+ INSURANCE_NAME: "Insurance name",
2085
+ INFO: "Additional information",
2086
+ WEIGHT: "Peso",
2087
+ WEIGHT_UNIT_KG: "kg",
2088
+ WEIGHT_UNIT_LB: "lb",
2089
+ HEIGHT: "Estatura",
2090
+ HEIGHT_UNIT_CM: "cm",
2091
+ HEIGHT_UNIT_FT_IN: "ft/in",
1977
2092
  STREET: "Calle",
1978
2093
  STREET_PLACEHOLDER: "Su calle",
1979
2094
  HOUSE_NUMBER: "Número",
@@ -2363,7 +2478,9 @@ var SHARED$a = {
2363
2478
  ADULTS: "Adultes",
2364
2479
  CHILDREN: "Enfants",
2365
2480
  SELECT: "Sélectionner",
2366
- SELECTED: "Sélectionné"
2481
+ SELECTED: "Sélectionné",
2482
+ BOOKED: "Réservé",
2483
+ SAVE: "Enregistrer"
2367
2484
  };
2368
2485
  var SIDEBAR$a = {
2369
2486
  OVERVIEW: "Aperçu",
@@ -2422,6 +2539,27 @@ var TRAVELERS_FORM$a = {
2422
2539
  FIRST_NAME: "Prénom",
2423
2540
  LAST_NAME: "Nom",
2424
2541
  BIRTHDATE: "Date de naissance",
2542
+ NICKNAME: "Nickname",
2543
+ BIRTHPLACE: "Birthplace",
2544
+ NATIONALITY: "Nationality",
2545
+ PREFERRED_LANGUAGE: "Preferred language",
2546
+ TRAVELER_EMAIL: "Email",
2547
+ TRAVELER_PHONE: "Phone",
2548
+ TRAVELER_MOBILE: "Mobile phone",
2549
+ PASSPORT_NUMBER: "Passport number",
2550
+ PASSPORT_ISSUE_DATE: "Passport issue date",
2551
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
2552
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
2553
+ EMERGENCY_NUMBER: "Emergency number",
2554
+ HAS_INSURANCE: "Has insurance",
2555
+ INSURANCE_NAME: "Insurance name",
2556
+ INFO: "Additional information",
2557
+ WEIGHT: "Poids",
2558
+ WEIGHT_UNIT_KG: "kg",
2559
+ WEIGHT_UNIT_LB: "lb",
2560
+ HEIGHT: "Taille",
2561
+ HEIGHT_UNIT_CM: "cm",
2562
+ HEIGHT_UNIT_FT_IN: "ft/in",
2425
2563
  STREET: "Rue",
2426
2564
  STREET_PLACEHOLDER: "Votre rue",
2427
2565
  HOUSE_NUMBER: "N°",
@@ -2814,7 +2952,9 @@ var SHARED$9 = {
2814
2952
  ADULTS: "Adultes",
2815
2953
  CHILDREN: "Enfants",
2816
2954
  SELECT: "Sélectionner",
2817
- SELECTED: "Sélectionné"
2955
+ SELECTED: "Sélectionné",
2956
+ BOOKED: "Réservé",
2957
+ SAVE: "Enregistrer"
2818
2958
  };
2819
2959
  var SIDEBAR$9 = {
2820
2960
  OVERVIEW: "Résumé",
@@ -2872,6 +3012,27 @@ var TRAVELERS_FORM$9 = {
2872
3012
  FIRST_NAME: "Prénom",
2873
3013
  LAST_NAME: "Nom",
2874
3014
  BIRTHDATE: "Date de naissance",
3015
+ NICKNAME: "Nickname",
3016
+ BIRTHPLACE: "Birthplace",
3017
+ NATIONALITY: "Nationality",
3018
+ PREFERRED_LANGUAGE: "Preferred language",
3019
+ TRAVELER_EMAIL: "Email",
3020
+ TRAVELER_PHONE: "Phone",
3021
+ TRAVELER_MOBILE: "Mobile phone",
3022
+ PASSPORT_NUMBER: "Passport number",
3023
+ PASSPORT_ISSUE_DATE: "Passport issue date",
3024
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
3025
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
3026
+ EMERGENCY_NUMBER: "Emergency number",
3027
+ HAS_INSURANCE: "Has insurance",
3028
+ INSURANCE_NAME: "Insurance name",
3029
+ INFO: "Additional information",
3030
+ WEIGHT: "Poids",
3031
+ WEIGHT_UNIT_KG: "kg",
3032
+ WEIGHT_UNIT_LB: "lb",
3033
+ HEIGHT: "Taille",
3034
+ HEIGHT_UNIT_CM: "cm",
3035
+ HEIGHT_UNIT_FT_IN: "ft/in",
2875
3036
  STREET: "Rue",
2876
3037
  STREET_PLACEHOLDER: "Votre rue",
2877
3038
  HOUSE_NUMBER: "Numéro",
@@ -3261,7 +3422,9 @@ var SHARED$8 = {
3261
3422
  ADULTS: "Fullorðnir",
3262
3423
  CHILDREN: "Börn",
3263
3424
  SELECT: "Velja",
3264
- SELECTED: "Valið"
3425
+ SELECTED: "Valið",
3426
+ BOOKED: "Bókað",
3427
+ SAVE: "Vista"
3265
3428
  };
3266
3429
  var SIDEBAR$8 = {
3267
3430
  OVERVIEW: "Yfirlit",
@@ -3319,6 +3482,27 @@ var TRAVELERS_FORM$8 = {
3319
3482
  FIRST_NAME: "Fornafn",
3320
3483
  LAST_NAME: "Eftirnafn",
3321
3484
  BIRTHDATE: "Fæðingardagur",
3485
+ NICKNAME: "Nickname",
3486
+ BIRTHPLACE: "Birthplace",
3487
+ NATIONALITY: "Nationality",
3488
+ PREFERRED_LANGUAGE: "Preferred language",
3489
+ TRAVELER_EMAIL: "Email",
3490
+ TRAVELER_PHONE: "Phone",
3491
+ TRAVELER_MOBILE: "Mobile phone",
3492
+ PASSPORT_NUMBER: "Passport number",
3493
+ PASSPORT_ISSUE_DATE: "Passport issue date",
3494
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
3495
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
3496
+ EMERGENCY_NUMBER: "Emergency number",
3497
+ HAS_INSURANCE: "Has insurance",
3498
+ INSURANCE_NAME: "Insurance name",
3499
+ INFO: "Additional information",
3500
+ WEIGHT: "Þyngd",
3501
+ WEIGHT_UNIT_KG: "kg",
3502
+ WEIGHT_UNIT_LB: "lb",
3503
+ HEIGHT: "Hæð",
3504
+ HEIGHT_UNIT_CM: "cm",
3505
+ HEIGHT_UNIT_FT_IN: "ft/in",
3322
3506
  STREET: "Gata",
3323
3507
  STREET_PLACEHOLDER: "Gatan þín",
3324
3508
  HOUSE_NUMBER: "Húsnúmer",
@@ -3708,7 +3892,9 @@ var SHARED$7 = {
3708
3892
  ADULTS: "Adulti",
3709
3893
  CHILDREN: "Bambini",
3710
3894
  SELECT: "Seleziona",
3711
- SELECTED: "Selezionato"
3895
+ SELECTED: "Selezionato",
3896
+ BOOKED: "Prenotato",
3897
+ SAVE: "Salva"
3712
3898
  };
3713
3899
  var SIDEBAR$7 = {
3714
3900
  OVERVIEW: "Riepilogo",
@@ -3766,6 +3952,27 @@ var TRAVELERS_FORM$7 = {
3766
3952
  FIRST_NAME: "Nome",
3767
3953
  LAST_NAME: "Cognome",
3768
3954
  BIRTHDATE: "Data di nascita",
3955
+ NICKNAME: "Nickname",
3956
+ BIRTHPLACE: "Birthplace",
3957
+ NATIONALITY: "Nationality",
3958
+ PREFERRED_LANGUAGE: "Preferred language",
3959
+ TRAVELER_EMAIL: "Email",
3960
+ TRAVELER_PHONE: "Phone",
3961
+ TRAVELER_MOBILE: "Mobile phone",
3962
+ PASSPORT_NUMBER: "Passport number",
3963
+ PASSPORT_ISSUE_DATE: "Passport issue date",
3964
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
3965
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
3966
+ EMERGENCY_NUMBER: "Emergency number",
3967
+ HAS_INSURANCE: "Has insurance",
3968
+ INSURANCE_NAME: "Insurance name",
3969
+ INFO: "Additional information",
3970
+ WEIGHT: "Peso",
3971
+ WEIGHT_UNIT_KG: "kg",
3972
+ WEIGHT_UNIT_LB: "lb",
3973
+ HEIGHT: "Altezza",
3974
+ HEIGHT_UNIT_CM: "cm",
3975
+ HEIGHT_UNIT_FT_IN: "ft/in",
3769
3976
  STREET: "Via",
3770
3977
  STREET_PLACEHOLDER: "La tua via",
3771
3978
  HOUSE_NUMBER: "Numero civico",
@@ -4155,7 +4362,9 @@ var SHARED$6 = {
4155
4362
  ADULTS: "Volwassenen",
4156
4363
  CHILDREN: "Kinderen",
4157
4364
  SELECT: "Selecteer",
4158
- SELECTED: "Geselecteerd"
4365
+ SELECTED: "Geselecteerd",
4366
+ BOOKED: "Geboekt",
4367
+ SAVE: "Opslaan"
4159
4368
  };
4160
4369
  var SIDEBAR$6 = {
4161
4370
  OVERVIEW: "Overzicht",
@@ -4214,6 +4423,27 @@ var TRAVELERS_FORM$6 = {
4214
4423
  FIRST_NAME: "Voornaam",
4215
4424
  LAST_NAME: "Naam",
4216
4425
  BIRTHDATE: "Geboortedatum",
4426
+ NICKNAME: "Nickname",
4427
+ BIRTHPLACE: "Birthplace",
4428
+ NATIONALITY: "Nationality",
4429
+ PREFERRED_LANGUAGE: "Preferred language",
4430
+ TRAVELER_EMAIL: "Email",
4431
+ TRAVELER_PHONE: "Phone",
4432
+ TRAVELER_MOBILE: "Mobile phone",
4433
+ PASSPORT_NUMBER: "Passport number",
4434
+ PASSPORT_ISSUE_DATE: "Passport issue date",
4435
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
4436
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
4437
+ EMERGENCY_NUMBER: "Emergency number",
4438
+ HAS_INSURANCE: "Has insurance",
4439
+ INSURANCE_NAME: "Insurance name",
4440
+ INFO: "Additional information",
4441
+ WEIGHT: "Gewicht",
4442
+ WEIGHT_UNIT_KG: "kg",
4443
+ WEIGHT_UNIT_LB: "lb",
4444
+ HEIGHT: "Lengte",
4445
+ HEIGHT_UNIT_CM: "cm",
4446
+ HEIGHT_UNIT_FT_IN: "ft/in",
4217
4447
  STREET: "Straat",
4218
4448
  STREET_PLACEHOLDER: "Jouw straat",
4219
4449
  HOUSE_NUMBER: "Huisnr",
@@ -4606,7 +4836,9 @@ var SHARED$5 = {
4606
4836
  ADULTS: "Volwassenen",
4607
4837
  CHILDREN: "Kinderen",
4608
4838
  SELECT: "Selecteren",
4609
- SELECTED: "Geselecteerd"
4839
+ SELECTED: "Geselecteerd",
4840
+ BOOKED: "Geboekt",
4841
+ SAVE: "Opslaan"
4610
4842
  };
4611
4843
  var SIDEBAR$5 = {
4612
4844
  OVERVIEW: "Overzicht",
@@ -4664,6 +4896,27 @@ var TRAVELERS_FORM$5 = {
4664
4896
  FIRST_NAME: "Voornaam",
4665
4897
  LAST_NAME: "Achternaam",
4666
4898
  BIRTHDATE: "Geboortedatum",
4899
+ NICKNAME: "Nickname",
4900
+ BIRTHPLACE: "Birthplace",
4901
+ NATIONALITY: "Nationality",
4902
+ PREFERRED_LANGUAGE: "Preferred language",
4903
+ TRAVELER_EMAIL: "Email",
4904
+ TRAVELER_PHONE: "Phone",
4905
+ TRAVELER_MOBILE: "Mobile phone",
4906
+ PASSPORT_NUMBER: "Passport number",
4907
+ PASSPORT_ISSUE_DATE: "Passport issue date",
4908
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
4909
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
4910
+ EMERGENCY_NUMBER: "Emergency number",
4911
+ HAS_INSURANCE: "Has insurance",
4912
+ INSURANCE_NAME: "Insurance name",
4913
+ INFO: "Additional information",
4914
+ WEIGHT: "Gewicht",
4915
+ WEIGHT_UNIT_KG: "kg",
4916
+ WEIGHT_UNIT_LB: "lb",
4917
+ HEIGHT: "Lengte",
4918
+ HEIGHT_UNIT_CM: "cm",
4919
+ HEIGHT_UNIT_FT_IN: "ft/in",
4667
4920
  STREET: "Straat",
4668
4921
  STREET_PLACEHOLDER: "Uw straat",
4669
4922
  HOUSE_NUMBER: "Huisnummer",
@@ -5053,7 +5306,9 @@ var SHARED$4 = {
5053
5306
  ADULTS: "Voksne",
5054
5307
  CHILDREN: "Barn",
5055
5308
  SELECT: "Velg",
5056
- SELECTED: "Valgt"
5309
+ SELECTED: "Valgt",
5310
+ BOOKED: "Booket",
5311
+ SAVE: "Lagre"
5057
5312
  };
5058
5313
  var SIDEBAR$4 = {
5059
5314
  OVERVIEW: "Oversikt",
@@ -5111,6 +5366,27 @@ var TRAVELERS_FORM$4 = {
5111
5366
  FIRST_NAME: "Fornavn",
5112
5367
  LAST_NAME: "Etternavn",
5113
5368
  BIRTHDATE: "Fødselsdato",
5369
+ NICKNAME: "Nickname",
5370
+ BIRTHPLACE: "Birthplace",
5371
+ NATIONALITY: "Nationality",
5372
+ PREFERRED_LANGUAGE: "Preferred language",
5373
+ TRAVELER_EMAIL: "Email",
5374
+ TRAVELER_PHONE: "Phone",
5375
+ TRAVELER_MOBILE: "Mobile phone",
5376
+ PASSPORT_NUMBER: "Passport number",
5377
+ PASSPORT_ISSUE_DATE: "Passport issue date",
5378
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
5379
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
5380
+ EMERGENCY_NUMBER: "Emergency number",
5381
+ HAS_INSURANCE: "Has insurance",
5382
+ INSURANCE_NAME: "Insurance name",
5383
+ INFO: "Additional information",
5384
+ WEIGHT: "Vekt",
5385
+ WEIGHT_UNIT_KG: "kg",
5386
+ WEIGHT_UNIT_LB: "lb",
5387
+ HEIGHT: "Høyde",
5388
+ HEIGHT_UNIT_CM: "cm",
5389
+ HEIGHT_UNIT_FT_IN: "ft/in",
5114
5390
  STREET: "Gate",
5115
5391
  STREET_PLACEHOLDER: "Din gate",
5116
5392
  HOUSE_NUMBER: "Husnummer",
@@ -5500,7 +5776,9 @@ var SHARED$3 = {
5500
5776
  ADULTS: "Dorośli",
5501
5777
  CHILDREN: "Dzieci",
5502
5778
  SELECT: "Wybierz",
5503
- SELECTED: "Wybrane"
5779
+ SELECTED: "Wybrane",
5780
+ BOOKED: "Zarezerwowane",
5781
+ SAVE: "Zapisz"
5504
5782
  };
5505
5783
  var SIDEBAR$3 = {
5506
5784
  OVERVIEW: "Podsumowanie",
@@ -5558,6 +5836,27 @@ var TRAVELERS_FORM$3 = {
5558
5836
  FIRST_NAME: "Imię",
5559
5837
  LAST_NAME: "Nazwisko",
5560
5838
  BIRTHDATE: "Data urodzenia",
5839
+ NICKNAME: "Nickname",
5840
+ BIRTHPLACE: "Birthplace",
5841
+ NATIONALITY: "Nationality",
5842
+ PREFERRED_LANGUAGE: "Preferred language",
5843
+ TRAVELER_EMAIL: "Email",
5844
+ TRAVELER_PHONE: "Phone",
5845
+ TRAVELER_MOBILE: "Mobile phone",
5846
+ PASSPORT_NUMBER: "Passport number",
5847
+ PASSPORT_ISSUE_DATE: "Passport issue date",
5848
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
5849
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
5850
+ EMERGENCY_NUMBER: "Emergency number",
5851
+ HAS_INSURANCE: "Has insurance",
5852
+ INSURANCE_NAME: "Insurance name",
5853
+ INFO: "Additional information",
5854
+ WEIGHT: "Waga",
5855
+ WEIGHT_UNIT_KG: "kg",
5856
+ WEIGHT_UNIT_LB: "lb",
5857
+ HEIGHT: "Wzrost",
5858
+ HEIGHT_UNIT_CM: "cm",
5859
+ HEIGHT_UNIT_FT_IN: "ft/in",
5561
5860
  STREET: "Ulica",
5562
5861
  STREET_PLACEHOLDER: "Twoja ulica",
5563
5862
  HOUSE_NUMBER: "Numer domu",
@@ -5947,7 +6246,9 @@ var SHARED$2 = {
5947
6246
  ADULTS: "Adultos",
5948
6247
  CHILDREN: "Crianças",
5949
6248
  SELECT: "Selecionar",
5950
- SELECTED: "Selecionado"
6249
+ SELECTED: "Selecionado",
6250
+ BOOKED: "Reservado",
6251
+ SAVE: "Guardar"
5951
6252
  };
5952
6253
  var SIDEBAR$2 = {
5953
6254
  OVERVIEW: "Resumo",
@@ -6005,6 +6306,27 @@ var TRAVELERS_FORM$2 = {
6005
6306
  FIRST_NAME: "Nome",
6006
6307
  LAST_NAME: "Apelido",
6007
6308
  BIRTHDATE: "Data de nascimento",
6309
+ NICKNAME: "Nickname",
6310
+ BIRTHPLACE: "Birthplace",
6311
+ NATIONALITY: "Nationality",
6312
+ PREFERRED_LANGUAGE: "Preferred language",
6313
+ TRAVELER_EMAIL: "Email",
6314
+ TRAVELER_PHONE: "Phone",
6315
+ TRAVELER_MOBILE: "Mobile phone",
6316
+ PASSPORT_NUMBER: "Passport number",
6317
+ PASSPORT_ISSUE_DATE: "Passport issue date",
6318
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
6319
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
6320
+ EMERGENCY_NUMBER: "Emergency number",
6321
+ HAS_INSURANCE: "Has insurance",
6322
+ INSURANCE_NAME: "Insurance name",
6323
+ INFO: "Additional information",
6324
+ WEIGHT: "Peso",
6325
+ WEIGHT_UNIT_KG: "kg",
6326
+ WEIGHT_UNIT_LB: "lb",
6327
+ HEIGHT: "Altura",
6328
+ HEIGHT_UNIT_CM: "cm",
6329
+ HEIGHT_UNIT_FT_IN: "ft/in",
6008
6330
  STREET: "Rua",
6009
6331
  STREET_PLACEHOLDER: "A sua rua",
6010
6332
  HOUSE_NUMBER: "Número de porta",
@@ -6394,7 +6716,9 @@ var SHARED$1 = {
6394
6716
  ADULTS: "Vuxna",
6395
6717
  CHILDREN: "Barn",
6396
6718
  SELECT: "Välj",
6397
- SELECTED: "Vald"
6719
+ SELECTED: "Vald",
6720
+ BOOKED: "Bokad",
6721
+ SAVE: "Spara"
6398
6722
  };
6399
6723
  var SIDEBAR$1 = {
6400
6724
  OVERVIEW: "Översikt",
@@ -6452,6 +6776,27 @@ var TRAVELERS_FORM$1 = {
6452
6776
  FIRST_NAME: "Förnamn",
6453
6777
  LAST_NAME: "Efternamn",
6454
6778
  BIRTHDATE: "Födelsedatum",
6779
+ NICKNAME: "Nickname",
6780
+ BIRTHPLACE: "Birthplace",
6781
+ NATIONALITY: "Nationality",
6782
+ PREFERRED_LANGUAGE: "Preferred language",
6783
+ TRAVELER_EMAIL: "Email",
6784
+ TRAVELER_PHONE: "Phone",
6785
+ TRAVELER_MOBILE: "Mobile phone",
6786
+ PASSPORT_NUMBER: "Passport number",
6787
+ PASSPORT_ISSUE_DATE: "Passport issue date",
6788
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
6789
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
6790
+ EMERGENCY_NUMBER: "Emergency number",
6791
+ HAS_INSURANCE: "Has insurance",
6792
+ INSURANCE_NAME: "Insurance name",
6793
+ INFO: "Additional information",
6794
+ WEIGHT: "Vikt",
6795
+ WEIGHT_UNIT_KG: "kg",
6796
+ WEIGHT_UNIT_LB: "lb",
6797
+ HEIGHT: "Längd",
6798
+ HEIGHT_UNIT_CM: "cm",
6799
+ HEIGHT_UNIT_FT_IN: "ft/in",
6455
6800
  STREET: "Gata",
6456
6801
  STREET_PLACEHOLDER: "Din gata",
6457
6802
  HOUSE_NUMBER: "Husnummer",
@@ -6841,7 +7186,9 @@ var SHARED = {
6841
7186
  ADULTS: "大人",
6842
7187
  CHILDREN: "子供",
6843
7188
  SELECT: "選択",
6844
- SELECTED: "選択済み"
7189
+ SELECTED: "選択済み",
7190
+ BOOKED: "予約済み",
7191
+ SAVE: "保存"
6845
7192
  };
6846
7193
  var SIDEBAR = {
6847
7194
  OVERVIEW: "概要",
@@ -6899,6 +7246,27 @@ var TRAVELERS_FORM = {
6899
7246
  FIRST_NAME: "名",
6900
7247
  LAST_NAME: "姓",
6901
7248
  BIRTHDATE: "生年月日",
7249
+ NICKNAME: "Nickname",
7250
+ BIRTHPLACE: "Birthplace",
7251
+ NATIONALITY: "Nationality",
7252
+ PREFERRED_LANGUAGE: "Preferred language",
7253
+ TRAVELER_EMAIL: "Email",
7254
+ TRAVELER_PHONE: "Phone",
7255
+ TRAVELER_MOBILE: "Mobile phone",
7256
+ PASSPORT_NUMBER: "Passport number",
7257
+ PASSPORT_ISSUE_DATE: "Passport issue date",
7258
+ PASSPORT_ISSUED_LOCATION: "Passport issued location",
7259
+ PASSPORT_EXPIRY_DATE: "Passport expiry date",
7260
+ EMERGENCY_NUMBER: "Emergency number",
7261
+ HAS_INSURANCE: "Has insurance",
7262
+ INSURANCE_NAME: "Insurance name",
7263
+ INFO: "Additional information",
7264
+ WEIGHT: "体重",
7265
+ WEIGHT_UNIT_KG: "kg",
7266
+ WEIGHT_UNIT_LB: "lb",
7267
+ HEIGHT: "身長",
7268
+ HEIGHT_UNIT_CM: "cm",
7269
+ HEIGHT_UNIT_FT_IN: "ft/in",
6902
7270
  STREET: "住所",
6903
7271
  STREET_PLACEHOLDER: "住所を入力",
6904
7272
  HOUSE_NUMBER: "番地",
@@ -7552,6 +7920,14 @@ exports.AvailabilitySearchType = void 0;
7552
7920
  AvailabilitySearchType[(AvailabilitySearchType["flight"] = 3)] = "flight";
7553
7921
  })(exports.AvailabilitySearchType || (exports.AvailabilitySearchType = {}));
7554
7922
 
7923
+ var CustomFieldDataType = {
7924
+ bool: 0,
7925
+ date: 1,
7926
+ time: 2,
7927
+ string: 3,
7928
+ numeric: 4,
7929
+ };
7930
+
7555
7931
  var DataType = {
7556
7932
  text: "text",
7557
7933
  numeric: "number",
@@ -7567,6 +7943,12 @@ var DataType = {
7567
7943
  template: "template",
7568
7944
  };
7569
7945
 
7946
+ exports.DateAmountType = void 0;
7947
+ (function (DateAmountType) {
7948
+ DateAmountType[(DateAmountType["days"] = 0)] = "days";
7949
+ DateAmountType[(DateAmountType["months"] = 1)] = "months";
7950
+ })(exports.DateAmountType || (exports.DateAmountType = {}));
7951
+
7570
7952
  var DossierType = {
7571
7953
  hotelOnly: 0,
7572
7954
  transportOnly: 1,
@@ -7574,6 +7956,13 @@ var DossierType = {
7574
7956
  package: 3,
7575
7957
  };
7576
7958
 
7959
+ var DurationType = {
7960
+ hours: 0,
7961
+ days: 1,
7962
+ nights: 2,
7963
+ minutes: 3,
7964
+ };
7965
+
7577
7966
  var EntryLineFlag = {
7578
7967
  none: 0,
7579
7968
  allotmentNoPlace: 1,
@@ -7651,6 +8040,11 @@ var Gender = {
7651
8040
  other: 2,
7652
8041
  };
7653
8042
 
8043
+ var HeightType = {
8044
+ centimeters: 0,
8045
+ feetInches: 1,
8046
+ };
8047
+
7654
8048
  exports.MetaDataItemPropertyType = void 0;
7655
8049
  (function (MetaDataItemPropertyType) {
7656
8050
  MetaDataItemPropertyType[(MetaDataItemPropertyType["Height"] = 0)] = "Height";
@@ -7687,6 +8081,22 @@ var PaymentType = {
7687
8081
  cash: 3,
7688
8082
  };
7689
8083
 
8084
+ exports.PortalQsmType = void 0;
8085
+ (function (PortalQsmType) {
8086
+ PortalQsmType[(PortalQsmType["Multidestination"] = 0)] = "Multidestination";
8087
+ PortalQsmType[(PortalQsmType["Accommodation"] = 1)] = "Accommodation";
8088
+ PortalQsmType[(PortalQsmType["AccommodationAndFlight"] = 2)] =
8089
+ "AccommodationAndFlight";
8090
+ PortalQsmType[(PortalQsmType["Flight"] = 3)] = "Flight";
8091
+ PortalQsmType[(PortalQsmType["RoundTrip"] = 4)] = "RoundTrip";
8092
+ PortalQsmType[(PortalQsmType["GroupTour"] = 5)] = "GroupTour";
8093
+ PortalQsmType[(PortalQsmType["Package"] = 6)] = "Package";
8094
+ PortalQsmType[(PortalQsmType["Ticket"] = 7)] = "Ticket";
8095
+ PortalQsmType[(PortalQsmType["Car"] = 8)] = "Car";
8096
+ PortalQsmType[(PortalQsmType["Transfer"] = 9)] = "Transfer";
8097
+ PortalQsmType[(PortalQsmType["Cruise"] = 10)] = "Cruise";
8098
+ })(exports.PortalQsmType || (exports.PortalQsmType = {}));
8099
+
7690
8100
  var PriceChartType = {
7691
8101
  purchasePrices: 0,
7692
8102
  sellingPrices: 1,
@@ -7720,6 +8130,26 @@ var RoomType = {
7720
8130
  pk6: 5,
7721
8131
  };
7722
8132
 
8133
+ var RouteTransportType = {
8134
+ none: 0,
8135
+ privateTransport: 1,
8136
+ publicTransport: 2,
8137
+ rentalCar: 3,
8138
+ bus: 4,
8139
+ camper: 5,
8140
+ car: 6,
8141
+ charter: 7,
8142
+ cruise: 8,
8143
+ ferry: 9,
8144
+ flight: 10,
8145
+ taxi: 11,
8146
+ train: 12,
8147
+ transfer: 13,
8148
+ rocket: 14,
8149
+ walking: 15,
8150
+ cycling: 16,
8151
+ };
8152
+
7723
8153
  var SaleType = {
7724
8154
  ownOrganization: 0,
7725
8155
  resale: 1,
@@ -7759,6 +8189,13 @@ var ServiceType = {
7759
8189
  camp: 30,
7760
8190
  };
7761
8191
 
8192
+ var TrajectNodeType = {
8193
+ regular: 0,
8194
+ connectingNode: 1,
8195
+ poi: 2,
8196
+ subroute: 3,
8197
+ };
8198
+
7762
8199
  exports.UnitOfMeasure = void 0;
7763
8200
  (function (UnitOfMeasure) {
7764
8201
  UnitOfMeasure[(UnitOfMeasure["cm"] = 0)] = "cm";
@@ -7791,60 +8228,9 @@ var VendorType = {
7791
8228
  sunnyCars: 20,
7792
8229
  };
7793
8230
 
7794
- exports.DateAmountType = void 0;
7795
- (function (DateAmountType) {
7796
- DateAmountType[(DateAmountType["days"] = 0)] = "days";
7797
- DateAmountType[(DateAmountType["months"] = 1)] = "months";
7798
- })(exports.DateAmountType || (exports.DateAmountType = {}));
7799
-
7800
- exports.PortalQsmType = void 0;
7801
- (function (PortalQsmType) {
7802
- PortalQsmType[(PortalQsmType["Multidestination"] = 0)] = "Multidestination";
7803
- PortalQsmType[(PortalQsmType["Accommodation"] = 1)] = "Accommodation";
7804
- PortalQsmType[(PortalQsmType["AccommodationAndFlight"] = 2)] =
7805
- "AccommodationAndFlight";
7806
- PortalQsmType[(PortalQsmType["Flight"] = 3)] = "Flight";
7807
- PortalQsmType[(PortalQsmType["RoundTrip"] = 4)] = "RoundTrip";
7808
- PortalQsmType[(PortalQsmType["GroupTour"] = 5)] = "GroupTour";
7809
- PortalQsmType[(PortalQsmType["Package"] = 6)] = "Package";
7810
- PortalQsmType[(PortalQsmType["Ticket"] = 7)] = "Ticket";
7811
- PortalQsmType[(PortalQsmType["Car"] = 8)] = "Car";
7812
- PortalQsmType[(PortalQsmType["Transfer"] = 9)] = "Transfer";
7813
- PortalQsmType[(PortalQsmType["Cruise"] = 10)] = "Cruise";
7814
- })(exports.PortalQsmType || (exports.PortalQsmType = {}));
7815
-
7816
- var TrajectNodeType = {
7817
- regular: 0,
7818
- connectingNode: 1,
7819
- poi: 2,
7820
- subroute: 3,
7821
- };
7822
-
7823
- var DurationType = {
7824
- hours: 0,
7825
- days: 1,
7826
- nights: 2,
7827
- minutes: 3,
7828
- };
7829
-
7830
- var RouteTransportType = {
7831
- none: 0,
7832
- privateTransport: 1,
7833
- publicTransport: 2,
7834
- rentalCar: 3,
7835
- bus: 4,
7836
- camper: 5,
7837
- car: 6,
7838
- charter: 7,
7839
- cruise: 8,
7840
- ferry: 9,
7841
- flight: 10,
7842
- taxi: 11,
7843
- train: 12,
7844
- transfer: 13,
7845
- rocket: 14,
7846
- walking: 15,
7847
- cycling: 16,
8231
+ var WeightType = {
8232
+ kilograms: 0,
8233
+ pounds: 1,
7848
8234
  };
7849
8235
 
7850
8236
  /******************************************************************************
@@ -14978,6 +15364,34 @@ var getContentDraft = function (config, signal) {
14978
15364
  var apiKey = config.apiKey;
14979
15365
  return get(url, apiKey, config.token, signal, true);
14980
15366
  };
15367
+ /**
15368
+ * api/web/content/live/filtered
15369
+ * Gets filtered Live content
15370
+ * @param config
15371
+ * @param request
15372
+ * @param signal
15373
+ * @returns OK if succeeded.
15374
+ */
15375
+ var getFilteredContentLive = function (config, request, signal) {
15376
+ var url = "" + config.host + ENDPOINT_LIVE + "/filtered";
15377
+ var apiKey = config.apiKey;
15378
+ var body = JSON.stringify(request);
15379
+ return post(url, apiKey, body, config.token, signal, true);
15380
+ };
15381
+ /**
15382
+ * api/web/content/draft/filtered
15383
+ * Gets filtered Draft (Internal) content
15384
+ * @param config
15385
+ * @param request
15386
+ * @param signal
15387
+ * @returns OK if succeeded.
15388
+ */
15389
+ var getFilteredContentDraft = function (config, request, signal) {
15390
+ var url = "" + config.host + ENDPOINT_DRAFT + "/filtered";
15391
+ var apiKey = config.apiKey;
15392
+ var body = JSON.stringify(request);
15393
+ return post(url, apiKey, body, config.token, signal, true);
15394
+ };
14981
15395
  /**
14982
15396
  * api/web/content/live/by-property
14983
15397
  * Gets Live content matching a property value (or values).
@@ -15105,6 +15519,7 @@ var ENDPOINT_TRAJECT = ENDPOINT$1 + "/traject";
15105
15519
  var ENDPOINT_ENTRY = function (magicLinkCode) {
15106
15520
  return ENDPOINT$1 + "/entry/" + magicLinkCode;
15107
15521
  };
15522
+ var ENDPOINT_SAVE_ENTRY = ENDPOINT$1 + "/entry/save";
15108
15523
  var startTransaction = function (config, signal) {
15109
15524
  var apiKey = config.apiKey;
15110
15525
  var url = "" + config.host + ENDPOINT_START_TRANSACTION;
@@ -15133,6 +15548,12 @@ var getEntry = function (config, magicLinkCode, signal) {
15133
15548
  var url = "" + config.host + ENDPOINT_ENTRY(magicLinkCode);
15134
15549
  return get(url, apiKey, config.token, signal, true);
15135
15550
  };
15551
+ var savePackagingEntry = function (config, request, signal) {
15552
+ var url = "" + config.host + ENDPOINT_SAVE_ENTRY;
15553
+ var apiKey = config.apiKey;
15554
+ var body = JSON.stringify(request);
15555
+ return post(url, apiKey, body, config.token, signal, true);
15556
+ };
15136
15557
  var getTrajectEntry = function (config, request, signal) {
15137
15558
  var url = "" + config.host + ENDPOINT_TRAJECT;
15138
15559
  var apiKey = config.apiKey;
@@ -15196,6 +15617,7 @@ var submitForm = function (config, id, request, signal) {
15196
15617
  };
15197
15618
 
15198
15619
  exports.AllotmentType = AllotmentType;
15620
+ exports.CustomFieldDataType = CustomFieldDataType;
15199
15621
  exports.DataType = DataType;
15200
15622
  exports.DossierType = DossierType;
15201
15623
  exports.DurationType = DurationType;
@@ -15206,6 +15628,7 @@ exports.FormFieldType = FormFieldType;
15206
15628
  exports.FormFieldWidth = FormFieldWidth;
15207
15629
  exports.FormType = FormType;
15208
15630
  exports.Gender = Gender;
15631
+ exports.HeightType = HeightType;
15209
15632
  exports.MetaDataType = MetaDataType;
15210
15633
  exports.PaymentType = PaymentType;
15211
15634
  exports.PriceChartType = PriceChartType;
@@ -15217,6 +15640,7 @@ exports.ServiceTokenError = ServiceTokenError;
15217
15640
  exports.ServiceType = ServiceType;
15218
15641
  exports.TrajectNodeType = TrajectNodeType;
15219
15642
  exports.VendorType = VendorType;
15643
+ exports.WeightType = WeightType;
15220
15644
  exports.agents = agents;
15221
15645
  exports.alternateFlights = alternateFlights;
15222
15646
  exports.alternateHotels = alternateHotels;
@@ -15264,6 +15688,8 @@ exports.getEntryList = getEntryList;
15264
15688
  exports.getEntryListv2 = getEntryListv2;
15265
15689
  exports.getEntryStatus = getEntryStatus;
15266
15690
  exports.getEntryTotals = getEntryTotals;
15691
+ exports.getFilteredContentDraft = getFilteredContentDraft;
15692
+ exports.getFilteredContentLive = getFilteredContentLive;
15267
15693
  exports.getInvoiceList = getInvoiceList;
15268
15694
  exports.getItinerary = getItinerary;
15269
15695
  exports.getLocations = getLocations;
@@ -15284,6 +15710,7 @@ exports.print = print;
15284
15710
  exports.readForm = readForm;
15285
15711
  exports.repriceAndIssueTicket = repriceAndIssueTicket;
15286
15712
  exports.resetPassword = resetPassword;
15713
+ exports.savePackagingEntry = savePackagingEntry;
15287
15714
  exports.search = search;
15288
15715
  exports.searchCountries = searchCountries;
15289
15716
  exports.searchElastic = searchElastic;
@@ -17475,7 +17902,7 @@ const Product = ({ productCode, productName, duration, rating }) => {
17475
17902
  const [hasFlight, setHasFlight] = useState(false);
17476
17903
  const [hasTransfer, setHasTransfer] = useState(false);
17477
17904
  const [rooms, setRooms] = useState([{ adults: 2, children: 0, childAges: [] }]);
17478
- const [searchResponse, setSearchResponse] = useState([]);
17905
+ const [searchResponse, setSearchResponse] = useState();
17479
17906
  const [detailResponse, setDetailResponse] = useState();
17480
17907
  const [dateRange, setDateRange] = useState();
17481
17908
  const [urlDateRange, setUrlDateRange] = useState({ from: null, to: null });
@@ -17613,6 +18040,9 @@ const Product = ({ productCode, productName, duration, rating }) => {
17613
18040
  setPackageProductName(selectedItem.name);
17614
18041
  };
17615
18042
  useEffect(() => {
18043
+ if (searchResponse === undefined) {
18044
+ return;
18045
+ }
17616
18046
  if (searchResponse && !isEmpty$1(searchResponse)) {
17617
18047
  setSearchResults(searchResponse);
17618
18048
  const selectedItem = searchResponse.find((item) => new Date(item.fromDate).getTime() === dateRange?.fromDate?.getTime() && new Date(item.toDate).getTime() === dateRange?.toDate?.getTime());
@@ -18611,276 +19041,1102 @@ const SUMMARY_STEP = 5;
18611
19041
  const CONFIRMATION_STEP = 6;
18612
19042
  const ERROR_STEP = 7;
18613
19043
 
18614
- const fetchPriceDetails$1 = async (apiSettings, request, signal, languageCode) => {
18615
- const tideClientConfig = buildTideClientConfig(apiSettings);
18616
- return await build.priceDetails(tideClientConfig, request, signal, languageCode);
18617
- };
18618
- const priceDetailsApi = {
18619
- fetchPriceDetails: fetchPriceDetails$1
19044
+ const LabeledInput = ({ name, type, required, value, defaultValue, min, max, label, placeholder, extraClassName, hasError, onChange, onBlur }) => {
19045
+ return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
19046
+ React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
19047
+ React__default.createElement("input", { name: name, type: type ?? 'text', required: required, className: "form__input", min: min, max: max, placeholder: placeholder, onChange: onChange, onBlur: onBlur, value: value, defaultValue: defaultValue })));
18620
19048
  };
18621
19049
 
18622
- const updatePackageDetails = (packageDetails, changedLines) => {
18623
- return {
18624
- ...packageDetails,
18625
- options: packageDetails.options.map((opt) => {
18626
- return {
18627
- ...opt,
18628
- rooms: opt.isSelected ? updateRooms(opt.rooms, changedLines) : opt.rooms,
18629
- groups: opt.isSelected ? updateBookingGroups(opt.groups, changedLines) : opt.groups,
18630
- optionUnits: opt.isSelected ? updateOptionUnits(opt.optionUnits, changedLines) : opt.optionUnits,
18631
- optionPax: opt.isSelected ? updateOptionPax(opt.optionPax, changedLines) : opt.optionPax
18632
- };
18633
- })
18634
- };
18635
- };
18636
- // ROOMS
18637
- const updateRooms = (rooms, changedLines) => {
18638
- return rooms.map((room) => ({
18639
- ...room,
18640
- options: room.options.map((option) => ({
18641
- ...option,
18642
- price: changedLines.find((x) => x.entryLineGuid == option.entryLineGuid)?.price ?? option.price
18643
- }))
18644
- }));
18645
- };
18646
- // PAX
18647
- const updateOptionPax = (pax, changedLines) => {
18648
- return pax.map((p) => ({
18649
- ...p,
18650
- groups: updatePaxGroups(p.groups, changedLines)
18651
- }));
18652
- };
18653
- const updatePaxGroups = (groups, changedLines) => {
18654
- return groups.map((g) => ({
18655
- ...g,
18656
- options: g.options.map((o) => ({
18657
- ...o,
18658
- groups: updatePaxGroups(o.groups, changedLines),
18659
- line: {
18660
- ...o.line,
18661
- price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
18662
- },
18663
- alternatives: o.alternatives.map((a) => ({
18664
- ...a,
18665
- price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
18666
- }))
18667
- }))
18668
- }));
18669
- };
18670
- // UNITS
18671
- const updateOptionUnits = (units, changedLines) => {
18672
- return units.map((u) => ({
18673
- ...u,
18674
- groups: updateUnitGroups(u.groups, changedLines)
18675
- }));
18676
- };
18677
- const updateUnitGroups = (groups, changedLines) => {
18678
- return groups.map((g) => ({
18679
- ...g,
18680
- options: g.options.map((o) => ({
18681
- ...o,
18682
- groups: updateUnitGroups(o.groups, changedLines),
18683
- pax: updateOptionPax(o.pax, changedLines),
18684
- line: {
18685
- ...o.line,
18686
- price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
18687
- },
18688
- alternatives: o.alternatives.map((a) => ({
18689
- ...a,
18690
- price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
18691
- }))
18692
- }))
18693
- }));
18694
- };
18695
- // BOOKING
18696
- const updateBookingGroups = (groups, changedLines) => {
18697
- return groups.map((g) => ({
18698
- ...g,
18699
- options: g.options.map((o) => ({
18700
- ...o,
18701
- groups: updateBookingGroups(o.groups, changedLines),
18702
- units: updateOptionUnits(o.units, changedLines),
18703
- pax: updateOptionPax(o.pax, changedLines),
18704
- line: {
18705
- ...o.line,
18706
- price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
18707
- },
18708
- alternatives: o.alternatives.map((a) => ({
18709
- ...a,
18710
- price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
18711
- }))
18712
- }))
18713
- }));
19050
+ const LabeledSelect = ({ name, id, required, value, defaultValue, label, extraClassName, extraDropdownClassName, hasError, options, onChange, onBlur }) => {
19051
+ return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
19052
+ React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
19053
+ React__default.createElement("div", { className: buildClassName(['dropdown', extraDropdownClassName]) },
19054
+ React__default.createElement("select", { name: name, id: id, defaultValue: defaultValue, value: value, onBlur: onBlur, onChange: onChange }, options?.map((option) => (React__default.createElement("option", { key: option.key, value: option.value }, option.label)))))));
18714
19055
  };
18715
19056
 
18716
- const fetchPriceDetails = createAsyncThunk('priceDetails/fetchPriceDetails', async (_, { dispatch, getState, signal }) => {
18717
- const state = getState();
18718
- const languageCode = selectLanguageCode(state);
18719
- const request = selectBookingPackageBookRequest(state);
18720
- if (!request) {
18721
- throw Error('Product not available.');
18722
- }
18723
- dispatch(setFetchingPriceDetails(true));
18724
- dispatch(resetPriceDetails());
18725
- const priceDetails = await priceDetailsApi.fetchPriceDetails(state.apiSettings, request, signal, languageCode);
18726
- dispatch(setFetchingPriceDetails(false));
18727
- const packageDetails = selectPackageDetails(state);
18728
- if (packageDetails) {
18729
- const updatedPackageDetails = updatePackageDetails(packageDetails, priceDetails.changedLines);
18730
- dispatch(setPackage(updatedPackageDetails));
19057
+ const normalize = (v) => (v == null ? '' : String(v));
19058
+ const parseCombined = (raw, countries) => {
19059
+ const value = normalize(raw).trim();
19060
+ if (!value)
19061
+ return { prefix: '', number: '' };
19062
+ // Try to match a known prefix at the start. Prefer longest match.
19063
+ const sorted = [...countries].sort((a, b) => b.phonePrefix.length - a.phonePrefix.length);
19064
+ const hit = sorted.find((c) => value.startsWith(c.phonePrefix));
19065
+ if (hit) {
19066
+ const rest = value
19067
+ .slice(hit.phonePrefix.length)
19068
+ .trim()
19069
+ .replace(/^[-\s]+/, '');
19070
+ return { prefix: hit.phonePrefix, number: rest };
18731
19071
  }
18732
- return priceDetails;
18733
- });
18734
- const priceDetailsSlice = createSlice({
18735
- name: 'priceDetails',
18736
- initialState: {
18737
- priceDetails: [],
18738
- notifications: [],
18739
- isBusy: false
18740
- },
18741
- reducers: {
18742
- setFetchingPriceDetails(state, action) {
18743
- state.isBusy = action.payload;
18744
- },
18745
- setNotifications(state, action) {
18746
- state.notifications = action.payload;
18747
- },
18748
- resetPriceDetails(state, _) {
18749
- state.priceDetails = [];
18750
- }
18751
- },
18752
- extraReducers: (builder) => {
18753
- builder.addCase(fetchPriceDetails.fulfilled, (state, action) => {
18754
- if (action.payload) {
18755
- state.deposit = action.payload.deposit;
18756
- state.commission = action.payload.commission;
18757
- state.priceDetails = action.payload.details;
18758
- state.notifications = action.payload.notifications;
18759
- }
18760
- });
18761
- builder.addCase(fetchPriceDetails.rejected, (state) => {
18762
- state.isBusy = false;
19072
+ // Fallback: split on first space if it looks like a +prefix number
19073
+ const m = value.match(/^(\+\d{1,4})[\s-]*(.*)$/);
19074
+ if (m)
19075
+ return { prefix: m[1], number: m[2] };
19076
+ return { prefix: '', number: value };
19077
+ };
19078
+ const PhoneInput = ({ name, required, value, label, placeholder, extraClassName, hasError, countries, countryIso2, onChange, onBlur }) => {
19079
+ // Derive initial state from `value`
19080
+ const initialCountry = countries.find((c) => c.iso2 === countryIso2);
19081
+ const initial = useMemo(() => parseCombined(normalize(value), countries), [value, countries]);
19082
+ const [prefix, setPrefix] = useState(initial.prefix);
19083
+ const [number, setNumber] = useState(initial.number);
19084
+ // Keep state in sync if the parent changes `value`
19085
+ useEffect(() => {
19086
+ const parsed = !prefix && !number && initialCountry ? { prefix: initialCountry.phonePrefix, number: '' } : parseCombined(normalize(value), countries);
19087
+ if (parsed.prefix)
19088
+ setPrefix(parsed.prefix);
19089
+ if (parsed.number)
19090
+ setNumber(parsed.number);
19091
+ }, [value, countries, countryIso2]);
19092
+ const emitCombinedChange = (e, nextPrefix, nextNumber) => {
19093
+ // Combine with a space, unless the number already starts with a dash or space
19094
+ const combined = nextPrefix && nextNumber ? compact([nextPrefix, nextNumber]).join(' ') : null;
19095
+ onChange?.({
19096
+ ...e,
19097
+ type: 'change',
19098
+ target: { name, value: combined },
19099
+ currentTarget: { name, value: combined }
18763
19100
  });
18764
- }
18765
- });
18766
- const { setFetchingPriceDetails } = priceDetailsSlice.actions;
18767
- const { resetPriceDetails, setNotifications } = priceDetailsSlice.actions;
18768
- const selectNotifications = (state) => state.priceDetails.notifications;
18769
- var priceDetailsReducer = priceDetailsSlice.reducer;
19101
+ };
19102
+ const handleCountryBlur = (e) => {
19103
+ onBlur?.(e);
19104
+ };
19105
+ const onCountryChange = (e) => {
19106
+ const next = e.target.value;
19107
+ setPrefix(next);
19108
+ emitCombinedChange(e, next, number);
19109
+ };
19110
+ const onPhoneChange = (e) => {
19111
+ const cleaned = e.target.value.replace(/[^\d\s-]/g, '');
19112
+ setNumber(cleaned);
19113
+ emitCombinedChange(e, prefix, cleaned);
19114
+ };
19115
+ const handleNumberBlur = (e) => {
19116
+ onBlur?.(e);
19117
+ };
19118
+ // Ensure the select shows a reasonable default when prefix is empty
19119
+ const selectValue = prefix || '';
19120
+ return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
19121
+ label && React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
19122
+ React__default.createElement("div", { className: "phone-input" },
19123
+ React__default.createElement("div", { className: "dropdown" },
19124
+ React__default.createElement("select", { "aria-label": label ? `${label} – country code` : 'Country calling code', name: `${name}__country`, value: selectValue, onBlur: handleCountryBlur, onChange: onCountryChange },
19125
+ React__default.createElement("option", { value: "", disabled: true }),
19126
+ countries?.map((option) => (React__default.createElement("option", { key: option.iso2, value: option.phonePrefix },
19127
+ option.name,
19128
+ " (",
19129
+ option.phonePrefix,
19130
+ ")"))))),
19131
+ React__default.createElement("input", { "aria-label": label ? `${label} – number` : 'Phone number', name: `${name}__number`, type: "tel", inputMode: "tel", required: required, className: "form__input", placeholder: placeholder, onChange: onPhoneChange, onBlur: handleNumberBlur, value: number }),
19132
+ React__default.createElement("input", { type: "hidden", name: name, value: compact([prefix, number]).join(' ') }))));
19133
+ };
18770
19134
 
18771
- const selectHasMounted = (state) => state.booking.hasMounted;
18772
- const selectGeneratePaymentUrl = (state) => state.booking.generatePaymentUrl;
18773
- const selectSkipPaymentWithAgent = (state) => state.booking.skipPaymentWithAgent;
18774
- const selectIsFetchingProductOptions = (state) => state.booking.isBusy;
18775
- const selectDepartureFlight = (state) => state.booking.package?.outwardFlights?.find((x) => x.isSelected);
18776
- const selectReturnFlight = (state) => state.booking.package?.returnFlights?.find((x) => x.isSelected);
18777
- const selectPackageRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.rooms;
18778
- const selectIncludedServiceTypes = (state) => selectActiveOption(state)?.includedServiceTypes;
18779
- const selectAvailabilities = (state) => state.booking.package?.options.find((x) => x.isSelected)?.availabilities;
18780
- const selectPackageTags = (state) => state.booking.package?.tags;
18781
- const selectIsOnRequest = (state) => state.booking.package?.options.find((x) => x.isSelected)?.isOnRequest;
18782
- const selectPackageOptionUnits = (state) => state.booking.package?.options.find((x) => x.isSelected)?.optionUnits;
18783
- const selectPackageOptionPax = (state) => state.booking.package?.options.find((x) => x.isSelected)?.optionPax;
18784
- const selectPackageGroups = (state) => state.booking.package?.options.find((x) => x.isSelected)?.groups;
18785
- const selectPackageDetails = (state) => state.booking.package;
18786
- const selectPackageFlights = (state) => ({
18787
- outward: state.booking.package?.outwardFlights,
18788
- return: state.booking.package?.returnFlights
18789
- });
18790
- const selectFlightMetaData = (state) => state.booking.package?.flightInfo.metaData;
18791
- const selectActiveOption = (state) => state.booking.package?.options.find((x) => x.isSelected);
18792
- const selectPackageAirlineGroups = createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airlineGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
18793
- const selectPackageAirportGroups = createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airportGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
18794
- const selectRoomOptionDepartureFlightsMetaData = createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
18795
- const roomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected).shift());
18796
- return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
18797
- });
18798
- const selectRoomOptionReturnFlightsMetaData = createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
18799
- const selectedRoomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected));
18800
- // check if there are return flights selected
18801
- if (selectedRoomOptions?.some((ro) => ro.length > 1)) {
18802
- const roomOptions = ativeOption?.rooms.map((r) => r.options
18803
- .filter((o) => o.isSelected)
18804
- .reverse()
18805
- .shift());
18806
- return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
18807
- }
18808
- return undefined;
18809
- });
18810
- const selectApiSettings = (state) => state.apiSettings;
18811
- const selectIsUnavailable = (state) => state.booking.isUnavailable;
18812
- const selectRequestRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.requestRooms;
18813
- const selectOfficeId = (state) => state.booking.officeId;
18814
- const selectLanguageCode = (state) => state.booking.languageCode;
18815
- const selectCurrencyCode = (state) => state.booking.package?.currencyCode ?? 'EUR';
18816
- const selectLanguage = (state) => state.booking.languageCode;
18817
- const selectAllDynamicTranslations = (state) => state.booking.translations;
18818
- const selectDynamicTranslations = createSelector([selectAllDynamicTranslations, selectLanguage], (allDynamicTranslations, language) => {
18819
- return allDynamicTranslations?.find((x) => x.language == language)?.value ?? {};
18820
- });
18821
- // Host override files are hand-maintained, and a null only ever blanks a key the component
18822
- // then reads, so treat it like a missing key (lodash merge already skips undefined).
18823
- const withoutNulls = (value) => isPlainObject$1(value)
18824
- ? mapValues(pickBy(value, (x) => x !== null), withoutNulls)
18825
- : value;
18826
- // getTranslations deep-merges the overrides over a clone of the built-in translations, so a
18827
- // host override of a nested group (TRAVELERS_FORM.VALIDATION, TRAVELERS_FORM.COUNTRIES)
18828
- // only replaces the keys it actually contains. Merging per section one level deep dropped
18829
- // every other built-in key of such a group, which made those keys resolve to undefined and
18830
- // crash format() in the consuming component.
18831
- const selectTranslations = createSelector([selectLanguage, selectDynamicTranslations], (language, dynamicTranslations) => getTranslations(language, isEmpty$1(dynamicTranslations) ? undefined : withoutNulls(dynamicTranslations)));
18832
- const selectBookingOptions = (state) => state.booking.bookingOptions;
18833
- const selectBookingType = (state) => state.booking.bookingType;
18834
- const selectTagIds = (state) => state.booking.tagIds;
18835
- const selectAgentAdressId = (state) => state.booking.agentAdressId;
18836
- const selectProductAttributes = (state) => state.booking.productAttributes;
18837
- const selectBookingAttributes = (state) => state.booking.bookingAttributes;
18838
- const selectBookingNumber = (state) => state.booking.bookingNumber;
18839
- const selectIsOption = (state) => state.booking.isOption;
18840
- const selectBookingRooms = (state) => state.booking.bookingAttributes?.rooms;
18841
- const selectBookingRemarks = (state) => state.booking.remarks;
18842
- const selectVoucherCodes = (state) => state.booking.voucherCodes;
18843
- const selectCalculateDeposit = (state) => state.booking.calculateDeposit;
18844
- const selectShowCommission = (state) => state.booking.showCommission;
18845
- const selectIsRetry = (state) => state.booking.isRetry;
18846
- const selectStartDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.fromDate;
18847
- const selectEndDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.toDate;
18848
- const selectAgents = (state) => state.booking.agents;
18849
- const selectCountries = (state) => state.booking.countries;
18850
- const selectProductCode = (state) => state.booking.productAttributes?.productCode;
18851
- const selectAccommodationCodes = (state) => {
18852
- const accommodationCodes = [];
18853
- state.booking.package?.options.forEach((o) => {
18854
- o.rooms.forEach((r) => r.options.forEach((ro) => {
18855
- if (!accommodationCodes.some((y) => y === ro.accommodationCode)) {
18856
- accommodationCodes.push(ro.accommodationCode);
18857
- }
18858
- }));
18859
- });
18860
- return accommodationCodes;
19135
+ const hasVisibleError = (formik, key) => get(formik.errors, key) && get(formik.touched, key);
19136
+
19137
+ const GenderControl = ({ translations, value, formik, name }) => {
19138
+ return (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(formik, name) && 'form__group--error']) },
19139
+ React__default.createElement("label", { className: "form__label" },
19140
+ translations.TRAVELERS_FORM.GENDER_ID,
19141
+ " *"),
19142
+ React__default.createElement("div", { className: "radiobutton-group" },
19143
+ React__default.createElement("div", { className: "radiobutton" },
19144
+ React__default.createElement("label", { className: "radiobutton__label" },
19145
+ React__default.createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: "m", checked: value.gender === 'm' }),
19146
+ translations.TRAVELERS_FORM.MALE_GENDER)),
19147
+ React__default.createElement("div", { className: "radiobutton" },
19148
+ React__default.createElement("label", { className: "radiobutton__label" },
19149
+ React__default.createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: "f", checked: value.gender === 'f' }),
19150
+ translations.TRAVELERS_FORM.FEMALE_GENDER)))));
18861
19151
  };
18862
- const selectAccommodationViews = (state) => state.booking.accommodationViews;
18863
- const selectMappingInfo = (state) => state.booking.package?.options.find((x) => x.isSelected)?.mappingInfo;
18864
- const selectBookingQuery = (state) => {
18865
- const bookingAttributes = state.booking.bookingAttributes;
18866
- if (!bookingAttributes) {
18867
- return undefined;
18868
- }
18869
- const params = {};
18870
- Object.entries(bookingAttributes).forEach(([key, value]) => {
18871
- if (key === 'startDate' || key === 'endDate') {
18872
- value = format$2(parseISO(value), 'yyyy-MM-dd');
18873
- }
18874
- if (key === 'rooms') {
18875
- value = JsonURL.stringify(value.map((room) => omit(room, ['children'])), {
18876
- AQF: true
18877
- });
19152
+
19153
+ const TypeAheadInput = ({ name, value, placeholder, options, onChange, onSelect, onClear }) => {
19154
+ const [showItems, setShowItems] = useState(false);
19155
+ const handleChange = (e) => {
19156
+ if (onChange) {
19157
+ onChange(e.target.value);
18878
19158
  }
18879
- if (key === 'allotmentIds' && !value.length) {
18880
- value = undefined;
19159
+ };
19160
+ const handleClearClick = (e) => {
19161
+ if (onClear) {
19162
+ onClear();
18881
19163
  }
18882
- if (key === 'flight' && value) {
18883
- var flightInfo = value;
19164
+ setShowItems(false);
19165
+ };
19166
+ return (React__default.createElement("div", { className: "typeahead" },
19167
+ React__default.createElement("div", { className: "typeahead__trigger typeahead__trigger--icon" },
19168
+ React__default.createElement(Icon, { name: "ui-qsm-location" }),
19169
+ React__default.createElement("input", { type: "text", className: "form__input", name: name, value: value, onChange: handleChange, placeholder: placeholder, required: true, autoComplete: "off", onKeyDown: (e) => {
19170
+ if (e.key === 'Tab' && options && onSelect) {
19171
+ onSelect(options[0].key);
19172
+ setShowItems(false);
19173
+ }
19174
+ }, onFocus: () => setShowItems(true) }),
19175
+ React__default.createElement("button", { type: "button", className: "button button--clear", onClick: handleClearClick })),
19176
+ options && options.length > 0 && showItems && (React__default.createElement("div", { className: "typeahead__options" }, (options ?? []).map((option) => {
19177
+ const matchIndex = typeof value !== 'undefined' ? option.text.indexOf(value) : 0;
19178
+ const prefix = option.text.slice(0, matchIndex);
19179
+ const highlight = option.text.slice(matchIndex, value?.length ?? 0);
19180
+ const suffix = option.text.slice(matchIndex);
19181
+ return (React__default.createElement("div", { className: "typeahead__option", key: option.key },
19182
+ React__default.createElement("div", { className: "typeahead__option-header" },
19183
+ React__default.createElement("button", { onClick: () => {
19184
+ if (onSelect)
19185
+ onSelect(option.key);
19186
+ setShowItems(false);
19187
+ }, type: "button", className: "button button--plain" },
19188
+ prefix,
19189
+ React__default.createElement("span", { className: "typeahead__option-highlight" }, highlight),
19190
+ suffix))));
19191
+ })))));
19192
+ };
19193
+
19194
+ // A traveler is a baby when the age they were booked with is at or below the baby
19195
+ // boundary. Babies get their own label and birth date validation (TIDE-3269). Only
19196
+ // meaningful for the regular form: the compact form asks for an age instead of a birth
19197
+ // date, so it has nothing to validate and its own age input already states the age.
19198
+ function isBabyAge(age, maxBabyAge = BABY_MAX_AGE) {
19199
+ return typeof age === 'number' && age <= maxBabyAge;
19200
+ }
19201
+ // The native date input can hold values format() throws on (e.g. a 5+ digit year while typing), so never format an unvalidated birthDate
19202
+ function formatBirthDate$1(birthDate) {
19203
+ if (!birthDate)
19204
+ return '';
19205
+ const parsed = parse(birthDate, 'yyyy-MM-dd', new Date());
19206
+ return isValid(parsed) ? format$2(parsed, 'dd-MM-yyyy') : '';
19207
+ }
19208
+ // A field can have separate "main-booker"/other-pax variants sharing the same identity
19209
+ // (customFieldConfigurationId for custom fields, fieldName for built-in fields).
19210
+ const MAIN_BOOKER_GROUP = 'main-booker';
19211
+ const isCustomPaxField = (field) => field.customFieldConfigurationId != null;
19212
+ function resolveApplicablePaxFields(fields, isMainBooker) {
19213
+ const variantsByKey = new Map();
19214
+ fields.forEach((field) => {
19215
+ const key = field.customFieldConfigurationId ?? field.fieldName;
19216
+ const variants = variantsByKey.get(key) ?? [];
19217
+ variants.push(field);
19218
+ variantsByKey.set(key, variants);
19219
+ });
19220
+ const applicableFields = [];
19221
+ variantsByKey.forEach((variants) => {
19222
+ const hasRoleSplit = variants.some((v) => v.group === MAIN_BOOKER_GROUP);
19223
+ if (!hasRoleSplit) {
19224
+ applicableFields.push(variants[0]);
19225
+ return;
19226
+ }
19227
+ const roleMatch = variants.find((v) => (v.group === MAIN_BOOKER_GROUP) === isMainBooker);
19228
+ if (roleMatch)
19229
+ applicableFields.push(roleMatch);
19230
+ });
19231
+ return applicableFields;
19232
+ }
19233
+ function buildEmptyCustomFields(paxFields = []) {
19234
+ const uniqueIds = Array.from(new Set(paxFields.filter(isCustomPaxField).map((field) => field.customFieldConfigurationId)));
19235
+ return uniqueIds.map((customFieldConfigurationId) => ({ customFieldConfigurationId, value: '' }));
19236
+ }
19237
+ function getApplicablePaxCustomFields(paxFields = [], isMainBooker) {
19238
+ return resolveApplicablePaxFields(paxFields.filter(isCustomPaxField), isMainBooker);
19239
+ }
19240
+ function getApplicableBuiltInPaxFields(paxFields = [], isMainBooker) {
19241
+ return resolveApplicablePaxFields(paxFields.filter((f) => !isCustomPaxField(f)), isMainBooker);
19242
+ }
19243
+ function getBuiltInPaxField(paxFields = [], fieldName, isMainBooker) {
19244
+ return getApplicableBuiltInPaxFields(paxFields, isMainBooker).find((f) => f.fieldName === fieldName);
19245
+ }
19246
+ // fieldName -> path on `Traveler`, shared with validate-form.ts.
19247
+ const BUILT_IN_FIELD_PATHS = {
19248
+ gender: 'gender',
19249
+ firstName: 'firstName',
19250
+ lastName: 'lastName',
19251
+ dateOfBirth: 'birthDate',
19252
+ nickname: 'nickname',
19253
+ birthplace: 'birthplace',
19254
+ nationality: 'nationality',
19255
+ preferredLanguageId: 'preferredLanguageId',
19256
+ email: 'email',
19257
+ phone: 'phone',
19258
+ mobile: 'mobile',
19259
+ passportIssueDate: 'passportIssueDate',
19260
+ passportIssuedLocation: 'passportIssuedLocation',
19261
+ passportExpiryDate: 'passportExpiryDate',
19262
+ passportNumber: 'passportNumber',
19263
+ emergencyNumber: 'emergencyNumber',
19264
+ hasInsurance: 'hasInsurance',
19265
+ insuranceName: 'insuranceName',
19266
+ info: 'info',
19267
+ street: 'address.street',
19268
+ location: 'address.location',
19269
+ countryId: 'address.country',
19270
+ postalCode: 'address.postalCode',
19271
+ number: 'address.number'
19272
+ };
19273
+ // The 4 fields that always render/validate regardless of paxFields config (fallback behavior).
19274
+ const CORE_FIELD_NAMES = new Set(['gender', 'firstName', 'lastName', 'dateOfBirth']);
19275
+ const ADDRESS_FIELD_NAMES = ['street', 'location', 'countryId', 'postalCode', 'number'];
19276
+ // Shared by buildPax (new-booking) and applyTravelersFormValuesToEditablePackagingEntry
19277
+ // (edit-booking), now that PackagingEntryPax and BookingPackagePax have the same shape.
19278
+ function applyTravelerToPax(pax, traveler, mainBookerId) {
19279
+ return {
19280
+ ...pax,
19281
+ firstName: traveler.firstName ?? '',
19282
+ lastName: traveler.lastName ?? '',
19283
+ dateOfBirth: traveler.birthDate || null,
19284
+ isMainBooker: mainBookerId != null ? traveler.id === mainBookerId : pax.isMainBooker,
19285
+ weight: traveler.weight ?? null,
19286
+ weightType: traveler.weightType ?? build.WeightType.kilograms,
19287
+ height: traveler.height ?? null,
19288
+ heightType: traveler.heightType ?? build.HeightType.centimeters,
19289
+ nickname: traveler.nickname,
19290
+ birthplace: traveler.birthplace,
19291
+ nationality: traveler.nationality,
19292
+ preferredLanguageId: traveler.preferredLanguageId,
19293
+ email: traveler.email,
19294
+ phone: traveler.phone,
19295
+ mobilePhone: traveler.mobile,
19296
+ emergencyNumber: traveler.emergencyNumber,
19297
+ passportNumber: traveler.passportNumber,
19298
+ passportIssueDate: traveler.passportIssueDate,
19299
+ passportIssuedLocation: traveler.passportIssuedLocation,
19300
+ passportExpiryDate: traveler.passportExpiryDate,
19301
+ hasInsurance: traveler.hasInsurance,
19302
+ insuranceName: traveler.insuranceName,
19303
+ info: traveler.info,
19304
+ address: buildTravelerAddress(traveler),
19305
+ customFields: traveler.customFields ?? []
19306
+ };
19307
+ }
19308
+ // name/email are required on the wire but aren't part of the per-traveler address sub-form -
19309
+ // derive them from the traveler's own name/email instead of asking twice.
19310
+ function buildTravelerAddress(traveler) {
19311
+ if (!traveler.address || !Object.values(traveler.address).some((v) => !!v))
19312
+ return undefined;
19313
+ return {
19314
+ name: `${traveler.firstName} ${traveler.lastName}`.trim(),
19315
+ street: traveler.address.street ?? '',
19316
+ number: traveler.address.number ?? '',
19317
+ postalCode: traveler.address.postalCode ?? '',
19318
+ location: traveler.address.location ?? '',
19319
+ country: traveler.address.country ?? '',
19320
+ email: traveler.email ?? ''
19321
+ };
19322
+ }
19323
+ // Always initialized (even when not shown) to keep Formik inputs controlled, matching weight/height.
19324
+ const EMPTY_BUILT_IN_FIELDS = {
19325
+ nickname: '',
19326
+ birthplace: '',
19327
+ nationality: '',
19328
+ preferredLanguageId: undefined,
19329
+ email: '',
19330
+ phone: '',
19331
+ mobile: '',
19332
+ passportNumber: '',
19333
+ passportIssueDate: '',
19334
+ passportIssuedLocation: '',
19335
+ passportExpiryDate: '',
19336
+ emergencyNumber: '',
19337
+ hasInsurance: false,
19338
+ insuranceName: '',
19339
+ info: '',
19340
+ address: { street: '', number: '', postalCode: '', location: '', country: '' }
19341
+ };
19342
+ function createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields) {
19343
+ if (isCompact) {
19344
+ return {
19345
+ id: traveler.id,
19346
+ firstName: personTranslation,
19347
+ lastName: `${followNumber.number++}`,
19348
+ birthDate: '',
19349
+ gender: '',
19350
+ // Keep a booked age of 0 instead of submitting and pricing the traveler as a 30 year
19351
+ // old, while still falling back for a missing or unusable age. `??` alone would let a
19352
+ // NaN (unparseable date of birth upstream) reach the age input and the booked pax.
19353
+ // See TIDE-3269.
19354
+ age: Number.isFinite(traveler.age) ? traveler.age : 30,
19355
+ // No isBaby here on purpose: the age below is editable and nothing revalidates it
19356
+ // in compact mode, so a stored flag would end up contradicting the entered age.
19357
+ weight: null,
19358
+ weightType: build.WeightType.kilograms,
19359
+ height: null,
19360
+ heightType: build.HeightType.centimeters,
19361
+ ...EMPTY_BUILT_IN_FIELDS,
19362
+ customFields: buildEmptyCustomFields(paxFields)
19363
+ };
19364
+ }
19365
+ return {
19366
+ id: traveler.id,
19367
+ firstName: '',
19368
+ lastName: '',
19369
+ birthDate: '',
19370
+ gender: '',
19371
+ isBaby: isBabyAge(traveler.age, maxBabyAge),
19372
+ weight: null,
19373
+ weightType: build.WeightType.kilograms,
19374
+ height: null,
19375
+ heightType: build.HeightType.centimeters,
19376
+ ...EMPTY_BUILT_IN_FIELDS,
19377
+ customFields: buildEmptyCustomFields(paxFields)
19378
+ };
19379
+ }
19380
+ function createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, personTranslation, isCompact, maxBabyAge, paxFields) {
19381
+ const followNumber = { number: 1 };
19382
+ const initialValues = {
19383
+ startDate,
19384
+ endDate,
19385
+ rooms: formRooms.map((room) => ({
19386
+ adults: room.adults.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields)),
19387
+ children: room.children.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge, paxFields))
19388
+ })),
19389
+ mainBookerId: -1,
19390
+ street: '',
19391
+ houseNumber: '',
19392
+ box: '',
19393
+ zipCode: '',
19394
+ place: '',
19395
+ country: '',
19396
+ phone: '',
19397
+ email: '',
19398
+ emailConfirmation: '',
19399
+ travelAgentId: agentAdressId ?? 0,
19400
+ travelAgentName: ''
19401
+ };
19402
+ if (initialValues.rooms?.[0]?.adults?.[0]) {
19403
+ initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
19404
+ }
19405
+ return initialValues;
19406
+ }
19407
+ function mapPackagingEntryPaxToTraveler(roomTraveler) {
19408
+ return {
19409
+ weight: roomTraveler.weight ?? null,
19410
+ weightType: roomTraveler.weightType ?? build.WeightType.kilograms,
19411
+ height: roomTraveler.height ?? null,
19412
+ heightType: roomTraveler.heightType ?? build.HeightType.centimeters,
19413
+ nickname: roomTraveler.nickname ?? '',
19414
+ birthplace: roomTraveler.birthplace ?? '',
19415
+ nationality: roomTraveler.nationality ?? '',
19416
+ preferredLanguageId: roomTraveler.preferredLanguageId,
19417
+ email: roomTraveler.email ?? '',
19418
+ phone: roomTraveler.phone ?? '',
19419
+ mobile: roomTraveler.mobilePhone ?? '',
19420
+ passportNumber: roomTraveler.passportNumber ?? '',
19421
+ passportIssueDate: roomTraveler.passportIssueDate ?? '',
19422
+ passportIssuedLocation: roomTraveler.passportIssuedLocation ?? '',
19423
+ passportExpiryDate: roomTraveler.passportExpiryDate ?? '',
19424
+ emergencyNumber: roomTraveler.emergencyNumber ?? '',
19425
+ hasInsurance: roomTraveler.hasInsurance ?? false,
19426
+ insuranceName: roomTraveler.insuranceName ?? '',
19427
+ info: roomTraveler.info ?? '',
19428
+ address: roomTraveler.address
19429
+ ? {
19430
+ street: roomTraveler.address.street ?? '',
19431
+ number: roomTraveler.address.number ?? '',
19432
+ postalCode: roomTraveler.address.postalCode ?? '',
19433
+ location: roomTraveler.address.location ?? '',
19434
+ country: roomTraveler.address.country ?? ''
19435
+ }
19436
+ : undefined,
19437
+ customFields: roomTraveler.customFields ?? []
19438
+ };
19439
+ }
19440
+ function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId) {
19441
+ const pax = editablePackagingEntry?.pax ?? [];
19442
+ const rooms = editablePackagingEntry.rooms.map((room) => {
19443
+ const roomPax = pax.filter((x) => room.paxIds.includes(x.id));
19444
+ const adults = roomPax.filter((x) => x.age >= 18);
19445
+ const children = roomPax.filter((x) => x.age < 18);
19446
+ return {
19447
+ adults: adults.map((roomTraveler) => {
19448
+ return {
19449
+ id: roomTraveler.id,
19450
+ firstName: roomTraveler.firstName ?? '',
19451
+ lastName: roomTraveler.lastName ?? '',
19452
+ birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
19453
+ gender: '',
19454
+ ...mapPackagingEntryPaxToTraveler(roomTraveler)
19455
+ };
19456
+ }),
19457
+ children: children.map((roomTraveler) => {
19458
+ return {
19459
+ id: roomTraveler.id,
19460
+ firstName: roomTraveler.firstName ?? '',
19461
+ lastName: roomTraveler.lastName ?? '',
19462
+ birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
19463
+ gender: '',
19464
+ isBaby: isBabyAge(roomTraveler.age),
19465
+ ...mapPackagingEntryPaxToTraveler(roomTraveler)
19466
+ };
19467
+ })
19468
+ };
19469
+ });
19470
+ const values = createInitialValuesFromRooms(rooms.map((room) => ({ adults: room.adults, children: room.children })), first(editablePackagingEntry?.lines)?.from, last(editablePackagingEntry?.lines)?.to, agentAdressId);
19471
+ values.rooms = rooms;
19472
+ values.mainBookerId = pax.find((x) => x.isMainBooker)?.id ?? rooms[0]?.adults?.[0]?.id ?? -1;
19473
+ const address = editablePackagingEntry?.address;
19474
+ values.street = address?.street ?? '';
19475
+ values.houseNumber = address?.houseNumber ?? '';
19476
+ values.box = address?.box ?? '';
19477
+ values.zipCode = address?.zipCode ?? '';
19478
+ values.place = address?.place ?? '';
19479
+ values.country = address?.country ?? '';
19480
+ values.phone = address?.phone ?? '';
19481
+ values.email = address?.email ?? '';
19482
+ values.emailConfirmation = address?.email ?? '';
19483
+ values.travelAgentId = address?.travelAgentId ?? agentAdressId ?? 0;
19484
+ return values;
19485
+ }
19486
+ function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry, values) {
19487
+ const travelers = values.rooms.flatMap((room) => [...room.adults, ...room.children]);
19488
+ // The backend treats the main booker's per-pax address as authoritative, so keep the
19489
+ // booking-level address in sync with it rather than sending two independent values.
19490
+ const mainBookerAddress = travelers.find((x) => x.id === values.mainBookerId)?.address;
19491
+ return {
19492
+ ...editablePackagingEntry,
19493
+ pax: (editablePackagingEntry.pax ?? []).map((pax) => {
19494
+ const traveler = travelers.find((x) => x.id === pax.id);
19495
+ return traveler ? applyTravelerToPax(pax, traveler, values.mainBookerId) : pax;
19496
+ }),
19497
+ address: {
19498
+ ...editablePackagingEntry.address,
19499
+ street: mainBookerAddress?.street || values.street,
19500
+ houseNumber: mainBookerAddress?.number || values.houseNumber,
19501
+ box: values.box,
19502
+ zipCode: mainBookerAddress?.postalCode || values.zipCode,
19503
+ place: mainBookerAddress?.location || values.place,
19504
+ country: mainBookerAddress?.country || values.country,
19505
+ travelAgentId: values.travelAgentId,
19506
+ phone: values.phone,
19507
+ email: values.email
19508
+ }
19509
+ };
19510
+ }
19511
+ const SharedTravelersForm = ({ formik, translations, travellersSettings, countries, agents, bookingType, agentAdressId, travelersFirstStep = false, isUnavailable = false, useCompactForm = false, showAllCountries = false, paxFields, showAgentSelection = false, initialShowAgents = false, renderPreviousButton, onBookingTypeChange }) => {
19512
+ const [showAgents, setShowAgents] = useState(initialShowAgents);
19513
+ const typeaheadAgents = useMemo(() => sortBy(agents?.map((agent) => ({
19514
+ key: `${agent.id}`,
19515
+ value: `${agent.name}${agent.postalCode || agent.location ? ` (${compact([agent.postalCode, agent.location]).join(' ')})` : ''}`,
19516
+ text: `${agent.name}${agent.postalCode || agent.location ? ` (${compact([agent.postalCode, agent.location]).join(' ')})` : ''}`
19517
+ })), 'value') ?? [], [agents]);
19518
+ const [filteredAgents, setFilteredAgents] = useState(typeaheadAgents);
19519
+ const flatErrors = flat(formik.errors);
19520
+ const errorKeys = Object.keys(flatErrors).filter((key) => get(formik.touched, key));
19521
+ const hasVisibleError = (key) => get(formik.errors, key) && get(formik.touched, key);
19522
+ const mainBooker = formik.values.rooms
19523
+ .find((room) => room.adults.find((traveler) => traveler.id === formik.values.mainBookerId))
19524
+ ?.adults.find((traveler) => traveler.id === formik.values.mainBookerId);
19525
+ const countryOptions = [
19526
+ { key: 'empty', value: undefined, label: translations.TRAVELERS_FORM.SELECT_COUNTRY },
19527
+ ...(showAllCountries
19528
+ ? countries?.map((country) => ({ key: country.iso2, value: country.iso2, label: country.name })) ?? []
19529
+ : travellersSettings?.countries?.map((country) => ({ key: country.iso2, value: country.iso2, label: country.name })) ?? [
19530
+ { key: 'be', value: 'be', label: translations.TRAVELERS_FORM.COUNTRIES.BELGIUM },
19531
+ { key: 'nl', value: 'nl', label: translations.TRAVELERS_FORM.COUNTRIES.NETHERLANDS },
19532
+ { key: 'fr', value: 'fr', label: translations.TRAVELERS_FORM.COUNTRIES.FRANCE }
19533
+ ])
19534
+ ];
19535
+ const handleMainBookerChange = (event) => {
19536
+ formik.setFieldValue('mainBookerId', parseInt(event.currentTarget.value, 10));
19537
+ };
19538
+ const handleAgentChange = (value) => {
19539
+ setFilteredAgents(typeaheadAgents.filter((x) => x.value.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) > -1));
19540
+ formik.setFieldValue('travelAgentName', value);
19541
+ };
19542
+ const handleAgentSelect = (key) => {
19543
+ const agent = typeaheadAgents.find((x) => x.key === key);
19544
+ formik.setValues({
19545
+ ...formik.values,
19546
+ travelAgentId: Number(agent?.key),
19547
+ travelAgentName: agent?.value ?? ''
19548
+ });
19549
+ onBookingTypeChange?.(agentAdressId && agentAdressId !== 0 ? 'b2b' : 'b2b2c');
19550
+ };
19551
+ const handleAgentClear = () => {
19552
+ formik.setValues({ ...formik.values, travelAgentId: 0, travelAgentName: '' });
19553
+ onBookingTypeChange?.('b2c');
19554
+ };
19555
+ const toggleAgent = (value) => {
19556
+ setShowAgents(value);
19557
+ if (!value) {
19558
+ handleAgentClear();
19559
+ setFilteredAgents([]);
19560
+ }
19561
+ };
19562
+ const handleAddTraveler = (roomIndex) => {
19563
+ const rooms = [...formik.values.rooms];
19564
+ const newAdult = {
19565
+ id: Date.now(),
19566
+ firstName: '',
19567
+ lastName: '',
19568
+ birthDate: '',
19569
+ gender: '',
19570
+ weight: null,
19571
+ weightType: build.WeightType.kilograms,
19572
+ height: null,
19573
+ heightType: build.HeightType.centimeters,
19574
+ ...EMPTY_BUILT_IN_FIELDS,
19575
+ customFields: buildEmptyCustomFields(paxFields)
19576
+ };
19577
+ rooms[roomIndex] = { ...rooms[roomIndex], adults: [...rooms[roomIndex].adults, newAdult] };
19578
+ formik.setFieldValue('rooms', rooms);
19579
+ };
19580
+ const handleRemoveTraveler = (roomIndex, travelerIndex) => {
19581
+ const rooms = [...formik.values.rooms];
19582
+ const adults = [...rooms[roomIndex].adults];
19583
+ if (adults.length <= 1)
19584
+ return;
19585
+ adults.splice(travelerIndex, 1);
19586
+ rooms[roomIndex] = { ...rooms[roomIndex], adults };
19587
+ formik.setFieldValue('rooms', rooms);
19588
+ };
19589
+ const handleAddRoom = () => {
19590
+ const rooms = [...formik.values.rooms];
19591
+ rooms.push({
19592
+ adults: [
19593
+ {
19594
+ id: Date.now(),
19595
+ firstName: '',
19596
+ lastName: '',
19597
+ birthDate: '',
19598
+ gender: '',
19599
+ weight: null,
19600
+ weightType: build.WeightType.kilograms,
19601
+ height: null,
19602
+ heightType: build.HeightType.centimeters,
19603
+ ...EMPTY_BUILT_IN_FIELDS,
19604
+ customFields: buildEmptyCustomFields(paxFields)
19605
+ }
19606
+ ],
19607
+ children: []
19608
+ });
19609
+ formik.setFieldValue('rooms', rooms);
19610
+ };
19611
+ const handleRemoveRoom = (roomIndex) => {
19612
+ const rooms = [...formik.values.rooms];
19613
+ rooms.splice(roomIndex, 1);
19614
+ formik.setFieldValue('rooms', rooms);
19615
+ };
19616
+ const renderWeightControl = (namePrefix, value, isRequired) => (React__default.createElement("div", { className: "form__row" },
19617
+ React__default.createElement(LabeledInput, { type: "number", min: 0, hasError: hasVisibleError(`${namePrefix}.weight`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.WEIGHT, required: isRequired, name: `${namePrefix}.weight`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.weight ?? '' }),
19618
+ React__default.createElement(LabeledSelect, { extraClassName: "form__group--md-33", name: `${namePrefix}.weightType`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.weightType, options: [
19619
+ { key: 'kg', value: build.WeightType.kilograms, label: translations.TRAVELERS_FORM.WEIGHT_UNIT_KG },
19620
+ { key: 'lb', value: build.WeightType.pounds, label: translations.TRAVELERS_FORM.WEIGHT_UNIT_LB }
19621
+ ] })));
19622
+ const renderHeightControl = (namePrefix, value, isRequired) => (React__default.createElement("div", { className: "form__row" },
19623
+ React__default.createElement(LabeledInput, { type: "number", min: 0, hasError: hasVisibleError(`${namePrefix}.height`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.HEIGHT, required: isRequired, name: `${namePrefix}.height`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.height ?? '' }),
19624
+ React__default.createElement(LabeledSelect, { extraClassName: "form__group--md-33", name: `${namePrefix}.heightType`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.heightType, options: [
19625
+ { key: 'cm', value: build.HeightType.centimeters, label: translations.TRAVELERS_FORM.HEIGHT_UNIT_CM },
19626
+ { key: 'ftIn', value: build.HeightType.feetInches, label: translations.TRAVELERS_FORM.HEIGHT_UNIT_FT_IN }
19627
+ ] })));
19628
+ const getCustomFieldControl = (field, value, name) => {
19629
+ const label = compact([field.fieldName, field.isRequired && '*']).join(' ');
19630
+ switch (field.dataType) {
19631
+ case build.CustomFieldDataType.bool:
19632
+ return (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
19633
+ React__default.createElement("div", { className: "checkbox" },
19634
+ React__default.createElement("label", { className: "checkbox__label" },
19635
+ React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: value === 'true', onChange: (e) => formik.setFieldValue(name, e.target.checked ? 'true' : 'false'), onBlur: formik.handleBlur, name: name }),
19636
+ label))));
19637
+ case build.CustomFieldDataType.date:
19638
+ return (React__default.createElement(LabeledInput, { type: "date", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
19639
+ case build.CustomFieldDataType.time:
19640
+ return (React__default.createElement(LabeledInput, { type: "time", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
19641
+ case build.CustomFieldDataType.numeric:
19642
+ return (React__default.createElement(LabeledInput, { type: "number", hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
19643
+ case build.CustomFieldDataType.string:
19644
+ default:
19645
+ return (React__default.createElement(LabeledInput, { hasError: hasVisibleError(name), label: label, name: name, onChange: (e) => formik.setFieldValue(name, e.target.value), onBlur: formik.handleBlur, value: value }));
19646
+ }
19647
+ };
19648
+ const renderCustomFields = (travelerValues, namePrefix) => {
19649
+ if (!paxFields?.length)
19650
+ return null;
19651
+ const isMainBooker = travelerValues.id === formik.values.mainBookerId;
19652
+ const applicableFields = getApplicablePaxCustomFields(paxFields, isMainBooker);
19653
+ if (!applicableFields.length)
19654
+ return null;
19655
+ return (React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, applicableFields.map((field) => {
19656
+ const fieldIndex = travelerValues.customFields?.findIndex((c) => c.customFieldConfigurationId === field.customFieldConfigurationId) ?? -1;
19657
+ if (fieldIndex < 0)
19658
+ return null;
19659
+ const name = `${namePrefix}.customFields[${fieldIndex}].value`;
19660
+ const value = travelerValues.customFields[fieldIndex].value;
19661
+ return (React__default.createElement("div", { key: field.customFieldConfigurationId, style: { gridColumn: `span ${field.col || 12}` } }, getCustomFieldControl(field, value, name)));
19662
+ })));
19663
+ };
19664
+ // Fields with a dedicated control (gender, hasInsurance, countryId) aren't listed here.
19665
+ const BUILT_IN_FIELD_CONTROL_META = {
19666
+ firstName: { label: translations.TRAVELERS_FORM.FIRST_NAME },
19667
+ lastName: { label: translations.TRAVELERS_FORM.LAST_NAME },
19668
+ dateOfBirth: { type: 'date', label: translations.TRAVELERS_FORM.BIRTHDATE },
19669
+ nickname: { label: translations.TRAVELERS_FORM.NICKNAME },
19670
+ birthplace: { label: translations.TRAVELERS_FORM.BIRTHPLACE },
19671
+ nationality: { label: translations.TRAVELERS_FORM.NATIONALITY },
19672
+ preferredLanguageId: { type: 'number', label: translations.TRAVELERS_FORM.PREFERRED_LANGUAGE },
19673
+ email: { type: 'email', label: translations.TRAVELERS_FORM.TRAVELER_EMAIL },
19674
+ phone: { label: translations.TRAVELERS_FORM.TRAVELER_PHONE },
19675
+ mobile: { label: translations.TRAVELERS_FORM.TRAVELER_MOBILE },
19676
+ passportNumber: { label: translations.TRAVELERS_FORM.PASSPORT_NUMBER },
19677
+ passportIssueDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_ISSUE_DATE },
19678
+ passportIssuedLocation: { label: translations.TRAVELERS_FORM.PASSPORT_ISSUED_LOCATION },
19679
+ passportExpiryDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_EXPIRY_DATE },
19680
+ emergencyNumber: { label: translations.TRAVELERS_FORM.EMERGENCY_NUMBER },
19681
+ insuranceName: { label: translations.TRAVELERS_FORM.INSURANCE_NAME },
19682
+ info: { label: translations.TRAVELERS_FORM.INFO },
19683
+ street: { label: translations.TRAVELERS_FORM.STREET },
19684
+ location: { label: translations.TRAVELERS_FORM.CITY },
19685
+ postalCode: { label: translations.TRAVELERS_FORM.ZIPCODE },
19686
+ number: { label: translations.TRAVELERS_FORM.HOUSE_NUMBER }
19687
+ };
19688
+ const renderBuiltInFieldControl = (fieldName, isRequired, travelerValues, namePrefix) => {
19689
+ const path = BUILT_IN_FIELD_PATHS[fieldName] ?? fieldName;
19690
+ const name = `${namePrefix}.${path}`;
19691
+ const value = get(travelerValues, path);
19692
+ switch (fieldName) {
19693
+ case 'gender':
19694
+ return React__default.createElement(GenderControl, { translations: translations, value: travelerValues, formik: formik, name: name });
19695
+ case 'hasInsurance':
19696
+ return (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
19697
+ React__default.createElement("div", { className: "checkbox" },
19698
+ React__default.createElement("label", { className: "checkbox__label" },
19699
+ React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: !!value, onChange: (e) => formik.setFieldValue(name, e.target.checked), onBlur: formik.handleBlur, name: name }),
19700
+ compact([translations.TRAVELERS_FORM.HAS_INSURANCE, isRequired && '*']).join(' ')))));
19701
+ case 'countryId':
19702
+ return (React__default.createElement(LabeledSelect, { hasError: hasVisibleError(name), label: translations.TRAVELERS_FORM.COUNTRY, required: isRequired, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value, options: countryOptions }));
19703
+ case 'weight':
19704
+ return renderWeightControl(namePrefix, travelerValues, isRequired);
19705
+ case 'height':
19706
+ return renderHeightControl(namePrefix, travelerValues, isRequired);
19707
+ default: {
19708
+ const meta = BUILT_IN_FIELD_CONTROL_META[fieldName] ?? { label: fieldName };
19709
+ return (React__default.createElement(LabeledInput, { type: meta.type, hasError: hasVisibleError(name), label: meta.label, required: isRequired, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value ?? '' }));
19710
+ }
19711
+ }
19712
+ };
19713
+ const CORE_FIELD_DEFAULTS = {
19714
+ gender: { isRequired: true, col: 4 },
19715
+ firstName: { isRequired: true, col: 4 },
19716
+ lastName: { isRequired: true, col: 4 },
19717
+ dateOfBirth: { isRequired: true, col: 4 }
19718
+ };
19719
+ const resolveBuiltInField = (fieldName, travelerValues) => {
19720
+ const isMainBooker = travelerValues.id === formik.values.mainBookerId;
19721
+ const configured = getBuiltInPaxField(paxFields, fieldName, isMainBooker);
19722
+ const fallback = CORE_FIELD_DEFAULTS[fieldName];
19723
+ if (!configured && !fallback)
19724
+ return undefined;
19725
+ return { isRequired: configured?.isRequired ?? fallback.isRequired, col: configured?.col ?? fallback.col };
19726
+ };
19727
+ const renderBuiltInField = (fieldName, travelerValues, namePrefix) => {
19728
+ const resolved = resolveBuiltInField(fieldName, travelerValues);
19729
+ if (!resolved)
19730
+ return null;
19731
+ return (React__default.createElement("div", { key: fieldName, style: { gridColumn: `span ${resolved.col || 12}` } }, renderBuiltInFieldControl(fieldName, resolved.isRequired, travelerValues, namePrefix)));
19732
+ };
19733
+ const renderTravelerAddressFields = (travelerValues, namePrefix) => {
19734
+ const fields = ADDRESS_FIELD_NAMES.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix)).filter(Boolean);
19735
+ if (!fields.length)
19736
+ return null;
19737
+ return React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, fields);
19738
+ };
19739
+ const getControl = (type, value, name) => {
19740
+ switch (type) {
19741
+ case 'country':
19742
+ return (React__default.createElement(LabeledSelect, { hasError: hasVisibleError('country'), label: translations.TRAVELERS_FORM.COUNTRY, required: true, name: "country", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.country, options: countryOptions }));
19743
+ case 'phone':
19744
+ return (React__default.createElement(PhoneInput, { countries: travellersSettings?.countries ?? [], countryIso2: formik.values.country, hasError: hasVisibleError('phone'), label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }));
19745
+ case 'email':
19746
+ return (React__default.createElement(React__default.Fragment, null,
19747
+ React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
19748
+ React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })));
19749
+ case 'street':
19750
+ return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('street'), extraClassName: "form__group--50 form__group--sm-60", label: translations.TRAVELERS_FORM.STREET, required: true, name: "street", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.street }));
19751
+ case 'houseNumber':
19752
+ return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('houseNumber'), extraClassName: "form__group--30 form__group--sm-20", label: translations.TRAVELERS_FORM.HOUSE_NUMBER, required: true, name: "houseNumber", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.houseNumber }));
19753
+ case 'box':
19754
+ return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('box'), extraClassName: "form__group--20", label: translations.TRAVELERS_FORM.POST_BOX, name: "box", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.box }));
19755
+ case 'zipCode':
19756
+ return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('zipCode'), extraClassName: "form__group--40 form__group--sm-20", label: translations.TRAVELERS_FORM.ZIPCODE, required: true, name: "zipCode", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.zipCode }));
19757
+ case 'place':
19758
+ return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('place'), extraClassName: "form__group--60 form__group--sm-40", label: translations.TRAVELERS_FORM.CITY, required: true, name: "place", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.place }));
19759
+ default:
19760
+ return null;
19761
+ }
19762
+ };
19763
+ const renderRoomLabel = (room) => compact([
19764
+ room.adults.length,
19765
+ room.adults.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
19766
+ room.adults.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
19767
+ room.adults?.length && room.children?.length && ', ',
19768
+ room.children.length,
19769
+ room.children.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
19770
+ room.children.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`
19771
+ ]).join('');
19772
+ const renderTravelerFields = (travelerValues, namePrefix, isAdult, roomIndex, travelerIndex) => {
19773
+ if (useCompactForm) {
19774
+ return (React__default.createElement("div", { className: "form__row" },
19775
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.age`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.AGE, required: true, name: `${namePrefix}.age`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.age })));
19776
+ }
19777
+ // 'birthDate' (the legacy formFields type string) is normalized to the paxFields catalog's
19778
+ // 'dateOfBirth' fieldName for config lookups.
19779
+ const baseFieldNames = (travellersSettings?.formFields?.length ? travellersSettings.formFields.map((field) => field.type) : ['gender', 'firstName', 'lastName', 'dateOfBirth']).map((fieldName) => (fieldName === 'birthDate' ? 'dateOfBirth' : fieldName));
19780
+ const isMainBooker = travelerValues.id === formik.values.mainBookerId;
19781
+ const extraFieldNames = getApplicableBuiltInPaxFields(paxFields, isMainBooker)
19782
+ .map((field) => field.fieldName)
19783
+ .filter((fieldName) => !baseFieldNames.includes(fieldName) && !ADDRESS_FIELD_NAMES.includes(fieldName));
19784
+ return (React__default.createElement(React__default.Fragment, null,
19785
+ React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, [...baseFieldNames, ...extraFieldNames].map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix))),
19786
+ renderTravelerAddressFields(travelerValues, namePrefix),
19787
+ renderCustomFields(travelerValues, namePrefix),
19788
+ travelersFirstStep && isAdult && formik.values.rooms[roomIndex].adults.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveTraveler(roomIndex, travelerIndex) }, translations.TRAVELERS_FORM.REMOVE_TRAVELER))));
19789
+ };
19790
+ return (React__default.createElement("form", { className: "form form__travelers", name: "booking--travellers", id: "booking--travellers", noValidate: true, onSubmit: formik.handleSubmit, onReset: formik.handleReset },
19791
+ React__default.createElement("div", { className: "form__travelers__wrapper" },
19792
+ formik.values.rooms.map((room, roomIndex) => (React__default.createElement("div", { key: roomIndex },
19793
+ formik.values.rooms.length > 1 && (React__default.createElement("div", { className: "form__region" },
19794
+ React__default.createElement("div", { className: "form__region-header" },
19795
+ React__default.createElement("h5", { className: "form__region-heading" },
19796
+ translations.SHARED.ROOM,
19797
+ " ",
19798
+ roomIndex + 1),
19799
+ React__default.createElement("p", { className: "form__region-label" }, renderRoomLabel(room))),
19800
+ !useCompactForm && travelersFirstStep && formik.values.rooms.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveRoom(roomIndex) }, "Verwijder reisgezelschap")))),
19801
+ room.adults.map((travelerValues, index) => (React__default.createElement("div", { className: "form__region", key: travelerValues.id },
19802
+ React__default.createElement("div", { className: "form__region-header" },
19803
+ React__default.createElement("h5", { className: "form__region-heading" },
19804
+ translations.TRAVELERS_FORM.TRAVELER,
19805
+ " ",
19806
+ index + 1),
19807
+ React__default.createElement("p", { className: "form__region-label" }, translations.TRAVELERS_FORM.ADULT),
19808
+ React__default.createElement("div", { className: "radiobutton" },
19809
+ React__default.createElement("label", { className: "radiobutton__label" },
19810
+ React__default.createElement("input", { type: "radio", name: "mainBookerId", onChange: handleMainBookerChange, onBlur: formik.handleBlur, value: travelerValues.id, checked: formik.values.mainBookerId === travelerValues.id, className: "radiobutton__input" }),
19811
+ translations.TRAVELERS_FORM.MAIN_BOOKER))),
19812
+ renderTravelerFields(travelerValues, `rooms[${roomIndex}].adults[${index}]`, true, roomIndex, index)))),
19813
+ room.children.map((travelerValues, index) => (React__default.createElement("div", { className: "form__region", key: travelerValues.id },
19814
+ React__default.createElement("div", { className: "form__region-header" },
19815
+ React__default.createElement("h5", { className: "form__region-heading" },
19816
+ translations.TRAVELERS_FORM.TRAVELER,
19817
+ " ",
19818
+ room.adults.length + index + 1),
19819
+ React__default.createElement("p", { className: "form__region-label" }, travelerValues.isBaby ? translations.TRAVELERS_FORM.BABY : translations.TRAVELERS_FORM.CHILD)),
19820
+ renderTravelerFields(travelerValues, `rooms[${roomIndex}].children[${index}]`, false, roomIndex, index)))),
19821
+ !useCompactForm && travelersFirstStep && (React__default.createElement("div", { className: "form__region" },
19822
+ React__default.createElement("button", { type: "button", className: "cta cta--select", onClick: () => handleAddTraveler(roomIndex) }, translations.TRAVELERS_FORM.ADD_TRAVELER)))))),
19823
+ !useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default.createElement("div", { className: "form__region" },
19824
+ React__default.createElement("div", { className: "form__region-header" },
19825
+ React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
19826
+ React__default.createElement("p", { className: "form__region-label" }, compact([compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
19827
+ travellersSettings?.mainBookerFormFields?.length ? (React__default.createElement("div", { className: "main-booker-form__grid" }, travellersSettings.mainBookerFormFields.map((field, index) => (React__default.createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, {}, field.type)))))) : (React__default.createElement(React__default.Fragment, null,
19828
+ React__default.createElement("div", { className: "form__twocolumn" },
19829
+ React__default.createElement("div", { className: "form__twocolumn-column" },
19830
+ React__default.createElement("div", { className: "form__row" },
19831
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError('street'), extraClassName: "form__group--50 form__group--sm-60", label: translations.TRAVELERS_FORM.STREET, required: true, name: "street", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.street }),
19832
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError('houseNumber'), extraClassName: "form__group--30 form__group--sm-20", label: translations.TRAVELERS_FORM.HOUSE_NUMBER, required: true, name: "houseNumber", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.houseNumber }),
19833
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError('box'), extraClassName: "form__group--20", label: translations.TRAVELERS_FORM.POST_BOX, name: "box", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.box }))),
19834
+ React__default.createElement("div", { className: "form__twocolumn-column" },
19835
+ React__default.createElement("div", { className: "form__row" },
19836
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError('zipCode'), extraClassName: "form__group--40 form__group--sm-20", label: translations.TRAVELERS_FORM.ZIPCODE, required: true, name: "zipCode", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.zipCode }),
19837
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError('place'), extraClassName: "form__group--60 form__group--sm-40", label: translations.TRAVELERS_FORM.CITY, required: true, name: "place", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.place }),
19838
+ React__default.createElement(LabeledSelect, { hasError: hasVisibleError('country'), extraClassName: "form__group--sm-40", label: translations.TRAVELERS_FORM.COUNTRY, required: true, name: "country", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.country, options: countryOptions })))),
19839
+ React__default.createElement("div", { className: "form__row" },
19840
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }),
19841
+ React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
19842
+ React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })))))) : !useCompactForm ? (React__default.createElement("div", { className: "form__region" },
19843
+ React__default.createElement("div", { className: "form__row" },
19844
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone })))) : null,
19845
+ !useCompactForm && showAgentSelection && (React__default.createElement("div", { className: "form__region" },
19846
+ React__default.createElement("div", { className: "form__region-header" },
19847
+ React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.BOOK_WITH_AGENT),
19848
+ React__default.createElement("div", { className: "checkbox", id: "cbxChooseOffice" },
19849
+ React__default.createElement("label", { className: "checkbox__label" },
19850
+ React__default.createElement("input", { type: "checkbox", name: "booking--mainbooker", checked: showAgents, onChange: () => toggleAgent(!showAgents), className: "checkbox__input" }),
19851
+ translations.TRAVELERS_FORM.CHOOSE_OFFICE))),
19852
+ showAgents && (React__default.createElement("div", { className: "form__row form__row--choose-office" },
19853
+ React__default.createElement("div", { className: buildClassName(['form__group', 'form__group--icon', hasVisibleError('travelAgentId') && 'form__group--error']) },
19854
+ React__default.createElement(TypeAheadInput, { value: formik.values.travelAgentName, options: filteredAgents, onChange: handleAgentChange, onSelect: handleAgentSelect, onClear: handleAgentClear, name: "travelAgentName", placeholder: translations.TRAVELERS_FORM.CHOOSE_AGENT_PLACEHOLDER }))))))),
19855
+ !useCompactForm && errorKeys.length > 0 && (React__default.createElement("div", { className: "form__region form__region--errors" },
19856
+ React__default.createElement("div", { className: "form__row" },
19857
+ React__default.createElement("div", { className: "form__group" },
19858
+ React__default.createElement("p", { className: "form__error-heading" },
19859
+ translations.TRAVELERS_FORM.VALIDATION_MESSAGE,
19860
+ ":"),
19861
+ React__default.createElement("ul", { className: "list" }, errorKeys.map((key) => (React__default.createElement("li", { key: key }, get(flatErrors, key))))))))),
19862
+ travelersFirstStep && (React__default.createElement("div", { className: "booking__navigator" },
19863
+ React__default.createElement("button", { type: "button", className: "cta cta--select", onClick: handleAddRoom }, translations.TRAVELERS_FORM.ADD_ROOM))),
19864
+ React__default.createElement("div", { className: "booking__navigator" },
19865
+ renderPreviousButton?.(),
19866
+ React__default.createElement("button", { type: "submit", title: translations.STEPS.NEXT, className: 'cta' + (isUnavailable ? ' cta--disabled' : '') }, translations.STEPS.NEXT))));
19867
+ };
19868
+
19869
+ const fetchPriceDetails$1 = async (apiSettings, request, signal, languageCode) => {
19870
+ const tideClientConfig = buildTideClientConfig(apiSettings);
19871
+ return await build.priceDetails(tideClientConfig, request, signal, languageCode);
19872
+ };
19873
+ const priceDetailsApi = {
19874
+ fetchPriceDetails: fetchPriceDetails$1
19875
+ };
19876
+
19877
+ const updatePackageDetails = (packageDetails, changedLines) => {
19878
+ return {
19879
+ ...packageDetails,
19880
+ options: packageDetails.options.map((opt) => {
19881
+ return {
19882
+ ...opt,
19883
+ rooms: opt.isSelected ? updateRooms(opt.rooms, changedLines) : opt.rooms,
19884
+ groups: opt.isSelected ? updateBookingGroups(opt.groups, changedLines) : opt.groups,
19885
+ optionUnits: opt.isSelected ? updateOptionUnits(opt.optionUnits, changedLines) : opt.optionUnits,
19886
+ optionPax: opt.isSelected ? updateOptionPax(opt.optionPax, changedLines) : opt.optionPax
19887
+ };
19888
+ })
19889
+ };
19890
+ };
19891
+ // ROOMS
19892
+ const updateRooms = (rooms, changedLines) => {
19893
+ return rooms.map((room) => ({
19894
+ ...room,
19895
+ options: room.options.map((option) => ({
19896
+ ...option,
19897
+ price: changedLines.find((x) => x.entryLineGuid == option.entryLineGuid)?.price ?? option.price
19898
+ }))
19899
+ }));
19900
+ };
19901
+ // PAX
19902
+ const updateOptionPax = (pax, changedLines) => {
19903
+ return pax.map((p) => ({
19904
+ ...p,
19905
+ groups: updatePaxGroups(p.groups, changedLines)
19906
+ }));
19907
+ };
19908
+ const updatePaxGroups = (groups, changedLines) => {
19909
+ return groups.map((g) => ({
19910
+ ...g,
19911
+ options: g.options.map((o) => ({
19912
+ ...o,
19913
+ groups: updatePaxGroups(o.groups, changedLines),
19914
+ line: {
19915
+ ...o.line,
19916
+ price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
19917
+ },
19918
+ alternatives: o.alternatives.map((a) => ({
19919
+ ...a,
19920
+ price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
19921
+ }))
19922
+ }))
19923
+ }));
19924
+ };
19925
+ // UNITS
19926
+ const updateOptionUnits = (units, changedLines) => {
19927
+ return units.map((u) => ({
19928
+ ...u,
19929
+ groups: updateUnitGroups(u.groups, changedLines)
19930
+ }));
19931
+ };
19932
+ const updateUnitGroups = (groups, changedLines) => {
19933
+ return groups.map((g) => ({
19934
+ ...g,
19935
+ options: g.options.map((o) => ({
19936
+ ...o,
19937
+ groups: updateUnitGroups(o.groups, changedLines),
19938
+ pax: updateOptionPax(o.pax, changedLines),
19939
+ line: {
19940
+ ...o.line,
19941
+ price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
19942
+ },
19943
+ alternatives: o.alternatives.map((a) => ({
19944
+ ...a,
19945
+ price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
19946
+ }))
19947
+ }))
19948
+ }));
19949
+ };
19950
+ // BOOKING
19951
+ const updateBookingGroups = (groups, changedLines) => {
19952
+ return groups.map((g) => ({
19953
+ ...g,
19954
+ options: g.options.map((o) => ({
19955
+ ...o,
19956
+ groups: updateBookingGroups(o.groups, changedLines),
19957
+ units: updateOptionUnits(o.units, changedLines),
19958
+ pax: updateOptionPax(o.pax, changedLines),
19959
+ line: {
19960
+ ...o.line,
19961
+ price: changedLines.find((cl) => cl.entryLineGuid === o.line.entryLineGuid)?.price ?? o.line.price
19962
+ },
19963
+ alternatives: o.alternatives.map((a) => ({
19964
+ ...a,
19965
+ price: changedLines.find((cl) => cl.entryLineGuid === a.entryLineGuid)?.price ?? a.price
19966
+ }))
19967
+ }))
19968
+ }));
19969
+ };
19970
+
19971
+ const fetchPriceDetails = createAsyncThunk('priceDetails/fetchPriceDetails', async (_, { dispatch, getState, signal }) => {
19972
+ const state = getState();
19973
+ const languageCode = selectLanguageCode(state);
19974
+ const request = selectBookingPackageBookRequest(state);
19975
+ if (!request) {
19976
+ throw Error('Product not available.');
19977
+ }
19978
+ dispatch(setFetchingPriceDetails(true));
19979
+ dispatch(resetPriceDetails());
19980
+ const priceDetails = await priceDetailsApi.fetchPriceDetails(state.apiSettings, request, signal, languageCode);
19981
+ dispatch(setFetchingPriceDetails(false));
19982
+ const packageDetails = selectPackageDetails(state);
19983
+ if (packageDetails) {
19984
+ const updatedPackageDetails = updatePackageDetails(packageDetails, priceDetails.changedLines);
19985
+ dispatch(setPackage(updatedPackageDetails));
19986
+ }
19987
+ return priceDetails;
19988
+ });
19989
+ const priceDetailsSlice = createSlice({
19990
+ name: 'priceDetails',
19991
+ initialState: {
19992
+ priceDetails: [],
19993
+ notifications: [],
19994
+ isBusy: false
19995
+ },
19996
+ reducers: {
19997
+ setFetchingPriceDetails(state, action) {
19998
+ state.isBusy = action.payload;
19999
+ },
20000
+ setNotifications(state, action) {
20001
+ state.notifications = action.payload;
20002
+ },
20003
+ resetPriceDetails(state, _) {
20004
+ state.priceDetails = [];
20005
+ }
20006
+ },
20007
+ extraReducers: (builder) => {
20008
+ builder.addCase(fetchPriceDetails.fulfilled, (state, action) => {
20009
+ if (action.payload) {
20010
+ state.deposit = action.payload.deposit;
20011
+ state.commission = action.payload.commission;
20012
+ state.priceDetails = action.payload.details;
20013
+ state.notifications = action.payload.notifications;
20014
+ }
20015
+ });
20016
+ builder.addCase(fetchPriceDetails.rejected, (state) => {
20017
+ state.isBusy = false;
20018
+ });
20019
+ }
20020
+ });
20021
+ const { setFetchingPriceDetails } = priceDetailsSlice.actions;
20022
+ const { resetPriceDetails, setNotifications } = priceDetailsSlice.actions;
20023
+ const selectNotifications = (state) => state.priceDetails.notifications;
20024
+ var priceDetailsReducer = priceDetailsSlice.reducer;
20025
+
20026
+ const selectHasMounted = (state) => state.booking.hasMounted;
20027
+ const selectGeneratePaymentUrl = (state) => state.booking.generatePaymentUrl;
20028
+ const selectSkipPaymentWithAgent = (state) => state.booking.skipPaymentWithAgent;
20029
+ const selectIsFetchingProductOptions = (state) => state.booking.isBusy;
20030
+ const selectDepartureFlight = (state) => state.booking.package?.outwardFlights?.find((x) => x.isSelected);
20031
+ const selectReturnFlight = (state) => state.booking.package?.returnFlights?.find((x) => x.isSelected);
20032
+ const selectPackageRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.rooms;
20033
+ const selectIncludedServiceTypes = (state) => selectActiveOption(state)?.includedServiceTypes;
20034
+ const selectAvailabilities = (state) => state.booking.package?.options.find((x) => x.isSelected)?.availabilities;
20035
+ const selectPackageTags = (state) => state.booking.package?.tags;
20036
+ const selectIsOnRequest = (state) => state.booking.package?.options.find((x) => x.isSelected)?.isOnRequest;
20037
+ const selectPackageOptionUnits = (state) => state.booking.package?.options.find((x) => x.isSelected)?.optionUnits;
20038
+ const selectPackageOptionPax = (state) => state.booking.package?.options.find((x) => x.isSelected)?.optionPax;
20039
+ const selectPackageGroups = (state) => state.booking.package?.options.find((x) => x.isSelected)?.groups;
20040
+ const selectPackageDetails = (state) => state.booking.package;
20041
+ const selectPaxFields = (state) => state.booking.package?.paxFields ?? [];
20042
+ const selectPackageFlights = (state) => ({
20043
+ outward: state.booking.package?.outwardFlights,
20044
+ return: state.booking.package?.returnFlights
20045
+ });
20046
+ const selectFlightMetaData = (state) => state.booking.package?.flightInfo.metaData;
20047
+ const selectActiveOption = (state) => state.booking.package?.options.find((x) => x.isSelected);
20048
+ const selectPackageAirlineGroups = createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airlineGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
20049
+ const selectPackageAirportGroups = createSelector(selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airportGroups.filter((x) => x.flightIds.includes(departureFlight?.entryLineGuid ?? '') || x.flightIds.includes(returnFlight?.entryLineGuid ?? '')));
20050
+ const selectRoomOptionDepartureFlightsMetaData = createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
20051
+ const roomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected).shift());
20052
+ return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
20053
+ });
20054
+ const selectRoomOptionReturnFlightsMetaData = createSelector(selectActiveOption, selectFlightMetaData, (ativeOption, flightMetaData) => {
20055
+ const selectedRoomOptions = ativeOption?.rooms.map((r) => r.options.filter((o) => o.isSelected));
20056
+ // check if there are return flights selected
20057
+ if (selectedRoomOptions?.some((ro) => ro.length > 1)) {
20058
+ const roomOptions = ativeOption?.rooms.map((r) => r.options
20059
+ .filter((o) => o.isSelected)
20060
+ .reverse()
20061
+ .shift());
20062
+ return roomOptions?.map((ro) => flightMetaData?.find((f) => f.entryLineGuid === ro?.entryLineGuid)?.flightMetaData).filter((f) => f !== undefined) ?? [];
20063
+ }
20064
+ return undefined;
20065
+ });
20066
+ const selectApiSettings = (state) => state.apiSettings;
20067
+ const selectIsUnavailable = (state) => state.booking.isUnavailable;
20068
+ const selectRequestRooms = (state) => state.booking.package?.options.find((x) => x.isSelected)?.requestRooms;
20069
+ const selectOfficeId = (state) => state.booking.officeId;
20070
+ const selectLanguageCode = (state) => state.booking.languageCode;
20071
+ const selectCurrencyCode = (state) => state.booking.package?.currencyCode ?? 'EUR';
20072
+ const selectLanguage = (state) => state.booking.languageCode;
20073
+ const selectAllDynamicTranslations = (state) => state.booking.translations;
20074
+ const selectDynamicTranslations = createSelector([selectAllDynamicTranslations, selectLanguage], (allDynamicTranslations, language) => {
20075
+ return allDynamicTranslations?.find((x) => x.language == language)?.value ?? {};
20076
+ });
20077
+ // Host override files are hand-maintained, and a null only ever blanks a key the component
20078
+ // then reads, so treat it like a missing key (lodash merge already skips undefined).
20079
+ const withoutNulls = (value) => isPlainObject$1(value)
20080
+ ? mapValues(pickBy(value, (x) => x !== null), withoutNulls)
20081
+ : value;
20082
+ // getTranslations deep-merges the overrides over a clone of the built-in translations, so a
20083
+ // host override of a nested group (TRAVELERS_FORM.VALIDATION, TRAVELERS_FORM.COUNTRIES)
20084
+ // only replaces the keys it actually contains. Merging per section one level deep dropped
20085
+ // every other built-in key of such a group, which made those keys resolve to undefined and
20086
+ // crash format() in the consuming component.
20087
+ const selectTranslations = createSelector([selectLanguage, selectDynamicTranslations], (language, dynamicTranslations) => getTranslations(language, isEmpty$1(dynamicTranslations) ? undefined : withoutNulls(dynamicTranslations)));
20088
+ const selectBookingOptions = (state) => state.booking.bookingOptions;
20089
+ const selectBookingType = (state) => state.booking.bookingType;
20090
+ const selectTagIds = (state) => state.booking.tagIds;
20091
+ const selectAgentAdressId = (state) => state.booking.agentAdressId;
20092
+ const selectProductAttributes = (state) => state.booking.productAttributes;
20093
+ const selectBookingAttributes = (state) => state.booking.bookingAttributes;
20094
+ const selectBookingNumber = (state) => state.booking.bookingNumber;
20095
+ const selectIsOption = (state) => state.booking.isOption;
20096
+ const selectBookingRooms = (state) => state.booking.bookingAttributes?.rooms;
20097
+ const selectBookingRemarks = (state) => state.booking.remarks;
20098
+ const selectVoucherCodes = (state) => state.booking.voucherCodes;
20099
+ const selectCalculateDeposit = (state) => state.booking.calculateDeposit;
20100
+ const selectShowCommission = (state) => state.booking.showCommission;
20101
+ const selectIsRetry = (state) => state.booking.isRetry;
20102
+ const selectStartDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.fromDate;
20103
+ const selectEndDate = (state) => state.booking.package?.options.find((x) => x.isSelected)?.toDate;
20104
+ const selectAgents = (state) => state.booking.agents;
20105
+ const selectCountries = (state) => state.booking.countries;
20106
+ const selectProductCode = (state) => state.booking.productAttributes?.productCode;
20107
+ const selectAccommodationCodes = (state) => {
20108
+ const accommodationCodes = [];
20109
+ state.booking.package?.options.forEach((o) => {
20110
+ o.rooms.forEach((r) => r.options.forEach((ro) => {
20111
+ if (!accommodationCodes.some((y) => y === ro.accommodationCode)) {
20112
+ accommodationCodes.push(ro.accommodationCode);
20113
+ }
20114
+ }));
20115
+ });
20116
+ return accommodationCodes;
20117
+ };
20118
+ const selectAccommodationViews = (state) => state.booking.accommodationViews;
20119
+ const selectMappingInfo = (state) => state.booking.package?.options.find((x) => x.isSelected)?.mappingInfo;
20120
+ const selectBookingQuery = (state) => {
20121
+ const bookingAttributes = state.booking.bookingAttributes;
20122
+ if (!bookingAttributes) {
20123
+ return undefined;
20124
+ }
20125
+ const params = {};
20126
+ Object.entries(bookingAttributes).forEach(([key, value]) => {
20127
+ if (key === 'startDate' || key === 'endDate') {
20128
+ value = format$2(parseISO(value), 'yyyy-MM-dd');
20129
+ }
20130
+ if (key === 'rooms') {
20131
+ value = JsonURL.stringify(value.map((room) => omit(room, ['children'])), {
20132
+ AQF: true
20133
+ });
20134
+ }
20135
+ if (key === 'allotmentIds' && !value.length) {
20136
+ value = undefined;
20137
+ }
20138
+ if (key === 'flight' && value) {
20139
+ var flightInfo = value;
18884
20140
  value = JsonURL.stringify(flightInfo, { AQF: true });
18885
20141
  }
18886
20142
  if (value) {
@@ -18918,14 +20174,17 @@ const selectBookingAddress = createSelector(selectTravelersFormValues, selectBoo
18918
20174
  const mainBooker = pax.find((x) => x.isMainBooker);
18919
20175
  if (!mainBooker || bookingType == 'b2b')
18920
20176
  return undefined;
20177
+ // The backend treats the main booker's per-pax address as authoritative, so keep the
20178
+ // booking-level address in sync with it rather than sending two independent values.
20179
+ const mainBookerAddress = mainBooker.address;
18921
20180
  return {
18922
20181
  name: `${mainBooker.firstName} ${mainBooker.lastName}`,
18923
- street: formValues?.street,
18924
- number: formValues?.houseNumber,
20182
+ street: mainBookerAddress?.street || formValues?.street,
20183
+ number: mainBookerAddress?.number || formValues?.houseNumber,
18925
20184
  box: formValues?.box,
18926
- postalCode: formValues?.zipCode,
18927
- location: formValues?.place,
18928
- country: formValues?.country,
20185
+ postalCode: mainBookerAddress?.postalCode || formValues?.zipCode,
20186
+ location: mainBookerAddress?.location || formValues?.place,
20187
+ country: mainBookerAddress?.country || formValues?.country,
18929
20188
  mobilePhone: formValues?.phone,
18930
20189
  email: formValues?.email
18931
20190
  };
@@ -19001,17 +20260,11 @@ const selectBookingPackageBookRequest = createSelector(selectBookingPackageReque
19001
20260
  return bookingPackageRequest;
19002
20261
  });
19003
20262
  const selectTravelersFirstStep = (state) => state.booking.travelersFirstStep;
19004
- const buildPax = (traveler, mainBookerId) => {
19005
- return {
19006
- id: traveler.id,
19007
- gender: parseGender(traveler.gender),
19008
- firstName: traveler.firstName,
19009
- lastName: traveler.lastName,
19010
- dateOfBirth: traveler.birthDate,
19011
- age: traveler.birthDate ? null : traveler.age,
19012
- isMainBooker: traveler.id == mainBookerId
19013
- };
19014
- };
20263
+ const buildPax = (traveler, mainBookerId) => applyTravelerToPax({
20264
+ id: traveler.id,
20265
+ gender: parseGender(traveler.gender),
20266
+ age: traveler.birthDate ? null : traveler.age
20267
+ }, traveler, mainBookerId);
19015
20268
  const parseGender = (gender) => {
19016
20269
  switch (gender) {
19017
20270
  case 'm':
@@ -23011,718 +24264,233 @@ const Summary = () => {
23011
24264
  React__default.createElement("div", { className: "form__row" },
23012
24265
  React__default.createElement("div", { className: "form__group" },
23013
24266
  React__default.createElement("div", { className: "info-message" },
23014
- React__default.createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
23015
- React__default.createElement("div", { className: "info-message__copy" },
23016
- React__default.createElement("h5", null, translations.SUMMARY.VALIDATE_TITLE),
23017
- settings.customValidateText ? (React__default.createElement("div", { dangerouslySetInnerHTML: {
23018
- __html: settings.customValidateText
23019
- } })) : (React__default.createElement(React__default.Fragment, null,
23020
- React__default.createElement("p", null, settings.isOffer ? translations.SUMMARY.VALIDATE_TEXT_OFFER : translations.SUMMARY.VALIDATE_TEXT_BOOKING),
23021
- settings.allowOption && React__default.createElement("p", null, translations.SUMMARY.VALIDATE_TEXT_OPTION))),
23022
- checkboxes &&
23023
- checkboxes.map((checkbox) => (React__default.createElement("div", { className: "checkbox", key: checkbox.id },
23024
- React__default.createElement("label", { className: "checkbox__label" },
23025
- React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: checkbox.isSelected, onChange: (e) => handleCheckboxChange(checkbox.id, e.target.checked) }),
23026
- React__default.createElement("span", { className: "checkbox__label-text", dangerouslySetInnerHTML: {
23027
- __html: checkbox.text
23028
- } }))))))))))),
23029
- React__default.createElement("div", { className: "booking__navigator" },
23030
- settings.skipRouter ? (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => goPrevious(), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : (React__default.createElement(Link, { to: `${!settings.skipBasePathInRouting ? settings.basePath : ''}${travelersFirstStep ? settings.options.pathSuffix : settings.travellers.pathSuffix}?${bookingQueryString}`, title: translations.STEPS.PREVIOUS, className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)),
23031
- settings.allowOption && (React__default.createElement("button", { title: translations.STEPS.SUBMIT_OPTION, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "option" }, translations.STEPS.SUBMIT_OPTION)),
23032
- React__default.createElement("button", { title: settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "default" }, settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING))))));
23033
- };
23034
-
23035
- function isValidEmail(email) {
23036
- return !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,24}$/i.test(email);
23037
- }
23038
- const NAME_CHARACTERS_REGEX = /^[\p{L}\s-]+$/u;
23039
- function hasInvalidNameCharacters(name) {
23040
- return !NAME_CHARACTERS_REGEX.test(name);
23041
- }
23042
- // Rejects values like a 5-digit year, which the native date input allows while typing
23043
- function isValidBirthDate(birthDateText) {
23044
- return isValid(parse(birthDateText, 'yyyy-MM-dd', new Date()));
23045
- }
23046
- function getAge(birthDateText, startDateText) {
23047
- var birthDate = new Date(birthDateText);
23048
- var startDate = new Date(startDateText);
23049
- var age = startDate.getFullYear() - birthDate.getFullYear();
23050
- var m = startDate.getMonth() - birthDate.getMonth();
23051
- if (m < 0 || (m === 0 && startDate.getDate() < birthDate.getDate())) {
23052
- age--;
23053
- }
23054
- return age;
23055
- }
23056
- const validateForm$1 = (values, agentRequired, bookingType, translations, formFields, mainBookerFormFields, maxChildAge = CHILD_MAX_AGE, maxBabyAge = BABY_MAX_AGE) => {
23057
- const errors = {};
23058
- const isFormFieldPresent = (type) => {
23059
- return formFields?.some((f) => f.type === type) ?? true;
23060
- };
23061
- const isMainBookerFormFieldPresent = (type) => {
23062
- return mainBookerFormFields?.some((f) => f.type === type) ?? true;
23063
- };
23064
- const formatTravelerField = (room, pax, field) => {
23065
- return values.rooms.length > 1
23066
- ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_FIELD, [room, pax, field])
23067
- : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_FIELD, [pax, field]);
23068
- };
23069
- const formatTravelerIsNoAdult = (room, pax) => {
23070
- return values.rooms.length > 1
23071
- ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_IS_NO_ADULT, [room, pax])
23072
- : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_IS_NO_ADULT, [pax]);
23073
- };
23074
- const formatTravelerIsNoChild = (room, pax) => {
23075
- return values.rooms.length > 1
23076
- ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_IS_NO_CHILD, [room, pax])
23077
- : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_IS_NO_CHILD, [pax]);
23078
- };
23079
- const formatTravelerIsNoBaby = (room, pax) => {
23080
- // The message states the boundary the traveler has to stay under, so we pass
23081
- // the first age that is too old rather than the inclusive maxBabyAge.
23082
- const tooOldAge = maxBabyAge + 1;
23083
- return values.rooms.length > 1
23084
- ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_IS_NO_BABY, [room, pax, tooOldAge])
23085
- : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_IS_NO_BABY, [pax, tooOldAge]);
23086
- };
23087
- const formatTravelerFieldInvalidCharacters = (room, pax, field) => {
23088
- return values.rooms.length > 1
23089
- ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_FIELD_INVALID_CHARACTERS, [room, pax, field])
23090
- : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_FIELD_INVALID_CHARACTERS, [pax, field]);
23091
- };
23092
- values.rooms.forEach((r, rIndex) => r.adults.forEach((adult, index) => {
23093
- if (isEmpty$1(adult.gender) && isFormFieldPresent('gender')) {
23094
- set(errors, `rooms[${rIndex}].adults[${index}].gender`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.GENDER));
23095
- }
23096
- if (isFormFieldPresent('firstName')) {
23097
- if (isEmpty$1(adult.firstName)) {
23098
- set(errors, `rooms[${rIndex}].adults[${index}].firstName`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
23099
- }
23100
- else if (hasInvalidNameCharacters(adult.firstName)) {
23101
- set(errors, `rooms[${rIndex}].adults[${index}].firstName`, formatTravelerFieldInvalidCharacters(rIndex + 1, index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
23102
- }
23103
- }
23104
- if (isFormFieldPresent('lastName')) {
23105
- if (isEmpty$1(adult.lastName)) {
23106
- set(errors, `rooms[${rIndex}].adults[${index}].lastName`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.LAST_NAME));
23107
- }
23108
- else if (hasInvalidNameCharacters(adult.lastName)) {
23109
- set(errors, `rooms[${rIndex}].adults[${index}].lastName`, formatTravelerFieldInvalidCharacters(rIndex + 1, index + 1, translations.TRAVELERS_FORM.LAST_NAME));
23110
- }
23111
- }
23112
- if (isFormFieldPresent('birthDate')) {
23113
- if (isEmpty$1(adult.birthDate) || !isValidBirthDate(adult.birthDate)) {
23114
- set(errors, `rooms[${rIndex}].adults[${index}].birthDate`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
23115
- }
23116
- else if (values.endDate) {
23117
- // If you are younger than the maxChildAge at the end of the trip, you are considered a child, so we check the endDate here instead of the startDate
23118
- const age = getAge(adult.birthDate, values.endDate);
23119
- if (age <= maxChildAge) {
23120
- set(errors, `rooms[${rIndex}].adults[${index}].birthDate`, formatTravelerIsNoAdult(rIndex + 1, index + 1));
23121
- }
23122
- }
23123
- }
23124
- }));
23125
- values.rooms.forEach((r, rIndex) => r.children.forEach((child, index) => {
23126
- if (isEmpty$1(child.gender) && isFormFieldPresent('gender')) {
23127
- set(errors, `rooms[${rIndex}].children[${index}].gender`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.GENDER));
23128
- }
23129
- if (isFormFieldPresent('firstName')) {
23130
- if (isEmpty$1(child.firstName)) {
23131
- set(errors, `rooms[${rIndex}].children[${index}].firstName`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
23132
- }
23133
- else if (hasInvalidNameCharacters(child.firstName)) {
23134
- set(errors, `rooms[${rIndex}].children[${index}].firstName`, formatTravelerFieldInvalidCharacters(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
23135
- }
23136
- }
23137
- if (isFormFieldPresent('lastName')) {
23138
- if (isEmpty$1(child.lastName)) {
23139
- set(errors, `rooms[${rIndex}].children[${index}].lastName`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.LAST_NAME));
23140
- }
23141
- else if (hasInvalidNameCharacters(child.lastName)) {
23142
- set(errors, `rooms[${rIndex}].children[${index}].lastName`, formatTravelerFieldInvalidCharacters(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.LAST_NAME));
23143
- }
23144
- }
23145
- if (isFormFieldPresent('birthDate')) {
23146
- if (isEmpty$1(child.birthDate) || !isValidBirthDate(child.birthDate)) {
23147
- set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
23148
- }
23149
- else if (child.isBaby && values.startDate) {
23150
- // A baby only has to be under the maxBabyAge on departure, so we check the startDate here instead of the endDate (TIDE-3269)
23151
- const age = getAge(child.birthDate, values.startDate);
23152
- if (age > maxBabyAge) {
23153
- set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerIsNoBaby(rIndex + 1, r.adults.length + index + 1));
23154
- }
23155
- }
23156
- else if (values.endDate) {
23157
- // You need to be under the maxChildAge until the end of the trip, so we check the endDate here instead of the startDate.
23158
- // Babies land here too when there is no startDate to check them against, so they keep at least the child age check.
23159
- const age = getAge(child.birthDate, values.endDate);
23160
- if (age > maxChildAge) {
23161
- set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerIsNoChild(rIndex + 1, r.adults.length + index + 1));
23162
- }
23163
- }
23164
- }
23165
- }));
23166
- if (values.mainBookerId < 0) {
23167
- errors.mainBookerId = translations.TRAVELERS_FORM.VALIDATION.NO_MAIN_BOOKER_SELECTED;
23168
- }
23169
- if (bookingType != 'b2b' || mainBookerFormFields?.length) {
23170
- if (isEmpty$1(values.street) && isMainBookerFormFieldPresent('street')) {
23171
- errors.street = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.STREET]);
23172
- }
23173
- if (isEmpty$1(values.houseNumber) && isMainBookerFormFieldPresent('houseNumber')) {
23174
- errors.houseNumber = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.HOUSE_NUMBER]);
23175
- }
23176
- if (isEmpty$1(values.zipCode) && isMainBookerFormFieldPresent('zipCode')) {
23177
- errors.zipCode = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.ZIPCODE]);
23178
- }
23179
- if (isEmpty$1(values.place) && isMainBookerFormFieldPresent('place')) {
23180
- errors.place = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.CITY]);
23181
- }
23182
- if (isMainBookerFormFieldPresent('email')) {
23183
- if (isEmpty$1(values.email)) {
23184
- errors.email = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.EMAIL]);
23185
- }
23186
- else if (isValidEmail(values.email)) {
23187
- errors.email = translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_EMAIL_IS_INVALID;
23188
- }
23189
- if (isEmpty$1(values.emailConfirmation)) {
23190
- errors.emailConfirmation = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.REPEAT_EMAIL]);
23191
- }
23192
- else if (values.emailConfirmation !== values.email) {
23193
- errors.emailConfirmation = translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_EMAIL_DOES_NOT_MATCH;
23194
- }
23195
- }
23196
- if (isEmpty$1(values.country) && isMainBookerFormFieldPresent('country')) {
23197
- errors.country = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.COUNTRY]);
23198
- }
23199
- if (isEmpty$1(values.phone) && isMainBookerFormFieldPresent('phone')) {
23200
- errors.phone = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.PHONE]);
23201
- }
23202
- }
23203
- else {
23204
- if (isEmpty$1(values.phone)) {
23205
- errors.phone = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.PHONE]);
23206
- }
23207
- }
23208
- if (agentRequired && !values.travelAgentId) {
23209
- errors.travelAgentId = translations.TRAVELERS_FORM.VALIDATION.AGENT_IS_REQUIRED;
23210
- }
23211
- return errors;
23212
- };
23213
-
23214
- const LabeledInput = ({ name, type, required, value, defaultValue, min, max, label, placeholder, extraClassName, hasError, onChange, onBlur }) => {
23215
- return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
23216
- React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
23217
- React__default.createElement("input", { name: name, type: type ?? 'text', required: required, className: "form__input", min: min, max: max, placeholder: placeholder, onChange: onChange, onBlur: onBlur, value: value, defaultValue: defaultValue })));
23218
- };
23219
-
23220
- const LabeledSelect = ({ name, id, required, value, defaultValue, label, extraClassName, extraDropdownClassName, hasError, options, onChange, onBlur }) => {
23221
- return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
23222
- React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
23223
- React__default.createElement("div", { className: buildClassName(['dropdown', extraDropdownClassName]) },
23224
- React__default.createElement("select", { name: name, id: id, defaultValue: defaultValue, value: value, onBlur: onBlur, onChange: onChange }, options?.map((option) => (React__default.createElement("option", { key: option.key, value: option.value }, option.label)))))));
23225
- };
23226
-
23227
- const normalize = (v) => (v == null ? '' : String(v));
23228
- const parseCombined = (raw, countries) => {
23229
- const value = normalize(raw).trim();
23230
- if (!value)
23231
- return { prefix: '', number: '' };
23232
- // Try to match a known prefix at the start. Prefer longest match.
23233
- const sorted = [...countries].sort((a, b) => b.phonePrefix.length - a.phonePrefix.length);
23234
- const hit = sorted.find((c) => value.startsWith(c.phonePrefix));
23235
- if (hit) {
23236
- const rest = value
23237
- .slice(hit.phonePrefix.length)
23238
- .trim()
23239
- .replace(/^[-\s]+/, '');
23240
- return { prefix: hit.phonePrefix, number: rest };
23241
- }
23242
- // Fallback: split on first space if it looks like a +prefix number
23243
- const m = value.match(/^(\+\d{1,4})[\s-]*(.*)$/);
23244
- if (m)
23245
- return { prefix: m[1], number: m[2] };
23246
- return { prefix: '', number: value };
23247
- };
23248
- const PhoneInput = ({ name, required, value, label, placeholder, extraClassName, hasError, countries, countryIso2, onChange, onBlur }) => {
23249
- // Derive initial state from `value`
23250
- const initialCountry = countries.find((c) => c.iso2 === countryIso2);
23251
- const initial = useMemo(() => parseCombined(normalize(value), countries), [value, countries]);
23252
- const [prefix, setPrefix] = useState(initial.prefix);
23253
- const [number, setNumber] = useState(initial.number);
23254
- // Keep state in sync if the parent changes `value`
23255
- useEffect(() => {
23256
- const parsed = !prefix && !number && initialCountry ? { prefix: initialCountry.phonePrefix, number: '' } : parseCombined(normalize(value), countries);
23257
- if (parsed.prefix)
23258
- setPrefix(parsed.prefix);
23259
- if (parsed.number)
23260
- setNumber(parsed.number);
23261
- }, [value, countries, countryIso2]);
23262
- const emitCombinedChange = (e, nextPrefix, nextNumber) => {
23263
- // Combine with a space, unless the number already starts with a dash or space
23264
- const combined = nextPrefix && nextNumber ? compact([nextPrefix, nextNumber]).join(' ') : null;
23265
- onChange?.({
23266
- ...e,
23267
- type: 'change',
23268
- target: { name, value: combined },
23269
- currentTarget: { name, value: combined }
23270
- });
23271
- };
23272
- const handleCountryBlur = (e) => {
23273
- onBlur?.(e);
23274
- };
23275
- const onCountryChange = (e) => {
23276
- const next = e.target.value;
23277
- setPrefix(next);
23278
- emitCombinedChange(e, next, number);
23279
- };
23280
- const onPhoneChange = (e) => {
23281
- const cleaned = e.target.value.replace(/[^\d\s-]/g, '');
23282
- setNumber(cleaned);
23283
- emitCombinedChange(e, prefix, cleaned);
23284
- };
23285
- const handleNumberBlur = (e) => {
23286
- onBlur?.(e);
23287
- };
23288
- // Ensure the select shows a reasonable default when prefix is empty
23289
- const selectValue = prefix || '';
23290
- return (React__default.createElement("label", { className: buildClassName(['form__group', extraClassName, hasError && 'form__group--error']) },
23291
- label && React__default.createElement("span", { className: "form__label" }, compact([label, required && '*']).join(' ')),
23292
- React__default.createElement("div", { className: "phone-input" },
23293
- React__default.createElement("div", { className: "dropdown" },
23294
- React__default.createElement("select", { "aria-label": label ? `${label} – country code` : 'Country calling code', name: `${name}__country`, value: selectValue, onBlur: handleCountryBlur, onChange: onCountryChange },
23295
- React__default.createElement("option", { value: "", disabled: true }),
23296
- countries?.map((option) => (React__default.createElement("option", { key: option.iso2, value: option.phonePrefix },
23297
- option.name,
23298
- " (",
23299
- option.phonePrefix,
23300
- ")"))))),
23301
- React__default.createElement("input", { "aria-label": label ? `${label} – number` : 'Phone number', name: `${name}__number`, type: "tel", inputMode: "tel", required: required, className: "form__input", placeholder: placeholder, onChange: onPhoneChange, onBlur: handleNumberBlur, value: number }),
23302
- React__default.createElement("input", { type: "hidden", name: name, value: compact([prefix, number]).join(' ') }))));
23303
- };
23304
-
23305
- const hasVisibleError = (formik, key) => get(formik.errors, key) && get(formik.touched, key);
23306
-
23307
- const GenderControl = ({ translations, value, formik, name }) => {
23308
- return (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(formik, name) && 'form__group--error']) },
23309
- React__default.createElement("label", { className: "form__label" },
23310
- translations.TRAVELERS_FORM.GENDER_ID,
23311
- " *"),
23312
- React__default.createElement("div", { className: "radiobutton-group" },
23313
- React__default.createElement("div", { className: "radiobutton" },
23314
- React__default.createElement("label", { className: "radiobutton__label" },
23315
- React__default.createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: "m", checked: value.gender === 'm' }),
23316
- translations.TRAVELERS_FORM.MALE_GENDER)),
23317
- React__default.createElement("div", { className: "radiobutton" },
23318
- React__default.createElement("label", { className: "radiobutton__label" },
23319
- React__default.createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: "f", checked: value.gender === 'f' }),
23320
- translations.TRAVELERS_FORM.FEMALE_GENDER)))));
23321
- };
23322
-
23323
- const TypeAheadInput = ({ name, value, placeholder, options, onChange, onSelect, onClear }) => {
23324
- const [showItems, setShowItems] = useState(false);
23325
- const handleChange = (e) => {
23326
- if (onChange) {
23327
- onChange(e.target.value);
23328
- }
23329
- };
23330
- const handleClearClick = (e) => {
23331
- if (onClear) {
23332
- onClear();
23333
- }
23334
- setShowItems(false);
23335
- };
23336
- return (React__default.createElement("div", { className: "typeahead" },
23337
- React__default.createElement("div", { className: "typeahead__trigger typeahead__trigger--icon" },
23338
- React__default.createElement(Icon, { name: "ui-qsm-location" }),
23339
- React__default.createElement("input", { type: "text", className: "form__input", name: name, value: value, onChange: handleChange, placeholder: placeholder, required: true, autoComplete: "off", onKeyDown: (e) => {
23340
- if (e.key === 'Tab' && options && onSelect) {
23341
- onSelect(options[0].key);
23342
- setShowItems(false);
23343
- }
23344
- }, onFocus: () => setShowItems(true) }),
23345
- React__default.createElement("button", { type: "button", className: "button button--clear", onClick: handleClearClick })),
23346
- options && options.length > 0 && showItems && (React__default.createElement("div", { className: "typeahead__options" }, (options ?? []).map((option) => {
23347
- const matchIndex = typeof value !== 'undefined' ? option.text.indexOf(value) : 0;
23348
- const prefix = option.text.slice(0, matchIndex);
23349
- const highlight = option.text.slice(matchIndex, value?.length ?? 0);
23350
- const suffix = option.text.slice(matchIndex);
23351
- return (React__default.createElement("div", { className: "typeahead__option", key: option.key },
23352
- React__default.createElement("div", { className: "typeahead__option-header" },
23353
- React__default.createElement("button", { onClick: () => {
23354
- if (onSelect)
23355
- onSelect(option.key);
23356
- setShowItems(false);
23357
- }, type: "button", className: "button button--plain" },
23358
- prefix,
23359
- React__default.createElement("span", { className: "typeahead__option-highlight" }, highlight),
23360
- suffix))));
23361
- })))));
23362
- };
23363
-
23364
- // A traveler is a baby when the age they were booked with is at or below the baby
23365
- // boundary. Babies get their own label and birth date validation (TIDE-3269). Only
23366
- // meaningful for the regular form: the compact form asks for an age instead of a birth
23367
- // date, so it has nothing to validate and its own age input already states the age.
23368
- function isBabyAge(age, maxBabyAge = BABY_MAX_AGE) {
23369
- return typeof age === 'number' && age <= maxBabyAge;
23370
- }
23371
- // The native date input can hold values format() throws on (e.g. a 5+ digit year while typing), so never format an unvalidated birthDate
23372
- function formatBirthDate$1(birthDate) {
23373
- if (!birthDate)
23374
- return '';
23375
- const parsed = parse(birthDate, 'yyyy-MM-dd', new Date());
23376
- return isValid(parsed) ? format$2(parsed, 'dd-MM-yyyy') : '';
23377
- }
23378
- function createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge) {
23379
- if (isCompact) {
23380
- return {
23381
- id: traveler.id,
23382
- firstName: personTranslation,
23383
- lastName: `${followNumber.number++}`,
23384
- birthDate: '',
23385
- gender: '',
23386
- // Keep a booked age of 0 instead of submitting and pricing the traveler as a 30 year
23387
- // old, while still falling back for a missing or unusable age. `??` alone would let a
23388
- // NaN (unparseable date of birth upstream) reach the age input and the booked pax.
23389
- // See TIDE-3269.
23390
- age: Number.isFinite(traveler.age) ? traveler.age : 30
23391
- // No isBaby here on purpose: the age below is editable and nothing revalidates it
23392
- // in compact mode, so a stored flag would end up contradicting the entered age.
23393
- };
23394
- }
23395
- return {
23396
- id: traveler.id,
23397
- firstName: '',
23398
- lastName: '',
23399
- birthDate: '',
23400
- gender: '',
23401
- isBaby: isBabyAge(traveler.age, maxBabyAge)
23402
- };
23403
- }
23404
- function createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, personTranslation, isCompact, maxBabyAge) {
23405
- const followNumber = { number: 1 };
23406
- const initialValues = {
23407
- startDate,
23408
- endDate,
23409
- rooms: formRooms.map((room) => ({
23410
- adults: room.adults.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge)),
23411
- children: room.children.map((traveler) => createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge))
23412
- })),
23413
- mainBookerId: -1,
23414
- street: '',
23415
- houseNumber: '',
23416
- box: '',
23417
- zipCode: '',
23418
- place: '',
23419
- country: '',
23420
- phone: '',
23421
- email: '',
23422
- emailConfirmation: '',
23423
- travelAgentId: agentAdressId ?? 0,
23424
- travelAgentName: ''
23425
- };
23426
- if (initialValues.rooms?.[0]?.adults?.[0]) {
23427
- initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
23428
- }
23429
- return initialValues;
23430
- }
23431
- function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId) {
23432
- const pax = editablePackagingEntry?.pax ?? [];
23433
- const rooms = editablePackagingEntry.rooms.map((room) => {
23434
- const roomPax = pax.filter((x) => room.paxIds.includes(x.id));
23435
- const adults = roomPax.filter((x) => x.age >= 18);
23436
- const children = roomPax.filter((x) => x.age < 18);
23437
- return {
23438
- adults: adults.map((roomTraveler) => {
23439
- return {
23440
- id: roomTraveler.id,
23441
- firstName: roomTraveler.firstName ?? '',
23442
- lastName: roomTraveler.lastName ?? '',
23443
- birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
23444
- gender: ''
23445
- };
23446
- }),
23447
- children: children.map((roomTraveler) => {
23448
- return {
23449
- id: roomTraveler.id,
23450
- firstName: roomTraveler.firstName ?? '',
23451
- lastName: roomTraveler.lastName ?? '',
23452
- birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
23453
- gender: '',
23454
- isBaby: isBabyAge(roomTraveler.age)
23455
- };
23456
- })
23457
- };
23458
- });
23459
- const values = createInitialValuesFromRooms(rooms.map((room) => ({ adults: room.adults, children: room.children })), first(editablePackagingEntry?.lines)?.from, last(editablePackagingEntry?.lines)?.to, agentAdressId);
23460
- values.rooms = rooms;
23461
- values.mainBookerId = pax.find((x) => x.isMainBooker)?.id ?? rooms[0]?.adults?.[0]?.id ?? -1;
23462
- const address = editablePackagingEntry?.address;
23463
- values.street = address?.street ?? '';
23464
- values.houseNumber = address?.houseNumber ?? '';
23465
- values.box = address?.box ?? '';
23466
- values.zipCode = address?.zipCode ?? '';
23467
- values.place = address?.place ?? '';
23468
- values.country = address?.country ?? '';
23469
- values.phone = address?.phone ?? '';
23470
- values.email = address?.email ?? '';
23471
- values.emailConfirmation = address?.email ?? '';
23472
- values.travelAgentId = address?.travelAgentId ?? agentAdressId ?? 0;
23473
- return values;
24267
+ React__default.createElement(Icon, { name: "ui-tooltip", className: "icon--secondary-color" }),
24268
+ React__default.createElement("div", { className: "info-message__copy" },
24269
+ React__default.createElement("h5", null, translations.SUMMARY.VALIDATE_TITLE),
24270
+ settings.customValidateText ? (React__default.createElement("div", { dangerouslySetInnerHTML: {
24271
+ __html: settings.customValidateText
24272
+ } })) : (React__default.createElement(React__default.Fragment, null,
24273
+ React__default.createElement("p", null, settings.isOffer ? translations.SUMMARY.VALIDATE_TEXT_OFFER : translations.SUMMARY.VALIDATE_TEXT_BOOKING),
24274
+ settings.allowOption && React__default.createElement("p", null, translations.SUMMARY.VALIDATE_TEXT_OPTION))),
24275
+ checkboxes &&
24276
+ checkboxes.map((checkbox) => (React__default.createElement("div", { className: "checkbox", key: checkbox.id },
24277
+ React__default.createElement("label", { className: "checkbox__label" },
24278
+ React__default.createElement("input", { type: "checkbox", className: "checkbox__input", checked: checkbox.isSelected, onChange: (e) => handleCheckboxChange(checkbox.id, e.target.checked) }),
24279
+ React__default.createElement("span", { className: "checkbox__label-text", dangerouslySetInnerHTML: {
24280
+ __html: checkbox.text
24281
+ } }))))))))))),
24282
+ React__default.createElement("div", { className: "booking__navigator" },
24283
+ settings.skipRouter ? (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => goPrevious(), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : (React__default.createElement(Link, { to: `${!settings.skipBasePathInRouting ? settings.basePath : ''}${travelersFirstStep ? settings.options.pathSuffix : settings.travellers.pathSuffix}?${bookingQueryString}`, title: translations.STEPS.PREVIOUS, className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)),
24284
+ settings.allowOption && (React__default.createElement("button", { title: translations.STEPS.SUBMIT_OPTION, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "option" }, translations.STEPS.SUBMIT_OPTION)),
24285
+ React__default.createElement("button", { title: settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "default" }, settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING))))));
24286
+ };
24287
+
24288
+ function isValidEmail(email) {
24289
+ return !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,24}$/i.test(email);
23474
24290
  }
23475
- function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry, values) {
23476
- const travelers = values.rooms.flatMap((room) => [...room.adults, ...room.children]);
23477
- return {
23478
- ...editablePackagingEntry,
23479
- pax: (editablePackagingEntry.pax ?? []).map((pax) => {
23480
- const traveler = travelers.find((x) => x.id === pax.id);
23481
- if (!traveler)
23482
- return pax;
23483
- return {
23484
- ...pax,
23485
- firstName: traveler.firstName ?? '',
23486
- lastName: traveler.lastName ?? '',
23487
- dateOfBirth: traveler.birthDate || null,
23488
- isMainBooker: traveler.id === values.mainBookerId
23489
- };
23490
- }),
23491
- address: {
23492
- ...editablePackagingEntry.address,
23493
- street: values.street,
23494
- houseNumber: values.houseNumber,
23495
- box: values.box,
23496
- zipCode: values.zipCode,
23497
- place: values.place,
23498
- country: values.country,
23499
- travelAgentId: values.travelAgentId,
23500
- phone: values.phone,
23501
- email: values.email
23502
- }
23503
- };
24291
+ const NAME_CHARACTERS_REGEX = /^[\p{L}\s-]+$/u;
24292
+ function hasInvalidNameCharacters(name) {
24293
+ return !NAME_CHARACTERS_REGEX.test(name);
23504
24294
  }
23505
- const SharedTravelersForm = ({ formik, translations, travellersSettings, countries, agents, bookingType, agentAdressId, travelersFirstStep = false, isUnavailable = false, useCompactForm = false, showAllCountries = false, showAgentSelection = false, initialShowAgents = false, renderPreviousButton, onBookingTypeChange }) => {
23506
- const [showAgents, setShowAgents] = useState(initialShowAgents);
23507
- const typeaheadAgents = useMemo(() => sortBy(agents?.map((agent) => ({
23508
- key: `${agent.id}`,
23509
- value: `${agent.name}${agent.postalCode || agent.location ? ` (${compact([agent.postalCode, agent.location]).join(' ')})` : ''}`,
23510
- text: `${agent.name}${agent.postalCode || agent.location ? ` (${compact([agent.postalCode, agent.location]).join(' ')})` : ''}`
23511
- })), 'value') ?? [], [agents]);
23512
- const [filteredAgents, setFilteredAgents] = useState(typeaheadAgents);
23513
- const flatErrors = flat(formik.errors);
23514
- const errorKeys = Object.keys(flatErrors).filter((key) => get(formik.touched, key));
23515
- const hasVisibleError = (key) => get(formik.errors, key) && get(formik.touched, key);
23516
- const mainBooker = formik.values.rooms
23517
- .find((room) => room.adults.find((traveler) => traveler.id === formik.values.mainBookerId))
23518
- ?.adults.find((traveler) => traveler.id === formik.values.mainBookerId);
23519
- const countryOptions = [
23520
- { key: 'empty', value: undefined, label: translations.TRAVELERS_FORM.SELECT_COUNTRY },
23521
- ...(showAllCountries
23522
- ? countries?.map((country) => ({ key: country.iso2, value: country.iso2, label: country.name })) ?? []
23523
- : travellersSettings?.countries?.map((country) => ({ key: country.iso2, value: country.iso2, label: country.name })) ?? [
23524
- { key: 'be', value: 'be', label: translations.TRAVELERS_FORM.COUNTRIES.BELGIUM },
23525
- { key: 'nl', value: 'nl', label: translations.TRAVELERS_FORM.COUNTRIES.NETHERLANDS },
23526
- { key: 'fr', value: 'fr', label: translations.TRAVELERS_FORM.COUNTRIES.FRANCE }
23527
- ])
23528
- ];
23529
- const handleMainBookerChange = (event) => {
23530
- formik.setFieldValue('mainBookerId', parseInt(event.currentTarget.value, 10));
24295
+ // Rejects values like a 5-digit year, which the native date input allows while typing
24296
+ function isValidBirthDate(birthDateText) {
24297
+ return isValid(parse(birthDateText, 'yyyy-MM-dd', new Date()));
24298
+ }
24299
+ function getAge(birthDateText, startDateText) {
24300
+ var birthDate = new Date(birthDateText);
24301
+ var startDate = new Date(startDateText);
24302
+ var age = startDate.getFullYear() - birthDate.getFullYear();
24303
+ var m = startDate.getMonth() - birthDate.getMonth();
24304
+ if (m < 0 || (m === 0 && startDate.getDate() < birthDate.getDate())) {
24305
+ age--;
24306
+ }
24307
+ return age;
24308
+ }
24309
+ const validateForm$1 = (values, agentRequired, bookingType, translations, formFields, mainBookerFormFields, maxChildAge = CHILD_MAX_AGE, maxBabyAge = BABY_MAX_AGE, paxFields = []) => {
24310
+ const errors = {};
24311
+ const isFormFieldPresent = (type) => {
24312
+ return formFields?.some((f) => f.type === type) ?? true;
23531
24313
  };
23532
- const handleAgentChange = (value) => {
23533
- setFilteredAgents(typeaheadAgents.filter((x) => x.value.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) > -1));
23534
- formik.setFieldValue('travelAgentName', value);
24314
+ const isMainBookerFormFieldPresent = (type) => {
24315
+ return mainBookerFormFields?.some((f) => f.type === type) ?? true;
23535
24316
  };
23536
- const handleAgentSelect = (key) => {
23537
- const agent = typeaheadAgents.find((x) => x.key === key);
23538
- formik.setValues({
23539
- ...formik.values,
23540
- travelAgentId: Number(agent?.key),
23541
- travelAgentName: agent?.value ?? ''
23542
- });
23543
- onBookingTypeChange?.(agentAdressId && agentAdressId !== 0 ? 'b2b' : 'b2b2c');
24317
+ const formatTravelerField = (room, pax, field) => {
24318
+ return values.rooms.length > 1
24319
+ ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_FIELD, [room, pax, field])
24320
+ : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_FIELD, [pax, field]);
23544
24321
  };
23545
- const handleAgentClear = () => {
23546
- formik.setValues({ ...formik.values, travelAgentId: 0, travelAgentName: '' });
23547
- onBookingTypeChange?.('b2c');
24322
+ const formatTravelerIsNoAdult = (room, pax) => {
24323
+ return values.rooms.length > 1
24324
+ ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_IS_NO_ADULT, [room, pax])
24325
+ : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_IS_NO_ADULT, [pax]);
23548
24326
  };
23549
- const toggleAgent = (value) => {
23550
- setShowAgents(value);
23551
- if (!value) {
23552
- handleAgentClear();
23553
- setFilteredAgents([]);
23554
- }
24327
+ const formatTravelerIsNoChild = (room, pax) => {
24328
+ return values.rooms.length > 1
24329
+ ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_IS_NO_CHILD, [room, pax])
24330
+ : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_IS_NO_CHILD, [pax]);
23555
24331
  };
23556
- const handleAddTraveler = (roomIndex) => {
23557
- const rooms = [...formik.values.rooms];
23558
- const newAdult = { id: Date.now(), firstName: '', lastName: '', birthDate: '', gender: '' };
23559
- rooms[roomIndex] = { ...rooms[roomIndex], adults: [...rooms[roomIndex].adults, newAdult] };
23560
- formik.setFieldValue('rooms', rooms);
24332
+ const formatTravelerIsNoBaby = (room, pax) => {
24333
+ // The message states the boundary the traveler has to stay under, so we pass
24334
+ // the first age that is too old rather than the inclusive maxBabyAge.
24335
+ const tooOldAge = maxBabyAge + 1;
24336
+ return values.rooms.length > 1
24337
+ ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_IS_NO_BABY, [room, pax, tooOldAge])
24338
+ : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_IS_NO_BABY, [pax, tooOldAge]);
23561
24339
  };
23562
- const handleRemoveTraveler = (roomIndex, travelerIndex) => {
23563
- const rooms = [...formik.values.rooms];
23564
- const adults = [...rooms[roomIndex].adults];
23565
- if (adults.length <= 1)
23566
- return;
23567
- adults.splice(travelerIndex, 1);
23568
- rooms[roomIndex] = { ...rooms[roomIndex], adults };
23569
- formik.setFieldValue('rooms', rooms);
24340
+ const formatTravelerFieldInvalidCharacters = (room, pax, field) => {
24341
+ return values.rooms.length > 1
24342
+ ? format$1(translations.TRAVELERS_FORM.VALIDATION.TRAVELER_X_FIELD_INVALID_CHARACTERS, [room, pax, field])
24343
+ : format$1(translations.TRAVELERS_FORM.VALIDATION.SINGLE_ROOM_TRAVELER_X_FIELD_INVALID_CHARACTERS, [pax, field]);
23570
24344
  };
23571
- const handleAddRoom = () => {
23572
- const rooms = [...formik.values.rooms];
23573
- rooms.push({ adults: [{ id: Date.now(), firstName: '', lastName: '', birthDate: '', gender: '' }], children: [] });
23574
- formik.setFieldValue('rooms', rooms);
24345
+ const validateRequiredCustomFields = (traveler, path, room, pax) => {
24346
+ const isMainBooker = traveler.id === values.mainBookerId;
24347
+ const requiredFields = getApplicablePaxCustomFields(paxFields, isMainBooker).filter((f) => f.isRequired);
24348
+ requiredFields.forEach((field) => {
24349
+ const fieldIndex = traveler.customFields?.findIndex((c) => c.customFieldConfigurationId === field.customFieldConfigurationId) ?? -1;
24350
+ if (fieldIndex < 0)
24351
+ return;
24352
+ if (isEmpty$1(traveler.customFields[fieldIndex].value)) {
24353
+ set(errors, `${path}.customFields[${fieldIndex}].value`, formatTravelerField(room, pax, field.fieldName));
24354
+ }
24355
+ });
23575
24356
  };
23576
- const handleRemoveRoom = (roomIndex) => {
23577
- const rooms = [...formik.values.rooms];
23578
- rooms.splice(roomIndex, 1);
23579
- formik.setFieldValue('rooms', rooms);
24357
+ // Excludes the 4 core fields, which are already validated unconditionally below.
24358
+ const validateRequiredBuiltInFields = (traveler, path, room, pax) => {
24359
+ const isMainBooker = traveler.id === values.mainBookerId;
24360
+ const requiredFields = getApplicableBuiltInPaxFields(paxFields, isMainBooker).filter((f) => f.isRequired && !CORE_FIELD_NAMES.has(f.fieldName));
24361
+ requiredFields.forEach((field) => {
24362
+ const fieldPath = BUILT_IN_FIELD_PATHS[field.fieldName];
24363
+ if (!fieldPath)
24364
+ return;
24365
+ if (isEmpty$1(get(traveler, fieldPath))) {
24366
+ set(errors, `${path}.${fieldPath}`, formatTravelerField(room, pax, field.fieldName));
24367
+ }
24368
+ });
23580
24369
  };
23581
- const renderGenderControl = (name, value) => (React__default.createElement("div", { className: buildClassName(['form__group', hasVisibleError(name) && 'form__group--error']) },
23582
- React__default.createElement("label", { className: "form__label" },
23583
- translations.TRAVELERS_FORM.GENDER_ID,
23584
- " *"),
23585
- React__default.createElement("div", { className: "radiobutton-group" }, [
23586
- ['m', translations.TRAVELERS_FORM.MALE_GENDER],
23587
- ['f', translations.TRAVELERS_FORM.FEMALE_GENDER]
23588
- ].map(([gender, label]) => (React__default.createElement("div", { className: "radiobutton", key: gender },
23589
- React__default.createElement("label", { className: "radiobutton__label" },
23590
- React__default.createElement("input", { type: "radio", className: "radiobutton__input", name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: gender, checked: value.gender === gender }),
23591
- label)))))));
23592
- const getControl = (type, value, name) => {
23593
- switch (type) {
23594
- case 'gender':
23595
- return React__default.createElement(GenderControl, { translations: translations, value: value, formik: formik, name: name });
23596
- case 'firstName':
23597
- return (React__default.createElement(LabeledInput, { hasError: hasVisibleError(name), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.FIRST_NAME, required: true, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.firstName }));
23598
- case 'lastName':
23599
- return (React__default.createElement(LabeledInput, { hasError: hasVisibleError(name), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.LAST_NAME, required: true, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.lastName }));
23600
- case 'birthDate':
23601
- return (React__default.createElement(LabeledInput, { type: "date", hasError: hasVisibleError(name), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.BIRTHDATE, required: true, name: name, onChange: formik.handleChange, onBlur: formik.handleBlur, value: value.birthDate }));
23602
- case 'country':
23603
- return (React__default.createElement(LabeledSelect, { hasError: hasVisibleError('country'), label: translations.TRAVELERS_FORM.COUNTRY, required: true, name: "country", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.country, options: countryOptions }));
23604
- case 'phone':
23605
- return (React__default.createElement(PhoneInput, { countries: travellersSettings?.countries ?? [], countryIso2: formik.values.country, hasError: hasVisibleError('phone'), label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }));
23606
- case 'email':
23607
- return (React__default.createElement(React__default.Fragment, null,
23608
- React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
23609
- React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })));
23610
- case 'street':
23611
- return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('street'), extraClassName: "form__group--50 form__group--sm-60", label: translations.TRAVELERS_FORM.STREET, required: true, name: "street", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.street }));
23612
- case 'houseNumber':
23613
- return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('houseNumber'), extraClassName: "form__group--30 form__group--sm-20", label: translations.TRAVELERS_FORM.HOUSE_NUMBER, required: true, name: "houseNumber", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.houseNumber }));
23614
- case 'box':
23615
- return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('box'), extraClassName: "form__group--20", label: translations.TRAVELERS_FORM.POST_BOX, name: "box", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.box }));
23616
- case 'zipCode':
23617
- return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('zipCode'), extraClassName: "form__group--40 form__group--sm-20", label: translations.TRAVELERS_FORM.ZIPCODE, required: true, name: "zipCode", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.zipCode }));
23618
- case 'place':
23619
- return (React__default.createElement(LabeledInput, { hasError: hasVisibleError('place'), extraClassName: "form__group--60 form__group--sm-40", label: translations.TRAVELERS_FORM.CITY, required: true, name: "place", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.place }));
23620
- default:
23621
- return null;
24370
+ values.rooms.forEach((r, rIndex) => r.adults.forEach((adult, index) => {
24371
+ if (isEmpty$1(adult.gender) && isFormFieldPresent('gender')) {
24372
+ set(errors, `rooms[${rIndex}].adults[${index}].gender`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.GENDER));
23622
24373
  }
23623
- };
23624
- const renderRoomLabel = (room) => compact([
23625
- room.adults.length,
23626
- room.adults.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
23627
- room.adults.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
23628
- room.adults?.length && room.children?.length && ', ',
23629
- room.children.length,
23630
- room.children.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
23631
- room.children.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`
23632
- ]).join('');
23633
- const renderTravelerFields = (travelerValues, namePrefix, isAdult, roomIndex, travelerIndex) => {
23634
- if (useCompactForm) {
23635
- return (React__default.createElement("div", { className: "form__row" },
23636
- React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.age`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.AGE, required: true, name: `${namePrefix}.age`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.age })));
24374
+ if (isFormFieldPresent('firstName')) {
24375
+ if (isEmpty$1(adult.firstName)) {
24376
+ set(errors, `rooms[${rIndex}].adults[${index}].firstName`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
24377
+ }
24378
+ else if (hasInvalidNameCharacters(adult.firstName)) {
24379
+ set(errors, `rooms[${rIndex}].adults[${index}].firstName`, formatTravelerFieldInvalidCharacters(rIndex + 1, index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
24380
+ }
23637
24381
  }
23638
- if (travellersSettings?.formFields?.length) {
23639
- return (React__default.createElement("div", { className: "travelers-form__grid" }, travellersSettings.formFields.map((field, index) => (React__default.createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, travelerValues, `${namePrefix}.${field.type}`))))));
24382
+ if (isFormFieldPresent('lastName')) {
24383
+ if (isEmpty$1(adult.lastName)) {
24384
+ set(errors, `rooms[${rIndex}].adults[${index}].lastName`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.LAST_NAME));
24385
+ }
24386
+ else if (hasInvalidNameCharacters(adult.lastName)) {
24387
+ set(errors, `rooms[${rIndex}].adults[${index}].lastName`, formatTravelerFieldInvalidCharacters(rIndex + 1, index + 1, translations.TRAVELERS_FORM.LAST_NAME));
24388
+ }
23640
24389
  }
23641
- return (React__default.createElement(React__default.Fragment, null,
23642
- React__default.createElement("div", { className: "form__row" }, renderGenderControl(`${namePrefix}.gender`, travelerValues)),
23643
- React__default.createElement("div", { className: "form__row" },
23644
- React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.firstName`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.FIRST_NAME, required: true, name: `${namePrefix}.firstName`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.firstName }),
23645
- React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.lastName`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.LAST_NAME, required: true, name: `${namePrefix}.lastName`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.lastName }),
23646
- React__default.createElement(LabeledInput, { type: "date", hasError: hasVisibleError(`${namePrefix}.birthDate`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.BIRTHDATE, required: true, name: `${namePrefix}.birthDate`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.birthDate })),
23647
- travelersFirstStep && isAdult && formik.values.rooms[roomIndex].adults.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveTraveler(roomIndex, travelerIndex) }, translations.TRAVELERS_FORM.REMOVE_TRAVELER))));
23648
- };
23649
- return (React__default.createElement("form", { className: "form form__travelers", name: "booking--travellers", id: "booking--travellers", noValidate: true, onSubmit: formik.handleSubmit, onReset: formik.handleReset },
23650
- React__default.createElement("div", { className: "form__travelers__wrapper" },
23651
- formik.values.rooms.map((room, roomIndex) => (React__default.createElement("div", { key: roomIndex },
23652
- formik.values.rooms.length > 1 && (React__default.createElement("div", { className: "form__region" },
23653
- React__default.createElement("div", { className: "form__region-header" },
23654
- React__default.createElement("h5", { className: "form__region-heading" },
23655
- translations.SHARED.ROOM,
23656
- " ",
23657
- roomIndex + 1),
23658
- React__default.createElement("p", { className: "form__region-label" }, renderRoomLabel(room))),
23659
- !useCompactForm && travelersFirstStep && formik.values.rooms.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveRoom(roomIndex) }, "Verwijder reisgezelschap")))),
23660
- room.adults.map((travelerValues, index) => (React__default.createElement("div", { className: "form__region", key: travelerValues.id },
23661
- React__default.createElement("div", { className: "form__region-header" },
23662
- React__default.createElement("h5", { className: "form__region-heading" },
23663
- translations.TRAVELERS_FORM.TRAVELER,
23664
- " ",
23665
- index + 1),
23666
- React__default.createElement("p", { className: "form__region-label" }, translations.TRAVELERS_FORM.ADULT),
23667
- React__default.createElement("div", { className: "radiobutton" },
23668
- React__default.createElement("label", { className: "radiobutton__label" },
23669
- React__default.createElement("input", { type: "radio", name: "mainBookerId", onChange: handleMainBookerChange, onBlur: formik.handleBlur, value: travelerValues.id, checked: formik.values.mainBookerId === travelerValues.id, className: "radiobutton__input" }),
23670
- translations.TRAVELERS_FORM.MAIN_BOOKER))),
23671
- renderTravelerFields(travelerValues, `rooms[${roomIndex}].adults[${index}]`, true, roomIndex, index)))),
23672
- room.children.map((travelerValues, index) => (React__default.createElement("div", { className: "form__region", key: travelerValues.id },
23673
- React__default.createElement("div", { className: "form__region-header" },
23674
- React__default.createElement("h5", { className: "form__region-heading" },
23675
- translations.TRAVELERS_FORM.TRAVELER,
23676
- " ",
23677
- room.adults.length + index + 1),
23678
- React__default.createElement("p", { className: "form__region-label" }, travelerValues.isBaby ? translations.TRAVELERS_FORM.BABY : translations.TRAVELERS_FORM.CHILD)),
23679
- renderTravelerFields(travelerValues, `rooms[${roomIndex}].children[${index}]`, false, roomIndex, index)))),
23680
- !useCompactForm && travelersFirstStep && (React__default.createElement("div", { className: "form__region" },
23681
- React__default.createElement("button", { type: "button", className: "cta cta--select", onClick: () => handleAddTraveler(roomIndex) }, translations.TRAVELERS_FORM.ADD_TRAVELER)))))),
23682
- !useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default.createElement("div", { className: "form__region" },
23683
- React__default.createElement("div", { className: "form__region-header" },
23684
- React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
23685
- React__default.createElement("p", { className: "form__region-label" }, compact([compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
23686
- travellersSettings?.mainBookerFormFields?.length ? (React__default.createElement("div", { className: "main-booker-form__grid" }, travellersSettings.mainBookerFormFields.map((field, index) => (React__default.createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, {}, field.type)))))) : (React__default.createElement(React__default.Fragment, null,
23687
- React__default.createElement("div", { className: "form__twocolumn" },
23688
- React__default.createElement("div", { className: "form__twocolumn-column" },
23689
- React__default.createElement("div", { className: "form__row" },
23690
- React__default.createElement(LabeledInput, { hasError: hasVisibleError('street'), extraClassName: "form__group--50 form__group--sm-60", label: translations.TRAVELERS_FORM.STREET, required: true, name: "street", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.street }),
23691
- React__default.createElement(LabeledInput, { hasError: hasVisibleError('houseNumber'), extraClassName: "form__group--30 form__group--sm-20", label: translations.TRAVELERS_FORM.HOUSE_NUMBER, required: true, name: "houseNumber", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.houseNumber }),
23692
- React__default.createElement(LabeledInput, { hasError: hasVisibleError('box'), extraClassName: "form__group--20", label: translations.TRAVELERS_FORM.POST_BOX, name: "box", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.box }))),
23693
- React__default.createElement("div", { className: "form__twocolumn-column" },
23694
- React__default.createElement("div", { className: "form__row" },
23695
- React__default.createElement(LabeledInput, { hasError: hasVisibleError('zipCode'), extraClassName: "form__group--40 form__group--sm-20", label: translations.TRAVELERS_FORM.ZIPCODE, required: true, name: "zipCode", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.zipCode }),
23696
- React__default.createElement(LabeledInput, { hasError: hasVisibleError('place'), extraClassName: "form__group--60 form__group--sm-40", label: translations.TRAVELERS_FORM.CITY, required: true, name: "place", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.place }),
23697
- React__default.createElement(LabeledSelect, { hasError: hasVisibleError('country'), extraClassName: "form__group--sm-40", label: translations.TRAVELERS_FORM.COUNTRY, required: true, name: "country", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.country, options: countryOptions })))),
23698
- React__default.createElement("div", { className: "form__row" },
23699
- React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }),
23700
- React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
23701
- React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })))))) : !useCompactForm ? (React__default.createElement("div", { className: "form__region" },
23702
- React__default.createElement("div", { className: "form__row" },
23703
- React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone })))) : null,
23704
- !useCompactForm && showAgentSelection && (React__default.createElement("div", { className: "form__region" },
23705
- React__default.createElement("div", { className: "form__region-header" },
23706
- React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.BOOK_WITH_AGENT),
23707
- React__default.createElement("div", { className: "checkbox", id: "cbxChooseOffice" },
23708
- React__default.createElement("label", { className: "checkbox__label" },
23709
- React__default.createElement("input", { type: "checkbox", name: "booking--mainbooker", checked: showAgents, onChange: () => toggleAgent(!showAgents), className: "checkbox__input" }),
23710
- translations.TRAVELERS_FORM.CHOOSE_OFFICE))),
23711
- showAgents && (React__default.createElement("div", { className: "form__row form__row--choose-office" },
23712
- React__default.createElement("div", { className: buildClassName(['form__group', 'form__group--icon', hasVisibleError('travelAgentId') && 'form__group--error']) },
23713
- React__default.createElement(TypeAheadInput, { value: formik.values.travelAgentName, options: filteredAgents, onChange: handleAgentChange, onSelect: handleAgentSelect, onClear: handleAgentClear, name: "travelAgentName", placeholder: translations.TRAVELERS_FORM.CHOOSE_AGENT_PLACEHOLDER }))))))),
23714
- !useCompactForm && errorKeys.length > 0 && (React__default.createElement("div", { className: "form__region form__region--errors" },
23715
- React__default.createElement("div", { className: "form__row" },
23716
- React__default.createElement("div", { className: "form__group" },
23717
- React__default.createElement("p", { className: "form__error-heading" },
23718
- translations.TRAVELERS_FORM.VALIDATION_MESSAGE,
23719
- ":"),
23720
- React__default.createElement("ul", { className: "list" }, errorKeys.map((key) => (React__default.createElement("li", { key: key }, get(flatErrors, key))))))))),
23721
- travelersFirstStep && (React__default.createElement("div", { className: "booking__navigator" },
23722
- React__default.createElement("button", { type: "button", className: "cta cta--select", onClick: handleAddRoom }, translations.TRAVELERS_FORM.ADD_ROOM))),
23723
- React__default.createElement("div", { className: "booking__navigator" },
23724
- renderPreviousButton?.(),
23725
- React__default.createElement("button", { type: "submit", title: translations.STEPS.NEXT, className: 'cta' + (isUnavailable ? ' cta--disabled' : '') }, translations.STEPS.NEXT))));
24390
+ if (isFormFieldPresent('birthDate')) {
24391
+ if (isEmpty$1(adult.birthDate) || !isValidBirthDate(adult.birthDate)) {
24392
+ set(errors, `rooms[${rIndex}].adults[${index}].birthDate`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
24393
+ }
24394
+ else if (values.endDate) {
24395
+ // If you are younger than the maxChildAge at the end of the trip, you are considered a child, so we check the endDate here instead of the startDate
24396
+ const age = getAge(adult.birthDate, values.endDate);
24397
+ if (age <= maxChildAge) {
24398
+ set(errors, `rooms[${rIndex}].adults[${index}].birthDate`, formatTravelerIsNoAdult(rIndex + 1, index + 1));
24399
+ }
24400
+ }
24401
+ }
24402
+ validateRequiredCustomFields(adult, `rooms[${rIndex}].adults[${index}]`, rIndex + 1, index + 1);
24403
+ validateRequiredBuiltInFields(adult, `rooms[${rIndex}].adults[${index}]`, rIndex + 1, index + 1);
24404
+ }));
24405
+ values.rooms.forEach((r, rIndex) => r.children.forEach((child, index) => {
24406
+ if (isEmpty$1(child.gender) && isFormFieldPresent('gender')) {
24407
+ set(errors, `rooms[${rIndex}].children[${index}].gender`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.GENDER));
24408
+ }
24409
+ if (isFormFieldPresent('firstName')) {
24410
+ if (isEmpty$1(child.firstName)) {
24411
+ set(errors, `rooms[${rIndex}].children[${index}].firstName`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
24412
+ }
24413
+ else if (hasInvalidNameCharacters(child.firstName)) {
24414
+ set(errors, `rooms[${rIndex}].children[${index}].firstName`, formatTravelerFieldInvalidCharacters(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
24415
+ }
24416
+ }
24417
+ if (isFormFieldPresent('lastName')) {
24418
+ if (isEmpty$1(child.lastName)) {
24419
+ set(errors, `rooms[${rIndex}].children[${index}].lastName`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.LAST_NAME));
24420
+ }
24421
+ else if (hasInvalidNameCharacters(child.lastName)) {
24422
+ set(errors, `rooms[${rIndex}].children[${index}].lastName`, formatTravelerFieldInvalidCharacters(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.LAST_NAME));
24423
+ }
24424
+ }
24425
+ if (isFormFieldPresent('birthDate')) {
24426
+ if (isEmpty$1(child.birthDate) || !isValidBirthDate(child.birthDate)) {
24427
+ set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
24428
+ }
24429
+ else if (child.isBaby && values.startDate) {
24430
+ // A baby only has to be under the maxBabyAge on departure, so we check the startDate here instead of the endDate (TIDE-3269)
24431
+ const age = getAge(child.birthDate, values.startDate);
24432
+ if (age > maxBabyAge) {
24433
+ set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerIsNoBaby(rIndex + 1, r.adults.length + index + 1));
24434
+ }
24435
+ }
24436
+ else if (values.endDate) {
24437
+ // You need to be under the maxChildAge until the end of the trip, so we check the endDate here instead of the startDate.
24438
+ // Babies land here too when there is no startDate to check them against, so they keep at least the child age check.
24439
+ const age = getAge(child.birthDate, values.endDate);
24440
+ if (age > maxChildAge) {
24441
+ set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerIsNoChild(rIndex + 1, r.adults.length + index + 1));
24442
+ }
24443
+ }
24444
+ }
24445
+ validateRequiredCustomFields(child, `rooms[${rIndex}].children[${index}]`, rIndex + 1, r.adults.length + index + 1);
24446
+ validateRequiredBuiltInFields(child, `rooms[${rIndex}].children[${index}]`, rIndex + 1, r.adults.length + index + 1);
24447
+ }));
24448
+ if (values.mainBookerId < 0) {
24449
+ errors.mainBookerId = translations.TRAVELERS_FORM.VALIDATION.NO_MAIN_BOOKER_SELECTED;
24450
+ }
24451
+ if (bookingType != 'b2b' || mainBookerFormFields?.length) {
24452
+ if (isEmpty$1(values.street) && isMainBookerFormFieldPresent('street')) {
24453
+ errors.street = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.STREET]);
24454
+ }
24455
+ if (isEmpty$1(values.houseNumber) && isMainBookerFormFieldPresent('houseNumber')) {
24456
+ errors.houseNumber = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.HOUSE_NUMBER]);
24457
+ }
24458
+ if (isEmpty$1(values.zipCode) && isMainBookerFormFieldPresent('zipCode')) {
24459
+ errors.zipCode = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.ZIPCODE]);
24460
+ }
24461
+ if (isEmpty$1(values.place) && isMainBookerFormFieldPresent('place')) {
24462
+ errors.place = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.CITY]);
24463
+ }
24464
+ if (isMainBookerFormFieldPresent('email')) {
24465
+ if (isEmpty$1(values.email)) {
24466
+ errors.email = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.EMAIL]);
24467
+ }
24468
+ else if (isValidEmail(values.email)) {
24469
+ errors.email = translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_EMAIL_IS_INVALID;
24470
+ }
24471
+ if (isEmpty$1(values.emailConfirmation)) {
24472
+ errors.emailConfirmation = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.REPEAT_EMAIL]);
24473
+ }
24474
+ else if (values.emailConfirmation !== values.email) {
24475
+ errors.emailConfirmation = translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_EMAIL_DOES_NOT_MATCH;
24476
+ }
24477
+ }
24478
+ if (isEmpty$1(values.country) && isMainBookerFormFieldPresent('country')) {
24479
+ errors.country = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.COUNTRY]);
24480
+ }
24481
+ if (isEmpty$1(values.phone) && isMainBookerFormFieldPresent('phone')) {
24482
+ errors.phone = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.PHONE]);
24483
+ }
24484
+ }
24485
+ else {
24486
+ if (isEmpty$1(values.phone)) {
24487
+ errors.phone = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.PHONE]);
24488
+ }
24489
+ }
24490
+ if (agentRequired && !values.travelAgentId) {
24491
+ errors.travelAgentId = translations.TRAVELERS_FORM.VALIDATION.AGENT_IS_REQUIRED;
24492
+ }
24493
+ return errors;
23726
24494
  };
23727
24495
 
23728
24496
  const TravelersForm = () => {
@@ -23743,12 +24511,13 @@ const TravelersForm = () => {
23743
24511
  const bookingAttributes = useSelector(selectBookingAttributes);
23744
24512
  const hasMounted = useSelector(selectHasMounted);
23745
24513
  const countries = useSelector(selectCountries);
24514
+ const paxFields = useSelector(selectPaxFields);
23746
24515
  const inFlight = useRef(false);
23747
24516
  const pendingRefetch = useRef(false);
23748
24517
  const useCompactForm = !!settings.travellers.compactForm && !!settings.agentAdressId;
23749
24518
  const showAllCountries = !!settings.travellers.showAllCountries;
23750
24519
  const initialValues = useSelector(selectTravelersFormValues) ??
23751
- createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm, settings.maxBabyAge);
24520
+ createInitialValuesFromRooms(formRooms, startDate, endDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm, settings.maxBabyAge, paxFields);
23752
24521
  const [showAgentSelection, setShowAgentSelection] = useState(!settings.agentAdressId && !settings.hideAgentSelection);
23753
24522
  const formik = useFormik({
23754
24523
  initialValues,
@@ -23758,7 +24527,7 @@ const TravelersForm = () => {
23758
24527
  // The travel dates are captured into initialValues once and then persisted in
23759
24528
  // redux, so validating against the values would use the dates of whichever
23760
24529
  // package option was selected first. Age checks need the current ones.
23761
- { ...values, startDate, endDate }, settings.agentRequired, bookingType, translations, settings.travellers.formFields, settings.travellers.mainBookerFormFields, settings.maxChildAge, settings.maxBabyAge),
24530
+ { ...values, startDate, endDate }, settings.agentRequired, bookingType, translations, settings.travellers.formFields, settings.travellers.mainBookerFormFields, settings.maxChildAge, settings.maxBabyAge, paxFields),
23762
24531
  onSubmit: (values) => {
23763
24532
  dispatch(setFormValues(values));
23764
24533
  if (useCompactForm) {
@@ -23841,7 +24610,7 @@ const TravelersForm = () => {
23841
24610
  dispatch(setFormValues(formValues));
23842
24611
  setShowAgentSelection(false);
23843
24612
  }, [agents, settings.affiliateSlug]);
23844
- return (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: settings.travellers, countries: countries, agents: agents, bookingType: bookingType, agentAdressId: agentAdressId, travelersFirstStep: travelersFirstStep, isUnavailable: isUnavailable, useCompactForm: useCompactForm, showAllCountries: showAllCountries, showAgentSelection: showAgentSelection, initialShowAgents: settings.agentRequired ?? false, onBookingTypeChange: (nextBookingType) => dispatch(setBookingType(nextBookingType)), renderPreviousButton: () => !travelersFirstStep && settings.skipRouter ? (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => dispatch(setCurrentStep$1(OPTIONS_FORM_STEP)), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : !travelersFirstStep ? (React__default.createElement(Link, { to: `${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.options.pathSuffix}?${bookingQueryString}`, title: translations.STEPS.PREVIOUS, className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : null }));
24613
+ return (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: settings.travellers, countries: countries, agents: agents, bookingType: bookingType, agentAdressId: agentAdressId, travelersFirstStep: travelersFirstStep, isUnavailable: isUnavailable, useCompactForm: useCompactForm, showAllCountries: showAllCountries, paxFields: paxFields, showAgentSelection: showAgentSelection, initialShowAgents: settings.agentRequired ?? false, onBookingTypeChange: (nextBookingType) => dispatch(setBookingType(nextBookingType)), renderPreviousButton: () => !travelersFirstStep && settings.skipRouter ? (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => dispatch(setCurrentStep$1(OPTIONS_FORM_STEP)), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : !travelersFirstStep ? (React__default.createElement(Link, { to: `${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.options.pathSuffix}?${bookingQueryString}`, title: translations.STEPS.PREVIOUS, className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) : null }));
23845
24614
  };
23846
24615
 
23847
24616
  const Booking = ({ productCode, productName, thumbnailUrl }) => {
@@ -27913,7 +28682,12 @@ const mapPackagingPaxToBookingPax = (pax, fallbackId, referenceDate) => ({
27913
28682
  dateOfBirth: pax?.dateOfBirth ?? undefined,
27914
28683
  age: pax?.dateOfBirth ? getAgeAtReferenceDate(pax.dateOfBirth, referenceDate) : undefined,
27915
28684
  isMainBooker: pax?.isMainBooker,
27916
- email: ''
28685
+ email: '',
28686
+ weight: null,
28687
+ weightType: build.WeightType.kilograms,
28688
+ height: null,
28689
+ heightType: build.HeightType.centimeters,
28690
+ customFields: []
27917
28691
  });
27918
28692
  const getRequestRoomsFromPackagingEntry = (entry) => {
27919
28693
  const accommodationLines = (entry.lines ?? []).filter((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE && line.pax?.length > 0);
@@ -27983,6 +28757,22 @@ const getPackagingRequestRoomsFromBookingRooms = (rooms) => {
27983
28757
  });
27984
28758
  };
27985
28759
 
28760
+ // Administrative service lines (fees, insurances, reductions, ...) live on the entry but say
28761
+ // nothing about the journey itself, so the itinerary never draws them.
28762
+ const HIDDEN_ITINERARY_SERVICE_TYPES = new Set([
28763
+ build.ServiceType.insurance,
28764
+ build.ServiceType.extraService,
28765
+ build.ServiceType.serviceFee,
28766
+ build.ServiceType.gift,
28767
+ build.ServiceType.reduction,
28768
+ build.ServiceType.fee,
28769
+ build.ServiceType.visum,
28770
+ build.ServiceType.voucher,
28771
+ build.ServiceType.specialServices
28772
+ ]);
28773
+ const isMeaningfulItineraryLine = (line) => {
28774
+ return !HIDDEN_ITINERARY_SERVICE_TYPES.has(line.serviceType ?? -1);
28775
+ };
27986
28776
  const getFlightLines = (flight) => {
27987
28777
  return flight?.flightInformation?.flightLines ?? [];
27988
28778
  };
@@ -28437,6 +29227,8 @@ const applyResultToLine = (line, result, roomIndex = 0) => {
28437
29227
  isChanged: true
28438
29228
  };
28439
29229
  };
29230
+ const buildNodeSelectionLines = (item, result, bookedMode) => bookedMode && matchesCode(result, item.node.code ?? '') ? item.lines : applyResultToLines(item.lines, result);
29231
+ const buildFlightSelectionLine = (item, flight, bookedMode) => bookedMode && flight.outwardGuid === item.line.guid ? item.line : applyFlightToLine(item.line, flight);
28440
29232
  const toDateOnlyUtcString = (value) => {
28441
29233
  const date = new Date(value);
28442
29234
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
@@ -28494,11 +29286,21 @@ const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
28494
29286
  * mapper gave them. This swaps in the guid of whatever each line resolved onto, leaving the
28495
29287
  * lines the traveller added themselves alone — those were built from a search result and already
28496
29288
  * carry the right one.
29289
+ *
29290
+ * A booked entry (the traject was rebuilt from a magic-link entry) is the other way around: its
29291
+ * lines live in the dossier under their own guids, and only a line the traveller actually swapped
29292
+ * (isChanged) exists in the search cache. Swapping an untouched line's guid would orphan it —
29293
+ * the backend drops the dossier line and finds nothing to add — so those keep theirs.
28497
29294
  */
28498
29295
  const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightAvailability) => {
28499
29296
  const cachedGuids = new Map();
29297
+ const bookedMode = !!trajectEntry.entry.magicLink;
29298
+ const editableByGuid = new Map((entry.lines ?? []).map((line) => [line.guid, line]));
29299
+ const keepsOwnGuid = (guid) => bookedMode && !editableByGuid.get(guid)?.isChanged;
28500
29300
  getTrajectNodesWithLines(trajectEntry).forEach((item) => {
28501
29301
  if (isTrajectFlightNode(item.node)) {
29302
+ if (keepsOwnGuid(item.line.guid))
29303
+ return;
28502
29304
  // A flight search caches the outward line under the guid it reports as outwardGuid.
28503
29305
  const guid = flightAvailability[item.line.guid]?.selectedGuid;
28504
29306
  if (guid)
@@ -28511,6 +29313,8 @@ const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightA
28511
29313
  return;
28512
29314
  // Room i took option i when the result was stamped on, so it takes option i here too.
28513
29315
  item.lines.forEach((line, index) => {
29316
+ if (keepsOwnGuid(line.guid))
29317
+ return;
28514
29318
  const guid = getOptionForRoom(result, index)?.guid;
28515
29319
  if (guid)
28516
29320
  cachedGuids.set(line.guid, guid);
@@ -28574,7 +29378,7 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
28574
29378
  return { node, lines };
28575
29379
  });
28576
29380
  const claimed = new Set(nodes.flatMap((item) => item.lines.map((line) => line.guid)));
28577
- const extras = (packagingEntry.lines ?? []).filter((line) => !claimed.has(line.guid));
29381
+ const extras = (packagingEntry.lines ?? []).filter((line) => !claimed.has(line.guid)).filter(isMeaningfulItineraryLine);
28578
29382
  if (!extras.length)
28579
29383
  return nodes;
28580
29384
  const dayOrderOf = (date) => trajectEntry.traject.days.find((day) => isSameDay(new Date(day.date), new Date(date)))?.order ??
@@ -28751,6 +29555,195 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
28751
29555
  })));
28752
29556
  };
28753
29557
 
29558
+ /**
29559
+ * A booked entry opened through its magic link knows nothing about the traject it may once have
29560
+ * been composed from — the dossier only keeps the lines. To give it the same day-by-day services
29561
+ * screen a traject gets, the traject structure is rebuilt from those lines: every booked service
29562
+ * becomes a node whose one "alternative" is the booked product itself, and the days span the trip.
29563
+ *
29564
+ * The synthesized response keeps the entry untouched (magic link included), which is also how the
29565
+ * rest of the component tells this mode apart from a real traject: see isBookedEntryTraject.
29566
+ */
29567
+ const isBookedEntryTraject = (trajectEntry) => !!trajectEntry?.entry?.magicLink;
29568
+ const NODE_SERVICE_TYPES = new Set([ACCOMMODATION_SERVICE_TYPE, EXCURSION_SERVICE_TYPE, FLIGHT_SERVICE_TYPE]);
29569
+ /**
29570
+ * A room or option line joins its parent's node; a flight line never does — an outward and its
29571
+ * return are separate legs of the trip even though the return points at the outward as parent.
29572
+ */
29573
+ const groupNodeLines = (lines) => {
29574
+ const groups = [];
29575
+ const groupByGuid = new Map();
29576
+ lines.forEach((line) => {
29577
+ const parentGroup = line.serviceType !== FLIGHT_SERVICE_TYPE && line.parentGuid ? groupByGuid.get(line.parentGuid) : undefined;
29578
+ if (parentGroup) {
29579
+ parentGroup.push(line);
29580
+ return;
29581
+ }
29582
+ const group = [line];
29583
+ groups.push(group);
29584
+ groupByGuid.set(line.guid, group);
29585
+ });
29586
+ return groups;
29587
+ };
29588
+ const buildBookedTrajectEntry = (entry) => {
29589
+ const lines = (entry.lines ?? []).filter((line) => NODE_SERVICE_TYPES.has(line.serviceType));
29590
+ const froms = lines.map((line) => new Date(line.from).getTime());
29591
+ const tos = lines.map((line) => new Date(line.to).getTime());
29592
+ const start = froms.length ? new Date(Math.min(...froms)) : new Date();
29593
+ const end = tos.length ? new Date(Math.max(...tos)) : start;
29594
+ const dayCount = Math.max(differenceInCalendarDays(end, start), 0) + 1;
29595
+ const days = Array.from({ length: dayCount }, (_, order) => ({
29596
+ order,
29597
+ name: '',
29598
+ date: toDateOnlyString(addDays(start, order))
29599
+ }));
29600
+ const nodes = groupNodeLines(lines).map((groupLines, index) => {
29601
+ const line = groupLines[0];
29602
+ const flightLines = line.flightInformation?.flightLines ?? [];
29603
+ return {
29604
+ lineGuid: line.guid,
29605
+ lineGuids: groupLines.map((x) => x.guid),
29606
+ nodeId: index + 1,
29607
+ dayOrder: Math.max(differenceInCalendarDays(new Date(line.from), start), 0),
29608
+ order: line.order,
29609
+ name: line.productName,
29610
+ serviceType: line.serviceType,
29611
+ trajectNodeType: REGULAR_TRAJECT_NODE_TYPE,
29612
+ requirementType: 0,
29613
+ contentSource: 0,
29614
+ code: line.productCode,
29615
+ preferredAccommodationCode: line.productCode,
29616
+ preferredAccommodationName: line.productName,
29617
+ alternatives: [],
29618
+ departureAirportCode: first(flightLines)?.departureAirportCode ?? null,
29619
+ arrivalAirportCode: last(flightLines)?.arrivalAirportCode ?? null,
29620
+ duration: 0,
29621
+ durationType: 0,
29622
+ from: line.from,
29623
+ to: line.to
29624
+ };
29625
+ });
29626
+ return {
29627
+ entry,
29628
+ traject: {
29629
+ id: 0,
29630
+ name: entry.dossierNumber ?? '',
29631
+ imageUrl: null,
29632
+ startDate: days[0]?.date ?? toDateOnlyString(start),
29633
+ endDate: last(days)?.date ?? toDateOnlyString(end),
29634
+ durationInDays: days.length,
29635
+ includeGroupHotelAlternatives: false,
29636
+ days
29637
+ },
29638
+ nodes
29639
+ };
29640
+ };
29641
+ /**
29642
+ * The card for a booked service when no search result carries it any more (sold out, delisted).
29643
+ * Rendered from the line, so the traveller still sees what they booked; price 0 makes the card
29644
+ * leave its price out — the paid price lives in the price details, not on the line.
29645
+ */
29646
+ const buildBookedNodeResult = (node, lines) => {
29647
+ const line = lines[0];
29648
+ return {
29649
+ code: line.productCode,
29650
+ name: line.productName,
29651
+ serviceType: line.serviceType,
29652
+ countryId: line.country?.id ?? null,
29653
+ countryName: line.country?.name ?? '',
29654
+ regionId: line.region?.id ?? null,
29655
+ regionName: line.region?.name ?? '',
29656
+ oordId: line.oord?.id ?? null,
29657
+ oordName: line.oord?.name ?? '',
29658
+ locationId: line.location?.id ?? null,
29659
+ locationName: line.location?.name ?? '',
29660
+ latitude: line.latitude ?? null,
29661
+ longitude: line.longitude ?? null,
29662
+ price: 0,
29663
+ averagePricePerPerson: 0,
29664
+ originalPrice: 0,
29665
+ originalAveragePricePerPerson: 0,
29666
+ currencyCode: 'EUR',
29667
+ fromDate: line.from,
29668
+ toDate: line.to,
29669
+ contents: '',
29670
+ rooms: lines.map((roomLine) => ({
29671
+ options: [
29672
+ {
29673
+ price: 0,
29674
+ originalPrice: 0,
29675
+ accommodationCode: roomLine.accommodationCode ?? '',
29676
+ accommodationName: roomLine.accommodationName ?? '',
29677
+ regimeCode: roomLine.regimeCode ?? '',
29678
+ regimeName: roomLine.regimeName ?? '',
29679
+ isSelected: true,
29680
+ guid: roomLine.guid,
29681
+ paxIds: (roomLine.pax ?? []).map((pax) => pax.paxId)
29682
+ }
29683
+ ]
29684
+ }))
29685
+ };
29686
+ };
29687
+ /**
29688
+ * The flight search API serializes these as ISO strings, whatever the type declaration says, and
29689
+ * the store must stay serializable — so the synthesized segments carry the same string form.
29690
+ */
29691
+ const toDateTime = (date, time) => `${toDateOnlyString(date)}T${time || '00:00:00'}`;
29692
+ /** The booked flight as a flight result, so the card that shows it is the card the search results use. */
29693
+ const buildBookedFlightResult = (line) => {
29694
+ const flightLines = line.flightInformation?.flightLines ?? [];
29695
+ const segments = flightLines.map((flightLine, index) => ({
29696
+ order: index,
29697
+ flightNumber: flightLine.flightNumber,
29698
+ operatingFlightNumber: flightLine.operatingFlightNumber ?? flightLine.flightNumber,
29699
+ marketingAirlineCode: flightLine.airlineCode,
29700
+ marketingAirlineName: flightLine.airlineDescription,
29701
+ operatingAirlineCode: flightLine.operatingAirlineCode ?? flightLine.airlineCode,
29702
+ operatingAirlineName: flightLine.operatingAirlineDescription ?? flightLine.airlineDescription,
29703
+ departureAirportCode: flightLine.departureAirportCode,
29704
+ departureAirportName: flightLine.departureAirportDescription,
29705
+ arrivalAirportCode: flightLine.arrivalAirportCode,
29706
+ arrivalAirportName: flightLine.arrivalAirportDescription,
29707
+ departureDateTime: toDateTime(flightLine.departureDate, flightLine.departureTime),
29708
+ arrivalDateTime: toDateTime(flightLine.arrivalDate, flightLine.arrivalTime),
29709
+ bookingClassCode: '',
29710
+ travelClass: 0,
29711
+ durationInTicks: flightLine.durationInTicks ?? 0
29712
+ }));
29713
+ const firstSegment = first(segments);
29714
+ const lastSegment = last(segments);
29715
+ // .NET ticks are 100ns, so a millisecond is 10 000 of them.
29716
+ const durationInTicks = firstSegment && lastSegment ? (new Date(lastSegment.arrivalDateTime).getTime() - new Date(firstSegment.departureDateTime).getTime()) * 10_000 : 0;
29717
+ return {
29718
+ code: line.productCode,
29719
+ name: line.productName,
29720
+ serviceType: line.serviceType,
29721
+ countryName: '',
29722
+ regionName: '',
29723
+ oordName: '',
29724
+ locationName: '',
29725
+ price: 0,
29726
+ averagePricePerPerson: 0,
29727
+ originalPrice: 0,
29728
+ originalAveragePricePerPerson: 0,
29729
+ currencyCode: 'EUR',
29730
+ fromDate: line.from,
29731
+ toDate: line.to,
29732
+ flightRouteId: line.guid,
29733
+ airlineCode: firstSegment?.marketingAirlineCode ?? '',
29734
+ airlineName: firstSegment?.marketingAirlineName ?? '',
29735
+ isLuggageIncluded: false,
29736
+ luggageInfo: '',
29737
+ outwardGuid: line.guid,
29738
+ outward: { code: line.productCode, fareType: 0, durationInTicks, segments },
29739
+ returnGuid: '',
29740
+ return: { code: '', fareType: 0, durationInTicks: 0, segments: [] },
29741
+ source: 0,
29742
+ provider: '',
29743
+ paxes: []
29744
+ };
29745
+ };
29746
+
28754
29747
  const getSegmentIcon = (segment) => {
28755
29748
  switch (segment.serviceType) {
28756
29749
  case 3:
@@ -28790,14 +29783,14 @@ const SERVICE_TYPE_PRIORITY = {
28790
29783
  const getServiceTypePriority = (serviceType) => {
28791
29784
  return SERVICE_TYPE_PRIORITY[serviceType ?? -1] ?? 2;
28792
29785
  };
28793
- const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation }) => {
29786
+ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation, onSaveEntry }) => {
28794
29787
  const context = useContext(SearchResultsConfigurationContext);
28795
29788
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
28796
29789
  const { editablePackagingEntry, priceDetails, trajectItineraryView } = useSelector((state) => state.searchResults);
28797
29790
  const dispatch = useDispatch();
28798
29791
  const packagingEntry = editablePackagingEntry ?? context?.packagingEntry;
28799
29792
  const sortedLines = useMemo(() => {
28800
- return [...(packagingEntry?.lines ?? [])].sort((a, b) => {
29793
+ return (packagingEntry?.lines ?? []).filter(isMeaningfulItineraryLine).sort((a, b) => {
28801
29794
  const dateA = getDateOnlyTime(a.from);
28802
29795
  const dateB = getDateOnlyTime(b.from);
28803
29796
  if (dateA !== dateB) {
@@ -28868,7 +29861,7 @@ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation })
28868
29861
  " ",
28869
29862
  translations.SRP.TOTAL,
28870
29863
  ")"))),
28871
- React__default.createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM),
29864
+ isBookedEntryTraject(context?.trajectEntry) ? (React__default.createElement("button", { className: "cta", onClick: onSaveEntry, disabled: !(packagingEntry?.lines ?? []).some((line) => line.isChanged) }, translations.SHARED.SAVE)) : (React__default.createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM)),
28872
29865
  !!context?.trajectEntry && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleTrajectView(!trajectItineraryView) }, trajectItineraryView ? translations.SRP.SHOW_SERVICES : translations.SRP.VIEW_FULL_ITINERARY))))),
28873
29866
  React__default.createElement("div", { className: "search__filter__itinerary" },
28874
29867
  React__default.createElement("p", null, translations.SRP.DAY_BY_DAY),
@@ -30925,7 +31918,7 @@ const selectSelectedCombinationFlight = createSelector([selectPackagingFlightRes
30925
31918
  return (packagingFlightResults.find((flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey && getFlightKey(flight.return.segments) === selectedReturnKey) ?? null);
30926
31919
  });
30927
31920
 
30928
- const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward, showSelectedState, currentSelectedPrice, price }) => {
31921
+ const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward, showSelectedState, currentSelectedPrice, price, selectLabel, selectedLabel }) => {
30929
31922
  const context = useContext(SearchResultsConfigurationContext);
30930
31923
  const language = context?.languageCode ?? 'en-GB';
30931
31924
  const translations = getTranslations(language);
@@ -30950,7 +31943,7 @@ const IndependentFlightOption = ({ item, onSelect, guid, selectedGuid, isOutward
30950
31943
  priceDifference > 0 ? '+' : '-',
30951
31944
  "\u00A0",
30952
31945
  formatPrice$3(Math.abs(priceDifference), 'EUR', context?.languageCode ?? 'en-GB'))))),
30953
- React__default.createElement("button", { type: "button", className: `cta ${selectedGuid === guid ? 'cta--selected' : 'cta--select'}`, onClick: () => onSelect?.() }, selectedGuid === guid ? 'Selected' : 'Select')))),
31946
+ React__default.createElement("button", { type: "button", className: `cta ${selectedGuid === guid ? 'cta--selected' : 'cta--select'}`, onClick: () => onSelect?.() }, selectedGuid === guid ? selectedLabel ?? translations.SHARED.SELECTED : selectLabel ?? translations.SHARED.SELECT)))),
30954
31947
  React__default.createElement("div", { className: "flight__flight" },
30955
31948
  React__default.createElement("div", { className: "flight__flight__container" },
30956
31949
  React__default.createElement("div", { className: "flight__flight__wrapper" },
@@ -31584,7 +32577,7 @@ const TrajectNodeCard = ({ node, result, isSelected, languageCode, translations,
31584
32577
  const image = candidate?.imageUrl ?? null;
31585
32578
  const description = toPlainText(candidate?.description);
31586
32579
  const title = candidate?.name ?? result.name;
31587
- const priceBlock = (React__default.createElement("div", { className: "search__result-card__price__wrapper" },
32580
+ const priceBlock = result.price > 0 && (React__default.createElement("div", { className: "search__result-card__price__wrapper" },
31588
32581
  React__default.createElement("span", { className: "search__result-card__price__label" }, translations?.SHARED.TOTAL_PRICE),
31589
32582
  React__default.createElement("span", { className: "search__result-card__price" }, price)));
31590
32583
  const canEditOptions = isSelected && !!onEditOptions && (result.rooms ?? []).some((room) => (room.options ?? []).length > 1);
@@ -31637,6 +32630,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
31637
32630
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
31638
32631
  const { trajectNodeAvailability, trajectEditLineGuid } = useSelector((state) => state.searchResults);
31639
32632
  const trajectEntry = context?.trajectEntry;
32633
+ const bookedMode = isBookedEntryTraject(trajectEntry);
31640
32634
  const item = useMemo(() => {
31641
32635
  if (!trajectEntry || !trajectEditLineGuid)
31642
32636
  return null;
@@ -31656,7 +32650,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
31656
32650
  if (!result)
31657
32651
  return;
31658
32652
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
31659
- applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
32653
+ buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
31660
32654
  dispatch(setTrajectEditLineGuid(null));
31661
32655
  dispatch(setFlyInIsOpen(false));
31662
32656
  };
@@ -31669,7 +32663,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
31669
32663
  ordered.length,
31670
32664
  "\u00A0",
31671
32665
  translations.SRP.TOTAL_RESULTS_LABEL)),
31672
- ordered.length === 0 ? (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default.createElement("div", { className: "search__results__cards" }, ordered.map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: item.node, result: result, isSelected: result.code === availability?.selectedCode, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(result.code), showNights: item.node.serviceType === ACCOMMODATION_SERVICE_TYPE })))))));
32666
+ ordered.length === 0 ? (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default.createElement("div", { className: "search__results__cards" }, ordered.map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: item.node, result: result, isSelected: result.code === availability?.selectedCode, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(result.code), showNights: item.node.serviceType === ACCOMMODATION_SERVICE_TYPE, selectedLabel: bookedMode && matchesCode(result, item.node.code ?? '') ? translations.SHARED.BOOKED : undefined })))))));
31673
32667
  };
31674
32668
 
31675
32669
  /**
@@ -31731,6 +32725,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
31731
32725
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
31732
32726
  const { trajectNodeAvailability, trajectDaySuggestions, trajectActivitiesDayOrder, editablePackagingEntry } = useSelector((state) => state.searchResults);
31733
32727
  const trajectEntry = context?.trajectEntry;
32728
+ const bookedMode = isBookedEntryTraject(trajectEntry);
31734
32729
  const items = useMemo(() => {
31735
32730
  if (!trajectEntry || trajectActivitiesDayOrder === null)
31736
32731
  return [];
@@ -31763,7 +32758,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
31763
32758
  if (!item)
31764
32759
  return;
31765
32760
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code: result.code }));
31766
- applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
32761
+ buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
31767
32762
  dispatch(setTrajectActivitiesDayOrder(null));
31768
32763
  dispatch(setFlyInIsOpen(false));
31769
32764
  };
@@ -31779,7 +32774,8 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
31779
32774
  cards.length === 0 ? (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default.createElement("div", { className: "search__results__cards" }, cards.map((card) => {
31780
32775
  const { result, item } = card;
31781
32776
  const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedLines(result).length > 0;
31782
- return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(card) : handleToggle(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? undefined : translations.SRP.REMOVE }));
32777
+ const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
32778
+ return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(card) : handleToggle(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
31783
32779
  })))));
31784
32780
  };
31785
32781
 
@@ -31855,7 +32851,7 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
31855
32851
  dispatch(setBookPackagingEntry(true));
31856
32852
  }
31857
32853
  };
31858
- return (React__default.createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' || flyInType === 'traject-day-activities' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
32854
+ return (React__default.createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' || flyInType === 'traject-day-activities' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
31859
32855
  ${flyInType === 'flight-outward-results' || flyInType === 'flight-return-results' || flyInType === 'traject-flight-results' ? 'flyin--flight' : ''}` },
31860
32856
  React__default.createElement("div", { className: `flyin__panel ${isOpen ? 'flyin__panel--active' : ''}`, ref: panelRef },
31861
32857
  React__default.createElement("div", { className: "flyin__content" },
@@ -33304,7 +34300,12 @@ const getRequestRoomsFromPackagingSegments = (entry, segments) => {
33304
34300
  dateOfBirth: paxSource?.dateOfBirth ?? undefined,
33305
34301
  age: paxSource?.dateOfBirth ? undefined : 30,
33306
34302
  isMainBooker: paxSource?.isMainBooker,
33307
- email: ''
34303
+ email: '',
34304
+ weight: null,
34305
+ weightType: build.WeightType.kilograms,
34306
+ height: null,
34307
+ heightType: build.HeightType.centimeters,
34308
+ customFields: []
33308
34309
  };
33309
34310
  if (!groupedByRoom.has(roomIndexWithinLine)) {
33310
34311
  groupedByRoom.set(roomIndexWithinLine, []);
@@ -33384,6 +34385,10 @@ const getUniqueItems = (items = []) => {
33384
34385
  return true;
33385
34386
  });
33386
34387
  };
34388
+ const isMeaningfulItem = (item, lines) => {
34389
+ const line = lines.find((l) => l.guid === item.itemGuid);
34390
+ return !line || isMeaningfulItineraryLine(line);
34391
+ };
33387
34392
  const findAccommodationForDay = (nodes, currentDay) => {
33388
34393
  for (const node of nodes ?? []) {
33389
34394
  const { startDay } = getNodeDayRange(node);
@@ -33443,20 +34448,20 @@ const buildFlightHtml = (line) => {
33443
34448
  */
33444
34449
  const buildFallbackHtml = (item, line) => {
33445
34450
  const details = [line?.accommodationName, line?.regimeName].filter(Boolean).join(' — ');
33446
- return `
33447
- <div class="itinerary-item__fallback">
33448
- <h3 class="itinerary-item__fallback-title">${escapeHtml(item.title)}</h3>
33449
- ${line ? buildFlightHtml(line) : ''}
33450
- ${details ? `<p class="itinerary-item__fallback-details">${escapeHtml(details)}</p>` : ''}
33451
- </div>
34451
+ return `
34452
+ <div class="itinerary-item__fallback">
34453
+ <h3 class="itinerary-item__fallback-title">${escapeHtml(item.title)}</h3>
34454
+ ${line ? buildFlightHtml(line) : ''}
34455
+ ${details ? `<p class="itinerary-item__fallback-details">${escapeHtml(details)}</p>` : ''}
34456
+ </div>
33452
34457
  `;
33453
34458
  };
33454
34459
  const buildItineraryHtml = (itinerary, translations, lines) => {
33455
34460
  if (!itinerary) {
33456
- return `
33457
- <div class="itinerary-shell">
33458
- <div class="itinerary-empty">Geen reisroute beschikbaar.</div>
33459
- </div>
34461
+ return `
34462
+ <div class="itinerary-shell">
34463
+ <div class="itinerary-empty">Geen reisroute beschikbaar.</div>
34464
+ </div>
33460
34465
  `;
33461
34466
  }
33462
34467
  const allNodes = itinerary.nodes ?? [];
@@ -33465,75 +34470,76 @@ const buildItineraryHtml = (itinerary, translations, lines) => {
33465
34470
  const { startDay } = getNodeDayRange(node);
33466
34471
  const day = node.startDate ? format$2(node.startDate, 'd') : null;
33467
34472
  const month = node.startDate ? format$2(node.startDate, 'MMM') : null;
33468
- const uniqueItems = getUniqueItems(node.items ?? []);
34473
+ const uniqueItems = getUniqueItems(node.items ?? []).filter((item) => isMeaningfulItem(item, lines));
33469
34474
  const hasItems = uniqueItems.length > 0;
33470
34475
  const hasAccommodationInCurrentNode = uniqueItems.some(isAccommodationItem);
33471
34476
  const activeAccommodation = findAccommodationForDay(allNodes, startDay);
33472
34477
  const accommodationBanner = !hasAccommodationInCurrentNode && activeAccommodation
33473
- ? `
33474
- <div class="itinerary-node__accommodation-banner">
33475
- Accommodatie voor deze dag: <strong>${escapeHtml(getAccommodationName(activeAccommodation))}</strong>
33476
- </div>
34478
+ ? `
34479
+ <div class="itinerary-node__accommodation-banner">
34480
+ Accommodatie voor deze dag: <strong>${escapeHtml(getAccommodationName(activeAccommodation))}</strong>
34481
+ </div>
33477
34482
  `
33478
34483
  : '';
33479
34484
  const itemsHtml = hasItems
33480
34485
  ? uniqueItems
33481
- .map((item) => `
33482
- <article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
34486
+ .map((item) => `
34487
+ <article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
33483
34488
  ${hasVisibleContent(item.contents)
33484
34489
  ? item.contents
33485
- : buildFallbackHtml(item, lines.find((line) => line.guid === item.itemGuid))}
33486
- </article>
34490
+ : buildFallbackHtml(item, lines.find((line) => line.guid === item.itemGuid))}
34491
+ </article>
33487
34492
  `)
33488
34493
  .join('')
33489
34494
  : `<div class="itinerary-node__empty">${translations.ITINERARY.NO_ITEMS}</div>`;
33490
- return `
33491
- <section class="itinerary-node">
33492
- <header class="itinerary-node__header">
33493
-
33494
- <div class="itinerary-node__day">
33495
- <p class="itinerary-node__day-day">${day}</p>
33496
- <p class="itinerary-node__day-month">${month}</p>
33497
- </div>
33498
-
33499
- <div>
33500
- <h2 class="itinerary-node__title">${escapeHtml(node.title)}</h2>
33501
- </div>
33502
- </header>
33503
-
33504
- <div class="itinerary-node__content">
33505
- ${accommodationBanner}
33506
- ${itemsHtml}
33507
- </div>
33508
- </section>
34495
+ return `
34496
+ <section class="itinerary-node">
34497
+ <header class="itinerary-node__header">
34498
+
34499
+ <div class="itinerary-node__day">
34500
+ <p class="itinerary-node__day-day">${day}</p>
34501
+ <p class="itinerary-node__day-month">${month}</p>
34502
+ </div>
34503
+
34504
+ <div>
34505
+ <h2 class="itinerary-node__title">${escapeHtml(node.title)}</h2>
34506
+ </div>
34507
+ </header>
34508
+
34509
+ <div class="itinerary-node__content">
34510
+ ${accommodationBanner}
34511
+ ${itemsHtml}
34512
+ </div>
34513
+ </section>
33509
34514
  `;
33510
34515
  })
33511
34516
  .join('');
33512
- const defaultItemsHtml = itinerary.defaultItems && itinerary.defaultItems.length > 0
33513
- ? `
33514
- <section class="itinerary-default-items">
33515
- <h2 class="itinerary-default-items__title">Algemene info</h2>
33516
- ${getUniqueItems(itinerary.defaultItems)
33517
- .map((item) => `
33518
- <article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
34517
+ const defaultItems = getUniqueItems(itinerary.defaultItems ?? []).filter((item) => isMeaningfulItem(item, lines));
34518
+ const defaultItemsHtml = defaultItems.length > 0
34519
+ ? `
34520
+ <section class="itinerary-default-items">
34521
+ <h2 class="itinerary-default-items__title">Algemene info</h2>
34522
+ ${defaultItems
34523
+ .map((item) => `
34524
+ <article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
33519
34525
  ${hasVisibleContent(item.contents)
33520
34526
  ? item.contents
33521
- : buildFallbackHtml(item, lines.find((line) => line.guid === item.itemGuid))}
33522
- </article>
34527
+ : buildFallbackHtml(item, lines.find((line) => line.guid === item.itemGuid))}
34528
+ </article>
33523
34529
  `)
33524
- .join('')}
33525
- </section>
34530
+ .join('')}
34531
+ </section>
33526
34532
  `
33527
34533
  : '';
33528
- return `
33529
- <div class="itinerary-shell">
33530
- ${itinerary.title ? `<header class="itinerary-shell__header"><h1 class="itinerary-shell__title">${escapeHtml(itinerary.title)}</h1></header>` : ''}
33531
-
33532
- <div class="itinerary-shell__content">
33533
- ${nodesHtml}
33534
- ${defaultItemsHtml}
33535
- </div>
33536
- </div>
34534
+ return `
34535
+ <div class="itinerary-shell">
34536
+ ${itinerary.title ? `<header class="itinerary-shell__header"><h1 class="itinerary-shell__title">${escapeHtml(itinerary.title)}</h1></header>` : ''}
34537
+
34538
+ <div class="itinerary-shell__content">
34539
+ ${nodesHtml}
34540
+ ${defaultItemsHtml}
34541
+ </div>
34542
+ </div>
33537
34543
  `;
33538
34544
  };
33539
34545
  const FullItinerary = ({ isLoading }) => {
@@ -33555,170 +34561,170 @@ const FullItinerary = ({ isLoading }) => {
33555
34561
  }
33556
34562
  const shadowRoot = host.shadowRoot ?? host.attachShadow({ mode: 'open' });
33557
34563
  shadowRootRef.current = shadowRoot;
33558
- shadowRoot.innerHTML = `
33559
- <style>
33560
- :host {
33561
- all: initial;
33562
- display: block;
33563
- width: 100%;
33564
- }
33565
-
33566
- *,
33567
- *::before,
33568
- *::after {
33569
- box-sizing: border-box;
33570
- }
33571
-
33572
- .itinerary-shell {
33573
- width: 100%;
33574
- margin: 0 auto;
33575
- font-family: 'Outfit', sans-serif;
33576
- color: #222;
33577
- }
33578
-
33579
- .itinerary-shell__header {
33580
- margin-bottom: 24px;
33581
- }
33582
-
33583
- .itinerary-shell__title {
33584
- margin: 0;
33585
- font-size: 32px;
33586
- line-height: 1.2;
33587
- }
33588
-
33589
- .itinerary-shell__content {
33590
- display: grid;
33591
- gap: 24px;
33592
- }
33593
-
33594
- .itinerary-node {
33595
- border: 1px solid #e5e7eb;
33596
- border-radius: 16px;
33597
- overflow: hidden;
33598
- background: #fff;
33599
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
33600
- }
33601
-
33602
- .itinerary-node__header {
33603
- display: flex;
33604
- gap: 16px;
33605
- align-items: center;
33606
- border-bottom: 1px solid #eef0f2;
33607
- background: #fafafa;
33608
- }
33609
-
33610
- .itinerary-node__day {
33611
- flex: 50px 0 0;
33612
- display: flex;
33613
- flex-flow: column;
33614
- align-items: center;
33615
- justify-content: center;
33616
- background: #1f9470;
33617
- color: white;
33618
- border: 1.5px solid var(--tide-booking-color-secondary);
33619
- }
33620
-
33621
- .itinerary-node__day-month {
33622
- margin: 0px;
33623
- }
33624
-
33625
- .itinerary-node__day-day {
33626
- margin: 0px;
33627
- font-weight: var(--tide-booking-search-results-label-date-month-font-weight);
33628
- color: var(--tide-booking-search-results-label-date-month-color);
33629
- font-size: 24px;
33630
- }
33631
-
33632
- .itinerary-node__title {
33633
- margin: 0;
33634
- font-size: 22px;
33635
- line-height: 1.25;
33636
- }
33637
-
33638
- .itinerary-node__content {
33639
- display: grid;
33640
- gap: 20px;
33641
- padding: 20px;
33642
- }
33643
-
33644
- .itinerary-node__accommodation-banner {
33645
- padding: 12px 16px;
33646
- border: 1px solid #dbeafe;
33647
- border-radius: 12px;
33648
- background: #eff6ff;
33649
- color: #1e3a8a;
33650
- font-size: 14px;
33651
- line-height: 1.4;
33652
- }
33653
-
33654
- .itinerary-item {
33655
- display: block;
33656
- border-radius: 12px;
33657
- overflow: hidden;
33658
- background: #fff;
33659
- }
33660
-
33661
- /* An item whose template has no content view of its own still has to read as a service. */
33662
- .itinerary-item__fallback {
33663
- padding: 16px 20px;
33664
- border: 1px solid #e5e7eb;
33665
- border-radius: 12px;
33666
- }
33667
-
33668
- .itinerary-item__fallback-title {
33669
- margin: 0;
33670
- font-size: 16px;
33671
- font-weight: 600;
33672
- color: #111827;
33673
- }
33674
-
33675
- .itinerary-item__legs {
33676
- margin: 8px 0 0;
33677
- padding-left: 18px;
33678
- color: #374151;
33679
- }
33680
-
33681
- .itinerary-item__legs li + li {
33682
- margin-top: 4px;
33683
- }
33684
-
33685
- .itinerary-item__fallback-details {
33686
- margin: 8px 0 0;
33687
- color: #6b7280;
33688
- }
33689
-
33690
- .itinerary-node__empty,
33691
- .itinerary-empty {
33692
- padding: 20px;
33693
- border: 1px dashed #d1d5db;
33694
- border-radius: 12px;
33695
- color: #6b7280;
33696
- background: #fafafa;
33697
- }
33698
-
33699
- .itinerary-default-items {
33700
- border: 1px solid #e5e7eb;
33701
- border-radius: 16px;
33702
- padding: 20px;
33703
- background: #fff;
33704
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
33705
- }
33706
-
33707
- .itinerary-default-items__title {
33708
- margin: 0 0 16px;
33709
- font-size: 22px;
33710
- }
33711
-
33712
- @media (max-width: 768px) {
33713
- .itinerary-shell {
33714
- padding: 16px;
33715
- }
33716
- }
33717
-
33718
- ${itinerary?.styleSheetBody ?? ''}
33719
- </style>
33720
-
33721
- ${html}
34564
+ shadowRoot.innerHTML = `
34565
+ <style>
34566
+ :host {
34567
+ all: initial;
34568
+ display: block;
34569
+ width: 100%;
34570
+ }
34571
+
34572
+ *,
34573
+ *::before,
34574
+ *::after {
34575
+ box-sizing: border-box;
34576
+ }
34577
+
34578
+ .itinerary-shell {
34579
+ width: 100%;
34580
+ margin: 0 auto;
34581
+ font-family: 'Outfit', sans-serif;
34582
+ color: #222;
34583
+ }
34584
+
34585
+ .itinerary-shell__header {
34586
+ margin-bottom: 24px;
34587
+ }
34588
+
34589
+ .itinerary-shell__title {
34590
+ margin: 0;
34591
+ font-size: 32px;
34592
+ line-height: 1.2;
34593
+ }
34594
+
34595
+ .itinerary-shell__content {
34596
+ display: grid;
34597
+ gap: 24px;
34598
+ }
34599
+
34600
+ .itinerary-node {
34601
+ border: 1px solid #e5e7eb;
34602
+ border-radius: 16px;
34603
+ overflow: hidden;
34604
+ background: #fff;
34605
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
34606
+ }
34607
+
34608
+ .itinerary-node__header {
34609
+ display: flex;
34610
+ gap: 16px;
34611
+ align-items: center;
34612
+ border-bottom: 1px solid #eef0f2;
34613
+ background: #fafafa;
34614
+ }
34615
+
34616
+ .itinerary-node__day {
34617
+ flex: 50px 0 0;
34618
+ display: flex;
34619
+ flex-flow: column;
34620
+ align-items: center;
34621
+ justify-content: center;
34622
+ background: #1f9470;
34623
+ color: white;
34624
+ border: 1.5px solid var(--tide-booking-color-secondary);
34625
+ }
34626
+
34627
+ .itinerary-node__day-month {
34628
+ margin: 0px;
34629
+ }
34630
+
34631
+ .itinerary-node__day-day {
34632
+ margin: 0px;
34633
+ font-weight: var(--tide-booking-search-results-label-date-month-font-weight);
34634
+ color: var(--tide-booking-search-results-label-date-month-color);
34635
+ font-size: 24px;
34636
+ }
34637
+
34638
+ .itinerary-node__title {
34639
+ margin: 0;
34640
+ font-size: 22px;
34641
+ line-height: 1.25;
34642
+ }
34643
+
34644
+ .itinerary-node__content {
34645
+ display: grid;
34646
+ gap: 20px;
34647
+ padding: 20px;
34648
+ }
34649
+
34650
+ .itinerary-node__accommodation-banner {
34651
+ padding: 12px 16px;
34652
+ border: 1px solid #dbeafe;
34653
+ border-radius: 12px;
34654
+ background: #eff6ff;
34655
+ color: #1e3a8a;
34656
+ font-size: 14px;
34657
+ line-height: 1.4;
34658
+ }
34659
+
34660
+ .itinerary-item {
34661
+ display: block;
34662
+ border-radius: 12px;
34663
+ overflow: hidden;
34664
+ background: #fff;
34665
+ }
34666
+
34667
+ /* An item whose template has no content view of its own still has to read as a service. */
34668
+ .itinerary-item__fallback {
34669
+ padding: 16px 20px;
34670
+ border: 1px solid #e5e7eb;
34671
+ border-radius: 12px;
34672
+ }
34673
+
34674
+ .itinerary-item__fallback-title {
34675
+ margin: 0;
34676
+ font-size: 16px;
34677
+ font-weight: 600;
34678
+ color: #111827;
34679
+ }
34680
+
34681
+ .itinerary-item__legs {
34682
+ margin: 8px 0 0;
34683
+ padding-left: 18px;
34684
+ color: #374151;
34685
+ }
34686
+
34687
+ .itinerary-item__legs li + li {
34688
+ margin-top: 4px;
34689
+ }
34690
+
34691
+ .itinerary-item__fallback-details {
34692
+ margin: 8px 0 0;
34693
+ color: #6b7280;
34694
+ }
34695
+
34696
+ .itinerary-node__empty,
34697
+ .itinerary-empty {
34698
+ padding: 20px;
34699
+ border: 1px dashed #d1d5db;
34700
+ border-radius: 12px;
34701
+ color: #6b7280;
34702
+ background: #fafafa;
34703
+ }
34704
+
34705
+ .itinerary-default-items {
34706
+ border: 1px solid #e5e7eb;
34707
+ border-radius: 16px;
34708
+ padding: 20px;
34709
+ background: #fff;
34710
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
34711
+ }
34712
+
34713
+ .itinerary-default-items__title {
34714
+ margin: 0 0 16px;
34715
+ font-size: 22px;
34716
+ }
34717
+
34718
+ @media (max-width: 768px) {
34719
+ .itinerary-shell {
34720
+ padding: 16px;
34721
+ }
34722
+ }
34723
+
34724
+ ${itinerary?.styleSheetBody ?? ''}
34725
+ </style>
34726
+
34727
+ ${html}
33722
34728
  `;
33723
34729
  }, [html, itinerary?.styleSheetBody, isLoading]);
33724
34730
  return (React__default.createElement(React__default.Fragment, null,
@@ -34172,7 +35178,7 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
34172
35178
  const formik = useFormik({
34173
35179
  initialValues,
34174
35180
  enableReinitialize: true,
34175
- validate: (values) => validateForm$1(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields),
35181
+ validate: (values) => validateForm$1(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields, undefined, undefined, editablePackagingEntry?.paxFields ?? []),
34176
35182
  onSubmit: (values) => {
34177
35183
  if (!editablePackagingEntry)
34178
35184
  return;
@@ -34257,7 +35263,7 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
34257
35263
  ".\u00A0",
34258
35264
  stepLabels[step])) },
34259
35265
  isConfirmationPage && isLoading && React__default.createElement(Spinner, { label: translations.SUMMARY.PROCESS_BOOKING }),
34260
- currentStep === 0 && (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false })),
35266
+ currentStep === 0 && (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false, paxFields: editablePackagingEntry?.paxFields ?? [] })),
34261
35267
  currentStep === 1 && (React__default.createElement(SharedSummary, { translations: translations, travelerFormValues: formik.values, isSubmitting: isSubmitting, skipPayment: !context.generatePaymentUrl, userValidated: userValidated, remarks: remarks, enableVoucher: false, allowOption: false, isOffer: false, onUserValidatedChange: setUserValidated, onRemarksChange: setRemarks, onSubmit: handleSummarySubmit, renderOptions: () => renderEditablePackagingEntrySummaryOptions(editablePackagingEntry, priceDetails, translations, selectedPackagingAccoResult?.currencyCode), renderPreviousButton: () => (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => dispatch(setCurrentStep(0)), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) })),
34262
35268
  currentStep === 2 && (React__default.createElement(SharedConfirmation, { bookingNumber: bookingNumber ?? editablePackagingEntry?.dossierNumber ?? '', isOption: false, isOffer: false, translations: translations.CONFIRMATION })),
34263
35269
  currentStep === 3 && React__default.createElement("div", null))),
@@ -34321,6 +35327,7 @@ const TrajectResults = ({ isLoading }) => {
34321
35327
  const locale = getLocale(context?.languageCode ?? 'en-GB');
34322
35328
  const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry } = useSelector((state) => state.searchResults);
34323
35329
  const trajectEntry = context?.trajectEntry;
35330
+ const bookedMode = isBookedEntryTraject(trajectEntry);
34324
35331
  const hideShowMoreResults = !!context?.hideShowMoreResults;
34325
35332
  const loadDayActivitiesOnDemand = !!context?.loadDayActivitiesOnDemand;
34326
35333
  const showNonPreferredHotels = !!context?.showNonPreferredHotels;
@@ -34377,7 +35384,7 @@ const TrajectResults = ({ isLoading }) => {
34377
35384
  if (!result)
34378
35385
  return;
34379
35386
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
34380
- applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
35387
+ buildNodeSelectionLines(item, result, bookedMode).forEach((line) => dispatch(updateEditableEntryLine(line)));
34381
35388
  };
34382
35389
  /** The remaining legs for a flight node open in the fly-in, as the regular flight results do. */
34383
35390
  const handleShowMoreFlights = (item) => {
@@ -34465,7 +35472,7 @@ const TrajectResults = ({ isLoading }) => {
34465
35472
  node.preferredAccommodationName,
34466
35473
  " \u2014 ",
34467
35474
  translations.SRP.NO_RESULTS))),
34468
- React__default.createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured, ...fill].map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE })))),
35475
+ React__default.createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured, ...fill].map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE, selectedLabel: bookedMode && matchesCode(result, node.code ?? '') ? translations.SHARED.BOOKED : undefined })))),
34469
35476
  remaining > 0 && !hideShowMoreResults && (React__default.createElement("div", { className: "search__results__cards__actions" },
34470
35477
  React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
34471
35478
  translations.SRP.SHOW_MORE,
@@ -34475,7 +35482,7 @@ const TrajectResults = ({ isLoading }) => {
34475
35482
  };
34476
35483
  const handleSelectFlight = (item, flight) => {
34477
35484
  dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
34478
- dispatch(updateEditableEntryLine(applyFlightToLine(item.line, flight)));
35485
+ dispatch(updateEditableEntryLine(buildFlightSelectionLine(item, flight, bookedMode)));
34479
35486
  };
34480
35487
  const renderFlightNode = (item) => {
34481
35488
  const { node, line } = item;
@@ -34501,7 +35508,7 @@ const TrajectResults = ({ isLoading }) => {
34501
35508
  status === 'unavailable' && React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
34502
35509
  status === 'resolved' && selected && (React__default.createElement(React__default.Fragment, null,
34503
35510
  React__default.createElement("div", { className: "search__results__cards search__results__cards--extended" },
34504
- React__default.createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price }),
35511
+ React__default.createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price, selectedLabel: bookedMode && selected.outwardGuid === line.guid ? translations.SHARED.BOOKED : undefined }),
34505
35512
  visible.map((result) => (React__default.createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected.price, onSelect: () => handleSelectFlight(item, result) })))),
34506
35513
  others.length > 2 && !hideShowMoreResults && (React__default.createElement("div", { className: "search__results__cards__actions" },
34507
35514
  React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreFlights(item) },
@@ -34585,7 +35592,8 @@ const TrajectResults = ({ isLoading }) => {
34585
35592
  */
34586
35593
  const renderActivityCard = ({ result, item }) => {
34587
35594
  const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedExcursionLines(result).length > 0;
34588
- return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(item, result.code) : handleToggleActivity(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? undefined : translations.SRP.REMOVE }));
35595
+ const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
35596
+ return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(item, result.code) : handleToggleActivity(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
34589
35597
  };
34590
35598
  if (isLoading)
34591
35599
  return React__default.createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
@@ -34629,6 +35637,7 @@ const useTrajectAvailability = () => {
34629
35637
  const controller = new AbortController();
34630
35638
  dispatch(resetTrajectAvailability());
34631
35639
  dispatch(setTrajectResolving(true));
35640
+ const bookedMode = isBookedEntryTraject(trajectEntry);
34632
35641
  const config = {
34633
35642
  host: context.tideConnection.host,
34634
35643
  apiKey: context.tideConnection.apiKey
@@ -34690,6 +35699,17 @@ const useTrajectAvailability = () => {
34690
35699
  });
34691
35700
  const configuredCodes = new Set(configuredResults.map((x) => x.code));
34692
35701
  const destinationResults = areaResults.filter((x) => !configuredCodes.has(x.code));
35702
+ if (bookedMode) {
35703
+ const results = [...configuredResults, ...destinationResults];
35704
+ let booked = results.find((x) => matchesCode(x, item.node.code ?? '')) ?? null;
35705
+ // Not searchable any more (sold out, delisted) — drawn from the line instead.
35706
+ if (!booked) {
35707
+ booked = buildBookedNodeResult(item.node, item.lines);
35708
+ results.unshift(booked);
35709
+ }
35710
+ dispatch(setTrajectNodeAvailability({ lineGuid, results, selectedCode: booked.code, preferredUnavailable: false }));
35711
+ return [];
35712
+ }
34693
35713
  const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
34694
35714
  const preferredUnavailable = configuredResults.length
34695
35715
  ? !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code))
@@ -34712,6 +35732,11 @@ const useTrajectAvailability = () => {
34712
35732
  if (controller.signal.aborted)
34713
35733
  return [];
34714
35734
  console.error('Failed to resolve traject node availability', item.node.name, error);
35735
+ if (bookedMode) {
35736
+ const booked = buildBookedNodeResult(item.node, item.lines);
35737
+ dispatch(setTrajectNodeAvailability({ lineGuid, results: [booked], selectedCode: booked.code, preferredUnavailable: false }));
35738
+ return [];
35739
+ }
34715
35740
  dispatch(setTrajectNodeAvailability({ lineGuid, results: [], selectedCode: null, preferredUnavailable: false }));
34716
35741
  return item.lines.map((x) => x.guid);
34717
35742
  }
@@ -34719,6 +35744,11 @@ const useTrajectAvailability = () => {
34719
35744
  const resolveFlightNode = async (item) => {
34720
35745
  const lineGuid = item.line.guid;
34721
35746
  if (!item.node.departureAirportCode || !item.node.arrivalAirportCode) {
35747
+ if (bookedMode) {
35748
+ const booked = buildBookedFlightResult(item.line);
35749
+ dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked], selectedGuid: booked.outwardGuid }));
35750
+ return [];
35751
+ }
34722
35752
  dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
34723
35753
  return item.lines.map((x) => x.guid);
34724
35754
  }
@@ -34727,6 +35757,11 @@ const useTrajectAvailability = () => {
34727
35757
  const flights = (await build.searchPackagingFlights(config, buildTrajectFlightRequest(item, searchContext, flightPax), controller.signal)) ?? [];
34728
35758
  if (controller.signal.aborted)
34729
35759
  return [];
35760
+ if (bookedMode) {
35761
+ const booked = buildBookedFlightResult(item.line);
35762
+ dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked, ...flights], selectedGuid: booked.outwardGuid }));
35763
+ return [];
35764
+ }
34730
35765
  const picked = pickCheapestFlight(flights);
34731
35766
  dispatch(setTrajectFlightAvailability({ lineGuid, results: flights, selectedGuid: picked?.outwardGuid ?? null }));
34732
35767
  if (!picked)
@@ -34738,6 +35773,11 @@ const useTrajectAvailability = () => {
34738
35773
  if (controller.signal.aborted)
34739
35774
  return [];
34740
35775
  console.error('Failed to resolve traject flight', item.node.name, error);
35776
+ if (bookedMode) {
35777
+ const booked = buildBookedFlightResult(item.line);
35778
+ dispatch(setTrajectFlightAvailability({ lineGuid, results: [booked], selectedGuid: booked.outwardGuid }));
35779
+ return [];
35780
+ }
34741
35781
  dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
34742
35782
  return item.lines.map((x) => x.guid);
34743
35783
  }
@@ -34775,6 +35815,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
34775
35815
  const [detailsIsLoading, setDetailsIsLoading] = useState(false);
34776
35816
  const [pricesAreLoading, setPricesAreLoading] = useState(false);
34777
35817
  const [itineraryIsLoading, setItineraryIsLoading] = useState(false);
35818
+ const [entrySaving, setEntrySaving] = useState(false);
34778
35819
  const [itineraryOpen, setItineraryOpen] = useState(false);
34779
35820
  const [isBookingConfirmation, setIsBookingConfirmation] = useState(false);
34780
35821
  const [selectedAccommodationSeed, setSelectedAccommodationSeed] = useState(null);
@@ -35531,6 +36572,31 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35531
36572
  useEffect(() => {
35532
36573
  setInitialFiltersSet(false);
35533
36574
  }, [activeSearchSeed]);
36575
+ const handleSaveEntry = async () => {
36576
+ if (!context || !bookableEntry || entrySaving)
36577
+ return;
36578
+ setEntrySaving(true);
36579
+ try {
36580
+ const config = {
36581
+ host: context.tideConnection.host,
36582
+ apiKey: context.tideConnection.apiKey
36583
+ };
36584
+ const request = {
36585
+ language: context.languageCode ?? 'en-GB',
36586
+ officeId: context.tideConnection.officeId,
36587
+ catalogueId: context.searchConfiguration.defaultCatalogueId ?? first(context?.tideConnection?.catalogueIds) ?? 1,
36588
+ agentId: context.agentId,
36589
+ payload: bookableEntry
36590
+ };
36591
+ await build.savePackagingEntry(config, request);
36592
+ if (typeof window !== 'undefined')
36593
+ window.location.reload();
36594
+ }
36595
+ catch (err) {
36596
+ console.error('Failed to save the entry', err);
36597
+ setEntrySaving(false);
36598
+ }
36599
+ };
35534
36600
  useEffect(() => {
35535
36601
  const fetchPriceDetails = async () => {
35536
36602
  if (!context || !editablePackagingEntry || isEmpty$1(editablePackagingEntry.lines))
@@ -35915,11 +36981,18 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35915
36981
  const id = paxId++;
35916
36982
  pax.push({
35917
36983
  id,
36984
+ guid: '',
35918
36985
  firstName: _.firstName || '',
35919
36986
  lastName: _.lastName || '',
35920
- dateOfBirth: _.dateOfBirth || null,
35921
- age: _.age || null,
35922
- isMainBooker: roomIndex === 0 && paxIndex === 0
36987
+ dateOfBirth: _.dateOfBirth || undefined,
36988
+ age: _.age || undefined,
36989
+ isMainBooker: roomIndex === 0 && paxIndex === 0,
36990
+ email: '',
36991
+ weight: null,
36992
+ weightType: build.WeightType.kilograms,
36993
+ height: null,
36994
+ heightType: build.HeightType.centimeters,
36995
+ customFields: []
35923
36996
  });
35924
36997
  return id;
35925
36998
  });
@@ -35939,6 +37012,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35939
37012
  depositAmount: 0,
35940
37013
  pax,
35941
37014
  rooms,
37015
+ paxFields: [],
35942
37016
  lines: [],
35943
37017
  address: {}
35944
37018
  };
@@ -35958,7 +37032,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35958
37032
  context.searchConfiguration.qsmType != build.PortalQsmType.AccommodationAndFlight && context.showFilters && (React__default.createElement(Filters, { initialFilters: initialFilters, filters: filters, isOpen: filtersOpen, handleSetIsOpen: () => setFiltersOpen(!filtersOpen),
35959
37033
  // handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
35960
37034
  isLoading: isLoading, setFilters: (filters) => dispatch(setFilters(filters)), resetFilters: (filters) => dispatch(resetFilters(filters)) })),
35961
- context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default.createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving, onEditAccommodation: handleEditAccommodation })),
37035
+ context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default.createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving || entrySaving, onEditAccommodation: handleEditAccommodation, onSaveEntry: handleSaveEntry })),
35962
37036
  React__default.createElement("div", { className: "search__results" },
35963
37037
  isMobile && (React__default.createElement("div", { className: "search__result-row" },
35964
37038
  React__default.createElement("div", { className: "search__results__actions" },
@@ -36046,8 +37120,15 @@ const createSearchResultsStore = () => configureStore({
36046
37120
 
36047
37121
  const SearchResults = ({ configuration, onBookingStarted }) => {
36048
37122
  const store = React__default.useMemo(() => createSearchResultsStore(), []);
37123
+ // A booked entry opened through its magic link gets the traject services screen by carrying a
37124
+ // traject rebuilt from its own lines. The magic link on the entry is what marks the mode.
37125
+ const effectiveConfiguration = React__default.useMemo(() => {
37126
+ if (!configuration.allowBookedEntryChanges || configuration.trajectEntry || !configuration.packagingEntry?.magicLink)
37127
+ return configuration;
37128
+ return { ...configuration, trajectEntry: buildBookedTrajectEntry(configuration.packagingEntry) };
37129
+ }, [configuration]);
36049
37130
  return (React__default.createElement(Provider, { store: store },
36050
- React__default.createElement(SearchResultsConfigurationContext.Provider, { value: configuration },
37131
+ React__default.createElement(SearchResultsConfigurationContext.Provider, { value: effectiveConfiguration },
36051
37132
  React__default.createElement(SearchResultsContainer, { onBookingStarted: onBookingStarted }))));
36052
37133
  };
36053
37134
 
@@ -38942,20 +40023,20 @@ function ItineraryMapView({ destinations: propDestinations, adults = 2, dateFrom
38942
40023
  const isStartEnd = dest.isStart || dest.isEnd;
38943
40024
  let iconHtml;
38944
40025
  if (isStartEnd) {
38945
- iconHtml = `
38946
- <div class="map-view__marker map-view__marker--plane">
38947
- <svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
38948
- <path d="M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10.1-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.3-15.8-20.6l49-196.3L112 288 68.8 377.6c-3 6.1-9.2 10.4-16 10.4l-2.8 0c-9.2 0-16-8.8-13.3-17.6L80 256L36.7 141.6C34 132.8 40.8 124 50 124l2.8 0c6.8 0 13 4.3 16 10.4L112 224l102.9 0-49-196.3C163.5 17.3 171.2 7 181.8 7l56.2 0c11.5 0 22.1 6 27.8 16.1L365.7 192l116.6 0z"/>
38949
- </svg>
40026
+ iconHtml = `
40027
+ <div class="map-view__marker map-view__marker--plane">
40028
+ <svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
40029
+ <path d="M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10.1-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.3-15.8-20.6l49-196.3L112 288 68.8 377.6c-3 6.1-9.2 10.4-16 10.4l-2.8 0c-9.2 0-16-8.8-13.3-17.6L80 256L36.7 141.6C34 132.8 40.8 124 50 124l2.8 0c6.8 0 13 4.3 16 10.4L112 224l102.9 0-49-196.3C163.5 17.3 171.2 7 181.8 7l56.2 0c11.5 0 22.1 6 27.8 16.1L365.7 192l116.6 0z"/>
40030
+ </svg>
38950
40031
  </div>`;
38951
40032
  }
38952
40033
  else {
38953
40034
  stopIndex++;
38954
40035
  const imgStyle = dest.imageUrl ? `style="background-image:url('${dest.imageUrl}')"` : '';
38955
- iconHtml = `
38956
- <div class="map-view__marker map-view__marker--stop" ${imgStyle}>
38957
- ${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
38958
- <span class="map-view__marker-badge">${stopIndex}</span>
40036
+ iconHtml = `
40037
+ <div class="map-view__marker map-view__marker--stop" ${imgStyle}>
40038
+ ${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
40039
+ <span class="map-view__marker-badge">${stopIndex}</span>
38959
40040
  </div>`;
38960
40041
  }
38961
40042
  const icon = L.divIcon({