@qite/tide-components 1.0.6 → 1.0.7

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 (23) hide show
  1. package/build/build-cjs/index.js +1046 -340
  2. package/build/build-cjs/src/search-results/components/itinerary/itinerary-utils.d.ts +12 -0
  3. package/build/build-cjs/src/search-results/components/itinerary/traject-itinerary.d.ts +9 -0
  4. package/build/build-cjs/src/search-results/components/traject/traject-day-activities-flyin.d.ts +6 -0
  5. package/build/build-cjs/src/search-results/components/traject/traject-flights-flyin.d.ts +13 -0
  6. package/build/build-cjs/src/search-results/components/traject/traject-node-card.d.ts +6 -3
  7. package/build/build-cjs/src/search-results/hooks/use-traject-day-activities.d.ts +6 -0
  8. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +11 -1
  9. package/build/build-cjs/src/search-results/types.d.ts +12 -2
  10. package/build/build-cjs/src/search-results/utils/traject-utils.d.ts +37 -1
  11. package/build/build-esm/index.js +1046 -340
  12. package/build/build-esm/src/search-results/components/itinerary/itinerary-utils.d.ts +12 -0
  13. package/build/build-esm/src/search-results/components/itinerary/traject-itinerary.d.ts +9 -0
  14. package/build/build-esm/src/search-results/components/traject/traject-day-activities-flyin.d.ts +6 -0
  15. package/build/build-esm/src/search-results/components/traject/traject-flights-flyin.d.ts +13 -0
  16. package/build/build-esm/src/search-results/components/traject/traject-node-card.d.ts +6 -3
  17. package/build/build-esm/src/search-results/hooks/use-traject-day-activities.d.ts +6 -0
  18. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +11 -1
  19. package/build/build-esm/src/search-results/types.d.ts +12 -2
  20. package/build/build-esm/src/search-results/utils/traject-utils.d.ts +37 -1
  21. package/package.json +2 -2
  22. package/styles/booking-search-results-variables.scss +6 -0
  23. package/styles/components/_search.scss +94 -5
@@ -438,6 +438,11 @@ var SRP$f = {
438
438
  ACCOMMODATION: "الإقامة",
439
439
  VIEW_DETAILS: "عرض التفاصيل",
440
440
  NIGHTS: "ليالٍ",
441
+ OF: "من",
442
+ ADD: "إضافة",
443
+ REMOVE: "إزالة",
444
+ ACTIVITIES: "الأنشطة",
445
+ SHOW_ACTIVITIES: "عرض الأنشطة",
441
446
  MORNING_RANGE: "الصباح",
442
447
  AFTERNOON_RANGE: "بعد الظهر",
443
448
  EVENING_RANGE: "المساء",
@@ -877,6 +882,11 @@ var SRP$e = {
877
882
  ACCOMMODATION: "Indkvartering",
878
883
  VIEW_DETAILS: "Se detaljer",
879
884
  NIGHTS: "nætter",
885
+ OF: "af",
886
+ ADD: "Tilføj",
887
+ REMOVE: "Fjern",
888
+ ACTIVITIES: "Aktiviteter",
889
+ SHOW_ACTIVITIES: "Vis aktiviteter",
880
890
  MORNING_RANGE: "Morgen",
881
891
  AFTERNOON_RANGE: "Eftermiddag",
882
892
  EVENING_RANGE: "Aften",
@@ -1320,6 +1330,11 @@ var SRP$d = {
1320
1330
  ACCOMMODATION: "Unterkunft",
1321
1331
  VIEW_DETAILS: "Details anzeigen",
1322
1332
  NIGHTS: "Nächte",
1333
+ OF: "von",
1334
+ ADD: "Hinzufügen",
1335
+ REMOVE: "Entfernen",
1336
+ ACTIVITIES: "Aktivitäten",
1337
+ SHOW_ACTIVITIES: "Aktivitäten anzeigen",
1323
1338
  MORNING_RANGE: "Morgen",
1324
1339
  AFTERNOON_RANGE: "Nachmittag",
1325
1340
  EVENING_RANGE: "Abend",
@@ -1763,6 +1778,11 @@ var SRP$c = {
1763
1778
  ACCOMMODATION: "Accommodation",
1764
1779
  VIEW_DETAILS: "View details",
1765
1780
  NIGHTS: "nights",
1781
+ OF: "of",
1782
+ ADD: "Add",
1783
+ REMOVE: "Remove",
1784
+ ACTIVITIES: "Activities",
1785
+ SHOW_ACTIVITIES: "Show activities",
1766
1786
  PRICE: "Price",
1767
1787
  MORNING_RANGE: "Morning",
1768
1788
  AFTERNOON_RANGE: "Afternoon",
@@ -2202,6 +2222,11 @@ var SRP$b = {
2202
2222
  ACCOMMODATION: "Alojamiento",
2203
2223
  VIEW_DETAILS: "Ver detalles",
2204
2224
  NIGHTS: "noches",
2225
+ OF: "de",
2226
+ ADD: "Añadir",
2227
+ REMOVE: "Eliminar",
2228
+ ACTIVITIES: "Actividades",
2229
+ SHOW_ACTIVITIES: "Ver actividades",
2205
2230
  MORNING_RANGE: "Mañana",
2206
2231
  AFTERNOON_RANGE: "Tarde",
2207
2232
  EVENING_RANGE: "Noche",
@@ -2645,6 +2670,11 @@ var SRP$a = {
2645
2670
  ACCOMMODATION: "Hébergement",
2646
2671
  VIEW_DETAILS: "Voir les détails",
2647
2672
  NIGHTS: "nuits",
2673
+ OF: "sur",
2674
+ ADD: "Ajouter",
2675
+ REMOVE: "Supprimer",
2676
+ ACTIVITIES: "Activités",
2677
+ SHOW_ACTIVITIES: "Voir les activités",
2648
2678
  MORNING_RANGE: "Matin",
2649
2679
  AFTERNOON_RANGE: "Après-midi",
2650
2680
  EVENING_RANGE: "Soir",
@@ -3084,6 +3114,11 @@ var SRP$9 = {
3084
3114
  ACCOMMODATION: "Hébergement",
3085
3115
  VIEW_DETAILS: "Voir les détails",
3086
3116
  NIGHTS: "nuits",
3117
+ OF: "sur",
3118
+ ADD: "Ajouter",
3119
+ REMOVE: "Supprimer",
3120
+ ACTIVITIES: "Activités",
3121
+ SHOW_ACTIVITIES: "Voir les activités",
3087
3122
  MORNING_RANGE: "Matin",
3088
3123
  AFTERNOON_RANGE: "Après-midi",
3089
3124
  EVENING_RANGE: "Soir",
@@ -3523,6 +3558,11 @@ var SRP$8 = {
3523
3558
  ACCOMMODATION: "Gisting",
3524
3559
  VIEW_DETAILS: "Skoða upplýsingar",
3525
3560
  NIGHTS: "nætur",
3561
+ OF: "af",
3562
+ ADD: "Bæta við",
3563
+ REMOVE: "Fjarlægja",
3564
+ ACTIVITIES: "Afþreying",
3565
+ SHOW_ACTIVITIES: "Sýna afþreyingu",
3526
3566
  MORNING_RANGE: "Morgunn",
3527
3567
  AFTERNOON_RANGE: "Síðdegi",
3528
3568
  EVENING_RANGE: "Kvöld",
@@ -3962,6 +4002,11 @@ var SRP$7 = {
3962
4002
  ACCOMMODATION: "Alloggio",
3963
4003
  VIEW_DETAILS: "Visualizza dettagli",
3964
4004
  NIGHTS: "notti",
4005
+ OF: "di",
4006
+ ADD: "Aggiungi",
4007
+ REMOVE: "Rimuovi",
4008
+ ACTIVITIES: "Attività",
4009
+ SHOW_ACTIVITIES: "Mostra attività",
3965
4010
  MORNING_RANGE: "Mattina",
3966
4011
  AFTERNOON_RANGE: "Pomeriggio",
3967
4012
  EVENING_RANGE: "Sera",
@@ -4405,6 +4450,11 @@ var SRP$6 = {
4405
4450
  ACCOMMODATION: "Accommodatie",
4406
4451
  VIEW_DETAILS: "Bekijk details",
4407
4452
  NIGHTS: "nachten",
4453
+ OF: "van",
4454
+ ADD: "Toevoegen",
4455
+ REMOVE: "Verwijderen",
4456
+ ACTIVITIES: "Activiteiten",
4457
+ SHOW_ACTIVITIES: "Toon activiteiten",
4408
4458
  MORNING_RANGE: "Ochtend",
4409
4459
  AFTERNOON_RANGE: "Namiddag",
4410
4460
  EVENING_RANGE: "Avond",
@@ -4844,6 +4894,11 @@ var SRP$5 = {
4844
4894
  ACCOMMODATION: "Accommodatie",
4845
4895
  VIEW_DETAILS: "Bekijk details",
4846
4896
  NIGHTS: "nachten",
4897
+ OF: "van",
4898
+ ADD: "Toevoegen",
4899
+ REMOVE: "Verwijderen",
4900
+ ACTIVITIES: "Activiteiten",
4901
+ SHOW_ACTIVITIES: "Toon activiteiten",
4847
4902
  MORNING_RANGE: "Ochtend",
4848
4903
  AFTERNOON_RANGE: "Namiddag",
4849
4904
  EVENING_RANGE: "Avond",
@@ -5283,6 +5338,11 @@ var SRP$4 = {
5283
5338
  ACCOMMODATION: "Overnatting",
5284
5339
  VIEW_DETAILS: "Se detaljer",
5285
5340
  NIGHTS: "netter",
5341
+ OF: "av",
5342
+ ADD: "Legg til",
5343
+ REMOVE: "Fjern",
5344
+ ACTIVITIES: "Aktiviteter",
5345
+ SHOW_ACTIVITIES: "Vis aktiviteter",
5286
5346
  MORNING_RANGE: "Morgen",
5287
5347
  AFTERNOON_RANGE: "Ettermiddag",
5288
5348
  EVENING_RANGE: "Kveld",
@@ -5722,6 +5782,11 @@ var SRP$3 = {
5722
5782
  ACCOMMODATION: "Zakwaterowanie",
5723
5783
  VIEW_DETAILS: "Zobacz szczegóły",
5724
5784
  NIGHTS: "noce",
5785
+ OF: "z",
5786
+ ADD: "Dodaj",
5787
+ REMOVE: "Usuń",
5788
+ ACTIVITIES: "Atrakcje",
5789
+ SHOW_ACTIVITIES: "Pokaż atrakcje",
5725
5790
  MORNING_RANGE: "Poranek",
5726
5791
  AFTERNOON_RANGE: "Popołudnie",
5727
5792
  EVENING_RANGE: "Wieczór",
@@ -6161,6 +6226,11 @@ var SRP$2 = {
6161
6226
  ACCOMMODATION: "Alojamento",
6162
6227
  VIEW_DETAILS: "Ver detalhes",
6163
6228
  NIGHTS: "noites",
6229
+ OF: "de",
6230
+ ADD: "Adicionar",
6231
+ REMOVE: "Remover",
6232
+ ACTIVITIES: "Atividades",
6233
+ SHOW_ACTIVITIES: "Ver atividades",
6164
6234
  MORNING_RANGE: "Manhã",
6165
6235
  AFTERNOON_RANGE: "Tarde",
6166
6236
  EVENING_RANGE: "Noite",
@@ -6600,6 +6670,11 @@ var SRP$1 = {
6600
6670
  ACCOMMODATION: "Boende",
6601
6671
  VIEW_DETAILS: "Visa detaljer",
6602
6672
  NIGHTS: "nätter",
6673
+ OF: "av",
6674
+ ADD: "Lägg till",
6675
+ REMOVE: "Ta bort",
6676
+ ACTIVITIES: "Aktiviteter",
6677
+ SHOW_ACTIVITIES: "Visa aktiviteter",
6603
6678
  MORNING_RANGE: "Morgon",
6604
6679
  AFTERNOON_RANGE: "Eftermiddag",
6605
6680
  EVENING_RANGE: "Kväll",
@@ -7039,6 +7114,11 @@ var SRP = {
7039
7114
  ACCOMMODATION: "宿泊",
7040
7115
  VIEW_DETAILS: "詳細を見る",
7041
7116
  NIGHTS: "泊",
7117
+ OF: "/",
7118
+ ADD: "追加",
7119
+ REMOVE: "削除",
7120
+ ACTIVITIES: "アクティビティ",
7121
+ SHOW_ACTIVITIES: "アクティビティを表示",
7042
7122
  MORNING_RANGE: "朝",
7043
7123
  AFTERNOON_RANGE: "午後",
7044
7124
  EVENING_RANGE: "夕方",
@@ -16532,7 +16612,7 @@ const Icon = ({ name, className, title, width, height, fill }) => {
16532
16612
  title && React__default["default"].createElement("title", null, title),
16533
16613
  React__default["default"].createElement("path", { d: "M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z" })));
16534
16614
  case 'ui-hotel':
16535
- return (React__default["default"].createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !lodash.isEmpty(className)).join(' '), width: width, height: height, viewBox: "0 0 640 640", fill: fill ?? 'currentColor' },
16615
+ return (React__default["default"].createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !lodash.isEmpty(className)).join(' '), width: width, height: height, viewBox: "0 0 512 512", fill: fill ?? 'currentColor' },
16536
16616
  React__default["default"].createElement(HTMLComment, { text: "!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc." }),
16537
16617
  title && React__default["default"].createElement("title", null, title),
16538
16618
  React__default["default"].createElement("path", { d: "M16 24C16 10.7 26.7 0 40 0L472 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-8 0 0 416 8 0c13.3 0 24 10.7 24 24s-10.7 24-24 24L40 512c-13.3 0-24-10.7-24-24s10.7-24 24-24l8 0 0-416-8 0C26.7 48 16 37.3 16 24zm208 88l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0c-8.8 0-16 7.2-16 16zM128 96c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0zm96 112l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0c-8.8 0-16 7.2-16 16zM352 96c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0zM112 208l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0c-8.8 0-16 7.2-16 16zm240-16c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0zM288 384l43.8 0c9.9 0 17.5-9 14-18.2-13.8-36.1-48.8-61.8-89.7-61.8s-75.9 25.7-89.7 61.8c-3.5 9.2 4.1 18.2 14 18.2l43.8 0 0 80 64 0 0-80z", fill: "currentColor" })));
@@ -16561,6 +16641,16 @@ const Icon = ({ name, className, title, width, height, fill }) => {
16561
16641
  React__default["default"].createElement(HTMLComment, { text: "!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc." }),
16562
16642
  title && React__default["default"].createElement("title", null, title),
16563
16643
  React__default["default"].createElement("path", { d: "M135.2 117.4l-26.1 74.6 293.8 0-26.1-74.6C372.3 104.6 360.2 96 346.6 96L165.4 96c-13.6 0-25.7 8.6-30.2 21.4zM39.6 196.8L74.8 96.3C88.3 57.8 124.6 32 165.4 32l181.2 0c40.8 0 77.1 25.8 90.6 64.3l35.2 100.5c23.2 9.6 39.6 32.5 39.6 59.2l0 192c0 17.7-14.3 32-32 32l-32 0c-17.7 0-32-14.3-32-32l0-32-320 0 0 32c0 17.7-14.3 32-32 32l-32 0c-17.7 0-32-14.3-32-32L0 256c0-26.7 16.4-49.6 39.6-59.2zM128 304a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zm288 32a32 32 0 1 0 0-64 32 32 0 1 0 0 64z", fill: "currentColor" })));
16644
+ case 'ui-bus':
16645
+ return (React__default["default"].createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !lodash.isEmpty(className)).join(' '), width: width, height: height, viewBox: "0 0 512 512", fill: fill ?? 'currentColor' },
16646
+ title && React__default["default"].createElement("title", null, title),
16647
+ React__default["default"].createElement("path", { d: "M112 32h288a64 64 0 0 1 64 64v256a64 64 0 0 1-64 64h-288a64 64 0 0 1-64-64V96a64 64 0 0 1 64-64zM96 112v104h136V112H96zm184 0v104h136V112H280zM160 352a36 36 0 1 0-72 0 36 36 0 1 0 72 0zm264 0a36 36 0 1 0-72 0 36 36 0 1 0 72 0z", fill: "currentColor", fillRule: "evenodd" }),
16648
+ React__default["default"].createElement("path", { d: "M112 416h64v48a24 24 0 0 1-24 24h-16a24 24 0 0 1-24-24v-48zm224 0h64v48a24 24 0 0 1-24 24h-16a24 24 0 0 1-24-24v-48z", fill: "currentColor" })));
16649
+ case 'ui-train':
16650
+ return (React__default["default"].createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !lodash.isEmpty(className)).join(' '), width: width, height: height, viewBox: "0 0 512 512", fill: fill ?? 'currentColor' },
16651
+ title && React__default["default"].createElement("title", null, title),
16652
+ React__default["default"].createElement("path", { d: "M160 32h192a64 64 0 0 1 64 64v224a64 64 0 0 1-64 64h-192a64 64 0 0 1-64-64V96a64 64 0 0 1 64-64zm-24 80v104h240V112H136zm56 168a28 28 0 1 0-56 0 28 28 0 1 0 56 0zm192 0a28 28 0 1 0-56 0 28 28 0 1 0 56 0z", fill: "currentColor", fillRule: "evenodd" }),
16653
+ React__default["default"].createElement("path", { d: "M168 416h72l-48 64h-72l48-64zm104 0h72l48 64h-72l-48-64z", fill: "currentColor" })));
16564
16654
  case 'ui-ship':
16565
16655
  return (React__default["default"].createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !lodash.isEmpty(className)).join(' '), width: width, height: height, viewBox: "0 0 640 512", fill: fill ?? 'currentColor' },
16566
16656
  React__default["default"].createElement(HTMLComment, { text: "!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc." }),
@@ -27379,7 +27469,9 @@ const initialState$1 = {
27379
27469
  bookingNumber: undefined,
27380
27470
  trajectNodeAvailability: {},
27381
27471
  trajectFlightAvailability: {},
27382
- trajectEditLineGuid: null
27472
+ trajectDaySuggestions: {},
27473
+ trajectEditLineGuid: null,
27474
+ trajectActivitiesDayOrder: null
27383
27475
  };
27384
27476
  const searchResultsSlice = toolkit.createSlice({
27385
27477
  name: 'searchResults',
@@ -27595,6 +27687,11 @@ const searchResultsSlice = toolkit.createSlice({
27595
27687
  return;
27596
27688
  state.editablePackagingEntry.lines[index] = action.payload;
27597
27689
  },
27690
+ addEditableEntryLines(state, action) {
27691
+ if (!state.editablePackagingEntry)
27692
+ return;
27693
+ state.editablePackagingEntry.lines = [...(state.editablePackagingEntry.lines ?? []), ...action.payload];
27694
+ },
27598
27695
  removeEditableEntryLines(state, action) {
27599
27696
  if (!state.editablePackagingEntry)
27600
27697
  return;
@@ -27626,9 +27723,24 @@ const searchResultsSlice = toolkit.createSlice({
27626
27723
  flight.selectedGuid = action.payload.guid;
27627
27724
  flight.status = 'resolved';
27628
27725
  },
27726
+ setTrajectDaySuggestionsLoading(state, action) {
27727
+ const dayOrder = action.payload;
27728
+ state.trajectDaySuggestions[dayOrder] = {
27729
+ dayOrder,
27730
+ status: 'loading',
27731
+ results: state.trajectDaySuggestions[dayOrder]?.results ?? []
27732
+ };
27733
+ },
27734
+ setTrajectDaySuggestions(state, action) {
27735
+ const { dayOrder, results } = action.payload;
27736
+ state.trajectDaySuggestions[dayOrder] = { dayOrder, status: 'resolved', results };
27737
+ },
27629
27738
  setTrajectEditLineGuid(state, action) {
27630
27739
  state.trajectEditLineGuid = action.payload;
27631
27740
  },
27741
+ setTrajectActivitiesDayOrder(state, action) {
27742
+ state.trajectActivitiesDayOrder = action.payload;
27743
+ },
27632
27744
  updateTrajectNodeResult(state, action) {
27633
27745
  const { lineGuid, result } = action.payload;
27634
27746
  const node = state.trajectNodeAvailability[lineGuid];
@@ -27641,11 +27753,13 @@ const searchResultsSlice = toolkit.createSlice({
27641
27753
  resetTrajectAvailability(state) {
27642
27754
  state.trajectNodeAvailability = {};
27643
27755
  state.trajectFlightAvailability = {};
27756
+ state.trajectDaySuggestions = {};
27644
27757
  state.trajectEditLineGuid = null;
27758
+ state.trajectActivitiesDayOrder = null;
27645
27759
  }
27646
27760
  }
27647
27761
  });
27648
- const { setResults, setFilteredResults, setSelectedSearchResult, setPackagingAccoResults, setFilteredPackagingAccoResults, setFilteredPackagingFlightResults, setPackagingAccoSearchDetails, setSelectedPackagingAccoResult, setPackagingFlightResults, setSelectedPackagingFlight, setSelectedFlight, setSelectedFlightDetails, setBookingPackageDetails, selectFlight, setIsLoading, setFlightsLoading, setInitialFilters, setFilters, resetFilters, setInitialFlightFilters, setFlightFilters, resetFlightFilters, setSortType, setFlightSortType, setActiveTab, setCurrentPage, resetSearchState, setFlyInIsOpen, setEditablePackagingEntry, setTransactionId, setFlyInType, setPriceDetails, setItinerary, setSelectedOutwardKey, setSelectedReturnKey, resetFlightSelection, setExcursionSearchParams, setSelectedExcursionSearchResult, confirmExcursionForDay, removeConfirmedExcursionForDay, clearConfirmedExcursionsForDay, setBookPackagingEntry, setCurrentStep, setBookingNumber, setTrajectNodeLoading, setTrajectNodeAvailability, setTrajectNodeSelection, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, setTrajectEditLineGuid, updateTrajectNodeResult, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
27762
+ const { setResults, setFilteredResults, setSelectedSearchResult, setPackagingAccoResults, setFilteredPackagingAccoResults, setFilteredPackagingFlightResults, setPackagingAccoSearchDetails, setSelectedPackagingAccoResult, setPackagingFlightResults, setSelectedPackagingFlight, setSelectedFlight, setSelectedFlightDetails, setBookingPackageDetails, selectFlight, setIsLoading, setFlightsLoading, setInitialFilters, setFilters, resetFilters, setInitialFlightFilters, setFlightFilters, resetFlightFilters, setSortType, setFlightSortType, setActiveTab, setCurrentPage, resetSearchState, setFlyInIsOpen, setEditablePackagingEntry, setTransactionId, setFlyInType, setPriceDetails, setItinerary, setSelectedOutwardKey, setSelectedReturnKey, resetFlightSelection, setExcursionSearchParams, setSelectedExcursionSearchResult, confirmExcursionForDay, removeConfirmedExcursionForDay, clearConfirmedExcursionsForDay, setBookPackagingEntry, setCurrentStep, setBookingNumber, setTrajectNodeLoading, setTrajectNodeAvailability, setTrajectNodeSelection, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, setTrajectEditLineGuid, setTrajectActivitiesDayOrder, setTrajectDaySuggestionsLoading, setTrajectDaySuggestions, addEditableEntryLines, updateTrajectNodeResult, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
27649
27763
  var searchResultsReducer = searchResultsSlice.reducer;
27650
27764
 
27651
27765
  const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
@@ -27830,6 +27944,518 @@ const getDuration = (flight) => {
27830
27944
  const numberOfNights = (segment) => {
27831
27945
  return dateFns.differenceInCalendarDays(new Date(segment.to), new Date(segment.from));
27832
27946
  };
27947
+ const CHARTER_SERVICE_TYPE = 10;
27948
+ const CRUISE_SERVICE_TYPE = 11;
27949
+ const FERRY_SERVICE_TYPE = 12;
27950
+ const TRANSFER_SERVICE_TYPE = 13;
27951
+ const BUS_SERVICE_TYPE = 14;
27952
+ const CAR_SERVICE_TYPE = 17;
27953
+ const CAMPER_SERVICE_TYPE = 18;
27954
+ const TRAIN_SERVICE_TYPE = 20;
27955
+ const RENTAL_SERVICE_TYPE = 22;
27956
+ const RESTAURANT_SERVICE_TYPE = 23;
27957
+ const EVENT_SERVICE_TYPE = 24;
27958
+ const TRAINING_SERVICE_TYPE = 25;
27959
+ /** Icon per service type, so every node on the itinerary reads at a glance. */
27960
+ const getServiceTypeIcon = (serviceType) => {
27961
+ switch (serviceType) {
27962
+ case ACCOMMODATION_SERVICE_TYPE:
27963
+ return 'ui-hotel';
27964
+ case EXCURSION_SERVICE_TYPE:
27965
+ return 'ui-excursion';
27966
+ case FLIGHT_SERVICE_TYPE:
27967
+ case CHARTER_SERVICE_TYPE:
27968
+ return 'ui-plane';
27969
+ case RESTAURANT_SERVICE_TYPE:
27970
+ return 'ui-utensils';
27971
+ case CRUISE_SERVICE_TYPE:
27972
+ case FERRY_SERVICE_TYPE:
27973
+ return 'ui-ship';
27974
+ case CAR_SERVICE_TYPE:
27975
+ case CAMPER_SERVICE_TYPE:
27976
+ case RENTAL_SERVICE_TYPE:
27977
+ return 'ui-car';
27978
+ case BUS_SERVICE_TYPE:
27979
+ return 'ui-bus';
27980
+ case TRAIN_SERVICE_TYPE:
27981
+ return 'ui-train';
27982
+ case TRANSFER_SERVICE_TYPE:
27983
+ return 'ui-transfer';
27984
+ case EVENT_SERVICE_TYPE:
27985
+ return 'ui-ticket';
27986
+ case TRAINING_SERVICE_TYPE:
27987
+ return 'ui-group';
27988
+ default:
27989
+ return 'ui-location';
27990
+ }
27991
+ };
27992
+ const getServiceTypeBadgeModifier = (serviceType) => {
27993
+ switch (serviceType) {
27994
+ case FLIGHT_SERVICE_TYPE:
27995
+ case CHARTER_SERVICE_TYPE:
27996
+ case CRUISE_SERVICE_TYPE:
27997
+ case FERRY_SERVICE_TYPE:
27998
+ return 'flight';
27999
+ case ACCOMMODATION_SERVICE_TYPE:
28000
+ return 'hotel';
28001
+ case EXCURSION_SERVICE_TYPE:
28002
+ case EVENT_SERVICE_TYPE:
28003
+ return 'excursion';
28004
+ case RESTAURANT_SERVICE_TYPE:
28005
+ return 'restaurant';
28006
+ default:
28007
+ return '';
28008
+ }
28009
+ };
28010
+ const POI_TRAJECT_NODE_TYPE = 2;
28011
+ const getTrajectNodeIcon = (node) => node.trajectNodeType === POI_TRAJECT_NODE_TYPE ? 'ui-location' : getServiceTypeIcon(node.serviceType);
28012
+ const getTrajectNodeBadgeModifier = (node) => node.trajectNodeType === POI_TRAJECT_NODE_TYPE ? 'poi' : getServiceTypeBadgeModifier(node.serviceType);
28013
+
28014
+ const REGULAR_TRAJECT_NODE_TYPE = 0;
28015
+ const CONNECTING_TRAJECT_NODE_TYPE = 1;
28016
+ const isSearchableTrajectNode = (node) => node.serviceType === ACCOMMODATION_SERVICE_TYPE || node.serviceType === EXCURSION_SERVICE_TYPE;
28017
+ const isTrajectFlightNode = (node) => node.serviceType === FLIGHT_SERVICE_TYPE;
28018
+ const getTrajectNodesWithLines = (trajectEntry) => {
28019
+ const linesByGuid = new Map((trajectEntry.entry.lines ?? []).map((line) => [line.guid, line]));
28020
+ return [...(trajectEntry.nodes ?? [])]
28021
+ .sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
28022
+ .map((node) => {
28023
+ const guids = node.lineGuids?.length ? node.lineGuids : [node.lineGuid];
28024
+ const lines = guids.map((guid) => linesByGuid.get(guid)).filter((x) => !!x);
28025
+ return { node, line: lines[0], lines };
28026
+ })
28027
+ .filter((x) => !!x.line);
28028
+ };
28029
+ const getCoordinates = (line, node, result) => {
28030
+ const sources = [
28031
+ ...(result ? [result] : []),
28032
+ ...(line ? [line] : []),
28033
+ ...(node?.alternatives ?? []).filter((x) => x.isPreferred),
28034
+ ...(node?.alternatives ?? [])
28035
+ ];
28036
+ const found = sources.find((x) => !!x.latitude && !!x.longitude);
28037
+ return found ? { latitude: found.latitude, longitude: found.longitude } : null;
28038
+ };
28039
+ const buildDestination = (line, node, result) => {
28040
+ const coordinates = getCoordinates(line, node, result);
28041
+ const place = (result?.locationId && { id: result.locationId, isLocation: true }) ||
28042
+ (result?.oordId && { id: result.oordId, isOord: true }) ||
28043
+ (result?.regionId && { id: result.regionId, isRegion: true }) ||
28044
+ (result?.countryId && { id: result.countryId, isCountry: true }) ||
28045
+ (line.location?.id && { id: line.location.id, isLocation: true }) ||
28046
+ (line.oord?.id && { id: line.oord.id, isOord: true }) ||
28047
+ (line.region?.id && { id: line.region.id, isRegion: true }) ||
28048
+ (line.country?.id && { id: line.country.id, isCountry: true }) ||
28049
+ null;
28050
+ return { id: 0, ...place, ...coordinates };
28051
+ };
28052
+ const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
28053
+ transactionId: context.transactionId,
28054
+ officeId: context.officeId,
28055
+ agentId: context.agentId ?? null,
28056
+ catalogueId: context.catalogueId,
28057
+ searchConfigurationId: context.searchConfigurationId,
28058
+ portalId: context.portalId ?? null,
28059
+ vendorConfigurationId: node.externalVendorId ?? null,
28060
+ language: context.language,
28061
+ serviceType: node.serviceType,
28062
+ fromDate: toDateOnlyString(line.from),
28063
+ toDate: toDateOnlyString(line.to),
28064
+ destination: buildDestination(line, node),
28065
+ productCode,
28066
+ rooms: context.rooms,
28067
+ tagIds: []
28068
+ });
28069
+ /**
28070
+ * Entry lines for an excursion the traveller picked out of the suggestions.
28071
+ *
28072
+ * A traject node already has its lines and only needs stamping; a suggestion has none, so this
28073
+ * builds them — one per selected option, as the regular day-by-day excursion flow does, since an
28074
+ * excursion's options are ticket types (adult, child) rather than rooms. Where the search marks no
28075
+ * default, the first option of each room stands in.
28076
+ */
28077
+ const buildTrajectExcursionLines = (result) => {
28078
+ const options = (result.rooms ?? []).flatMap((room) => {
28079
+ const selected = (room.options ?? []).filter((x) => x.isSelected);
28080
+ return selected.length ? selected : (room.options ?? []).slice(0, 1);
28081
+ });
28082
+ if (!options.length)
28083
+ return [];
28084
+ const guids = options.map((option) => option.guid || crypto.randomUUID());
28085
+ return options.map((option, index) => ({
28086
+ guid: guids[index],
28087
+ moment: '',
28088
+ parentGuid: index === 0 ? null : guids[0],
28089
+ order: index,
28090
+ isChanged: true,
28091
+ from: result.fromDate,
28092
+ to: result.toDate,
28093
+ serviceType: EXCURSION_SERVICE_TYPE,
28094
+ productName: result.name,
28095
+ productCode: result.code,
28096
+ accommodationName: option.accommodationName,
28097
+ accommodationCode: option.accommodationCode,
28098
+ regimeName: option.regimeName,
28099
+ regimeCode: option.regimeCode,
28100
+ country: result.countryId ? { id: result.countryId, name: result.countryName, localizations: [] } : null,
28101
+ region: result.regionId ? { id: result.regionId, name: result.regionName, localizations: [] } : null,
28102
+ oord: result.oordId ? { id: result.oordId, name: result.oordName, localizations: [] } : null,
28103
+ location: result.locationId ? { id: result.locationId, name: result.locationName, localizations: [] } : null,
28104
+ longitude: result.longitude ?? null,
28105
+ latitude: result.latitude ?? null,
28106
+ pax: (option.paxIds ?? []).map((paxId, paxIndex) => ({ paxId, room: 0, order: paxIndex })),
28107
+ flightInformation: null
28108
+ }));
28109
+ };
28110
+ const buildDayActivityCards = (items, availability, suggestions) => {
28111
+ const cards = [];
28112
+ const seen = new Set();
28113
+ const push = (result, item) => {
28114
+ if (!result || seen.has(result.code))
28115
+ return;
28116
+ seen.add(result.code);
28117
+ cards.push({ result, item });
28118
+ };
28119
+ items.forEach((item) => {
28120
+ const results = availability[item.line.guid]?.results ?? [];
28121
+ const selected = results.find((x) => x.code === availability[item.line.guid]?.selectedCode);
28122
+ push(selected, item);
28123
+ results.filter((x) => !!findCandidateForResult(item.node, x)).forEach((result) => push(result, item));
28124
+ });
28125
+ suggestions.forEach((result) => push(result));
28126
+ // Whatever the nodes' own destination search found and the day's search did not — normally
28127
+ // nothing, as they are the same search, but a node can resolve where a day has no place to look.
28128
+ items.forEach((item) => (availability[item.line.guid]?.results ?? []).forEach((result) => push(result, item)));
28129
+ return cards;
28130
+ };
28131
+ const getNodeCandidates = (node) => {
28132
+ const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
28133
+ if (configured.length)
28134
+ return configured;
28135
+ const fallbackCode = node.code ?? node.preferredAccommodationCode;
28136
+ if (!fallbackCode || !fallbackCode.trim().length)
28137
+ return [];
28138
+ return [
28139
+ {
28140
+ code: fallbackCode,
28141
+ name: node.name,
28142
+ description: node.description,
28143
+ imageUrl: node.imageUrl,
28144
+ contentSource: node.contentSource,
28145
+ vendor: node.vendor,
28146
+ externalVendorId: node.externalVendorId,
28147
+ isPreferred: true
28148
+ }
28149
+ ];
28150
+ };
28151
+ const findCandidateForResult = (node, result) => getNodeCandidates(node).find((candidate) => matchesCode(result, candidate.code)) ?? null;
28152
+ const matchesCode = (result, code) => {
28153
+ if (result.code === code)
28154
+ return true;
28155
+ return (result.rooms ?? []).some((room) => (room.options ?? []).some((option) => option.accommodationCode === code));
28156
+ };
28157
+ const getPackagingRoomsFromEntry = (entry) => {
28158
+ const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));
28159
+ const rooms = (entry.rooms ?? []).map((room) => ({
28160
+ travellers: (room.paxIds ?? []).map((paxId) => {
28161
+ const pax = paxById.get(paxId);
28162
+ return {
28163
+ id: paxId,
28164
+ age: pax?.age ?? null,
28165
+ dateOfBirth: pax?.dateOfBirth ?? null
28166
+ };
28167
+ })
28168
+ }));
28169
+ return rooms.filter((room) => room.travellers.length > 0);
28170
+ };
28171
+ const pickCheapest = (results) => [...results].sort((a, b) => a.price - b.price)[0] ?? null;
28172
+ const applyResultToLines = (lines, result) => lines.map((line, index) => applyResultToLine(line, result, index));
28173
+ const getOptionForRoom = (result, roomIndex) => {
28174
+ const room = (result.rooms ?? [])[roomIndex];
28175
+ if (room)
28176
+ return (room.options ?? []).find((x) => x.isSelected) ?? (room.options ?? [])[0];
28177
+ return (result.rooms ?? []).flatMap((x) => x.options ?? []).find((x) => x.isSelected) ?? (result.rooms ?? [])[0]?.options?.[0];
28178
+ };
28179
+ const applyResultToLine = (line, result, roomIndex = 0) => {
28180
+ const option = getOptionForRoom(result, roomIndex);
28181
+ return {
28182
+ ...line,
28183
+ productName: result.name ?? line.productName,
28184
+ productCode: result.code ?? line.productCode,
28185
+ accommodationCode: option?.accommodationCode ?? line.accommodationCode,
28186
+ accommodationName: option?.accommodationName ?? line.accommodationName,
28187
+ regimeCode: option?.regimeCode ?? line.regimeCode,
28188
+ regimeName: option?.regimeName ?? line.regimeName,
28189
+ latitude: result.latitude ?? line.latitude,
28190
+ longitude: result.longitude ?? line.longitude,
28191
+ isChanged: true
28192
+ };
28193
+ };
28194
+ const toDateOnlyUtcString = (value) => {
28195
+ const date = new Date(value);
28196
+ return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
28197
+ };
28198
+ const toTimeOnlyString = (value) => {
28199
+ const date = new Date(value);
28200
+ const hh = String(date.getUTCHours()).padStart(2, '0');
28201
+ const mm = String(date.getUTCMinutes()).padStart(2, '0');
28202
+ const ss = String(date.getUTCSeconds()).padStart(2, '0');
28203
+ return `${hh}:${mm}:${ss}`;
28204
+ };
28205
+ const mapFlightSegmentsToFlightLines = (segments) => segments.map((segment) => ({
28206
+ airlineCode: segment.marketingAirlineCode,
28207
+ airlineDescription: segment.marketingAirlineName,
28208
+ operatingAirlineCode: segment.operatingAirlineCode,
28209
+ operatingAirlineDescription: segment.operatingAirlineName,
28210
+ flightNumber: segment.flightNumber,
28211
+ operatingFlightNumber: segment.operatingFlightNumber ?? null,
28212
+ departureDate: toDateOnlyUtcString(segment.departureDateTime),
28213
+ departureTime: toTimeOnlyString(segment.departureDateTime),
28214
+ departureAirportCode: segment.departureAirportCode,
28215
+ departureAirportDescription: segment.departureAirportName,
28216
+ arrivalDate: toDateOnlyUtcString(segment.arrivalDateTime),
28217
+ arrivalTime: toTimeOnlyString(segment.arrivalDateTime),
28218
+ arrivalAirportCode: segment.arrivalAirportCode,
28219
+ arrivalAirportDescription: segment.arrivalAirportName,
28220
+ durationInTicks: segment.durationInTicks
28221
+ }));
28222
+ const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
28223
+ transactionId: context.transactionId,
28224
+ officeId: context.officeId,
28225
+ catalogueId: context.catalogueId,
28226
+ agentId: context.agentId ?? null,
28227
+ language: context.language,
28228
+ departureAirportCode: node.departureAirportCode ?? '',
28229
+ arrivalAirportCode: node.arrivalAirportCode ?? '',
28230
+ returnAirportCode: null,
28231
+ luggageIncluded: null,
28232
+ maxStops: null,
28233
+ travelClass: null,
28234
+ vendorConfigurationId: node.externalVendorId ?? null,
28235
+ pax,
28236
+ outward: { date: dateToDateStruct(new Date(line.from)) },
28237
+ return: null
28238
+ });
28239
+ const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
28240
+ const applyFlightToLine = (line, flight) => {
28241
+ const segments = flight.outward?.segments ?? [];
28242
+ if (!segments.length)
28243
+ return line;
28244
+ const firstSegment = segments[0];
28245
+ const lastSegment = segments[segments.length - 1];
28246
+ return {
28247
+ ...line,
28248
+ from: new Date(firstSegment.departureDateTime).toISOString(),
28249
+ to: new Date(lastSegment.arrivalDateTime).toISOString(),
28250
+ productName: `${firstSegment.departureAirportName} - ${lastSegment.arrivalAirportName} (${firstSegment.marketingAirlineName})`,
28251
+ productCode: `${firstSegment.departureAirportCode} ${lastSegment.arrivalAirportCode}/${firstSegment.marketingAirlineCode}`,
28252
+ accommodationName: firstSegment.metaData?.farePriceClassName ?? line.accommodationName,
28253
+ accommodationCode: firstSegment.metaData?.fareCode ?? line.accommodationCode,
28254
+ flightInformation: {
28255
+ pnr: '',
28256
+ flightLines: mapFlightSegmentsToFlightLines(segments)
28257
+ },
28258
+ isChanged: true
28259
+ };
28260
+ };
28261
+ /**
28262
+ * Externally sourced products carry a vendor configuration; products held internally in Tide have
28263
+ * none. `vendorType` is not a reliable signal — the packaging service nulls it out when the search
28264
+ * configuration has ExposeProvider off — so the vendor ids are what we go on.
28265
+ */
28266
+ const isExternalResult = (result) => result.vendorId != null || result.vendorConfigurationId != null;
28267
+ const isExternalCandidate = (candidate) => candidate.externalVendorId != null || candidate.vendor != null;
28268
+
28269
+ const badgeClass = (kind, modifier) => {
28270
+ const base = `search__filter__itinerary__${kind}-badge`;
28271
+ const fallback = kind === 'segment' ? `${base}--secondary` : `${base}--default`;
28272
+ return `${base} ${modifier ? `${base}--${modifier}` : fallback}`;
28273
+ };
28274
+ const nightsOf = (node, line) => dateFns.differenceInCalendarDays(new Date(line?.to ?? node.to), new Date(line?.from ?? node.from));
28275
+ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
28276
+ const timeline = React.useMemo(() => {
28277
+ const linesByGuid = new Map((packagingEntry.lines ?? []).map((line) => [line.guid, line]));
28278
+ const nodes = [...(trajectEntry.nodes ?? [])]
28279
+ .sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
28280
+ .map((node) => {
28281
+ const guids = node.lineGuids?.length ? node.lineGuids : [node.lineGuid];
28282
+ const lines = guids.map((guid) => linesByGuid.get(guid)).filter((x) => !!x);
28283
+ return { node, lines };
28284
+ });
28285
+ const claimed = new Set(nodes.flatMap((item) => item.lines.map((line) => line.guid)));
28286
+ const extras = (packagingEntry.lines ?? []).filter((line) => !claimed.has(line.guid));
28287
+ if (!extras.length)
28288
+ return nodes;
28289
+ const dayOrderOf = (date) => trajectEntry.traject.days.find((day) => dateFns.isSameDay(new Date(day.date), new Date(date)))?.order ??
28290
+ Math.max(dateFns.differenceInCalendarDays(new Date(date), new Date(trajectEntry.traject.startDate)), 0);
28291
+ // One product bought once, however many option lines it took (an adult and a child ticket).
28292
+ const grouped = new Map();
28293
+ extras.forEach((line) => {
28294
+ const key = `${line.productCode}|${line.from}`;
28295
+ grouped.set(key, [...(grouped.get(key) ?? []), line]);
28296
+ });
28297
+ const byDay = new Map();
28298
+ nodes.forEach((item) => byDay.set(item.node.dayOrder, [...(byDay.get(item.node.dayOrder) ?? []), item]));
28299
+ [...grouped.values()].forEach((lines, index) => {
28300
+ const line = lines[0];
28301
+ const dayOrder = dayOrderOf(line.from);
28302
+ const item = {
28303
+ lines,
28304
+ node: {
28305
+ nodeId: -(index + 1),
28306
+ lineGuid: line.guid,
28307
+ lineGuids: lines.map((x) => x.guid),
28308
+ dayOrder,
28309
+ order: Number.MAX_SAFE_INTEGER,
28310
+ name: line.productName,
28311
+ serviceType: line.serviceType,
28312
+ trajectNodeType: REGULAR_TRAJECT_NODE_TYPE,
28313
+ requirementType: 0,
28314
+ contentSource: 0,
28315
+ alternatives: [],
28316
+ from: line.from,
28317
+ to: line.to
28318
+ }
28319
+ };
28320
+ const dayItems = [...(byDay.get(dayOrder) ?? [])];
28321
+ let at = dayItems.length;
28322
+ while (at > 0 && dayItems[at - 1].node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE)
28323
+ at--;
28324
+ dayItems.splice(at, 0, item);
28325
+ byDay.set(dayOrder, dayItems);
28326
+ });
28327
+ return [...byDay.keys()].sort((a, b) => a - b).flatMap((dayOrder) => byDay.get(dayOrder));
28328
+ }, [trajectEntry, packagingEntry]);
28329
+ const stayByDay = React.useMemo(() => {
28330
+ const map = new Map();
28331
+ timeline
28332
+ .filter(({ node }) => node.trajectNodeType === REGULAR_TRAJECT_NODE_TYPE && node.serviceType === ACCOMMODATION_SERVICE_TYPE)
28333
+ .forEach(({ node, lines }) => {
28334
+ const line = lines[0];
28335
+ const nights = Math.max(nightsOf(node, line), 1);
28336
+ const name = line?.productName || node.preferredAccommodationName || node.name || '';
28337
+ for (let night = 0; night < nights; night++)
28338
+ map.set(node.dayOrder + night, { name, night, nights });
28339
+ });
28340
+ return map;
28341
+ }, [timeline]);
28342
+ const renderDate = (value) => (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-date" },
28343
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-date-date" },
28344
+ React__default["default"].createElement("strong", null, dateFns.format(new Date(value), 'd'))),
28345
+ React__default["default"].createElement("p", null, dateFns.format(new Date(value), 'MMM'))));
28346
+ const renderConnectingNode = ({ node }) => {
28347
+ const distance = node.distanceInKm ? `${Math.round(node.distanceInKm)} km` : '';
28348
+ return (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport", key: `connect-${node.nodeId}` },
28349
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
28350
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
28351
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-item" },
28352
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-date" }),
28353
+ React__default["default"].createElement("div", { className: badgeClass('transport', getTrajectNodeBadgeModifier(node)) },
28354
+ React__default["default"].createElement(Icon, { name: getTrajectNodeIcon(node), height: 15 })),
28355
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-details" },
28356
+ React__default["default"].createElement("h6", null, node.name || distance),
28357
+ !!node.name && !!distance && React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" }, distance)))));
28358
+ };
28359
+ const renderOvernight = (item, index) => {
28360
+ const { dayOrder } = item.node;
28361
+ const closesTheDay = timeline[index + 1]?.node.dayOrder !== dayOrder;
28362
+ const stay = stayByDay.get(dayOrder);
28363
+ if (!closesTheDay || !stay)
28364
+ return null;
28365
+ return (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport", key: `overnight-${item.node.nodeId}` },
28366
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
28367
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
28368
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-item" },
28369
+ renderDate(item.node.from),
28370
+ React__default["default"].createElement("div", { className: badgeClass('transport', getServiceTypeBadgeModifier(ACCOMMODATION_SERVICE_TYPE)) },
28371
+ React__default["default"].createElement(Icon, { name: "ui-bed", height: 15 })),
28372
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-details" },
28373
+ React__default["default"].createElement("h6", null, stay.name),
28374
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" },
28375
+ stay.night + 1,
28376
+ " ",
28377
+ translations.SRP.OF,
28378
+ " ",
28379
+ stay.nights,
28380
+ " ",
28381
+ translations.SRP.NIGHTS)))));
28382
+ };
28383
+ const renderFlightNode = ({ node, lines }) => {
28384
+ const line = lines[0];
28385
+ return (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport", key: `flight-${node.nodeId}` },
28386
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
28387
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
28388
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-item" },
28389
+ renderDate(line?.from ?? node.from),
28390
+ React__default["default"].createElement("div", { className: badgeClass('transport', getServiceTypeBadgeModifier(FLIGHT_SERVICE_TYPE)) },
28391
+ React__default["default"].createElement(Icon, { name: "ui-plane", height: 15 })),
28392
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-details" },
28393
+ React__default["default"].createElement("h6", null, line?.productName || node.name),
28394
+ !!getDepartureTime(line) && (React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-plane" },
28395
+ React__default["default"].createElement("span", null,
28396
+ React__default["default"].createElement(Icon, { name: "ui-plane-depart", height: 14 }),
28397
+ " ",
28398
+ React__default["default"].createElement("strong", null, getDepartureTime(line))),
28399
+ ' ',
28400
+ "-",
28401
+ ' ',
28402
+ React__default["default"].createElement("span", null,
28403
+ React__default["default"].createElement(Icon, { name: "ui-plane-arrive", height: 14 }),
28404
+ " ",
28405
+ React__default["default"].createElement("strong", null, getArrivalTime(line))))),
28406
+ !!getDuration(line) && (React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" },
28407
+ React__default["default"].createElement("span", null,
28408
+ React__default["default"].createElement(Icon, { name: "ui-clock", height: 20 }),
28409
+ " ",
28410
+ getDuration(line))))))));
28411
+ };
28412
+ const renderServiceNode = ({ node, lines }) => {
28413
+ const line = lines[0];
28414
+ const isStay = node.serviceType === ACCOMMODATION_SERVICE_TYPE;
28415
+ const nights = isStay ? nightsOf(node, line) : 0;
28416
+ return (React__default["default"].createElement("div", { className: "search__filter__itinerary__segments", key: `node-${node.nodeId}` },
28417
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segments__wrapper" },
28418
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segments-timeline" },
28419
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segments-timeline-line" })),
28420
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment" },
28421
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-item" },
28422
+ React__default["default"].createElement("div", { className: `search__filter__itinerary__segment-date ${isStay && nights > 0 ? 'search__filter__itinerary__segment-nights' : ''}` }, isStay && nights > 0 ? (React__default["default"].createElement(React__default["default"].Fragment, null,
28423
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__segment-date-date" },
28424
+ React__default["default"].createElement("strong", null, nights)),
28425
+ React__default["default"].createElement(Icon, { name: "ui-moon", width: 16, height: 16 }))) : (React__default["default"].createElement(React__default["default"].Fragment, null,
28426
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__segment-date-date" },
28427
+ React__default["default"].createElement("strong", null, dateFns.format(new Date(line?.from ?? node.from), 'd'))),
28428
+ React__default["default"].createElement("p", null, dateFns.format(new Date(line?.from ?? node.from), 'MMM'))))),
28429
+ React__default["default"].createElement("div", { className: badgeClass('segment', getTrajectNodeBadgeModifier(node)) },
28430
+ React__default["default"].createElement(Icon, { name: getTrajectNodeIcon(node), width: 15, height: 15 })),
28431
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details" },
28432
+ React__default["default"].createElement("h6", null, line?.productName || node.preferredAccommodationName || node.name),
28433
+ isStay &&
28434
+ lines.map((roomLine, index) => (React__default["default"].createElement(React__default["default"].Fragment, { key: roomLine.guid },
28435
+ lines.length > 1 && (React__default["default"].createElement("strong", null,
28436
+ translations.SHARED.ROOM,
28437
+ "\u00A0",
28438
+ index + 1)),
28439
+ roomLine.accommodationName && (React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details__room" },
28440
+ React__default["default"].createElement(Icon, { name: "ui-bed", width: 12, height: 12 }),
28441
+ roomLine.accommodationName)),
28442
+ roomLine.regimeName && (React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details__room" },
28443
+ React__default["default"].createElement(Icon, { name: "ui-utensils", width: 12, height: 12 }),
28444
+ roomLine.regimeName))))),
28445
+ !isStay && React__default["default"].createElement("p", { className: "search__filter__itinerary__segment-details-text" }, dateFns.format(new Date(line?.from ?? node.from), 'EEE. d MMM yyyy'))))))));
28446
+ };
28447
+ return (React__default["default"].createElement(React__default["default"].Fragment, null, timeline.map((item, index) => {
28448
+ if (item.node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE) {
28449
+ return (React__default["default"].createElement(React__default["default"].Fragment, { key: `connect-${item.node.nodeId}` },
28450
+ renderConnectingNode(item),
28451
+ renderOvernight(item, index)));
28452
+ }
28453
+ if (item.node.trajectNodeType === REGULAR_TRAJECT_NODE_TYPE && item.node.serviceType === FLIGHT_SERVICE_TYPE)
28454
+ return renderFlightNode(item);
28455
+ return renderServiceNode(item);
28456
+ })));
28457
+ };
28458
+
27833
28459
  const getSegmentIcon = (segment) => {
27834
28460
  switch (segment.serviceType) {
27835
28461
  case 3:
@@ -27953,116 +28579,119 @@ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation })
27953
28579
  dateFns.format(new Date(firstEntryLine.from), 'EEE. d MMM yyyy'),
27954
28580
  " - ",
27955
28581
  React__default["default"].createElement("strong", null, translations.SRP.START))))),
27956
- outboundFlight && (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport" },
27957
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
27958
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
27959
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-item" },
27960
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-date" },
27961
- React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-date-date" },
27962
- React__default["default"].createElement("strong", null, dateFns.format(new Date(outboundFlight.from), 'd'))),
27963
- React__default["default"].createElement("p", null, dateFns.format(new Date(outboundFlight.from), 'MMM'))),
27964
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-badge" },
27965
- React__default["default"].createElement(Icon, { name: "ui-plane", height: 15 })),
27966
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-details" },
27967
- React__default["default"].createElement("h6", null, outboundFlight.productName),
27968
- React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-plane" },
27969
- React__default["default"].createElement("span", null,
27970
- React__default["default"].createElement(Icon, { name: "ui-plane-depart", height: 14 }),
27971
- " ",
27972
- React__default["default"].createElement("strong", null, getDepartureTime(outboundFlight))),
27973
- ' ',
27974
- "-",
27975
- ' ',
27976
- React__default["default"].createElement("span", null,
27977
- React__default["default"].createElement(Icon, { name: "ui-plane-arrive", height: 14 }),
27978
- " ",
27979
- React__default["default"].createElement("strong", null, getArrivalTime(outboundFlight)))),
27980
- React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" },
27981
- React__default["default"].createElement("span", null,
27982
- React__default["default"].createElement(Icon, { name: "ui-clock", height: 20 }),
27983
- " ",
27984
- getDuration(outboundFlight))))))),
27985
- !lodash.isEmpty(groupedOtherSegments) &&
27986
- groupedOtherSegments.map((group) => {
27987
- const firstSegment = lodash.first(group.segments);
27988
- if (!firstSegment)
27989
- return null;
27990
- return (React__default["default"].createElement("div", { className: "search__filter__itinerary__segments" },
27991
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segments__wrapper", key: group.key },
27992
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segments-timeline" },
27993
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segments-timeline-line" })),
27994
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segment" },
27995
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-item search__filter__itinerary__segment-item--start" },
27996
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-date" },
27997
- React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-date-date" },
27998
- React__default["default"].createElement("strong", null, dateFns.format(new Date(firstSegment.from), 'd'))),
27999
- React__default["default"].createElement("p", null, dateFns.format(new Date(firstSegment.from), 'MMM'))),
28000
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-badge" },
28001
- React__default["default"].createElement(Icon, { name: "ui-location", width: 15, height: 15 })),
28002
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details" },
28003
- React__default["default"].createElement("h6", null,
28004
- firstSegment.location?.name || firstSegment.oord?.name || firstSegment.region?.name,
28005
- (firstSegment.location?.name || firstSegment.oord?.name || firstSegment.region?.name) && firstSegment.country?.name ? ', ' : '',
28006
- firstSegment.country?.name),
28007
- React__default["default"].createElement("p", { className: "search__filter__itinerary__segment-details-text" },
28008
- dateFns.format(new Date(firstSegment.from), 'EEE. d MMM yyyy'),
28009
- "> ",
28010
- dateFns.format(new Date(firstSegment.to), 'EEE. d MMM yyyy'))))),
28011
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segment" },
28012
- React__default["default"].createElement("div", { className: `search__filter__itinerary__segment-item ${canEdit(firstSegment) ? 'search__filter__itinerary__segment-item--editable' : ''}`, onClick: () => {
28013
- if (canEdit(firstSegment) && onEditAccommodation) {
28014
- onEditAccommodation(group.segments);
28015
- }
28016
- } },
28017
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-date search__filter__itinerary__segment-nights" }, firstSegment.serviceType === ACCOMMODATION_SERVICE_TYPE && (React__default["default"].createElement(React__default["default"].Fragment, null,
28018
- React__default["default"].createElement("p", { className: "search__filter__itinerary__segment-date-date" },
28019
- React__default["default"].createElement("strong", null, numberOfNights(firstSegment))),
28020
- React__default["default"].createElement(Icon, { name: "ui-moon", width: 16, height: 16 })))),
28021
- getSegmentIcon(firstSegment),
28022
- React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details" },
28023
- React__default["default"].createElement("h6", null, getSegmentTitle(firstSegment)),
28024
- firstSegment.serviceType === ACCOMMODATION_SERVICE_TYPE &&
28025
- group.segments.map((segment, index) => (React__default["default"].createElement(React__default["default"].Fragment, { key: segment.guid },
28026
- React__default["default"].createElement("strong", null,
28027
- translations.SHARED.ROOM,
28028
- "\u00A0",
28029
- index + 1),
28030
- segment.productName && segment.accommodationName && (React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details__room" },
28031
- React__default["default"].createElement(Icon, { name: "ui-bed", width: 12, height: 12 }),
28032
- segment.accommodationName)),
28033
- segment.regimeName && (React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details__room" },
28034
- React__default["default"].createElement(Icon, { name: "ui-utensils", width: 12, height: 12 }),
28035
- segment.regimeName)))))))))));
28036
- }),
28037
- returnFlight && returnFlight !== outboundFlight && (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport" },
28038
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
28039
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
28040
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-item" },
28041
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-date" },
28042
- React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-date-date" },
28043
- React__default["default"].createElement("strong", null, dateFns.format(new Date(returnFlight.from), 'd'))),
28044
- React__default["default"].createElement("p", null, dateFns.format(new Date(returnFlight.from), 'MMM'))),
28045
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-badge" },
28046
- React__default["default"].createElement(Icon, { name: "ui-plane", height: 15 })),
28047
- React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-details" },
28048
- React__default["default"].createElement("h6", null, returnFlight.productName),
28049
- React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-plane" },
28050
- React__default["default"].createElement("span", null,
28051
- React__default["default"].createElement(Icon, { name: "ui-plane-depart", height: 14 }),
28052
- " ",
28053
- React__default["default"].createElement("strong", null, getDepartureTime(returnFlight))),
28054
- ' ',
28055
- "-",
28056
- ' ',
28057
- React__default["default"].createElement("span", null,
28058
- React__default["default"].createElement(Icon, { name: "ui-plane-arrive", height: 14 }),
28059
- " ",
28060
- React__default["default"].createElement("strong", null, getArrivalTime(returnFlight)))),
28061
- React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" },
28062
- React__default["default"].createElement("span", null,
28063
- React__default["default"].createElement(Icon, { name: "ui-clock", height: 20 }),
28064
- " ",
28065
- getDuration(returnFlight))))))),
28582
+ context?.trajectEntry ? (React__default["default"].createElement(TrajectItinerary, { trajectEntry: context.trajectEntry, packagingEntry: packagingEntry, translations: translations })) : (React__default["default"].createElement(React__default["default"].Fragment, null,
28583
+ outboundFlight && (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport" },
28584
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
28585
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
28586
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-item" },
28587
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-date" },
28588
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-date-date" },
28589
+ React__default["default"].createElement("strong", null, dateFns.format(new Date(outboundFlight.from), 'd'))),
28590
+ React__default["default"].createElement("p", null, dateFns.format(new Date(outboundFlight.from), 'MMM'))),
28591
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-badge" },
28592
+ React__default["default"].createElement(Icon, { name: "ui-plane", height: 15 })),
28593
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-details" },
28594
+ React__default["default"].createElement("h6", null, outboundFlight.productName),
28595
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-plane" },
28596
+ React__default["default"].createElement("span", null,
28597
+ React__default["default"].createElement(Icon, { name: "ui-plane-depart", height: 14 }),
28598
+ " ",
28599
+ React__default["default"].createElement("strong", null, getDepartureTime(outboundFlight))),
28600
+ ' ',
28601
+ "-",
28602
+ ' ',
28603
+ React__default["default"].createElement("span", null,
28604
+ React__default["default"].createElement(Icon, { name: "ui-plane-arrive", height: 14 }),
28605
+ " ",
28606
+ React__default["default"].createElement("strong", null, getArrivalTime(outboundFlight)))),
28607
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" },
28608
+ React__default["default"].createElement("span", null,
28609
+ React__default["default"].createElement(Icon, { name: "ui-clock", height: 20 }),
28610
+ " ",
28611
+ getDuration(outboundFlight))))))),
28612
+ !lodash.isEmpty(groupedOtherSegments) &&
28613
+ groupedOtherSegments.map((group) => {
28614
+ const firstSegment = lodash.first(group.segments);
28615
+ if (!firstSegment)
28616
+ return null;
28617
+ return (React__default["default"].createElement("div", { className: "search__filter__itinerary__segments" },
28618
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segments__wrapper", key: group.key },
28619
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segments-timeline" },
28620
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segments-timeline-line" })),
28621
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment" },
28622
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-item search__filter__itinerary__segment-item--start" },
28623
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-date" },
28624
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-date-date" },
28625
+ React__default["default"].createElement("strong", null, dateFns.format(new Date(firstSegment.from), 'd'))),
28626
+ React__default["default"].createElement("p", null, dateFns.format(new Date(firstSegment.from), 'MMM'))),
28627
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-badge" },
28628
+ React__default["default"].createElement(Icon, { name: "ui-location", width: 15, height: 15 })),
28629
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details" },
28630
+ React__default["default"].createElement("h6", null,
28631
+ firstSegment.location?.name || firstSegment.oord?.name || firstSegment.region?.name,
28632
+ (firstSegment.location?.name || firstSegment.oord?.name || firstSegment.region?.name) && firstSegment.country?.name
28633
+ ? ', '
28634
+ : '',
28635
+ firstSegment.country?.name),
28636
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__segment-details-text" },
28637
+ dateFns.format(new Date(firstSegment.from), 'EEE. d MMM yyyy'),
28638
+ "> ",
28639
+ dateFns.format(new Date(firstSegment.to), 'EEE. d MMM yyyy'))))),
28640
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment" },
28641
+ React__default["default"].createElement("div", { className: `search__filter__itinerary__segment-item ${canEdit(firstSegment) ? 'search__filter__itinerary__segment-item--editable' : ''}`, onClick: () => {
28642
+ if (canEdit(firstSegment) && onEditAccommodation) {
28643
+ onEditAccommodation(group.segments);
28644
+ }
28645
+ } },
28646
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-date search__filter__itinerary__segment-nights" }, firstSegment.serviceType === ACCOMMODATION_SERVICE_TYPE && (React__default["default"].createElement(React__default["default"].Fragment, null,
28647
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__segment-date-date" },
28648
+ React__default["default"].createElement("strong", null, numberOfNights(firstSegment))),
28649
+ React__default["default"].createElement(Icon, { name: "ui-moon", width: 16, height: 16 })))),
28650
+ getSegmentIcon(firstSegment),
28651
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details" },
28652
+ React__default["default"].createElement("h6", null, getSegmentTitle(firstSegment)),
28653
+ firstSegment.serviceType === ACCOMMODATION_SERVICE_TYPE &&
28654
+ group.segments.map((segment, index) => (React__default["default"].createElement(React__default["default"].Fragment, { key: segment.guid },
28655
+ React__default["default"].createElement("strong", null,
28656
+ translations.SHARED.ROOM,
28657
+ "\u00A0",
28658
+ index + 1),
28659
+ segment.productName && segment.accommodationName && (React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details__room" },
28660
+ React__default["default"].createElement(Icon, { name: "ui-bed", width: 12, height: 12 }),
28661
+ segment.accommodationName)),
28662
+ segment.regimeName && (React__default["default"].createElement("div", { className: "search__filter__itinerary__segment-details__room" },
28663
+ React__default["default"].createElement(Icon, { name: "ui-utensils", width: 12, height: 12 }),
28664
+ segment.regimeName)))))))))));
28665
+ }),
28666
+ returnFlight && returnFlight !== outboundFlight && (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport" },
28667
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
28668
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
28669
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-item" },
28670
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-date" },
28671
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-date-date" },
28672
+ React__default["default"].createElement("strong", null, dateFns.format(new Date(returnFlight.from), 'd'))),
28673
+ React__default["default"].createElement("p", null, dateFns.format(new Date(returnFlight.from), 'MMM'))),
28674
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-badge" },
28675
+ React__default["default"].createElement(Icon, { name: "ui-plane", height: 15 })),
28676
+ React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-details" },
28677
+ React__default["default"].createElement("h6", null, returnFlight.productName),
28678
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-plane" },
28679
+ React__default["default"].createElement("span", null,
28680
+ React__default["default"].createElement(Icon, { name: "ui-plane-depart", height: 14 }),
28681
+ " ",
28682
+ React__default["default"].createElement("strong", null, getDepartureTime(returnFlight))),
28683
+ ' ',
28684
+ "-",
28685
+ ' ',
28686
+ React__default["default"].createElement("span", null,
28687
+ React__default["default"].createElement(Icon, { name: "ui-plane-arrive", height: 14 }),
28688
+ " ",
28689
+ React__default["default"].createElement("strong", null, getArrivalTime(returnFlight)))),
28690
+ React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" },
28691
+ React__default["default"].createElement("span", null,
28692
+ React__default["default"].createElement(Icon, { name: "ui-clock", height: 20 }),
28693
+ " ",
28694
+ getDuration(returnFlight))))))))),
28066
28695
  lastEntryLine && (React__default["default"].createElement("div", { className: "search__filter__itinerary__country" },
28067
28696
  React__default["default"].createElement("div", { className: "search__filter__itinerary__country-icon" },
28068
28697
  React__default["default"].createElement(Icon, { name: "ui-flag", width: 17.5, height: 20 })),
@@ -30625,181 +31254,6 @@ const ExcursionDetails = () => {
30625
31254
  React__default["default"].createElement("button", { type: "button", className: "cta cta--primary", onClick: handleConfirm }, translations?.QSM.CONFIRM))));
30626
31255
  };
30627
31256
 
30628
- const REGULAR_TRAJECT_NODE_TYPE = 0;
30629
- const isSearchableTrajectNode = (node) => node.serviceType === ACCOMMODATION_SERVICE_TYPE || node.serviceType === EXCURSION_SERVICE_TYPE;
30630
- const isTrajectFlightNode = (node) => node.serviceType === FLIGHT_SERVICE_TYPE;
30631
- const getTrajectNodesWithLines = (trajectEntry) => {
30632
- const linesByGuid = new Map((trajectEntry.entry.lines ?? []).map((line) => [line.guid, line]));
30633
- return [...(trajectEntry.nodes ?? [])]
30634
- .sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
30635
- .map((node) => {
30636
- const guids = node.lineGuids?.length ? node.lineGuids : [node.lineGuid];
30637
- const lines = guids.map((guid) => linesByGuid.get(guid)).filter((x) => !!x);
30638
- return { node, line: lines[0], lines };
30639
- })
30640
- .filter((x) => !!x.line);
30641
- };
30642
- const buildDestination = (line) => {
30643
- if (line.location?.id)
30644
- return { id: line.location.id, isLocation: true };
30645
- if (line.oord?.id)
30646
- return { id: line.oord.id, isOord: true };
30647
- if (line.region?.id)
30648
- return { id: line.region.id, isRegion: true };
30649
- if (line.country?.id)
30650
- return { id: line.country.id, isCountry: true };
30651
- if (line.latitude && line.longitude)
30652
- return { latitude: line.latitude, longitude: line.longitude };
30653
- return { id: 0 };
30654
- };
30655
- const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
30656
- transactionId: context.transactionId,
30657
- officeId: context.officeId,
30658
- agentId: context.agentId ?? null,
30659
- catalogueId: context.catalogueId,
30660
- searchConfigurationId: context.searchConfigurationId,
30661
- portalId: context.portalId ?? null,
30662
- vendorConfigurationId: node.externalVendorId ?? null,
30663
- language: context.language,
30664
- serviceType: node.serviceType,
30665
- fromDate: toDateOnlyString(line.from),
30666
- toDate: toDateOnlyString(line.to),
30667
- destination: buildDestination(line),
30668
- productCode,
30669
- rooms: context.rooms,
30670
- tagIds: []
30671
- });
30672
- const getNodeCandidates = (node) => {
30673
- const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
30674
- if (configured.length)
30675
- return configured;
30676
- const fallbackCode = node.code ?? node.preferredAccommodationCode;
30677
- if (!fallbackCode || !fallbackCode.trim().length)
30678
- return [];
30679
- return [
30680
- {
30681
- code: fallbackCode,
30682
- name: node.name,
30683
- description: node.description,
30684
- imageUrl: node.imageUrl,
30685
- contentSource: node.contentSource,
30686
- vendor: node.vendor,
30687
- externalVendorId: node.externalVendorId,
30688
- isPreferred: true
30689
- }
30690
- ];
30691
- };
30692
- const findCandidateForResult = (node, result) => getNodeCandidates(node).find((candidate) => matchesCode(result, candidate.code)) ?? null;
30693
- const matchesCode = (result, code) => {
30694
- if (result.code === code)
30695
- return true;
30696
- return (result.rooms ?? []).some((room) => (room.options ?? []).some((option) => option.accommodationCode === code));
30697
- };
30698
- const getPackagingRoomsFromEntry = (entry) => {
30699
- const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));
30700
- const rooms = (entry.rooms ?? []).map((room) => ({
30701
- travellers: (room.paxIds ?? []).map((paxId) => {
30702
- const pax = paxById.get(paxId);
30703
- return {
30704
- id: paxId,
30705
- age: pax?.age ?? null,
30706
- dateOfBirth: pax?.dateOfBirth ?? null
30707
- };
30708
- })
30709
- }));
30710
- return rooms.filter((room) => room.travellers.length > 0);
30711
- };
30712
- const pickCheapest = (results) => [...results].sort((a, b) => a.price - b.price)[0] ?? null;
30713
- const applyResultToLines = (lines, result) => lines.map((line, index) => applyResultToLine(line, result, index));
30714
- const getOptionForRoom = (result, roomIndex) => {
30715
- const room = (result.rooms ?? [])[roomIndex];
30716
- if (room)
30717
- return (room.options ?? []).find((x) => x.isSelected) ?? (room.options ?? [])[0];
30718
- return (result.rooms ?? []).flatMap((x) => x.options ?? []).find((x) => x.isSelected) ?? (result.rooms ?? [])[0]?.options?.[0];
30719
- };
30720
- const applyResultToLine = (line, result, roomIndex = 0) => {
30721
- const option = getOptionForRoom(result, roomIndex);
30722
- return {
30723
- ...line,
30724
- productName: result.name ?? line.productName,
30725
- productCode: result.code ?? line.productCode,
30726
- accommodationCode: option?.accommodationCode ?? line.accommodationCode,
30727
- accommodationName: option?.accommodationName ?? line.accommodationName,
30728
- regimeCode: option?.regimeCode ?? line.regimeCode,
30729
- regimeName: option?.regimeName ?? line.regimeName,
30730
- latitude: result.latitude ?? line.latitude,
30731
- longitude: result.longitude ?? line.longitude,
30732
- isChanged: true
30733
- };
30734
- };
30735
- const toDateOnlyUtcString = (value) => {
30736
- const date = new Date(value);
30737
- return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
30738
- };
30739
- const toTimeOnlyString = (value) => {
30740
- const date = new Date(value);
30741
- const hh = String(date.getUTCHours()).padStart(2, '0');
30742
- const mm = String(date.getUTCMinutes()).padStart(2, '0');
30743
- const ss = String(date.getUTCSeconds()).padStart(2, '0');
30744
- return `${hh}:${mm}:${ss}`;
30745
- };
30746
- const mapFlightSegmentsToFlightLines = (segments) => segments.map((segment) => ({
30747
- airlineCode: segment.marketingAirlineCode,
30748
- airlineDescription: segment.marketingAirlineName,
30749
- operatingAirlineCode: segment.operatingAirlineCode,
30750
- operatingAirlineDescription: segment.operatingAirlineName,
30751
- flightNumber: segment.flightNumber,
30752
- operatingFlightNumber: segment.operatingFlightNumber ?? null,
30753
- departureDate: toDateOnlyUtcString(segment.departureDateTime),
30754
- departureTime: toTimeOnlyString(segment.departureDateTime),
30755
- departureAirportCode: segment.departureAirportCode,
30756
- departureAirportDescription: segment.departureAirportName,
30757
- arrivalDate: toDateOnlyUtcString(segment.arrivalDateTime),
30758
- arrivalTime: toTimeOnlyString(segment.arrivalDateTime),
30759
- arrivalAirportCode: segment.arrivalAirportCode,
30760
- arrivalAirportDescription: segment.arrivalAirportName,
30761
- durationInTicks: segment.durationInTicks
30762
- }));
30763
- const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
30764
- transactionId: context.transactionId,
30765
- officeId: context.officeId,
30766
- catalogueId: context.catalogueId,
30767
- agentId: context.agentId ?? null,
30768
- language: context.language,
30769
- departureAirportCode: node.departureAirportCode ?? '',
30770
- arrivalAirportCode: node.arrivalAirportCode ?? '',
30771
- returnAirportCode: null,
30772
- luggageIncluded: null,
30773
- maxStops: null,
30774
- travelClass: null,
30775
- vendorConfigurationId: node.externalVendorId ?? null,
30776
- pax,
30777
- outward: { date: dateToDateStruct(new Date(line.from)) },
30778
- return: null
30779
- });
30780
- const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
30781
- const applyFlightToLine = (line, flight) => {
30782
- const segments = flight.outward?.segments ?? [];
30783
- if (!segments.length)
30784
- return line;
30785
- const firstSegment = segments[0];
30786
- const lastSegment = segments[segments.length - 1];
30787
- return {
30788
- ...line,
30789
- from: new Date(firstSegment.departureDateTime).toISOString(),
30790
- to: new Date(lastSegment.arrivalDateTime).toISOString(),
30791
- productName: `${firstSegment.departureAirportName} - ${lastSegment.arrivalAirportName} (${firstSegment.marketingAirlineName})`,
30792
- productCode: `${firstSegment.departureAirportCode} ${lastSegment.arrivalAirportCode}/${firstSegment.marketingAirlineCode}`,
30793
- accommodationName: firstSegment.metaData?.farePriceClassName ?? line.accommodationName,
30794
- accommodationCode: firstSegment.metaData?.fareCode ?? line.accommodationCode,
30795
- flightInformation: {
30796
- pnr: '',
30797
- flightLines: mapFlightSegmentsToFlightLines(segments)
30798
- },
30799
- isChanged: true
30800
- };
30801
- };
30802
-
30803
31257
  const getLocation = (result) => {
30804
31258
  const place = result.locationName || result.regionName || result.oordName;
30805
31259
  if (!place)
@@ -30814,13 +31268,12 @@ const toPlainText = (value) => {
30814
31268
  .replace(/\s+/g, ' ')
30815
31269
  .trim();
30816
31270
  };
30817
- const TrajectNodeCard = ({ item, result, isSelected, languageCode, translations, onSelect, onEditOptions, showNights }) => {
30818
- const { node } = item;
31271
+ const TrajectNodeCard = ({ node, result, isSelected, languageCode, translations, onSelect, onEditOptions, showNights, selectLabel, selectedLabel }) => {
30819
31272
  const selectedPerRoom = (result.rooms ?? []).map((room) => (room.options ?? []).find((x) => x.isSelected) ?? (room.options ?? [])[0]);
30820
31273
  const isMultiRoom = selectedPerRoom.length > 1;
30821
31274
  const price = formatPrice$3(result.price, result.currencyCode, languageCode);
30822
31275
  const nights = calculateNights(new Date(result.fromDate), new Date(result.toDate));
30823
- const candidate = findCandidateForResult(node, result);
31276
+ const candidate = node ? findCandidateForResult(node, result) : null;
30824
31277
  const image = candidate?.imageUrl ?? null;
30825
31278
  const description = toPlainText(candidate?.description);
30826
31279
  const title = candidate?.name ?? result.name;
@@ -30829,7 +31282,7 @@ const TrajectNodeCard = ({ item, result, isSelected, languageCode, translations,
30829
31282
  React__default["default"].createElement("span", { className: "search__result-card__price" }, price)));
30830
31283
  const canEditOptions = isSelected && !!onEditOptions && (result.rooms ?? []).some((room) => (room.options ?? []).length > 1);
30831
31284
  const selectButton = (React__default["default"].createElement(React__default["default"].Fragment, null,
30832
- React__default["default"].createElement("button", { type: "button", className: `cta ${isSelected ? 'cta--selected' : 'cta--select'}`, onClick: onSelect }, isSelected ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT),
31285
+ React__default["default"].createElement("button", { type: "button", className: `cta ${isSelected ? 'cta--selected' : 'cta--select'}`, onClick: onSelect }, isSelected ? selectedLabel ?? translations?.SHARED.SELECTED : selectLabel ?? translations?.SHARED.SELECT),
30833
31286
  canEditOptions && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: onEditOptions },
30834
31287
  translations?.SRP.SELECT,
30835
31288
  " ",
@@ -30909,7 +31362,112 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
30909
31362
  ordered.length,
30910
31363
  "\u00A0",
30911
31364
  translations.SRP.TOTAL_RESULTS_LABEL)),
30912
- ordered.length === 0 ? (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--compact" }, ordered.map((result) => (React__default["default"].createElement(TrajectNodeCard, { key: result.code, item: item, result: result, isSelected: result.code === availability?.selectedCode, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(result.code), showNights: item.node.serviceType === ACCOMMODATION_SERVICE_TYPE })))))));
31365
+ ordered.length === 0 ? (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default["default"].createElement("div", { className: "search__results__cards" }, ordered.map((result) => (React__default["default"].createElement(TrajectNodeCard, { key: result.code, node: item.node, result: result, isSelected: result.code === availability?.selectedCode, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(result.code), showNights: item.node.serviceType === ACCOMMODATION_SERVICE_TYPE })))))));
31366
+ };
31367
+
31368
+ /**
31369
+ * Every flight found for one traject leg, shown in the fly-in.
31370
+ *
31371
+ * A one-way search can return far more options than belong in the results column, so the column
31372
+ * keeps three and hands the rest to this list — the same shape the regular flight results use.
31373
+ * Each leg is searched on its own, so the single leg of a result always sits in `outward`.
31374
+ */
31375
+ const TrajectFlightsFlyIn = ({ isLoading }) => {
31376
+ const context = React.useContext(SearchResultsConfigurationContext);
31377
+ const dispatch = reactRedux.useDispatch();
31378
+ const translations = getTranslations(context?.languageCode ?? 'en-GB');
31379
+ const { trajectFlightAvailability, trajectEditLineGuid, flightsLoading } = reactRedux.useSelector((state) => state.searchResults);
31380
+ const trajectEntry = context?.trajectEntry;
31381
+ const item = React.useMemo(() => {
31382
+ if (!trajectEntry || !trajectEditLineGuid)
31383
+ return null;
31384
+ return getTrajectNodesWithLines(trajectEntry).find((x) => x.line.guid === trajectEditLineGuid) ?? null;
31385
+ }, [trajectEntry, trajectEditLineGuid]);
31386
+ if (!context || !item)
31387
+ return null;
31388
+ const availability = trajectFlightAvailability[item.line.guid];
31389
+ const flights = availability?.results ?? [];
31390
+ const selectedGuid = availability?.selectedGuid;
31391
+ const selected = flights.find((x) => x.outwardGuid === selectedGuid) ?? null;
31392
+ const handleSelect = (outwardGuid) => {
31393
+ const flight = flights.find((x) => x.outwardGuid === outwardGuid);
31394
+ if (!flight)
31395
+ return;
31396
+ dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
31397
+ dispatch(updateEditableEntryLine(applyFlightToLine(item.line, flight)));
31398
+ dispatch(setTrajectEditLineGuid(null));
31399
+ dispatch(setFlyInIsOpen(false));
31400
+ };
31401
+ if (isLoading || flightsLoading) {
31402
+ return React__default["default"].createElement(React__default["default"].Fragment, null, context.customSpinner ?? React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_FLIGHTS }));
31403
+ }
31404
+ // The picked flight stays at the top; the rest follow by price.
31405
+ const ordered = [...flights].sort((a, b) => {
31406
+ if (a.outwardGuid === selectedGuid)
31407
+ return -1;
31408
+ if (b.outwardGuid === selectedGuid)
31409
+ return 1;
31410
+ return a.price - b.price;
31411
+ });
31412
+ return (React__default["default"].createElement("div", { className: "flyin__content" },
31413
+ React__default["default"].createElement("div", { className: "search__result-row" },
31414
+ React__default["default"].createElement("span", { className: "search__result-row-text" },
31415
+ ordered.length,
31416
+ "\u00A0",
31417
+ translations.SRP.TOTAL_RESULTS_LABEL)),
31418
+ ordered.length === 0 ? (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--extended" }, ordered.map((result) => (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, selectedGuid: selectedGuid ?? undefined, isOutward: true, showSelectedState: true, price: result.price, currentSelectedPrice: selected?.price, onSelect: result.outwardGuid === selectedGuid ? undefined : () => handleSelect(result.outwardGuid) })))))));
31419
+ };
31420
+
31421
+ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
31422
+ const context = React.useContext(SearchResultsConfigurationContext);
31423
+ const dispatch = reactRedux.useDispatch();
31424
+ const translations = getTranslations(context?.languageCode ?? 'en-GB');
31425
+ const { trajectNodeAvailability, trajectDaySuggestions, trajectActivitiesDayOrder, editablePackagingEntry } = reactRedux.useSelector((state) => state.searchResults);
31426
+ const trajectEntry = context?.trajectEntry;
31427
+ const items = React.useMemo(() => {
31428
+ if (!trajectEntry || trajectActivitiesDayOrder === null)
31429
+ return [];
31430
+ return getTrajectNodesWithLines(trajectEntry).filter(({ node }) => node.dayOrder === trajectActivitiesDayOrder && node.trajectNodeType === REGULAR_TRAJECT_NODE_TYPE && node.serviceType === EXCURSION_SERVICE_TYPE);
31431
+ }, [trajectEntry, trajectActivitiesDayOrder]);
31432
+ if (!context || trajectActivitiesDayOrder === null)
31433
+ return null;
31434
+ const suggestions = trajectDaySuggestions[trajectActivitiesDayOrder];
31435
+ const cards = buildDayActivityCards(items, trajectNodeAvailability, suggestions?.results ?? []);
31436
+ const getAddedLines = (result) => (editablePackagingEntry?.lines ?? []).filter((line) => line.serviceType === EXCURSION_SERVICE_TYPE && line.productCode === result.code && dateFns.isSameDay(new Date(line.from), new Date(result.fromDate)));
31437
+ /** Adding is not a decision that ends the list — the traveller may want several. */
31438
+ const handleToggle = (result) => {
31439
+ const added = getAddedLines(result);
31440
+ if (added.length) {
31441
+ dispatch(removeEditableEntryLines(added.map((line) => line.guid)));
31442
+ return;
31443
+ }
31444
+ const lines = buildTrajectExcursionLines(result);
31445
+ if (lines.length)
31446
+ dispatch(addEditableEntryLines(lines));
31447
+ };
31448
+ /** Swapping what the traject books is one decision, so the list closes behind it. */
31449
+ const handleSelect = ({ result, item }) => {
31450
+ if (!item)
31451
+ return;
31452
+ dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code: result.code }));
31453
+ applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
31454
+ dispatch(setTrajectActivitiesDayOrder(null));
31455
+ dispatch(setFlyInIsOpen(false));
31456
+ };
31457
+ if (isLoading || suggestions?.status === 'loading') {
31458
+ return React__default["default"].createElement(React__default["default"].Fragment, null, context.customSpinner ?? React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_EXCURSIONS }));
31459
+ }
31460
+ return (React__default["default"].createElement("div", { className: "flyin__content" },
31461
+ React__default["default"].createElement("div", { className: "search__result-row" },
31462
+ React__default["default"].createElement("span", { className: "search__result-row-text" },
31463
+ cards.length,
31464
+ "\u00A0",
31465
+ translations.SRP.TOTAL_RESULTS_LABEL)),
31466
+ cards.length === 0 ? (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default["default"].createElement("div", { className: "search__results__cards" }, cards.map((card) => {
31467
+ const { result, item } = card;
31468
+ const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedLines(result).length > 0;
31469
+ return (React__default["default"].createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(card) : handleToggle(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? undefined : translations.SRP.REMOVE }));
31470
+ })))));
30913
31471
  };
30914
31472
 
30915
31473
  const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, detailsLoading, flyInType, isPackageEditFlow, handleConfirm, sortByTypes, activeSearchSeed, toggleFilters, filtersOpen }) => {
@@ -30984,8 +31542,8 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
30984
31542
  dispatch(setBookPackagingEntry(true));
30985
31543
  }
30986
31544
  };
30987
- return (React__default["default"].createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
30988
- ${flyInType === 'flight-outward-results' || flyInType === 'flight-return-results' ? 'flyin--flight' : ''}` },
31545
+ return (React__default["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' : ''}
31546
+ ${flyInType === 'flight-outward-results' || flyInType === 'flight-return-results' || flyInType === 'traject-flight-results' ? 'flyin--flight' : ''}` },
30989
31547
  React__default["default"].createElement("div", { className: `flyin__panel ${isOpen ? 'flyin__panel--active' : ''}`, ref: panelRef },
30990
31548
  React__default["default"].createElement("div", { className: "flyin__content" },
30991
31549
  React__default["default"].createElement("div", { className: "flyin__content-title-row" },
@@ -31002,6 +31560,8 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
31002
31560
  flyInType === 'flight-return-results' &&
31003
31561
  `${translations.SRP.SELECT} ${translations.FLIGHTS_FORM.RETURN_FLIGHT}`,
31004
31562
  srpType === build.PortalQsmType.AccommodationAndFlight && flyInType === 'flight-details' && 'Select your fare',
31563
+ flyInType === 'traject-flight-results' && `${translations.SRP.SELECT} ${translations.SRP.DEPARTURE}`,
31564
+ flyInType === 'traject-day-activities' && translations.SRP.ACTIVITIES,
31005
31565
  flyInType === 'excursion-results' || (flyInType === 'excursion-details' && 'Select excursion')),
31006
31566
  React__default["default"].createElement("span", { className: "flyin__close", onClick: () => handleClose() },
31007
31567
  React__default["default"].createElement(Icon, { name: "ui-close", width: 30, height: 30, "aria-hidden": "true" }))),
@@ -31011,6 +31571,8 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
31011
31571
  "Go Back")))),
31012
31572
  srpType === build.PortalQsmType.Flight && React__default["default"].createElement(FlightsFlyIn, { isOpen: isOpen, setIsOpen: setIsOpen }),
31013
31573
  context?.trajectEntry && flyInType === 'acco-results' && React__default["default"].createElement(TrajectResultsFlyIn, { isLoading: detailsLoading }),
31574
+ context?.trajectEntry && flyInType === 'traject-flight-results' && React__default["default"].createElement(TrajectFlightsFlyIn, { isLoading: detailsLoading }),
31575
+ context?.trajectEntry && flyInType === 'traject-day-activities' && React__default["default"].createElement(TrajectDayActivitiesFlyIn, { isLoading: detailsLoading }),
31014
31576
  !context?.trajectEntry &&
31015
31577
  (srpType === build.PortalQsmType.Accommodation || srpType === build.PortalQsmType.AccommodationAndFlight) &&
31016
31578
  flyInType === 'acco-results' && (React__default["default"].createElement("div", { className: "flyin__content flyin__content--columns" },
@@ -33295,14 +33857,17 @@ const getNodeIcon = (node) => {
33295
33857
  return 'ui-bed';
33296
33858
  return 'ui-location';
33297
33859
  };
33860
+ const isRenderableNode = (node) => node.trajectNodeType === REGULAR_TRAJECT_NODE_TYPE &&
33861
+ (node.serviceType === ACCOMMODATION_SERVICE_TYPE || node.serviceType === EXCURSION_SERVICE_TYPE || node.serviceType === FLIGHT_SERVICE_TYPE);
33862
+ const MAX_DAY_ACTIVITIES = 6;
33298
33863
  const TrajectResults = ({ isLoading }) => {
33299
33864
  const context = React.useContext(SearchResultsConfigurationContext);
33300
33865
  const dispatch = reactRedux.useDispatch();
33301
33866
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
33302
33867
  const locale = getLocale(context?.languageCode ?? 'en-GB');
33303
- const { trajectNodeAvailability, trajectFlightAvailability } = reactRedux.useSelector((state) => state.searchResults);
33304
- const [expandedNodes, setExpandedNodes] = React.useState({});
33868
+ const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry } = reactRedux.useSelector((state) => state.searchResults);
33305
33869
  const trajectEntry = context?.trajectEntry;
33870
+ const hideShowMoreResults = !!context?.hideShowMoreResults;
33306
33871
  const nodesWithLines = React.useMemo(() => (trajectEntry ? getTrajectNodesWithLines(trajectEntry) : []), [trajectEntry]);
33307
33872
  const lineByNodeId = React.useMemo(() => new Map(nodesWithLines.map((x) => [x.node.nodeId, x])), [nodesWithLines]);
33308
33873
  const nodesByDay = React.useMemo(() => {
@@ -33316,9 +33881,22 @@ const TrajectResults = ({ isLoading }) => {
33316
33881
  });
33317
33882
  return map;
33318
33883
  }, [trajectEntry]);
33884
+ const { stayByDay, stayStartByNodeId } = React.useMemo(() => {
33885
+ const byDay = new Map();
33886
+ const byNodeId = new Map();
33887
+ nodesWithLines
33888
+ .filter((x) => x.node.serviceType === ACCOMMODATION_SERVICE_TYPE)
33889
+ .forEach((item) => {
33890
+ const nights = Math.max(dateFns.differenceInCalendarDays(new Date(item.line.to), new Date(item.line.from)), 1);
33891
+ byNodeId.set(item.node.nodeId, { item, night: 0, nights });
33892
+ for (let night = 0; night < nights; night++) {
33893
+ byDay.set(item.node.dayOrder + night, { item, night, nights });
33894
+ }
33895
+ });
33896
+ return { stayByDay: byDay, stayStartByNodeId: byNodeId };
33897
+ }, [nodesWithLines]);
33319
33898
  if (!context || !trajectEntry)
33320
33899
  return null;
33321
- const toggleExpanded = (lineGuid) => setExpandedNodes((prev) => ({ ...prev, [lineGuid]: !prev[lineGuid] }));
33322
33900
  const handleSelect = (item, code) => {
33323
33901
  const availability = trajectNodeAvailability[item.line.guid];
33324
33902
  const result = availability?.results.find((x) => x.code === code);
@@ -33327,6 +33905,12 @@ const TrajectResults = ({ isLoading }) => {
33327
33905
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
33328
33906
  applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
33329
33907
  };
33908
+ /** The remaining legs for a flight node open in the fly-in, as the regular flight results do. */
33909
+ const handleShowMoreFlights = (item) => {
33910
+ dispatch(setTrajectEditLineGuid(item.line.guid));
33911
+ dispatch(setFlyInType('traject-flight-results'));
33912
+ dispatch(setFlyInIsOpen(true));
33913
+ };
33330
33914
  const handleShowMore = (item) => {
33331
33915
  dispatch(setTrajectEditLineGuid(item.line.guid));
33332
33916
  dispatch(setFlyInType('acco-results'));
@@ -33343,8 +33927,41 @@ const TrajectResults = ({ isLoading }) => {
33343
33927
  dispatch(setFlyInType('acco-details'));
33344
33928
  dispatch(setFlyInIsOpen(true));
33345
33929
  };
33346
- const renderServiceNode = (item) => {
33347
- console.log('renderServiceNode', item);
33930
+ const getStayLocation = (item) => {
33931
+ const availability = trajectNodeAvailability[item.line.guid];
33932
+ const result = availability?.results.find((x) => x.code === availability?.selectedCode);
33933
+ return (result?.locationName ||
33934
+ result?.oordName ||
33935
+ result?.regionName ||
33936
+ result?.countryName ||
33937
+ item.line.location?.name ||
33938
+ item.line.oord?.name ||
33939
+ item.line.region?.name ||
33940
+ item.line.country?.name ||
33941
+ item.node.alternatives?.find((x) => x.isPreferred)?.city ||
33942
+ '');
33943
+ };
33944
+ const getStayName = (item) => {
33945
+ const availability = trajectNodeAvailability[item.line.guid];
33946
+ const result = availability?.results.find((x) => x.code === availability?.selectedCode);
33947
+ return result?.name || item.node.preferredAccommodationName || item.node.name || '';
33948
+ };
33949
+ const getStayTitle = (stay) => [getStayLocation(stay.item), getStayName(stay.item), `${stay.night + 1} ${translations.SRP.OF} ${stay.nights} ${translations.SRP.NIGHTS}`]
33950
+ .filter(Boolean)
33951
+ .join(' - ');
33952
+ const renderDayHeader = (day, stay) => {
33953
+ const date = new Date(day.date);
33954
+ const title = stay ? getStayTitle(stay) : day.name;
33955
+ return (React__default["default"].createElement("div", { className: "search__results__label search__results__label--secondary" },
33956
+ React__default["default"].createElement("div", { className: "search__results__label__date" },
33957
+ React__default["default"].createElement("p", { className: "search__results__label__date-date" }, dateFns.format(date, 'd', { locale })),
33958
+ React__default["default"].createElement("p", null, dateFns.format(date, 'MMM', { locale }))),
33959
+ React__default["default"].createElement("div", { className: "search__results__label__text" },
33960
+ React__default["default"].createElement(Icon, { name: stay ? 'ui-bed' : 'ui-location', height: 16 }),
33961
+ React__default["default"].createElement("h3", null,
33962
+ React__default["default"].createElement("strong", null, title)))));
33963
+ };
33964
+ const renderServiceNode = (item, showHeader = true, headerTitle) => {
33348
33965
  const { node, line } = item;
33349
33966
  const availability = trajectNodeAvailability[line.guid];
33350
33967
  const results = availability?.results ?? [];
@@ -33354,12 +33971,14 @@ const TrajectResults = ({ isLoading }) => {
33354
33971
  // No entry yet means the node's search has been queued but not dispatched — still loading.
33355
33972
  const status = availability?.status ?? 'loading';
33356
33973
  return (React__default["default"].createElement(React__default["default"].Fragment, { key: line.guid },
33357
- React__default["default"].createElement("div", { className: "search__results__label search__results__label--secondary" },
33974
+ showHeader && (React__default["default"].createElement("div", { className: "search__results__label search__results__label--secondary" },
33358
33975
  React__default["default"].createElement("div", { className: "search__results__label__date" },
33359
33976
  React__default["default"].createElement("p", { className: "search__results__label__date-date" }, dateFns.format(new Date(line.from), 'd', { locale })),
33360
33977
  React__default["default"].createElement("p", null, dateFns.format(new Date(line.from), 'MMM', { locale }))),
33361
33978
  React__default["default"].createElement("div", { className: "search__results__label__text" },
33362
- React__default["default"].createElement(Icon, { name: getNodeIcon(node), height: 16 }))),
33979
+ React__default["default"].createElement(Icon, { name: getNodeIcon(node), height: 16 }),
33980
+ React__default["default"].createElement("h3", null,
33981
+ React__default["default"].createElement("strong", null, headerTitle || node.name))))),
33363
33982
  status === 'loading' && (React__default["default"].createElement(Spinner, { label: node.serviceType === EXCURSION_SERVICE_TYPE ? translations.SRP.LOADING_EXCURSIONS : translations.SRP.LOADING_ACCOMMODATIONS })),
33364
33983
  status === 'unavailable' && React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
33365
33984
  status === 'resolved' && selected && (React__default["default"].createElement(React__default["default"].Fragment, null,
@@ -33368,8 +33987,8 @@ const TrajectResults = ({ isLoading }) => {
33368
33987
  node.preferredAccommodationName,
33369
33988
  " \u2014 ",
33370
33989
  translations.SRP.NO_RESULTS))),
33371
- React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--compact" }, [selected, ...configured].map((result) => (React__default["default"].createElement(TrajectNodeCard, { key: result.code, item: item, 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 })))),
33372
- others.length > 0 && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
33990
+ React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured].map((result) => (React__default["default"].createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE })))),
33991
+ others.length > 0 && !hideShowMoreResults && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
33373
33992
  React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
33374
33993
  translations.SRP.SHOW_MORE,
33375
33994
  " (",
@@ -33387,8 +34006,7 @@ const TrajectResults = ({ isLoading }) => {
33387
34006
  const flights = availability?.results ?? [];
33388
34007
  const selected = flights.find((x) => x.outwardGuid === availability?.selectedGuid) ?? null;
33389
34008
  const others = flights.filter((x) => x.outwardGuid !== availability?.selectedGuid);
33390
- const isExpanded = !!expandedNodes[line.guid];
33391
- const visible = isExpanded ? others : others.slice(0, 2);
34009
+ const visible = others.slice(0, 2);
33392
34010
  return (React__default["default"].createElement(React__default["default"].Fragment, { key: line.guid },
33393
34011
  React__default["default"].createElement("div", { className: "search__results__label search__results__label--secondary" },
33394
34012
  React__default["default"].createElement("div", { className: "search__results__label__date" },
@@ -33409,28 +34027,109 @@ const TrajectResults = ({ isLoading }) => {
33409
34027
  React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--extended" },
33410
34028
  React__default["default"].createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price }),
33411
34029
  visible.map((result) => (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected.price, onSelect: () => handleSelectFlight(item, result) })))),
33412
- others.length > 2 && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
33413
- React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => toggleExpanded(line.guid) }, isExpanded ? translations.SRP.SHOW_LESS : `${translations.SRP.SHOW_MORE} (${others.length - 2})`)))))));
34030
+ others.length > 2 && !hideShowMoreResults && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
34031
+ React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreFlights(item) },
34032
+ translations.SRP.SHOW_MORE,
34033
+ " (",
34034
+ others.length - 2,
34035
+ ")")))))));
34036
+ };
34037
+ /** The lines a suggested activity put on the entry, which is also how we know it was added. */
34038
+ const getAddedExcursionLines = (result) => (editablePackagingEntry?.lines ?? []).filter((line) => line.serviceType === EXCURSION_SERVICE_TYPE && line.productCode === result.code && dateFns.isSameDay(new Date(line.from), new Date(result.fromDate)));
34039
+ const handleToggleActivity = (result) => {
34040
+ const added = getAddedExcursionLines(result);
34041
+ if (added.length) {
34042
+ dispatch(removeEditableEntryLines(added.map((line) => line.guid)));
34043
+ return;
34044
+ }
34045
+ const lines = buildTrajectExcursionLines(result);
34046
+ if (lines.length)
34047
+ dispatch(addEditableEntryLines(lines));
34048
+ };
34049
+ const handleShowMoreActivities = (dayOrder) => {
34050
+ dispatch(setTrajectActivitiesDayOrder(dayOrder));
34051
+ dispatch(setFlyInType('traject-day-activities'));
34052
+ dispatch(setFlyInIsOpen(true));
34053
+ };
34054
+ /** The excursion nodes the traject itself puts on a day. */
34055
+ const getDayExcursionItems = (dayOrder) => (nodesByDay.get(dayOrder) ?? [])
34056
+ .filter((node) => node.trajectNodeType === REGULAR_TRAJECT_NODE_TYPE && node.serviceType === EXCURSION_SERVICE_TYPE)
34057
+ .map((node) => lineByNodeId.get(node.nodeId))
34058
+ .filter((x) => !!x);
34059
+ /**
34060
+ * One block per day for everything there is to do that day.
34061
+ *
34062
+ * What the traject books sits first and stays selected; the rest of the day follows as things
34063
+ * the traveller may add. They share a row because they answer the same question — an excursion
34064
+ * on the traject and one found for the day are alternatives to each other, and a block apiece
34065
+ * would only hide that.
34066
+ */
34067
+ const renderDayActivities = (day) => {
34068
+ const items = getDayExcursionItems(day.order);
34069
+ const suggestions = trajectDaySuggestions[day.order];
34070
+ const cards = buildDayActivityCards(items, trajectNodeAvailability, suggestions?.results ?? []);
34071
+ const isResolving = items.some((item) => (trajectNodeAvailability[item.line.guid]?.status ?? 'loading') === 'loading') || suggestions?.status === 'loading';
34072
+ // A day with nothing configured and nothing found has nothing to say. A day whose own
34073
+ // excursion came back empty does, so the gap is not passed off as a day without activities.
34074
+ if (!cards.length && !items.length)
34075
+ return null;
34076
+ const visible = cards.slice(0, MAX_DAY_ACTIVITIES);
34077
+ const hidden = cards.length - visible.length;
34078
+ return (React__default["default"].createElement(React__default["default"].Fragment, { key: `activities-${day.order}` },
34079
+ React__default["default"].createElement("div", { className: "search__results__label search__results__label--secondary" },
34080
+ React__default["default"].createElement("div", { className: "search__results__label__date" },
34081
+ React__default["default"].createElement("p", { className: "search__results__label__date-date" }, dateFns.format(new Date(day.date), 'd', { locale })),
34082
+ React__default["default"].createElement("p", null, dateFns.format(new Date(day.date), 'MMM', { locale }))),
34083
+ React__default["default"].createElement("div", { className: "search__results__label__text" },
34084
+ React__default["default"].createElement(Icon, { name: "ui-excursion", height: 16 }),
34085
+ React__default["default"].createElement("h3", null,
34086
+ React__default["default"].createElement("strong", null, translations.SRP.ACTIVITIES)))),
34087
+ isResolving && !cards.length && React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_EXCURSIONS }),
34088
+ !isResolving && !cards.length && React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
34089
+ !!cards.length && (React__default["default"].createElement(React__default["default"].Fragment, null,
34090
+ React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--scroll" }, visible.map(renderActivityCard)),
34091
+ hidden > 0 && !hideShowMoreResults && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
34092
+ React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreActivities(day.order) },
34093
+ translations.SRP.SHOW_MORE,
34094
+ " (",
34095
+ hidden,
34096
+ ")")))))));
34097
+ };
34098
+ /**
34099
+ * An activity the traject books is swapped for another, the way a hotel is; one the traveller
34100
+ * found for themselves is added to the trip or taken back off it.
34101
+ */
34102
+ const renderActivityCard = ({ result, item }) => {
34103
+ const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedExcursionLines(result).length > 0;
34104
+ return (React__default["default"].createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(item, result.code) : handleToggleActivity(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? undefined : translations.SRP.REMOVE }));
33414
34105
  };
33415
34106
  if (isLoading)
33416
34107
  return React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
33417
34108
  return (React__default["default"].createElement(React__default["default"].Fragment, null, trajectEntry.traject.days.map((day) => {
33418
- const dayNodes = nodesByDay.get(day.order) ?? [];
33419
- if (!dayNodes.length)
33420
- return null;
33421
- return (React__default["default"].createElement(React__default["default"].Fragment, { key: `day-${day.order}` }, dayNodes.map((node) => {
33422
- if (node.serviceType !== ACCOMMODATION_SERVICE_TYPE && node.serviceType !== EXCURSION_SERVICE_TYPE && node.serviceType !== FLIGHT_SERVICE_TYPE)
33423
- return null;
33424
- // if (node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE) return null;
33425
- // if (node.trajectNodeType !== REGULAR_TRAJECT_NODE_TYPE) return renderContextNode(node);
33426
- if (node.trajectNodeType !== REGULAR_TRAJECT_NODE_TYPE)
33427
- return null;
33428
- const item = lineByNodeId.get(node.nodeId);
33429
- // if (!item) return renderContextNode(node);
33430
- if (!item)
33431
- return null;
33432
- return isTrajectFlightNode(node) ? renderFlightNode(item) : renderServiceNode(item);
33433
- })));
34109
+ const stay = stayByDay.get(day.order);
34110
+ const dayNodes = (nodesByDay.get(day.order) ?? []).filter((node) => isRenderableNode(node) && lineByNodeId.has(node.nodeId));
34111
+ const stayLeadsDay = !!stay && (stay.night > 0 || dayNodes[0]?.nodeId === stay.item.node.nodeId);
34112
+ // Where the day's activities belong in the order: with the first excursion it carries.
34113
+ const firstExcursionNodeId = dayNodes.find((node) => node.serviceType === EXCURSION_SERVICE_TYPE)?.nodeId;
34114
+ const showDayHeader = stayLeadsDay || !!day.name?.trim();
34115
+ return (React__default["default"].createElement(React__default["default"].Fragment, { key: `day-${day.order}` },
34116
+ showDayHeader && renderDayHeader(day, stayLeadsDay ? stay : undefined),
34117
+ dayNodes.map((node) => {
34118
+ const item = lineByNodeId.get(node.nodeId);
34119
+ if (node.serviceType === ACCOMMODATION_SERVICE_TYPE) {
34120
+ const stayStart = stayStartByNodeId.get(node.nodeId);
34121
+ const titledByDayHeader = stayLeadsDay && stay.item.node.nodeId === node.nodeId;
34122
+ return renderServiceNode(item, !titledByDayHeader, stayStart && getStayTitle(stayStart));
34123
+ }
34124
+ // Every excursion the day holds is drawn once, in one block, where the first of
34125
+ // them falls in the order — so the activities still sit between the stay and the
34126
+ // flight that follow them.
34127
+ if (node.serviceType === EXCURSION_SERVICE_TYPE) {
34128
+ return node.nodeId === firstExcursionNodeId ? renderDayActivities(day) : null;
34129
+ }
34130
+ return renderFlightNode(item);
34131
+ }),
34132
+ firstExcursionNodeId === undefined && renderDayActivities(day)));
33434
34133
  })));
33435
34134
  };
33436
34135
 
@@ -33438,7 +34137,8 @@ const useTrajectAvailability = () => {
33438
34137
  const context = React.useContext(SearchResultsConfigurationContext);
33439
34138
  const dispatch = reactRedux.useDispatch();
33440
34139
  const trajectEntry = context?.trajectEntry;
33441
- const showNonPreferredItems = !!context?.showNonPreferredItems;
34140
+ const showApiItems = !!context?.showApiItems;
34141
+ const hideShowMoreResults = !!context?.hideShowMoreResults;
33442
34142
  React.useEffect(() => {
33443
34143
  if (!context || !trajectEntry)
33444
34144
  return;
@@ -33471,7 +34171,8 @@ const useTrajectAvailability = () => {
33471
34171
  const search = item.node.serviceType === EXCURSION_SERVICE_TYPE ? build.searchPackagingExcursions : build.searchPackagingAccommodations;
33472
34172
  dispatch(setTrajectNodeLoading(lineGuid));
33473
34173
  try {
33474
- const candidates = getNodeCandidates(item.node);
34174
+ // With external items switched off the node only looks at products held inside Tide.
34175
+ const candidates = getNodeCandidates(item.node).filter((x) => showApiItems || !isExternalCandidate(x));
33475
34176
  const attempts = await Promise.all(candidates.map(async (candidate) => {
33476
34177
  try {
33477
34178
  const attempt = await search(config, buildTrajectNodeRequest(item, searchContext, candidate.code), controller.signal);
@@ -33488,11 +34189,16 @@ const useTrajectAvailability = () => {
33488
34189
  .filter((x, i, all) => all.findIndex((y) => y.code === x.code) === i);
33489
34190
  const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
33490
34191
  let preferredUnavailable = !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code));
33491
- const destinationResults = showNonPreferredItems
33492
- ? ((await search(config, buildTrajectNodeRequest(item, searchContext, ''), controller.signal)) ?? []).filter((x) => !configuredResults.some((configured) => configured.code === x.code))
33493
- : [];
33494
- const results = [...configuredResults, ...destinationResults];
34192
+ // The destination search exists only to stock the show-more fly-in. With the button hidden
34193
+ // a node is limited to its configured products; if none are available it simply reports so,
34194
+ // rather than quietly substituting a hotel nobody configured.
34195
+ const destinationResults = hideShowMoreResults
34196
+ ? []
34197
+ : ((await search(config, buildTrajectNodeRequest(item, searchContext, ''), controller.signal)) ?? [])
34198
+ .filter((x) => showApiItems || !isExternalResult(x))
34199
+ .filter((x) => !configuredResults.some((configured) => configured.code === x.code));
33495
34200
  const picked = configuredResults[0] ?? pickCheapest(destinationResults);
34201
+ const results = [...configuredResults, ...destinationResults];
33496
34202
  if (!configuredResults.length)
33497
34203
  preferredUnavailable = candidates.length > 0;
33498
34204
  if (controller.signal.aborted)
@@ -33555,7 +34261,7 @@ const useTrajectAvailability = () => {
33555
34261
  dispatch(removeEditableEntryLines(emptyLineGuids));
33556
34262
  })();
33557
34263
  return () => controller.abort();
33558
- }, [trajectEntry, showNonPreferredItems]);
34264
+ }, [trajectEntry, showApiItems, hideShowMoreResults]);
33559
34265
  };
33560
34266
 
33561
34267
  const SearchResultsContainer = ({ onBookingStarted }) => {
@@ -37732,20 +38438,20 @@ function ItineraryMapView({ destinations: propDestinations, adults = 2, dateFrom
37732
38438
  const isStartEnd = dest.isStart || dest.isEnd;
37733
38439
  let iconHtml;
37734
38440
  if (isStartEnd) {
37735
- iconHtml = `
37736
- <div class="map-view__marker map-view__marker--plane">
37737
- <svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
37738
- <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"/>
37739
- </svg>
38441
+ iconHtml = `
38442
+ <div class="map-view__marker map-view__marker--plane">
38443
+ <svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
38444
+ <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"/>
38445
+ </svg>
37740
38446
  </div>`;
37741
38447
  }
37742
38448
  else {
37743
38449
  stopIndex++;
37744
38450
  const imgStyle = dest.imageUrl ? `style="background-image:url('${dest.imageUrl}')"` : '';
37745
- iconHtml = `
37746
- <div class="map-view__marker map-view__marker--stop" ${imgStyle}>
37747
- ${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
37748
- <span class="map-view__marker-badge">${stopIndex}</span>
38451
+ iconHtml = `
38452
+ <div class="map-view__marker map-view__marker--stop" ${imgStyle}>
38453
+ ${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
38454
+ <span class="map-view__marker-badge">${stopIndex}</span>
37749
38455
  </div>`;
37750
38456
  }
37751
38457
  const icon = L.divIcon({