@qite/tide-components 1.0.7 → 1.0.9

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.
@@ -417,6 +417,8 @@ var SRP$f = {
417
417
  DEPARTURE_ASC: "تاريخ المغادرة (الأقرب أولاً)",
418
418
  FILTERS: "عوامل التصفية",
419
419
  SHOW_ITINERARY: "عرض خط سير الرحلة",
420
+ VIEW_FULL_ITINERARY: "عرض خط السير الكامل",
421
+ SHOW_SERVICES: "عرض الخدمات",
420
422
  VIEW_BOOKING: "عرض الحجز",
421
423
  ITINERARY_TITLE: "ملخص رحلتك",
422
424
  DOSSIER_NUMBER: "رقم الملف",
@@ -458,6 +460,7 @@ var SRP$f = {
458
460
  TRAVEL_GROUP: "مجموعة المسافرين",
459
461
  EXCURSION: "رحلة",
460
462
  LOADING_EXCURSIONS: "جارٍ تحميل الرحلات...",
463
+ LOADING_ACTIVITIES: "جارٍ تحميل الأنشطة...",
461
464
  LOADING_FLIGHTS: "جارٍ تحميل الرحلات الجوية...",
462
465
  LOADING_ACCOMMODATIONS: "جارٍ تحميل الإقامات...",
463
466
  LOADING_ITINERARY: "جارٍ تحميل خط سير الرحلة...",
@@ -861,6 +864,8 @@ var SRP$e = {
861
864
  DEPARTURE_ASC: "Afrejsedato (snarest først)",
862
865
  FILTERS: "Filtre",
863
866
  SHOW_ITINERARY: "Vis rejseplan",
867
+ VIEW_FULL_ITINERARY: "Se hele rejseplanen",
868
+ SHOW_SERVICES: "Vis ydelser",
864
869
  VIEW_BOOKING: "Se booking",
865
870
  ITINERARY_TITLE: "Din rejseoversigt",
866
871
  DOSSIER_NUMBER: "Sagsnummer",
@@ -902,6 +907,7 @@ var SRP$e = {
902
907
  TRAVEL_GROUP: "Rejseselskab",
903
908
  EXCURSION: "Udflugt",
904
909
  LOADING_EXCURSIONS: "Indlæser udflugter...",
910
+ LOADING_ACTIVITIES: "Indlæser aktiviteter...",
905
911
  LOADING_FLIGHTS: "Indlæser fly...",
906
912
  LOADING_ACCOMMODATIONS: "Indlæser indkvarteringer...",
907
913
  LOADING_ITINERARY: "Indlæser rejseplan...",
@@ -1309,6 +1315,8 @@ var SRP$d = {
1309
1315
  DEPARTURE_ASC: "Abreisedatum (früheste zuerst)",
1310
1316
  FILTERS: "Filter",
1311
1317
  SHOW_ITINERARY: "Reiseverlauf anzeigen",
1318
+ VIEW_FULL_ITINERARY: "Vollständigen Reiseverlauf ansehen",
1319
+ SHOW_SERVICES: "Leistungen anzeigen",
1312
1320
  VIEW_BOOKING: "Buchung anzeigen",
1313
1321
  ITINERARY_TITLE: "Ihre Reiseübersicht",
1314
1322
  DOSSIER_NUMBER: "Vorgangsnummer",
@@ -1346,6 +1354,7 @@ var SRP$d = {
1346
1354
  TRAVEL_GROUP: "Reisegruppe",
1347
1355
  EXCURSION: "Ausflug",
1348
1356
  LOADING_EXCURSIONS: "Lade Ausflüge...",
1357
+ LOADING_ACTIVITIES: "Lade Aktivitäten...",
1349
1358
  LOADING_FLIGHTS: "Lade Flüge...",
1350
1359
  LOADING_ACCOMMODATIONS: "Lade Unterkünfte...",
1351
1360
  LOADING_ITINERARY: "Lade Reiseverlauf...",
@@ -1757,6 +1766,8 @@ var SRP$c = {
1757
1766
  DEPARTURE_ASC: "Departure date (soonest first)",
1758
1767
  FILTERS: "Filters",
1759
1768
  SHOW_ITINERARY: "Show itinerary",
1769
+ VIEW_FULL_ITINERARY: "View full itinerary",
1770
+ SHOW_SERVICES: "Show services",
1760
1771
  VIEW_BOOKING: "View booking",
1761
1772
  ITINERARY_TITLE: "Your trip summary",
1762
1773
  DOSSIER_NUMBER: "File number",
@@ -1794,6 +1805,7 @@ var SRP$c = {
1794
1805
  TRAVEL_GROUP: "Travel group",
1795
1806
  EXCURSION: "Excursion",
1796
1807
  LOADING_EXCURSIONS: "Loading excursions...",
1808
+ LOADING_ACTIVITIES: "Loading activities...",
1797
1809
  LOADING_FLIGHTS: "Loading flights...",
1798
1810
  LOADING_ACCOMMODATIONS: "Loading accommodations...",
1799
1811
  LOADING_ITINERARY: "Loading itinerary...",
@@ -2201,6 +2213,8 @@ var SRP$b = {
2201
2213
  DEPARTURE_ASC: "Fecha de salida (más próxima primero)",
2202
2214
  FILTERS: "Filtros",
2203
2215
  SHOW_ITINERARY: "Mostrar itinerario",
2216
+ VIEW_FULL_ITINERARY: "Ver itinerario completo",
2217
+ SHOW_SERVICES: "Ver servicios",
2204
2218
  VIEW_BOOKING: "Ver reserva",
2205
2219
  ITINERARY_TITLE: "Resumen de tu viaje",
2206
2220
  DOSSIER_NUMBER: "Número de expediente",
@@ -2238,6 +2252,7 @@ var SRP$b = {
2238
2252
  TRAVEL_GROUP: "Grupo de viaje",
2239
2253
  EXCURSION: "Excursión",
2240
2254
  LOADING_EXCURSIONS: "Cargando excursiones...",
2255
+ LOADING_ACTIVITIES: "Cargando actividades...",
2241
2256
  LOADING_FLIGHTS: "Cargando vuelos...",
2242
2257
  LOADING_ACCOMMODATIONS: "Cargando alojamientos...",
2243
2258
  LOADING_ITINERARY: "Cargando itinerario...",
@@ -2649,6 +2664,8 @@ var SRP$a = {
2649
2664
  DEPARTURE_ASC: "Date de départ (la plus proche d’abord)",
2650
2665
  FILTERS: "Filtres",
2651
2666
  SHOW_ITINERARY: "Afficher l’itinéraire",
2667
+ VIEW_FULL_ITINERARY: "Voir l'itinéraire complet",
2668
+ SHOW_SERVICES: "Voir les services",
2652
2669
  VIEW_BOOKING: "Voir la réservation",
2653
2670
  ITINERARY_TITLE: "Résumé de votre voyage",
2654
2671
  DOSSIER_NUMBER: "Numéro de dossier",
@@ -2686,6 +2703,7 @@ var SRP$a = {
2686
2703
  TRAVEL_GROUP: "Groupe de voyageurs",
2687
2704
  EXCURSION: "Excursion",
2688
2705
  LOADING_EXCURSIONS: "Chargement des excursions...",
2706
+ LOADING_ACTIVITIES: "Chargement des activités...",
2689
2707
  LOADING_FLIGHTS: "Chargement des vols...",
2690
2708
  LOADING_ACCOMMODATIONS: "Chargement des hébergements...",
2691
2709
  LOADING_ITINERARY: "Chargement de l’itinéraire...",
@@ -3093,6 +3111,8 @@ var SRP$9 = {
3093
3111
  DEPARTURE_ASC: "Date de départ (la plus proche d’abord)",
3094
3112
  FILTERS: "Filtres",
3095
3113
  SHOW_ITINERARY: "Afficher l’itinéraire",
3114
+ VIEW_FULL_ITINERARY: "Voir l'itinéraire complet",
3115
+ SHOW_SERVICES: "Voir les services",
3096
3116
  VIEW_BOOKING: "Voir la réservation",
3097
3117
  ITINERARY_TITLE: "Résumé de votre voyage",
3098
3118
  DOSSIER_NUMBER: "Numéro de dossier",
@@ -3130,6 +3150,7 @@ var SRP$9 = {
3130
3150
  TRAVEL_GROUP: "Groupe de voyageurs",
3131
3151
  EXCURSION: "Excursion",
3132
3152
  LOADING_EXCURSIONS: "Chargement des excursions...",
3153
+ LOADING_ACTIVITIES: "Chargement des activités...",
3133
3154
  LOADING_FLIGHTS: "Chargement des vols...",
3134
3155
  LOADING_ACCOMMODATIONS: "Chargement des hébergements...",
3135
3156
  LOADING_ITINERARY: "Chargement de l’itinéraire...",
@@ -3537,6 +3558,8 @@ var SRP$8 = {
3537
3558
  DEPARTURE_ASC: "Brottfarardagur (nærst fyrst)",
3538
3559
  FILTERS: "Síur",
3539
3560
  SHOW_ITINERARY: "Sýna ferðaráætlun",
3561
+ VIEW_FULL_ITINERARY: "Skoða alla ferðaáætlunina",
3562
+ SHOW_SERVICES: "Sýna þjónustu",
3540
3563
  VIEW_BOOKING: "Skoða bókun",
3541
3564
  ITINERARY_TITLE: "Yfirlit ferðarinnar",
3542
3565
  DOSSIER_NUMBER: "Skrárnúmer",
@@ -3574,6 +3597,7 @@ var SRP$8 = {
3574
3597
  TRAVEL_GROUP: "Ferðahópur",
3575
3598
  EXCURSION: "Útflutningur",
3576
3599
  LOADING_EXCURSIONS: "Hleðst inn í útflutninga...",
3600
+ LOADING_ACTIVITIES: "Hleð inn afþreyingu...",
3577
3601
  LOADING_FLIGHTS: "Hleðst inn í flug...",
3578
3602
  LOADING_ACCOMMODATIONS: "Hleðst inn í gistingar...",
3579
3603
  LOADING_ITINERARY: "Hleðst inn í ferðaráætlun...",
@@ -3981,6 +4005,8 @@ var SRP$7 = {
3981
4005
  DEPARTURE_ASC: "Data di partenza (prima la più vicina)",
3982
4006
  FILTERS: "Filtri",
3983
4007
  SHOW_ITINERARY: "Mostra itinerario",
4008
+ VIEW_FULL_ITINERARY: "Vedi l'itinerario completo",
4009
+ SHOW_SERVICES: "Mostra i servizi",
3984
4010
  VIEW_BOOKING: "Visualizza prenotazione",
3985
4011
  ITINERARY_TITLE: "Riepilogo del tuo viaggio",
3986
4012
  DOSSIER_NUMBER: "Numero di pratica",
@@ -4018,6 +4044,7 @@ var SRP$7 = {
4018
4044
  TRAVEL_GROUP: "Gruppo di viaggio",
4019
4045
  EXCURSION: "Escursione",
4020
4046
  LOADING_EXCURSIONS: "Caricamento delle escursioni...",
4047
+ LOADING_ACTIVITIES: "Caricamento delle attività...",
4021
4048
  LOADING_FLIGHTS: "Caricamento dei voli...",
4022
4049
  LOADING_ACCOMMODATIONS: "Caricamento degli alloggi...",
4023
4050
  LOADING_ITINERARY: "Caricamento dell'itinerario...",
@@ -4429,6 +4456,8 @@ var SRP$6 = {
4429
4456
  DEPARTURE_ASC: "Vertrekdatum (dichtstbij eerst)",
4430
4457
  FILTERS: "Filters",
4431
4458
  SHOW_ITINERARY: "Toon reisplan",
4459
+ VIEW_FULL_ITINERARY: "Bekijk volledige reisroute",
4460
+ SHOW_SERVICES: "Toon diensten",
4432
4461
  VIEW_BOOKING: "Bekijk boeking",
4433
4462
  ITINERARY_TITLE: "Overzicht van je reis",
4434
4463
  DOSSIER_NUMBER: "Dossiernummer",
@@ -4466,6 +4495,7 @@ var SRP$6 = {
4466
4495
  TRAVEL_GROUP: "Reisgezelschap",
4467
4496
  EXCURSION: "Excursie",
4468
4497
  LOADING_EXCURSIONS: "Excursies laden...",
4498
+ LOADING_ACTIVITIES: "Activiteiten laden...",
4469
4499
  LOADING_FLIGHTS: "Vluchten laden...",
4470
4500
  LOADING_ACCOMMODATIONS: "Accommodaties laden...",
4471
4501
  LOADING_ITINERARY: "Reisplan laden...",
@@ -4873,6 +4903,8 @@ var SRP$5 = {
4873
4903
  DEPARTURE_ASC: "Vertrekdatum (dichtstbij eerst)",
4874
4904
  FILTERS: "Filters",
4875
4905
  SHOW_ITINERARY: "Toon reisplan",
4906
+ VIEW_FULL_ITINERARY: "Bekijk volledige reisroute",
4907
+ SHOW_SERVICES: "Toon diensten",
4876
4908
  VIEW_BOOKING: "Bekijk boeking",
4877
4909
  ITINERARY_TITLE: "Overzicht van je reis",
4878
4910
  DOSSIER_NUMBER: "Dossiernummer",
@@ -4910,6 +4942,7 @@ var SRP$5 = {
4910
4942
  TRAVEL_GROUP: "Reisgezelschap",
4911
4943
  EXCURSION: "Excursie",
4912
4944
  LOADING_EXCURSIONS: "Excursies laden...",
4945
+ LOADING_ACTIVITIES: "Activiteiten laden...",
4913
4946
  LOADING_FLIGHTS: "Vluchten laden...",
4914
4947
  LOADING_ACCOMMODATIONS: "Accommodaties laden...",
4915
4948
  LOADING_ITINERARY: "Reisplan laden...",
@@ -5317,6 +5350,8 @@ var SRP$4 = {
5317
5350
  DEPARTURE_ASC: "Avreisedato (nærmeste først)",
5318
5351
  FILTERS: "Filtre",
5319
5352
  SHOW_ITINERARY: "Vis reiserute",
5353
+ VIEW_FULL_ITINERARY: "Se hele reiseruten",
5354
+ SHOW_SERVICES: "Vis tjenester",
5320
5355
  VIEW_BOOKING: "Se bestilling",
5321
5356
  ITINERARY_TITLE: "Din reisemåloversikt",
5322
5357
  DOSSIER_NUMBER: "Saksnummer",
@@ -5354,6 +5389,7 @@ var SRP$4 = {
5354
5389
  TRAVEL_GROUP: "Reisefølge",
5355
5390
  EXCURSION: "Utflukt",
5356
5391
  LOADING_EXCURSIONS: "Laster utflukter...",
5392
+ LOADING_ACTIVITIES: "Laster aktiviteter...",
5357
5393
  LOADING_FLIGHTS: "Laster flyvninger...",
5358
5394
  LOADING_ACCOMMODATIONS: "Laster overnattinger...",
5359
5395
  LOADING_ITINERARY: "Laster reiserute...",
@@ -5761,6 +5797,8 @@ var SRP$3 = {
5761
5797
  DEPARTURE_ASC: "Data wyjazdu (najbliższa najpierw)",
5762
5798
  FILTERS: "Filtry",
5763
5799
  SHOW_ITINERARY: "Pokaż plan podróży",
5800
+ VIEW_FULL_ITINERARY: "Zobacz pełny plan podróży",
5801
+ SHOW_SERVICES: "Pokaż usługi",
5764
5802
  VIEW_BOOKING: "Zobacz rezerwację",
5765
5803
  ITINERARY_TITLE: "Podsumowanie Twojej podróży",
5766
5804
  DOSSIER_NUMBER: "Numer pliku",
@@ -5798,6 +5836,7 @@ var SRP$3 = {
5798
5836
  TRAVEL_GROUP: "Grupa podróżnych",
5799
5837
  EXCURSION: "Wycieczka",
5800
5838
  LOADING_EXCURSIONS: "Ładowanie wycieczek...",
5839
+ LOADING_ACTIVITIES: "Ładowanie atrakcji...",
5801
5840
  LOADING_FLIGHTS: "Ładowanie lotów...",
5802
5841
  LOADING_ACCOMMODATIONS: "Ładowanie zakwaterowań...",
5803
5842
  LOADING_ITINERARY: "Ładowanie planu podróży...",
@@ -6205,6 +6244,8 @@ var SRP$2 = {
6205
6244
  DEPARTURE_ASC: "Data de partida (mais próxima primeiro)",
6206
6245
  FILTERS: "Filtros",
6207
6246
  SHOW_ITINERARY: "Mostrar itinerário",
6247
+ VIEW_FULL_ITINERARY: "Ver itinerário completo",
6248
+ SHOW_SERVICES: "Ver serviços",
6208
6249
  VIEW_BOOKING: "Ver reserva",
6209
6250
  ITINERARY_TITLE: "Resumo da sua viagem",
6210
6251
  DOSSIER_NUMBER: "Número do processo",
@@ -6242,6 +6283,7 @@ var SRP$2 = {
6242
6283
  TRAVEL_GROUP: "Grupo de viajantes",
6243
6284
  EXCURSION: "Excursão",
6244
6285
  LOADING_EXCURSIONS: "A carregar excursões...",
6286
+ LOADING_ACTIVITIES: "A carregar atividades...",
6245
6287
  LOADING_FLIGHTS: "A carregar voos...",
6246
6288
  LOADING_ACCOMMODATIONS: "A carregar alojamentos...",
6247
6289
  LOADING_ITINERARY: "A carregar itinerário...",
@@ -6649,6 +6691,8 @@ var SRP$1 = {
6649
6691
  DEPARTURE_ASC: "Avresedatum (närmast först)",
6650
6692
  FILTERS: "Filter",
6651
6693
  SHOW_ITINERARY: "Visa resplan",
6694
+ VIEW_FULL_ITINERARY: "Visa hela resplanen",
6695
+ SHOW_SERVICES: "Visa tjänster",
6652
6696
  VIEW_BOOKING: "Visa bokning",
6653
6697
  ITINERARY_TITLE: "Din resesammanfattning",
6654
6698
  DOSSIER_NUMBER: "Filnummer",
@@ -6686,6 +6730,7 @@ var SRP$1 = {
6686
6730
  TRAVEL_GROUP: "Resesällskap",
6687
6731
  EXCURSION: "Utflykt",
6688
6732
  LOADING_EXCURSIONS: "Laddar utflykter...",
6733
+ LOADING_ACTIVITIES: "Laddar aktiviteter...",
6689
6734
  LOADING_FLIGHTS: "Laddar flyg...",
6690
6735
  LOADING_ACCOMMODATIONS: "Laddar boenden...",
6691
6736
  LOADING_ITINERARY: "Laddar resplan...",
@@ -7093,6 +7138,8 @@ var SRP = {
7093
7138
  DEPARTURE_ASC: "出発日(早い順)",
7094
7139
  FILTERS: "フィルター",
7095
7140
  SHOW_ITINERARY: "旅程を表示",
7141
+ VIEW_FULL_ITINERARY: "旅程の詳細を見る",
7142
+ SHOW_SERVICES: "サービスを表示",
7096
7143
  VIEW_BOOKING: "予約を見る",
7097
7144
  ITINERARY_TITLE: "あなたの旅行概要",
7098
7145
  DOSSIER_NUMBER: "ファイル番号",
@@ -7130,6 +7177,7 @@ var SRP = {
7130
7177
  TRAVEL_GROUP: "旅行グループ",
7131
7178
  EXCURSION: "エクスカーション",
7132
7179
  LOADING_EXCURSIONS: "エクスカーションを読み込み中...",
7180
+ LOADING_ACTIVITIES: "アクティビティを読み込み中...",
7133
7181
  LOADING_FLIGHTS: "フライトを読み込み中...",
7134
7182
  LOADING_ACCOMMODATIONS: "宿泊施設を読み込み中...",
7135
7183
  LOADING_ITINERARY: "旅程を読み込み中...",
@@ -7801,6 +7849,33 @@ var TrajectNodeType = {
7801
7849
  subroute: 3,
7802
7850
  };
7803
7851
 
7852
+ var DurationType = {
7853
+ hours: 0,
7854
+ days: 1,
7855
+ nights: 2,
7856
+ minutes: 3,
7857
+ };
7858
+
7859
+ var RouteTransportType = {
7860
+ none: 0,
7861
+ privateTransport: 1,
7862
+ publicTransport: 2,
7863
+ rentalCar: 3,
7864
+ bus: 4,
7865
+ camper: 5,
7866
+ car: 6,
7867
+ charter: 7,
7868
+ cruise: 8,
7869
+ ferry: 9,
7870
+ flight: 10,
7871
+ taxi: 11,
7872
+ train: 12,
7873
+ transfer: 13,
7874
+ rocket: 14,
7875
+ walking: 15,
7876
+ cycling: 16,
7877
+ };
7878
+
7804
7879
  /******************************************************************************
7805
7880
  Copyright (c) Microsoft Corporation.
7806
7881
 
@@ -15152,6 +15227,7 @@ var submitForm = function (config, id, request, signal) {
15152
15227
  exports.AllotmentType = AllotmentType;
15153
15228
  exports.DataType = DataType;
15154
15229
  exports.DossierType = DossierType;
15230
+ exports.DurationType = DurationType;
15155
15231
  exports.EntryLineFlag = EntryLineFlag;
15156
15232
  exports.EntryLineStatus = EntryLineStatus;
15157
15233
  exports.ExportStatus = ExportStatus;
@@ -15164,6 +15240,7 @@ exports.PaymentType = PaymentType;
15164
15240
  exports.PriceChartType = PriceChartType;
15165
15241
  exports.RequirementType = RequirementType;
15166
15242
  exports.RoomType = RoomType;
15243
+ exports.RouteTransportType = RouteTransportType;
15167
15244
  exports.SaleType = SaleType;
15168
15245
  exports.ServiceTokenError = ServiceTokenError;
15169
15246
  exports.ServiceType = ServiceType;
@@ -16641,6 +16718,16 @@ const Icon = ({ name, className, title, width, height, fill }) => {
16641
16718
  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." }),
16642
16719
  title && React__default["default"].createElement("title", null, title),
16643
16720
  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" })));
16721
+ case 'ui-cycling':
16722
+ 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' },
16723
+ React__default["default"].createElement(HTMLComment, { text: "!Font Awesome Free v5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc." }),
16724
+ title && React__default["default"].createElement("title", null, title),
16725
+ React__default["default"].createElement("path", { d: "M512.509 192.001c-16.373-.064-32.03 2.955-46.436 8.495l-77.68-125.153A24 24 0 0 0 368.001 64h-64c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h50.649l14.896 24H256.002v-16c0-8.837-7.163-16-16-16h-87.459c-13.441 0-24.777 10.999-24.536 24.437.232 13.044 10.876 23.563 23.995 23.563h48.726l-29.417 47.52c-13.433-4.83-27.904-7.483-42.992-7.52C58.094 191.83.412 249.012.002 319.236-.413 390.279 57.055 448 128.002 448c59.642 0 109.758-40.793 123.967-96h52.033a24 24 0 0 0 20.406-11.367L410.37 201.77l14.938 24.067c-25.455 23.448-41.385 57.081-41.307 94.437.145 68.833 57.899 127.051 126.729 127.719 70.606.685 128.181-55.803 129.255-125.996 1.086-70.941-56.526-129.72-127.476-129.996zM186.75 265.772c9.727 10.529 16.673 23.661 19.642 38.228h-43.306l23.664-38.228zM128.002 400c-44.112 0-80-35.888-80-80s35.888-80 80-80c5.869 0 11.586.653 17.099 1.859l-45.505 73.509C89.715 331.327 101.213 352 120.002 352h81.3c-12.37 28.225-40.562 48-73.3 48zm162.63-96h-35.624c-3.96-31.756-19.556-59.894-42.383-80.026L237.371 184h127.547l-74.286 120zm217.057 95.886c-41.036-2.165-74.049-35.692-75.627-76.755-.812-21.121 6.633-40.518 19.335-55.263l44.433 71.586c4.66 7.508 14.524 9.816 22.032 5.156l13.594-8.437c7.508-4.66 9.817-14.524 5.156-22.032l-44.468-71.643a79.901 79.901 0 0 1 19.858-2.497c44.112 0 80 35.888 80 80-.001 45.54-38.252 82.316-84.313 79.885z", fill: "currentColor" })));
16726
+ case 'ui-walking':
16727
+ return (React__default["default"].createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !lodash.isEmpty(className)).join(' '), width: width, height: height, viewBox: "0 0 320 512", fill: fill ?? 'currentColor' },
16728
+ React__default["default"].createElement(HTMLComment, { text: "!Font Awesome Free v5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc." }),
16729
+ title && React__default["default"].createElement("title", null, title),
16730
+ React__default["default"].createElement("path", { d: "M208 96c26.5 0 48-21.5 48-48S234.5 0 208 0s-48 21.5-48 48 21.5 48 48 48zm94.5 149.1l-23.3-11.8-9.7-29.4c-14.7-44.6-55.7-75.8-102.2-75.9-36-.1-55.9 10.1-93.3 25.2-21.6 8.7-39.3 25.2-49.7 46.2L17.6 213c-7.8 15.8-1.5 35 14.2 42.9 15.6 7.9 34.6 1.5 42.5-14.3L81 228c3.5-7 9.3-12.5 16.5-15.4l26.8-10.8-15.2 60.7c-5.2 20.8.4 42.9 14.9 58.8l59.9 65.4c7.2 7.9 12.3 17.4 14.9 27.7l18.3 73.3c4.3 17.1 21.7 27.6 38.8 23.3 17.1-4.3 27.6-21.7 23.3-38.8l-22.2-89c-2.6-10.3-7.7-19.9-14.9-27.7l-45.5-49.7 17.2-68.7 5.5 16.5c5.3 16.1 16.7 29.4 31.7 37l23.3 11.8c15.6 7.9 34.6 1.5 42.5-14.3 7.7-15.7 1.4-35.1-14.3-43zM73.6 385.8c-3.2 8.1-8 15.4-14.2 21.5l-50 50.1c-12.5 12.5-12.5 32.8 0 45.3s32.7 12.5 45.2 0l59.4-59.4c6.1-6.1 10.9-13.4 14.2-21.5l13.5-33.8c-55.3-60.3-38.7-41.8-47.4-53.7l-20.7 51.5z", fill: "currentColor" })));
16644
16731
  case 'ui-bus':
16645
16732
  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
16733
  title && React__default["default"].createElement("title", null, title),
@@ -16954,10 +17041,10 @@ const DateRangePicker$1 = (props) => {
16954
17041
  month: dateFns.getMonth(new Date())
16955
17042
  });
16956
17043
  const [isWaitingForToDate, setWaitingForToDate] = React.useState(false);
16957
- const { searchType = 0 } = React.useContext(SettingsContext$1);
17044
+ const { searchType = 0, allowSingleDayDateSelect = false } = React.useContext(SettingsContext$1);
16958
17045
  const handleDayClick = (day) => {
16959
17046
  const { onSelectionChange } = props;
16960
- if (isWaitingForToDate && !lodash.isNil(fromDate) && dateFns.isAfter(day, fromDate)) {
17047
+ if (isWaitingForToDate && !lodash.isNil(fromDate) && (dateFns.isAfter(day, fromDate) || (allowSingleDayDateSelect && dateFns.isSameDay(day, fromDate)))) {
16961
17048
  if (searchType === 1) {
16962
17049
  // Only allow selecting the exact toDate
16963
17050
  const expectedToDate = props.toDateByFromDate?.(fromDate);
@@ -16998,7 +17085,7 @@ const DateRangePicker$1 = (props) => {
16998
17085
  }
16999
17086
  };
17000
17087
  const handleDayMouseOver = (day) => {
17001
- if (isWaitingForToDate && (lodash.isNil(fromDate) || dateFns.isEqual(day, fromDate) || dateFns.isAfter(day, fromDate))) {
17088
+ if (isWaitingForToDate && (lodash.isNil(fromDate) || dateFns.isSameDay(day, fromDate) || dateFns.isAfter(day, fromDate))) {
17002
17089
  setToDate(day);
17003
17090
  }
17004
17091
  };
@@ -27471,7 +27558,9 @@ const initialState$1 = {
27471
27558
  trajectFlightAvailability: {},
27472
27559
  trajectDaySuggestions: {},
27473
27560
  trajectEditLineGuid: null,
27474
- trajectActivitiesDayOrder: null
27561
+ trajectActivitiesDayOrder: null,
27562
+ trajectResolving: false,
27563
+ trajectItineraryView: false
27475
27564
  };
27476
27565
  const searchResultsSlice = toolkit.createSlice({
27477
27566
  name: 'searchResults',
@@ -27741,6 +27830,12 @@ const searchResultsSlice = toolkit.createSlice({
27741
27830
  setTrajectActivitiesDayOrder(state, action) {
27742
27831
  state.trajectActivitiesDayOrder = action.payload;
27743
27832
  },
27833
+ setTrajectResolving(state, action) {
27834
+ state.trajectResolving = action.payload;
27835
+ },
27836
+ setTrajectItineraryView(state, action) {
27837
+ state.trajectItineraryView = action.payload;
27838
+ },
27744
27839
  updateTrajectNodeResult(state, action) {
27745
27840
  const { lineGuid, result } = action.payload;
27746
27841
  const node = state.trajectNodeAvailability[lineGuid];
@@ -27756,10 +27851,12 @@ const searchResultsSlice = toolkit.createSlice({
27756
27851
  state.trajectDaySuggestions = {};
27757
27852
  state.trajectEditLineGuid = null;
27758
27853
  state.trajectActivitiesDayOrder = null;
27854
+ state.trajectResolving = false;
27855
+ state.trajectItineraryView = false;
27759
27856
  }
27760
27857
  }
27761
27858
  });
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;
27859
+ 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, setTrajectResolving, setTrajectItineraryView, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, setTrajectEditLineGuid, setTrajectActivitiesDayOrder, setTrajectDaySuggestionsLoading, setTrajectDaySuggestions, addEditableEntryLines, updateTrajectNodeResult, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
27763
27860
  var searchResultsReducer = searchResultsSlice.reducer;
27764
27861
 
27765
27862
  const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
@@ -28007,8 +28104,97 @@ const getServiceTypeBadgeModifier = (serviceType) => {
28007
28104
  return '';
28008
28105
  }
28009
28106
  };
28107
+ // DurationType, as the SDK numbers it.
28108
+ const DURATION_HOURS = 0;
28109
+ const DURATION_DAYS = 1;
28110
+ const DURATION_NIGHTS = 2;
28111
+ const DURATION_MINUTES = 3;
28112
+ /**
28113
+ * How long a node takes, in the same shape the flight legs are written in — an hour count only
28114
+ * once there is one, so a short drive reads as plain minutes.
28115
+ */
28116
+ const getTrajectNodeDuration = (node) => {
28117
+ const minutes = toMinutes(node);
28118
+ if (!minutes)
28119
+ return '';
28120
+ const hours = Math.floor(minutes / 60);
28121
+ const rest = minutes % 60;
28122
+ return hours ? `${hours}h ${rest.toString().padStart(2, '0')}m` : `${rest} min`;
28123
+ };
28124
+ const toMinutes = (node) => {
28125
+ const duration = node.duration ?? 0;
28126
+ if (duration <= 0)
28127
+ return 0;
28128
+ switch (node.durationType) {
28129
+ case DURATION_MINUTES:
28130
+ return duration;
28131
+ case DURATION_HOURS:
28132
+ return duration * 60;
28133
+ case DURATION_DAYS:
28134
+ case DURATION_NIGHTS:
28135
+ return duration * 24 * 60;
28136
+ default:
28137
+ return 0;
28138
+ }
28139
+ };
28140
+ // RouteTransportType, as the SDK numbers it. It says how a leg is travelled, which is not the
28141
+ // same question as what was sold: cycling and walking have no service type of their own.
28142
+ const TRANSPORT_PRIVATE = 1;
28143
+ const TRANSPORT_PUBLIC = 2;
28144
+ const TRANSPORT_RENTAL_CAR = 3;
28145
+ const TRANSPORT_BUS = 4;
28146
+ const TRANSPORT_CAMPER = 5;
28147
+ const TRANSPORT_CAR = 6;
28148
+ const TRANSPORT_CHARTER = 7;
28149
+ const TRANSPORT_CRUISE = 8;
28150
+ const TRANSPORT_FERRY = 9;
28151
+ const TRANSPORT_FLIGHT = 10;
28152
+ const TRANSPORT_TAXI = 11;
28153
+ const TRANSPORT_TRAIN = 12;
28154
+ const TRANSPORT_TRANSFER = 13;
28155
+ const TRANSPORT_WALKING = 15;
28156
+ const TRANSPORT_CYCLING = 16;
28157
+ /** Icon per way of travelling, where the route records one. */
28158
+ const getTransportTypeIcon = (transportType) => {
28159
+ switch (transportType) {
28160
+ case TRANSPORT_WALKING:
28161
+ return 'ui-walking';
28162
+ case TRANSPORT_CYCLING:
28163
+ return 'ui-cycling';
28164
+ case TRANSPORT_PRIVATE:
28165
+ case TRANSPORT_RENTAL_CAR:
28166
+ case TRANSPORT_CAMPER:
28167
+ case TRANSPORT_CAR:
28168
+ return 'ui-car';
28169
+ case TRANSPORT_TAXI:
28170
+ case TRANSPORT_TRANSFER:
28171
+ return 'ui-transfer';
28172
+ case TRANSPORT_PUBLIC:
28173
+ case TRANSPORT_BUS:
28174
+ return 'ui-bus';
28175
+ case TRANSPORT_TRAIN:
28176
+ return 'ui-train';
28177
+ case TRANSPORT_CRUISE:
28178
+ case TRANSPORT_FERRY:
28179
+ return 'ui-ship';
28180
+ case TRANSPORT_FLIGHT:
28181
+ case TRANSPORT_CHARTER:
28182
+ return 'ui-plane';
28183
+ default:
28184
+ return null;
28185
+ }
28186
+ };
28010
28187
  const POI_TRAJECT_NODE_TYPE = 2;
28011
- const getTrajectNodeIcon = (node) => node.trajectNodeType === POI_TRAJECT_NODE_TYPE ? 'ui-location' : getServiceTypeIcon(node.serviceType);
28188
+ /**
28189
+ * A point of interest is a place on the map rather than a service, so it gets a marker. Anything
28190
+ * else goes by how it is travelled where the route says so — a leg on foot or by bike is sold as
28191
+ * nothing, and its service type falls back to a transfer — and by what it is where it does not.
28192
+ */
28193
+ const getTrajectNodeIcon = (node) => {
28194
+ if (node.trajectNodeType === POI_TRAJECT_NODE_TYPE)
28195
+ return 'ui-location';
28196
+ return getTransportTypeIcon(node.transportType) ?? getServiceTypeIcon(node.serviceType);
28197
+ };
28012
28198
  const getTrajectNodeBadgeModifier = (node) => node.trajectNodeType === POI_TRAJECT_NODE_TYPE ? 'poi' : getServiceTypeBadgeModifier(node.serviceType);
28013
28199
 
28014
28200
  const REGULAR_TRAJECT_NODE_TYPE = 0;
@@ -28049,7 +28235,22 @@ const buildDestination = (line, node, result) => {
28049
28235
  null;
28050
28236
  return { id: 0, ...place, ...coordinates };
28051
28237
  };
28052
- const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
28238
+ const hasDestination = (destination) => !!destination && (!!destination.id || (!!destination.latitude && !!destination.longitude));
28239
+ const buildTrajectClientConfig = (context) => ({
28240
+ host: context.tideConnection.host,
28241
+ apiKey: context.tideConnection.apiKey
28242
+ });
28243
+ const buildTrajectSearchContext = (context, trajectEntry) => ({
28244
+ transactionId: trajectEntry.entry.transactionId,
28245
+ officeId: context.tideConnection.officeId ?? 1,
28246
+ catalogueId: context.searchConfiguration.defaultCatalogueId ?? context.tideConnection.catalogueIds?.[0] ?? 1,
28247
+ searchConfigurationId: context.searchConfiguration.id,
28248
+ portalId: context.portalId ?? null,
28249
+ agentId: context.agentId ?? null,
28250
+ language: context.languageCode ?? 'en-GB',
28251
+ rooms: getPackagingRoomsFromEntry(trajectEntry.entry)
28252
+ });
28253
+ const buildTrajectNodeRequest = ({ node, line }, context, productCode, destination) => ({
28053
28254
  transactionId: context.transactionId,
28054
28255
  officeId: context.officeId,
28055
28256
  agentId: context.agentId ?? null,
@@ -28060,25 +28261,69 @@ const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
28060
28261
  language: context.language,
28061
28262
  serviceType: node.serviceType,
28062
28263
  fromDate: toDateOnlyString(line.from),
28063
- toDate: toDateOnlyString(line.to),
28064
- destination: buildDestination(line, node),
28264
+ // An excursion happens on a day rather than over a span. The traject gives its line an end a day
28265
+ // out, the way a night is counted, which asks the search for a window it does not have.
28266
+ toDate: toDateOnlyString(node.serviceType === EXCURSION_SERVICE_TYPE ? line.from : line.to),
28267
+ destination: destination ?? buildDestination(line, node),
28065
28268
  productCode,
28066
28269
  rooms: context.rooms,
28067
28270
  tagIds: []
28068
28271
  });
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);
28272
+ const coversDay = ({ node, line }, dayOrder) => {
28273
+ const nights = Math.max(dateFns.differenceInCalendarDays(new Date(line.to), new Date(line.from)), 1);
28274
+ return dayOrder >= node.dayOrder && dayOrder < node.dayOrder + nights;
28275
+ };
28276
+ const getDayDestinationItem = (items, dayOrder) => {
28277
+ const knowsWhereItIs = (x) => hasDestination(buildDestination(x.line, x.node));
28278
+ const stay = items.find((x) => x.node.serviceType === ACCOMMODATION_SERVICE_TYPE && coversDay(x, dayOrder) && knowsWhereItIs(x));
28279
+ if (stay)
28280
+ return stay;
28281
+ return ([...items]
28282
+ .filter((x) => x.node.dayOrder <= dayOrder && knowsWhereItIs(x))
28283
+ .sort((a, b) => a.node.dayOrder - b.node.dayOrder || a.node.order - b.node.order)
28284
+ .pop() ?? null);
28285
+ };
28286
+ const getDayDestination = (items, availability, dayOrder) => {
28287
+ const item = getDayDestinationItem(items, dayOrder);
28288
+ if (!item)
28289
+ return null;
28290
+ const resolved = availability[item.line.guid];
28291
+ const result = resolved?.results.find((x) => x.code === resolved.selectedCode) ?? null;
28292
+ const destination = buildDestination(item.line, item.node, result);
28293
+ return hasDestination(destination) ? destination : null;
28294
+ };
28295
+ const buildTrajectDayExcursionRequest = (date, destination, context) => ({
28296
+ transactionId: context.transactionId,
28297
+ officeId: context.officeId,
28298
+ agentId: context.agentId ?? null,
28299
+ catalogueId: context.catalogueId,
28300
+ searchConfigurationId: context.searchConfigurationId,
28301
+ portalId: context.portalId ?? null,
28302
+ vendorConfigurationId: null,
28303
+ language: context.language,
28304
+ serviceType: EXCURSION_SERVICE_TYPE,
28305
+ fromDate: toDateOnlyString(date),
28306
+ toDate: toDateOnlyString(date),
28307
+ destination,
28308
+ productCode: '',
28309
+ rooms: context.rooms,
28310
+ tagIds: []
28311
+ });
28312
+ const getExcursionOptionGroups = (result) => {
28313
+ const groups = new Map();
28314
+ (result.rooms ?? [])
28315
+ .flatMap((room) => room.options ?? [])
28316
+ .forEach((option) => {
28317
+ const key = [...(option.paxIds ?? [])].sort((a, b) => a - b).join(',');
28318
+ groups.set(key, [...(groups.get(key) ?? []), option]);
28081
28319
  });
28320
+ return [...groups.values()];
28321
+ };
28322
+ const excursionNeedsChoice = (result) => getExcursionOptionGroups(result).some((group) => group.length > 1 && !group.some((option) => option.isSelected));
28323
+ const buildTrajectExcursionLines = (result) => {
28324
+ const options = getExcursionOptionGroups(result)
28325
+ .map((group) => group.find((x) => x.isSelected) ?? (group.length === 1 ? group[0] : null))
28326
+ .filter((x) => !!x);
28082
28327
  if (!options.length)
28083
28328
  return [];
28084
28329
  const guids = options.map((option) => option.guid || crypto.randomUUID());
@@ -28107,6 +28352,21 @@ const buildTrajectExcursionLines = (result) => {
28107
28352
  flightInformation: null
28108
28353
  }));
28109
28354
  };
28355
+ const buildExcursionSearchParams = (result) => ({
28356
+ date: result.fromDate,
28357
+ fromDate: result.fromDate,
28358
+ toDate: result.toDate,
28359
+ countryId: result.countryId,
28360
+ regionId: result.regionId,
28361
+ oordId: result.oordId,
28362
+ locationId: result.locationId,
28363
+ locationName: result.locationName,
28364
+ accommodationCode: null,
28365
+ accommodationName: null,
28366
+ hotelCode: result.code,
28367
+ hotelName: result.name,
28368
+ rooms: result.rooms ?? []
28369
+ });
28110
28370
  const buildDayActivityCards = (items, availability, suggestions) => {
28111
28371
  const cards = [];
28112
28372
  const seen = new Set();
@@ -28123,11 +28383,27 @@ const buildDayActivityCards = (items, availability, suggestions) => {
28123
28383
  results.filter((x) => !!findCandidateForResult(item.node, x)).forEach((result) => push(result, item));
28124
28384
  });
28125
28385
  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)));
28386
+ items.forEach((item) => (availability[item.line.guid]?.results ?? []).forEach((result) => push(result)));
28129
28387
  return cards;
28130
28388
  };
28389
+ /**
28390
+ * Where to search for a node.
28391
+ *
28392
+ * Normally the node says so itself, through the product it was configured with. An excursion slot
28393
+ * left empty on the traject says nothing at all — no code, no alternatives, and a line with no
28394
+ * place on it — so it falls back to wherever the party is staying that day, the same anchor the
28395
+ * day's own activity search uses.
28396
+ */
28397
+ const getNodeSearchDestination = (items, item) => {
28398
+ const own = buildDestination(item.line, item.node);
28399
+ if (hasDestination(own))
28400
+ return own;
28401
+ return getDayDestination(items, {}, item.node.dayOrder) ?? own;
28402
+ };
28403
+ const getConfiguredExcursionCodes = (items, dayOrder) => new Set(items
28404
+ .filter((x) => x.node.dayOrder === dayOrder && x.node.serviceType === EXCURSION_SERVICE_TYPE)
28405
+ .flatMap((x) => [x.node.code, ...getNodeCandidates(x.node).map((candidate) => candidate.code)])
28406
+ .filter((code) => !!code));
28131
28407
  const getNodeCandidates = (node) => {
28132
28408
  const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
28133
28409
  if (configured.length)
@@ -28236,6 +28512,51 @@ const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
28236
28512
  outward: { date: dateToDateStruct(new Date(line.from)) },
28237
28513
  return: null
28238
28514
  });
28515
+ /**
28516
+ * The entry as the backend can price it.
28517
+ *
28518
+ * A search caches an EntryLine per option and hands back that line's guid on the option. The
28519
+ * backend then rebuilds the entry by looking each line up in that cache on its guid, so a line
28520
+ * it cannot find is dropped — PackagingEntryBuilder.SyncEntryLines skips it, and an entry whose
28521
+ * lines all came off a traject prices as nothing at all.
28522
+ *
28523
+ * A traject entry is rendered before any search runs, so its lines carry the guids the traject
28524
+ * mapper gave them. This swaps in the guid of whatever each line resolved onto, leaving the
28525
+ * lines the traveller added themselves alone — those were built from a search result and already
28526
+ * carry the right one.
28527
+ */
28528
+ const withCachedEntryLineGuids = (entry, trajectEntry, nodeAvailability, flightAvailability) => {
28529
+ const cachedGuids = new Map();
28530
+ getTrajectNodesWithLines(trajectEntry).forEach((item) => {
28531
+ if (isTrajectFlightNode(item.node)) {
28532
+ // A flight search caches the outward line under the guid it reports as outwardGuid.
28533
+ const guid = flightAvailability[item.line.guid]?.selectedGuid;
28534
+ if (guid)
28535
+ cachedGuids.set(item.line.guid, guid);
28536
+ return;
28537
+ }
28538
+ const availability = nodeAvailability[item.line.guid];
28539
+ const result = availability?.results.find((x) => x.code === availability.selectedCode);
28540
+ if (!result)
28541
+ return;
28542
+ // Room i took option i when the result was stamped on, so it takes option i here too.
28543
+ item.lines.forEach((line, index) => {
28544
+ const guid = getOptionForRoom(result, index)?.guid;
28545
+ if (guid)
28546
+ cachedGuids.set(line.guid, guid);
28547
+ });
28548
+ });
28549
+ if (!cachedGuids.size)
28550
+ return entry;
28551
+ return {
28552
+ ...entry,
28553
+ lines: (entry.lines ?? []).map((line) => ({
28554
+ ...line,
28555
+ guid: cachedGuids.get(line.guid) ?? line.guid,
28556
+ parentGuid: (line.parentGuid && cachedGuids.get(line.parentGuid)) ?? line.parentGuid
28557
+ }))
28558
+ };
28559
+ };
28239
28560
  const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
28240
28561
  const applyFlightToLine = (line, flight) => {
28241
28562
  const segments = flight.outward?.segments ?? [];
@@ -28312,6 +28633,8 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
28312
28633
  trajectNodeType: REGULAR_TRAJECT_NODE_TYPE,
28313
28634
  requirementType: 0,
28314
28635
  contentSource: 0,
28636
+ duration: 0,
28637
+ durationType: 0,
28315
28638
  alternatives: [],
28316
28639
  from: line.from,
28317
28640
  to: line.to
@@ -28345,6 +28668,8 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
28345
28668
  React__default["default"].createElement("p", null, dateFns.format(new Date(value), 'MMM'))));
28346
28669
  const renderConnectingNode = ({ node }) => {
28347
28670
  const distance = node.distanceInKm ? `${Math.round(node.distanceInKm)} km` : '';
28671
+ // How long the hop takes and how far it is, the way the traject editor puts them.
28672
+ const journey = [getTrajectNodeDuration(node), distance].filter(Boolean).join(' · ');
28348
28673
  return (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport", key: `connect-${node.nodeId}` },
28349
28674
  React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
28350
28675
  React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
@@ -28353,8 +28678,8 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
28353
28678
  React__default["default"].createElement("div", { className: badgeClass('transport', getTrajectNodeBadgeModifier(node)) },
28354
28679
  React__default["default"].createElement(Icon, { name: getTrajectNodeIcon(node), height: 15 })),
28355
28680
  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)))));
28681
+ React__default["default"].createElement("h6", null, node.name || journey),
28682
+ !!node.name && !!journey && React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" }, journey)))));
28358
28683
  };
28359
28684
  const renderOvernight = (item, index) => {
28360
28685
  const { dayOrder } = item.node;
@@ -28498,7 +28823,7 @@ const getServiceTypePriority = (serviceType) => {
28498
28823
  const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation }) => {
28499
28824
  const context = React.useContext(SearchResultsConfigurationContext);
28500
28825
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
28501
- const { editablePackagingEntry, priceDetails } = reactRedux.useSelector((state) => state.searchResults);
28826
+ const { editablePackagingEntry, priceDetails, trajectItineraryView } = reactRedux.useSelector((state) => state.searchResults);
28502
28827
  const dispatch = reactRedux.useDispatch();
28503
28828
  const packagingEntry = editablePackagingEntry ?? context?.packagingEntry;
28504
28829
  const sortedLines = React.useMemo(() => {
@@ -28541,6 +28866,11 @@ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation })
28541
28866
  const handleConfirm = () => {
28542
28867
  dispatch(setBookPackagingEntry(true));
28543
28868
  };
28869
+ const handleTrajectView = (itinerary) => {
28870
+ dispatch(setTrajectItineraryView(itinerary));
28871
+ if (typeof window !== 'undefined')
28872
+ window.scrollTo(0, 0);
28873
+ };
28544
28874
  return (React__default["default"].createElement("div", { className: `search__filters--modal ${isOpen ? 'is-open' : ''}` },
28545
28875
  React__default["default"].createElement("div", { className: "search__filters--background", onClick: handleSetIsOpen }),
28546
28876
  React__default["default"].createElement("button", { className: "search__filters--close", onClick: handleSetIsOpen },
@@ -28568,7 +28898,8 @@ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation })
28568
28898
  " ",
28569
28899
  translations.SRP.TOTAL,
28570
28900
  ")"))),
28571
- React__default["default"].createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM)))),
28901
+ React__default["default"].createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM),
28902
+ !!context?.trajectEntry && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleTrajectView(!trajectItineraryView) }, trajectItineraryView ? translations.SRP.SHOW_SERVICES : translations.SRP.VIEW_FULL_ITINERARY))))),
28572
28903
  React__default["default"].createElement("div", { className: "search__filter__itinerary" },
28573
28904
  React__default["default"].createElement("p", null, translations.SRP.DAY_BY_DAY),
28574
28905
  firstEntryLine && (React__default["default"].createElement("div", { className: "search__filter__itinerary__country" },
@@ -31062,10 +31393,9 @@ const getOptionPaxIds = (option) => {
31062
31393
  const optionAppliesToPax = (option, paxId) => {
31063
31394
  return getOptionPaxIds(option).includes(paxId);
31064
31395
  };
31065
- const optionAppliesToAllTravellers = (option, travellerCount) => {
31396
+ const optionAppliesToAllTravellers = (option, travellerIds) => {
31066
31397
  const paxIds = getOptionPaxIds(option);
31067
- const expected = Array.from({ length: travellerCount }, (_, i) => i);
31068
- return paxIds.length === expected.length && paxIds.every((id, index) => id === expected[index]);
31398
+ return paxIds.length === travellerIds.length && travellerIds.every((id) => paxIds.includes(id));
31069
31399
  };
31070
31400
  const groupOptionsByExcursion = (options) => {
31071
31401
  const groupedMap = new Map();
@@ -31090,26 +31420,26 @@ const ExcursionDetails = () => {
31090
31420
  return null;
31091
31421
  }
31092
31422
  const translations = getTranslations(context.languageCode ?? 'en-GB');
31093
- const travellerCount = editablePackagingEntry.pax.length;
31423
+ const travellerIds = editablePackagingEntry.pax.map((pax) => pax.id);
31094
31424
  const allOptions = React.useMemo(() => {
31095
31425
  return selectedExcursionSearchResult.rooms.flatMap((room) => room.options ?? []);
31096
31426
  }, [selectedExcursionSearchResult]);
31097
31427
  const sharedOptions = React.useMemo(() => {
31098
- return allOptions.filter((option) => optionAppliesToAllTravellers(option, travellerCount));
31099
- }, [allOptions, travellerCount]);
31428
+ return allOptions.filter((option) => optionAppliesToAllTravellers(option, travellerIds));
31429
+ }, [allOptions, travellerIds]);
31100
31430
  const sharedExcursions = React.useMemo(() => {
31101
31431
  return groupOptionsByExcursion(sharedOptions);
31102
31432
  }, [sharedOptions]);
31103
31433
  const paxGroups = React.useMemo(() => {
31104
31434
  return editablePackagingEntry.pax.map((pax) => {
31105
- const paxOptions = allOptions.filter((option) => optionAppliesToPax(option, pax.id) && !optionAppliesToAllTravellers(option, travellerCount));
31435
+ const paxOptions = allOptions.filter((option) => optionAppliesToPax(option, pax.id) && !optionAppliesToAllTravellers(option, travellerIds));
31106
31436
  return {
31107
31437
  pax,
31108
31438
  paxId: pax.id,
31109
31439
  excursions: groupOptionsByExcursion(paxOptions)
31110
31440
  };
31111
31441
  });
31112
- }, [editablePackagingEntry.pax, allOptions, travellerCount]);
31442
+ }, [editablePackagingEntry.pax, allOptions, travellerIds]);
31113
31443
  const getSelectedSharedOption = () => {
31114
31444
  return sharedOptions.find((option) => option.isSelected);
31115
31445
  };
@@ -31117,11 +31447,11 @@ const ExcursionDetails = () => {
31117
31447
  return sharedOptions.find((option) => option.accommodationCode === accommodationCode && option.isSelected);
31118
31448
  };
31119
31449
  const getSelectedOptionForPax = (paxId) => {
31120
- return allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerCount) && option.isSelected);
31450
+ return allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerIds) && option.isSelected);
31121
31451
  };
31122
31452
  const getSelectedOptionForExcursion = (paxId, accommodationCode) => {
31123
31453
  return allOptions.find((option) => optionAppliesToPax(option, paxId) &&
31124
- !optionAppliesToAllTravellers(option, travellerCount) &&
31454
+ !optionAppliesToAllTravellers(option, travellerIds) &&
31125
31455
  option.accommodationCode === accommodationCode &&
31126
31456
  option.isSelected);
31127
31457
  };
@@ -31131,7 +31461,7 @@ const ExcursionDetails = () => {
31131
31461
  rooms: selectedExcursionSearchResult.rooms.map((room) => ({
31132
31462
  ...room,
31133
31463
  options: room.options.map((option) => {
31134
- const isSharedOption = optionAppliesToAllTravellers(option, travellerCount);
31464
+ const isSharedOption = optionAppliesToAllTravellers(option, travellerIds);
31135
31465
  if (paxId === undefined) {
31136
31466
  if (!isSharedOption) {
31137
31467
  return option;
@@ -31178,7 +31508,7 @@ const ExcursionDetails = () => {
31178
31508
  targetPrice = selectedOption.price;
31179
31509
  }
31180
31510
  else {
31181
- const firstOption = allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerCount) && option.accommodationCode === accommodationCode);
31511
+ const firstOption = allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerIds) && option.accommodationCode === accommodationCode);
31182
31512
  targetPrice = firstOption?.price || 0;
31183
31513
  }
31184
31514
  return targetPrice - (currentSelectedPrice || 0);
@@ -31200,6 +31530,13 @@ const ExcursionDetails = () => {
31200
31530
  return 'flyin__acco__price';
31201
31531
  };
31202
31532
  const handleConfirm = () => {
31533
+ if (context.trajectEntry) {
31534
+ const lines = buildTrajectExcursionLines(selectedExcursionSearchResult);
31535
+ if (lines.length)
31536
+ dispatch(addEditableEntryLines(lines));
31537
+ dispatch(setFlyInIsOpen(false));
31538
+ return;
31539
+ }
31203
31540
  const dayKey = getExcursionDayKey(excursionSearchParams.date);
31204
31541
  dispatch(confirmExcursionForDay({
31205
31542
  dayKey,
@@ -31441,6 +31778,12 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
31441
31778
  dispatch(removeEditableEntryLines(added.map((line) => line.guid)));
31442
31779
  return;
31443
31780
  }
31781
+ if (excursionNeedsChoice(result)) {
31782
+ dispatch(setExcursionSearchParams(buildExcursionSearchParams(result)));
31783
+ dispatch(setSelectedExcursionSearchResult(result));
31784
+ dispatch(setFlyInType('excursion-details'));
31785
+ return;
31786
+ }
31444
31787
  const lines = buildTrajectExcursionLines(result);
31445
31788
  if (lines.length)
31446
31789
  dispatch(addEditableEntryLines(lines));
@@ -31455,7 +31798,7 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
31455
31798
  dispatch(setFlyInIsOpen(false));
31456
31799
  };
31457
31800
  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 }));
31801
+ return React__default["default"].createElement(React__default["default"].Fragment, null, context.customSpinner ?? React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACTIVITIES }));
31459
31802
  }
31460
31803
  return (React__default["default"].createElement("div", { className: "flyin__content" },
31461
31804
  React__default["default"].createElement("div", { className: "search__result-row" },
@@ -33009,6 +33352,27 @@ const getRequestRoomsFromPackagingSegments = (entry, segments) => {
33009
33352
  }));
33010
33353
  };
33011
33354
 
33355
+ /**
33356
+ * The entry to send to the backend, as opposed to the one the page works with.
33357
+ *
33358
+ * They differ only for a traject: the page keeps the line guids the traject was rendered with,
33359
+ * because that is what joins its nodes to its lines, while pricing and booking need the guids the
33360
+ * searches cached their lines under. Anything else passes through untouched, so this can be used
33361
+ * wherever the entry leaves the component without checking which flow is running.
33362
+ */
33363
+ const useBookableEntry = () => {
33364
+ const context = React.useContext(SearchResultsConfigurationContext);
33365
+ const { editablePackagingEntry, trajectNodeAvailability, trajectFlightAvailability } = reactRedux.useSelector((state) => state.searchResults);
33366
+ const trajectEntry = context?.trajectEntry;
33367
+ return React.useMemo(() => {
33368
+ if (!editablePackagingEntry)
33369
+ return null;
33370
+ if (!trajectEntry)
33371
+ return editablePackagingEntry;
33372
+ return withCachedEntryLineGuids(editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability);
33373
+ }, [editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability]);
33374
+ };
33375
+
33012
33376
  const escapeHtml = (value) => {
33013
33377
  if (!value)
33014
33378
  return '';
@@ -33067,7 +33431,57 @@ const findAccommodationForDay = (nodes, currentDay) => {
33067
33431
  }
33068
33432
  return null;
33069
33433
  };
33070
- const buildItineraryHtml = (itinerary, translations) => {
33434
+ const formatTime = (time) => (time ? time.slice(0, 5) : '');
33435
+ /**
33436
+ * Whether generated content actually shows something.
33437
+ *
33438
+ * A content view whose data is missing still returns its wrapper markup, or the whitespace left by
33439
+ * a guard around its body — markup that renders as a blank gap. Only text or an image counts as
33440
+ * something the traveller can read.
33441
+ */
33442
+ const hasVisibleContent = (contents) => {
33443
+ if (!contents)
33444
+ return false;
33445
+ if (/<(img|svg|picture|video|iframe)\b/i.test(contents))
33446
+ return true;
33447
+ return (contents
33448
+ .replace(/<[^>]*>/g, ' ')
33449
+ .replace(/&nbsp;/gi, ' ')
33450
+ .trim().length > 0);
33451
+ };
33452
+ /** The legs of a flight, as the entry line records them. */
33453
+ const buildFlightHtml = (line) => {
33454
+ const flightLines = line.flightInformation?.flightLines ?? [];
33455
+ if (!flightLines.length)
33456
+ return '';
33457
+ const legs = flightLines
33458
+ .map((leg) => {
33459
+ const from = escapeHtml(leg.departureAirportDescription || leg.departureAirportCode);
33460
+ const to = escapeHtml(leg.arrivalAirportDescription || leg.arrivalAirportCode);
33461
+ const carrier = escapeHtml([leg.airlineDescription, leg.flightNumber].filter(Boolean).join(' '));
33462
+ return `<li>${from} ${formatTime(leg.departureTime)} &rarr; ${to} ${formatTime(leg.arrivalTime)}${carrier ? ` &middot; ${carrier}` : ''}</li>`;
33463
+ })
33464
+ .join('');
33465
+ return `<ul class="itinerary-item__legs">${legs}</ul>`;
33466
+ };
33467
+ /**
33468
+ * What to show for an item the generator returned no content for.
33469
+ *
33470
+ * An item comes back with a title and a template but an empty body whenever its template has no
33471
+ * content view of its own — flights, today. Rendering that empty body leaves a blank where a
33472
+ * service should be, so what the entry already knows about the line is drawn instead.
33473
+ */
33474
+ const buildFallbackHtml = (item, line) => {
33475
+ const details = [line?.accommodationName, line?.regimeName].filter(Boolean).join(' — ');
33476
+ return `
33477
+ <div class="itinerary-item__fallback">
33478
+ <h3 class="itinerary-item__fallback-title">${escapeHtml(item.title)}</h3>
33479
+ ${line ? buildFlightHtml(line) : ''}
33480
+ ${details ? `<p class="itinerary-item__fallback-details">${escapeHtml(details)}</p>` : ''}
33481
+ </div>
33482
+ `;
33483
+ };
33484
+ const buildItineraryHtml = (itinerary, translations, lines) => {
33071
33485
  if (!itinerary) {
33072
33486
  return `
33073
33487
  <div class="itinerary-shell">
@@ -33096,7 +33510,9 @@ const buildItineraryHtml = (itinerary, translations) => {
33096
33510
  ? uniqueItems
33097
33511
  .map((item) => `
33098
33512
  <article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
33099
- ${item.contents ?? ''}
33513
+ ${hasVisibleContent(item.contents)
33514
+ ? item.contents
33515
+ : buildFallbackHtml(item, lines.find((line) => line.guid === item.itemGuid))}
33100
33516
  </article>
33101
33517
  `)
33102
33518
  .join('')
@@ -33130,7 +33546,9 @@ const buildItineraryHtml = (itinerary, translations) => {
33130
33546
  ${getUniqueItems(itinerary.defaultItems)
33131
33547
  .map((item) => `
33132
33548
  <article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
33133
- ${item.contents ?? ''}
33549
+ ${hasVisibleContent(item.contents)
33550
+ ? item.contents
33551
+ : buildFallbackHtml(item, lines.find((line) => line.guid === item.itemGuid))}
33134
33552
  </article>
33135
33553
  `)
33136
33554
  .join('')}
@@ -33151,10 +33569,12 @@ const buildItineraryHtml = (itinerary, translations) => {
33151
33569
  const FullItinerary = ({ isLoading }) => {
33152
33570
  const { itinerary } = reactRedux.useSelector((state) => state.searchResults);
33153
33571
  const context = React.useContext(SearchResultsConfigurationContext);
33572
+ // The entry as it was sent: its line guids are the ones the itinerary items carry back.
33573
+ const bookableEntry = useBookableEntry();
33154
33574
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
33155
33575
  const hostRef = React.useRef(null);
33156
33576
  const shadowRootRef = React.useRef(null);
33157
- const html = React.useMemo(() => buildItineraryHtml(itinerary, translations), [itinerary, translations]);
33577
+ const html = React.useMemo(() => buildItineraryHtml(itinerary, translations, bookableEntry?.lines ?? []), [itinerary, translations, bookableEntry]);
33158
33578
  React.useEffect(() => {
33159
33579
  if (isLoading) {
33160
33580
  return;
@@ -33268,6 +33688,35 @@ const FullItinerary = ({ isLoading }) => {
33268
33688
  background: #fff;
33269
33689
  }
33270
33690
 
33691
+ /* An item whose template has no content view of its own still has to read as a service. */
33692
+ .itinerary-item__fallback {
33693
+ padding: 16px 20px;
33694
+ border: 1px solid #e5e7eb;
33695
+ border-radius: 12px;
33696
+ }
33697
+
33698
+ .itinerary-item__fallback-title {
33699
+ margin: 0;
33700
+ font-size: 16px;
33701
+ font-weight: 600;
33702
+ color: #111827;
33703
+ }
33704
+
33705
+ .itinerary-item__legs {
33706
+ margin: 8px 0 0;
33707
+ padding-left: 18px;
33708
+ color: #374151;
33709
+ }
33710
+
33711
+ .itinerary-item__legs li + li {
33712
+ margin-top: 4px;
33713
+ }
33714
+
33715
+ .itinerary-item__fallback-details {
33716
+ margin: 8px 0 0;
33717
+ color: #6b7280;
33718
+ }
33719
+
33271
33720
  .itinerary-node__empty,
33272
33721
  .itinerary-empty {
33273
33722
  padding: 20px;
@@ -33787,6 +34236,8 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
33787
34236
  setSelectedPackagingAccoResult(selectedPackagingAccoResult);
33788
34237
  }
33789
34238
  }, [selectedPackagingAccoResultCode, packagingAccoResults]);
34239
+ // What the page holds versus what the backend can look up; they differ for a traject.
34240
+ const bookableEntry = useBookableEntry();
33790
34241
  if (!context || !editablePackagingEntry || !priceDetails || !config)
33791
34242
  return React__default["default"].createElement(Spinner, { label: translations.SUMMARY.PROCESS_BOOKING });
33792
34243
  const handleSummarySubmit = async (e) => {
@@ -33795,20 +34246,15 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
33795
34246
  if (typeof window !== 'undefined') {
33796
34247
  window.scrollTo(0, 0);
33797
34248
  }
33798
- let updatedEditablePackagingEntry = {
33799
- ...editablePackagingEntry,
33800
- remarks
33801
- };
34249
+ // Held apart from the entry itself so they can be put on both copies of it.
34250
+ let bookingFields = { remarks };
33802
34251
  if (context.generatePaymentUrl && typeof window !== 'undefined') {
33803
34252
  const redirectUrl = new URL(window.location.href);
33804
34253
  redirectUrl.searchParams.set('bookingConfirmation', 'true');
33805
34254
  redirectUrl.searchParams.set('link', '');
33806
- updatedEditablePackagingEntry = {
33807
- ...updatedEditablePackagingEntry,
33808
- redirectUrl: redirectUrl.toString(),
33809
- returnPaymentUrl: true
33810
- };
34255
+ bookingFields = { ...bookingFields, redirectUrl: redirectUrl.toString(), returnPaymentUrl: true };
33811
34256
  }
34257
+ const updatedEditablePackagingEntry = { ...editablePackagingEntry, ...bookingFields };
33812
34258
  dispatch(setEditablePackagingEntry(updatedEditablePackagingEntry));
33813
34259
  try {
33814
34260
  const request = {
@@ -33816,7 +34262,8 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
33816
34262
  officeId: context.tideConnection.officeId,
33817
34263
  catalogueId: context.searchConfiguration.defaultCatalogueId ?? 0,
33818
34264
  agentId: context.agentId,
33819
- payload: updatedEditablePackagingEntry
34265
+ // The page keeps the entry it works with; the backend gets the one it can look up.
34266
+ payload: { ...(bookableEntry ?? editablePackagingEntry), ...bookingFields }
33820
34267
  };
33821
34268
  const bookingResponse = await build.bookPackagingEntry(config, request);
33822
34269
  dispatch(setBookingNumber(bookingResponse.number));
@@ -33848,6 +34295,41 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
33848
34295
  React__default["default"].createElement(WLSidebar, { activeSearchSeed: activeSearchSeed, packagingAccoResult: selectedPackagingAccoResult }))));
33849
34296
  };
33850
34297
 
34298
+ const useTrajectDayActivities = () => {
34299
+ const context = React.useContext(SearchResultsConfigurationContext);
34300
+ const dispatch = reactRedux.useDispatch();
34301
+ const { trajectDaySuggestions, trajectNodeAvailability } = reactRedux.useSelector((state) => state.searchResults);
34302
+ const trajectEntry = context?.trajectEntry;
34303
+ const showApiItems = !!context?.showApiItems;
34304
+ const loadDay = React.useCallback(async (day) => {
34305
+ if (!context || !trajectEntry)
34306
+ return;
34307
+ // Already asked for, or already answered: leave it be.
34308
+ if (trajectDaySuggestions[day.order])
34309
+ return;
34310
+ const nodesWithLines = getTrajectNodesWithLines(trajectEntry);
34311
+ const destination = getDayDestination(nodesWithLines, trajectNodeAvailability, day.order);
34312
+ if (!destination)
34313
+ return;
34314
+ dispatch(setTrajectDaySuggestionsLoading(day.order));
34315
+ try {
34316
+ const results = (await build.searchPackagingExcursions(buildTrajectClientConfig(context), buildTrajectDayExcursionRequest(day.date, destination, buildTrajectSearchContext(context, trajectEntry)))) ?? [];
34317
+ // With external items switched off a day only offers what Tide holds itself, and whatever
34318
+ // the traject already books that day has a card of its own further up the block.
34319
+ const configured = getConfiguredExcursionCodes(nodesWithLines, day.order);
34320
+ dispatch(setTrajectDaySuggestions({
34321
+ dayOrder: day.order,
34322
+ results: results.filter((x) => showApiItems || !isExternalResult(x)).filter((x) => !configured.has(x.code))
34323
+ }));
34324
+ }
34325
+ catch (error) {
34326
+ console.error('Failed to load traject day activities', day.order, error);
34327
+ dispatch(setTrajectDaySuggestions({ dayOrder: day.order, results: [] }));
34328
+ }
34329
+ }, [context, trajectEntry, showApiItems, trajectDaySuggestions, trajectNodeAvailability, dispatch]);
34330
+ return loadDay;
34331
+ };
34332
+
33851
34333
  const getNodeIcon = (node) => {
33852
34334
  if (isTrajectFlightNode(node))
33853
34335
  return 'ui-flight';
@@ -33863,6 +34345,7 @@ const MAX_DAY_ACTIVITIES = 6;
33863
34345
  const TrajectResults = ({ isLoading }) => {
33864
34346
  const context = React.useContext(SearchResultsConfigurationContext);
33865
34347
  const dispatch = reactRedux.useDispatch();
34348
+ const loadDay = useTrajectDayActivities();
33866
34349
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
33867
34350
  const locale = getLocale(context?.languageCode ?? 'en-GB');
33868
34351
  const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry } = reactRedux.useSelector((state) => state.searchResults);
@@ -33895,6 +34378,23 @@ const TrajectResults = ({ isLoading }) => {
33895
34378
  });
33896
34379
  return { stayByDay: byDay, stayStartByNodeId: byNodeId };
33897
34380
  }, [nodesWithLines]);
34381
+ /** Whether every node of the trip has an answer, one way or the other. */
34382
+ const tripResolved = React.useMemo(() => nodesWithLines
34383
+ .filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node))
34384
+ .every((x) => {
34385
+ const status = isTrajectFlightNode(x.node) ? trajectFlightAvailability[x.line.guid]?.status : trajectNodeAvailability[x.line.guid]?.status;
34386
+ return !!status && status !== 'loading';
34387
+ }), [nodesWithLines, trajectNodeAvailability, trajectFlightAvailability]);
34388
+ /**
34389
+ * Each day's activities are one more search, and a traject has as many as it has days. They go
34390
+ * out together, but only once the trip itself has resolved — sharing the connections with the
34391
+ * searches the trip cannot do without would only make those slower.
34392
+ */
34393
+ React.useEffect(() => {
34394
+ if (!trajectEntry || !tripResolved)
34395
+ return;
34396
+ (trajectEntry.traject.days ?? []).filter((day) => stayByDay.has(day.order)).forEach((day) => loadDay(day));
34397
+ }, [trajectEntry, tripResolved, stayByDay]);
33898
34398
  if (!context || !trajectEntry)
33899
34399
  return null;
33900
34400
  const handleSelect = (item, code) => {
@@ -33979,7 +34479,7 @@ const TrajectResults = ({ isLoading }) => {
33979
34479
  React__default["default"].createElement(Icon, { name: getNodeIcon(node), height: 16 }),
33980
34480
  React__default["default"].createElement("h3", null,
33981
34481
  React__default["default"].createElement("strong", null, headerTitle || node.name))))),
33982
- status === 'loading' && (React__default["default"].createElement(Spinner, { label: node.serviceType === EXCURSION_SERVICE_TYPE ? translations.SRP.LOADING_EXCURSIONS : translations.SRP.LOADING_ACCOMMODATIONS })),
34482
+ status === 'loading' && React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACCOMMODATIONS }),
33983
34483
  status === 'unavailable' && React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
33984
34484
  status === 'resolved' && selected && (React__default["default"].createElement(React__default["default"].Fragment, null,
33985
34485
  availability.preferredUnavailable && node.preferredAccommodationName && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
@@ -34015,8 +34515,6 @@ const TrajectResults = ({ isLoading }) => {
34015
34515
  React__default["default"].createElement("div", { className: "search__results__label__text" },
34016
34516
  React__default["default"].createElement(Icon, { name: "ui-flight", height: 16 }),
34017
34517
  React__default["default"].createElement("h3", null,
34018
- translations.SRP.SELECT,
34019
- ' ',
34020
34518
  React__default["default"].createElement("strong", null,
34021
34519
  node.departureAirportCode,
34022
34520
  " - ",
@@ -34042,6 +34540,13 @@ const TrajectResults = ({ isLoading }) => {
34042
34540
  dispatch(removeEditableEntryLines(added.map((line) => line.guid)));
34043
34541
  return;
34044
34542
  }
34543
+ if (excursionNeedsChoice(result)) {
34544
+ dispatch(setExcursionSearchParams(buildExcursionSearchParams(result)));
34545
+ dispatch(setSelectedExcursionSearchResult(result));
34546
+ dispatch(setFlyInType('excursion-details'));
34547
+ dispatch(setFlyInIsOpen(true));
34548
+ return;
34549
+ }
34045
34550
  const lines = buildTrajectExcursionLines(result);
34046
34551
  if (lines.length)
34047
34552
  dispatch(addEditableEntryLines(lines));
@@ -34068,32 +34573,30 @@ const TrajectResults = ({ isLoading }) => {
34068
34573
  const items = getDayExcursionItems(day.order);
34069
34574
  const suggestions = trajectDaySuggestions[day.order];
34070
34575
  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)
34576
+ const nodesResolving = items.some((item) => (trajectNodeAvailability[item.line.guid]?.status ?? 'loading') === 'loading');
34577
+ const isSearching = suggestions?.status === 'loading';
34578
+ // A day is worth filling only if the party is staying somewhere that night. The day they fly
34579
+ // home is covered by no stay — the last night was the night before — and nobody is looking for
34580
+ // something to do on it.
34581
+ const canSearch = stayByDay.has(day.order) && !!getDayDestination(nodesWithLines, trajectNodeAvailability, day.order);
34582
+ if (!items.length && !canSearch)
34075
34583
  return null;
34076
34584
  const visible = cards.slice(0, MAX_DAY_ACTIVITIES);
34077
34585
  const hidden = cards.length - visible.length;
34078
34586
  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 }))),
34587
+ React__default["default"].createElement("div", { className: "search__results__label search__results__label--sub" },
34083
34588
  React__default["default"].createElement("div", { className: "search__results__label__text" },
34084
34589
  React__default["default"].createElement(Icon, { name: "ui-excursion", height: 16 }),
34085
34590
  React__default["default"].createElement("h3", null,
34086
34591
  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
- ")")))))));
34592
+ (nodesResolving || isSearching) && !cards.length && React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACTIVITIES }),
34593
+ !!cards.length && React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--scroll" }, visible.map(renderActivityCard)),
34594
+ !nodesResolving && !isSearching && !cards.length && (!!items.length || !!suggestions) && (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)),
34595
+ React__default["default"].createElement("div", { className: "search__results__cards__actions" }, hidden > 0 && !hideShowMoreResults && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreActivities(day.order) },
34596
+ translations.SRP.SHOW_MORE,
34597
+ " (",
34598
+ hidden,
34599
+ ")")))));
34097
34600
  };
34098
34601
  /**
34099
34602
  * An activity the traject books is swapped for another, the way a hotel is; one the traveller
@@ -34144,6 +34647,7 @@ const useTrajectAvailability = () => {
34144
34647
  return;
34145
34648
  const controller = new AbortController();
34146
34649
  dispatch(resetTrajectAvailability());
34650
+ dispatch(setTrajectResolving(true));
34147
34651
  const config = {
34148
34652
  host: context.tideConnection.host,
34149
34653
  apiKey: context.tideConnection.apiKey
@@ -34170,42 +34674,51 @@ const useTrajectAvailability = () => {
34170
34674
  const lineGuid = item.line.guid;
34171
34675
  const search = item.node.serviceType === EXCURSION_SERVICE_TYPE ? build.searchPackagingExcursions : build.searchPackagingAccommodations;
34172
34676
  dispatch(setTrajectNodeLoading(lineGuid));
34677
+ const destination = getNodeSearchDestination(nodesWithLines, item);
34678
+ const searchFor = async (productCode) => {
34679
+ try {
34680
+ const results = (await search(config, buildTrajectNodeRequest(item, searchContext, productCode, destination), controller.signal)) ?? [];
34681
+ return results.filter((x) => showApiItems || !isExternalResult(x));
34682
+ }
34683
+ catch (error) {
34684
+ if (!controller.signal.aborted)
34685
+ console.error('Traject product unavailable', item.node.name, productCode, error);
34686
+ return [];
34687
+ }
34688
+ };
34173
34689
  try {
34174
34690
  // With external items switched off the node only looks at products held inside Tide.
34175
34691
  const candidates = getNodeCandidates(item.node).filter((x) => showApiItems || !isExternalCandidate(x));
34176
- const attempts = await Promise.all(candidates.map(async (candidate) => {
34177
- try {
34178
- const attempt = await search(config, buildTrajectNodeRequest(item, searchContext, candidate.code), controller.signal);
34179
- return (attempt ?? []).find((result) => matchesCode(result, candidate.code)) ?? null;
34180
- }
34181
- catch (error) {
34182
- if (!controller.signal.aborted)
34183
- console.error('Traject hotel unavailable', candidate.code, error);
34184
- return null;
34185
- }
34692
+ const areaResults = hideShowMoreResults ? [] : await searchFor('');
34693
+ if (controller.signal.aborted)
34694
+ return [];
34695
+ const configuredResults = [];
34696
+ const found = await Promise.all(candidates.map(async (candidate) => {
34697
+ const known = areaResults.find((x) => matchesCode(x, candidate.code));
34698
+ if (known)
34699
+ return known;
34700
+ return (await searchFor(candidate.code)).find((x) => matchesCode(x, candidate.code)) ?? null;
34186
34701
  }));
34187
- const configuredResults = attempts
34188
- .filter((x) => !!x)
34189
- .filter((x, i, all) => all.findIndex((y) => y.code === x.code) === i);
34702
+ if (controller.signal.aborted)
34703
+ return [];
34704
+ // Two configured codes can land on the same product — a hotel and one of its room types.
34705
+ found.forEach((result) => {
34706
+ if (!result || configuredResults.some((x) => x.code === result.code))
34707
+ return;
34708
+ configuredResults.push(result);
34709
+ });
34710
+ const configuredCodes = new Set(configuredResults.map((x) => x.code));
34711
+ const destinationResults = areaResults.filter((x) => !configuredCodes.has(x.code));
34190
34712
  const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
34191
- let preferredUnavailable = !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code));
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));
34713
+ const preferredUnavailable = configuredResults.length
34714
+ ? !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code))
34715
+ : candidates.length > 0;
34200
34716
  const picked = configuredResults[0] ?? pickCheapest(destinationResults);
34201
- const results = [...configuredResults, ...destinationResults];
34202
- if (!configuredResults.length)
34203
- preferredUnavailable = candidates.length > 0;
34204
34717
  if (controller.signal.aborted)
34205
34718
  return [];
34206
34719
  dispatch(setTrajectNodeAvailability({
34207
34720
  lineGuid,
34208
- results,
34721
+ results: [...configuredResults, ...destinationResults],
34209
34722
  selectedCode: picked?.code ?? null,
34210
34723
  preferredUnavailable
34211
34724
  }));
@@ -34249,11 +34762,11 @@ const useTrajectAvailability = () => {
34249
34762
  }
34250
34763
  };
34251
34764
  (async () => {
34252
- const searchable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node));
34253
- const flightNodes = nodesWithLines.filter((x) => isTrajectFlightNode(x.node));
34254
- const unresolved = (await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)])).flat();
34765
+ const resolvable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node));
34766
+ const unresolved = (await Promise.all(resolvable.map((item) => (isTrajectFlightNode(item.node) ? resolveFlightNode(item) : resolveNode(item))))).flat();
34255
34767
  if (controller.signal.aborted)
34256
34768
  return;
34769
+ dispatch(setTrajectResolving(false));
34257
34770
  // A node with no availability anywhere cannot be priced or booked, so its line comes off
34258
34771
  // the entry. The card stays visible and reports the gap.
34259
34772
  const emptyLineGuids = unresolved.filter(Boolean);
@@ -34269,10 +34782,12 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
34269
34782
  const dispatch = reactRedux.useDispatch();
34270
34783
  const context = React.useContext(SearchResultsConfigurationContext);
34271
34784
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
34272
- const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry, trajectEditLineGuid } = reactRedux.useSelector((state) => state.searchResults);
34785
+ const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry, trajectEditLineGuid, trajectResolving, trajectItineraryView } = reactRedux.useSelector((state) => state.searchResults);
34273
34786
  const isMobile = useMediaQuery('(max-width: 1200px)');
34274
34787
  // Resolves live availability per traject node; no-op unless a traject entry is configured.
34275
34788
  useTrajectAvailability();
34789
+ // The entry as the backend can price it: a traject swaps in the guids its searches cached.
34790
+ const bookableEntry = useBookableEntry();
34276
34791
  const [initialFiltersSet, setInitialFiltersSet] = React.useState(false);
34277
34792
  const [initialFlightFiltersSet, setInitialFlightFiltersSet] = React.useState(false);
34278
34793
  const [filtersOpen, setFiltersOpen] = React.useState(false);
@@ -35039,6 +35554,10 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35039
35554
  const fetchPriceDetails = async () => {
35040
35555
  if (!context || !editablePackagingEntry || lodash.isEmpty(editablePackagingEntry.lines))
35041
35556
  return;
35557
+ // A traject resolves one node at a time. Pricing each step would show a total that climbs
35558
+ // as the trip fills in, so the whole trip is priced once, when the last node is in.
35559
+ if (context.trajectEntry && trajectResolving)
35560
+ return;
35042
35561
  setPricesAreLoading(true);
35043
35562
  try {
35044
35563
  const config = {
@@ -35050,7 +35569,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35050
35569
  officeId: context.tideConnection.officeId,
35051
35570
  catalogueId: context.searchConfiguration.defaultCatalogueId ?? lodash.first(context?.tideConnection?.catalogueIds) ?? 1,
35052
35571
  agentId: context.agentId,
35053
- payload: editablePackagingEntry
35572
+ payload: bookableEntry ?? editablePackagingEntry
35054
35573
  };
35055
35574
  const priceDetails = await build.getPriceDetails(config, request);
35056
35575
  dispatch(setPriceDetails(priceDetails));
@@ -35061,11 +35580,15 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35061
35580
  setPricesAreLoading(false);
35062
35581
  }
35063
35582
  };
35583
+ fetchPriceDetails();
35584
+ }, [editablePackagingEntry, bookableEntry, trajectResolving]);
35585
+ React.useEffect(() => {
35064
35586
  const fetchItinerary = async () => {
35065
35587
  if (!context || !context.packagingEntry || !editablePackagingEntry || lodash.isEmpty(editablePackagingEntry.lines))
35066
35588
  return;
35067
- // The traject view renders its own day-by-day column, so the generated itinerary is unused.
35068
- if (context.trajectEntry)
35589
+ // While a traject is being composed its own day-by-day column is the itinerary; the generated
35590
+ // one is what the traveller reads the finished trip back from, so it waits until then.
35591
+ if (context.trajectEntry && (trajectResolving || !trajectItineraryView))
35069
35592
  return;
35070
35593
  setItineraryIsLoading(true);
35071
35594
  try {
@@ -35078,7 +35601,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35078
35601
  officeId: context.tideConnection.officeId,
35079
35602
  catalogueId: context.searchConfiguration.defaultCatalogueId ?? lodash.first(context?.tideConnection?.catalogueIds) ?? 1,
35080
35603
  agentId: context.agentId,
35081
- payload: editablePackagingEntry
35604
+ payload: bookableEntry ?? editablePackagingEntry
35082
35605
  };
35083
35606
  const itinerary = await build.getItinerary(config, request);
35084
35607
  dispatch(setItinerary(itinerary));
@@ -35089,9 +35612,8 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35089
35612
  setItineraryIsLoading(false);
35090
35613
  }
35091
35614
  };
35092
- fetchPriceDetails();
35093
35615
  fetchItinerary();
35094
- }, [editablePackagingEntry]);
35616
+ }, [editablePackagingEntry, bookableEntry, trajectResolving, trajectItineraryView]);
35095
35617
  // Flight selection
35096
35618
  // const [selectedOutwardKey, setSelectedOutwardKey] = useState<string | null>(null);
35097
35619
  // const [selectedReturnKey, setSelectedReturnKey] = useState<string | null>(null);
@@ -35455,7 +35977,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35455
35977
  context.searchConfiguration.qsmType != build.PortalQsmType.AccommodationAndFlight && context.showFilters && (React__default["default"].createElement(Filters, { initialFilters: initialFilters, filters: filters, isOpen: filtersOpen, handleSetIsOpen: () => setFiltersOpen(!filtersOpen),
35456
35978
  // handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
35457
35979
  isLoading: isLoading, setFilters: (filters) => dispatch(setFilters(filters)), resetFilters: (filters) => dispatch(resetFilters(filters)) })),
35458
- context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default["default"].createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading, onEditAccommodation: handleEditAccommodation })),
35980
+ context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && (React__default["default"].createElement(Itinerary, { isOpen: itineraryOpen, handleSetIsOpen: () => setItineraryOpen(!itineraryOpen), isLoading: isLoading || pricesAreLoading || flightsLoading || itineraryIsLoading || trajectResolving, onEditAccommodation: handleEditAccommodation })),
35459
35981
  React__default["default"].createElement("div", { className: "search__results" },
35460
35982
  isMobile && (React__default["default"].createElement("div", { className: "search__result-row" },
35461
35983
  React__default["default"].createElement("div", { className: "search__results__actions" },
@@ -35529,7 +36051,8 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
35529
36051
  React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--extended" },
35530
36052
  selectedReturnKey && selectedReturn && (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${selectedReturnKey}`, item: selectedReturn.return, guid: selectedReturn.outwardGuid, selectedGuid: selectedReturn.outwardGuid, isOutward: false, showSelectedState: true, price: selectedReturn.price })),
35531
36053
  uniqueReturnFlights.map((result) => (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.return, onSelect: () => dispatch(setSelectedReturnKey(getFlightKey(result.return.segments))), guid: result.outwardGuid, isOutward: false, currentSelectedPrice: selectedReturn?.price, price: result.price })))))),
35532
- context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && (React__default["default"].createElement(TrajectResults, { isLoading: isLoading })),
36054
+ context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && !trajectItineraryView && (React__default["default"].createElement(TrajectResults, { isLoading: isLoading })),
36055
+ context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && trajectItineraryView && (React__default["default"].createElement(FullItinerary, { isLoading: itineraryIsLoading })),
35533
36056
  context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.packagingEntry && !context.trajectEntry && (React__default["default"].createElement(FullItinerary, { isLoading: itineraryIsLoading })))),
35534
36057
  React__default["default"].createElement(FlyIn, { srpType: context.searchConfiguration.qsmType, isOpen: flyInIsOpen, setIsOpen: handleFlyInToggle, handleConfirm: () => handleConfirmHotelSwap(), onPanelRef: (el) => (panelRef.current = el), detailsLoading: detailsIsLoading, flyInType: flyInType, isPackageEditFlow: !!context.packagingEntry, sortByTypes: sortByTypes, activeSearchSeed: activeSearchSeed, toggleFilters: () => setFiltersOpen(!filtersOpen), filtersOpen: filtersOpen })))))))));
35535
36058
  };