@qite/tide-components 1.0.14-preview.2 → 1.0.14-preview.4

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.
@@ -480,6 +480,39 @@ var FORM$f = {
480
480
  YES: "نعم",
481
481
  NO: "لا"
482
482
  };
483
+ var AGENT_ENTRIES$f = {
484
+ TITLE: "الحجوزات",
485
+ MY_BOOKINGS: "حجوزاتي",
486
+ NUMBER: "الرقم",
487
+ DEPARTURE_DATE: "تاريخ المغادرة",
488
+ STATUS: "الحالة",
489
+ CUSTOM_STATUS: "حالة مخصصة",
490
+ RETURN_DATE: "تاريخ العودة",
491
+ PROFIT: "الربح",
492
+ NETTO_SELLING_PRICE: "صافي سعر البيع",
493
+ YOUR_SURCHARGE: "رسومك الإضافية",
494
+ CREATED: "تاريخ الإنشاء",
495
+ CONTACT: "جهة الاتصال",
496
+ MAIN_BOOKER: "الحاجز الرئيسي",
497
+ PRODUCT: "المنتج",
498
+ TRAVELERS: "المسافرون",
499
+ ACTIONS: "الإجراءات",
500
+ DETAILS: "التفاصيل",
501
+ HIDE_DETAILS: "إخفاء التفاصيل",
502
+ PRINTS: "المطبوعات",
503
+ ALL: "الكل",
504
+ X_ITEMS: "{0} عناصر",
505
+ PAGE_SIZE: "عناصر لكل صفحة",
506
+ PREVIOUS: "السابق",
507
+ NEXT: "التالي",
508
+ PAGE_X_OF_Y: "الصفحة {0} من {1}",
509
+ LOADING: "جارٍ التحميل...",
510
+ NO_ITEMS: "لم يتم العثور على حجوزات.",
511
+ ERROR: "حدث خطأ أثناء تحميل حجوزاتك.",
512
+ PRINT_ERROR: "فشلت الطباعة، يرجى المحاولة مرة أخرى.",
513
+ NOT_LOGGED_IN: "سجّل الدخول كوكيل لعرض حجوزاتك.",
514
+ SESSION_EXPIRED: "انتهت صلاحية جلستك، يرجى تسجيل الدخول مرة أخرى."
515
+ };
483
516
  var arJson = {
484
517
  STEPS: STEPS$f,
485
518
  INPUT: INPUT$f,
@@ -500,7 +533,8 @@ var arJson = {
500
533
  QSM: QSM$g,
501
534
  SRP: SRP$f,
502
535
  ITINERARY: ITINERARY$f,
503
- FORM: FORM$f
536
+ FORM: FORM$f,
537
+ AGENT_ENTRIES: AGENT_ENTRIES$f
504
538
  };
505
539
 
506
540
  var STEPS$e = {
@@ -953,6 +987,39 @@ var FORM$e = {
953
987
  YES: "Ja",
954
988
  NO: "Nej"
955
989
  };
990
+ var AGENT_ENTRIES$e = {
991
+ TITLE: "Bookinger",
992
+ MY_BOOKINGS: "Mine bookinger",
993
+ NUMBER: "Nummer",
994
+ DEPARTURE_DATE: "Afrejsedato",
995
+ STATUS: "Status",
996
+ CUSTOM_STATUS: "Tilpasset status",
997
+ RETURN_DATE: "Hjemrejsedato",
998
+ PROFIT: "Fortjeneste",
999
+ NETTO_SELLING_PRICE: "Netto salgspris",
1000
+ YOUR_SURCHARGE: "Dit tillæg",
1001
+ CREATED: "Oprettet",
1002
+ CONTACT: "Kontakt",
1003
+ MAIN_BOOKER: "Hovedbooker",
1004
+ PRODUCT: "Produkt",
1005
+ TRAVELERS: "Rejsende",
1006
+ ACTIONS: "Handlinger",
1007
+ DETAILS: "Detaljer",
1008
+ HIDE_DETAILS: "Skjul detaljer",
1009
+ PRINTS: "Udskrifter",
1010
+ ALL: "Alle",
1011
+ X_ITEMS: "{0} elementer",
1012
+ PAGE_SIZE: "Elementer pr. side",
1013
+ PREVIOUS: "Forrige",
1014
+ NEXT: "Næste",
1015
+ PAGE_X_OF_Y: "Side {0} af {1}",
1016
+ LOADING: "Indlæser...",
1017
+ NO_ITEMS: "Ingen bookinger fundet.",
1018
+ ERROR: "Der opstod en fejl under indlæsning af dine bookinger.",
1019
+ PRINT_ERROR: "Udskrivning mislykkedes, prøv igen.",
1020
+ NOT_LOGGED_IN: "Log ind som agent for at se dine bookinger.",
1021
+ SESSION_EXPIRED: "Din session er udløbet, log ind igen."
1022
+ };
956
1023
  var daJson = {
957
1024
  STEPS: STEPS$e,
958
1025
  INPUT: INPUT$e,
@@ -973,7 +1040,8 @@ var daJson = {
973
1040
  QSM: QSM$f,
974
1041
  SRP: SRP$e,
975
1042
  ITINERARY: ITINERARY$e,
976
- FORM: FORM$e
1043
+ FORM: FORM$e,
1044
+ AGENT_ENTRIES: AGENT_ENTRIES$e
977
1045
  };
978
1046
 
979
1047
  var STEPS$d = {
@@ -1426,6 +1494,39 @@ var FORM$d = {
1426
1494
  YES: "Ja",
1427
1495
  NO: "Nein"
1428
1496
  };
1497
+ var AGENT_ENTRIES$d = {
1498
+ TITLE: "Buchungen",
1499
+ MY_BOOKINGS: "Meine Buchungen",
1500
+ NUMBER: "Nummer",
1501
+ DEPARTURE_DATE: "Abreisedatum",
1502
+ STATUS: "Status",
1503
+ CUSTOM_STATUS: "Benutzerdefinierter Status",
1504
+ RETURN_DATE: "Rückreisedatum",
1505
+ PROFIT: "Gewinn",
1506
+ NETTO_SELLING_PRICE: "Netto-Verkaufspreis",
1507
+ YOUR_SURCHARGE: "Ihr Aufschlag",
1508
+ CREATED: "Erstellt",
1509
+ CONTACT: "Kontakt",
1510
+ MAIN_BOOKER: "Hauptbucher",
1511
+ PRODUCT: "Produkt",
1512
+ TRAVELERS: "Reisende",
1513
+ ACTIONS: "Aktionen",
1514
+ DETAILS: "Details",
1515
+ HIDE_DETAILS: "Details ausblenden",
1516
+ PRINTS: "Drucke",
1517
+ ALL: "Alle",
1518
+ X_ITEMS: "{0} Einträge",
1519
+ PAGE_SIZE: "Einträge pro Seite",
1520
+ PREVIOUS: "Zurück",
1521
+ NEXT: "Weiter",
1522
+ PAGE_X_OF_Y: "Seite {0} von {1}",
1523
+ LOADING: "Wird geladen...",
1524
+ NO_ITEMS: "Keine Buchungen gefunden.",
1525
+ ERROR: "Beim Laden Ihrer Buchungen ist ein Fehler aufgetreten.",
1526
+ PRINT_ERROR: "Drucken fehlgeschlagen, bitte versuchen Sie es erneut.",
1527
+ NOT_LOGGED_IN: "Melden Sie sich als Agent an, um Ihre Buchungen zu sehen.",
1528
+ SESSION_EXPIRED: "Ihre Sitzung ist abgelaufen, bitte melden Sie sich erneut an."
1529
+ };
1429
1530
  var deJson = {
1430
1531
  STEPS: STEPS$d,
1431
1532
  INPUT: INPUT$d,
@@ -1446,7 +1547,8 @@ var deJson = {
1446
1547
  QSM: QSM$e,
1447
1548
  SRP: SRP$d,
1448
1549
  ITINERARY: ITINERARY$d,
1449
- FORM: FORM$d
1550
+ FORM: FORM$d,
1551
+ AGENT_ENTRIES: AGENT_ENTRIES$d
1450
1552
  };
1451
1553
 
1452
1554
  var STEPS$c = {
@@ -1903,6 +2005,39 @@ var FORM$c = {
1903
2005
  YES: "Yes",
1904
2006
  NO: "No"
1905
2007
  };
2008
+ var AGENT_ENTRIES$c = {
2009
+ TITLE: "Bookings",
2010
+ MY_BOOKINGS: "My bookings",
2011
+ NUMBER: "Number",
2012
+ DEPARTURE_DATE: "Departure date",
2013
+ STATUS: "Status",
2014
+ CUSTOM_STATUS: "Custom status",
2015
+ RETURN_DATE: "Return date",
2016
+ PROFIT: "Profit",
2017
+ NETTO_SELLING_PRICE: "Netto selling price",
2018
+ YOUR_SURCHARGE: "Your surcharge",
2019
+ CREATED: "Created",
2020
+ CONTACT: "Contact",
2021
+ MAIN_BOOKER: "Main booker",
2022
+ PRODUCT: "Product",
2023
+ TRAVELERS: "Travellers",
2024
+ ACTIONS: "Actions",
2025
+ DETAILS: "Details",
2026
+ HIDE_DETAILS: "Hide details",
2027
+ PRINTS: "Prints",
2028
+ ALL: "All",
2029
+ X_ITEMS: "{0} items",
2030
+ PAGE_SIZE: "Items per page",
2031
+ PREVIOUS: "Previous",
2032
+ NEXT: "Next",
2033
+ PAGE_X_OF_Y: "Page {0} of {1}",
2034
+ LOADING: "Loading...",
2035
+ NO_ITEMS: "No bookings found.",
2036
+ ERROR: "Something went wrong while loading your bookings.",
2037
+ PRINT_ERROR: "Printing failed, please try again.",
2038
+ NOT_LOGGED_IN: "Log in as an agent to see your bookings.",
2039
+ SESSION_EXPIRED: "Your session has expired, please log in again."
2040
+ };
1906
2041
  var enJson = {
1907
2042
  STEPS: STEPS$c,
1908
2043
  INPUT: INPUT$c,
@@ -1923,7 +2058,8 @@ var enJson = {
1923
2058
  QSM: QSM$d,
1924
2059
  SRP: SRP$c,
1925
2060
  ITINERARY: ITINERARY$c,
1926
- FORM: FORM$c
2061
+ FORM: FORM$c,
2062
+ AGENT_ENTRIES: AGENT_ENTRIES$c
1927
2063
  };
1928
2064
 
1929
2065
  var STEPS$b = {
@@ -2376,6 +2512,39 @@ var FORM$b = {
2376
2512
  YES: "Sí",
2377
2513
  NO: "No"
2378
2514
  };
2515
+ var AGENT_ENTRIES$b = {
2516
+ TITLE: "Reservas",
2517
+ MY_BOOKINGS: "Mis reservas",
2518
+ NUMBER: "Número",
2519
+ DEPARTURE_DATE: "Fecha de salida",
2520
+ STATUS: "Estado",
2521
+ CUSTOM_STATUS: "Estado personalizado",
2522
+ RETURN_DATE: "Fecha de regreso",
2523
+ PROFIT: "Beneficio",
2524
+ NETTO_SELLING_PRICE: "Precio de venta neto",
2525
+ YOUR_SURCHARGE: "Su recargo",
2526
+ CREATED: "Creado",
2527
+ CONTACT: "Contacto",
2528
+ MAIN_BOOKER: "Titular de la reserva",
2529
+ PRODUCT: "Producto",
2530
+ TRAVELERS: "Viajeros",
2531
+ ACTIONS: "Acciones",
2532
+ DETAILS: "Detalles",
2533
+ HIDE_DETAILS: "Ocultar detalles",
2534
+ PRINTS: "Impresiones",
2535
+ ALL: "Todos",
2536
+ X_ITEMS: "{0} elementos",
2537
+ PAGE_SIZE: "Elementos por página",
2538
+ PREVIOUS: "Anterior",
2539
+ NEXT: "Siguiente",
2540
+ PAGE_X_OF_Y: "Página {0} de {1}",
2541
+ LOADING: "Cargando...",
2542
+ NO_ITEMS: "No se encontraron reservas.",
2543
+ ERROR: "Se produjo un error al cargar sus reservas.",
2544
+ PRINT_ERROR: "La impresión ha fallado, inténtelo de nuevo.",
2545
+ NOT_LOGGED_IN: "Inicie sesión como agente para ver sus reservas.",
2546
+ SESSION_EXPIRED: "Su sesión ha caducado, inicie sesión de nuevo."
2547
+ };
2379
2548
  var esJson = {
2380
2549
  STEPS: STEPS$b,
2381
2550
  INPUT: INPUT$b,
@@ -2396,7 +2565,8 @@ var esJson = {
2396
2565
  QSM: QSM$c,
2397
2566
  SRP: SRP$b,
2398
2567
  ITINERARY: ITINERARY$b,
2399
- FORM: FORM$b
2568
+ FORM: FORM$b,
2569
+ AGENT_ENTRIES: AGENT_ENTRIES$b
2400
2570
  };
2401
2571
 
2402
2572
  var STEPS$a = {
@@ -2853,6 +3023,39 @@ var FORM$a = {
2853
3023
  YES: "Oui",
2854
3024
  NO: "Non"
2855
3025
  };
3026
+ var AGENT_ENTRIES$a = {
3027
+ TITLE: "Réservations",
3028
+ MY_BOOKINGS: "Mes réservations",
3029
+ NUMBER: "Numéro",
3030
+ DEPARTURE_DATE: "Date de départ",
3031
+ STATUS: "Statut",
3032
+ CUSTOM_STATUS: "Statut personnalisé",
3033
+ RETURN_DATE: "Date de retour",
3034
+ PROFIT: "Bénéfice",
3035
+ NETTO_SELLING_PRICE: "Prix de vente net",
3036
+ YOUR_SURCHARGE: "Votre supplément",
3037
+ CREATED: "Créé le",
3038
+ CONTACT: "Contact",
3039
+ MAIN_BOOKER: "Réservant principal",
3040
+ PRODUCT: "Produit",
3041
+ TRAVELERS: "Voyageurs",
3042
+ ACTIONS: "Actions",
3043
+ DETAILS: "Détails",
3044
+ HIDE_DETAILS: "Masquer les détails",
3045
+ PRINTS: "Impressions",
3046
+ ALL: "Tous",
3047
+ X_ITEMS: "{0} éléments",
3048
+ PAGE_SIZE: "Éléments par page",
3049
+ PREVIOUS: "Précédent",
3050
+ NEXT: "Suivant",
3051
+ PAGE_X_OF_Y: "Page {0} sur {1}",
3052
+ LOADING: "Chargement...",
3053
+ NO_ITEMS: "Aucune réservation trouvée.",
3054
+ ERROR: "Une erreur est survenue lors du chargement de vos réservations.",
3055
+ PRINT_ERROR: "L'impression a échoué, veuillez réessayer.",
3056
+ NOT_LOGGED_IN: "Connectez-vous en tant qu'agent pour voir vos réservations.",
3057
+ SESSION_EXPIRED: "Votre session a expiré, veuillez vous reconnecter."
3058
+ };
2856
3059
  var frBeJson = {
2857
3060
  STEPS: STEPS$a,
2858
3061
  INPUT: INPUT$a,
@@ -2873,7 +3076,8 @@ var frBeJson = {
2873
3076
  QSM: QSM$b,
2874
3077
  SRP: SRP$a,
2875
3078
  ITINERARY: ITINERARY$a,
2876
- FORM: FORM$a
3079
+ FORM: FORM$a,
3080
+ AGENT_ENTRIES: AGENT_ENTRIES$a
2877
3081
  };
2878
3082
 
2879
3083
  var STEPS$9 = {
@@ -3326,6 +3530,39 @@ var FORM$9 = {
3326
3530
  YES: "Oui",
3327
3531
  NO: "Non"
3328
3532
  };
3533
+ var AGENT_ENTRIES$9 = {
3534
+ TITLE: "Réservations",
3535
+ MY_BOOKINGS: "Mes réservations",
3536
+ NUMBER: "Numéro",
3537
+ DEPARTURE_DATE: "Date de départ",
3538
+ STATUS: "Statut",
3539
+ CUSTOM_STATUS: "Statut personnalisé",
3540
+ RETURN_DATE: "Date de retour",
3541
+ PROFIT: "Bénéfice",
3542
+ NETTO_SELLING_PRICE: "Prix de vente net",
3543
+ YOUR_SURCHARGE: "Votre supplément",
3544
+ CREATED: "Créé le",
3545
+ CONTACT: "Contact",
3546
+ MAIN_BOOKER: "Réservant principal",
3547
+ PRODUCT: "Produit",
3548
+ TRAVELERS: "Voyageurs",
3549
+ ACTIONS: "Actions",
3550
+ DETAILS: "Détails",
3551
+ HIDE_DETAILS: "Masquer les détails",
3552
+ PRINTS: "Impressions",
3553
+ ALL: "Tous",
3554
+ X_ITEMS: "{0} éléments",
3555
+ PAGE_SIZE: "Éléments par page",
3556
+ PREVIOUS: "Précédent",
3557
+ NEXT: "Suivant",
3558
+ PAGE_X_OF_Y: "Page {0} sur {1}",
3559
+ LOADING: "Chargement...",
3560
+ NO_ITEMS: "Aucune réservation trouvée.",
3561
+ ERROR: "Une erreur est survenue lors du chargement de vos réservations.",
3562
+ PRINT_ERROR: "L'impression a échoué, veuillez réessayer.",
3563
+ NOT_LOGGED_IN: "Connectez-vous en tant qu'agent pour voir vos réservations.",
3564
+ SESSION_EXPIRED: "Votre session a expiré, veuillez vous reconnecter."
3565
+ };
3329
3566
  var frFrJson = {
3330
3567
  STEPS: STEPS$9,
3331
3568
  INPUT: INPUT$9,
@@ -3346,7 +3583,8 @@ var frFrJson = {
3346
3583
  QSM: QSM$a,
3347
3584
  SRP: SRP$9,
3348
3585
  ITINERARY: ITINERARY$9,
3349
- FORM: FORM$9
3586
+ FORM: FORM$9,
3587
+ AGENT_ENTRIES: AGENT_ENTRIES$9
3350
3588
  };
3351
3589
 
3352
3590
  var STEPS$8 = {
@@ -3799,6 +4037,39 @@ var FORM$8 = {
3799
4037
  YES: "Já",
3800
4038
  NO: "Nei"
3801
4039
  };
4040
+ var AGENT_ENTRIES$8 = {
4041
+ TITLE: "Bókanir",
4042
+ MY_BOOKINGS: "Mínar bókanir",
4043
+ NUMBER: "Númer",
4044
+ DEPARTURE_DATE: "Brottfarardagur",
4045
+ STATUS: "Staða",
4046
+ CUSTOM_STATUS: "Sérsniðin staða",
4047
+ RETURN_DATE: "Heimkomudagur",
4048
+ PROFIT: "Hagnaður",
4049
+ NETTO_SELLING_PRICE: "Nettó söluverð",
4050
+ YOUR_SURCHARGE: "Þitt álag",
4051
+ CREATED: "Stofnað",
4052
+ CONTACT: "Tengiliður",
4053
+ MAIN_BOOKER: "Aðalbókandi",
4054
+ PRODUCT: "Vara",
4055
+ TRAVELERS: "Ferðalangar",
4056
+ ACTIONS: "Aðgerðir",
4057
+ DETAILS: "Nánar",
4058
+ HIDE_DETAILS: "Fela nánar",
4059
+ PRINTS: "Útprentanir",
4060
+ ALL: "Allt",
4061
+ X_ITEMS: "{0} atriði",
4062
+ PAGE_SIZE: "Atriði á síðu",
4063
+ PREVIOUS: "Fyrri",
4064
+ NEXT: "Næsta",
4065
+ PAGE_X_OF_Y: "Síða {0} af {1}",
4066
+ LOADING: "Hleður...",
4067
+ NO_ITEMS: "Engar bókanir fundust.",
4068
+ ERROR: "Eitthvað fór úrskeiðis við að hlaða bókunum þínum.",
4069
+ PRINT_ERROR: "Prentun mistókst, reyndu aftur.",
4070
+ NOT_LOGGED_IN: "Skráðu þig inn sem umboðsaðili til að sjá bókanir þínar.",
4071
+ SESSION_EXPIRED: "Lotan þín er útrunnin, skráðu þig inn aftur."
4072
+ };
3802
4073
  var isJson = {
3803
4074
  STEPS: STEPS$8,
3804
4075
  INPUT: INPUT$8,
@@ -3819,7 +4090,8 @@ var isJson = {
3819
4090
  QSM: QSM$9,
3820
4091
  SRP: SRP$8,
3821
4092
  ITINERARY: ITINERARY$8,
3822
- FORM: FORM$8
4093
+ FORM: FORM$8,
4094
+ AGENT_ENTRIES: AGENT_ENTRIES$8
3823
4095
  };
3824
4096
 
3825
4097
  var STEPS$7 = {
@@ -4272,6 +4544,39 @@ var FORM$7 = {
4272
4544
  YES: "Sì",
4273
4545
  NO: "No"
4274
4546
  };
4547
+ var AGENT_ENTRIES$7 = {
4548
+ TITLE: "Prenotazioni",
4549
+ MY_BOOKINGS: "Le mie prenotazioni",
4550
+ NUMBER: "Numero",
4551
+ DEPARTURE_DATE: "Data di partenza",
4552
+ STATUS: "Stato",
4553
+ CUSTOM_STATUS: "Stato personalizzato",
4554
+ RETURN_DATE: "Data di ritorno",
4555
+ PROFIT: "Profitto",
4556
+ NETTO_SELLING_PRICE: "Prezzo di vendita netto",
4557
+ YOUR_SURCHARGE: "Il tuo supplemento",
4558
+ CREATED: "Creato",
4559
+ CONTACT: "Contatto",
4560
+ MAIN_BOOKER: "Prenotante principale",
4561
+ PRODUCT: "Prodotto",
4562
+ TRAVELERS: "Viaggiatori",
4563
+ ACTIONS: "Azioni",
4564
+ DETAILS: "Dettagli",
4565
+ HIDE_DETAILS: "Nascondi dettagli",
4566
+ PRINTS: "Stampe",
4567
+ ALL: "Tutti",
4568
+ X_ITEMS: "{0} elementi",
4569
+ PAGE_SIZE: "Elementi per pagina",
4570
+ PREVIOUS: "Precedente",
4571
+ NEXT: "Successivo",
4572
+ PAGE_X_OF_Y: "Pagina {0} di {1}",
4573
+ LOADING: "Caricamento...",
4574
+ NO_ITEMS: "Nessuna prenotazione trovata.",
4575
+ ERROR: "Si è verificato un errore durante il caricamento delle prenotazioni.",
4576
+ PRINT_ERROR: "Stampa non riuscita, riprova.",
4577
+ NOT_LOGGED_IN: "Accedi come agente per vedere le tue prenotazioni.",
4578
+ SESSION_EXPIRED: "La sessione è scaduta, accedi di nuovo."
4579
+ };
4275
4580
  var itJson = {
4276
4581
  STEPS: STEPS$7,
4277
4582
  INPUT: INPUT$7,
@@ -4292,7 +4597,8 @@ var itJson = {
4292
4597
  QSM: QSM$8,
4293
4598
  SRP: SRP$7,
4294
4599
  ITINERARY: ITINERARY$7,
4295
- FORM: FORM$7
4600
+ FORM: FORM$7,
4601
+ AGENT_ENTRIES: AGENT_ENTRIES$7
4296
4602
  };
4297
4603
 
4298
4604
  var STEPS$6 = {
@@ -4749,6 +5055,39 @@ var FORM$6 = {
4749
5055
  YES: "Ja",
4750
5056
  NO: "Nee"
4751
5057
  };
5058
+ var AGENT_ENTRIES$6 = {
5059
+ TITLE: "Boekingen",
5060
+ MY_BOOKINGS: "Mijn boekingen",
5061
+ NUMBER: "Nummer",
5062
+ DEPARTURE_DATE: "Vertrekdatum",
5063
+ STATUS: "Status",
5064
+ CUSTOM_STATUS: "Aangepaste status",
5065
+ RETURN_DATE: "Terugkeerdatum",
5066
+ PROFIT: "Winst",
5067
+ NETTO_SELLING_PRICE: "Netto verkoopprijs",
5068
+ YOUR_SURCHARGE: "Jouw toeslag",
5069
+ CREATED: "Aangemaakt",
5070
+ CONTACT: "Contact",
5071
+ MAIN_BOOKER: "Hoofdboeker",
5072
+ PRODUCT: "Product",
5073
+ TRAVELERS: "Reizigers",
5074
+ ACTIONS: "Acties",
5075
+ DETAILS: "Details",
5076
+ HIDE_DETAILS: "Details verbergen",
5077
+ PRINTS: "Afdrukken",
5078
+ ALL: "Alle",
5079
+ X_ITEMS: "{0} items",
5080
+ PAGE_SIZE: "Items per pagina",
5081
+ PREVIOUS: "Vorige",
5082
+ NEXT: "Volgende",
5083
+ PAGE_X_OF_Y: "Pagina {0} van {1}",
5084
+ LOADING: "Laden...",
5085
+ NO_ITEMS: "Geen boekingen gevonden.",
5086
+ ERROR: "Er ging iets mis bij het laden van je boekingen.",
5087
+ PRINT_ERROR: "Afdrukken mislukt, probeer het opnieuw.",
5088
+ NOT_LOGGED_IN: "Log in als agent om je boekingen te zien.",
5089
+ SESSION_EXPIRED: "Je sessie is verlopen, log opnieuw in."
5090
+ };
4752
5091
  var nlBeJson = {
4753
5092
  STEPS: STEPS$6,
4754
5093
  INPUT: INPUT$6,
@@ -4769,7 +5108,8 @@ var nlBeJson = {
4769
5108
  QSM: QSM$7,
4770
5109
  SRP: SRP$6,
4771
5110
  ITINERARY: ITINERARY$6,
4772
- FORM: FORM$6
5111
+ FORM: FORM$6,
5112
+ AGENT_ENTRIES: AGENT_ENTRIES$6
4773
5113
  };
4774
5114
 
4775
5115
  var STEPS$5 = {
@@ -5222,6 +5562,39 @@ var FORM$5 = {
5222
5562
  YES: "Ja",
5223
5563
  NO: "Nee"
5224
5564
  };
5565
+ var AGENT_ENTRIES$5 = {
5566
+ TITLE: "Boekingen",
5567
+ MY_BOOKINGS: "Mijn boekingen",
5568
+ NUMBER: "Nummer",
5569
+ DEPARTURE_DATE: "Vertrekdatum",
5570
+ STATUS: "Status",
5571
+ CUSTOM_STATUS: "Aangepaste status",
5572
+ RETURN_DATE: "Terugkeerdatum",
5573
+ PROFIT: "Winst",
5574
+ NETTO_SELLING_PRICE: "Netto verkoopprijs",
5575
+ YOUR_SURCHARGE: "Jouw toeslag",
5576
+ CREATED: "Aangemaakt",
5577
+ CONTACT: "Contact",
5578
+ MAIN_BOOKER: "Hoofdboeker",
5579
+ PRODUCT: "Product",
5580
+ TRAVELERS: "Reizigers",
5581
+ ACTIONS: "Acties",
5582
+ DETAILS: "Details",
5583
+ HIDE_DETAILS: "Details verbergen",
5584
+ PRINTS: "Afdrukken",
5585
+ ALL: "Alle",
5586
+ X_ITEMS: "{0} items",
5587
+ PAGE_SIZE: "Items per pagina",
5588
+ PREVIOUS: "Vorige",
5589
+ NEXT: "Volgende",
5590
+ PAGE_X_OF_Y: "Pagina {0} van {1}",
5591
+ LOADING: "Laden...",
5592
+ NO_ITEMS: "Geen boekingen gevonden.",
5593
+ ERROR: "Er ging iets mis bij het laden van je boekingen.",
5594
+ PRINT_ERROR: "Afdrukken mislukt, probeer het opnieuw.",
5595
+ NOT_LOGGED_IN: "Log in als agent om je boekingen te zien.",
5596
+ SESSION_EXPIRED: "Je sessie is verlopen, log opnieuw in."
5597
+ };
5225
5598
  var nlNlJson = {
5226
5599
  STEPS: STEPS$5,
5227
5600
  INPUT: INPUT$5,
@@ -5242,7 +5615,8 @@ var nlNlJson = {
5242
5615
  QSM: QSM$6,
5243
5616
  SRP: SRP$5,
5244
5617
  ITINERARY: ITINERARY$5,
5245
- FORM: FORM$5
5618
+ FORM: FORM$5,
5619
+ AGENT_ENTRIES: AGENT_ENTRIES$5
5246
5620
  };
5247
5621
 
5248
5622
  var STEPS$4 = {
@@ -5695,6 +6069,39 @@ var FORM$4 = {
5695
6069
  YES: "Ja",
5696
6070
  NO: "Nei"
5697
6071
  };
6072
+ var AGENT_ENTRIES$4 = {
6073
+ TITLE: "Bestillinger",
6074
+ MY_BOOKINGS: "Mine bestillinger",
6075
+ NUMBER: "Nummer",
6076
+ DEPARTURE_DATE: "Avreisedato",
6077
+ STATUS: "Status",
6078
+ CUSTOM_STATUS: "Egendefinert status",
6079
+ RETURN_DATE: "Returdato",
6080
+ PROFIT: "Fortjeneste",
6081
+ NETTO_SELLING_PRICE: "Netto salgspris",
6082
+ YOUR_SURCHARGE: "Ditt tillegg",
6083
+ CREATED: "Opprettet",
6084
+ CONTACT: "Kontakt",
6085
+ MAIN_BOOKER: "Hovedbestiller",
6086
+ PRODUCT: "Produkt",
6087
+ TRAVELERS: "Reisende",
6088
+ ACTIONS: "Handlinger",
6089
+ DETAILS: "Detaljer",
6090
+ HIDE_DETAILS: "Skjul detaljer",
6091
+ PRINTS: "Utskrifter",
6092
+ ALL: "Alle",
6093
+ X_ITEMS: "{0} elementer",
6094
+ PAGE_SIZE: "Elementer per side",
6095
+ PREVIOUS: "Forrige",
6096
+ NEXT: "Neste",
6097
+ PAGE_X_OF_Y: "Side {0} av {1}",
6098
+ LOADING: "Laster...",
6099
+ NO_ITEMS: "Ingen bestillinger funnet.",
6100
+ ERROR: "Noe gikk galt under lasting av bestillingene dine.",
6101
+ PRINT_ERROR: "Utskrift mislyktes, prøv igjen.",
6102
+ NOT_LOGGED_IN: "Logg inn som agent for å se bestillingene dine.",
6103
+ SESSION_EXPIRED: "Økten din er utløpt, logg inn på nytt."
6104
+ };
5698
6105
  var noJson = {
5699
6106
  STEPS: STEPS$4,
5700
6107
  INPUT: INPUT$4,
@@ -5715,7 +6122,8 @@ var noJson = {
5715
6122
  QSM: QSM$5,
5716
6123
  SRP: SRP$4,
5717
6124
  ITINERARY: ITINERARY$4,
5718
- FORM: FORM$4
6125
+ FORM: FORM$4,
6126
+ AGENT_ENTRIES: AGENT_ENTRIES$4
5719
6127
  };
5720
6128
 
5721
6129
  var STEPS$3 = {
@@ -6168,6 +6576,39 @@ var FORM$3 = {
6168
6576
  YES: "Tak",
6169
6577
  NO: "Nie"
6170
6578
  };
6579
+ var AGENT_ENTRIES$3 = {
6580
+ TITLE: "Rezerwacje",
6581
+ MY_BOOKINGS: "Moje rezerwacje",
6582
+ NUMBER: "Numer",
6583
+ DEPARTURE_DATE: "Data wyjazdu",
6584
+ STATUS: "Status",
6585
+ CUSTOM_STATUS: "Status niestandardowy",
6586
+ RETURN_DATE: "Data powrotu",
6587
+ PROFIT: "Zysk",
6588
+ NETTO_SELLING_PRICE: "Cena sprzedaży netto",
6589
+ YOUR_SURCHARGE: "Twoja dopłata",
6590
+ CREATED: "Utworzono",
6591
+ CONTACT: "Kontakt",
6592
+ MAIN_BOOKER: "Główny rezerwujący",
6593
+ PRODUCT: "Produkt",
6594
+ TRAVELERS: "Podróżni",
6595
+ ACTIONS: "Akcje",
6596
+ DETAILS: "Szczegóły",
6597
+ HIDE_DETAILS: "Ukryj szczegóły",
6598
+ PRINTS: "Wydruki",
6599
+ ALL: "Wszystkie",
6600
+ X_ITEMS: "{0} pozycji",
6601
+ PAGE_SIZE: "Pozycji na stronę",
6602
+ PREVIOUS: "Poprzednia",
6603
+ NEXT: "Następna",
6604
+ PAGE_X_OF_Y: "Strona {0} z {1}",
6605
+ LOADING: "Ładowanie...",
6606
+ NO_ITEMS: "Nie znaleziono rezerwacji.",
6607
+ ERROR: "Wystąpił błąd podczas ładowania rezerwacji.",
6608
+ PRINT_ERROR: "Drukowanie nie powiodło się, spróbuj ponownie.",
6609
+ NOT_LOGGED_IN: "Zaloguj się jako agent, aby zobaczyć swoje rezerwacje.",
6610
+ SESSION_EXPIRED: "Twoja sesja wygasła, zaloguj się ponownie."
6611
+ };
6171
6612
  var plJson = {
6172
6613
  STEPS: STEPS$3,
6173
6614
  INPUT: INPUT$3,
@@ -6188,7 +6629,8 @@ var plJson = {
6188
6629
  QSM: QSM$4,
6189
6630
  SRP: SRP$3,
6190
6631
  ITINERARY: ITINERARY$3,
6191
- FORM: FORM$3
6632
+ FORM: FORM$3,
6633
+ AGENT_ENTRIES: AGENT_ENTRIES$3
6192
6634
  };
6193
6635
 
6194
6636
  var STEPS$2 = {
@@ -6641,6 +7083,39 @@ var FORM$2 = {
6641
7083
  YES: "Sim",
6642
7084
  NO: "Não"
6643
7085
  };
7086
+ var AGENT_ENTRIES$2 = {
7087
+ TITLE: "Reservas",
7088
+ MY_BOOKINGS: "As minhas reservas",
7089
+ NUMBER: "Número",
7090
+ DEPARTURE_DATE: "Data de partida",
7091
+ STATUS: "Estado",
7092
+ CUSTOM_STATUS: "Estado personalizado",
7093
+ RETURN_DATE: "Data de regresso",
7094
+ PROFIT: "Lucro",
7095
+ NETTO_SELLING_PRICE: "Preço de venda líquido",
7096
+ YOUR_SURCHARGE: "A sua sobretaxa",
7097
+ CREATED: "Criado",
7098
+ CONTACT: "Contacto",
7099
+ MAIN_BOOKER: "Titular da reserva",
7100
+ PRODUCT: "Produto",
7101
+ TRAVELERS: "Viajantes",
7102
+ ACTIONS: "Ações",
7103
+ DETAILS: "Detalhes",
7104
+ HIDE_DETAILS: "Ocultar detalhes",
7105
+ PRINTS: "Impressões",
7106
+ ALL: "Todos",
7107
+ X_ITEMS: "{0} itens",
7108
+ PAGE_SIZE: "Itens por página",
7109
+ PREVIOUS: "Anterior",
7110
+ NEXT: "Seguinte",
7111
+ PAGE_X_OF_Y: "Página {0} de {1}",
7112
+ LOADING: "A carregar...",
7113
+ NO_ITEMS: "Nenhuma reserva encontrada.",
7114
+ ERROR: "Ocorreu um erro ao carregar as suas reservas.",
7115
+ PRINT_ERROR: "A impressão falhou, tente novamente.",
7116
+ NOT_LOGGED_IN: "Inicie sessão como agente para ver as suas reservas.",
7117
+ SESSION_EXPIRED: "A sua sessão expirou, inicie sessão novamente."
7118
+ };
6644
7119
  var ptJson = {
6645
7120
  STEPS: STEPS$2,
6646
7121
  INPUT: INPUT$2,
@@ -6661,7 +7136,8 @@ var ptJson = {
6661
7136
  QSM: QSM$3,
6662
7137
  SRP: SRP$2,
6663
7138
  ITINERARY: ITINERARY$2,
6664
- FORM: FORM$2
7139
+ FORM: FORM$2,
7140
+ AGENT_ENTRIES: AGENT_ENTRIES$2
6665
7141
  };
6666
7142
 
6667
7143
  var STEPS$1 = {
@@ -7114,6 +7590,39 @@ var FORM$1 = {
7114
7590
  YES: "Ja",
7115
7591
  NO: "Nej"
7116
7592
  };
7593
+ var AGENT_ENTRIES$1 = {
7594
+ TITLE: "Bokningar",
7595
+ MY_BOOKINGS: "Mina bokningar",
7596
+ NUMBER: "Nummer",
7597
+ DEPARTURE_DATE: "Avresedatum",
7598
+ STATUS: "Status",
7599
+ CUSTOM_STATUS: "Anpassad status",
7600
+ RETURN_DATE: "Returdatum",
7601
+ PROFIT: "Vinst",
7602
+ NETTO_SELLING_PRICE: "Nettoförsäljningspris",
7603
+ YOUR_SURCHARGE: "Ditt tillägg",
7604
+ CREATED: "Skapad",
7605
+ CONTACT: "Kontakt",
7606
+ MAIN_BOOKER: "Huvudbokare",
7607
+ PRODUCT: "Produkt",
7608
+ TRAVELERS: "Resenärer",
7609
+ ACTIONS: "Åtgärder",
7610
+ DETAILS: "Detaljer",
7611
+ HIDE_DETAILS: "Dölj detaljer",
7612
+ PRINTS: "Utskrifter",
7613
+ ALL: "Alla",
7614
+ X_ITEMS: "{0} objekt",
7615
+ PAGE_SIZE: "Objekt per sida",
7616
+ PREVIOUS: "Föregående",
7617
+ NEXT: "Nästa",
7618
+ PAGE_X_OF_Y: "Sida {0} av {1}",
7619
+ LOADING: "Laddar...",
7620
+ NO_ITEMS: "Inga bokningar hittades.",
7621
+ ERROR: "Något gick fel när dina bokningar laddades.",
7622
+ PRINT_ERROR: "Utskriften misslyckades, försök igen.",
7623
+ NOT_LOGGED_IN: "Logga in som agent för att se dina bokningar.",
7624
+ SESSION_EXPIRED: "Din session har gått ut, logga in igen."
7625
+ };
7117
7626
  var svJson = {
7118
7627
  STEPS: STEPS$1,
7119
7628
  INPUT: INPUT$1,
@@ -7134,7 +7643,8 @@ var svJson = {
7134
7643
  QSM: QSM$2,
7135
7644
  SRP: SRP$1,
7136
7645
  ITINERARY: ITINERARY$1,
7137
- FORM: FORM$1
7646
+ FORM: FORM$1,
7647
+ AGENT_ENTRIES: AGENT_ENTRIES$1
7138
7648
  };
7139
7649
 
7140
7650
  var STEPS = {
@@ -7587,6 +8097,39 @@ var FORM = {
7587
8097
  YES: "はい",
7588
8098
  NO: "いいえ"
7589
8099
  };
8100
+ var AGENT_ENTRIES = {
8101
+ TITLE: "予約",
8102
+ MY_BOOKINGS: "マイ予約",
8103
+ NUMBER: "番号",
8104
+ DEPARTURE_DATE: "出発日",
8105
+ STATUS: "ステータス",
8106
+ CUSTOM_STATUS: "カスタムステータス",
8107
+ RETURN_DATE: "帰着日",
8108
+ PROFIT: "利益",
8109
+ NETTO_SELLING_PRICE: "正味販売価格",
8110
+ YOUR_SURCHARGE: "手数料",
8111
+ CREATED: "作成日",
8112
+ CONTACT: "連絡先",
8113
+ MAIN_BOOKER: "代表予約者",
8114
+ PRODUCT: "商品",
8115
+ TRAVELERS: "旅行者",
8116
+ ACTIONS: "操作",
8117
+ DETAILS: "詳細",
8118
+ HIDE_DETAILS: "詳細を隠す",
8119
+ PRINTS: "印刷",
8120
+ ALL: "すべて",
8121
+ X_ITEMS: "{0} 件",
8122
+ PAGE_SIZE: "1ページあたりの件数",
8123
+ PREVIOUS: "前へ",
8124
+ NEXT: "次へ",
8125
+ PAGE_X_OF_Y: "{0} / {1} ページ",
8126
+ LOADING: "読み込み中...",
8127
+ NO_ITEMS: "予約が見つかりません。",
8128
+ ERROR: "予約の読み込み中にエラーが発生しました。",
8129
+ PRINT_ERROR: "印刷に失敗しました。もう一度お試しください。",
8130
+ NOT_LOGGED_IN: "予約を表示するにはエージェントとしてログインしてください。",
8131
+ SESSION_EXPIRED: "セッションの有効期限が切れました。再度ログインしてください。"
8132
+ };
7590
8133
  var jaJson = {
7591
8134
  STEPS: STEPS,
7592
8135
  INPUT: INPUT,
@@ -7607,7 +8150,8 @@ var jaJson = {
7607
8150
  QSM: QSM$1,
7608
8151
  SRP: SRP,
7609
8152
  ITINERARY: ITINERARY,
7610
- FORM: FORM
8153
+ FORM: FORM,
8154
+ AGENT_ENTRIES: AGENT_ENTRIES
7611
8155
  };
7612
8156
 
7613
8157
  var DepartureRange;
@@ -15560,6 +16104,7 @@ var ENDPOINT$1 = "/api/web/packaging";
15560
16104
  var ENDPOINT_START_TRANSACTION = ENDPOINT$1 + "/start";
15561
16105
  var ENDPOINT_ACCOMMODATIONS = ENDPOINT$1 + "/accommodations";
15562
16106
  var ENDPOINT_EXCURSIONS = ENDPOINT$1 + "/excursions";
16107
+ var ENDPOINT_TRANSFERS = ENDPOINT$1 + "/transfers";
15563
16108
  var ENDPOINT_FLIGHTS = ENDPOINT$1 + "/flights";
15564
16109
  var ENDPOINT_PRICE_DETAILS = ENDPOINT$1 + "/price-details";
15565
16110
  var ENDPOINT_BOOK = ENDPOINT$1 + "/book";
@@ -15592,6 +16137,12 @@ var searchPackagingExcursions = function (config, request, signal) {
15592
16137
  var body = JSON.stringify(request);
15593
16138
  return post(url, apiKey, body, config.token, signal, true);
15594
16139
  };
16140
+ var searchPackagingTransfers = function (config, request, signal) {
16141
+ var url = "" + config.host + ENDPOINT_TRANSFERS;
16142
+ var apiKey = config.apiKey;
16143
+ var body = JSON.stringify(request);
16144
+ return post(url, apiKey, body, config.token, signal, true);
16145
+ };
15595
16146
  var getEntry = function (config, magicLinkCode, signal) {
15596
16147
  var apiKey = config.apiKey;
15597
16148
  var url = "" + config.host + ENDPOINT_ENTRY(magicLinkCode);
@@ -15769,6 +16320,7 @@ exports.searchOords = searchOords;
15769
16320
  exports.searchPackagingAccommodations = searchPackagingAccommodations;
15770
16321
  exports.searchPackagingExcursions = searchPackagingExcursions;
15771
16322
  exports.searchPackagingFlights = searchPackagingFlights;
16323
+ exports.searchPackagingTransfers = searchPackagingTransfers;
15772
16324
  exports.searchRegions = searchRegions;
15773
16325
  exports.searchWithErrorMapping = searchWithErrorMapping;
15774
16326
  exports.sendContactForm = sendContactForm;
@@ -19261,10 +19813,30 @@ function formatBirthDate$1(birthDate) {
19261
19813
  // A field can have separate "main-booker"/other-pax variants sharing the same identity
19262
19814
  // (customFieldConfigurationId for custom fields, fieldName for built-in fields).
19263
19815
  const MAIN_BOOKER_GROUP = 'main-booker';
19816
+ const MAIN_BOOKER_FIELD_PREFIX = 'mainBooker';
19264
19817
  const isCustomPaxField = (field) => field.customFieldConfigurationId != null;
19818
+ // Tide names the built-in main-booker fields with a prefix ('mainBookerGender', 'mainBookerCountryId', ...),
19819
+ // the other-pax ones without ('gender', 'countryId'). Strip it so both are variants of the same field.
19820
+ function normalizeBuiltInFieldName(field) {
19821
+ if (isCustomPaxField(field) || !field.fieldName?.startsWith(MAIN_BOOKER_FIELD_PREFIX))
19822
+ return field;
19823
+ const stripped = field.fieldName.slice(MAIN_BOOKER_FIELD_PREFIX.length);
19824
+ if (!stripped)
19825
+ return field;
19826
+ return { ...field, fieldName: stripped.charAt(0).toLowerCase() + stripped.slice(1) };
19827
+ }
19828
+ // Once Tide sends built-in fields, that configuration decides which built-in fields are shown/required;
19829
+ // the hardcoded formFields / core defaults are only the fallback for when it doesn't.
19830
+ function hasConfiguredBuiltInPaxFields(paxFields = []) {
19831
+ return paxFields.some((f) => !isCustomPaxField(f));
19832
+ }
19833
+ // The main booker's address/contact details are then asked on the main booker's own traveler block.
19834
+ function hasConfiguredMainBookerFields(paxFields = []) {
19835
+ return paxFields.some((f) => !isCustomPaxField(f) && f.group === MAIN_BOOKER_GROUP);
19836
+ }
19265
19837
  function resolveApplicablePaxFields(fields, isMainBooker) {
19266
19838
  const variantsByKey = new Map();
19267
- fields.forEach((field) => {
19839
+ fields.map(normalizeBuiltInFieldName).forEach((field) => {
19268
19840
  const key = field.customFieldConfigurationId ?? field.fieldName;
19269
19841
  const variants = variantsByKey.get(key) ?? [];
19270
19842
  variants.push(field);
@@ -19326,11 +19898,50 @@ const BUILT_IN_FIELD_PATHS = {
19326
19898
  // The 4 fields that always render/validate regardless of paxFields config (fallback behavior).
19327
19899
  const CORE_FIELD_NAMES = new Set(['gender', 'firstName', 'lastName', 'dateOfBirth']);
19328
19900
  const ADDRESS_FIELD_NAMES = ['street', 'location', 'countryId', 'postalCode', 'number'];
19901
+ // Built-in fields have no dataType from Tide; their control type and label follow from the fieldName.
19902
+ // gender, hasInsurance, countryId, weight and height have a dedicated control and only need a label here.
19903
+ function getBuiltInFieldControlMeta(translations) {
19904
+ return {
19905
+ gender: { label: translations.TRAVELERS_FORM.GENDER_ID },
19906
+ firstName: { label: translations.TRAVELERS_FORM.FIRST_NAME },
19907
+ lastName: { label: translations.TRAVELERS_FORM.LAST_NAME },
19908
+ dateOfBirth: { type: 'date', label: translations.TRAVELERS_FORM.BIRTHDATE },
19909
+ nickname: { label: translations.TRAVELERS_FORM.NICKNAME },
19910
+ birthplace: { label: translations.TRAVELERS_FORM.BIRTHPLACE },
19911
+ nationality: { label: translations.TRAVELERS_FORM.NATIONALITY },
19912
+ preferredLanguageId: { type: 'number', label: translations.TRAVELERS_FORM.PREFERRED_LANGUAGE },
19913
+ email: { type: 'email', label: translations.TRAVELERS_FORM.TRAVELER_EMAIL },
19914
+ phone: { type: 'tel', label: translations.TRAVELERS_FORM.TRAVELER_PHONE },
19915
+ mobile: { type: 'tel', label: translations.TRAVELERS_FORM.TRAVELER_MOBILE },
19916
+ passportNumber: { label: translations.TRAVELERS_FORM.PASSPORT_NUMBER },
19917
+ passportIssueDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_ISSUE_DATE },
19918
+ passportIssuedLocation: { label: translations.TRAVELERS_FORM.PASSPORT_ISSUED_LOCATION },
19919
+ passportExpiryDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_EXPIRY_DATE },
19920
+ emergencyNumber: { type: 'tel', label: translations.TRAVELERS_FORM.EMERGENCY_NUMBER },
19921
+ hasInsurance: { label: translations.TRAVELERS_FORM.HAS_INSURANCE },
19922
+ insuranceName: { label: translations.TRAVELERS_FORM.INSURANCE_NAME },
19923
+ info: { label: translations.TRAVELERS_FORM.INFO },
19924
+ weight: { label: translations.TRAVELERS_FORM.WEIGHT },
19925
+ height: { label: translations.TRAVELERS_FORM.HEIGHT },
19926
+ street: { label: translations.TRAVELERS_FORM.STREET },
19927
+ location: { label: translations.TRAVELERS_FORM.CITY },
19928
+ countryId: { label: translations.TRAVELERS_FORM.COUNTRY },
19929
+ postalCode: { label: translations.TRAVELERS_FORM.ZIPCODE },
19930
+ number: { label: translations.TRAVELERS_FORM.HOUSE_NUMBER }
19931
+ };
19932
+ }
19933
+ // The form's gender radio values ('m'/'f'/'x') <-> Tide's Gender enum.
19934
+ const GENDER_BY_FORM_VALUE = { m: build.Gender.male, f: build.Gender.female, x: build.Gender.other };
19935
+ function formValueFromGender(gender) {
19936
+ return Object.keys(GENDER_BY_FORM_VALUE).find((key) => GENDER_BY_FORM_VALUE[key] === gender) ?? '';
19937
+ }
19329
19938
  // Shared by buildPax (new-booking) and applyTravelersFormValuesToEditablePackagingEntry
19330
19939
  // (edit-booking), now that PackagingEntryPax and BookingPackagePax have the same shape.
19331
19940
  function applyTravelerToPax(pax, traveler, mainBookerId) {
19332
19941
  return {
19333
19942
  ...pax,
19943
+ // Unanswered (optional) gender keeps whatever the pax already had.
19944
+ gender: GENDER_BY_FORM_VALUE[traveler.gender] ?? pax.gender,
19334
19945
  firstName: traveler.firstName ?? '',
19335
19946
  lastName: traveler.lastName ?? '',
19336
19947
  dateOfBirth: traveler.birthDate || null,
@@ -19490,7 +20101,13 @@ function mapPackagingEntryPaxToTraveler(roomTraveler) {
19490
20101
  customFields: roomTraveler.customFields ?? []
19491
20102
  };
19492
20103
  }
19493
- function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId) {
20104
+ // Keeps the values already on the entry's pax and adds an empty slot for every configured custom field it lacks,
20105
+ // so the form renders/validates the same set as createTraveler does for a new booking.
20106
+ function mergeCustomFields(existing = [], paxFields) {
20107
+ const missing = buildEmptyCustomFields(paxFields).filter((empty) => !existing.some((c) => c.customFieldConfigurationId === empty.customFieldConfigurationId));
20108
+ return [...existing, ...missing];
20109
+ }
20110
+ function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId, paxFields = editablePackagingEntry?.paxFields ?? []) {
19494
20111
  const pax = editablePackagingEntry?.pax ?? [];
19495
20112
  const rooms = editablePackagingEntry.rooms.map((room) => {
19496
20113
  const roomPax = pax.filter((x) => room.paxIds.includes(x.id));
@@ -19503,8 +20120,9 @@ function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, a
19503
20120
  firstName: roomTraveler.firstName ?? '',
19504
20121
  lastName: roomTraveler.lastName ?? '',
19505
20122
  birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
19506
- gender: '',
19507
- ...mapPackagingEntryPaxToTraveler(roomTraveler)
20123
+ gender: formValueFromGender(roomTraveler.gender),
20124
+ ...mapPackagingEntryPaxToTraveler(roomTraveler),
20125
+ customFields: mergeCustomFields(roomTraveler.customFields, paxFields)
19508
20126
  };
19509
20127
  }),
19510
20128
  children: children.map((roomTraveler) => {
@@ -19513,9 +20131,10 @@ function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, a
19513
20131
  firstName: roomTraveler.firstName ?? '',
19514
20132
  lastName: roomTraveler.lastName ?? '',
19515
20133
  birthDate: roomTraveler.dateOfBirth ? format$2(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
19516
- gender: '',
20134
+ gender: formValueFromGender(roomTraveler.gender),
19517
20135
  isBaby: isBabyAge(roomTraveler.age),
19518
- ...mapPackagingEntryPaxToTraveler(roomTraveler)
20136
+ ...mapPackagingEntryPaxToTraveler(roomTraveler),
20137
+ customFields: mergeCustomFields(roomTraveler.customFields, paxFields)
19519
20138
  };
19520
20139
  })
19521
20140
  };
@@ -19540,7 +20159,8 @@ function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry
19540
20159
  const travelers = values.rooms.flatMap((room) => [...room.adults, ...room.children]);
19541
20160
  // The backend treats the main booker's per-pax address as authoritative, so keep the
19542
20161
  // booking-level address in sync with it rather than sending two independent values.
19543
- const mainBookerAddress = travelers.find((x) => x.id === values.mainBookerId)?.address;
20162
+ const mainBookerTraveler = travelers.find((x) => x.id === values.mainBookerId);
20163
+ const mainBookerAddress = mainBookerTraveler?.address;
19544
20164
  return {
19545
20165
  ...editablePackagingEntry,
19546
20166
  pax: (editablePackagingEntry.pax ?? []).map((pax) => {
@@ -19556,8 +20176,9 @@ function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry
19556
20176
  place: mainBookerAddress?.location || values.place,
19557
20177
  country: mainBookerAddress?.country || values.country,
19558
20178
  travelAgentId: values.travelAgentId,
19559
- phone: values.phone,
19560
- email: values.email
20179
+ // When Tide configures the main-booker fields, contact details live on the main booker's traveler block.
20180
+ phone: values.phone || mainBookerTraveler?.mobile || mainBookerTraveler?.phone,
20181
+ email: values.email || mainBookerTraveler?.email
19561
20182
  }
19562
20183
  };
19563
20184
  }
@@ -19714,30 +20335,7 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19714
20335
  return (React__default.createElement("div", { key: field.customFieldConfigurationId, style: { gridColumn: `span ${field.col || 12}` } }, getCustomFieldControl(field, value, name)));
19715
20336
  })));
19716
20337
  };
19717
- // Fields with a dedicated control (gender, hasInsurance, countryId) aren't listed here.
19718
- const BUILT_IN_FIELD_CONTROL_META = {
19719
- firstName: { label: translations.TRAVELERS_FORM.FIRST_NAME },
19720
- lastName: { label: translations.TRAVELERS_FORM.LAST_NAME },
19721
- dateOfBirth: { type: 'date', label: translations.TRAVELERS_FORM.BIRTHDATE },
19722
- nickname: { label: translations.TRAVELERS_FORM.NICKNAME },
19723
- birthplace: { label: translations.TRAVELERS_FORM.BIRTHPLACE },
19724
- nationality: { label: translations.TRAVELERS_FORM.NATIONALITY },
19725
- preferredLanguageId: { type: 'number', label: translations.TRAVELERS_FORM.PREFERRED_LANGUAGE },
19726
- email: { type: 'email', label: translations.TRAVELERS_FORM.TRAVELER_EMAIL },
19727
- phone: { label: translations.TRAVELERS_FORM.TRAVELER_PHONE },
19728
- mobile: { label: translations.TRAVELERS_FORM.TRAVELER_MOBILE },
19729
- passportNumber: { label: translations.TRAVELERS_FORM.PASSPORT_NUMBER },
19730
- passportIssueDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_ISSUE_DATE },
19731
- passportIssuedLocation: { label: translations.TRAVELERS_FORM.PASSPORT_ISSUED_LOCATION },
19732
- passportExpiryDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_EXPIRY_DATE },
19733
- emergencyNumber: { label: translations.TRAVELERS_FORM.EMERGENCY_NUMBER },
19734
- insuranceName: { label: translations.TRAVELERS_FORM.INSURANCE_NAME },
19735
- info: { label: translations.TRAVELERS_FORM.INFO },
19736
- street: { label: translations.TRAVELERS_FORM.STREET },
19737
- location: { label: translations.TRAVELERS_FORM.CITY },
19738
- postalCode: { label: translations.TRAVELERS_FORM.ZIPCODE },
19739
- number: { label: translations.TRAVELERS_FORM.HOUSE_NUMBER }
19740
- };
20338
+ const BUILT_IN_FIELD_CONTROL_META = getBuiltInFieldControlMeta(translations);
19741
20339
  const renderBuiltInFieldControl = (fieldName, isRequired, travelerValues, namePrefix) => {
19742
20340
  const path = BUILT_IN_FIELD_PATHS[fieldName] ?? fieldName;
19743
20341
  const name = `${namePrefix}.${path}`;
@@ -19772,7 +20370,7 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19772
20370
  const resolveBuiltInField = (fieldName, travelerValues) => {
19773
20371
  const isMainBooker = travelerValues.id === formik.values.mainBookerId;
19774
20372
  const configured = getBuiltInPaxField(paxFields, fieldName, isMainBooker);
19775
- const fallback = CORE_FIELD_DEFAULTS[fieldName];
20373
+ const fallback = hasConfiguredBuiltInPaxFields(paxFields) ? undefined : CORE_FIELD_DEFAULTS[fieldName];
19776
20374
  if (!configured && !fallback)
19777
20375
  return undefined;
19778
20376
  return { isRequired: configured?.isRequired ?? fallback.isRequired, col: configured?.col ?? fallback.col };
@@ -19784,7 +20382,14 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19784
20382
  return (React__default.createElement("div", { key: fieldName, style: { gridColumn: `span ${resolved.col || 12}` } }, renderBuiltInFieldControl(fieldName, resolved.isRequired, travelerValues, namePrefix)));
19785
20383
  };
19786
20384
  const renderTravelerAddressFields = (travelerValues, namePrefix) => {
19787
- const fields = ADDRESS_FIELD_NAMES.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix)).filter(Boolean);
20385
+ const isMainBooker = travelerValues.id === formik.values.mainBookerId;
20386
+ // Configured order when Tide sends one, so the configured col widths line up as intended.
20387
+ const fieldNames = hasConfiguredBuiltInPaxFields(paxFields)
20388
+ ? getApplicableBuiltInPaxFields(paxFields, isMainBooker)
20389
+ .map((field) => field.fieldName)
20390
+ .filter((fieldName) => ADDRESS_FIELD_NAMES.includes(fieldName))
20391
+ : ADDRESS_FIELD_NAMES;
20392
+ const fields = fieldNames.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix)).filter(Boolean);
19788
20393
  if (!fields.length)
19789
20394
  return null;
19790
20395
  return React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, fields);
@@ -19827,15 +20432,18 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19827
20432
  return (React__default.createElement("div", { className: "form__row" },
19828
20433
  React__default.createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.age`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.AGE, required: true, name: `${namePrefix}.age`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.age })));
19829
20434
  }
19830
- // 'birthDate' (the legacy formFields type string) is normalized to the paxFields catalog's
19831
- // 'dateOfBirth' fieldName for config lookups.
19832
- const baseFieldNames = (travellersSettings?.formFields?.length ? travellersSettings.formFields.map((field) => field.type) : ['gender', 'firstName', 'lastName', 'dateOfBirth']).map((fieldName) => (fieldName === 'birthDate' ? 'dateOfBirth' : fieldName));
19833
20435
  const isMainBooker = travelerValues.id === formik.values.mainBookerId;
19834
- const extraFieldNames = getApplicableBuiltInPaxFields(paxFields, isMainBooker)
19835
- .map((field) => field.fieldName)
19836
- .filter((fieldName) => !baseFieldNames.includes(fieldName) && !ADDRESS_FIELD_NAMES.includes(fieldName));
20436
+ // With a Tide field configuration, exactly the configured fields render, in their configured order.
20437
+ // Without one, fall back to formFields ('birthDate', the legacy type string, maps to 'dateOfBirth').
20438
+ const fieldNames = hasConfiguredBuiltInPaxFields(paxFields)
20439
+ ? getApplicableBuiltInPaxFields(paxFields, isMainBooker)
20440
+ .map((field) => field.fieldName)
20441
+ .filter((fieldName) => !ADDRESS_FIELD_NAMES.includes(fieldName))
20442
+ : (travellersSettings?.formFields?.length
20443
+ ? travellersSettings.formFields.map((field) => field.type)
20444
+ : ['gender', 'firstName', 'lastName', 'dateOfBirth']).map((fieldName) => (fieldName === 'birthDate' ? 'dateOfBirth' : fieldName));
19837
20445
  return (React__default.createElement(React__default.Fragment, null,
19838
- React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, [...baseFieldNames, ...extraFieldNames].map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix))),
20446
+ React__default.createElement("div", { className: "travelers-form__custom-fields-grid" }, fieldNames.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix))),
19839
20447
  renderTravelerAddressFields(travelerValues, namePrefix),
19840
20448
  renderCustomFields(travelerValues, namePrefix),
19841
20449
  travelersFirstStep && isAdult && formik.values.rooms[roomIndex].adults.length > 1 && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveTraveler(roomIndex, travelerIndex) }, translations.TRAVELERS_FORM.REMOVE_TRAVELER))));
@@ -19873,7 +20481,7 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19873
20481
  renderTravelerFields(travelerValues, `rooms[${roomIndex}].children[${index}]`, false, roomIndex, index)))),
19874
20482
  !useCompactForm && travelersFirstStep && (React__default.createElement("div", { className: "form__region" },
19875
20483
  React__default.createElement("button", { type: "button", className: "cta cta--select", onClick: () => handleAddTraveler(roomIndex) }, translations.TRAVELERS_FORM.ADD_TRAVELER)))))),
19876
- !useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default.createElement("div", { className: "form__region" },
20484
+ useCompactForm || hasConfiguredMainBookerFields(paxFields) ? null : bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length ? (React__default.createElement("div", { className: "form__region" },
19877
20485
  React__default.createElement("div", { className: "form__region-header" },
19878
20486
  React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
19879
20487
  React__default.createElement("p", { className: "form__region-label" }, compact([compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
@@ -19892,9 +20500,9 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19892
20500
  React__default.createElement("div", { className: "form__row" },
19893
20501
  React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }),
19894
20502
  React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
19895
- React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })))))) : !useCompactForm ? (React__default.createElement("div", { className: "form__region" },
20503
+ React__default.createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })))))) : (React__default.createElement("div", { className: "form__region" },
19896
20504
  React__default.createElement("div", { className: "form__row" },
19897
- React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone })))) : null,
20505
+ React__default.createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone })))),
19898
20506
  !useCompactForm && showAgentSelection && (React__default.createElement("div", { className: "form__region" },
19899
20507
  React__default.createElement("div", { className: "form__region-header" },
19900
20508
  React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.BOOK_WITH_AGENT),
@@ -20505,8 +21113,9 @@ const selectBookingPackagePax = createSelector(selectTravelersFormValues, (formV
20505
21113
  formValues?.rooms.forEach((r) => r.adults.forEach((x) => {
20506
21114
  const adultPax = buildPax(x, formValues?.mainBookerId);
20507
21115
  if (adultPax.isMainBooker) {
20508
- adultPax.mobilePhone = formValues?.phone;
20509
- adultPax.email = formValues?.email;
21116
+ // Without the main booker block (Tide configures main-booker fields), keep the traveler's own details.
21117
+ adultPax.mobilePhone = formValues?.phone || adultPax.mobilePhone;
21118
+ adultPax.email = formValues?.email || adultPax.email;
20510
21119
  }
20511
21120
  pax.push(adultPax);
20512
21121
  }));
@@ -20530,8 +21139,8 @@ const selectBookingAddress = createSelector(selectTravelersFormValues, selectBoo
20530
21139
  postalCode: mainBookerAddress?.postalCode || formValues?.zipCode,
20531
21140
  location: mainBookerAddress?.location || formValues?.place,
20532
21141
  country: mainBookerAddress?.country || formValues?.country,
20533
- mobilePhone: formValues?.phone,
20534
- email: formValues?.email
21142
+ mobilePhone: mainBooker.mobilePhone,
21143
+ email: mainBooker.email
20535
21144
  };
20536
21145
  });
20537
21146
  const selectSubFormAnswers = (state) => state.booking.subFormAnswers;
@@ -25668,6 +26277,10 @@ const Summary = () => {
25668
26277
  React__default.createElement("button", { title: settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "default" }, settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING))))));
25669
26278
  };
25670
26279
 
26280
+ // lodash isEmpty is true for every number, which would flag a filled-in preferredLanguageId as missing.
26281
+ function isBlank(value) {
26282
+ return value === null || value === undefined || (typeof value === 'string' && value.trim() === '');
26283
+ }
25671
26284
  function isValidEmail(email) {
25672
26285
  return !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,24}$/i.test(email);
25673
26286
  }
@@ -25691,9 +26304,14 @@ function getAge(birthDateText, startDateText) {
25691
26304
  }
25692
26305
  const validateForm = (values, agentRequired, bookingType, translations, formFields, mainBookerFormFields, maxChildAge = CHILD_MAX_AGE, maxBabyAge = BABY_MAX_AGE, paxFields = []) => {
25693
26306
  const errors = {};
26307
+ const usesFieldConfiguration = hasConfiguredBuiltInPaxFields(paxFields);
26308
+ const builtInFieldMeta = getBuiltInFieldControlMeta(translations);
25694
26309
  const isFormFieldPresent = (type) => {
25695
26310
  return formFields?.some((f) => f.type === type) ?? true;
25696
26311
  };
26312
+ // The 4 core fields: with a Tide field configuration they're required only when configured so for the
26313
+ // traveler's role (main booker / other pax); without one, whenever formFields lists them (legacy behavior).
26314
+ const isCoreFieldRequired = (traveler, legacyType, fieldName = legacyType) => usesFieldConfiguration ? !!getBuiltInPaxField(paxFields, fieldName, traveler.id === values.mainBookerId)?.isRequired : isFormFieldPresent(legacyType);
25697
26315
  const isMainBookerFormFieldPresent = (type) => {
25698
26316
  return mainBookerFormFields?.some((f) => f.type === type) ?? true;
25699
26317
  };
@@ -25745,16 +26363,16 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25745
26363
  const fieldPath = BUILT_IN_FIELD_PATHS[field.fieldName];
25746
26364
  if (!fieldPath)
25747
26365
  return;
25748
- if (isEmpty$1(get(traveler, fieldPath))) {
25749
- set(errors, `${path}.${fieldPath}`, formatTravelerField(room, pax, field.fieldName));
26366
+ if (isBlank(get(traveler, fieldPath))) {
26367
+ set(errors, `${path}.${fieldPath}`, formatTravelerField(room, pax, builtInFieldMeta[field.fieldName]?.label ?? field.fieldName));
25750
26368
  }
25751
26369
  });
25752
26370
  };
25753
26371
  values.rooms.forEach((r, rIndex) => r.adults.forEach((adult, index) => {
25754
- if (isEmpty$1(adult.gender) && isFormFieldPresent('gender')) {
26372
+ if (isEmpty$1(adult.gender) && isCoreFieldRequired(adult, 'gender')) {
25755
26373
  set(errors, `rooms[${rIndex}].adults[${index}].gender`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.GENDER));
25756
26374
  }
25757
- if (isFormFieldPresent('firstName')) {
26375
+ if (isCoreFieldRequired(adult, 'firstName') || !isEmpty$1(adult.firstName)) {
25758
26376
  if (isEmpty$1(adult.firstName)) {
25759
26377
  set(errors, `rooms[${rIndex}].adults[${index}].firstName`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
25760
26378
  }
@@ -25762,7 +26380,7 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25762
26380
  set(errors, `rooms[${rIndex}].adults[${index}].firstName`, formatTravelerFieldInvalidCharacters(rIndex + 1, index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
25763
26381
  }
25764
26382
  }
25765
- if (isFormFieldPresent('lastName')) {
26383
+ if (isCoreFieldRequired(adult, 'lastName') || !isEmpty$1(adult.lastName)) {
25766
26384
  if (isEmpty$1(adult.lastName)) {
25767
26385
  set(errors, `rooms[${rIndex}].adults[${index}].lastName`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.LAST_NAME));
25768
26386
  }
@@ -25770,7 +26388,7 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25770
26388
  set(errors, `rooms[${rIndex}].adults[${index}].lastName`, formatTravelerFieldInvalidCharacters(rIndex + 1, index + 1, translations.TRAVELERS_FORM.LAST_NAME));
25771
26389
  }
25772
26390
  }
25773
- if (isFormFieldPresent('birthDate')) {
26391
+ if (isCoreFieldRequired(adult, 'birthDate', 'dateOfBirth') || !isEmpty$1(adult.birthDate)) {
25774
26392
  if (isEmpty$1(adult.birthDate) || !isValidBirthDate(adult.birthDate)) {
25775
26393
  set(errors, `rooms[${rIndex}].adults[${index}].birthDate`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
25776
26394
  }
@@ -25786,10 +26404,10 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25786
26404
  validateRequiredBuiltInFields(adult, `rooms[${rIndex}].adults[${index}]`, rIndex + 1, index + 1);
25787
26405
  }));
25788
26406
  values.rooms.forEach((r, rIndex) => r.children.forEach((child, index) => {
25789
- if (isEmpty$1(child.gender) && isFormFieldPresent('gender')) {
26407
+ if (isEmpty$1(child.gender) && isCoreFieldRequired(child, 'gender')) {
25790
26408
  set(errors, `rooms[${rIndex}].children[${index}].gender`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.GENDER));
25791
26409
  }
25792
- if (isFormFieldPresent('firstName')) {
26410
+ if (isCoreFieldRequired(child, 'firstName') || !isEmpty$1(child.firstName)) {
25793
26411
  if (isEmpty$1(child.firstName)) {
25794
26412
  set(errors, `rooms[${rIndex}].children[${index}].firstName`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
25795
26413
  }
@@ -25797,7 +26415,7 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25797
26415
  set(errors, `rooms[${rIndex}].children[${index}].firstName`, formatTravelerFieldInvalidCharacters(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
25798
26416
  }
25799
26417
  }
25800
- if (isFormFieldPresent('lastName')) {
26418
+ if (isCoreFieldRequired(child, 'lastName') || !isEmpty$1(child.lastName)) {
25801
26419
  if (isEmpty$1(child.lastName)) {
25802
26420
  set(errors, `rooms[${rIndex}].children[${index}].lastName`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.LAST_NAME));
25803
26421
  }
@@ -25805,7 +26423,7 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25805
26423
  set(errors, `rooms[${rIndex}].children[${index}].lastName`, formatTravelerFieldInvalidCharacters(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.LAST_NAME));
25806
26424
  }
25807
26425
  }
25808
- if (isFormFieldPresent('birthDate')) {
26426
+ if (isCoreFieldRequired(child, 'birthDate', 'dateOfBirth') || !isEmpty$1(child.birthDate)) {
25809
26427
  if (isEmpty$1(child.birthDate) || !isValidBirthDate(child.birthDate)) {
25810
26428
  set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
25811
26429
  }
@@ -25831,7 +26449,8 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25831
26449
  if (values.mainBookerId < 0) {
25832
26450
  errors.mainBookerId = translations.TRAVELERS_FORM.VALIDATION.NO_MAIN_BOOKER_SELECTED;
25833
26451
  }
25834
- if (bookingType != 'b2b' || mainBookerFormFields?.length) {
26452
+ if (hasConfiguredMainBookerFields(paxFields)) ;
26453
+ else if (bookingType != 'b2b' || mainBookerFormFields?.length) {
25835
26454
  if (isEmpty$1(values.street) && isMainBookerFormFieldPresent('street')) {
25836
26455
  errors.street = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.STREET]);
25837
26456
  }
@@ -26526,7 +27145,7 @@ const LanguageSwitcher = ({ value = 'EN', languages = DEFAULT_LANGUAGES, onChang
26526
27145
  React__default.createElement("span", { className: "nav__subnav__languages__option__label" }, l.label)))))));
26527
27146
  };
26528
27147
 
26529
- const Navbar = ({ currentPath, logo, onLogoClick, topLinks, items, language, languages, onLanguageChange, onSearch, member, onLogin, onLogout }) => {
27148
+ const Navbar = ({ currentPath, logo, onLogoClick, topLinks, items, language, languages, onLanguageChange, onSearch, member, onLogin, onLogout, onMyBookings }) => {
26530
27149
  const [menuOpen, setMenuOpen] = useState(false);
26531
27150
  const [query, setQuery] = useState('');
26532
27151
  const [activeMobileGroup, setActiveMobileGroup] = useState();
@@ -26620,6 +27239,12 @@ const Navbar = ({ currentPath, logo, onLogoClick, topLinks, items, language, lan
26620
27239
  onLogout();
26621
27240
  }
26622
27241
  };
27242
+ const handleMyBookings = (event) => {
27243
+ event.preventDefault();
27244
+ if (onMyBookings) {
27245
+ onMyBookings();
27246
+ }
27247
+ };
26623
27248
  const handleLogin = (event) => {
26624
27249
  event.preventDefault();
26625
27250
  if (onLogin) {
@@ -26633,7 +27258,9 @@ const Navbar = ({ currentPath, logo, onLogoClick, topLinks, items, language, lan
26633
27258
  member && (React__default.createElement("span", { className: "nav__subnav__member" },
26634
27259
  translations.LOGIN.WELCOME_X,
26635
27260
  member.name)),
26636
- member ? (React__default.createElement(React__default.Fragment, null, onLogout && (React__default.createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleLogout }, translations.LOGIN.LOGOUT)))) : (React__default.createElement(React__default.Fragment, null, onLogin && (React__default.createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleLogin }, translations.LOGIN.LOGIN)))),
27261
+ member ? (React__default.createElement(React__default.Fragment, null,
27262
+ onMyBookings && (React__default.createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleMyBookings }, translations.AGENT_ENTRIES.MY_BOOKINGS)),
27263
+ onLogout && (React__default.createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleLogout }, translations.LOGIN.LOGOUT)))) : (React__default.createElement(React__default.Fragment, null, onLogin && (React__default.createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleLogin }, translations.LOGIN.LOGIN)))),
26637
27264
  React__default.createElement(LanguageSwitcher, { value: language.code, languages: languages, onChange: (lang) => {
26638
27265
  console.log('Selected language:', lang);
26639
27266
  onLanguageChange(lang);
@@ -28602,6 +29229,7 @@ const initialState$1 = {
28602
29229
  bookingNumber: undefined,
28603
29230
  trajectNodeAvailability: {},
28604
29231
  trajectFlightAvailability: {},
29232
+ trajectTransferAvailability: {},
28605
29233
  trajectDaySuggestions: {},
28606
29234
  trajectEditLineGuid: null,
28607
29235
  trajectActivitiesDayOrder: null,
@@ -28814,6 +29442,12 @@ const searchResultsSlice = createSlice({
28814
29442
  node.selectedCode = code;
28815
29443
  node.status = 'resolved';
28816
29444
  },
29445
+ clearTrajectNodeSelection(state, action) {
29446
+ const node = state.trajectNodeAvailability[action.payload];
29447
+ if (!node)
29448
+ return;
29449
+ node.selectedCode = null;
29450
+ },
28817
29451
  updateEditableEntryLine(state, action) {
28818
29452
  if (!state.editablePackagingEntry)
28819
29453
  return;
@@ -28827,6 +29461,32 @@ const searchResultsSlice = createSlice({
28827
29461
  return;
28828
29462
  state.editablePackagingEntry.lines = [...(state.editablePackagingEntry.lines ?? []), ...action.payload];
28829
29463
  },
29464
+ upsertEditableEntryLines(state, action) {
29465
+ if (!state.editablePackagingEntry)
29466
+ return;
29467
+ const lines = [...(state.editablePackagingEntry.lines ?? [])];
29468
+ action.payload.forEach((line) => {
29469
+ const index = lines.findIndex((x) => x.guid === line.guid);
29470
+ if (index === -1)
29471
+ lines.push(line);
29472
+ else
29473
+ lines[index] = line;
29474
+ });
29475
+ state.editablePackagingEntry.lines = lines;
29476
+ const restored = new Set(action.payload.map((line) => line.trajectNodeId).filter((x) => x != null));
29477
+ if (restored.size && state.editablePackagingEntry.removedTrajectNodeIds?.length) {
29478
+ state.editablePackagingEntry.removedTrajectNodeIds = state.editablePackagingEntry.removedTrajectNodeIds.filter((x) => !restored.has(x));
29479
+ }
29480
+ },
29481
+ removeTrajectNode(state, action) {
29482
+ if (!state.editablePackagingEntry)
29483
+ return;
29484
+ const guids = new Set(action.payload.lineGuids);
29485
+ state.editablePackagingEntry.lines = (state.editablePackagingEntry.lines ?? []).filter((x) => !guids.has(x.guid));
29486
+ const removed = state.editablePackagingEntry.removedTrajectNodeIds ?? [];
29487
+ if (!removed.includes(action.payload.nodeId))
29488
+ state.editablePackagingEntry.removedTrajectNodeIds = [...removed, action.payload.nodeId];
29489
+ },
28830
29490
  removeEditableEntryLines(state, action) {
28831
29491
  if (!state.editablePackagingEntry)
28832
29492
  return;
@@ -28858,6 +29518,19 @@ const searchResultsSlice = createSlice({
28858
29518
  flight.selectedGuid = action.payload.guid;
28859
29519
  flight.status = 'resolved';
28860
29520
  },
29521
+ clearTrajectFlightSelection(state, action) {
29522
+ const flight = state.trajectFlightAvailability[action.payload];
29523
+ if (!flight)
29524
+ return;
29525
+ flight.selectedGuid = null;
29526
+ },
29527
+ setTrajectTransferLoading(state, action) {
29528
+ state.trajectTransferAvailability[action.payload] = { nodeId: action.payload, status: 'loading', result: null };
29529
+ },
29530
+ setTrajectTransferAvailability(state, action) {
29531
+ const { nodeId, result } = action.payload;
29532
+ state.trajectTransferAvailability[nodeId] = { nodeId, status: result ? 'resolved' : 'unavailable', result };
29533
+ },
28861
29534
  setTrajectDaySuggestionsLoading(state, action) {
28862
29535
  const dayOrder = action.payload;
28863
29536
  state.trajectDaySuggestions[dayOrder] = {
@@ -28894,6 +29567,7 @@ const searchResultsSlice = createSlice({
28894
29567
  resetTrajectAvailability(state) {
28895
29568
  state.trajectNodeAvailability = {};
28896
29569
  state.trajectFlightAvailability = {};
29570
+ state.trajectTransferAvailability = {};
28897
29571
  state.trajectDaySuggestions = {};
28898
29572
  state.trajectEditLineGuid = null;
28899
29573
  state.trajectActivitiesDayOrder = null;
@@ -28902,7 +29576,7 @@ const searchResultsSlice = createSlice({
28902
29576
  }
28903
29577
  }
28904
29578
  });
28905
- 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;
29579
+ 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, clearTrajectNodeSelection, setTrajectResolving, setTrajectItineraryView, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, clearTrajectFlightSelection, setTrajectTransferLoading, setTrajectTransferAvailability, setTrajectEditLineGuid, setTrajectActivitiesDayOrder, setTrajectDaySuggestionsLoading, setTrajectDaySuggestions, addEditableEntryLines, upsertEditableEntryLines, removeTrajectNode, updateTrajectNodeResult, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
28906
29580
  var searchResultsReducer = searchResultsSlice.reducer;
28907
29581
 
28908
29582
  const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
@@ -29117,7 +29791,7 @@ const numberOfNights = (segment) => {
29117
29791
  const CHARTER_SERVICE_TYPE = 10;
29118
29792
  const CRUISE_SERVICE_TYPE = 11;
29119
29793
  const FERRY_SERVICE_TYPE = 12;
29120
- const TRANSFER_SERVICE_TYPE = 13;
29794
+ const TRANSFER_SERVICE_TYPE$1 = 13;
29121
29795
  const BUS_SERVICE_TYPE = 14;
29122
29796
  const CAR_SERVICE_TYPE = 17;
29123
29797
  const CAMPER_SERVICE_TYPE = 18;
@@ -29149,7 +29823,7 @@ const getServiceTypeIcon = (serviceType) => {
29149
29823
  return 'ui-bus';
29150
29824
  case TRAIN_SERVICE_TYPE:
29151
29825
  return 'ui-train';
29152
- case TRANSFER_SERVICE_TYPE:
29826
+ case TRANSFER_SERVICE_TYPE$1:
29153
29827
  return 'ui-transfer';
29154
29828
  case EVENT_SERVICE_TYPE:
29155
29829
  return 'ui-ticket';
@@ -29285,6 +29959,81 @@ const getTrajectNodesWithLines = (trajectEntry) => {
29285
29959
  })
29286
29960
  .filter((x) => !!x.line);
29287
29961
  };
29962
+ // Qite.Offer.Enums.ServiceType.Transfer: a traject's connecting node is booked as one.
29963
+ const TRANSFER_SERVICE_TYPE = 13;
29964
+ // Qite.Offer.Enums.RequirementType. A Mandatory (0) stop, and one RequiredInGroup (3) — one of the node's
29965
+ // alternatives has to be booked — always keep a selection; only these two may be taken off the trip.
29966
+ const OPTIONAL_REQUIREMENT_TYPE = 1;
29967
+ const OPTIONAL_IN_GROUP_REQUIREMENT_TYPE = 2;
29968
+ const canRemoveTrajectNode = (node) => node.requirementType === OPTIONAL_REQUIREMENT_TYPE || node.requirementType === OPTIONAL_IN_GROUP_REQUIREMENT_TYPE;
29969
+ const getDroppedTrajectNodeIds = (trajectEntry, entry) => {
29970
+ const dropped = new Set();
29971
+ if (!entry || !!trajectEntry.entry.magicLink)
29972
+ return dropped;
29973
+ const removed = new Set(entry.removedTrajectNodeIds ?? []);
29974
+ if (!removed.size)
29975
+ return dropped;
29976
+ const byDay = new Map();
29977
+ [...(trajectEntry.nodes ?? [])]
29978
+ .sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
29979
+ .forEach((node) => byDay.set(node.dayOrder, [...(byDay.get(node.dayOrder) ?? []), node]));
29980
+ byDay.forEach((nodes) => nodes.forEach((node, index) => {
29981
+ if (node.trajectNodeType !== REGULAR_TRAJECT_NODE_TYPE || !canRemoveTrajectNode(node) || !removed.has(node.nodeId))
29982
+ return;
29983
+ dropped.add(node.nodeId);
29984
+ [nodes[index - 1], nodes[index + 1]]
29985
+ .filter((x) => !!x && x.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE)
29986
+ .forEach((x) => dropped.add(x.nodeId));
29987
+ }));
29988
+ return dropped;
29989
+ };
29990
+ const isTrajectTransferNode = (node) => node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE && !!node.pickUp && !!node.dropOff;
29991
+ const buildTrajectTransferRequest = (node, context) => ({
29992
+ transactionId: context.transactionId,
29993
+ officeId: context.officeId,
29994
+ agentId: context.agentId ?? null,
29995
+ catalogueId: context.catalogueId,
29996
+ searchConfigurationId: context.searchConfigurationId,
29997
+ language: context.language,
29998
+ date: node.from,
29999
+ pickUp: node.pickUp,
30000
+ dropOff: node.dropOff,
30001
+ travellers: context.rooms.flatMap((room) => room.travellers)
30002
+ });
30003
+ const buildTrajectTransferLine = (node, result) => {
30004
+ const option = result.rooms?.[0]?.options?.find((x) => x.isSelected) ?? result.rooms?.[0]?.options?.[0];
30005
+ if (!option?.guid)
30006
+ return null;
30007
+ return {
30008
+ guid: option.guid,
30009
+ parentGuid: null,
30010
+ order: 0,
30011
+ trajectNodeId: node.nodeId,
30012
+ isChanged: true,
30013
+ from: result.fromDate ?? node.from,
30014
+ to: result.toDate ?? node.to,
30015
+ moment: node.moment ?? '',
30016
+ serviceType: TRANSFER_SERVICE_TYPE,
30017
+ productName: result.name,
30018
+ productCode: result.code,
30019
+ accommodationName: option.accommodationName,
30020
+ accommodationCode: option.accommodationCode,
30021
+ regimeName: option.regimeName,
30022
+ regimeCode: option.regimeCode,
30023
+ vendor: result.vendorType ?? null,
30024
+ externalVendorId: result.vendorId ?? null,
30025
+ groupKey: '',
30026
+ isActive: true,
30027
+ country: result.countryId ? { id: result.countryId, name: result.countryName, localizations: [] } : null,
30028
+ region: result.regionId ? { id: result.regionId, name: result.regionName, localizations: [] } : null,
30029
+ oord: result.oordId ? { id: result.oordId, name: result.oordName, localizations: [] } : null,
30030
+ location: result.locationId ? { id: result.locationId, name: result.locationName, localizations: [] } : null,
30031
+ longitude: result.longitude ?? null,
30032
+ latitude: result.latitude ?? null,
30033
+ pax: (option.paxIds ?? []).map((paxId, paxIndex) => ({ paxId, room: 0, order: paxIndex })),
30034
+ flightInformation: null
30035
+ };
30036
+ };
29288
30037
  const getCoordinates = (line, node, result) => {
29289
30038
  const sources = [
29290
30039
  ...(result ? [result] : []),
@@ -29712,9 +30461,15 @@ const nightsOf = (node, line) => differenceInCalendarDays(new Date(line?.to ?? n
29712
30461
  const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
29713
30462
  const timeline = useMemo(() => {
29714
30463
  const linesByGuid = new Map((packagingEntry.lines ?? []).map((line) => [line.guid, line]));
30464
+ const dropped = getDroppedTrajectNodeIds(trajectEntry, packagingEntry);
29715
30465
  const nodes = [...(trajectEntry.nodes ?? [])]
30466
+ .filter((node) => !dropped.has(node.nodeId))
29716
30467
  .sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
29717
30468
  .map((node) => {
30469
+ // A connecting node has no line of its own; the transfer found for it carries its node id.
30470
+ if (node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE) {
30471
+ return { node, lines: (packagingEntry.lines ?? []).filter((line) => line.trajectNodeId === node.nodeId) };
30472
+ }
29718
30473
  const guids = node.lineGuids?.length ? node.lineGuids : [node.lineGuid];
29719
30474
  const lines = guids.map((guid) => linesByGuid.get(guid)).filter((x) => !!x);
29720
30475
  const groupKey = lines.length ? getLineGroupKey(lines[0]) : '';
@@ -29784,10 +30539,11 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
29784
30539
  React__default.createElement("p", { className: "search__filter__itinerary__transport-date-date" },
29785
30540
  React__default.createElement("strong", null, format$2(new Date(value), 'd'))),
29786
30541
  React__default.createElement("p", null, format$2(new Date(value), 'MMM'))));
29787
- const renderConnectingNode = ({ node }) => {
30542
+ const renderConnectingNode = ({ node, lines }) => {
29788
30543
  const distance = node.distanceInKm ? `${Math.round(node.distanceInKm)} km` : '';
29789
30544
  // How long the hop takes and how far it is, the way the traject editor puts them.
29790
30545
  const journey = [getTrajectNodeDuration(node), distance].filter(Boolean).join(' · ');
30546
+ const title = lines[0]?.productName || node.name;
29791
30547
  return (React__default.createElement("div", { className: "search__filter__itinerary__transport", key: `connect-${node.nodeId}` },
29792
30548
  React__default.createElement("div", { className: "search__filter__itinerary__transport-timeline" },
29793
30549
  React__default.createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
@@ -29796,8 +30552,8 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
29796
30552
  React__default.createElement("div", { className: badgeClass('transport', getTrajectNodeBadgeModifier(node)) },
29797
30553
  React__default.createElement(Icon, { name: getTrajectNodeIcon(node), height: 15 })),
29798
30554
  React__default.createElement("div", { className: "search__filter__itinerary__transport-details" },
29799
- React__default.createElement("h6", null, node.name || journey),
29800
- !!node.name && !!journey && React__default.createElement("p", { className: "search__filter__itinerary__transport-details-time" }, journey)))));
30555
+ React__default.createElement("h6", null, title || journey),
30556
+ !!title && !!journey && React__default.createElement("p", { className: "search__filter__itinerary__transport-details-time" }, journey)))));
29801
30557
  };
29802
30558
  const renderOvernight = (item, index) => {
29803
30559
  const { dayOrder } = item.node;
@@ -33048,7 +33804,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
33048
33804
  if (!result)
33049
33805
  return;
33050
33806
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
33051
- buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? []).forEach((line) => dispatch(updateEditableEntryLine(line)));
33807
+ dispatch(upsertEditableEntryLines(buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? [])));
33052
33808
  dispatch(setTrajectEditLineGuid(null));
33053
33809
  dispatch(setFlyInIsOpen(false));
33054
33810
  };
@@ -33093,7 +33849,7 @@ const TrajectFlightsFlyIn = ({ isLoading }) => {
33093
33849
  if (!flight)
33094
33850
  return;
33095
33851
  dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
33096
- dispatch(updateEditableEntryLine(applyFlightToLine(item.line, flight)));
33852
+ dispatch(upsertEditableEntryLines([applyFlightToLine(item.line, flight)]));
33097
33853
  dispatch(setTrajectEditLineGuid(null));
33098
33854
  dispatch(setFlyInIsOpen(false));
33099
33855
  };
@@ -33156,10 +33912,16 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
33156
33912
  if (!item)
33157
33913
  return;
33158
33914
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code: result.code }));
33159
- buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? []).forEach((line) => dispatch(updateEditableEntryLine(line)));
33915
+ dispatch(upsertEditableEntryLines(buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? [])));
33160
33916
  dispatch(setTrajectActivitiesDayOrder(null));
33161
33917
  dispatch(setFlyInIsOpen(false));
33162
33918
  };
33919
+ const handleRemove = ({ item }) => {
33920
+ if (!item)
33921
+ return;
33922
+ dispatch(clearTrajectNodeSelection(item.line.guid));
33923
+ dispatch(removeTrajectNode({ nodeId: item.node.nodeId, lineGuids: item.lines.map((line) => line.guid) }));
33924
+ };
33163
33925
  if (isLoading || suggestions?.status === 'loading') {
33164
33926
  return React__default.createElement(React__default.Fragment, null, context.customSpinner ?? React__default.createElement(Spinner, { label: translations.SRP.LOADING_ACTIVITIES }));
33165
33927
  }
@@ -33173,7 +33935,8 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
33173
33935
  const { result, item } = card;
33174
33936
  const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedLines(result).length > 0;
33175
33937
  const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
33176
- return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(card) : handleToggle(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
33938
+ const canRemove = !!item && isSelected && !bookedMode && canRemoveTrajectNode(item.node);
33939
+ return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (!item ? handleToggle(result) : canRemove ? handleRemove(card) : handleSelect(card)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item && !canRemove ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
33177
33940
  })))));
33178
33941
  };
33179
33942
 
@@ -35567,16 +36330,18 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
35567
36330
  apiKey: context.tideConnection.apiKey
35568
36331
  };
35569
36332
  }, [context]);
36333
+ // The field configuration on the entry is leading for which traveler fields are shown and required.
36334
+ const paxFields = editablePackagingEntry?.paxFields ?? [];
35570
36335
  const initialValues = useMemo(() => {
35571
36336
  if (!editablePackagingEntry) {
35572
36337
  return {};
35573
36338
  }
35574
- return createInitialValuesFromEditablePackagingEntry(editablePackagingEntry);
36339
+ return createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, undefined, paxFields);
35575
36340
  }, [editablePackagingEntry?.transactionId]);
35576
36341
  const formik = useFormik({
35577
36342
  initialValues,
35578
36343
  enableReinitialize: true,
35579
- validate: (values) => validateForm(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields, undefined, undefined, editablePackagingEntry?.paxFields ?? []),
36344
+ validate: (values) => validateForm(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields, undefined, undefined, paxFields),
35580
36345
  onSubmit: (values) => {
35581
36346
  if (!editablePackagingEntry)
35582
36347
  return;
@@ -35661,7 +36426,7 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
35661
36426
  ".\u00A0",
35662
36427
  stepLabels[step])) },
35663
36428
  isConfirmationPage && isLoading && React__default.createElement(Spinner, { label: translations.SUMMARY.PROCESS_BOOKING }),
35664
- currentStep === 0 && (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false, paxFields: editablePackagingEntry?.paxFields ?? [] })),
36429
+ currentStep === 0 && (React__default.createElement(SharedTravelersForm, { formik: formik, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false, paxFields: paxFields })),
35665
36430
  currentStep === 1 && (React__default.createElement(SharedSummary, { translations: translations, travelerFormValues: formik.values, isSubmitting: isSubmitting, skipPayment: !context.generatePaymentUrl, userValidated: userValidated, remarks: remarks, enableVoucher: false, allowOption: false, isOffer: false, onUserValidatedChange: setUserValidated, onRemarksChange: setRemarks, onSubmit: handleSummarySubmit, renderOptions: () => renderEditablePackagingEntrySummaryOptions(editablePackagingEntry, priceDetails, translations, selectedPackagingAccoResult?.currencyCode), renderPreviousButton: () => (React__default.createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => dispatch(setCurrentStep(0)), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) })),
35666
36431
  currentStep === 2 && (React__default.createElement(SharedConfirmation, { bookingNumber: bookingNumber ?? editablePackagingEntry?.dossierNumber ?? '', isOption: false, isOffer: false, translations: translations.CONFIRMATION })),
35667
36432
  currentStep === 3 && React__default.createElement("div", null))),
@@ -35761,11 +36526,13 @@ const TrajectResults = ({ isLoading }) => {
35761
36526
  });
35762
36527
  return map;
35763
36528
  }, [trajectEntry]);
36529
+ const droppedNodeIds = trajectEntry ? getDroppedTrajectNodeIds(trajectEntry, editablePackagingEntry) : new Set();
36530
+ const droppedKey = [...droppedNodeIds].sort((a, b) => a - b).join(',');
35764
36531
  const { stayByDay, stayStartByNodeId } = useMemo(() => {
35765
36532
  const byDay = new Map();
35766
36533
  const byNodeId = new Map();
35767
36534
  nodesWithLines
35768
- .filter((x) => x.node.serviceType === ACCOMMODATION_SERVICE_TYPE)
36535
+ .filter((x) => x.node.serviceType === ACCOMMODATION_SERVICE_TYPE && !droppedNodeIds.has(x.node.nodeId))
35769
36536
  .forEach((item) => {
35770
36537
  const nights = Math.max(differenceInCalendarDays(new Date(item.line.to), new Date(item.line.from)), 1);
35771
36538
  byNodeId.set(item.node.nodeId, { item, night: 0, nights });
@@ -35774,7 +36541,7 @@ const TrajectResults = ({ isLoading }) => {
35774
36541
  }
35775
36542
  });
35776
36543
  return { stayByDay: byDay, stayStartByNodeId: byNodeId };
35777
- }, [nodesWithLines]);
36544
+ }, [nodesWithLines, droppedKey]);
35778
36545
  /** Whether every node of the trip has an answer, one way or the other. */
35779
36546
  const tripResolved = useMemo(() => nodesWithLines
35780
36547
  .filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node))
@@ -35801,7 +36568,20 @@ const TrajectResults = ({ isLoading }) => {
35801
36568
  if (!result)
35802
36569
  return;
35803
36570
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
35804
- buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? []).forEach((line) => dispatch(updateEditableEntryLine(line)));
36571
+ dispatch(upsertEditableEntryLines(buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? [])));
36572
+ };
36573
+ /**
36574
+ * An optional stop can be taken off the trip; a mandatory one, or one of which the group needs a pick,
36575
+ * only swapped. A booked entry's services are never taken off here.
36576
+ */
36577
+ const canRemove = (item) => !bookedMode && canRemoveTrajectNode(item.node);
36578
+ const handleRemoveNode = (item) => {
36579
+ dispatch(clearTrajectNodeSelection(item.line.guid));
36580
+ dispatch(removeTrajectNode({ nodeId: item.node.nodeId, lineGuids: item.lines.map((line) => line.guid) }));
36581
+ };
36582
+ const handleRemoveFlight = (item) => {
36583
+ dispatch(clearTrajectFlightSelection(item.line.guid));
36584
+ dispatch(removeTrajectNode({ nodeId: item.node.nodeId, lineGuids: item.lines.map((line) => line.guid) }));
35805
36585
  };
35806
36586
  /** The remaining legs for a flight node open in the fly-in, as the regular flight results do. */
35807
36587
  const handleShowMoreFlights = (item) => {
@@ -35869,9 +36649,17 @@ const TrajectResults = ({ isLoading }) => {
35869
36649
  // A hotel row holds the hotels configured on the node; a portal can also let it fill up with
35870
36650
  // non-preferred hotels found in the area, the rest staying behind "show more".
35871
36651
  const fill = showNonPreferredHotels && node.serviceType === ACCOMMODATION_SERVICE_TYPE ? others.slice(0, Math.max(MAX_HOTEL_RESULTS - 1 - configured.length, 0)) : [];
35872
- const remaining = others.length - fill.length;
35873
36652
  // No entry yet means the node's search has been queued but not dispatched — still loading.
35874
36653
  const status = availability?.status ?? 'loading';
36654
+ // A stop taken off the trip keeps its results in view, to pick one back.
36655
+ const isRemoved = status === 'resolved' && !selected && results.length > 0;
36656
+ const removable = canRemove(item);
36657
+ const shown = selected
36658
+ ? [selected, ...configured, ...fill]
36659
+ : configured.length || fill.length
36660
+ ? [...configured, ...fill]
36661
+ : others.slice(0, MAX_HOTEL_RESULTS);
36662
+ const remaining = results.length - shown.length;
35875
36663
  return (React__default.createElement(React__default.Fragment, { key: line.guid },
35876
36664
  showHeader && (React__default.createElement("div", { className: "search__results__label search__results__label--secondary" },
35877
36665
  React__default.createElement("div", { className: "search__results__label__date" },
@@ -35883,13 +36671,18 @@ const TrajectResults = ({ isLoading }) => {
35883
36671
  React__default.createElement("strong", null, headerTitle || node.name))))),
35884
36672
  status === 'loading' && React__default.createElement(Spinner, { label: translations.SRP.LOADING_ACCOMMODATIONS }),
35885
36673
  status === 'unavailable' && React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
35886
- status === 'resolved' && selected && (React__default.createElement(React__default.Fragment, null,
35887
- availability.preferredUnavailable && node.preferredAccommodationName && (React__default.createElement("div", { className: "search__results__cards__actions" },
36674
+ status === 'resolved' && (selected || isRemoved) && (React__default.createElement(React__default.Fragment, null,
36675
+ selected && availability.preferredUnavailable && node.preferredAccommodationName && (React__default.createElement("div", { className: "search__results__cards__actions" },
35888
36676
  React__default.createElement("span", null,
35889
36677
  node.preferredAccommodationName,
35890
36678
  " \u2014 ",
35891
36679
  translations.SRP.NO_RESULTS))),
35892
- React__default.createElement(TrajectCardRow, { selectionKey: selected.code }, [selected, ...configured, ...fill].map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE })))),
36680
+ React__default.createElement(TrajectCardRow, { selectionKey: selected?.code ?? '' }, shown.map((result) => {
36681
+ const isSelected = result.code === selected?.code;
36682
+ return (React__default.createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (isSelected && removable ? handleRemoveNode(item) : handleSelect(item, result.code)), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE,
36683
+ // selectedLabel={bookedMode && matchesCode(result, node.code ?? '') ? translations.SHARED.BOOKED : undefined}
36684
+ selectedLabel: removable ? translations.SRP.REMOVE : undefined }));
36685
+ })),
35893
36686
  remaining > 0 && !hideShowMoreResults && (React__default.createElement("div", { className: "search__results__cards__actions" },
35894
36687
  React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
35895
36688
  translations.SRP.SHOW_MORE,
@@ -35899,7 +36692,7 @@ const TrajectResults = ({ isLoading }) => {
35899
36692
  };
35900
36693
  const handleSelectFlight = (item, flight) => {
35901
36694
  dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
35902
- dispatch(updateEditableEntryLine(buildFlightSelectionLine(item, flight, bookedMode)));
36695
+ dispatch(upsertEditableEntryLines([buildFlightSelectionLine(item, flight, bookedMode)]));
35903
36696
  };
35904
36697
  const renderFlightNode = (item) => {
35905
36698
  const { node, line } = item;
@@ -35908,7 +36701,9 @@ const TrajectResults = ({ isLoading }) => {
35908
36701
  const flights = availability?.results ?? [];
35909
36702
  const selected = flights.find((x) => x.outwardGuid === availability?.selectedGuid) ?? null;
35910
36703
  const others = flights.filter((x) => x.outwardGuid !== availability?.selectedGuid);
35911
- const visible = others.slice(0, 2);
36704
+ const isRemoved = status === 'resolved' && !selected && flights.length > 0;
36705
+ const removable = canRemove(item);
36706
+ const visible = others.slice(0, selected ? 2 : 3);
35912
36707
  return (React__default.createElement(React__default.Fragment, { key: line.guid },
35913
36708
  React__default.createElement("div", { className: "search__results__label search__results__label--secondary" },
35914
36709
  React__default.createElement("div", { className: "search__results__label__date" },
@@ -35923,15 +36718,15 @@ const TrajectResults = ({ isLoading }) => {
35923
36718
  node.arrivalAirportCode)))),
35924
36719
  status === 'loading' && React__default.createElement(Spinner, { label: translations.SRP.LOADING_FLIGHTS }),
35925
36720
  status === 'unavailable' && React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
35926
- status === 'resolved' && selected && (React__default.createElement(React__default.Fragment, null,
36721
+ status === 'resolved' && (selected || isRemoved) && (React__default.createElement(React__default.Fragment, null,
35927
36722
  React__default.createElement("div", { className: "search__results__cards search__results__cards--extended" },
35928
- React__default.createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price, selectedLabel: bookedMode && selected.outwardGuid === line.guid ? translations.SHARED.BOOKED : undefined }),
35929
- visible.map((result) => (React__default.createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected.price, onSelect: () => handleSelectFlight(item, result) })))),
35930
- others.length > 2 && !hideShowMoreResults && (React__default.createElement("div", { className: "search__results__cards__actions" },
36723
+ selected && (React__default.createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price, onSelect: removable ? () => handleRemoveFlight(item) : undefined, selectedLabel: bookedMode && selected.outwardGuid === line.guid ? translations.SHARED.BOOKED : removable ? translations.SRP.REMOVE : undefined })),
36724
+ visible.map((result) => (React__default.createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected?.price, onSelect: () => handleSelectFlight(item, result) })))),
36725
+ others.length > visible.length && !hideShowMoreResults && (React__default.createElement("div", { className: "search__results__cards__actions" },
35931
36726
  React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreFlights(item) },
35932
36727
  translations.SRP.SHOW_MORE,
35933
36728
  " (",
35934
- others.length - 2,
36729
+ others.length - visible.length,
35935
36730
  ")")))))));
35936
36731
  };
35937
36732
  /** The lines a suggested activity put on the entry, which is also how we know it was added. */
@@ -36007,13 +36802,21 @@ const TrajectResults = ({ isLoading }) => {
36007
36802
  ")")))));
36008
36803
  };
36009
36804
  /**
36010
- * An activity the traject books is swapped for another, the way a hotel is; one the traveller
36011
- * found for themselves is added to the trip or taken back off it.
36805
+ * An activity the traject books is swapped for another, the way a hotel is, or - when it is optional -
36806
+ * taken off the trip; one the traveller found for themselves is added to the trip or taken back off it.
36012
36807
  */
36013
36808
  const renderActivityCard = ({ result, item }) => {
36014
36809
  const isSelected = isActivitySelected({ result, item });
36015
36810
  const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
36016
- return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(item, result.code) : handleToggleActivity(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
36811
+ const removable = !!item && canRemove(item);
36812
+ const handleClick = () => {
36813
+ if (!item)
36814
+ return handleToggleActivity(result);
36815
+ if (isSelected && removable)
36816
+ return handleRemoveNode(item);
36817
+ handleSelect(item, result.code);
36818
+ };
36819
+ return (React__default.createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: handleClick, selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item && !removable ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
36017
36820
  };
36018
36821
  if (isLoading)
36019
36822
  return React__default.createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
@@ -36048,6 +36851,7 @@ const TrajectResults = ({ isLoading }) => {
36048
36851
  const useTrajectAvailability = () => {
36049
36852
  const context = useContext(SearchResultsConfigurationContext);
36050
36853
  const dispatch = useDispatch();
36854
+ const { editablePackagingEntry, trajectTransferAvailability } = useSelector((state) => state.searchResults);
36051
36855
  const trajectEntry = context?.trajectEntry;
36052
36856
  const showApiItems = !!context?.showApiItems;
36053
36857
  const hideShowMoreResults = !!context?.hideShowMoreResults;
@@ -36073,12 +36877,14 @@ const useTrajectAvailability = () => {
36073
36877
  rooms: getPackagingRoomsFromEntry(trajectEntry.entry)
36074
36878
  };
36075
36879
  // Flight searches take passengers rather than rooms; the API buckets by age.
36880
+ // The ids must be the entry's own pax ids: the flight lines this search caches carry them as
36881
+ // EntryLinePax.PaxId, and booking maps those onto the entry's travelers (PackagingService.SyncPaxIds).
36076
36882
  const pax = trajectEntry.entry.pax ?? [];
36077
36883
  const ageOf = (p) => p.age ?? 30;
36078
- const adults = pax.filter((p) => ageOf(p) >= 12).length;
36079
- const kids = pax.filter((p) => ageOf(p) >= 2 && ageOf(p) < 12).length;
36080
- const babies = pax.filter((p) => ageOf(p) < 2).length;
36081
- const flightPax = concat(Array.from({ length: adults }, (_, index) => ({ id: index, age: 31 })), Array.from({ length: kids }, (_, index) => ({ id: index + adults, age: 8 })), Array.from({ length: babies }, (_, index) => ({ id: index + adults + kids, age: 1 })));
36884
+ const adults = pax.filter((p) => ageOf(p) >= 12);
36885
+ const kids = pax.filter((p) => ageOf(p) >= 2 && ageOf(p) < 12);
36886
+ const babies = pax.filter((p) => ageOf(p) < 2);
36887
+ const flightPax = concat(adults.map((p) => ({ id: p.id, age: 31 })), kids.map((p) => ({ id: p.id, age: 8 })), babies.map((p) => ({ id: p.id, age: 1 })));
36082
36888
  const nodesWithLines = getTrajectNodesWithLines(trajectEntry);
36083
36889
  // The other members of a line group are alternatives whether or not a search still finds
36084
36890
  // them; the ones it does not are drawn from their lines, as the booked service itself is.
@@ -36209,9 +37015,30 @@ const useTrajectAvailability = () => {
36209
37015
  return item.lines.map((x) => x.guid);
36210
37016
  }
36211
37017
  };
37018
+ const resolveTransferNode = async (node) => {
37019
+ dispatch(setTrajectTransferLoading(node.nodeId));
37020
+ try {
37021
+ const results = (await build.searchPackagingTransfers(config, buildTrajectTransferRequest(node, searchContext), controller.signal)) ?? [];
37022
+ if (controller.signal.aborted)
37023
+ return [];
37024
+ const result = results[0] ?? null;
37025
+ dispatch(setTrajectTransferAvailability({ nodeId: node.nodeId, result: result && buildTrajectTransferLine(node, result) ? result : null }));
37026
+ }
37027
+ catch (error) {
37028
+ if (controller.signal.aborted)
37029
+ return [];
37030
+ console.error('Failed to resolve traject transfer', node.name, error);
37031
+ dispatch(setTrajectTransferAvailability({ nodeId: node.nodeId, result: null }));
37032
+ }
37033
+ return [];
37034
+ };
36212
37035
  (async () => {
36213
37036
  const resolvable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node));
36214
- const unresolved = (await Promise.all(resolvable.map((item) => (isTrajectFlightNode(item.node) ? resolveFlightNode(item) : resolveNode(item))))).flat();
37037
+ const transfers = bookedMode ? [] : (trajectEntry.nodes ?? []).filter(isTrajectTransferNode);
37038
+ const unresolved = (await Promise.all([
37039
+ ...resolvable.map((item) => (isTrajectFlightNode(item.node) ? resolveFlightNode(item) : resolveNode(item))),
37040
+ ...transfers.map(resolveTransferNode)
37041
+ ])).flat();
36215
37042
  if (controller.signal.aborted)
36216
37043
  return;
36217
37044
  dispatch(setTrajectResolving(false));
@@ -36223,6 +37050,28 @@ const useTrajectAvailability = () => {
36223
37050
  })();
36224
37051
  return () => controller.abort();
36225
37052
  }, [trajectEntry, showApiItems, hideShowMoreResults]);
37053
+ useEffect(() => {
37054
+ if (!trajectEntry || !editablePackagingEntry || isBookedEntryTraject(trajectEntry))
37055
+ return;
37056
+ const dropped = getDroppedTrajectNodeIds(trajectEntry, editablePackagingEntry);
37057
+ const guids = new Set((editablePackagingEntry.lines ?? []).map((line) => line.guid));
37058
+ const toAdd = [];
37059
+ const toRemove = [];
37060
+ (trajectEntry.nodes ?? []).filter(isTrajectTransferNode).forEach((node) => {
37061
+ const result = trajectTransferAvailability[node.nodeId]?.result;
37062
+ const line = result ? buildTrajectTransferLine(node, result) : null;
37063
+ if (!line)
37064
+ return;
37065
+ if (dropped.has(node.nodeId) && guids.has(line.guid))
37066
+ toRemove.push(line.guid);
37067
+ if (!dropped.has(node.nodeId) && !guids.has(line.guid))
37068
+ toAdd.push(line);
37069
+ });
37070
+ if (toRemove.length)
37071
+ dispatch(removeEditableEntryLines(toRemove));
37072
+ if (toAdd.length)
37073
+ dispatch(addEditableEntryLines(toAdd));
37074
+ }, [trajectEntry, editablePackagingEntry, trajectTransferAvailability]);
36226
37075
  };
36227
37076
 
36228
37077
  const SearchResultsContainer = ({ onBookingStarted }) => {
@@ -36527,10 +37376,9 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
36527
37376
  const item = getTrajectNodesWithLines(context.trajectEntry).find((x) => x.line.guid === trajectEditLineGuid);
36528
37377
  const result = packagingAccoSearchDetails.find((x) => x.code === selectedPackagingAccoResultCode);
36529
37378
  if (item && result) {
36530
- const currentLines = item.lines
36531
- .map((line) => editablePackagingEntry?.lines?.find((x) => x.guid === line.guid))
36532
- .filter((x) => !!x);
36533
- applyResultToLines(currentLines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
37379
+ // A stop the traveller took off has no lines left on the entry: the traject's own put it back.
37380
+ const currentLines = item.lines.map((line) => editablePackagingEntry?.lines?.find((x) => x.guid === line.guid) ?? line);
37381
+ dispatch(upsertEditableEntryLines(applyResultToLines(currentLines, result)));
36534
37382
  dispatch(updateTrajectNodeResult({ lineGuid: trajectEditLineGuid, result }));
36535
37383
  }
36536
37384
  dispatch(setTrajectEditLineGuid(null));
@@ -40155,6 +41003,363 @@ const Login = ({ tideClientConfig, portalId, languageCode, imageSrc, logo, isMem
40155
41003
  isMemberConfirmation && (React__default.createElement(ConfirmComponent, { tideClientConfig: tideClientConfig, portalId: portalId, languageCode: languageCode, member: member, setMember: setMember, handleBackToHome: handleBackToHome, handleBackToLogin: handleBackToLogin }))))));
40156
41004
  };
40157
41005
 
41006
+ /** Agent endpoints need the member token, fall back to the one the Login component stored. */
41007
+ const withAgentToken = (config) => ({
41008
+ ...config,
41009
+ token: config.token ?? selectAgentToken()
41010
+ });
41011
+ /** False when the token is not a JWT or has expired. */
41012
+ const isAgentTokenValid = (token) => {
41013
+ if (!token)
41014
+ return false;
41015
+ try {
41016
+ const { exp } = jwtDecode(token);
41017
+ return !exp || exp * 1000 > Date.now();
41018
+ }
41019
+ catch {
41020
+ return false;
41021
+ }
41022
+ };
41023
+ // tide-client throws Error(statusText) without the status, and statusText is empty over HTTP/2,
41024
+ // so also treat any failure with an invalid/expired token as unauthorized.
41025
+ const isUnauthorizedError = (error, token) => (error instanceof Error && /unauthori[sz]ed|forbidden/i.test(error.message)) || !isAgentTokenValid(token);
41026
+ const fetchLookups = async (config, languageCode, signal) => {
41027
+ // A failing lookup should not block the list itself.
41028
+ const [entryStatuses, customEntryStatuses, printActions] = await Promise.allSettled([
41029
+ build.getEntryStatus(config, signal, languageCode),
41030
+ build.getCustomEntryStatus(config, signal, languageCode),
41031
+ build.getPrintActions(config, build.PrintActionGroup.Dossier, signal)
41032
+ ]);
41033
+ return {
41034
+ entryStatuses: entryStatuses.status === 'fulfilled' ? entryStatuses.value ?? [] : [],
41035
+ customEntryStatuses: customEntryStatuses.status === 'fulfilled' ? customEntryStatuses.value ?? [] : [],
41036
+ printActions: printActions.status === 'fulfilled' ? printActions.value ?? [] : []
41037
+ };
41038
+ };
41039
+ /** Converts the raw filter inputs to the OData column filters understood by tide-client's createParams. */
41040
+ const buildFilterItem = (columns, filterValues, sort, page, take) => {
41041
+ const filterColumns = {};
41042
+ columns.forEach((column) => {
41043
+ const raw = filterValues[column.id]?.trim();
41044
+ if (!raw)
41045
+ return;
41046
+ switch (column.kind) {
41047
+ case 'text':
41048
+ filterColumns[column.id] = { type: 'text', value: raw };
41049
+ break;
41050
+ case 'number': {
41051
+ const value = parseFloat(raw.replace(',', '.'));
41052
+ if (!isNaN(value))
41053
+ filterColumns[column.id] = { type: 'number', value };
41054
+ break;
41055
+ }
41056
+ case 'date': {
41057
+ // <input type="date"> value: yyyy-MM-dd, createParams expects a 1-based month.
41058
+ const [year, month, day] = raw.split('-').map((x) => parseInt(x, 10));
41059
+ if (year && month && day)
41060
+ filterColumns[column.id] = { type: 'date', value: { year, month, day } };
41061
+ break;
41062
+ }
41063
+ case 'status':
41064
+ case 'customStatus':
41065
+ filterColumns[column.id] = { type: 'enum', value: parseInt(raw, 10) };
41066
+ break;
41067
+ }
41068
+ });
41069
+ return { take, page, sort, columns: filterColumns };
41070
+ };
41071
+ const fetchEntries = (config, filter, signal) => build.getEntryList(config, filter, undefined, signal);
41072
+ /** Prints the entry and returns an object url to the resulting pdf. */
41073
+ const printEntry = async (config, printActionId, entryId) => {
41074
+ // Same request as the agent portal: the print action and the entry (version) id.
41075
+ const request = { id: printActionId, entryId };
41076
+ const response = await build.print(config, request);
41077
+ if (!response.ok)
41078
+ throw new Error(response.statusText);
41079
+ const buffer = await response.arrayBuffer();
41080
+ return URL.createObjectURL(new Blob([buffer], { type: 'application/pdf' }));
41081
+ };
41082
+
41083
+ const PAGE_SIZES = [10, 20, 50, 100];
41084
+ const FILTER_DEBOUNCE_MS = 400;
41085
+ const EyeIcon = () => (React__default.createElement("svg", { className: "agent-entries__icon", viewBox: "0 0 576 512", fill: "currentColor", "aria-hidden": "true" },
41086
+ React__default.createElement("path", { d: "M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4 142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1 3.3-7.9 3.3-16.7 0-24.6-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1-288 0zm144-64c0 35.3-28.7 64-64 64-7.1 0-13.9-1.2-20.3-3.3-5.5-1.8-11.9 1.6-11.7 7.4.3 6.9 1.3 13.8 3.2 20.7 13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1-5.8-.2-9.2 6.1-7.4 11.7 2.1 6.4 3.3 13.2 3.3 20.3z" })));
41087
+ const PrintIcon = () => (React__default.createElement("svg", { className: "agent-entries__icon", viewBox: "0 0 512 512", fill: "currentColor", "aria-hidden": "true" },
41088
+ React__default.createElement("path", { d: "M128 0C92.7 0 64 28.7 64 64v96h64V64h226.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zm256 352v96H128v-96h256zm64 32h32c17.7 0 32-14.3 32-32v-96c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32h32v64c0 35.3 28.7 64 64 64h256c35.3 0 64-28.7 64-64v-64zm-16-136a24 24 0 1 1 0 48 24 24 0 1 1 0-48z" })));
41089
+ const SortIcon = ({ asc }) => (React__default.createElement("svg", { className: buildClassName(['agent-entries__sort-icon', !asc && 'agent-entries__sort-icon--desc']), viewBox: "0 0 320 512", fill: "currentColor", "aria-hidden": "true" },
41090
+ React__default.createElement("path", { d: "M182.6 137.4c-12.5-12.5-32.8-12.5-45.3 0l-128 128c-9.2 9.2-11.9 22.9-6.9 34.9S19 320 32 320h256c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-128-128z" })));
41091
+ const AgentEntries = ({ tideClientConfig, languageCode, title, pageSize, customTranslations, onLogin, onUnauthorized }) => {
41092
+ const translations = useMemo(() => getTranslations(languageCode ?? 'en-GB', customTranslations), [languageCode, customTranslations]);
41093
+ const t = translations.AGENT_ENTRIES;
41094
+ const config = useMemo(() => withAgentToken(tideClientConfig), [tideClientConfig.host, tideClientConfig.apiKey, tideClientConfig.token]);
41095
+ const isLoggedIn = !!config.token;
41096
+ const hasValidToken = isLoggedIn && isAgentTokenValid(config.token);
41097
+ const columns = useMemo(() => [
41098
+ { id: 'number', kind: 'text', label: t.NUMBER },
41099
+ { id: 'departureDate', kind: 'date', label: t.DEPARTURE_DATE },
41100
+ { id: 'status', kind: 'status', label: t.STATUS },
41101
+ { id: 'customEntryStatusId', kind: 'customStatus', label: t.CUSTOM_STATUS },
41102
+ { id: 'returnDate', kind: 'date', label: t.RETURN_DATE },
41103
+ { id: 'profit', kind: 'number', label: t.PROFIT },
41104
+ { id: 'totalPrice', kind: 'number', label: t.NETTO_SELLING_PRICE },
41105
+ { id: 'calculatedAgentSurchargeAmount', kind: 'number', label: t.YOUR_SURCHARGE },
41106
+ { id: 'createdDate', kind: 'date', label: t.CREATED },
41107
+ { id: 'contact', kind: 'text', label: t.CONTACT },
41108
+ { id: 'travelerAddress', kind: 'text', label: t.MAIN_BOOKER }
41109
+ ], [t]);
41110
+ const [lookups, setLookups] = useState({ entryStatuses: [], customEntryStatuses: [], printActions: [] });
41111
+ const [entries, setEntries] = useState([]);
41112
+ const [count, setCount] = useState();
41113
+ const [loadState, setLoadState] = useState('idle');
41114
+ const [filterInputs, setFilterInputs] = useState({});
41115
+ const [filterValues, setFilterValues] = useState({});
41116
+ const [sort, setSort] = useState({ name: 'number', asc: true });
41117
+ const [page, setPage] = useState(1);
41118
+ const [take, setTake] = useState(pageSize ?? 20);
41119
+ const [expandedId, setExpandedId] = useState();
41120
+ const [printingKey, setPrintingKey] = useState();
41121
+ const [printError, setPrintError] = useState(false);
41122
+ const handleError = (error) => {
41123
+ if (error instanceof DOMException && error.name === 'AbortError')
41124
+ return;
41125
+ if (isUnauthorizedError(error, config.token)) {
41126
+ setLoadState('unauthorized');
41127
+ onUnauthorized?.();
41128
+ }
41129
+ else {
41130
+ console.error(error);
41131
+ setLoadState('error');
41132
+ }
41133
+ };
41134
+ useEffect(() => {
41135
+ if (isLoggedIn && !hasValidToken)
41136
+ onUnauthorized?.();
41137
+ }, [isLoggedIn, hasValidToken]);
41138
+ // Lookups (statuses & print actions) only need to be fetched once.
41139
+ useEffect(() => {
41140
+ if (!hasValidToken)
41141
+ return;
41142
+ const controller = new AbortController();
41143
+ fetchLookups(config, languageCode, controller.signal)
41144
+ .then(setLookups)
41145
+ .catch(() => { });
41146
+ return () => controller.abort();
41147
+ }, [config, languageCode, hasValidToken]);
41148
+ // Debounce the typed filters, a selected dropdown/date is applied immediately.
41149
+ useEffect(() => {
41150
+ const handle = setTimeout(() => {
41151
+ if (isEqual$1(filterInputs, filterValues))
41152
+ return;
41153
+ setFilterValues(filterInputs);
41154
+ setPage(1);
41155
+ }, FILTER_DEBOUNCE_MS);
41156
+ return () => clearTimeout(handle);
41157
+ }, [filterInputs]);
41158
+ useEffect(() => {
41159
+ if (!hasValidToken)
41160
+ return;
41161
+ const controller = new AbortController();
41162
+ setLoadState('loading');
41163
+ fetchEntries(config, buildFilterItem(columns, filterValues, sort, page, take), controller.signal)
41164
+ .then((result) => {
41165
+ setEntries(result?.items ?? []);
41166
+ setCount(result?.count ?? undefined);
41167
+ setLoadState('loaded');
41168
+ })
41169
+ .catch(handleError);
41170
+ return () => controller.abort();
41171
+ }, [config, hasValidToken, columns, filterValues, sort, page, take]);
41172
+ const totalPages = count !== undefined ? Math.max(1, Math.ceil(count / take)) : undefined;
41173
+ const hasNextPage = totalPages !== undefined ? page < totalPages : entries.length === take;
41174
+ const handleSort = (columnId) => {
41175
+ setSort((current) => (current.name === columnId ? { name: columnId, asc: !current.asc } : { name: columnId, asc: true }));
41176
+ setPage(1);
41177
+ };
41178
+ const handleFilterChange = (columnId, value, immediate) => {
41179
+ const next = { ...filterInputs, [columnId]: value };
41180
+ setFilterInputs(next);
41181
+ if (immediate) {
41182
+ setFilterValues(next);
41183
+ setPage(1);
41184
+ }
41185
+ };
41186
+ const handlePrint = async (entry, printAction) => {
41187
+ // Open the tab synchronously, otherwise the popup blocker kicks in once the pdf arrives.
41188
+ const printWindow = window.open('', '_blank');
41189
+ setPrintingKey(`${entry.id}-${printAction.id}`);
41190
+ setPrintError(false);
41191
+ try {
41192
+ const url = await printEntry(config, printAction.id, entry.id);
41193
+ if (printWindow) {
41194
+ printWindow.location.href = url;
41195
+ }
41196
+ else {
41197
+ window.open(url, '_blank');
41198
+ }
41199
+ setTimeout(() => URL.revokeObjectURL(url), 60000);
41200
+ }
41201
+ catch (error) {
41202
+ printWindow?.close();
41203
+ if (isUnauthorizedError(error, config.token)) {
41204
+ handleError(error);
41205
+ }
41206
+ else {
41207
+ console.error(error);
41208
+ setPrintError(true);
41209
+ }
41210
+ }
41211
+ finally {
41212
+ setPrintingKey(undefined);
41213
+ }
41214
+ };
41215
+ const formatDate = (value) => {
41216
+ if (!value)
41217
+ return '';
41218
+ const date = new Date(value);
41219
+ if (isNaN(date.getTime()))
41220
+ return '';
41221
+ return new Intl.DateTimeFormat(languageCode, { day: '2-digit', month: '2-digit', year: 'numeric' }).format(date);
41222
+ };
41223
+ const formatNumber = (value) => {
41224
+ if (value === undefined || value === null)
41225
+ return '';
41226
+ return new Intl.NumberFormat(languageCode, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(value);
41227
+ };
41228
+ const getEntryStatusLabel = (status) => lookups.entryStatuses.find((x) => x.key === status)?.value ?? '';
41229
+ const getCustomEntryStatusLabel = (id) => lookups.customEntryStatuses.find((x) => x.id === id)?.name ?? '';
41230
+ const getPrintActionsForEntry = (entry) => lookups.printActions.filter((x) => x.validEntryStatuses?.includes(entry.status));
41231
+ const renderCell = (entry, column) => {
41232
+ const value = entry[column.id];
41233
+ switch (column.kind) {
41234
+ case 'date':
41235
+ return formatDate(value);
41236
+ case 'number':
41237
+ return formatNumber(value);
41238
+ case 'status':
41239
+ return getEntryStatusLabel(value);
41240
+ case 'customStatus':
41241
+ return getCustomEntryStatusLabel(value);
41242
+ default:
41243
+ return value ?? '';
41244
+ }
41245
+ };
41246
+ const renderFilter = (column) => {
41247
+ const value = filterInputs[column.id] ?? '';
41248
+ const className = 'agent-entries__filter';
41249
+ switch (column.kind) {
41250
+ case 'date':
41251
+ return (React__default.createElement("input", { type: "date", className: className, value: value, "aria-label": column.label, onChange: (e) => handleFilterChange(column.id, e.target.value, true) }));
41252
+ case 'status':
41253
+ case 'customStatus': {
41254
+ const options = column.kind === 'status'
41255
+ ? lookups.entryStatuses.filter((x) => x.key !== undefined && x.key !== null).map((x) => ({ key: x.key, value: x.value }))
41256
+ : lookups.customEntryStatuses.map((x) => ({ key: x.id, value: x.name }));
41257
+ return (React__default.createElement("select", { className: className, value: value, "aria-label": column.label, onChange: (e) => handleFilterChange(column.id, e.target.value, true) },
41258
+ React__default.createElement("option", { value: "" }, t.ALL),
41259
+ options.map((option) => (React__default.createElement("option", { key: option.key, value: option.key }, option.value)))));
41260
+ }
41261
+ case 'number':
41262
+ return (React__default.createElement("input", { type: "number", className: className, value: value, "aria-label": column.label, onChange: (e) => handleFilterChange(column.id, e.target.value) }));
41263
+ default:
41264
+ return (React__default.createElement("input", { type: "text", className: className, value: value, "aria-label": column.label, onChange: (e) => handleFilterChange(column.id, e.target.value) }));
41265
+ }
41266
+ };
41267
+ const renderDetails = (entry) => {
41268
+ const printActions = getPrintActionsForEntry(entry);
41269
+ const travelers = entry.pax?.length ? entry.pax.map((p) => (p.isMainBooker ? `${p.name} (${t.MAIN_BOOKER.toLowerCase()})` : p.name)).join(', ') : '';
41270
+ const details = [
41271
+ { label: t.NUMBER, value: entry.number },
41272
+ { label: t.PRODUCT, value: entry.firstProductName },
41273
+ { label: t.STATUS, value: getEntryStatusLabel(entry.status) },
41274
+ { label: t.CUSTOM_STATUS, value: getCustomEntryStatusLabel(entry.customEntryStatusId) },
41275
+ { label: t.DEPARTURE_DATE, value: formatDate(entry.departureDate) },
41276
+ { label: t.RETURN_DATE, value: formatDate(entry.returnDate) },
41277
+ { label: t.CREATED, value: formatDate(entry.createdDate) },
41278
+ { label: t.CONTACT, value: entry.contact },
41279
+ { label: t.MAIN_BOOKER, value: entry.travelerAddress },
41280
+ { label: t.TRAVELERS, value: travelers || (entry.paxCount ? entry.paxCount : '') },
41281
+ { label: t.NETTO_SELLING_PRICE, value: formatNumber(entry.totalPrice) },
41282
+ { label: t.YOUR_SURCHARGE, value: formatNumber(entry.calculatedAgentSurchargeAmount) },
41283
+ { label: t.PROFIT, value: formatNumber(entry.profit) }
41284
+ ];
41285
+ return (React__default.createElement("div", { className: "agent-entries__details" },
41286
+ React__default.createElement("dl", { className: "agent-entries__details__list" }, details
41287
+ .filter((detail) => detail.value !== undefined && detail.value !== null && detail.value !== '')
41288
+ .map((detail) => (React__default.createElement("div", { className: "agent-entries__details__item", key: detail.label },
41289
+ React__default.createElement("dt", null, detail.label),
41290
+ React__default.createElement("dd", null, detail.value))))),
41291
+ printActions.length > 0 && (React__default.createElement("div", { className: "agent-entries__details__prints" },
41292
+ React__default.createElement("span", { className: "agent-entries__details__prints__title" }, t.PRINTS),
41293
+ React__default.createElement("div", { className: "agent-entries__details__prints__buttons" }, printActions.map((printAction) => (React__default.createElement("button", { type: "button", key: printAction.id, className: "agent-entries__print-button", disabled: printingKey === `${entry.id}-${printAction.id}`, onClick: () => handlePrint(entry, printAction) },
41294
+ React__default.createElement(PrintIcon, null),
41295
+ printAction.label))))))));
41296
+ };
41297
+ const renderLoginMessage = (message) => (React__default.createElement("div", { className: "agent-entries__message" },
41298
+ React__default.createElement("p", null, message),
41299
+ onLogin && (React__default.createElement("button", { type: "button", className: "cta cta--primary", onClick: onLogin }, translations.LOGIN.LOGIN))));
41300
+ if (!isLoggedIn) {
41301
+ return (React__default.createElement("div", { className: "agent-entries" },
41302
+ React__default.createElement("h2", { className: "agent-entries__title" }, title ?? t.TITLE),
41303
+ renderLoginMessage(t.NOT_LOGGED_IN)));
41304
+ }
41305
+ if (!hasValidToken || loadState === 'unauthorized') {
41306
+ return (React__default.createElement("div", { className: "agent-entries" },
41307
+ React__default.createElement("h2", { className: "agent-entries__title" }, title ?? t.TITLE),
41308
+ renderLoginMessage(t.SESSION_EXPIRED)));
41309
+ }
41310
+ const columnCount = columns.length + 1;
41311
+ return (React__default.createElement("div", { className: "agent-entries" },
41312
+ React__default.createElement("h2", { className: "agent-entries__title" }, title ?? t.TITLE),
41313
+ printError && (React__default.createElement("div", { className: "agent-entries__error", role: "alert" },
41314
+ t.PRINT_ERROR,
41315
+ React__default.createElement("button", { type: "button", className: "agent-entries__error__close", "aria-label": "close", onClick: () => setPrintError(false) }, "\u00D7"))),
41316
+ React__default.createElement("div", { className: buildClassName(['agent-entries__card', loadState === 'loading' && 'agent-entries__card--loading']) },
41317
+ React__default.createElement("div", { className: "agent-entries__table-wrapper" },
41318
+ React__default.createElement("table", { className: "agent-entries__table" },
41319
+ React__default.createElement("thead", null,
41320
+ React__default.createElement("tr", null,
41321
+ React__default.createElement("th", { className: "agent-entries__actions-header" },
41322
+ React__default.createElement("span", { className: "agent-entries__sr-only" }, t.ACTIONS)),
41323
+ columns.map((column) => (React__default.createElement("th", { key: column.id, "aria-sort": sort.name === column.id ? (sort.asc ? 'ascending' : 'descending') : undefined },
41324
+ React__default.createElement("button", { type: "button", className: "agent-entries__sort", onClick: () => handleSort(column.id) },
41325
+ column.label,
41326
+ sort.name === column.id && React__default.createElement(SortIcon, { asc: sort.asc })))))),
41327
+ React__default.createElement("tr", { className: "agent-entries__filter-row" },
41328
+ React__default.createElement("th", null),
41329
+ columns.map((column) => (React__default.createElement("th", { key: column.id }, renderFilter(column)))))),
41330
+ React__default.createElement("tbody", null,
41331
+ loadState === 'error' && (React__default.createElement("tr", null,
41332
+ React__default.createElement("td", { colSpan: columnCount, className: "agent-entries__empty" }, t.ERROR))),
41333
+ loadState !== 'error' && entries.length === 0 && (React__default.createElement("tr", null,
41334
+ React__default.createElement("td", { colSpan: columnCount, className: "agent-entries__empty" }, loadState === 'loading' ? t.LOADING : t.NO_ITEMS))),
41335
+ loadState !== 'error' &&
41336
+ entries.map((entry) => {
41337
+ const isExpanded = expandedId === entry.id;
41338
+ return (React__default.createElement(React__default.Fragment, { key: entry.id },
41339
+ React__default.createElement("tr", { className: buildClassName(['agent-entries__row', isExpanded && 'agent-entries__row--expanded']) },
41340
+ React__default.createElement("td", { className: "agent-entries__actions" },
41341
+ React__default.createElement("button", { type: "button", className: "agent-entries__action agent-entries__action--primary", title: isExpanded ? t.HIDE_DETAILS : t.DETAILS, "aria-label": isExpanded ? t.HIDE_DETAILS : t.DETAILS, "aria-expanded": isExpanded, onClick: () => setExpandedId(isExpanded ? undefined : entry.id) },
41342
+ React__default.createElement(EyeIcon, null)),
41343
+ getPrintActionsForEntry(entry).map((printAction) => (React__default.createElement("button", { type: "button", key: printAction.id, className: "agent-entries__action", title: printAction.label, "aria-label": printAction.label, disabled: printingKey === `${entry.id}-${printAction.id}`, onClick: () => handlePrint(entry, printAction) },
41344
+ React__default.createElement(PrintIcon, null))))),
41345
+ columns.map((column) => (React__default.createElement("td", { key: column.id, className: `agent-entries__cell agent-entries__cell--${column.kind}` }, renderCell(entry, column))))),
41346
+ isExpanded && (React__default.createElement("tr", { className: "agent-entries__details-row" },
41347
+ React__default.createElement("td", { colSpan: columnCount }, renderDetails(entry))))));
41348
+ })))),
41349
+ React__default.createElement("div", { className: "agent-entries__footer" },
41350
+ React__default.createElement("select", { className: "agent-entries__page-size", value: take, "aria-label": t.PAGE_SIZE, onChange: (e) => {
41351
+ setTake(parseInt(e.target.value, 10));
41352
+ setPage(1);
41353
+ } }, Array.from(new Set([...PAGE_SIZES, take]))
41354
+ .sort((a, b) => a - b)
41355
+ .map((size) => (React__default.createElement("option", { key: size, value: size }, size)))),
41356
+ count !== undefined && React__default.createElement("span", { className: "agent-entries__count" }, format$1(t.X_ITEMS, [count])),
41357
+ React__default.createElement("div", { className: "agent-entries__pager" },
41358
+ React__default.createElement("button", { type: "button", className: "agent-entries__pager__button", disabled: page <= 1, onClick: () => setPage(page - 1) }, t.PREVIOUS),
41359
+ React__default.createElement("span", { className: "agent-entries__pager__info" }, totalPages !== undefined ? format$1(t.PAGE_X_OF_Y, [page, totalPages]) : page),
41360
+ React__default.createElement("button", { type: "button", className: "agent-entries__pager__button", disabled: !hasNextPage, onClick: () => setPage(page + 1) }, t.NEXT))))));
41361
+ };
41362
+
40158
41363
  const ImageWithTextCard = ({ noCard, fullImage, reverse, imageSrc, imageAlt, title, section1Title, section1Text, section2Title, section2Text, buttonText, onButtonClick }) => {
40159
41364
  let cardClassName = 'image-with-text__card';
40160
41365
  if (noCard) {
@@ -44613,4 +45818,4 @@ var signalR = /*#__PURE__*/_mergeNamespaces({
44613
45818
  'default': signalR$1
44614
45819
  }, [signalR$1]);
44615
45820
 
44616
- export { BookingProduct, BookingWizard, Breadcrumbs, DepartureRange, FAQ, FeaturedTrips, Footer, Header, ImageCardGrid, ImageWithTextSection, ItineraryMapView, Login, Navbar, PhotoGallery, QSM, SearchResults, Slider, Spinner, TideForm };
45821
+ export { AgentEntries, BookingProduct, BookingWizard, Breadcrumbs, DepartureRange, FAQ, FeaturedTrips, Footer, Header, ImageCardGrid, ImageWithTextSection, ItineraryMapView, Login, Navbar, PhotoGallery, QSM, SearchResults, Slider, Spinner, TideForm };