@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.
@@ -509,6 +509,39 @@ var FORM$f = {
509
509
  YES: "نعم",
510
510
  NO: "لا"
511
511
  };
512
+ var AGENT_ENTRIES$f = {
513
+ TITLE: "الحجوزات",
514
+ MY_BOOKINGS: "حجوزاتي",
515
+ NUMBER: "الرقم",
516
+ DEPARTURE_DATE: "تاريخ المغادرة",
517
+ STATUS: "الحالة",
518
+ CUSTOM_STATUS: "حالة مخصصة",
519
+ RETURN_DATE: "تاريخ العودة",
520
+ PROFIT: "الربح",
521
+ NETTO_SELLING_PRICE: "صافي سعر البيع",
522
+ YOUR_SURCHARGE: "رسومك الإضافية",
523
+ CREATED: "تاريخ الإنشاء",
524
+ CONTACT: "جهة الاتصال",
525
+ MAIN_BOOKER: "الحاجز الرئيسي",
526
+ PRODUCT: "المنتج",
527
+ TRAVELERS: "المسافرون",
528
+ ACTIONS: "الإجراءات",
529
+ DETAILS: "التفاصيل",
530
+ HIDE_DETAILS: "إخفاء التفاصيل",
531
+ PRINTS: "المطبوعات",
532
+ ALL: "الكل",
533
+ X_ITEMS: "{0} عناصر",
534
+ PAGE_SIZE: "عناصر لكل صفحة",
535
+ PREVIOUS: "السابق",
536
+ NEXT: "التالي",
537
+ PAGE_X_OF_Y: "الصفحة {0} من {1}",
538
+ LOADING: "جارٍ التحميل...",
539
+ NO_ITEMS: "لم يتم العثور على حجوزات.",
540
+ ERROR: "حدث خطأ أثناء تحميل حجوزاتك.",
541
+ PRINT_ERROR: "فشلت الطباعة، يرجى المحاولة مرة أخرى.",
542
+ NOT_LOGGED_IN: "سجّل الدخول كوكيل لعرض حجوزاتك.",
543
+ SESSION_EXPIRED: "انتهت صلاحية جلستك، يرجى تسجيل الدخول مرة أخرى."
544
+ };
512
545
  var arJson = {
513
546
  STEPS: STEPS$f,
514
547
  INPUT: INPUT$f,
@@ -529,7 +562,8 @@ var arJson = {
529
562
  QSM: QSM$g,
530
563
  SRP: SRP$f,
531
564
  ITINERARY: ITINERARY$f,
532
- FORM: FORM$f
565
+ FORM: FORM$f,
566
+ AGENT_ENTRIES: AGENT_ENTRIES$f
533
567
  };
534
568
 
535
569
  var STEPS$e = {
@@ -982,6 +1016,39 @@ var FORM$e = {
982
1016
  YES: "Ja",
983
1017
  NO: "Nej"
984
1018
  };
1019
+ var AGENT_ENTRIES$e = {
1020
+ TITLE: "Bookinger",
1021
+ MY_BOOKINGS: "Mine bookinger",
1022
+ NUMBER: "Nummer",
1023
+ DEPARTURE_DATE: "Afrejsedato",
1024
+ STATUS: "Status",
1025
+ CUSTOM_STATUS: "Tilpasset status",
1026
+ RETURN_DATE: "Hjemrejsedato",
1027
+ PROFIT: "Fortjeneste",
1028
+ NETTO_SELLING_PRICE: "Netto salgspris",
1029
+ YOUR_SURCHARGE: "Dit tillæg",
1030
+ CREATED: "Oprettet",
1031
+ CONTACT: "Kontakt",
1032
+ MAIN_BOOKER: "Hovedbooker",
1033
+ PRODUCT: "Produkt",
1034
+ TRAVELERS: "Rejsende",
1035
+ ACTIONS: "Handlinger",
1036
+ DETAILS: "Detaljer",
1037
+ HIDE_DETAILS: "Skjul detaljer",
1038
+ PRINTS: "Udskrifter",
1039
+ ALL: "Alle",
1040
+ X_ITEMS: "{0} elementer",
1041
+ PAGE_SIZE: "Elementer pr. side",
1042
+ PREVIOUS: "Forrige",
1043
+ NEXT: "Næste",
1044
+ PAGE_X_OF_Y: "Side {0} af {1}",
1045
+ LOADING: "Indlæser...",
1046
+ NO_ITEMS: "Ingen bookinger fundet.",
1047
+ ERROR: "Der opstod en fejl under indlæsning af dine bookinger.",
1048
+ PRINT_ERROR: "Udskrivning mislykkedes, prøv igen.",
1049
+ NOT_LOGGED_IN: "Log ind som agent for at se dine bookinger.",
1050
+ SESSION_EXPIRED: "Din session er udløbet, log ind igen."
1051
+ };
985
1052
  var daJson = {
986
1053
  STEPS: STEPS$e,
987
1054
  INPUT: INPUT$e,
@@ -1002,7 +1069,8 @@ var daJson = {
1002
1069
  QSM: QSM$f,
1003
1070
  SRP: SRP$e,
1004
1071
  ITINERARY: ITINERARY$e,
1005
- FORM: FORM$e
1072
+ FORM: FORM$e,
1073
+ AGENT_ENTRIES: AGENT_ENTRIES$e
1006
1074
  };
1007
1075
 
1008
1076
  var STEPS$d = {
@@ -1455,6 +1523,39 @@ var FORM$d = {
1455
1523
  YES: "Ja",
1456
1524
  NO: "Nein"
1457
1525
  };
1526
+ var AGENT_ENTRIES$d = {
1527
+ TITLE: "Buchungen",
1528
+ MY_BOOKINGS: "Meine Buchungen",
1529
+ NUMBER: "Nummer",
1530
+ DEPARTURE_DATE: "Abreisedatum",
1531
+ STATUS: "Status",
1532
+ CUSTOM_STATUS: "Benutzerdefinierter Status",
1533
+ RETURN_DATE: "Rückreisedatum",
1534
+ PROFIT: "Gewinn",
1535
+ NETTO_SELLING_PRICE: "Netto-Verkaufspreis",
1536
+ YOUR_SURCHARGE: "Ihr Aufschlag",
1537
+ CREATED: "Erstellt",
1538
+ CONTACT: "Kontakt",
1539
+ MAIN_BOOKER: "Hauptbucher",
1540
+ PRODUCT: "Produkt",
1541
+ TRAVELERS: "Reisende",
1542
+ ACTIONS: "Aktionen",
1543
+ DETAILS: "Details",
1544
+ HIDE_DETAILS: "Details ausblenden",
1545
+ PRINTS: "Drucke",
1546
+ ALL: "Alle",
1547
+ X_ITEMS: "{0} Einträge",
1548
+ PAGE_SIZE: "Einträge pro Seite",
1549
+ PREVIOUS: "Zurück",
1550
+ NEXT: "Weiter",
1551
+ PAGE_X_OF_Y: "Seite {0} von {1}",
1552
+ LOADING: "Wird geladen...",
1553
+ NO_ITEMS: "Keine Buchungen gefunden.",
1554
+ ERROR: "Beim Laden Ihrer Buchungen ist ein Fehler aufgetreten.",
1555
+ PRINT_ERROR: "Drucken fehlgeschlagen, bitte versuchen Sie es erneut.",
1556
+ NOT_LOGGED_IN: "Melden Sie sich als Agent an, um Ihre Buchungen zu sehen.",
1557
+ SESSION_EXPIRED: "Ihre Sitzung ist abgelaufen, bitte melden Sie sich erneut an."
1558
+ };
1458
1559
  var deJson = {
1459
1560
  STEPS: STEPS$d,
1460
1561
  INPUT: INPUT$d,
@@ -1475,7 +1576,8 @@ var deJson = {
1475
1576
  QSM: QSM$e,
1476
1577
  SRP: SRP$d,
1477
1578
  ITINERARY: ITINERARY$d,
1478
- FORM: FORM$d
1579
+ FORM: FORM$d,
1580
+ AGENT_ENTRIES: AGENT_ENTRIES$d
1479
1581
  };
1480
1582
 
1481
1583
  var STEPS$c = {
@@ -1932,6 +2034,39 @@ var FORM$c = {
1932
2034
  YES: "Yes",
1933
2035
  NO: "No"
1934
2036
  };
2037
+ var AGENT_ENTRIES$c = {
2038
+ TITLE: "Bookings",
2039
+ MY_BOOKINGS: "My bookings",
2040
+ NUMBER: "Number",
2041
+ DEPARTURE_DATE: "Departure date",
2042
+ STATUS: "Status",
2043
+ CUSTOM_STATUS: "Custom status",
2044
+ RETURN_DATE: "Return date",
2045
+ PROFIT: "Profit",
2046
+ NETTO_SELLING_PRICE: "Netto selling price",
2047
+ YOUR_SURCHARGE: "Your surcharge",
2048
+ CREATED: "Created",
2049
+ CONTACT: "Contact",
2050
+ MAIN_BOOKER: "Main booker",
2051
+ PRODUCT: "Product",
2052
+ TRAVELERS: "Travellers",
2053
+ ACTIONS: "Actions",
2054
+ DETAILS: "Details",
2055
+ HIDE_DETAILS: "Hide details",
2056
+ PRINTS: "Prints",
2057
+ ALL: "All",
2058
+ X_ITEMS: "{0} items",
2059
+ PAGE_SIZE: "Items per page",
2060
+ PREVIOUS: "Previous",
2061
+ NEXT: "Next",
2062
+ PAGE_X_OF_Y: "Page {0} of {1}",
2063
+ LOADING: "Loading...",
2064
+ NO_ITEMS: "No bookings found.",
2065
+ ERROR: "Something went wrong while loading your bookings.",
2066
+ PRINT_ERROR: "Printing failed, please try again.",
2067
+ NOT_LOGGED_IN: "Log in as an agent to see your bookings.",
2068
+ SESSION_EXPIRED: "Your session has expired, please log in again."
2069
+ };
1935
2070
  var enJson = {
1936
2071
  STEPS: STEPS$c,
1937
2072
  INPUT: INPUT$c,
@@ -1952,7 +2087,8 @@ var enJson = {
1952
2087
  QSM: QSM$d,
1953
2088
  SRP: SRP$c,
1954
2089
  ITINERARY: ITINERARY$c,
1955
- FORM: FORM$c
2090
+ FORM: FORM$c,
2091
+ AGENT_ENTRIES: AGENT_ENTRIES$c
1956
2092
  };
1957
2093
 
1958
2094
  var STEPS$b = {
@@ -2405,6 +2541,39 @@ var FORM$b = {
2405
2541
  YES: "Sí",
2406
2542
  NO: "No"
2407
2543
  };
2544
+ var AGENT_ENTRIES$b = {
2545
+ TITLE: "Reservas",
2546
+ MY_BOOKINGS: "Mis reservas",
2547
+ NUMBER: "Número",
2548
+ DEPARTURE_DATE: "Fecha de salida",
2549
+ STATUS: "Estado",
2550
+ CUSTOM_STATUS: "Estado personalizado",
2551
+ RETURN_DATE: "Fecha de regreso",
2552
+ PROFIT: "Beneficio",
2553
+ NETTO_SELLING_PRICE: "Precio de venta neto",
2554
+ YOUR_SURCHARGE: "Su recargo",
2555
+ CREATED: "Creado",
2556
+ CONTACT: "Contacto",
2557
+ MAIN_BOOKER: "Titular de la reserva",
2558
+ PRODUCT: "Producto",
2559
+ TRAVELERS: "Viajeros",
2560
+ ACTIONS: "Acciones",
2561
+ DETAILS: "Detalles",
2562
+ HIDE_DETAILS: "Ocultar detalles",
2563
+ PRINTS: "Impresiones",
2564
+ ALL: "Todos",
2565
+ X_ITEMS: "{0} elementos",
2566
+ PAGE_SIZE: "Elementos por página",
2567
+ PREVIOUS: "Anterior",
2568
+ NEXT: "Siguiente",
2569
+ PAGE_X_OF_Y: "Página {0} de {1}",
2570
+ LOADING: "Cargando...",
2571
+ NO_ITEMS: "No se encontraron reservas.",
2572
+ ERROR: "Se produjo un error al cargar sus reservas.",
2573
+ PRINT_ERROR: "La impresión ha fallado, inténtelo de nuevo.",
2574
+ NOT_LOGGED_IN: "Inicie sesión como agente para ver sus reservas.",
2575
+ SESSION_EXPIRED: "Su sesión ha caducado, inicie sesión de nuevo."
2576
+ };
2408
2577
  var esJson = {
2409
2578
  STEPS: STEPS$b,
2410
2579
  INPUT: INPUT$b,
@@ -2425,7 +2594,8 @@ var esJson = {
2425
2594
  QSM: QSM$c,
2426
2595
  SRP: SRP$b,
2427
2596
  ITINERARY: ITINERARY$b,
2428
- FORM: FORM$b
2597
+ FORM: FORM$b,
2598
+ AGENT_ENTRIES: AGENT_ENTRIES$b
2429
2599
  };
2430
2600
 
2431
2601
  var STEPS$a = {
@@ -2882,6 +3052,39 @@ var FORM$a = {
2882
3052
  YES: "Oui",
2883
3053
  NO: "Non"
2884
3054
  };
3055
+ var AGENT_ENTRIES$a = {
3056
+ TITLE: "Réservations",
3057
+ MY_BOOKINGS: "Mes réservations",
3058
+ NUMBER: "Numéro",
3059
+ DEPARTURE_DATE: "Date de départ",
3060
+ STATUS: "Statut",
3061
+ CUSTOM_STATUS: "Statut personnalisé",
3062
+ RETURN_DATE: "Date de retour",
3063
+ PROFIT: "Bénéfice",
3064
+ NETTO_SELLING_PRICE: "Prix de vente net",
3065
+ YOUR_SURCHARGE: "Votre supplément",
3066
+ CREATED: "Créé le",
3067
+ CONTACT: "Contact",
3068
+ MAIN_BOOKER: "Réservant principal",
3069
+ PRODUCT: "Produit",
3070
+ TRAVELERS: "Voyageurs",
3071
+ ACTIONS: "Actions",
3072
+ DETAILS: "Détails",
3073
+ HIDE_DETAILS: "Masquer les détails",
3074
+ PRINTS: "Impressions",
3075
+ ALL: "Tous",
3076
+ X_ITEMS: "{0} éléments",
3077
+ PAGE_SIZE: "Éléments par page",
3078
+ PREVIOUS: "Précédent",
3079
+ NEXT: "Suivant",
3080
+ PAGE_X_OF_Y: "Page {0} sur {1}",
3081
+ LOADING: "Chargement...",
3082
+ NO_ITEMS: "Aucune réservation trouvée.",
3083
+ ERROR: "Une erreur est survenue lors du chargement de vos réservations.",
3084
+ PRINT_ERROR: "L'impression a échoué, veuillez réessayer.",
3085
+ NOT_LOGGED_IN: "Connectez-vous en tant qu'agent pour voir vos réservations.",
3086
+ SESSION_EXPIRED: "Votre session a expiré, veuillez vous reconnecter."
3087
+ };
2885
3088
  var frBeJson = {
2886
3089
  STEPS: STEPS$a,
2887
3090
  INPUT: INPUT$a,
@@ -2902,7 +3105,8 @@ var frBeJson = {
2902
3105
  QSM: QSM$b,
2903
3106
  SRP: SRP$a,
2904
3107
  ITINERARY: ITINERARY$a,
2905
- FORM: FORM$a
3108
+ FORM: FORM$a,
3109
+ AGENT_ENTRIES: AGENT_ENTRIES$a
2906
3110
  };
2907
3111
 
2908
3112
  var STEPS$9 = {
@@ -3355,6 +3559,39 @@ var FORM$9 = {
3355
3559
  YES: "Oui",
3356
3560
  NO: "Non"
3357
3561
  };
3562
+ var AGENT_ENTRIES$9 = {
3563
+ TITLE: "Réservations",
3564
+ MY_BOOKINGS: "Mes réservations",
3565
+ NUMBER: "Numéro",
3566
+ DEPARTURE_DATE: "Date de départ",
3567
+ STATUS: "Statut",
3568
+ CUSTOM_STATUS: "Statut personnalisé",
3569
+ RETURN_DATE: "Date de retour",
3570
+ PROFIT: "Bénéfice",
3571
+ NETTO_SELLING_PRICE: "Prix de vente net",
3572
+ YOUR_SURCHARGE: "Votre supplément",
3573
+ CREATED: "Créé le",
3574
+ CONTACT: "Contact",
3575
+ MAIN_BOOKER: "Réservant principal",
3576
+ PRODUCT: "Produit",
3577
+ TRAVELERS: "Voyageurs",
3578
+ ACTIONS: "Actions",
3579
+ DETAILS: "Détails",
3580
+ HIDE_DETAILS: "Masquer les détails",
3581
+ PRINTS: "Impressions",
3582
+ ALL: "Tous",
3583
+ X_ITEMS: "{0} éléments",
3584
+ PAGE_SIZE: "Éléments par page",
3585
+ PREVIOUS: "Précédent",
3586
+ NEXT: "Suivant",
3587
+ PAGE_X_OF_Y: "Page {0} sur {1}",
3588
+ LOADING: "Chargement...",
3589
+ NO_ITEMS: "Aucune réservation trouvée.",
3590
+ ERROR: "Une erreur est survenue lors du chargement de vos réservations.",
3591
+ PRINT_ERROR: "L'impression a échoué, veuillez réessayer.",
3592
+ NOT_LOGGED_IN: "Connectez-vous en tant qu'agent pour voir vos réservations.",
3593
+ SESSION_EXPIRED: "Votre session a expiré, veuillez vous reconnecter."
3594
+ };
3358
3595
  var frFrJson = {
3359
3596
  STEPS: STEPS$9,
3360
3597
  INPUT: INPUT$9,
@@ -3375,7 +3612,8 @@ var frFrJson = {
3375
3612
  QSM: QSM$a,
3376
3613
  SRP: SRP$9,
3377
3614
  ITINERARY: ITINERARY$9,
3378
- FORM: FORM$9
3615
+ FORM: FORM$9,
3616
+ AGENT_ENTRIES: AGENT_ENTRIES$9
3379
3617
  };
3380
3618
 
3381
3619
  var STEPS$8 = {
@@ -3828,6 +4066,39 @@ var FORM$8 = {
3828
4066
  YES: "Já",
3829
4067
  NO: "Nei"
3830
4068
  };
4069
+ var AGENT_ENTRIES$8 = {
4070
+ TITLE: "Bókanir",
4071
+ MY_BOOKINGS: "Mínar bókanir",
4072
+ NUMBER: "Númer",
4073
+ DEPARTURE_DATE: "Brottfarardagur",
4074
+ STATUS: "Staða",
4075
+ CUSTOM_STATUS: "Sérsniðin staða",
4076
+ RETURN_DATE: "Heimkomudagur",
4077
+ PROFIT: "Hagnaður",
4078
+ NETTO_SELLING_PRICE: "Nettó söluverð",
4079
+ YOUR_SURCHARGE: "Þitt álag",
4080
+ CREATED: "Stofnað",
4081
+ CONTACT: "Tengiliður",
4082
+ MAIN_BOOKER: "Aðalbókandi",
4083
+ PRODUCT: "Vara",
4084
+ TRAVELERS: "Ferðalangar",
4085
+ ACTIONS: "Aðgerðir",
4086
+ DETAILS: "Nánar",
4087
+ HIDE_DETAILS: "Fela nánar",
4088
+ PRINTS: "Útprentanir",
4089
+ ALL: "Allt",
4090
+ X_ITEMS: "{0} atriði",
4091
+ PAGE_SIZE: "Atriði á síðu",
4092
+ PREVIOUS: "Fyrri",
4093
+ NEXT: "Næsta",
4094
+ PAGE_X_OF_Y: "Síða {0} af {1}",
4095
+ LOADING: "Hleður...",
4096
+ NO_ITEMS: "Engar bókanir fundust.",
4097
+ ERROR: "Eitthvað fór úrskeiðis við að hlaða bókunum þínum.",
4098
+ PRINT_ERROR: "Prentun mistókst, reyndu aftur.",
4099
+ NOT_LOGGED_IN: "Skráðu þig inn sem umboðsaðili til að sjá bókanir þínar.",
4100
+ SESSION_EXPIRED: "Lotan þín er útrunnin, skráðu þig inn aftur."
4101
+ };
3831
4102
  var isJson = {
3832
4103
  STEPS: STEPS$8,
3833
4104
  INPUT: INPUT$8,
@@ -3848,7 +4119,8 @@ var isJson = {
3848
4119
  QSM: QSM$9,
3849
4120
  SRP: SRP$8,
3850
4121
  ITINERARY: ITINERARY$8,
3851
- FORM: FORM$8
4122
+ FORM: FORM$8,
4123
+ AGENT_ENTRIES: AGENT_ENTRIES$8
3852
4124
  };
3853
4125
 
3854
4126
  var STEPS$7 = {
@@ -4301,6 +4573,39 @@ var FORM$7 = {
4301
4573
  YES: "Sì",
4302
4574
  NO: "No"
4303
4575
  };
4576
+ var AGENT_ENTRIES$7 = {
4577
+ TITLE: "Prenotazioni",
4578
+ MY_BOOKINGS: "Le mie prenotazioni",
4579
+ NUMBER: "Numero",
4580
+ DEPARTURE_DATE: "Data di partenza",
4581
+ STATUS: "Stato",
4582
+ CUSTOM_STATUS: "Stato personalizzato",
4583
+ RETURN_DATE: "Data di ritorno",
4584
+ PROFIT: "Profitto",
4585
+ NETTO_SELLING_PRICE: "Prezzo di vendita netto",
4586
+ YOUR_SURCHARGE: "Il tuo supplemento",
4587
+ CREATED: "Creato",
4588
+ CONTACT: "Contatto",
4589
+ MAIN_BOOKER: "Prenotante principale",
4590
+ PRODUCT: "Prodotto",
4591
+ TRAVELERS: "Viaggiatori",
4592
+ ACTIONS: "Azioni",
4593
+ DETAILS: "Dettagli",
4594
+ HIDE_DETAILS: "Nascondi dettagli",
4595
+ PRINTS: "Stampe",
4596
+ ALL: "Tutti",
4597
+ X_ITEMS: "{0} elementi",
4598
+ PAGE_SIZE: "Elementi per pagina",
4599
+ PREVIOUS: "Precedente",
4600
+ NEXT: "Successivo",
4601
+ PAGE_X_OF_Y: "Pagina {0} di {1}",
4602
+ LOADING: "Caricamento...",
4603
+ NO_ITEMS: "Nessuna prenotazione trovata.",
4604
+ ERROR: "Si è verificato un errore durante il caricamento delle prenotazioni.",
4605
+ PRINT_ERROR: "Stampa non riuscita, riprova.",
4606
+ NOT_LOGGED_IN: "Accedi come agente per vedere le tue prenotazioni.",
4607
+ SESSION_EXPIRED: "La sessione è scaduta, accedi di nuovo."
4608
+ };
4304
4609
  var itJson = {
4305
4610
  STEPS: STEPS$7,
4306
4611
  INPUT: INPUT$7,
@@ -4321,7 +4626,8 @@ var itJson = {
4321
4626
  QSM: QSM$8,
4322
4627
  SRP: SRP$7,
4323
4628
  ITINERARY: ITINERARY$7,
4324
- FORM: FORM$7
4629
+ FORM: FORM$7,
4630
+ AGENT_ENTRIES: AGENT_ENTRIES$7
4325
4631
  };
4326
4632
 
4327
4633
  var STEPS$6 = {
@@ -4778,6 +5084,39 @@ var FORM$6 = {
4778
5084
  YES: "Ja",
4779
5085
  NO: "Nee"
4780
5086
  };
5087
+ var AGENT_ENTRIES$6 = {
5088
+ TITLE: "Boekingen",
5089
+ MY_BOOKINGS: "Mijn boekingen",
5090
+ NUMBER: "Nummer",
5091
+ DEPARTURE_DATE: "Vertrekdatum",
5092
+ STATUS: "Status",
5093
+ CUSTOM_STATUS: "Aangepaste status",
5094
+ RETURN_DATE: "Terugkeerdatum",
5095
+ PROFIT: "Winst",
5096
+ NETTO_SELLING_PRICE: "Netto verkoopprijs",
5097
+ YOUR_SURCHARGE: "Jouw toeslag",
5098
+ CREATED: "Aangemaakt",
5099
+ CONTACT: "Contact",
5100
+ MAIN_BOOKER: "Hoofdboeker",
5101
+ PRODUCT: "Product",
5102
+ TRAVELERS: "Reizigers",
5103
+ ACTIONS: "Acties",
5104
+ DETAILS: "Details",
5105
+ HIDE_DETAILS: "Details verbergen",
5106
+ PRINTS: "Afdrukken",
5107
+ ALL: "Alle",
5108
+ X_ITEMS: "{0} items",
5109
+ PAGE_SIZE: "Items per pagina",
5110
+ PREVIOUS: "Vorige",
5111
+ NEXT: "Volgende",
5112
+ PAGE_X_OF_Y: "Pagina {0} van {1}",
5113
+ LOADING: "Laden...",
5114
+ NO_ITEMS: "Geen boekingen gevonden.",
5115
+ ERROR: "Er ging iets mis bij het laden van je boekingen.",
5116
+ PRINT_ERROR: "Afdrukken mislukt, probeer het opnieuw.",
5117
+ NOT_LOGGED_IN: "Log in als agent om je boekingen te zien.",
5118
+ SESSION_EXPIRED: "Je sessie is verlopen, log opnieuw in."
5119
+ };
4781
5120
  var nlBeJson = {
4782
5121
  STEPS: STEPS$6,
4783
5122
  INPUT: INPUT$6,
@@ -4798,7 +5137,8 @@ var nlBeJson = {
4798
5137
  QSM: QSM$7,
4799
5138
  SRP: SRP$6,
4800
5139
  ITINERARY: ITINERARY$6,
4801
- FORM: FORM$6
5140
+ FORM: FORM$6,
5141
+ AGENT_ENTRIES: AGENT_ENTRIES$6
4802
5142
  };
4803
5143
 
4804
5144
  var STEPS$5 = {
@@ -5251,6 +5591,39 @@ var FORM$5 = {
5251
5591
  YES: "Ja",
5252
5592
  NO: "Nee"
5253
5593
  };
5594
+ var AGENT_ENTRIES$5 = {
5595
+ TITLE: "Boekingen",
5596
+ MY_BOOKINGS: "Mijn boekingen",
5597
+ NUMBER: "Nummer",
5598
+ DEPARTURE_DATE: "Vertrekdatum",
5599
+ STATUS: "Status",
5600
+ CUSTOM_STATUS: "Aangepaste status",
5601
+ RETURN_DATE: "Terugkeerdatum",
5602
+ PROFIT: "Winst",
5603
+ NETTO_SELLING_PRICE: "Netto verkoopprijs",
5604
+ YOUR_SURCHARGE: "Jouw toeslag",
5605
+ CREATED: "Aangemaakt",
5606
+ CONTACT: "Contact",
5607
+ MAIN_BOOKER: "Hoofdboeker",
5608
+ PRODUCT: "Product",
5609
+ TRAVELERS: "Reizigers",
5610
+ ACTIONS: "Acties",
5611
+ DETAILS: "Details",
5612
+ HIDE_DETAILS: "Details verbergen",
5613
+ PRINTS: "Afdrukken",
5614
+ ALL: "Alle",
5615
+ X_ITEMS: "{0} items",
5616
+ PAGE_SIZE: "Items per pagina",
5617
+ PREVIOUS: "Vorige",
5618
+ NEXT: "Volgende",
5619
+ PAGE_X_OF_Y: "Pagina {0} van {1}",
5620
+ LOADING: "Laden...",
5621
+ NO_ITEMS: "Geen boekingen gevonden.",
5622
+ ERROR: "Er ging iets mis bij het laden van je boekingen.",
5623
+ PRINT_ERROR: "Afdrukken mislukt, probeer het opnieuw.",
5624
+ NOT_LOGGED_IN: "Log in als agent om je boekingen te zien.",
5625
+ SESSION_EXPIRED: "Je sessie is verlopen, log opnieuw in."
5626
+ };
5254
5627
  var nlNlJson = {
5255
5628
  STEPS: STEPS$5,
5256
5629
  INPUT: INPUT$5,
@@ -5271,7 +5644,8 @@ var nlNlJson = {
5271
5644
  QSM: QSM$6,
5272
5645
  SRP: SRP$5,
5273
5646
  ITINERARY: ITINERARY$5,
5274
- FORM: FORM$5
5647
+ FORM: FORM$5,
5648
+ AGENT_ENTRIES: AGENT_ENTRIES$5
5275
5649
  };
5276
5650
 
5277
5651
  var STEPS$4 = {
@@ -5724,6 +6098,39 @@ var FORM$4 = {
5724
6098
  YES: "Ja",
5725
6099
  NO: "Nei"
5726
6100
  };
6101
+ var AGENT_ENTRIES$4 = {
6102
+ TITLE: "Bestillinger",
6103
+ MY_BOOKINGS: "Mine bestillinger",
6104
+ NUMBER: "Nummer",
6105
+ DEPARTURE_DATE: "Avreisedato",
6106
+ STATUS: "Status",
6107
+ CUSTOM_STATUS: "Egendefinert status",
6108
+ RETURN_DATE: "Returdato",
6109
+ PROFIT: "Fortjeneste",
6110
+ NETTO_SELLING_PRICE: "Netto salgspris",
6111
+ YOUR_SURCHARGE: "Ditt tillegg",
6112
+ CREATED: "Opprettet",
6113
+ CONTACT: "Kontakt",
6114
+ MAIN_BOOKER: "Hovedbestiller",
6115
+ PRODUCT: "Produkt",
6116
+ TRAVELERS: "Reisende",
6117
+ ACTIONS: "Handlinger",
6118
+ DETAILS: "Detaljer",
6119
+ HIDE_DETAILS: "Skjul detaljer",
6120
+ PRINTS: "Utskrifter",
6121
+ ALL: "Alle",
6122
+ X_ITEMS: "{0} elementer",
6123
+ PAGE_SIZE: "Elementer per side",
6124
+ PREVIOUS: "Forrige",
6125
+ NEXT: "Neste",
6126
+ PAGE_X_OF_Y: "Side {0} av {1}",
6127
+ LOADING: "Laster...",
6128
+ NO_ITEMS: "Ingen bestillinger funnet.",
6129
+ ERROR: "Noe gikk galt under lasting av bestillingene dine.",
6130
+ PRINT_ERROR: "Utskrift mislyktes, prøv igjen.",
6131
+ NOT_LOGGED_IN: "Logg inn som agent for å se bestillingene dine.",
6132
+ SESSION_EXPIRED: "Økten din er utløpt, logg inn på nytt."
6133
+ };
5727
6134
  var noJson = {
5728
6135
  STEPS: STEPS$4,
5729
6136
  INPUT: INPUT$4,
@@ -5744,7 +6151,8 @@ var noJson = {
5744
6151
  QSM: QSM$5,
5745
6152
  SRP: SRP$4,
5746
6153
  ITINERARY: ITINERARY$4,
5747
- FORM: FORM$4
6154
+ FORM: FORM$4,
6155
+ AGENT_ENTRIES: AGENT_ENTRIES$4
5748
6156
  };
5749
6157
 
5750
6158
  var STEPS$3 = {
@@ -6197,6 +6605,39 @@ var FORM$3 = {
6197
6605
  YES: "Tak",
6198
6606
  NO: "Nie"
6199
6607
  };
6608
+ var AGENT_ENTRIES$3 = {
6609
+ TITLE: "Rezerwacje",
6610
+ MY_BOOKINGS: "Moje rezerwacje",
6611
+ NUMBER: "Numer",
6612
+ DEPARTURE_DATE: "Data wyjazdu",
6613
+ STATUS: "Status",
6614
+ CUSTOM_STATUS: "Status niestandardowy",
6615
+ RETURN_DATE: "Data powrotu",
6616
+ PROFIT: "Zysk",
6617
+ NETTO_SELLING_PRICE: "Cena sprzedaży netto",
6618
+ YOUR_SURCHARGE: "Twoja dopłata",
6619
+ CREATED: "Utworzono",
6620
+ CONTACT: "Kontakt",
6621
+ MAIN_BOOKER: "Główny rezerwujący",
6622
+ PRODUCT: "Produkt",
6623
+ TRAVELERS: "Podróżni",
6624
+ ACTIONS: "Akcje",
6625
+ DETAILS: "Szczegóły",
6626
+ HIDE_DETAILS: "Ukryj szczegóły",
6627
+ PRINTS: "Wydruki",
6628
+ ALL: "Wszystkie",
6629
+ X_ITEMS: "{0} pozycji",
6630
+ PAGE_SIZE: "Pozycji na stronę",
6631
+ PREVIOUS: "Poprzednia",
6632
+ NEXT: "Następna",
6633
+ PAGE_X_OF_Y: "Strona {0} z {1}",
6634
+ LOADING: "Ładowanie...",
6635
+ NO_ITEMS: "Nie znaleziono rezerwacji.",
6636
+ ERROR: "Wystąpił błąd podczas ładowania rezerwacji.",
6637
+ PRINT_ERROR: "Drukowanie nie powiodło się, spróbuj ponownie.",
6638
+ NOT_LOGGED_IN: "Zaloguj się jako agent, aby zobaczyć swoje rezerwacje.",
6639
+ SESSION_EXPIRED: "Twoja sesja wygasła, zaloguj się ponownie."
6640
+ };
6200
6641
  var plJson = {
6201
6642
  STEPS: STEPS$3,
6202
6643
  INPUT: INPUT$3,
@@ -6217,7 +6658,8 @@ var plJson = {
6217
6658
  QSM: QSM$4,
6218
6659
  SRP: SRP$3,
6219
6660
  ITINERARY: ITINERARY$3,
6220
- FORM: FORM$3
6661
+ FORM: FORM$3,
6662
+ AGENT_ENTRIES: AGENT_ENTRIES$3
6221
6663
  };
6222
6664
 
6223
6665
  var STEPS$2 = {
@@ -6670,6 +7112,39 @@ var FORM$2 = {
6670
7112
  YES: "Sim",
6671
7113
  NO: "Não"
6672
7114
  };
7115
+ var AGENT_ENTRIES$2 = {
7116
+ TITLE: "Reservas",
7117
+ MY_BOOKINGS: "As minhas reservas",
7118
+ NUMBER: "Número",
7119
+ DEPARTURE_DATE: "Data de partida",
7120
+ STATUS: "Estado",
7121
+ CUSTOM_STATUS: "Estado personalizado",
7122
+ RETURN_DATE: "Data de regresso",
7123
+ PROFIT: "Lucro",
7124
+ NETTO_SELLING_PRICE: "Preço de venda líquido",
7125
+ YOUR_SURCHARGE: "A sua sobretaxa",
7126
+ CREATED: "Criado",
7127
+ CONTACT: "Contacto",
7128
+ MAIN_BOOKER: "Titular da reserva",
7129
+ PRODUCT: "Produto",
7130
+ TRAVELERS: "Viajantes",
7131
+ ACTIONS: "Ações",
7132
+ DETAILS: "Detalhes",
7133
+ HIDE_DETAILS: "Ocultar detalhes",
7134
+ PRINTS: "Impressões",
7135
+ ALL: "Todos",
7136
+ X_ITEMS: "{0} itens",
7137
+ PAGE_SIZE: "Itens por página",
7138
+ PREVIOUS: "Anterior",
7139
+ NEXT: "Seguinte",
7140
+ PAGE_X_OF_Y: "Página {0} de {1}",
7141
+ LOADING: "A carregar...",
7142
+ NO_ITEMS: "Nenhuma reserva encontrada.",
7143
+ ERROR: "Ocorreu um erro ao carregar as suas reservas.",
7144
+ PRINT_ERROR: "A impressão falhou, tente novamente.",
7145
+ NOT_LOGGED_IN: "Inicie sessão como agente para ver as suas reservas.",
7146
+ SESSION_EXPIRED: "A sua sessão expirou, inicie sessão novamente."
7147
+ };
6673
7148
  var ptJson = {
6674
7149
  STEPS: STEPS$2,
6675
7150
  INPUT: INPUT$2,
@@ -6690,7 +7165,8 @@ var ptJson = {
6690
7165
  QSM: QSM$3,
6691
7166
  SRP: SRP$2,
6692
7167
  ITINERARY: ITINERARY$2,
6693
- FORM: FORM$2
7168
+ FORM: FORM$2,
7169
+ AGENT_ENTRIES: AGENT_ENTRIES$2
6694
7170
  };
6695
7171
 
6696
7172
  var STEPS$1 = {
@@ -7143,6 +7619,39 @@ var FORM$1 = {
7143
7619
  YES: "Ja",
7144
7620
  NO: "Nej"
7145
7621
  };
7622
+ var AGENT_ENTRIES$1 = {
7623
+ TITLE: "Bokningar",
7624
+ MY_BOOKINGS: "Mina bokningar",
7625
+ NUMBER: "Nummer",
7626
+ DEPARTURE_DATE: "Avresedatum",
7627
+ STATUS: "Status",
7628
+ CUSTOM_STATUS: "Anpassad status",
7629
+ RETURN_DATE: "Returdatum",
7630
+ PROFIT: "Vinst",
7631
+ NETTO_SELLING_PRICE: "Nettoförsäljningspris",
7632
+ YOUR_SURCHARGE: "Ditt tillägg",
7633
+ CREATED: "Skapad",
7634
+ CONTACT: "Kontakt",
7635
+ MAIN_BOOKER: "Huvudbokare",
7636
+ PRODUCT: "Produkt",
7637
+ TRAVELERS: "Resenärer",
7638
+ ACTIONS: "Åtgärder",
7639
+ DETAILS: "Detaljer",
7640
+ HIDE_DETAILS: "Dölj detaljer",
7641
+ PRINTS: "Utskrifter",
7642
+ ALL: "Alla",
7643
+ X_ITEMS: "{0} objekt",
7644
+ PAGE_SIZE: "Objekt per sida",
7645
+ PREVIOUS: "Föregående",
7646
+ NEXT: "Nästa",
7647
+ PAGE_X_OF_Y: "Sida {0} av {1}",
7648
+ LOADING: "Laddar...",
7649
+ NO_ITEMS: "Inga bokningar hittades.",
7650
+ ERROR: "Något gick fel när dina bokningar laddades.",
7651
+ PRINT_ERROR: "Utskriften misslyckades, försök igen.",
7652
+ NOT_LOGGED_IN: "Logga in som agent för att se dina bokningar.",
7653
+ SESSION_EXPIRED: "Din session har gått ut, logga in igen."
7654
+ };
7146
7655
  var svJson = {
7147
7656
  STEPS: STEPS$1,
7148
7657
  INPUT: INPUT$1,
@@ -7163,7 +7672,8 @@ var svJson = {
7163
7672
  QSM: QSM$2,
7164
7673
  SRP: SRP$1,
7165
7674
  ITINERARY: ITINERARY$1,
7166
- FORM: FORM$1
7675
+ FORM: FORM$1,
7676
+ AGENT_ENTRIES: AGENT_ENTRIES$1
7167
7677
  };
7168
7678
 
7169
7679
  var STEPS = {
@@ -7616,6 +8126,39 @@ var FORM = {
7616
8126
  YES: "はい",
7617
8127
  NO: "いいえ"
7618
8128
  };
8129
+ var AGENT_ENTRIES = {
8130
+ TITLE: "予約",
8131
+ MY_BOOKINGS: "マイ予約",
8132
+ NUMBER: "番号",
8133
+ DEPARTURE_DATE: "出発日",
8134
+ STATUS: "ステータス",
8135
+ CUSTOM_STATUS: "カスタムステータス",
8136
+ RETURN_DATE: "帰着日",
8137
+ PROFIT: "利益",
8138
+ NETTO_SELLING_PRICE: "正味販売価格",
8139
+ YOUR_SURCHARGE: "手数料",
8140
+ CREATED: "作成日",
8141
+ CONTACT: "連絡先",
8142
+ MAIN_BOOKER: "代表予約者",
8143
+ PRODUCT: "商品",
8144
+ TRAVELERS: "旅行者",
8145
+ ACTIONS: "操作",
8146
+ DETAILS: "詳細",
8147
+ HIDE_DETAILS: "詳細を隠す",
8148
+ PRINTS: "印刷",
8149
+ ALL: "すべて",
8150
+ X_ITEMS: "{0} 件",
8151
+ PAGE_SIZE: "1ページあたりの件数",
8152
+ PREVIOUS: "前へ",
8153
+ NEXT: "次へ",
8154
+ PAGE_X_OF_Y: "{0} / {1} ページ",
8155
+ LOADING: "読み込み中...",
8156
+ NO_ITEMS: "予約が見つかりません。",
8157
+ ERROR: "予約の読み込み中にエラーが発生しました。",
8158
+ PRINT_ERROR: "印刷に失敗しました。もう一度お試しください。",
8159
+ NOT_LOGGED_IN: "予約を表示するにはエージェントとしてログインしてください。",
8160
+ SESSION_EXPIRED: "セッションの有効期限が切れました。再度ログインしてください。"
8161
+ };
7619
8162
  var jaJson = {
7620
8163
  STEPS: STEPS,
7621
8164
  INPUT: INPUT,
@@ -7636,7 +8179,8 @@ var jaJson = {
7636
8179
  QSM: QSM$1,
7637
8180
  SRP: SRP,
7638
8181
  ITINERARY: ITINERARY,
7639
- FORM: FORM
8182
+ FORM: FORM,
8183
+ AGENT_ENTRIES: AGENT_ENTRIES
7640
8184
  };
7641
8185
 
7642
8186
  exports.DepartureRange = void 0;
@@ -15589,6 +16133,7 @@ var ENDPOINT$1 = "/api/web/packaging";
15589
16133
  var ENDPOINT_START_TRANSACTION = ENDPOINT$1 + "/start";
15590
16134
  var ENDPOINT_ACCOMMODATIONS = ENDPOINT$1 + "/accommodations";
15591
16135
  var ENDPOINT_EXCURSIONS = ENDPOINT$1 + "/excursions";
16136
+ var ENDPOINT_TRANSFERS = ENDPOINT$1 + "/transfers";
15592
16137
  var ENDPOINT_FLIGHTS = ENDPOINT$1 + "/flights";
15593
16138
  var ENDPOINT_PRICE_DETAILS = ENDPOINT$1 + "/price-details";
15594
16139
  var ENDPOINT_BOOK = ENDPOINT$1 + "/book";
@@ -15621,6 +16166,12 @@ var searchPackagingExcursions = function (config, request, signal) {
15621
16166
  var body = JSON.stringify(request);
15622
16167
  return post(url, apiKey, body, config.token, signal, true);
15623
16168
  };
16169
+ var searchPackagingTransfers = function (config, request, signal) {
16170
+ var url = "" + config.host + ENDPOINT_TRANSFERS;
16171
+ var apiKey = config.apiKey;
16172
+ var body = JSON.stringify(request);
16173
+ return post(url, apiKey, body, config.token, signal, true);
16174
+ };
15624
16175
  var getEntry = function (config, magicLinkCode, signal) {
15625
16176
  var apiKey = config.apiKey;
15626
16177
  var url = "" + config.host + ENDPOINT_ENTRY(magicLinkCode);
@@ -15798,6 +16349,7 @@ exports.searchOords = searchOords;
15798
16349
  exports.searchPackagingAccommodations = searchPackagingAccommodations;
15799
16350
  exports.searchPackagingExcursions = searchPackagingExcursions;
15800
16351
  exports.searchPackagingFlights = searchPackagingFlights;
16352
+ exports.searchPackagingTransfers = searchPackagingTransfers;
15801
16353
  exports.searchRegions = searchRegions;
15802
16354
  exports.searchWithErrorMapping = searchWithErrorMapping;
15803
16355
  exports.sendContactForm = sendContactForm;
@@ -19290,10 +19842,30 @@ function formatBirthDate$1(birthDate) {
19290
19842
  // A field can have separate "main-booker"/other-pax variants sharing the same identity
19291
19843
  // (customFieldConfigurationId for custom fields, fieldName for built-in fields).
19292
19844
  const MAIN_BOOKER_GROUP = 'main-booker';
19845
+ const MAIN_BOOKER_FIELD_PREFIX = 'mainBooker';
19293
19846
  const isCustomPaxField = (field) => field.customFieldConfigurationId != null;
19847
+ // Tide names the built-in main-booker fields with a prefix ('mainBookerGender', 'mainBookerCountryId', ...),
19848
+ // the other-pax ones without ('gender', 'countryId'). Strip it so both are variants of the same field.
19849
+ function normalizeBuiltInFieldName(field) {
19850
+ if (isCustomPaxField(field) || !field.fieldName?.startsWith(MAIN_BOOKER_FIELD_PREFIX))
19851
+ return field;
19852
+ const stripped = field.fieldName.slice(MAIN_BOOKER_FIELD_PREFIX.length);
19853
+ if (!stripped)
19854
+ return field;
19855
+ return { ...field, fieldName: stripped.charAt(0).toLowerCase() + stripped.slice(1) };
19856
+ }
19857
+ // Once Tide sends built-in fields, that configuration decides which built-in fields are shown/required;
19858
+ // the hardcoded formFields / core defaults are only the fallback for when it doesn't.
19859
+ function hasConfiguredBuiltInPaxFields(paxFields = []) {
19860
+ return paxFields.some((f) => !isCustomPaxField(f));
19861
+ }
19862
+ // The main booker's address/contact details are then asked on the main booker's own traveler block.
19863
+ function hasConfiguredMainBookerFields(paxFields = []) {
19864
+ return paxFields.some((f) => !isCustomPaxField(f) && f.group === MAIN_BOOKER_GROUP);
19865
+ }
19294
19866
  function resolveApplicablePaxFields(fields, isMainBooker) {
19295
19867
  const variantsByKey = new Map();
19296
- fields.forEach((field) => {
19868
+ fields.map(normalizeBuiltInFieldName).forEach((field) => {
19297
19869
  const key = field.customFieldConfigurationId ?? field.fieldName;
19298
19870
  const variants = variantsByKey.get(key) ?? [];
19299
19871
  variants.push(field);
@@ -19355,11 +19927,50 @@ const BUILT_IN_FIELD_PATHS = {
19355
19927
  // The 4 fields that always render/validate regardless of paxFields config (fallback behavior).
19356
19928
  const CORE_FIELD_NAMES = new Set(['gender', 'firstName', 'lastName', 'dateOfBirth']);
19357
19929
  const ADDRESS_FIELD_NAMES = ['street', 'location', 'countryId', 'postalCode', 'number'];
19930
+ // Built-in fields have no dataType from Tide; their control type and label follow from the fieldName.
19931
+ // gender, hasInsurance, countryId, weight and height have a dedicated control and only need a label here.
19932
+ function getBuiltInFieldControlMeta(translations) {
19933
+ return {
19934
+ gender: { label: translations.TRAVELERS_FORM.GENDER_ID },
19935
+ firstName: { label: translations.TRAVELERS_FORM.FIRST_NAME },
19936
+ lastName: { label: translations.TRAVELERS_FORM.LAST_NAME },
19937
+ dateOfBirth: { type: 'date', label: translations.TRAVELERS_FORM.BIRTHDATE },
19938
+ nickname: { label: translations.TRAVELERS_FORM.NICKNAME },
19939
+ birthplace: { label: translations.TRAVELERS_FORM.BIRTHPLACE },
19940
+ nationality: { label: translations.TRAVELERS_FORM.NATIONALITY },
19941
+ preferredLanguageId: { type: 'number', label: translations.TRAVELERS_FORM.PREFERRED_LANGUAGE },
19942
+ email: { type: 'email', label: translations.TRAVELERS_FORM.TRAVELER_EMAIL },
19943
+ phone: { type: 'tel', label: translations.TRAVELERS_FORM.TRAVELER_PHONE },
19944
+ mobile: { type: 'tel', label: translations.TRAVELERS_FORM.TRAVELER_MOBILE },
19945
+ passportNumber: { label: translations.TRAVELERS_FORM.PASSPORT_NUMBER },
19946
+ passportIssueDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_ISSUE_DATE },
19947
+ passportIssuedLocation: { label: translations.TRAVELERS_FORM.PASSPORT_ISSUED_LOCATION },
19948
+ passportExpiryDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_EXPIRY_DATE },
19949
+ emergencyNumber: { type: 'tel', label: translations.TRAVELERS_FORM.EMERGENCY_NUMBER },
19950
+ hasInsurance: { label: translations.TRAVELERS_FORM.HAS_INSURANCE },
19951
+ insuranceName: { label: translations.TRAVELERS_FORM.INSURANCE_NAME },
19952
+ info: { label: translations.TRAVELERS_FORM.INFO },
19953
+ weight: { label: translations.TRAVELERS_FORM.WEIGHT },
19954
+ height: { label: translations.TRAVELERS_FORM.HEIGHT },
19955
+ street: { label: translations.TRAVELERS_FORM.STREET },
19956
+ location: { label: translations.TRAVELERS_FORM.CITY },
19957
+ countryId: { label: translations.TRAVELERS_FORM.COUNTRY },
19958
+ postalCode: { label: translations.TRAVELERS_FORM.ZIPCODE },
19959
+ number: { label: translations.TRAVELERS_FORM.HOUSE_NUMBER }
19960
+ };
19961
+ }
19962
+ // The form's gender radio values ('m'/'f'/'x') <-> Tide's Gender enum.
19963
+ const GENDER_BY_FORM_VALUE = { m: build.Gender.male, f: build.Gender.female, x: build.Gender.other };
19964
+ function formValueFromGender(gender) {
19965
+ return Object.keys(GENDER_BY_FORM_VALUE).find((key) => GENDER_BY_FORM_VALUE[key] === gender) ?? '';
19966
+ }
19358
19967
  // Shared by buildPax (new-booking) and applyTravelersFormValuesToEditablePackagingEntry
19359
19968
  // (edit-booking), now that PackagingEntryPax and BookingPackagePax have the same shape.
19360
19969
  function applyTravelerToPax(pax, traveler, mainBookerId) {
19361
19970
  return {
19362
19971
  ...pax,
19972
+ // Unanswered (optional) gender keeps whatever the pax already had.
19973
+ gender: GENDER_BY_FORM_VALUE[traveler.gender] ?? pax.gender,
19363
19974
  firstName: traveler.firstName ?? '',
19364
19975
  lastName: traveler.lastName ?? '',
19365
19976
  dateOfBirth: traveler.birthDate || null,
@@ -19519,7 +20130,13 @@ function mapPackagingEntryPaxToTraveler(roomTraveler) {
19519
20130
  customFields: roomTraveler.customFields ?? []
19520
20131
  };
19521
20132
  }
19522
- function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId) {
20133
+ // Keeps the values already on the entry's pax and adds an empty slot for every configured custom field it lacks,
20134
+ // so the form renders/validates the same set as createTraveler does for a new booking.
20135
+ function mergeCustomFields(existing = [], paxFields) {
20136
+ const missing = buildEmptyCustomFields(paxFields).filter((empty) => !existing.some((c) => c.customFieldConfigurationId === empty.customFieldConfigurationId));
20137
+ return [...existing, ...missing];
20138
+ }
20139
+ function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, agentAdressId, paxFields = editablePackagingEntry?.paxFields ?? []) {
19523
20140
  const pax = editablePackagingEntry?.pax ?? [];
19524
20141
  const rooms = editablePackagingEntry.rooms.map((room) => {
19525
20142
  const roomPax = pax.filter((x) => room.paxIds.includes(x.id));
@@ -19532,8 +20149,9 @@ function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, a
19532
20149
  firstName: roomTraveler.firstName ?? '',
19533
20150
  lastName: roomTraveler.lastName ?? '',
19534
20151
  birthDate: roomTraveler.dateOfBirth ? dateFns.format(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
19535
- gender: '',
19536
- ...mapPackagingEntryPaxToTraveler(roomTraveler)
20152
+ gender: formValueFromGender(roomTraveler.gender),
20153
+ ...mapPackagingEntryPaxToTraveler(roomTraveler),
20154
+ customFields: mergeCustomFields(roomTraveler.customFields, paxFields)
19537
20155
  };
19538
20156
  }),
19539
20157
  children: children.map((roomTraveler) => {
@@ -19542,9 +20160,10 @@ function createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, a
19542
20160
  firstName: roomTraveler.firstName ?? '',
19543
20161
  lastName: roomTraveler.lastName ?? '',
19544
20162
  birthDate: roomTraveler.dateOfBirth ? dateFns.format(new Date(roomTraveler.dateOfBirth), 'yyyy-MM-dd') : '',
19545
- gender: '',
20163
+ gender: formValueFromGender(roomTraveler.gender),
19546
20164
  isBaby: isBabyAge(roomTraveler.age),
19547
- ...mapPackagingEntryPaxToTraveler(roomTraveler)
20165
+ ...mapPackagingEntryPaxToTraveler(roomTraveler),
20166
+ customFields: mergeCustomFields(roomTraveler.customFields, paxFields)
19548
20167
  };
19549
20168
  })
19550
20169
  };
@@ -19569,7 +20188,8 @@ function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry
19569
20188
  const travelers = values.rooms.flatMap((room) => [...room.adults, ...room.children]);
19570
20189
  // The backend treats the main booker's per-pax address as authoritative, so keep the
19571
20190
  // booking-level address in sync with it rather than sending two independent values.
19572
- const mainBookerAddress = travelers.find((x) => x.id === values.mainBookerId)?.address;
20191
+ const mainBookerTraveler = travelers.find((x) => x.id === values.mainBookerId);
20192
+ const mainBookerAddress = mainBookerTraveler?.address;
19573
20193
  return {
19574
20194
  ...editablePackagingEntry,
19575
20195
  pax: (editablePackagingEntry.pax ?? []).map((pax) => {
@@ -19585,8 +20205,9 @@ function applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry
19585
20205
  place: mainBookerAddress?.location || values.place,
19586
20206
  country: mainBookerAddress?.country || values.country,
19587
20207
  travelAgentId: values.travelAgentId,
19588
- phone: values.phone,
19589
- email: values.email
20208
+ // When Tide configures the main-booker fields, contact details live on the main booker's traveler block.
20209
+ phone: values.phone || mainBookerTraveler?.mobile || mainBookerTraveler?.phone,
20210
+ email: values.email || mainBookerTraveler?.email
19590
20211
  }
19591
20212
  };
19592
20213
  }
@@ -19743,30 +20364,7 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19743
20364
  return (React__default["default"].createElement("div", { key: field.customFieldConfigurationId, style: { gridColumn: `span ${field.col || 12}` } }, getCustomFieldControl(field, value, name)));
19744
20365
  })));
19745
20366
  };
19746
- // Fields with a dedicated control (gender, hasInsurance, countryId) aren't listed here.
19747
- const BUILT_IN_FIELD_CONTROL_META = {
19748
- firstName: { label: translations.TRAVELERS_FORM.FIRST_NAME },
19749
- lastName: { label: translations.TRAVELERS_FORM.LAST_NAME },
19750
- dateOfBirth: { type: 'date', label: translations.TRAVELERS_FORM.BIRTHDATE },
19751
- nickname: { label: translations.TRAVELERS_FORM.NICKNAME },
19752
- birthplace: { label: translations.TRAVELERS_FORM.BIRTHPLACE },
19753
- nationality: { label: translations.TRAVELERS_FORM.NATIONALITY },
19754
- preferredLanguageId: { type: 'number', label: translations.TRAVELERS_FORM.PREFERRED_LANGUAGE },
19755
- email: { type: 'email', label: translations.TRAVELERS_FORM.TRAVELER_EMAIL },
19756
- phone: { label: translations.TRAVELERS_FORM.TRAVELER_PHONE },
19757
- mobile: { label: translations.TRAVELERS_FORM.TRAVELER_MOBILE },
19758
- passportNumber: { label: translations.TRAVELERS_FORM.PASSPORT_NUMBER },
19759
- passportIssueDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_ISSUE_DATE },
19760
- passportIssuedLocation: { label: translations.TRAVELERS_FORM.PASSPORT_ISSUED_LOCATION },
19761
- passportExpiryDate: { type: 'date', label: translations.TRAVELERS_FORM.PASSPORT_EXPIRY_DATE },
19762
- emergencyNumber: { label: translations.TRAVELERS_FORM.EMERGENCY_NUMBER },
19763
- insuranceName: { label: translations.TRAVELERS_FORM.INSURANCE_NAME },
19764
- info: { label: translations.TRAVELERS_FORM.INFO },
19765
- street: { label: translations.TRAVELERS_FORM.STREET },
19766
- location: { label: translations.TRAVELERS_FORM.CITY },
19767
- postalCode: { label: translations.TRAVELERS_FORM.ZIPCODE },
19768
- number: { label: translations.TRAVELERS_FORM.HOUSE_NUMBER }
19769
- };
20367
+ const BUILT_IN_FIELD_CONTROL_META = getBuiltInFieldControlMeta(translations);
19770
20368
  const renderBuiltInFieldControl = (fieldName, isRequired, travelerValues, namePrefix) => {
19771
20369
  const path = BUILT_IN_FIELD_PATHS[fieldName] ?? fieldName;
19772
20370
  const name = `${namePrefix}.${path}`;
@@ -19801,7 +20399,7 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19801
20399
  const resolveBuiltInField = (fieldName, travelerValues) => {
19802
20400
  const isMainBooker = travelerValues.id === formik.values.mainBookerId;
19803
20401
  const configured = getBuiltInPaxField(paxFields, fieldName, isMainBooker);
19804
- const fallback = CORE_FIELD_DEFAULTS[fieldName];
20402
+ const fallback = hasConfiguredBuiltInPaxFields(paxFields) ? undefined : CORE_FIELD_DEFAULTS[fieldName];
19805
20403
  if (!configured && !fallback)
19806
20404
  return undefined;
19807
20405
  return { isRequired: configured?.isRequired ?? fallback.isRequired, col: configured?.col ?? fallback.col };
@@ -19813,7 +20411,14 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19813
20411
  return (React__default["default"].createElement("div", { key: fieldName, style: { gridColumn: `span ${resolved.col || 12}` } }, renderBuiltInFieldControl(fieldName, resolved.isRequired, travelerValues, namePrefix)));
19814
20412
  };
19815
20413
  const renderTravelerAddressFields = (travelerValues, namePrefix) => {
19816
- const fields = ADDRESS_FIELD_NAMES.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix)).filter(Boolean);
20414
+ const isMainBooker = travelerValues.id === formik.values.mainBookerId;
20415
+ // Configured order when Tide sends one, so the configured col widths line up as intended.
20416
+ const fieldNames = hasConfiguredBuiltInPaxFields(paxFields)
20417
+ ? getApplicableBuiltInPaxFields(paxFields, isMainBooker)
20418
+ .map((field) => field.fieldName)
20419
+ .filter((fieldName) => ADDRESS_FIELD_NAMES.includes(fieldName))
20420
+ : ADDRESS_FIELD_NAMES;
20421
+ const fields = fieldNames.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix)).filter(Boolean);
19817
20422
  if (!fields.length)
19818
20423
  return null;
19819
20424
  return React__default["default"].createElement("div", { className: "travelers-form__custom-fields-grid" }, fields);
@@ -19856,15 +20461,18 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19856
20461
  return (React__default["default"].createElement("div", { className: "form__row" },
19857
20462
  React__default["default"].createElement(LabeledInput, { hasError: hasVisibleError(`${namePrefix}.age`), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.AGE, required: true, name: `${namePrefix}.age`, onChange: formik.handleChange, onBlur: formik.handleBlur, value: travelerValues.age })));
19858
20463
  }
19859
- // 'birthDate' (the legacy formFields type string) is normalized to the paxFields catalog's
19860
- // 'dateOfBirth' fieldName for config lookups.
19861
- const baseFieldNames = (travellersSettings?.formFields?.length ? travellersSettings.formFields.map((field) => field.type) : ['gender', 'firstName', 'lastName', 'dateOfBirth']).map((fieldName) => (fieldName === 'birthDate' ? 'dateOfBirth' : fieldName));
19862
20464
  const isMainBooker = travelerValues.id === formik.values.mainBookerId;
19863
- const extraFieldNames = getApplicableBuiltInPaxFields(paxFields, isMainBooker)
19864
- .map((field) => field.fieldName)
19865
- .filter((fieldName) => !baseFieldNames.includes(fieldName) && !ADDRESS_FIELD_NAMES.includes(fieldName));
20465
+ // With a Tide field configuration, exactly the configured fields render, in their configured order.
20466
+ // Without one, fall back to formFields ('birthDate', the legacy type string, maps to 'dateOfBirth').
20467
+ const fieldNames = hasConfiguredBuiltInPaxFields(paxFields)
20468
+ ? getApplicableBuiltInPaxFields(paxFields, isMainBooker)
20469
+ .map((field) => field.fieldName)
20470
+ .filter((fieldName) => !ADDRESS_FIELD_NAMES.includes(fieldName))
20471
+ : (travellersSettings?.formFields?.length
20472
+ ? travellersSettings.formFields.map((field) => field.type)
20473
+ : ['gender', 'firstName', 'lastName', 'dateOfBirth']).map((fieldName) => (fieldName === 'birthDate' ? 'dateOfBirth' : fieldName));
19866
20474
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
19867
- React__default["default"].createElement("div", { className: "travelers-form__custom-fields-grid" }, [...baseFieldNames, ...extraFieldNames].map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix))),
20475
+ React__default["default"].createElement("div", { className: "travelers-form__custom-fields-grid" }, fieldNames.map((fieldName) => renderBuiltInField(fieldName, travelerValues, namePrefix))),
19868
20476
  renderTravelerAddressFields(travelerValues, namePrefix),
19869
20477
  renderCustomFields(travelerValues, namePrefix),
19870
20478
  travelersFirstStep && isAdult && formik.values.rooms[roomIndex].adults.length > 1 && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleRemoveTraveler(roomIndex, travelerIndex) }, translations.TRAVELERS_FORM.REMOVE_TRAVELER))));
@@ -19902,7 +20510,7 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19902
20510
  renderTravelerFields(travelerValues, `rooms[${roomIndex}].children[${index}]`, false, roomIndex, index)))),
19903
20511
  !useCompactForm && travelersFirstStep && (React__default["default"].createElement("div", { className: "form__region" },
19904
20512
  React__default["default"].createElement("button", { type: "button", className: "cta cta--select", onClick: () => handleAddTraveler(roomIndex) }, translations.TRAVELERS_FORM.ADD_TRAVELER)))))),
19905
- !useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default["default"].createElement("div", { className: "form__region" },
20513
+ useCompactForm || hasConfiguredMainBookerFields(paxFields) ? null : bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length ? (React__default["default"].createElement("div", { className: "form__region" },
19906
20514
  React__default["default"].createElement("div", { className: "form__region-header" },
19907
20515
  React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
19908
20516
  React__default["default"].createElement("p", { className: "form__region-label" }, lodash.compact([lodash.compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
@@ -19921,9 +20529,9 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
19921
20529
  React__default["default"].createElement("div", { className: "form__row" },
19922
20530
  React__default["default"].createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone }),
19923
20531
  React__default["default"].createElement(LabeledInput, { type: "email", hasError: hasVisibleError('email'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.EMAIL, required: true, name: "email", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.email }),
19924
- React__default["default"].createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })))))) : !useCompactForm ? (React__default["default"].createElement("div", { className: "form__region" },
20532
+ React__default["default"].createElement(LabeledInput, { type: "email", hasError: hasVisibleError('emailConfirmation'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.REPEAT_EMAIL, required: true, name: "emailConfirmation", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.emailConfirmation })))))) : (React__default["default"].createElement("div", { className: "form__region" },
19925
20533
  React__default["default"].createElement("div", { className: "form__row" },
19926
- React__default["default"].createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone })))) : null,
20534
+ React__default["default"].createElement(LabeledInput, { hasError: hasVisibleError('phone'), extraClassName: "form__group--md-33", label: translations.TRAVELERS_FORM.PHONE, required: true, name: "phone", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.phone })))),
19927
20535
  !useCompactForm && showAgentSelection && (React__default["default"].createElement("div", { className: "form__region" },
19928
20536
  React__default["default"].createElement("div", { className: "form__region-header" },
19929
20537
  React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.BOOK_WITH_AGENT),
@@ -20534,8 +21142,9 @@ const selectBookingPackagePax = toolkit.createSelector(selectTravelersFormValues
20534
21142
  formValues?.rooms.forEach((r) => r.adults.forEach((x) => {
20535
21143
  const adultPax = buildPax(x, formValues?.mainBookerId);
20536
21144
  if (adultPax.isMainBooker) {
20537
- adultPax.mobilePhone = formValues?.phone;
20538
- adultPax.email = formValues?.email;
21145
+ // Without the main booker block (Tide configures main-booker fields), keep the traveler's own details.
21146
+ adultPax.mobilePhone = formValues?.phone || adultPax.mobilePhone;
21147
+ adultPax.email = formValues?.email || adultPax.email;
20539
21148
  }
20540
21149
  pax.push(adultPax);
20541
21150
  }));
@@ -20559,8 +21168,8 @@ const selectBookingAddress = toolkit.createSelector(selectTravelersFormValues, s
20559
21168
  postalCode: mainBookerAddress?.postalCode || formValues?.zipCode,
20560
21169
  location: mainBookerAddress?.location || formValues?.place,
20561
21170
  country: mainBookerAddress?.country || formValues?.country,
20562
- mobilePhone: formValues?.phone,
20563
- email: formValues?.email
21171
+ mobilePhone: mainBooker.mobilePhone,
21172
+ email: mainBooker.email
20564
21173
  };
20565
21174
  });
20566
21175
  const selectSubFormAnswers = (state) => state.booking.subFormAnswers;
@@ -25697,6 +26306,10 @@ const Summary = () => {
25697
26306
  React__default["default"].createElement("button", { title: settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING, className: buildClassName(['cta', !userValidated && 'cta--disabled']), disabled: !userValidated, name: "default" }, settings.isOffer ? translations.STEPS.SUBMIT_OFFER : translations.STEPS.SUBMIT_BOOKING))))));
25698
26307
  };
25699
26308
 
26309
+ // lodash isEmpty is true for every number, which would flag a filled-in preferredLanguageId as missing.
26310
+ function isBlank(value) {
26311
+ return value === null || value === undefined || (typeof value === 'string' && value.trim() === '');
26312
+ }
25700
26313
  function isValidEmail(email) {
25701
26314
  return !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,24}$/i.test(email);
25702
26315
  }
@@ -25720,9 +26333,14 @@ function getAge(birthDateText, startDateText) {
25720
26333
  }
25721
26334
  const validateForm = (values, agentRequired, bookingType, translations, formFields, mainBookerFormFields, maxChildAge = CHILD_MAX_AGE, maxBabyAge = BABY_MAX_AGE, paxFields = []) => {
25722
26335
  const errors = {};
26336
+ const usesFieldConfiguration = hasConfiguredBuiltInPaxFields(paxFields);
26337
+ const builtInFieldMeta = getBuiltInFieldControlMeta(translations);
25723
26338
  const isFormFieldPresent = (type) => {
25724
26339
  return formFields?.some((f) => f.type === type) ?? true;
25725
26340
  };
26341
+ // The 4 core fields: with a Tide field configuration they're required only when configured so for the
26342
+ // traveler's role (main booker / other pax); without one, whenever formFields lists them (legacy behavior).
26343
+ const isCoreFieldRequired = (traveler, legacyType, fieldName = legacyType) => usesFieldConfiguration ? !!getBuiltInPaxField(paxFields, fieldName, traveler.id === values.mainBookerId)?.isRequired : isFormFieldPresent(legacyType);
25726
26344
  const isMainBookerFormFieldPresent = (type) => {
25727
26345
  return mainBookerFormFields?.some((f) => f.type === type) ?? true;
25728
26346
  };
@@ -25774,16 +26392,16 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25774
26392
  const fieldPath = BUILT_IN_FIELD_PATHS[field.fieldName];
25775
26393
  if (!fieldPath)
25776
26394
  return;
25777
- if (lodash.isEmpty(lodash.get(traveler, fieldPath))) {
25778
- lodash.set(errors, `${path}.${fieldPath}`, formatTravelerField(room, pax, field.fieldName));
26395
+ if (isBlank(lodash.get(traveler, fieldPath))) {
26396
+ lodash.set(errors, `${path}.${fieldPath}`, formatTravelerField(room, pax, builtInFieldMeta[field.fieldName]?.label ?? field.fieldName));
25779
26397
  }
25780
26398
  });
25781
26399
  };
25782
26400
  values.rooms.forEach((r, rIndex) => r.adults.forEach((adult, index) => {
25783
- if (lodash.isEmpty(adult.gender) && isFormFieldPresent('gender')) {
26401
+ if (lodash.isEmpty(adult.gender) && isCoreFieldRequired(adult, 'gender')) {
25784
26402
  lodash.set(errors, `rooms[${rIndex}].adults[${index}].gender`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.GENDER));
25785
26403
  }
25786
- if (isFormFieldPresent('firstName')) {
26404
+ if (isCoreFieldRequired(adult, 'firstName') || !lodash.isEmpty(adult.firstName)) {
25787
26405
  if (lodash.isEmpty(adult.firstName)) {
25788
26406
  lodash.set(errors, `rooms[${rIndex}].adults[${index}].firstName`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
25789
26407
  }
@@ -25791,7 +26409,7 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25791
26409
  lodash.set(errors, `rooms[${rIndex}].adults[${index}].firstName`, formatTravelerFieldInvalidCharacters(rIndex + 1, index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
25792
26410
  }
25793
26411
  }
25794
- if (isFormFieldPresent('lastName')) {
26412
+ if (isCoreFieldRequired(adult, 'lastName') || !lodash.isEmpty(adult.lastName)) {
25795
26413
  if (lodash.isEmpty(adult.lastName)) {
25796
26414
  lodash.set(errors, `rooms[${rIndex}].adults[${index}].lastName`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.LAST_NAME));
25797
26415
  }
@@ -25799,7 +26417,7 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25799
26417
  lodash.set(errors, `rooms[${rIndex}].adults[${index}].lastName`, formatTravelerFieldInvalidCharacters(rIndex + 1, index + 1, translations.TRAVELERS_FORM.LAST_NAME));
25800
26418
  }
25801
26419
  }
25802
- if (isFormFieldPresent('birthDate')) {
26420
+ if (isCoreFieldRequired(adult, 'birthDate', 'dateOfBirth') || !lodash.isEmpty(adult.birthDate)) {
25803
26421
  if (lodash.isEmpty(adult.birthDate) || !isValidBirthDate(adult.birthDate)) {
25804
26422
  lodash.set(errors, `rooms[${rIndex}].adults[${index}].birthDate`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
25805
26423
  }
@@ -25815,10 +26433,10 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25815
26433
  validateRequiredBuiltInFields(adult, `rooms[${rIndex}].adults[${index}]`, rIndex + 1, index + 1);
25816
26434
  }));
25817
26435
  values.rooms.forEach((r, rIndex) => r.children.forEach((child, index) => {
25818
- if (lodash.isEmpty(child.gender) && isFormFieldPresent('gender')) {
26436
+ if (lodash.isEmpty(child.gender) && isCoreFieldRequired(child, 'gender')) {
25819
26437
  lodash.set(errors, `rooms[${rIndex}].children[${index}].gender`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.GENDER));
25820
26438
  }
25821
- if (isFormFieldPresent('firstName')) {
26439
+ if (isCoreFieldRequired(child, 'firstName') || !lodash.isEmpty(child.firstName)) {
25822
26440
  if (lodash.isEmpty(child.firstName)) {
25823
26441
  lodash.set(errors, `rooms[${rIndex}].children[${index}].firstName`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
25824
26442
  }
@@ -25826,7 +26444,7 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25826
26444
  lodash.set(errors, `rooms[${rIndex}].children[${index}].firstName`, formatTravelerFieldInvalidCharacters(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.FIRST_NAME));
25827
26445
  }
25828
26446
  }
25829
- if (isFormFieldPresent('lastName')) {
26447
+ if (isCoreFieldRequired(child, 'lastName') || !lodash.isEmpty(child.lastName)) {
25830
26448
  if (lodash.isEmpty(child.lastName)) {
25831
26449
  lodash.set(errors, `rooms[${rIndex}].children[${index}].lastName`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.LAST_NAME));
25832
26450
  }
@@ -25834,7 +26452,7 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25834
26452
  lodash.set(errors, `rooms[${rIndex}].children[${index}].lastName`, formatTravelerFieldInvalidCharacters(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.LAST_NAME));
25835
26453
  }
25836
26454
  }
25837
- if (isFormFieldPresent('birthDate')) {
26455
+ if (isCoreFieldRequired(child, 'birthDate', 'dateOfBirth') || !lodash.isEmpty(child.birthDate)) {
25838
26456
  if (lodash.isEmpty(child.birthDate) || !isValidBirthDate(child.birthDate)) {
25839
26457
  lodash.set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
25840
26458
  }
@@ -25860,7 +26478,8 @@ const validateForm = (values, agentRequired, bookingType, translations, formFiel
25860
26478
  if (values.mainBookerId < 0) {
25861
26479
  errors.mainBookerId = translations.TRAVELERS_FORM.VALIDATION.NO_MAIN_BOOKER_SELECTED;
25862
26480
  }
25863
- if (bookingType != 'b2b' || mainBookerFormFields?.length) {
26481
+ if (hasConfiguredMainBookerFields(paxFields)) ;
26482
+ else if (bookingType != 'b2b' || mainBookerFormFields?.length) {
25864
26483
  if (lodash.isEmpty(values.street) && isMainBookerFormFieldPresent('street')) {
25865
26484
  errors.street = format$1(translations.TRAVELERS_FORM.VALIDATION.MAIN_BOOKER_FIELD, [translations.TRAVELERS_FORM.STREET]);
25866
26485
  }
@@ -26555,7 +27174,7 @@ const LanguageSwitcher = ({ value = 'EN', languages = DEFAULT_LANGUAGES, onChang
26555
27174
  React__default["default"].createElement("span", { className: "nav__subnav__languages__option__label" }, l.label)))))));
26556
27175
  };
26557
27176
 
26558
- const Navbar = ({ currentPath, logo, onLogoClick, topLinks, items, language, languages, onLanguageChange, onSearch, member, onLogin, onLogout }) => {
27177
+ const Navbar = ({ currentPath, logo, onLogoClick, topLinks, items, language, languages, onLanguageChange, onSearch, member, onLogin, onLogout, onMyBookings }) => {
26559
27178
  const [menuOpen, setMenuOpen] = React.useState(false);
26560
27179
  const [query, setQuery] = React.useState('');
26561
27180
  const [activeMobileGroup, setActiveMobileGroup] = React.useState();
@@ -26649,6 +27268,12 @@ const Navbar = ({ currentPath, logo, onLogoClick, topLinks, items, language, lan
26649
27268
  onLogout();
26650
27269
  }
26651
27270
  };
27271
+ const handleMyBookings = (event) => {
27272
+ event.preventDefault();
27273
+ if (onMyBookings) {
27274
+ onMyBookings();
27275
+ }
27276
+ };
26652
27277
  const handleLogin = (event) => {
26653
27278
  event.preventDefault();
26654
27279
  if (onLogin) {
@@ -26662,7 +27287,9 @@ const Navbar = ({ currentPath, logo, onLogoClick, topLinks, items, language, lan
26662
27287
  member && (React__default["default"].createElement("span", { className: "nav__subnav__member" },
26663
27288
  translations.LOGIN.WELCOME_X,
26664
27289
  member.name)),
26665
- member ? (React__default["default"].createElement(React__default["default"].Fragment, null, onLogout && (React__default["default"].createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleLogout }, translations.LOGIN.LOGOUT)))) : (React__default["default"].createElement(React__default["default"].Fragment, null, onLogin && (React__default["default"].createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleLogin }, translations.LOGIN.LOGIN)))),
27290
+ member ? (React__default["default"].createElement(React__default["default"].Fragment, null,
27291
+ onMyBookings && (React__default["default"].createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleMyBookings }, translations.AGENT_ENTRIES.MY_BOOKINGS)),
27292
+ onLogout && (React__default["default"].createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleLogout }, translations.LOGIN.LOGOUT)))) : (React__default["default"].createElement(React__default["default"].Fragment, null, onLogin && (React__default["default"].createElement("a", { href: "#", className: "nav__subnav__link", onClick: handleLogin }, translations.LOGIN.LOGIN)))),
26666
27293
  React__default["default"].createElement(LanguageSwitcher, { value: language.code, languages: languages, onChange: (lang) => {
26667
27294
  console.log('Selected language:', lang);
26668
27295
  onLanguageChange(lang);
@@ -28631,6 +29258,7 @@ const initialState$1 = {
28631
29258
  bookingNumber: undefined,
28632
29259
  trajectNodeAvailability: {},
28633
29260
  trajectFlightAvailability: {},
29261
+ trajectTransferAvailability: {},
28634
29262
  trajectDaySuggestions: {},
28635
29263
  trajectEditLineGuid: null,
28636
29264
  trajectActivitiesDayOrder: null,
@@ -28843,6 +29471,12 @@ const searchResultsSlice = toolkit.createSlice({
28843
29471
  node.selectedCode = code;
28844
29472
  node.status = 'resolved';
28845
29473
  },
29474
+ clearTrajectNodeSelection(state, action) {
29475
+ const node = state.trajectNodeAvailability[action.payload];
29476
+ if (!node)
29477
+ return;
29478
+ node.selectedCode = null;
29479
+ },
28846
29480
  updateEditableEntryLine(state, action) {
28847
29481
  if (!state.editablePackagingEntry)
28848
29482
  return;
@@ -28856,6 +29490,32 @@ const searchResultsSlice = toolkit.createSlice({
28856
29490
  return;
28857
29491
  state.editablePackagingEntry.lines = [...(state.editablePackagingEntry.lines ?? []), ...action.payload];
28858
29492
  },
29493
+ upsertEditableEntryLines(state, action) {
29494
+ if (!state.editablePackagingEntry)
29495
+ return;
29496
+ const lines = [...(state.editablePackagingEntry.lines ?? [])];
29497
+ action.payload.forEach((line) => {
29498
+ const index = lines.findIndex((x) => x.guid === line.guid);
29499
+ if (index === -1)
29500
+ lines.push(line);
29501
+ else
29502
+ lines[index] = line;
29503
+ });
29504
+ state.editablePackagingEntry.lines = lines;
29505
+ const restored = new Set(action.payload.map((line) => line.trajectNodeId).filter((x) => x != null));
29506
+ if (restored.size && state.editablePackagingEntry.removedTrajectNodeIds?.length) {
29507
+ state.editablePackagingEntry.removedTrajectNodeIds = state.editablePackagingEntry.removedTrajectNodeIds.filter((x) => !restored.has(x));
29508
+ }
29509
+ },
29510
+ removeTrajectNode(state, action) {
29511
+ if (!state.editablePackagingEntry)
29512
+ return;
29513
+ const guids = new Set(action.payload.lineGuids);
29514
+ state.editablePackagingEntry.lines = (state.editablePackagingEntry.lines ?? []).filter((x) => !guids.has(x.guid));
29515
+ const removed = state.editablePackagingEntry.removedTrajectNodeIds ?? [];
29516
+ if (!removed.includes(action.payload.nodeId))
29517
+ state.editablePackagingEntry.removedTrajectNodeIds = [...removed, action.payload.nodeId];
29518
+ },
28859
29519
  removeEditableEntryLines(state, action) {
28860
29520
  if (!state.editablePackagingEntry)
28861
29521
  return;
@@ -28887,6 +29547,19 @@ const searchResultsSlice = toolkit.createSlice({
28887
29547
  flight.selectedGuid = action.payload.guid;
28888
29548
  flight.status = 'resolved';
28889
29549
  },
29550
+ clearTrajectFlightSelection(state, action) {
29551
+ const flight = state.trajectFlightAvailability[action.payload];
29552
+ if (!flight)
29553
+ return;
29554
+ flight.selectedGuid = null;
29555
+ },
29556
+ setTrajectTransferLoading(state, action) {
29557
+ state.trajectTransferAvailability[action.payload] = { nodeId: action.payload, status: 'loading', result: null };
29558
+ },
29559
+ setTrajectTransferAvailability(state, action) {
29560
+ const { nodeId, result } = action.payload;
29561
+ state.trajectTransferAvailability[nodeId] = { nodeId, status: result ? 'resolved' : 'unavailable', result };
29562
+ },
28890
29563
  setTrajectDaySuggestionsLoading(state, action) {
28891
29564
  const dayOrder = action.payload;
28892
29565
  state.trajectDaySuggestions[dayOrder] = {
@@ -28923,6 +29596,7 @@ const searchResultsSlice = toolkit.createSlice({
28923
29596
  resetTrajectAvailability(state) {
28924
29597
  state.trajectNodeAvailability = {};
28925
29598
  state.trajectFlightAvailability = {};
29599
+ state.trajectTransferAvailability = {};
28926
29600
  state.trajectDaySuggestions = {};
28927
29601
  state.trajectEditLineGuid = null;
28928
29602
  state.trajectActivitiesDayOrder = null;
@@ -28931,7 +29605,7 @@ const searchResultsSlice = toolkit.createSlice({
28931
29605
  }
28932
29606
  }
28933
29607
  });
28934
- 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;
29608
+ 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;
28935
29609
  var searchResultsReducer = searchResultsSlice.reducer;
28936
29610
 
28937
29611
  const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
@@ -29146,7 +29820,7 @@ const numberOfNights = (segment) => {
29146
29820
  const CHARTER_SERVICE_TYPE = 10;
29147
29821
  const CRUISE_SERVICE_TYPE = 11;
29148
29822
  const FERRY_SERVICE_TYPE = 12;
29149
- const TRANSFER_SERVICE_TYPE = 13;
29823
+ const TRANSFER_SERVICE_TYPE$1 = 13;
29150
29824
  const BUS_SERVICE_TYPE = 14;
29151
29825
  const CAR_SERVICE_TYPE = 17;
29152
29826
  const CAMPER_SERVICE_TYPE = 18;
@@ -29178,7 +29852,7 @@ const getServiceTypeIcon = (serviceType) => {
29178
29852
  return 'ui-bus';
29179
29853
  case TRAIN_SERVICE_TYPE:
29180
29854
  return 'ui-train';
29181
- case TRANSFER_SERVICE_TYPE:
29855
+ case TRANSFER_SERVICE_TYPE$1:
29182
29856
  return 'ui-transfer';
29183
29857
  case EVENT_SERVICE_TYPE:
29184
29858
  return 'ui-ticket';
@@ -29314,6 +29988,81 @@ const getTrajectNodesWithLines = (trajectEntry) => {
29314
29988
  })
29315
29989
  .filter((x) => !!x.line);
29316
29990
  };
29991
+ // Qite.Offer.Enums.ServiceType.Transfer: a traject's connecting node is booked as one.
29992
+ const TRANSFER_SERVICE_TYPE = 13;
29993
+ // Qite.Offer.Enums.RequirementType. A Mandatory (0) stop, and one RequiredInGroup (3) — one of the node's
29994
+ // alternatives has to be booked — always keep a selection; only these two may be taken off the trip.
29995
+ const OPTIONAL_REQUIREMENT_TYPE = 1;
29996
+ const OPTIONAL_IN_GROUP_REQUIREMENT_TYPE = 2;
29997
+ const canRemoveTrajectNode = (node) => node.requirementType === OPTIONAL_REQUIREMENT_TYPE || node.requirementType === OPTIONAL_IN_GROUP_REQUIREMENT_TYPE;
29998
+ const getDroppedTrajectNodeIds = (trajectEntry, entry) => {
29999
+ const dropped = new Set();
30000
+ if (!entry || !!trajectEntry.entry.magicLink)
30001
+ return dropped;
30002
+ const removed = new Set(entry.removedTrajectNodeIds ?? []);
30003
+ if (!removed.size)
30004
+ return dropped;
30005
+ const byDay = new Map();
30006
+ [...(trajectEntry.nodes ?? [])]
30007
+ .sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
30008
+ .forEach((node) => byDay.set(node.dayOrder, [...(byDay.get(node.dayOrder) ?? []), node]));
30009
+ byDay.forEach((nodes) => nodes.forEach((node, index) => {
30010
+ if (node.trajectNodeType !== REGULAR_TRAJECT_NODE_TYPE || !canRemoveTrajectNode(node) || !removed.has(node.nodeId))
30011
+ return;
30012
+ dropped.add(node.nodeId);
30013
+ [nodes[index - 1], nodes[index + 1]]
30014
+ .filter((x) => !!x && x.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE)
30015
+ .forEach((x) => dropped.add(x.nodeId));
30016
+ }));
30017
+ return dropped;
30018
+ };
30019
+ const isTrajectTransferNode = (node) => node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE && !!node.pickUp && !!node.dropOff;
30020
+ const buildTrajectTransferRequest = (node, context) => ({
30021
+ transactionId: context.transactionId,
30022
+ officeId: context.officeId,
30023
+ agentId: context.agentId ?? null,
30024
+ catalogueId: context.catalogueId,
30025
+ searchConfigurationId: context.searchConfigurationId,
30026
+ language: context.language,
30027
+ date: node.from,
30028
+ pickUp: node.pickUp,
30029
+ dropOff: node.dropOff,
30030
+ travellers: context.rooms.flatMap((room) => room.travellers)
30031
+ });
30032
+ const buildTrajectTransferLine = (node, result) => {
30033
+ const option = result.rooms?.[0]?.options?.find((x) => x.isSelected) ?? result.rooms?.[0]?.options?.[0];
30034
+ if (!option?.guid)
30035
+ return null;
30036
+ return {
30037
+ guid: option.guid,
30038
+ parentGuid: null,
30039
+ order: 0,
30040
+ trajectNodeId: node.nodeId,
30041
+ isChanged: true,
30042
+ from: result.fromDate ?? node.from,
30043
+ to: result.toDate ?? node.to,
30044
+ moment: node.moment ?? '',
30045
+ serviceType: TRANSFER_SERVICE_TYPE,
30046
+ productName: result.name,
30047
+ productCode: result.code,
30048
+ accommodationName: option.accommodationName,
30049
+ accommodationCode: option.accommodationCode,
30050
+ regimeName: option.regimeName,
30051
+ regimeCode: option.regimeCode,
30052
+ vendor: result.vendorType ?? null,
30053
+ externalVendorId: result.vendorId ?? null,
30054
+ groupKey: '',
30055
+ isActive: true,
30056
+ country: result.countryId ? { id: result.countryId, name: result.countryName, localizations: [] } : null,
30057
+ region: result.regionId ? { id: result.regionId, name: result.regionName, localizations: [] } : null,
30058
+ oord: result.oordId ? { id: result.oordId, name: result.oordName, localizations: [] } : null,
30059
+ location: result.locationId ? { id: result.locationId, name: result.locationName, localizations: [] } : null,
30060
+ longitude: result.longitude ?? null,
30061
+ latitude: result.latitude ?? null,
30062
+ pax: (option.paxIds ?? []).map((paxId, paxIndex) => ({ paxId, room: 0, order: paxIndex })),
30063
+ flightInformation: null
30064
+ };
30065
+ };
29317
30066
  const getCoordinates = (line, node, result) => {
29318
30067
  const sources = [
29319
30068
  ...(result ? [result] : []),
@@ -29741,9 +30490,15 @@ const nightsOf = (node, line) => dateFns.differenceInCalendarDays(new Date(line?
29741
30490
  const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
29742
30491
  const timeline = React.useMemo(() => {
29743
30492
  const linesByGuid = new Map((packagingEntry.lines ?? []).map((line) => [line.guid, line]));
30493
+ const dropped = getDroppedTrajectNodeIds(trajectEntry, packagingEntry);
29744
30494
  const nodes = [...(trajectEntry.nodes ?? [])]
30495
+ .filter((node) => !dropped.has(node.nodeId))
29745
30496
  .sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
29746
30497
  .map((node) => {
30498
+ // A connecting node has no line of its own; the transfer found for it carries its node id.
30499
+ if (node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE) {
30500
+ return { node, lines: (packagingEntry.lines ?? []).filter((line) => line.trajectNodeId === node.nodeId) };
30501
+ }
29747
30502
  const guids = node.lineGuids?.length ? node.lineGuids : [node.lineGuid];
29748
30503
  const lines = guids.map((guid) => linesByGuid.get(guid)).filter((x) => !!x);
29749
30504
  const groupKey = lines.length ? getLineGroupKey(lines[0]) : '';
@@ -29813,10 +30568,11 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
29813
30568
  React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-date-date" },
29814
30569
  React__default["default"].createElement("strong", null, dateFns.format(new Date(value), 'd'))),
29815
30570
  React__default["default"].createElement("p", null, dateFns.format(new Date(value), 'MMM'))));
29816
- const renderConnectingNode = ({ node }) => {
30571
+ const renderConnectingNode = ({ node, lines }) => {
29817
30572
  const distance = node.distanceInKm ? `${Math.round(node.distanceInKm)} km` : '';
29818
30573
  // How long the hop takes and how far it is, the way the traject editor puts them.
29819
30574
  const journey = [getTrajectNodeDuration(node), distance].filter(Boolean).join(' · ');
30575
+ const title = lines[0]?.productName || node.name;
29820
30576
  return (React__default["default"].createElement("div", { className: "search__filter__itinerary__transport", key: `connect-${node.nodeId}` },
29821
30577
  React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline" },
29822
30578
  React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
@@ -29825,8 +30581,8 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
29825
30581
  React__default["default"].createElement("div", { className: badgeClass('transport', getTrajectNodeBadgeModifier(node)) },
29826
30582
  React__default["default"].createElement(Icon, { name: getTrajectNodeIcon(node), height: 15 })),
29827
30583
  React__default["default"].createElement("div", { className: "search__filter__itinerary__transport-details" },
29828
- React__default["default"].createElement("h6", null, node.name || journey),
29829
- !!node.name && !!journey && React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" }, journey)))));
30584
+ React__default["default"].createElement("h6", null, title || journey),
30585
+ !!title && !!journey && React__default["default"].createElement("p", { className: "search__filter__itinerary__transport-details-time" }, journey)))));
29830
30586
  };
29831
30587
  const renderOvernight = (item, index) => {
29832
30588
  const { dayOrder } = item.node;
@@ -33077,7 +33833,7 @@ const TrajectResultsFlyIn = ({ isLoading }) => {
33077
33833
  if (!result)
33078
33834
  return;
33079
33835
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
33080
- buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? []).forEach((line) => dispatch(updateEditableEntryLine(line)));
33836
+ dispatch(upsertEditableEntryLines(buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? [])));
33081
33837
  dispatch(setTrajectEditLineGuid(null));
33082
33838
  dispatch(setFlyInIsOpen(false));
33083
33839
  };
@@ -33122,7 +33878,7 @@ const TrajectFlightsFlyIn = ({ isLoading }) => {
33122
33878
  if (!flight)
33123
33879
  return;
33124
33880
  dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
33125
- dispatch(updateEditableEntryLine(applyFlightToLine(item.line, flight)));
33881
+ dispatch(upsertEditableEntryLines([applyFlightToLine(item.line, flight)]));
33126
33882
  dispatch(setTrajectEditLineGuid(null));
33127
33883
  dispatch(setFlyInIsOpen(false));
33128
33884
  };
@@ -33185,10 +33941,16 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
33185
33941
  if (!item)
33186
33942
  return;
33187
33943
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code: result.code }));
33188
- buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? []).forEach((line) => dispatch(updateEditableEntryLine(line)));
33944
+ dispatch(upsertEditableEntryLines(buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? [])));
33189
33945
  dispatch(setTrajectActivitiesDayOrder(null));
33190
33946
  dispatch(setFlyInIsOpen(false));
33191
33947
  };
33948
+ const handleRemove = ({ item }) => {
33949
+ if (!item)
33950
+ return;
33951
+ dispatch(clearTrajectNodeSelection(item.line.guid));
33952
+ dispatch(removeTrajectNode({ nodeId: item.node.nodeId, lineGuids: item.lines.map((line) => line.guid) }));
33953
+ };
33192
33954
  if (isLoading || suggestions?.status === 'loading') {
33193
33955
  return React__default["default"].createElement(React__default["default"].Fragment, null, context.customSpinner ?? React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACTIVITIES }));
33194
33956
  }
@@ -33202,7 +33964,8 @@ const TrajectDayActivitiesFlyIn = ({ isLoading }) => {
33202
33964
  const { result, item } = card;
33203
33965
  const isSelected = item ? trajectNodeAvailability[item.line.guid]?.selectedCode === result.code : getAddedLines(result).length > 0;
33204
33966
  const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
33205
- return (React__default["default"].createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(card) : handleToggle(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
33967
+ const canRemove = !!item && isSelected && !bookedMode && canRemoveTrajectNode(item.node);
33968
+ return (React__default["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 }));
33206
33969
  })))));
33207
33970
  };
33208
33971
 
@@ -35596,16 +36359,18 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
35596
36359
  apiKey: context.tideConnection.apiKey
35597
36360
  };
35598
36361
  }, [context]);
36362
+ // The field configuration on the entry is leading for which traveler fields are shown and required.
36363
+ const paxFields = editablePackagingEntry?.paxFields ?? [];
35599
36364
  const initialValues = React.useMemo(() => {
35600
36365
  if (!editablePackagingEntry) {
35601
36366
  return {};
35602
36367
  }
35603
- return createInitialValuesFromEditablePackagingEntry(editablePackagingEntry);
36368
+ return createInitialValuesFromEditablePackagingEntry(editablePackagingEntry, undefined, paxFields);
35604
36369
  }, [editablePackagingEntry?.transactionId]);
35605
36370
  const formik$1 = formik.useFormik({
35606
36371
  initialValues,
35607
36372
  enableReinitialize: true,
35608
- validate: (values) => validateForm(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields, undefined, undefined, editablePackagingEntry?.paxFields ?? []),
36373
+ validate: (values) => validateForm(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields, undefined, undefined, paxFields),
35609
36374
  onSubmit: (values) => {
35610
36375
  if (!editablePackagingEntry)
35611
36376
  return;
@@ -35690,7 +36455,7 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
35690
36455
  ".\u00A0",
35691
36456
  stepLabels[step])) },
35692
36457
  isConfirmationPage && isLoading && React__default["default"].createElement(Spinner, { label: translations.SUMMARY.PROCESS_BOOKING }),
35693
- currentStep === 0 && (React__default["default"].createElement(SharedTravelersForm, { formik: formik$1, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false, paxFields: editablePackagingEntry?.paxFields ?? [] })),
36458
+ currentStep === 0 && (React__default["default"].createElement(SharedTravelersForm, { formik: formik$1, translations: translations, travellersSettings: travellersSettings, countries: countries, travelersFirstStep: false, isUnavailable: false, useCompactForm: false, showAgentSelection: false, paxFields: paxFields })),
35694
36459
  currentStep === 1 && (React__default["default"].createElement(SharedSummary, { translations: translations, travelerFormValues: formik$1.values, isSubmitting: isSubmitting, skipPayment: !context.generatePaymentUrl, userValidated: userValidated, remarks: remarks, enableVoucher: false, allowOption: false, isOffer: false, onUserValidatedChange: setUserValidated, onRemarksChange: setRemarks, onSubmit: handleSummarySubmit, renderOptions: () => renderEditablePackagingEntrySummaryOptions(editablePackagingEntry, priceDetails, translations, selectedPackagingAccoResult?.currencyCode), renderPreviousButton: () => (React__default["default"].createElement("button", { type: "button", title: translations.STEPS.PREVIOUS, onClick: () => dispatch(setCurrentStep(0)), className: "cta cta--secondary" }, translations.STEPS.PREVIOUS)) })),
35695
36460
  currentStep === 2 && (React__default["default"].createElement(SharedConfirmation, { bookingNumber: bookingNumber ?? editablePackagingEntry?.dossierNumber ?? '', isOption: false, isOffer: false, translations: translations.CONFIRMATION })),
35696
36461
  currentStep === 3 && React__default["default"].createElement("div", null))),
@@ -35790,11 +36555,13 @@ const TrajectResults = ({ isLoading }) => {
35790
36555
  });
35791
36556
  return map;
35792
36557
  }, [trajectEntry]);
36558
+ const droppedNodeIds = trajectEntry ? getDroppedTrajectNodeIds(trajectEntry, editablePackagingEntry) : new Set();
36559
+ const droppedKey = [...droppedNodeIds].sort((a, b) => a - b).join(',');
35793
36560
  const { stayByDay, stayStartByNodeId } = React.useMemo(() => {
35794
36561
  const byDay = new Map();
35795
36562
  const byNodeId = new Map();
35796
36563
  nodesWithLines
35797
- .filter((x) => x.node.serviceType === ACCOMMODATION_SERVICE_TYPE)
36564
+ .filter((x) => x.node.serviceType === ACCOMMODATION_SERVICE_TYPE && !droppedNodeIds.has(x.node.nodeId))
35798
36565
  .forEach((item) => {
35799
36566
  const nights = Math.max(dateFns.differenceInCalendarDays(new Date(item.line.to), new Date(item.line.from)), 1);
35800
36567
  byNodeId.set(item.node.nodeId, { item, night: 0, nights });
@@ -35803,7 +36570,7 @@ const TrajectResults = ({ isLoading }) => {
35803
36570
  }
35804
36571
  });
35805
36572
  return { stayByDay: byDay, stayStartByNodeId: byNodeId };
35806
- }, [nodesWithLines]);
36573
+ }, [nodesWithLines, droppedKey]);
35807
36574
  /** Whether every node of the trip has an answer, one way or the other. */
35808
36575
  const tripResolved = React.useMemo(() => nodesWithLines
35809
36576
  .filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node))
@@ -35830,7 +36597,20 @@ const TrajectResults = ({ isLoading }) => {
35830
36597
  if (!result)
35831
36598
  return;
35832
36599
  dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
35833
- buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? []).forEach((line) => dispatch(updateEditableEntryLine(line)));
36600
+ dispatch(upsertEditableEntryLines(buildNodeSelectionLines(item, result, bookedMode, editablePackagingEntry?.lines ?? [])));
36601
+ };
36602
+ /**
36603
+ * An optional stop can be taken off the trip; a mandatory one, or one of which the group needs a pick,
36604
+ * only swapped. A booked entry's services are never taken off here.
36605
+ */
36606
+ const canRemove = (item) => !bookedMode && canRemoveTrajectNode(item.node);
36607
+ const handleRemoveNode = (item) => {
36608
+ dispatch(clearTrajectNodeSelection(item.line.guid));
36609
+ dispatch(removeTrajectNode({ nodeId: item.node.nodeId, lineGuids: item.lines.map((line) => line.guid) }));
36610
+ };
36611
+ const handleRemoveFlight = (item) => {
36612
+ dispatch(clearTrajectFlightSelection(item.line.guid));
36613
+ dispatch(removeTrajectNode({ nodeId: item.node.nodeId, lineGuids: item.lines.map((line) => line.guid) }));
35834
36614
  };
35835
36615
  /** The remaining legs for a flight node open in the fly-in, as the regular flight results do. */
35836
36616
  const handleShowMoreFlights = (item) => {
@@ -35898,9 +36678,17 @@ const TrajectResults = ({ isLoading }) => {
35898
36678
  // A hotel row holds the hotels configured on the node; a portal can also let it fill up with
35899
36679
  // non-preferred hotels found in the area, the rest staying behind "show more".
35900
36680
  const fill = showNonPreferredHotels && node.serviceType === ACCOMMODATION_SERVICE_TYPE ? others.slice(0, Math.max(MAX_HOTEL_RESULTS - 1 - configured.length, 0)) : [];
35901
- const remaining = others.length - fill.length;
35902
36681
  // No entry yet means the node's search has been queued but not dispatched — still loading.
35903
36682
  const status = availability?.status ?? 'loading';
36683
+ // A stop taken off the trip keeps its results in view, to pick one back.
36684
+ const isRemoved = status === 'resolved' && !selected && results.length > 0;
36685
+ const removable = canRemove(item);
36686
+ const shown = selected
36687
+ ? [selected, ...configured, ...fill]
36688
+ : configured.length || fill.length
36689
+ ? [...configured, ...fill]
36690
+ : others.slice(0, MAX_HOTEL_RESULTS);
36691
+ const remaining = results.length - shown.length;
35904
36692
  return (React__default["default"].createElement(React__default["default"].Fragment, { key: line.guid },
35905
36693
  showHeader && (React__default["default"].createElement("div", { className: "search__results__label search__results__label--secondary" },
35906
36694
  React__default["default"].createElement("div", { className: "search__results__label__date" },
@@ -35912,13 +36700,18 @@ const TrajectResults = ({ isLoading }) => {
35912
36700
  React__default["default"].createElement("strong", null, headerTitle || node.name))))),
35913
36701
  status === 'loading' && React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACCOMMODATIONS }),
35914
36702
  status === 'unavailable' && React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
35915
- status === 'resolved' && selected && (React__default["default"].createElement(React__default["default"].Fragment, null,
35916
- availability.preferredUnavailable && node.preferredAccommodationName && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
36703
+ status === 'resolved' && (selected || isRemoved) && (React__default["default"].createElement(React__default["default"].Fragment, null,
36704
+ selected && availability.preferredUnavailable && node.preferredAccommodationName && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
35917
36705
  React__default["default"].createElement("span", null,
35918
36706
  node.preferredAccommodationName,
35919
36707
  " \u2014 ",
35920
36708
  translations.SRP.NO_RESULTS))),
35921
- React__default["default"].createElement(TrajectCardRow, { selectionKey: selected.code }, [selected, ...configured, ...fill].map((result) => (React__default["default"].createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE })))),
36709
+ React__default["default"].createElement(TrajectCardRow, { selectionKey: selected?.code ?? '' }, shown.map((result) => {
36710
+ const isSelected = result.code === selected?.code;
36711
+ return (React__default["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,
36712
+ // selectedLabel={bookedMode && matchesCode(result, node.code ?? '') ? translations.SHARED.BOOKED : undefined}
36713
+ selectedLabel: removable ? translations.SRP.REMOVE : undefined }));
36714
+ })),
35922
36715
  remaining > 0 && !hideShowMoreResults && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
35923
36716
  React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
35924
36717
  translations.SRP.SHOW_MORE,
@@ -35928,7 +36721,7 @@ const TrajectResults = ({ isLoading }) => {
35928
36721
  };
35929
36722
  const handleSelectFlight = (item, flight) => {
35930
36723
  dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
35931
- dispatch(updateEditableEntryLine(buildFlightSelectionLine(item, flight, bookedMode)));
36724
+ dispatch(upsertEditableEntryLines([buildFlightSelectionLine(item, flight, bookedMode)]));
35932
36725
  };
35933
36726
  const renderFlightNode = (item) => {
35934
36727
  const { node, line } = item;
@@ -35937,7 +36730,9 @@ const TrajectResults = ({ isLoading }) => {
35937
36730
  const flights = availability?.results ?? [];
35938
36731
  const selected = flights.find((x) => x.outwardGuid === availability?.selectedGuid) ?? null;
35939
36732
  const others = flights.filter((x) => x.outwardGuid !== availability?.selectedGuid);
35940
- const visible = others.slice(0, 2);
36733
+ const isRemoved = status === 'resolved' && !selected && flights.length > 0;
36734
+ const removable = canRemove(item);
36735
+ const visible = others.slice(0, selected ? 2 : 3);
35941
36736
  return (React__default["default"].createElement(React__default["default"].Fragment, { key: line.guid },
35942
36737
  React__default["default"].createElement("div", { className: "search__results__label search__results__label--secondary" },
35943
36738
  React__default["default"].createElement("div", { className: "search__results__label__date" },
@@ -35952,15 +36747,15 @@ const TrajectResults = ({ isLoading }) => {
35952
36747
  node.arrivalAirportCode)))),
35953
36748
  status === 'loading' && React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_FLIGHTS }),
35954
36749
  status === 'unavailable' && React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS),
35955
- status === 'resolved' && selected && (React__default["default"].createElement(React__default["default"].Fragment, null,
36750
+ status === 'resolved' && (selected || isRemoved) && (React__default["default"].createElement(React__default["default"].Fragment, null,
35956
36751
  React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--extended" },
35957
- React__default["default"].createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price, selectedLabel: bookedMode && selected.outwardGuid === line.guid ? translations.SHARED.BOOKED : undefined }),
35958
- visible.map((result) => (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected.price, onSelect: () => handleSelectFlight(item, result) })))),
35959
- others.length > 2 && !hideShowMoreResults && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
36752
+ selected && (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${selected.outwardGuid}`, item: selected.outward, guid: selected.outwardGuid, selectedGuid: selected.outwardGuid, isOutward: true, showSelectedState: true, price: selected.price, onSelect: removable ? () => handleRemoveFlight(item) : undefined, selectedLabel: bookedMode && selected.outwardGuid === line.guid ? translations.SHARED.BOOKED : removable ? translations.SRP.REMOVE : undefined })),
36753
+ visible.map((result) => (React__default["default"].createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.outward, guid: result.outwardGuid, isOutward: true, price: result.price, currentSelectedPrice: selected?.price, onSelect: () => handleSelectFlight(item, result) })))),
36754
+ others.length > visible.length && !hideShowMoreResults && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
35960
36755
  React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreFlights(item) },
35961
36756
  translations.SRP.SHOW_MORE,
35962
36757
  " (",
35963
- others.length - 2,
36758
+ others.length - visible.length,
35964
36759
  ")")))))));
35965
36760
  };
35966
36761
  /** The lines a suggested activity put on the entry, which is also how we know it was added. */
@@ -36036,13 +36831,21 @@ const TrajectResults = ({ isLoading }) => {
36036
36831
  ")")))));
36037
36832
  };
36038
36833
  /**
36039
- * An activity the traject books is swapped for another, the way a hotel is; one the traveller
36040
- * found for themselves is added to the trip or taken back off it.
36834
+ * An activity the traject books is swapped for another, the way a hotel is, or - when it is optional -
36835
+ * taken off the trip; one the traveller found for themselves is added to the trip or taken back off it.
36041
36836
  */
36042
36837
  const renderActivityCard = ({ result, item }) => {
36043
36838
  const isSelected = isActivitySelected({ result, item });
36044
36839
  const isBookedCard = !!item && bookedMode && matchesCode(result, item.node.code ?? '');
36045
- return (React__default["default"].createElement(TrajectNodeCard, { key: `activity-${result.code}`, node: item?.node, result: result, isSelected: isSelected, languageCode: context.languageCode, translations: translations, onSelect: () => (item ? handleSelect(item, result.code) : handleToggleActivity(result)), selectLabel: item ? undefined : translations.SRP.ADD, selectedLabel: item ? (isBookedCard ? translations.SHARED.BOOKED : undefined) : translations.SRP.REMOVE }));
36840
+ const removable = !!item && canRemove(item);
36841
+ const handleClick = () => {
36842
+ if (!item)
36843
+ return handleToggleActivity(result);
36844
+ if (isSelected && removable)
36845
+ return handleRemoveNode(item);
36846
+ handleSelect(item, result.code);
36847
+ };
36848
+ return (React__default["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 }));
36046
36849
  };
36047
36850
  if (isLoading)
36048
36851
  return React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
@@ -36077,6 +36880,7 @@ const TrajectResults = ({ isLoading }) => {
36077
36880
  const useTrajectAvailability = () => {
36078
36881
  const context = React.useContext(SearchResultsConfigurationContext);
36079
36882
  const dispatch = reactRedux.useDispatch();
36883
+ const { editablePackagingEntry, trajectTransferAvailability } = reactRedux.useSelector((state) => state.searchResults);
36080
36884
  const trajectEntry = context?.trajectEntry;
36081
36885
  const showApiItems = !!context?.showApiItems;
36082
36886
  const hideShowMoreResults = !!context?.hideShowMoreResults;
@@ -36102,12 +36906,14 @@ const useTrajectAvailability = () => {
36102
36906
  rooms: getPackagingRoomsFromEntry(trajectEntry.entry)
36103
36907
  };
36104
36908
  // Flight searches take passengers rather than rooms; the API buckets by age.
36909
+ // The ids must be the entry's own pax ids: the flight lines this search caches carry them as
36910
+ // EntryLinePax.PaxId, and booking maps those onto the entry's travelers (PackagingService.SyncPaxIds).
36105
36911
  const pax = trajectEntry.entry.pax ?? [];
36106
36912
  const ageOf = (p) => p.age ?? 30;
36107
- const adults = pax.filter((p) => ageOf(p) >= 12).length;
36108
- const kids = pax.filter((p) => ageOf(p) >= 2 && ageOf(p) < 12).length;
36109
- const babies = pax.filter((p) => ageOf(p) < 2).length;
36110
- const flightPax = lodash.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 })));
36913
+ const adults = pax.filter((p) => ageOf(p) >= 12);
36914
+ const kids = pax.filter((p) => ageOf(p) >= 2 && ageOf(p) < 12);
36915
+ const babies = pax.filter((p) => ageOf(p) < 2);
36916
+ const flightPax = lodash.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 })));
36111
36917
  const nodesWithLines = getTrajectNodesWithLines(trajectEntry);
36112
36918
  // The other members of a line group are alternatives whether or not a search still finds
36113
36919
  // them; the ones it does not are drawn from their lines, as the booked service itself is.
@@ -36238,9 +37044,30 @@ const useTrajectAvailability = () => {
36238
37044
  return item.lines.map((x) => x.guid);
36239
37045
  }
36240
37046
  };
37047
+ const resolveTransferNode = async (node) => {
37048
+ dispatch(setTrajectTransferLoading(node.nodeId));
37049
+ try {
37050
+ const results = (await build.searchPackagingTransfers(config, buildTrajectTransferRequest(node, searchContext), controller.signal)) ?? [];
37051
+ if (controller.signal.aborted)
37052
+ return [];
37053
+ const result = results[0] ?? null;
37054
+ dispatch(setTrajectTransferAvailability({ nodeId: node.nodeId, result: result && buildTrajectTransferLine(node, result) ? result : null }));
37055
+ }
37056
+ catch (error) {
37057
+ if (controller.signal.aborted)
37058
+ return [];
37059
+ console.error('Failed to resolve traject transfer', node.name, error);
37060
+ dispatch(setTrajectTransferAvailability({ nodeId: node.nodeId, result: null }));
37061
+ }
37062
+ return [];
37063
+ };
36241
37064
  (async () => {
36242
37065
  const resolvable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node));
36243
- const unresolved = (await Promise.all(resolvable.map((item) => (isTrajectFlightNode(item.node) ? resolveFlightNode(item) : resolveNode(item))))).flat();
37066
+ const transfers = bookedMode ? [] : (trajectEntry.nodes ?? []).filter(isTrajectTransferNode);
37067
+ const unresolved = (await Promise.all([
37068
+ ...resolvable.map((item) => (isTrajectFlightNode(item.node) ? resolveFlightNode(item) : resolveNode(item))),
37069
+ ...transfers.map(resolveTransferNode)
37070
+ ])).flat();
36244
37071
  if (controller.signal.aborted)
36245
37072
  return;
36246
37073
  dispatch(setTrajectResolving(false));
@@ -36252,6 +37079,28 @@ const useTrajectAvailability = () => {
36252
37079
  })();
36253
37080
  return () => controller.abort();
36254
37081
  }, [trajectEntry, showApiItems, hideShowMoreResults]);
37082
+ React.useEffect(() => {
37083
+ if (!trajectEntry || !editablePackagingEntry || isBookedEntryTraject(trajectEntry))
37084
+ return;
37085
+ const dropped = getDroppedTrajectNodeIds(trajectEntry, editablePackagingEntry);
37086
+ const guids = new Set((editablePackagingEntry.lines ?? []).map((line) => line.guid));
37087
+ const toAdd = [];
37088
+ const toRemove = [];
37089
+ (trajectEntry.nodes ?? []).filter(isTrajectTransferNode).forEach((node) => {
37090
+ const result = trajectTransferAvailability[node.nodeId]?.result;
37091
+ const line = result ? buildTrajectTransferLine(node, result) : null;
37092
+ if (!line)
37093
+ return;
37094
+ if (dropped.has(node.nodeId) && guids.has(line.guid))
37095
+ toRemove.push(line.guid);
37096
+ if (!dropped.has(node.nodeId) && !guids.has(line.guid))
37097
+ toAdd.push(line);
37098
+ });
37099
+ if (toRemove.length)
37100
+ dispatch(removeEditableEntryLines(toRemove));
37101
+ if (toAdd.length)
37102
+ dispatch(addEditableEntryLines(toAdd));
37103
+ }, [trajectEntry, editablePackagingEntry, trajectTransferAvailability]);
36255
37104
  };
36256
37105
 
36257
37106
  const SearchResultsContainer = ({ onBookingStarted }) => {
@@ -36556,10 +37405,9 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
36556
37405
  const item = getTrajectNodesWithLines(context.trajectEntry).find((x) => x.line.guid === trajectEditLineGuid);
36557
37406
  const result = packagingAccoSearchDetails.find((x) => x.code === selectedPackagingAccoResultCode);
36558
37407
  if (item && result) {
36559
- const currentLines = item.lines
36560
- .map((line) => editablePackagingEntry?.lines?.find((x) => x.guid === line.guid))
36561
- .filter((x) => !!x);
36562
- applyResultToLines(currentLines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
37408
+ // A stop the traveller took off has no lines left on the entry: the traject's own put it back.
37409
+ const currentLines = item.lines.map((line) => editablePackagingEntry?.lines?.find((x) => x.guid === line.guid) ?? line);
37410
+ dispatch(upsertEditableEntryLines(applyResultToLines(currentLines, result)));
36563
37411
  dispatch(updateTrajectNodeResult({ lineGuid: trajectEditLineGuid, result }));
36564
37412
  }
36565
37413
  dispatch(setTrajectEditLineGuid(null));
@@ -40184,6 +41032,363 @@ const Login = ({ tideClientConfig, portalId, languageCode, imageSrc, logo, isMem
40184
41032
  isMemberConfirmation && (React__default["default"].createElement(ConfirmComponent, { tideClientConfig: tideClientConfig, portalId: portalId, languageCode: languageCode, member: member, setMember: setMember, handleBackToHome: handleBackToHome, handleBackToLogin: handleBackToLogin }))))));
40185
41033
  };
40186
41034
 
41035
+ /** Agent endpoints need the member token, fall back to the one the Login component stored. */
41036
+ const withAgentToken = (config) => ({
41037
+ ...config,
41038
+ token: config.token ?? selectAgentToken()
41039
+ });
41040
+ /** False when the token is not a JWT or has expired. */
41041
+ const isAgentTokenValid = (token) => {
41042
+ if (!token)
41043
+ return false;
41044
+ try {
41045
+ const { exp } = jwtDecode(token);
41046
+ return !exp || exp * 1000 > Date.now();
41047
+ }
41048
+ catch {
41049
+ return false;
41050
+ }
41051
+ };
41052
+ // tide-client throws Error(statusText) without the status, and statusText is empty over HTTP/2,
41053
+ // so also treat any failure with an invalid/expired token as unauthorized.
41054
+ const isUnauthorizedError = (error, token) => (error instanceof Error && /unauthori[sz]ed|forbidden/i.test(error.message)) || !isAgentTokenValid(token);
41055
+ const fetchLookups = async (config, languageCode, signal) => {
41056
+ // A failing lookup should not block the list itself.
41057
+ const [entryStatuses, customEntryStatuses, printActions] = await Promise.allSettled([
41058
+ build.getEntryStatus(config, signal, languageCode),
41059
+ build.getCustomEntryStatus(config, signal, languageCode),
41060
+ build.getPrintActions(config, build.PrintActionGroup.Dossier, signal)
41061
+ ]);
41062
+ return {
41063
+ entryStatuses: entryStatuses.status === 'fulfilled' ? entryStatuses.value ?? [] : [],
41064
+ customEntryStatuses: customEntryStatuses.status === 'fulfilled' ? customEntryStatuses.value ?? [] : [],
41065
+ printActions: printActions.status === 'fulfilled' ? printActions.value ?? [] : []
41066
+ };
41067
+ };
41068
+ /** Converts the raw filter inputs to the OData column filters understood by tide-client's createParams. */
41069
+ const buildFilterItem = (columns, filterValues, sort, page, take) => {
41070
+ const filterColumns = {};
41071
+ columns.forEach((column) => {
41072
+ const raw = filterValues[column.id]?.trim();
41073
+ if (!raw)
41074
+ return;
41075
+ switch (column.kind) {
41076
+ case 'text':
41077
+ filterColumns[column.id] = { type: 'text', value: raw };
41078
+ break;
41079
+ case 'number': {
41080
+ const value = parseFloat(raw.replace(',', '.'));
41081
+ if (!isNaN(value))
41082
+ filterColumns[column.id] = { type: 'number', value };
41083
+ break;
41084
+ }
41085
+ case 'date': {
41086
+ // <input type="date"> value: yyyy-MM-dd, createParams expects a 1-based month.
41087
+ const [year, month, day] = raw.split('-').map((x) => parseInt(x, 10));
41088
+ if (year && month && day)
41089
+ filterColumns[column.id] = { type: 'date', value: { year, month, day } };
41090
+ break;
41091
+ }
41092
+ case 'status':
41093
+ case 'customStatus':
41094
+ filterColumns[column.id] = { type: 'enum', value: parseInt(raw, 10) };
41095
+ break;
41096
+ }
41097
+ });
41098
+ return { take, page, sort, columns: filterColumns };
41099
+ };
41100
+ const fetchEntries = (config, filter, signal) => build.getEntryList(config, filter, undefined, signal);
41101
+ /** Prints the entry and returns an object url to the resulting pdf. */
41102
+ const printEntry = async (config, printActionId, entryId) => {
41103
+ // Same request as the agent portal: the print action and the entry (version) id.
41104
+ const request = { id: printActionId, entryId };
41105
+ const response = await build.print(config, request);
41106
+ if (!response.ok)
41107
+ throw new Error(response.statusText);
41108
+ const buffer = await response.arrayBuffer();
41109
+ return URL.createObjectURL(new Blob([buffer], { type: 'application/pdf' }));
41110
+ };
41111
+
41112
+ const PAGE_SIZES = [10, 20, 50, 100];
41113
+ const FILTER_DEBOUNCE_MS = 400;
41114
+ const EyeIcon = () => (React__default["default"].createElement("svg", { className: "agent-entries__icon", viewBox: "0 0 576 512", fill: "currentColor", "aria-hidden": "true" },
41115
+ React__default["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" })));
41116
+ const PrintIcon = () => (React__default["default"].createElement("svg", { className: "agent-entries__icon", viewBox: "0 0 512 512", fill: "currentColor", "aria-hidden": "true" },
41117
+ React__default["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" })));
41118
+ const SortIcon = ({ asc }) => (React__default["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" },
41119
+ React__default["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" })));
41120
+ const AgentEntries = ({ tideClientConfig, languageCode, title, pageSize, customTranslations, onLogin, onUnauthorized }) => {
41121
+ const translations = React.useMemo(() => getTranslations(languageCode ?? 'en-GB', customTranslations), [languageCode, customTranslations]);
41122
+ const t = translations.AGENT_ENTRIES;
41123
+ const config = React.useMemo(() => withAgentToken(tideClientConfig), [tideClientConfig.host, tideClientConfig.apiKey, tideClientConfig.token]);
41124
+ const isLoggedIn = !!config.token;
41125
+ const hasValidToken = isLoggedIn && isAgentTokenValid(config.token);
41126
+ const columns = React.useMemo(() => [
41127
+ { id: 'number', kind: 'text', label: t.NUMBER },
41128
+ { id: 'departureDate', kind: 'date', label: t.DEPARTURE_DATE },
41129
+ { id: 'status', kind: 'status', label: t.STATUS },
41130
+ { id: 'customEntryStatusId', kind: 'customStatus', label: t.CUSTOM_STATUS },
41131
+ { id: 'returnDate', kind: 'date', label: t.RETURN_DATE },
41132
+ { id: 'profit', kind: 'number', label: t.PROFIT },
41133
+ { id: 'totalPrice', kind: 'number', label: t.NETTO_SELLING_PRICE },
41134
+ { id: 'calculatedAgentSurchargeAmount', kind: 'number', label: t.YOUR_SURCHARGE },
41135
+ { id: 'createdDate', kind: 'date', label: t.CREATED },
41136
+ { id: 'contact', kind: 'text', label: t.CONTACT },
41137
+ { id: 'travelerAddress', kind: 'text', label: t.MAIN_BOOKER }
41138
+ ], [t]);
41139
+ const [lookups, setLookups] = React.useState({ entryStatuses: [], customEntryStatuses: [], printActions: [] });
41140
+ const [entries, setEntries] = React.useState([]);
41141
+ const [count, setCount] = React.useState();
41142
+ const [loadState, setLoadState] = React.useState('idle');
41143
+ const [filterInputs, setFilterInputs] = React.useState({});
41144
+ const [filterValues, setFilterValues] = React.useState({});
41145
+ const [sort, setSort] = React.useState({ name: 'number', asc: true });
41146
+ const [page, setPage] = React.useState(1);
41147
+ const [take, setTake] = React.useState(pageSize ?? 20);
41148
+ const [expandedId, setExpandedId] = React.useState();
41149
+ const [printingKey, setPrintingKey] = React.useState();
41150
+ const [printError, setPrintError] = React.useState(false);
41151
+ const handleError = (error) => {
41152
+ if (error instanceof DOMException && error.name === 'AbortError')
41153
+ return;
41154
+ if (isUnauthorizedError(error, config.token)) {
41155
+ setLoadState('unauthorized');
41156
+ onUnauthorized?.();
41157
+ }
41158
+ else {
41159
+ console.error(error);
41160
+ setLoadState('error');
41161
+ }
41162
+ };
41163
+ React.useEffect(() => {
41164
+ if (isLoggedIn && !hasValidToken)
41165
+ onUnauthorized?.();
41166
+ }, [isLoggedIn, hasValidToken]);
41167
+ // Lookups (statuses & print actions) only need to be fetched once.
41168
+ React.useEffect(() => {
41169
+ if (!hasValidToken)
41170
+ return;
41171
+ const controller = new AbortController();
41172
+ fetchLookups(config, languageCode, controller.signal)
41173
+ .then(setLookups)
41174
+ .catch(() => { });
41175
+ return () => controller.abort();
41176
+ }, [config, languageCode, hasValidToken]);
41177
+ // Debounce the typed filters, a selected dropdown/date is applied immediately.
41178
+ React.useEffect(() => {
41179
+ const handle = setTimeout(() => {
41180
+ if (lodash.isEqual(filterInputs, filterValues))
41181
+ return;
41182
+ setFilterValues(filterInputs);
41183
+ setPage(1);
41184
+ }, FILTER_DEBOUNCE_MS);
41185
+ return () => clearTimeout(handle);
41186
+ }, [filterInputs]);
41187
+ React.useEffect(() => {
41188
+ if (!hasValidToken)
41189
+ return;
41190
+ const controller = new AbortController();
41191
+ setLoadState('loading');
41192
+ fetchEntries(config, buildFilterItem(columns, filterValues, sort, page, take), controller.signal)
41193
+ .then((result) => {
41194
+ setEntries(result?.items ?? []);
41195
+ setCount(result?.count ?? undefined);
41196
+ setLoadState('loaded');
41197
+ })
41198
+ .catch(handleError);
41199
+ return () => controller.abort();
41200
+ }, [config, hasValidToken, columns, filterValues, sort, page, take]);
41201
+ const totalPages = count !== undefined ? Math.max(1, Math.ceil(count / take)) : undefined;
41202
+ const hasNextPage = totalPages !== undefined ? page < totalPages : entries.length === take;
41203
+ const handleSort = (columnId) => {
41204
+ setSort((current) => (current.name === columnId ? { name: columnId, asc: !current.asc } : { name: columnId, asc: true }));
41205
+ setPage(1);
41206
+ };
41207
+ const handleFilterChange = (columnId, value, immediate) => {
41208
+ const next = { ...filterInputs, [columnId]: value };
41209
+ setFilterInputs(next);
41210
+ if (immediate) {
41211
+ setFilterValues(next);
41212
+ setPage(1);
41213
+ }
41214
+ };
41215
+ const handlePrint = async (entry, printAction) => {
41216
+ // Open the tab synchronously, otherwise the popup blocker kicks in once the pdf arrives.
41217
+ const printWindow = window.open('', '_blank');
41218
+ setPrintingKey(`${entry.id}-${printAction.id}`);
41219
+ setPrintError(false);
41220
+ try {
41221
+ const url = await printEntry(config, printAction.id, entry.id);
41222
+ if (printWindow) {
41223
+ printWindow.location.href = url;
41224
+ }
41225
+ else {
41226
+ window.open(url, '_blank');
41227
+ }
41228
+ setTimeout(() => URL.revokeObjectURL(url), 60000);
41229
+ }
41230
+ catch (error) {
41231
+ printWindow?.close();
41232
+ if (isUnauthorizedError(error, config.token)) {
41233
+ handleError(error);
41234
+ }
41235
+ else {
41236
+ console.error(error);
41237
+ setPrintError(true);
41238
+ }
41239
+ }
41240
+ finally {
41241
+ setPrintingKey(undefined);
41242
+ }
41243
+ };
41244
+ const formatDate = (value) => {
41245
+ if (!value)
41246
+ return '';
41247
+ const date = new Date(value);
41248
+ if (isNaN(date.getTime()))
41249
+ return '';
41250
+ return new Intl.DateTimeFormat(languageCode, { day: '2-digit', month: '2-digit', year: 'numeric' }).format(date);
41251
+ };
41252
+ const formatNumber = (value) => {
41253
+ if (value === undefined || value === null)
41254
+ return '';
41255
+ return new Intl.NumberFormat(languageCode, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(value);
41256
+ };
41257
+ const getEntryStatusLabel = (status) => lookups.entryStatuses.find((x) => x.key === status)?.value ?? '';
41258
+ const getCustomEntryStatusLabel = (id) => lookups.customEntryStatuses.find((x) => x.id === id)?.name ?? '';
41259
+ const getPrintActionsForEntry = (entry) => lookups.printActions.filter((x) => x.validEntryStatuses?.includes(entry.status));
41260
+ const renderCell = (entry, column) => {
41261
+ const value = entry[column.id];
41262
+ switch (column.kind) {
41263
+ case 'date':
41264
+ return formatDate(value);
41265
+ case 'number':
41266
+ return formatNumber(value);
41267
+ case 'status':
41268
+ return getEntryStatusLabel(value);
41269
+ case 'customStatus':
41270
+ return getCustomEntryStatusLabel(value);
41271
+ default:
41272
+ return value ?? '';
41273
+ }
41274
+ };
41275
+ const renderFilter = (column) => {
41276
+ const value = filterInputs[column.id] ?? '';
41277
+ const className = 'agent-entries__filter';
41278
+ switch (column.kind) {
41279
+ case 'date':
41280
+ return (React__default["default"].createElement("input", { type: "date", className: className, value: value, "aria-label": column.label, onChange: (e) => handleFilterChange(column.id, e.target.value, true) }));
41281
+ case 'status':
41282
+ case 'customStatus': {
41283
+ const options = column.kind === 'status'
41284
+ ? lookups.entryStatuses.filter((x) => x.key !== undefined && x.key !== null).map((x) => ({ key: x.key, value: x.value }))
41285
+ : lookups.customEntryStatuses.map((x) => ({ key: x.id, value: x.name }));
41286
+ return (React__default["default"].createElement("select", { className: className, value: value, "aria-label": column.label, onChange: (e) => handleFilterChange(column.id, e.target.value, true) },
41287
+ React__default["default"].createElement("option", { value: "" }, t.ALL),
41288
+ options.map((option) => (React__default["default"].createElement("option", { key: option.key, value: option.key }, option.value)))));
41289
+ }
41290
+ case 'number':
41291
+ return (React__default["default"].createElement("input", { type: "number", className: className, value: value, "aria-label": column.label, onChange: (e) => handleFilterChange(column.id, e.target.value) }));
41292
+ default:
41293
+ return (React__default["default"].createElement("input", { type: "text", className: className, value: value, "aria-label": column.label, onChange: (e) => handleFilterChange(column.id, e.target.value) }));
41294
+ }
41295
+ };
41296
+ const renderDetails = (entry) => {
41297
+ const printActions = getPrintActionsForEntry(entry);
41298
+ const travelers = entry.pax?.length ? entry.pax.map((p) => (p.isMainBooker ? `${p.name} (${t.MAIN_BOOKER.toLowerCase()})` : p.name)).join(', ') : '';
41299
+ const details = [
41300
+ { label: t.NUMBER, value: entry.number },
41301
+ { label: t.PRODUCT, value: entry.firstProductName },
41302
+ { label: t.STATUS, value: getEntryStatusLabel(entry.status) },
41303
+ { label: t.CUSTOM_STATUS, value: getCustomEntryStatusLabel(entry.customEntryStatusId) },
41304
+ { label: t.DEPARTURE_DATE, value: formatDate(entry.departureDate) },
41305
+ { label: t.RETURN_DATE, value: formatDate(entry.returnDate) },
41306
+ { label: t.CREATED, value: formatDate(entry.createdDate) },
41307
+ { label: t.CONTACT, value: entry.contact },
41308
+ { label: t.MAIN_BOOKER, value: entry.travelerAddress },
41309
+ { label: t.TRAVELERS, value: travelers || (entry.paxCount ? entry.paxCount : '') },
41310
+ { label: t.NETTO_SELLING_PRICE, value: formatNumber(entry.totalPrice) },
41311
+ { label: t.YOUR_SURCHARGE, value: formatNumber(entry.calculatedAgentSurchargeAmount) },
41312
+ { label: t.PROFIT, value: formatNumber(entry.profit) }
41313
+ ];
41314
+ return (React__default["default"].createElement("div", { className: "agent-entries__details" },
41315
+ React__default["default"].createElement("dl", { className: "agent-entries__details__list" }, details
41316
+ .filter((detail) => detail.value !== undefined && detail.value !== null && detail.value !== '')
41317
+ .map((detail) => (React__default["default"].createElement("div", { className: "agent-entries__details__item", key: detail.label },
41318
+ React__default["default"].createElement("dt", null, detail.label),
41319
+ React__default["default"].createElement("dd", null, detail.value))))),
41320
+ printActions.length > 0 && (React__default["default"].createElement("div", { className: "agent-entries__details__prints" },
41321
+ React__default["default"].createElement("span", { className: "agent-entries__details__prints__title" }, t.PRINTS),
41322
+ React__default["default"].createElement("div", { className: "agent-entries__details__prints__buttons" }, printActions.map((printAction) => (React__default["default"].createElement("button", { type: "button", key: printAction.id, className: "agent-entries__print-button", disabled: printingKey === `${entry.id}-${printAction.id}`, onClick: () => handlePrint(entry, printAction) },
41323
+ React__default["default"].createElement(PrintIcon, null),
41324
+ printAction.label))))))));
41325
+ };
41326
+ const renderLoginMessage = (message) => (React__default["default"].createElement("div", { className: "agent-entries__message" },
41327
+ React__default["default"].createElement("p", null, message),
41328
+ onLogin && (React__default["default"].createElement("button", { type: "button", className: "cta cta--primary", onClick: onLogin }, translations.LOGIN.LOGIN))));
41329
+ if (!isLoggedIn) {
41330
+ return (React__default["default"].createElement("div", { className: "agent-entries" },
41331
+ React__default["default"].createElement("h2", { className: "agent-entries__title" }, title ?? t.TITLE),
41332
+ renderLoginMessage(t.NOT_LOGGED_IN)));
41333
+ }
41334
+ if (!hasValidToken || loadState === 'unauthorized') {
41335
+ return (React__default["default"].createElement("div", { className: "agent-entries" },
41336
+ React__default["default"].createElement("h2", { className: "agent-entries__title" }, title ?? t.TITLE),
41337
+ renderLoginMessage(t.SESSION_EXPIRED)));
41338
+ }
41339
+ const columnCount = columns.length + 1;
41340
+ return (React__default["default"].createElement("div", { className: "agent-entries" },
41341
+ React__default["default"].createElement("h2", { className: "agent-entries__title" }, title ?? t.TITLE),
41342
+ printError && (React__default["default"].createElement("div", { className: "agent-entries__error", role: "alert" },
41343
+ t.PRINT_ERROR,
41344
+ React__default["default"].createElement("button", { type: "button", className: "agent-entries__error__close", "aria-label": "close", onClick: () => setPrintError(false) }, "\u00D7"))),
41345
+ React__default["default"].createElement("div", { className: buildClassName(['agent-entries__card', loadState === 'loading' && 'agent-entries__card--loading']) },
41346
+ React__default["default"].createElement("div", { className: "agent-entries__table-wrapper" },
41347
+ React__default["default"].createElement("table", { className: "agent-entries__table" },
41348
+ React__default["default"].createElement("thead", null,
41349
+ React__default["default"].createElement("tr", null,
41350
+ React__default["default"].createElement("th", { className: "agent-entries__actions-header" },
41351
+ React__default["default"].createElement("span", { className: "agent-entries__sr-only" }, t.ACTIONS)),
41352
+ columns.map((column) => (React__default["default"].createElement("th", { key: column.id, "aria-sort": sort.name === column.id ? (sort.asc ? 'ascending' : 'descending') : undefined },
41353
+ React__default["default"].createElement("button", { type: "button", className: "agent-entries__sort", onClick: () => handleSort(column.id) },
41354
+ column.label,
41355
+ sort.name === column.id && React__default["default"].createElement(SortIcon, { asc: sort.asc })))))),
41356
+ React__default["default"].createElement("tr", { className: "agent-entries__filter-row" },
41357
+ React__default["default"].createElement("th", null),
41358
+ columns.map((column) => (React__default["default"].createElement("th", { key: column.id }, renderFilter(column)))))),
41359
+ React__default["default"].createElement("tbody", null,
41360
+ loadState === 'error' && (React__default["default"].createElement("tr", null,
41361
+ React__default["default"].createElement("td", { colSpan: columnCount, className: "agent-entries__empty" }, t.ERROR))),
41362
+ loadState !== 'error' && entries.length === 0 && (React__default["default"].createElement("tr", null,
41363
+ React__default["default"].createElement("td", { colSpan: columnCount, className: "agent-entries__empty" }, loadState === 'loading' ? t.LOADING : t.NO_ITEMS))),
41364
+ loadState !== 'error' &&
41365
+ entries.map((entry) => {
41366
+ const isExpanded = expandedId === entry.id;
41367
+ return (React__default["default"].createElement(React__default["default"].Fragment, { key: entry.id },
41368
+ React__default["default"].createElement("tr", { className: buildClassName(['agent-entries__row', isExpanded && 'agent-entries__row--expanded']) },
41369
+ React__default["default"].createElement("td", { className: "agent-entries__actions" },
41370
+ React__default["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) },
41371
+ React__default["default"].createElement(EyeIcon, null)),
41372
+ getPrintActionsForEntry(entry).map((printAction) => (React__default["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) },
41373
+ React__default["default"].createElement(PrintIcon, null))))),
41374
+ columns.map((column) => (React__default["default"].createElement("td", { key: column.id, className: `agent-entries__cell agent-entries__cell--${column.kind}` }, renderCell(entry, column))))),
41375
+ isExpanded && (React__default["default"].createElement("tr", { className: "agent-entries__details-row" },
41376
+ React__default["default"].createElement("td", { colSpan: columnCount }, renderDetails(entry))))));
41377
+ })))),
41378
+ React__default["default"].createElement("div", { className: "agent-entries__footer" },
41379
+ React__default["default"].createElement("select", { className: "agent-entries__page-size", value: take, "aria-label": t.PAGE_SIZE, onChange: (e) => {
41380
+ setTake(parseInt(e.target.value, 10));
41381
+ setPage(1);
41382
+ } }, Array.from(new Set([...PAGE_SIZES, take]))
41383
+ .sort((a, b) => a - b)
41384
+ .map((size) => (React__default["default"].createElement("option", { key: size, value: size }, size)))),
41385
+ count !== undefined && React__default["default"].createElement("span", { className: "agent-entries__count" }, format$1(t.X_ITEMS, [count])),
41386
+ React__default["default"].createElement("div", { className: "agent-entries__pager" },
41387
+ React__default["default"].createElement("button", { type: "button", className: "agent-entries__pager__button", disabled: page <= 1, onClick: () => setPage(page - 1) }, t.PREVIOUS),
41388
+ React__default["default"].createElement("span", { className: "agent-entries__pager__info" }, totalPages !== undefined ? format$1(t.PAGE_X_OF_Y, [page, totalPages]) : page),
41389
+ React__default["default"].createElement("button", { type: "button", className: "agent-entries__pager__button", disabled: !hasNextPage, onClick: () => setPage(page + 1) }, t.NEXT))))));
41390
+ };
41391
+
40187
41392
  const ImageWithTextCard = ({ noCard, fullImage, reverse, imageSrc, imageAlt, title, section1Title, section1Text, section2Title, section2Text, buttonText, onButtonClick }) => {
40188
41393
  let cardClassName = 'image-with-text__card';
40189
41394
  if (noCard) {
@@ -44642,6 +45847,7 @@ var signalR = /*#__PURE__*/_mergeNamespaces({
44642
45847
  'default': signalR$1
44643
45848
  }, [signalR$1]);
44644
45849
 
45850
+ exports.AgentEntries = AgentEntries;
44645
45851
  exports.BookingProduct = BookingProduct;
44646
45852
  exports.BookingWizard = BookingWizard;
44647
45853
  exports.Breadcrumbs = Breadcrumbs;