@qite/tide-components 1.0.8 → 1.0.10
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.
- package/build/build-cjs/index.js +585 -319
- package/build/build-cjs/src/booking-product/types.d.ts +10 -0
- package/build/build-cjs/src/search-results/components/itinerary/itinerary-utils.d.ts +12 -0
- package/build/build-cjs/src/search-results/types.d.ts +12 -0
- package/build/build-esm/index.js +586 -320
- package/build/build-esm/src/booking-product/types.d.ts +10 -0
- package/build/build-esm/src/search-results/components/itinerary/itinerary-utils.d.ts +12 -0
- package/build/build-esm/src/search-results/types.d.ts +12 -0
- package/package.json +2 -2
- package/styles/abstracts/_mixins.scss +74 -74
- package/styles/abstracts/_variables.scss +57 -57
- package/styles/base/_fonts.scss +2 -2
- package/styles/base/_normalize.scss +227 -227
- package/styles/base/_typography.scss +35 -35
- package/styles/booking-joker-variables.scss +596 -596
- package/styles/booking-product-variables.scss +330 -330
- package/styles/booking-product.scss +438 -438
- package/styles/booking-qsm-variables.scss +501 -501
- package/styles/booking-qsm.scss +52 -52
- package/styles/booking-search-results-variables.scss +734 -734
- package/styles/booking-search-results.scss +53 -53
- package/styles/booking-wizard-variables.scss +603 -603
- package/styles/booking-wizard.scss +61 -61
- package/styles/components/_accordion.scss +67 -67
- package/styles/components/_animations.scss +39 -39
- package/styles/components/_base.scss +107 -107
- package/styles/components/_booking.scss +906 -906
- package/styles/components/_breadcrumb.scss +92 -92
- package/styles/components/_button.scss +238 -238
- package/styles/components/_checkbox.scss +230 -230
- package/styles/components/_contact.scss +255 -255
- package/styles/components/_content.scss +336 -336
- package/styles/components/_cta.scss +238 -238
- package/styles/components/_date-list.scss +41 -41
- package/styles/components/_date-range-picker.scss +223 -223
- package/styles/components/_decrement-increment.scss +35 -35
- package/styles/components/_dropdown.scss +77 -77
- package/styles/components/_error.scss +50 -50
- package/styles/components/_faq.scss +30 -30
- package/styles/components/_flight-option.scss +1432 -1432
- package/styles/components/_flyin.scss +830 -830
- package/styles/components/_footer.scss +135 -135
- package/styles/components/_form.scss +1693 -1693
- package/styles/components/_gallery.scss +317 -317
- package/styles/components/_header.scss +113 -113
- package/styles/components/_image-with-text.scss +206 -206
- package/styles/components/_img-slider.scss +175 -175
- package/styles/components/_info-message.scss +75 -75
- package/styles/components/_input.scss +35 -35
- package/styles/components/_list.scss +185 -185
- package/styles/components/_loader.scss +152 -152
- package/styles/components/_login.scss +140 -140
- package/styles/components/_map-view.scss +1100 -1100
- package/styles/components/_mixins.scss +579 -579
- package/styles/components/_navbar.scss +765 -765
- package/styles/components/_passenger-picker.scss +306 -306
- package/styles/components/_phone-input.scss +8 -8
- package/styles/components/_placeholders.scss +165 -165
- package/styles/components/_pricing-summary.scss +163 -163
- package/styles/components/_qsm.scss +17 -17
- package/styles/components/_radiobutton.scss +170 -170
- package/styles/components/_search.scss +2197 -2178
- package/styles/components/_select-wrapper.scss +81 -81
- package/styles/components/_slider.scss +128 -128
- package/styles/components/_spinner.scss +29 -29
- package/styles/components/_step-indicators.scss +187 -187
- package/styles/components/_table.scss +81 -81
- package/styles/components/_tide-form.scss +578 -578
- package/styles/components/_tree.scss +648 -648
- package/styles/components/_typeahead.scss +275 -275
- package/styles/components/_variables.scss +89 -89
- package/styles/content-blocks-variables.scss +543 -543
- package/styles/content-blocks.scss +66 -66
- package/styles/font.scss +2 -2
- package/styles/qsm/_calendar.scss +274 -274
- package/styles/qsm/_qsm.scss +1097 -1097
- package/styles/search.scss +1200 -1200
- package/styles/tide-form-variables.scss +275 -275
- package/styles/tide-form.scss +56 -56
package/build/build-esm/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import React__default, { useLayoutEffect as useLayoutEffect$1, useEffect, useContext, useState, useRef, useCallback, useMemo } from 'react';
|
|
4
4
|
import JsonURL from '@jsonurl/jsonurl';
|
|
5
|
-
import { format as format$2, isToday, getDate, startOfWeek, startOfMonth, endOfWeek, addWeeks, endOfMonth, eachDayOfInterval, getYear, getMonth, getISOWeek, getISODay, isSameMonth, startOfDay, isAfter, isEqual, isWithinInterval, endOfDay, isBefore,
|
|
5
|
+
import { format as format$2, isToday, getDate, startOfWeek, startOfMonth, endOfWeek, addWeeks, endOfMonth, eachDayOfInterval, getYear, getMonth, getISOWeek, getISODay, isSameMonth, startOfDay, isAfter, isSameDay, isEqual, isWithinInterval, endOfDay, isBefore, differenceInCalendarDays, addMonths, addDays, formatISO, addYears, differenceInYears, parseISO, differenceInMinutes, isValid, parse, startOfToday } from 'date-fns';
|
|
6
6
|
import { merge, cloneDeep, isNil, isArray as isArray$1, compact, isEmpty as isEmpty$1, range, chunk, isFunction as isFunction$1, clamp, now, omit, isPlainObject as isPlainObject$1, mapValues, pickBy, first, orderBy, uniq, uniqBy, sortBy, sum, last, findIndex as findIndex$1, set, get, isEqual as isEqual$1, groupBy, minBy, concat, flatMap } from 'lodash';
|
|
7
7
|
import { arSA, da, de, enGB, es, fr, is, it, nl, nb, pl, pt, sv, ja, enUS } from 'date-fns/locale';
|
|
8
8
|
import { usePopper } from 'react-popper';
|
|
@@ -95,7 +95,7 @@ var PRODUCT$f = {
|
|
|
95
95
|
PER_PERSON_PER_NIGHT: "لكل شخص / لكل ليلة",
|
|
96
96
|
BOOK_NOW: "احجز الآن",
|
|
97
97
|
TO_YOUR_OFFER: "إلى عرضك",
|
|
98
|
-
NOT_AVAILABLE: "غير متاح",
|
|
98
|
+
NOT_AVAILABLE: "غير متاح — يرجى اختيار تاريخ آخر",
|
|
99
99
|
NUMBER_OF_ROOMS: "عدد الغرف",
|
|
100
100
|
AGE_BY_DEPARTURE_DATE: "عمر الأطفال عند تاريخ المغادرة",
|
|
101
101
|
YEAR: "سنة/سنوات",
|
|
@@ -388,6 +388,8 @@ var SRP$f = {
|
|
|
388
388
|
DEPARTURE_ASC: "تاريخ المغادرة (الأقرب أولاً)",
|
|
389
389
|
FILTERS: "عوامل التصفية",
|
|
390
390
|
SHOW_ITINERARY: "عرض خط سير الرحلة",
|
|
391
|
+
VIEW_FULL_ITINERARY: "عرض خط السير الكامل",
|
|
392
|
+
SHOW_SERVICES: "عرض الخدمات",
|
|
391
393
|
VIEW_BOOKING: "عرض الحجز",
|
|
392
394
|
ITINERARY_TITLE: "ملخص رحلتك",
|
|
393
395
|
DOSSIER_NUMBER: "رقم الملف",
|
|
@@ -437,7 +439,7 @@ var SRP$f = {
|
|
|
437
439
|
};
|
|
438
440
|
var ITINERARY$f = {
|
|
439
441
|
DAY: "اليوم",
|
|
440
|
-
NO_ITEMS: "
|
|
442
|
+
NO_ITEMS: "لم يتم اختيار أنشطة لهذا اليوم."
|
|
441
443
|
};
|
|
442
444
|
var FORM$f = {
|
|
443
445
|
LOADING: "جاري تحميل النموذج...",
|
|
@@ -540,7 +542,7 @@ var PRODUCT$e = {
|
|
|
540
542
|
PER_PERSON_PER_NIGHT: "Per person / per nat",
|
|
541
543
|
BOOK_NOW: "Book nu",
|
|
542
544
|
TO_YOUR_OFFER: "Til dit tilbud",
|
|
543
|
-
NOT_AVAILABLE: "Ikke tilgængelig",
|
|
545
|
+
NOT_AVAILABLE: "Ikke tilgængelig — vælg venligst en anden dato",
|
|
544
546
|
NUMBER_OF_ROOMS: "Antal værelser",
|
|
545
547
|
AGE_BY_DEPARTURE_DATE: "Børns alder på afrejsedato",
|
|
546
548
|
YEAR: "år",
|
|
@@ -833,6 +835,8 @@ var SRP$e = {
|
|
|
833
835
|
DEPARTURE_ASC: "Afrejsedato (snarest først)",
|
|
834
836
|
FILTERS: "Filtre",
|
|
835
837
|
SHOW_ITINERARY: "Vis rejseplan",
|
|
838
|
+
VIEW_FULL_ITINERARY: "Se hele rejseplanen",
|
|
839
|
+
SHOW_SERVICES: "Vis ydelser",
|
|
836
840
|
VIEW_BOOKING: "Se booking",
|
|
837
841
|
ITINERARY_TITLE: "Din rejseoversigt",
|
|
838
842
|
DOSSIER_NUMBER: "Sagsnummer",
|
|
@@ -882,7 +886,7 @@ var SRP$e = {
|
|
|
882
886
|
};
|
|
883
887
|
var ITINERARY$e = {
|
|
884
888
|
DAY: "Dag",
|
|
885
|
-
NO_ITEMS: "Ingen
|
|
889
|
+
NO_ITEMS: "Ingen aktiviteter valgt for denne dag."
|
|
886
890
|
};
|
|
887
891
|
var FORM$e = {
|
|
888
892
|
LOADING: "Indlæser formular...",
|
|
@@ -985,7 +989,7 @@ var PRODUCT$d = {
|
|
|
985
989
|
PER_PERSON_PER_NIGHT: "Pro Person / pro Nacht",
|
|
986
990
|
BOOK_NOW: "Jetzt buchen",
|
|
987
991
|
TO_YOUR_OFFER: "Zu Ihrem Angebot",
|
|
988
|
-
NOT_AVAILABLE: "Nicht verfügbar",
|
|
992
|
+
NOT_AVAILABLE: "Nicht verfügbar — bitte wählen Sie ein anderes Datum",
|
|
989
993
|
NUMBER_OF_ROOMS: "Anzahl der Zimmer",
|
|
990
994
|
AGE_BY_DEPARTURE_DATE: "Alter der Kinder am Abreisedatum",
|
|
991
995
|
YEAR: "Jahr(e)",
|
|
@@ -1282,6 +1286,8 @@ var SRP$d = {
|
|
|
1282
1286
|
DEPARTURE_ASC: "Abreisedatum (früheste zuerst)",
|
|
1283
1287
|
FILTERS: "Filter",
|
|
1284
1288
|
SHOW_ITINERARY: "Reiseverlauf anzeigen",
|
|
1289
|
+
VIEW_FULL_ITINERARY: "Vollständigen Reiseverlauf ansehen",
|
|
1290
|
+
SHOW_SERVICES: "Leistungen anzeigen",
|
|
1285
1291
|
VIEW_BOOKING: "Buchung anzeigen",
|
|
1286
1292
|
ITINERARY_TITLE: "Ihre Reiseübersicht",
|
|
1287
1293
|
DOSSIER_NUMBER: "Vorgangsnummer",
|
|
@@ -1327,7 +1333,7 @@ var SRP$d = {
|
|
|
1327
1333
|
};
|
|
1328
1334
|
var ITINERARY$d = {
|
|
1329
1335
|
DAY: "Tag",
|
|
1330
|
-
NO_ITEMS: "Keine
|
|
1336
|
+
NO_ITEMS: "Keine Aktivitäten für diesen Tag ausgewählt."
|
|
1331
1337
|
};
|
|
1332
1338
|
var FORM$d = {
|
|
1333
1339
|
LOADING: "Formular wird geladen...",
|
|
@@ -1430,7 +1436,7 @@ var PRODUCT$c = {
|
|
|
1430
1436
|
PER_PERSON_PER_NIGHT: "Per person / per night",
|
|
1431
1437
|
BOOK_NOW: "Book now",
|
|
1432
1438
|
TO_YOUR_OFFER: "To your quote",
|
|
1433
|
-
NOT_AVAILABLE: "Not available",
|
|
1439
|
+
NOT_AVAILABLE: "Not available — please select a different date",
|
|
1434
1440
|
NUMBER_OF_ROOMS: "Number of rooms",
|
|
1435
1441
|
AGE_BY_DEPARTURE_DATE: "Age of children on departure date",
|
|
1436
1442
|
YEAR: "Year(s)",
|
|
@@ -1731,6 +1737,8 @@ var SRP$c = {
|
|
|
1731
1737
|
DEPARTURE_ASC: "Departure date (soonest first)",
|
|
1732
1738
|
FILTERS: "Filters",
|
|
1733
1739
|
SHOW_ITINERARY: "Show itinerary",
|
|
1740
|
+
VIEW_FULL_ITINERARY: "View full itinerary",
|
|
1741
|
+
SHOW_SERVICES: "Show services",
|
|
1734
1742
|
VIEW_BOOKING: "View booking",
|
|
1735
1743
|
ITINERARY_TITLE: "Your trip summary",
|
|
1736
1744
|
DOSSIER_NUMBER: "File number",
|
|
@@ -1776,7 +1784,7 @@ var SRP$c = {
|
|
|
1776
1784
|
};
|
|
1777
1785
|
var ITINERARY$c = {
|
|
1778
1786
|
DAY: "Day",
|
|
1779
|
-
NO_ITEMS: "No
|
|
1787
|
+
NO_ITEMS: "No activities selected for this day."
|
|
1780
1788
|
};
|
|
1781
1789
|
var FORM$c = {
|
|
1782
1790
|
LOADING: "Loading form...",
|
|
@@ -1879,7 +1887,7 @@ var PRODUCT$b = {
|
|
|
1879
1887
|
PER_PERSON_PER_NIGHT: "Por persona / por noche",
|
|
1880
1888
|
BOOK_NOW: "Reservar ahora",
|
|
1881
1889
|
TO_YOUR_OFFER: "A su presupuesto",
|
|
1882
|
-
NOT_AVAILABLE: "No disponible",
|
|
1890
|
+
NOT_AVAILABLE: "No disponible — seleccione otra fecha",
|
|
1883
1891
|
NUMBER_OF_ROOMS: "Número de habitaciones",
|
|
1884
1892
|
AGE_BY_DEPARTURE_DATE: "Edad de los niños en la fecha de salida",
|
|
1885
1893
|
YEAR: "Año(s)",
|
|
@@ -2176,6 +2184,8 @@ var SRP$b = {
|
|
|
2176
2184
|
DEPARTURE_ASC: "Fecha de salida (más próxima primero)",
|
|
2177
2185
|
FILTERS: "Filtros",
|
|
2178
2186
|
SHOW_ITINERARY: "Mostrar itinerario",
|
|
2187
|
+
VIEW_FULL_ITINERARY: "Ver itinerario completo",
|
|
2188
|
+
SHOW_SERVICES: "Ver servicios",
|
|
2179
2189
|
VIEW_BOOKING: "Ver reserva",
|
|
2180
2190
|
ITINERARY_TITLE: "Resumen de tu viaje",
|
|
2181
2191
|
DOSSIER_NUMBER: "Número de expediente",
|
|
@@ -2221,7 +2231,7 @@ var SRP$b = {
|
|
|
2221
2231
|
};
|
|
2222
2232
|
var ITINERARY$b = {
|
|
2223
2233
|
DAY: "Día",
|
|
2224
|
-
NO_ITEMS: "No hay
|
|
2234
|
+
NO_ITEMS: "No hay actividades seleccionadas para este día."
|
|
2225
2235
|
};
|
|
2226
2236
|
var FORM$b = {
|
|
2227
2237
|
LOADING: "Cargando formulario...",
|
|
@@ -2324,7 +2334,7 @@ var PRODUCT$a = {
|
|
|
2324
2334
|
PER_PERSON_PER_NIGHT: "Par personne / par nuit",
|
|
2325
2335
|
BOOK_NOW: "Réserver maintenant",
|
|
2326
2336
|
TO_YOUR_OFFER: "Vers votre devis",
|
|
2327
|
-
NOT_AVAILABLE: "Non disponible",
|
|
2337
|
+
NOT_AVAILABLE: "Non disponible — veuillez sélectionner une autre date",
|
|
2328
2338
|
NUMBER_OF_ROOMS: "Nombre de chambres",
|
|
2329
2339
|
AGE_BY_DEPARTURE_DATE: "Âge des enfants à la date de départ",
|
|
2330
2340
|
YEAR: "An(s)",
|
|
@@ -2625,6 +2635,8 @@ var SRP$a = {
|
|
|
2625
2635
|
DEPARTURE_ASC: "Date de départ (la plus proche d’abord)",
|
|
2626
2636
|
FILTERS: "Filtres",
|
|
2627
2637
|
SHOW_ITINERARY: "Afficher l’itinéraire",
|
|
2638
|
+
VIEW_FULL_ITINERARY: "Voir l'itinéraire complet",
|
|
2639
|
+
SHOW_SERVICES: "Voir les services",
|
|
2628
2640
|
VIEW_BOOKING: "Voir la réservation",
|
|
2629
2641
|
ITINERARY_TITLE: "Résumé de votre voyage",
|
|
2630
2642
|
DOSSIER_NUMBER: "Numéro de dossier",
|
|
@@ -2670,7 +2682,7 @@ var SRP$a = {
|
|
|
2670
2682
|
};
|
|
2671
2683
|
var ITINERARY$a = {
|
|
2672
2684
|
DAY: "Jour",
|
|
2673
|
-
NO_ITEMS: "
|
|
2685
|
+
NO_ITEMS: "Aucune activité sélectionnée pour ce jour."
|
|
2674
2686
|
};
|
|
2675
2687
|
var FORM$a = {
|
|
2676
2688
|
LOADING: "Chargement du formulaire...",
|
|
@@ -2773,7 +2785,7 @@ var PRODUCT$9 = {
|
|
|
2773
2785
|
PER_PERSON_PER_NIGHT: "Par personne / par nuit",
|
|
2774
2786
|
BOOK_NOW: "Réservez maintenant",
|
|
2775
2787
|
TO_YOUR_OFFER: "Vers votre devis",
|
|
2776
|
-
NOT_AVAILABLE: "Indisponible",
|
|
2788
|
+
NOT_AVAILABLE: "Indisponible — veuillez sélectionner une autre date",
|
|
2777
2789
|
NUMBER_OF_ROOMS: "Nombre de chambres",
|
|
2778
2790
|
AGE_BY_DEPARTURE_DATE: "Âge des enfants à la date de départ",
|
|
2779
2791
|
YEAR: "An(s)",
|
|
@@ -3070,6 +3082,8 @@ var SRP$9 = {
|
|
|
3070
3082
|
DEPARTURE_ASC: "Date de départ (la plus proche d’abord)",
|
|
3071
3083
|
FILTERS: "Filtres",
|
|
3072
3084
|
SHOW_ITINERARY: "Afficher l’itinéraire",
|
|
3085
|
+
VIEW_FULL_ITINERARY: "Voir l'itinéraire complet",
|
|
3086
|
+
SHOW_SERVICES: "Voir les services",
|
|
3073
3087
|
VIEW_BOOKING: "Voir la réservation",
|
|
3074
3088
|
ITINERARY_TITLE: "Résumé de votre voyage",
|
|
3075
3089
|
DOSSIER_NUMBER: "Numéro de dossier",
|
|
@@ -3115,7 +3129,7 @@ var SRP$9 = {
|
|
|
3115
3129
|
};
|
|
3116
3130
|
var ITINERARY$9 = {
|
|
3117
3131
|
DAY: "Jour",
|
|
3118
|
-
NO_ITEMS: "
|
|
3132
|
+
NO_ITEMS: "Aucune activité sélectionnée pour ce jour."
|
|
3119
3133
|
};
|
|
3120
3134
|
var FORM$9 = {
|
|
3121
3135
|
LOADING: "Chargement du formulaire...",
|
|
@@ -3218,7 +3232,7 @@ var PRODUCT$8 = {
|
|
|
3218
3232
|
PER_PERSON_PER_NIGHT: "Á mann / á nótt",
|
|
3219
3233
|
BOOK_NOW: "Panta núna",
|
|
3220
3234
|
TO_YOUR_OFFER: "Til tilboðsins þíns",
|
|
3221
|
-
NOT_AVAILABLE: "Ekki í boði",
|
|
3235
|
+
NOT_AVAILABLE: "Ekki í boði — vinsamlegast veldu aðra dagsetningu",
|
|
3222
3236
|
NUMBER_OF_ROOMS: "Fjöldi herbergja",
|
|
3223
3237
|
AGE_BY_DEPARTURE_DATE: "Aldur barna á brottfarardegi",
|
|
3224
3238
|
YEAR: "ár",
|
|
@@ -3515,6 +3529,8 @@ var SRP$8 = {
|
|
|
3515
3529
|
DEPARTURE_ASC: "Brottfarardagur (nærst fyrst)",
|
|
3516
3530
|
FILTERS: "Síur",
|
|
3517
3531
|
SHOW_ITINERARY: "Sýna ferðaráætlun",
|
|
3532
|
+
VIEW_FULL_ITINERARY: "Skoða alla ferðaáætlunina",
|
|
3533
|
+
SHOW_SERVICES: "Sýna þjónustu",
|
|
3518
3534
|
VIEW_BOOKING: "Skoða bókun",
|
|
3519
3535
|
ITINERARY_TITLE: "Yfirlit ferðarinnar",
|
|
3520
3536
|
DOSSIER_NUMBER: "Skrárnúmer",
|
|
@@ -3560,7 +3576,7 @@ var SRP$8 = {
|
|
|
3560
3576
|
};
|
|
3561
3577
|
var ITINERARY$8 = {
|
|
3562
3578
|
DAY: "Dagur",
|
|
3563
|
-
NO_ITEMS: "
|
|
3579
|
+
NO_ITEMS: "Engin afþreying valin fyrir þennan dag."
|
|
3564
3580
|
};
|
|
3565
3581
|
var FORM$8 = {
|
|
3566
3582
|
LOADING: "Hleður eyðublað...",
|
|
@@ -3663,7 +3679,7 @@ var PRODUCT$7 = {
|
|
|
3663
3679
|
PER_PERSON_PER_NIGHT: "A persona / a notte",
|
|
3664
3680
|
BOOK_NOW: "Prenota ora",
|
|
3665
3681
|
TO_YOUR_OFFER: "Vai al preventivo",
|
|
3666
|
-
NOT_AVAILABLE: "Non disponibile",
|
|
3682
|
+
NOT_AVAILABLE: "Non disponibile — seleziona un'altra data",
|
|
3667
3683
|
NUMBER_OF_ROOMS: "Numero di camere",
|
|
3668
3684
|
AGE_BY_DEPARTURE_DATE: "Età dei bambini alla data di partenza",
|
|
3669
3685
|
YEAR: "Anno/i",
|
|
@@ -3960,6 +3976,8 @@ var SRP$7 = {
|
|
|
3960
3976
|
DEPARTURE_ASC: "Data di partenza (prima la più vicina)",
|
|
3961
3977
|
FILTERS: "Filtri",
|
|
3962
3978
|
SHOW_ITINERARY: "Mostra itinerario",
|
|
3979
|
+
VIEW_FULL_ITINERARY: "Vedi l'itinerario completo",
|
|
3980
|
+
SHOW_SERVICES: "Mostra i servizi",
|
|
3963
3981
|
VIEW_BOOKING: "Visualizza prenotazione",
|
|
3964
3982
|
ITINERARY_TITLE: "Riepilogo del tuo viaggio",
|
|
3965
3983
|
DOSSIER_NUMBER: "Numero di pratica",
|
|
@@ -4005,7 +4023,7 @@ var SRP$7 = {
|
|
|
4005
4023
|
};
|
|
4006
4024
|
var ITINERARY$7 = {
|
|
4007
4025
|
DAY: "Giorno",
|
|
4008
|
-
NO_ITEMS: "
|
|
4026
|
+
NO_ITEMS: "Nessuna attività selezionata per questo giorno."
|
|
4009
4027
|
};
|
|
4010
4028
|
var FORM$7 = {
|
|
4011
4029
|
LOADING: "Caricamento modulo...",
|
|
@@ -4108,7 +4126,7 @@ var PRODUCT$6 = {
|
|
|
4108
4126
|
PER_PERSON_PER_NIGHT: "Per persoon / per nacht",
|
|
4109
4127
|
BOOK_NOW: "Boek nu",
|
|
4110
4128
|
TO_YOUR_OFFER: "Naar uw offerte",
|
|
4111
|
-
NOT_AVAILABLE: "Niet beschikbaar",
|
|
4129
|
+
NOT_AVAILABLE: "Niet beschikbaar — kies een andere datum",
|
|
4112
4130
|
NUMBER_OF_ROOMS: "Aantal kamers",
|
|
4113
4131
|
AGE_BY_DEPARTURE_DATE: "Leeftijd kinderen op vertrekdatum",
|
|
4114
4132
|
YEAR: "Jaar",
|
|
@@ -4409,6 +4427,8 @@ var SRP$6 = {
|
|
|
4409
4427
|
DEPARTURE_ASC: "Vertrekdatum (dichtstbij eerst)",
|
|
4410
4428
|
FILTERS: "Filters",
|
|
4411
4429
|
SHOW_ITINERARY: "Toon reisplan",
|
|
4430
|
+
VIEW_FULL_ITINERARY: "Bekijk volledige reisroute",
|
|
4431
|
+
SHOW_SERVICES: "Toon diensten",
|
|
4412
4432
|
VIEW_BOOKING: "Bekijk boeking",
|
|
4413
4433
|
ITINERARY_TITLE: "Overzicht van je reis",
|
|
4414
4434
|
DOSSIER_NUMBER: "Dossiernummer",
|
|
@@ -4454,7 +4474,7 @@ var SRP$6 = {
|
|
|
4454
4474
|
};
|
|
4455
4475
|
var ITINERARY$6 = {
|
|
4456
4476
|
DAY: "Dag",
|
|
4457
|
-
NO_ITEMS: "Geen
|
|
4477
|
+
NO_ITEMS: "Geen activiteiten geselecteerd voor deze dag."
|
|
4458
4478
|
};
|
|
4459
4479
|
var FORM$6 = {
|
|
4460
4480
|
LOADING: "Formulier laden...",
|
|
@@ -4557,7 +4577,7 @@ var PRODUCT$5 = {
|
|
|
4557
4577
|
PER_PERSON_PER_NIGHT: "Per persoon / per nacht",
|
|
4558
4578
|
BOOK_NOW: "Nu boeken",
|
|
4559
4579
|
TO_YOUR_OFFER: "Naar uw offerte",
|
|
4560
|
-
NOT_AVAILABLE: "Niet beschikbaar",
|
|
4580
|
+
NOT_AVAILABLE: "Niet beschikbaar — kies een andere datum",
|
|
4561
4581
|
NUMBER_OF_ROOMS: "Aantal kamers",
|
|
4562
4582
|
AGE_BY_DEPARTURE_DATE: "Leeftijd van kinderen op vertrekdatum",
|
|
4563
4583
|
YEAR: "Jaar",
|
|
@@ -4854,6 +4874,8 @@ var SRP$5 = {
|
|
|
4854
4874
|
DEPARTURE_ASC: "Vertrekdatum (dichtstbij eerst)",
|
|
4855
4875
|
FILTERS: "Filters",
|
|
4856
4876
|
SHOW_ITINERARY: "Toon reisplan",
|
|
4877
|
+
VIEW_FULL_ITINERARY: "Bekijk volledige reisroute",
|
|
4878
|
+
SHOW_SERVICES: "Toon diensten",
|
|
4857
4879
|
VIEW_BOOKING: "Bekijk boeking",
|
|
4858
4880
|
ITINERARY_TITLE: "Overzicht van je reis",
|
|
4859
4881
|
DOSSIER_NUMBER: "Dossiernummer",
|
|
@@ -4899,7 +4921,7 @@ var SRP$5 = {
|
|
|
4899
4921
|
};
|
|
4900
4922
|
var ITINERARY$5 = {
|
|
4901
4923
|
DAY: "Dag",
|
|
4902
|
-
NO_ITEMS: "Geen
|
|
4924
|
+
NO_ITEMS: "Geen activiteiten geselecteerd voor deze dag."
|
|
4903
4925
|
};
|
|
4904
4926
|
var FORM$5 = {
|
|
4905
4927
|
LOADING: "Formulier laden...",
|
|
@@ -5002,7 +5024,7 @@ var PRODUCT$4 = {
|
|
|
5002
5024
|
PER_PERSON_PER_NIGHT: "Per person / per natt",
|
|
5003
5025
|
BOOK_NOW: "Bestill nå",
|
|
5004
5026
|
TO_YOUR_OFFER: "Til ditt tilbud",
|
|
5005
|
-
NOT_AVAILABLE: "Ikke tilgjengelig",
|
|
5027
|
+
NOT_AVAILABLE: "Ikke tilgjengelig — velg en annen dato",
|
|
5006
5028
|
NUMBER_OF_ROOMS: "Antall rom",
|
|
5007
5029
|
AGE_BY_DEPARTURE_DATE: "Barnas alder på avreisedato",
|
|
5008
5030
|
YEAR: "År",
|
|
@@ -5299,6 +5321,8 @@ var SRP$4 = {
|
|
|
5299
5321
|
DEPARTURE_ASC: "Avreisedato (nærmeste først)",
|
|
5300
5322
|
FILTERS: "Filtre",
|
|
5301
5323
|
SHOW_ITINERARY: "Vis reiserute",
|
|
5324
|
+
VIEW_FULL_ITINERARY: "Se hele reiseruten",
|
|
5325
|
+
SHOW_SERVICES: "Vis tjenester",
|
|
5302
5326
|
VIEW_BOOKING: "Se bestilling",
|
|
5303
5327
|
ITINERARY_TITLE: "Din reisemåloversikt",
|
|
5304
5328
|
DOSSIER_NUMBER: "Saksnummer",
|
|
@@ -5344,7 +5368,7 @@ var SRP$4 = {
|
|
|
5344
5368
|
};
|
|
5345
5369
|
var ITINERARY$4 = {
|
|
5346
5370
|
DAY: "Dag",
|
|
5347
|
-
NO_ITEMS: "Ingen
|
|
5371
|
+
NO_ITEMS: "Ingen aktiviteter valgt for denne dagen."
|
|
5348
5372
|
};
|
|
5349
5373
|
var FORM$4 = {
|
|
5350
5374
|
LOADING: "Laster inn skjema...",
|
|
@@ -5447,7 +5471,7 @@ var PRODUCT$3 = {
|
|
|
5447
5471
|
PER_PERSON_PER_NIGHT: "Za osobę / za noc",
|
|
5448
5472
|
BOOK_NOW: "Zarezerwuj teraz",
|
|
5449
5473
|
TO_YOUR_OFFER: "Do oferty",
|
|
5450
|
-
NOT_AVAILABLE: "Niedostępne",
|
|
5474
|
+
NOT_AVAILABLE: "Niedostępne — wybierz inną datę",
|
|
5451
5475
|
NUMBER_OF_ROOMS: "Liczba pokoi",
|
|
5452
5476
|
AGE_BY_DEPARTURE_DATE: "Wiek dzieci w dniu wyjazdu",
|
|
5453
5477
|
YEAR: "Rok(lata)",
|
|
@@ -5744,6 +5768,8 @@ var SRP$3 = {
|
|
|
5744
5768
|
DEPARTURE_ASC: "Data wyjazdu (najbliższa najpierw)",
|
|
5745
5769
|
FILTERS: "Filtry",
|
|
5746
5770
|
SHOW_ITINERARY: "Pokaż plan podróży",
|
|
5771
|
+
VIEW_FULL_ITINERARY: "Zobacz pełny plan podróży",
|
|
5772
|
+
SHOW_SERVICES: "Pokaż usługi",
|
|
5747
5773
|
VIEW_BOOKING: "Zobacz rezerwację",
|
|
5748
5774
|
ITINERARY_TITLE: "Podsumowanie Twojej podróży",
|
|
5749
5775
|
DOSSIER_NUMBER: "Numer pliku",
|
|
@@ -5789,7 +5815,7 @@ var SRP$3 = {
|
|
|
5789
5815
|
};
|
|
5790
5816
|
var ITINERARY$3 = {
|
|
5791
5817
|
DAY: "Dzień",
|
|
5792
|
-
NO_ITEMS: "
|
|
5818
|
+
NO_ITEMS: "Nie wybrano atrakcji na ten dzień."
|
|
5793
5819
|
};
|
|
5794
5820
|
var FORM$3 = {
|
|
5795
5821
|
LOADING: "Ładowanie formularza...",
|
|
@@ -5892,7 +5918,7 @@ var PRODUCT$2 = {
|
|
|
5892
5918
|
PER_PERSON_PER_NIGHT: "Por pessoa / por noite",
|
|
5893
5919
|
BOOK_NOW: "Reservar agora",
|
|
5894
5920
|
TO_YOUR_OFFER: "Ir para o orçamento",
|
|
5895
|
-
NOT_AVAILABLE: "Indisponível",
|
|
5921
|
+
NOT_AVAILABLE: "Indisponível — selecione outra data",
|
|
5896
5922
|
NUMBER_OF_ROOMS: "Número de quartos",
|
|
5897
5923
|
AGE_BY_DEPARTURE_DATE: "Idade das crianças à data de partida",
|
|
5898
5924
|
YEAR: "Ano(s)",
|
|
@@ -6189,6 +6215,8 @@ var SRP$2 = {
|
|
|
6189
6215
|
DEPARTURE_ASC: "Data de partida (mais próxima primeiro)",
|
|
6190
6216
|
FILTERS: "Filtros",
|
|
6191
6217
|
SHOW_ITINERARY: "Mostrar itinerário",
|
|
6218
|
+
VIEW_FULL_ITINERARY: "Ver itinerário completo",
|
|
6219
|
+
SHOW_SERVICES: "Ver serviços",
|
|
6192
6220
|
VIEW_BOOKING: "Ver reserva",
|
|
6193
6221
|
ITINERARY_TITLE: "Resumo da sua viagem",
|
|
6194
6222
|
DOSSIER_NUMBER: "Número do processo",
|
|
@@ -6234,7 +6262,7 @@ var SRP$2 = {
|
|
|
6234
6262
|
};
|
|
6235
6263
|
var ITINERARY$2 = {
|
|
6236
6264
|
DAY: "Dia",
|
|
6237
|
-
NO_ITEMS: "
|
|
6265
|
+
NO_ITEMS: "Nenhuma atividade selecionada para este dia."
|
|
6238
6266
|
};
|
|
6239
6267
|
var FORM$2 = {
|
|
6240
6268
|
LOADING: "A carregar formulário...",
|
|
@@ -6337,7 +6365,7 @@ var PRODUCT$1 = {
|
|
|
6337
6365
|
PER_PERSON_PER_NIGHT: "Per person / per natt",
|
|
6338
6366
|
BOOK_NOW: "Boka nu",
|
|
6339
6367
|
TO_YOUR_OFFER: "Till din offert",
|
|
6340
|
-
NOT_AVAILABLE: "Ej tillgänglig",
|
|
6368
|
+
NOT_AVAILABLE: "Ej tillgänglig — välj ett annat datum",
|
|
6341
6369
|
NUMBER_OF_ROOMS: "Antal rum",
|
|
6342
6370
|
AGE_BY_DEPARTURE_DATE: "Barnens ålder vid avresedatum",
|
|
6343
6371
|
YEAR: "År",
|
|
@@ -6634,6 +6662,8 @@ var SRP$1 = {
|
|
|
6634
6662
|
DEPARTURE_ASC: "Avresedatum (närmast först)",
|
|
6635
6663
|
FILTERS: "Filter",
|
|
6636
6664
|
SHOW_ITINERARY: "Visa resplan",
|
|
6665
|
+
VIEW_FULL_ITINERARY: "Visa hela resplanen",
|
|
6666
|
+
SHOW_SERVICES: "Visa tjänster",
|
|
6637
6667
|
VIEW_BOOKING: "Visa bokning",
|
|
6638
6668
|
ITINERARY_TITLE: "Din resesammanfattning",
|
|
6639
6669
|
DOSSIER_NUMBER: "Filnummer",
|
|
@@ -6679,7 +6709,7 @@ var SRP$1 = {
|
|
|
6679
6709
|
};
|
|
6680
6710
|
var ITINERARY$1 = {
|
|
6681
6711
|
DAY: "Dag",
|
|
6682
|
-
NO_ITEMS: "Inga
|
|
6712
|
+
NO_ITEMS: "Inga aktiviteter valda för denna dag."
|
|
6683
6713
|
};
|
|
6684
6714
|
var FORM$1 = {
|
|
6685
6715
|
LOADING: "Laddar formulär...",
|
|
@@ -6782,7 +6812,7 @@ var PRODUCT = {
|
|
|
6782
6812
|
PER_PERSON_PER_NIGHT: "1名・1泊あたり",
|
|
6783
6813
|
BOOK_NOW: "今すぐ予約",
|
|
6784
6814
|
TO_YOUR_OFFER: "見積もりへ",
|
|
6785
|
-
NOT_AVAILABLE: "利用不可",
|
|
6815
|
+
NOT_AVAILABLE: "利用不可 — 別の日付をお選びください",
|
|
6786
6816
|
NUMBER_OF_ROOMS: "客室数",
|
|
6787
6817
|
AGE_BY_DEPARTURE_DATE: "出発日時点での子供の年齢",
|
|
6788
6818
|
YEAR: "歳",
|
|
@@ -7079,6 +7109,8 @@ var SRP = {
|
|
|
7079
7109
|
DEPARTURE_ASC: "出発日(早い順)",
|
|
7080
7110
|
FILTERS: "フィルター",
|
|
7081
7111
|
SHOW_ITINERARY: "旅程を表示",
|
|
7112
|
+
VIEW_FULL_ITINERARY: "旅程の詳細を見る",
|
|
7113
|
+
SHOW_SERVICES: "サービスを表示",
|
|
7082
7114
|
VIEW_BOOKING: "予約を見る",
|
|
7083
7115
|
ITINERARY_TITLE: "あなたの旅行概要",
|
|
7084
7116
|
DOSSIER_NUMBER: "ファイル番号",
|
|
@@ -7124,7 +7156,7 @@ var SRP = {
|
|
|
7124
7156
|
};
|
|
7125
7157
|
var ITINERARY = {
|
|
7126
7158
|
DAY: "日",
|
|
7127
|
-
NO_ITEMS: "
|
|
7159
|
+
NO_ITEMS: "この日に選択されたアクティビティはありません。"
|
|
7128
7160
|
};
|
|
7129
7161
|
var FORM = {
|
|
7130
7162
|
LOADING: "フォームを読み込んでいます...",
|
|
@@ -7788,6 +7820,33 @@ var TrajectNodeType = {
|
|
|
7788
7820
|
subroute: 3,
|
|
7789
7821
|
};
|
|
7790
7822
|
|
|
7823
|
+
var DurationType = {
|
|
7824
|
+
hours: 0,
|
|
7825
|
+
days: 1,
|
|
7826
|
+
nights: 2,
|
|
7827
|
+
minutes: 3,
|
|
7828
|
+
};
|
|
7829
|
+
|
|
7830
|
+
var RouteTransportType = {
|
|
7831
|
+
none: 0,
|
|
7832
|
+
privateTransport: 1,
|
|
7833
|
+
publicTransport: 2,
|
|
7834
|
+
rentalCar: 3,
|
|
7835
|
+
bus: 4,
|
|
7836
|
+
camper: 5,
|
|
7837
|
+
car: 6,
|
|
7838
|
+
charter: 7,
|
|
7839
|
+
cruise: 8,
|
|
7840
|
+
ferry: 9,
|
|
7841
|
+
flight: 10,
|
|
7842
|
+
taxi: 11,
|
|
7843
|
+
train: 12,
|
|
7844
|
+
transfer: 13,
|
|
7845
|
+
rocket: 14,
|
|
7846
|
+
walking: 15,
|
|
7847
|
+
cycling: 16,
|
|
7848
|
+
};
|
|
7849
|
+
|
|
7791
7850
|
/******************************************************************************
|
|
7792
7851
|
Copyright (c) Microsoft Corporation.
|
|
7793
7852
|
|
|
@@ -15139,6 +15198,7 @@ var submitForm = function (config, id, request, signal) {
|
|
|
15139
15198
|
exports.AllotmentType = AllotmentType;
|
|
15140
15199
|
exports.DataType = DataType;
|
|
15141
15200
|
exports.DossierType = DossierType;
|
|
15201
|
+
exports.DurationType = DurationType;
|
|
15142
15202
|
exports.EntryLineFlag = EntryLineFlag;
|
|
15143
15203
|
exports.EntryLineStatus = EntryLineStatus;
|
|
15144
15204
|
exports.ExportStatus = ExportStatus;
|
|
@@ -15151,6 +15211,7 @@ exports.PaymentType = PaymentType;
|
|
|
15151
15211
|
exports.PriceChartType = PriceChartType;
|
|
15152
15212
|
exports.RequirementType = RequirementType;
|
|
15153
15213
|
exports.RoomType = RoomType;
|
|
15214
|
+
exports.RouteTransportType = RouteTransportType;
|
|
15154
15215
|
exports.SaleType = SaleType;
|
|
15155
15216
|
exports.ServiceTokenError = ServiceTokenError;
|
|
15156
15217
|
exports.ServiceType = ServiceType;
|
|
@@ -16628,6 +16689,16 @@ const Icon = ({ name, className, title, width, height, fill }) => {
|
|
|
16628
16689
|
React__default.createElement(HTMLComment, { text: "!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc." }),
|
|
16629
16690
|
title && React__default.createElement("title", null, title),
|
|
16630
16691
|
React__default.createElement("path", { d: "M135.2 117.4l-26.1 74.6 293.8 0-26.1-74.6C372.3 104.6 360.2 96 346.6 96L165.4 96c-13.6 0-25.7 8.6-30.2 21.4zM39.6 196.8L74.8 96.3C88.3 57.8 124.6 32 165.4 32l181.2 0c40.8 0 77.1 25.8 90.6 64.3l35.2 100.5c23.2 9.6 39.6 32.5 39.6 59.2l0 192c0 17.7-14.3 32-32 32l-32 0c-17.7 0-32-14.3-32-32l0-32-320 0 0 32c0 17.7-14.3 32-32 32l-32 0c-17.7 0-32-14.3-32-32L0 256c0-26.7 16.4-49.6 39.6-59.2zM128 304a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zm288 32a32 32 0 1 0 0-64 32 32 0 1 0 0 64z", fill: "currentColor" })));
|
|
16692
|
+
case 'ui-cycling':
|
|
16693
|
+
return (React__default.createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !isEmpty$1(className)).join(' '), width: width, height: height, viewBox: "0 0 640 512", fill: fill ?? 'currentColor' },
|
|
16694
|
+
React__default.createElement(HTMLComment, { text: "!Font Awesome Free v5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc." }),
|
|
16695
|
+
title && React__default.createElement("title", null, title),
|
|
16696
|
+
React__default.createElement("path", { d: "M512.509 192.001c-16.373-.064-32.03 2.955-46.436 8.495l-77.68-125.153A24 24 0 0 0 368.001 64h-64c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h50.649l14.896 24H256.002v-16c0-8.837-7.163-16-16-16h-87.459c-13.441 0-24.777 10.999-24.536 24.437.232 13.044 10.876 23.563 23.995 23.563h48.726l-29.417 47.52c-13.433-4.83-27.904-7.483-42.992-7.52C58.094 191.83.412 249.012.002 319.236-.413 390.279 57.055 448 128.002 448c59.642 0 109.758-40.793 123.967-96h52.033a24 24 0 0 0 20.406-11.367L410.37 201.77l14.938 24.067c-25.455 23.448-41.385 57.081-41.307 94.437.145 68.833 57.899 127.051 126.729 127.719 70.606.685 128.181-55.803 129.255-125.996 1.086-70.941-56.526-129.72-127.476-129.996zM186.75 265.772c9.727 10.529 16.673 23.661 19.642 38.228h-43.306l23.664-38.228zM128.002 400c-44.112 0-80-35.888-80-80s35.888-80 80-80c5.869 0 11.586.653 17.099 1.859l-45.505 73.509C89.715 331.327 101.213 352 120.002 352h81.3c-12.37 28.225-40.562 48-73.3 48zm162.63-96h-35.624c-3.96-31.756-19.556-59.894-42.383-80.026L237.371 184h127.547l-74.286 120zm217.057 95.886c-41.036-2.165-74.049-35.692-75.627-76.755-.812-21.121 6.633-40.518 19.335-55.263l44.433 71.586c4.66 7.508 14.524 9.816 22.032 5.156l13.594-8.437c7.508-4.66 9.817-14.524 5.156-22.032l-44.468-71.643a79.901 79.901 0 0 1 19.858-2.497c44.112 0 80 35.888 80 80-.001 45.54-38.252 82.316-84.313 79.885z", fill: "currentColor" })));
|
|
16697
|
+
case 'ui-walking':
|
|
16698
|
+
return (React__default.createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !isEmpty$1(className)).join(' '), width: width, height: height, viewBox: "0 0 320 512", fill: fill ?? 'currentColor' },
|
|
16699
|
+
React__default.createElement(HTMLComment, { text: "!Font Awesome Free v5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc." }),
|
|
16700
|
+
title && React__default.createElement("title", null, title),
|
|
16701
|
+
React__default.createElement("path", { d: "M208 96c26.5 0 48-21.5 48-48S234.5 0 208 0s-48 21.5-48 48 21.5 48 48 48zm94.5 149.1l-23.3-11.8-9.7-29.4c-14.7-44.6-55.7-75.8-102.2-75.9-36-.1-55.9 10.1-93.3 25.2-21.6 8.7-39.3 25.2-49.7 46.2L17.6 213c-7.8 15.8-1.5 35 14.2 42.9 15.6 7.9 34.6 1.5 42.5-14.3L81 228c3.5-7 9.3-12.5 16.5-15.4l26.8-10.8-15.2 60.7c-5.2 20.8.4 42.9 14.9 58.8l59.9 65.4c7.2 7.9 12.3 17.4 14.9 27.7l18.3 73.3c4.3 17.1 21.7 27.6 38.8 23.3 17.1-4.3 27.6-21.7 23.3-38.8l-22.2-89c-2.6-10.3-7.7-19.9-14.9-27.7l-45.5-49.7 17.2-68.7 5.5 16.5c5.3 16.1 16.7 29.4 31.7 37l23.3 11.8c15.6 7.9 34.6 1.5 42.5-14.3 7.7-15.7 1.4-35.1-14.3-43zM73.6 385.8c-3.2 8.1-8 15.4-14.2 21.5l-50 50.1c-12.5 12.5-12.5 32.8 0 45.3s32.7 12.5 45.2 0l59.4-59.4c6.1-6.1 10.9-13.4 14.2-21.5l13.5-33.8c-55.3-60.3-38.7-41.8-47.4-53.7l-20.7 51.5z", fill: "currentColor" })));
|
|
16631
16702
|
case 'ui-bus':
|
|
16632
16703
|
return (React__default.createElement("svg", { className: ['icon', `icon--${name}`, className].filter((className) => !isEmpty$1(className)).join(' '), width: width, height: height, viewBox: "0 0 512 512", fill: fill ?? 'currentColor' },
|
|
16633
16704
|
title && React__default.createElement("title", null, title),
|
|
@@ -16941,10 +17012,10 @@ const DateRangePicker$1 = (props) => {
|
|
|
16941
17012
|
month: getMonth(new Date())
|
|
16942
17013
|
});
|
|
16943
17014
|
const [isWaitingForToDate, setWaitingForToDate] = useState(false);
|
|
16944
|
-
const { searchType = 0 } = useContext(SettingsContext$1);
|
|
17015
|
+
const { searchType = 0, allowSingleDayDateSelect = false } = useContext(SettingsContext$1);
|
|
16945
17016
|
const handleDayClick = (day) => {
|
|
16946
17017
|
const { onSelectionChange } = props;
|
|
16947
|
-
if (isWaitingForToDate && !isNil(fromDate) && isAfter(day, fromDate)) {
|
|
17018
|
+
if (isWaitingForToDate && !isNil(fromDate) && (isAfter(day, fromDate) || (allowSingleDayDateSelect && isSameDay(day, fromDate)))) {
|
|
16948
17019
|
if (searchType === 1) {
|
|
16949
17020
|
// Only allow selecting the exact toDate
|
|
16950
17021
|
const expectedToDate = props.toDateByFromDate?.(fromDate);
|
|
@@ -16985,7 +17056,7 @@ const DateRangePicker$1 = (props) => {
|
|
|
16985
17056
|
}
|
|
16986
17057
|
};
|
|
16987
17058
|
const handleDayMouseOver = (day) => {
|
|
16988
|
-
if (isWaitingForToDate && (isNil(fromDate) ||
|
|
17059
|
+
if (isWaitingForToDate && (isNil(fromDate) || isSameDay(day, fromDate) || isAfter(day, fromDate))) {
|
|
16989
17060
|
setToDate(day);
|
|
16990
17061
|
}
|
|
16991
17062
|
};
|
|
@@ -21753,6 +21824,7 @@ const OptionRoom = ({ packageRoom, pax, optionPax, onRoomChange, includedService
|
|
|
21753
21824
|
|
|
21754
21825
|
function useOfferPrinter({ bookingPackage, getPax, tagIds = [], printActionId = null, onPrinted }) {
|
|
21755
21826
|
const settings = useContext(SettingsContext);
|
|
21827
|
+
const apiSettings = useSelector(selectApiSettings);
|
|
21756
21828
|
if (!settings)
|
|
21757
21829
|
throw new Error('useOfferPrinter must be used inside <BookingWizard>');
|
|
21758
21830
|
const { language, officeId } = settings;
|
|
@@ -21781,9 +21853,9 @@ function useOfferPrinter({ bookingPackage, getPax, tagIds = [], printActionId =
|
|
|
21781
21853
|
customerRequests: []
|
|
21782
21854
|
}
|
|
21783
21855
|
};
|
|
21784
|
-
const cfg = buildTideClientConfig();
|
|
21856
|
+
const cfg = buildTideClientConfig(apiSettings);
|
|
21785
21857
|
return build.book(cfg, request, undefined, language);
|
|
21786
|
-
}, [agentId, bookingPackage, getPax, language, officeId, tagIds]);
|
|
21858
|
+
}, [agentId, apiSettings, bookingPackage, getPax, language, officeId, tagIds]);
|
|
21787
21859
|
const languageData = [
|
|
21788
21860
|
{ code: 'nl-BE', tideId: 1 },
|
|
21789
21861
|
{ code: 'fr-BE', tideId: 2 },
|
|
@@ -21793,7 +21865,7 @@ function useOfferPrinter({ bookingPackage, getPax, tagIds = [], printActionId =
|
|
|
21793
21865
|
return languageData.find((l) => l.code === code)?.tideId || 1;
|
|
21794
21866
|
}
|
|
21795
21867
|
const printOffer = useCallback(async (offer) => {
|
|
21796
|
-
const cfg = buildTideClientConfig();
|
|
21868
|
+
const cfg = buildTideClientConfig(apiSettings);
|
|
21797
21869
|
const req = {
|
|
21798
21870
|
id: printActionId ?? 0,
|
|
21799
21871
|
dossierNumber: offer.dossierNumber ?? offer.number,
|
|
@@ -21804,7 +21876,7 @@ function useOfferPrinter({ bookingPackage, getPax, tagIds = [], printActionId =
|
|
|
21804
21876
|
const url = URL.createObjectURL(new Blob([buf], { type: 'application/pdf' }));
|
|
21805
21877
|
onPrinted?.(url);
|
|
21806
21878
|
window.open(url);
|
|
21807
|
-
}, [language, onPrinted]);
|
|
21879
|
+
}, [apiSettings, language, onPrinted, printActionId]);
|
|
21808
21880
|
const handlePrint = useCallback(async () => {
|
|
21809
21881
|
try {
|
|
21810
21882
|
setStage('creating');
|
|
@@ -28004,8 +28076,97 @@ const getServiceTypeBadgeModifier = (serviceType) => {
|
|
|
28004
28076
|
return '';
|
|
28005
28077
|
}
|
|
28006
28078
|
};
|
|
28079
|
+
// DurationType, as the SDK numbers it.
|
|
28080
|
+
const DURATION_HOURS = 0;
|
|
28081
|
+
const DURATION_DAYS = 1;
|
|
28082
|
+
const DURATION_NIGHTS = 2;
|
|
28083
|
+
const DURATION_MINUTES = 3;
|
|
28084
|
+
/**
|
|
28085
|
+
* How long a node takes, in the same shape the flight legs are written in — an hour count only
|
|
28086
|
+
* once there is one, so a short drive reads as plain minutes.
|
|
28087
|
+
*/
|
|
28088
|
+
const getTrajectNodeDuration = (node) => {
|
|
28089
|
+
const minutes = toMinutes(node);
|
|
28090
|
+
if (!minutes)
|
|
28091
|
+
return '';
|
|
28092
|
+
const hours = Math.floor(minutes / 60);
|
|
28093
|
+
const rest = minutes % 60;
|
|
28094
|
+
return hours ? `${hours}h ${rest.toString().padStart(2, '0')}m` : `${rest} min`;
|
|
28095
|
+
};
|
|
28096
|
+
const toMinutes = (node) => {
|
|
28097
|
+
const duration = node.duration ?? 0;
|
|
28098
|
+
if (duration <= 0)
|
|
28099
|
+
return 0;
|
|
28100
|
+
switch (node.durationType) {
|
|
28101
|
+
case DURATION_MINUTES:
|
|
28102
|
+
return duration;
|
|
28103
|
+
case DURATION_HOURS:
|
|
28104
|
+
return duration * 60;
|
|
28105
|
+
case DURATION_DAYS:
|
|
28106
|
+
case DURATION_NIGHTS:
|
|
28107
|
+
return duration * 24 * 60;
|
|
28108
|
+
default:
|
|
28109
|
+
return 0;
|
|
28110
|
+
}
|
|
28111
|
+
};
|
|
28112
|
+
// RouteTransportType, as the SDK numbers it. It says how a leg is travelled, which is not the
|
|
28113
|
+
// same question as what was sold: cycling and walking have no service type of their own.
|
|
28114
|
+
const TRANSPORT_PRIVATE = 1;
|
|
28115
|
+
const TRANSPORT_PUBLIC = 2;
|
|
28116
|
+
const TRANSPORT_RENTAL_CAR = 3;
|
|
28117
|
+
const TRANSPORT_BUS = 4;
|
|
28118
|
+
const TRANSPORT_CAMPER = 5;
|
|
28119
|
+
const TRANSPORT_CAR = 6;
|
|
28120
|
+
const TRANSPORT_CHARTER = 7;
|
|
28121
|
+
const TRANSPORT_CRUISE = 8;
|
|
28122
|
+
const TRANSPORT_FERRY = 9;
|
|
28123
|
+
const TRANSPORT_FLIGHT = 10;
|
|
28124
|
+
const TRANSPORT_TAXI = 11;
|
|
28125
|
+
const TRANSPORT_TRAIN = 12;
|
|
28126
|
+
const TRANSPORT_TRANSFER = 13;
|
|
28127
|
+
const TRANSPORT_WALKING = 15;
|
|
28128
|
+
const TRANSPORT_CYCLING = 16;
|
|
28129
|
+
/** Icon per way of travelling, where the route records one. */
|
|
28130
|
+
const getTransportTypeIcon = (transportType) => {
|
|
28131
|
+
switch (transportType) {
|
|
28132
|
+
case TRANSPORT_WALKING:
|
|
28133
|
+
return 'ui-walking';
|
|
28134
|
+
case TRANSPORT_CYCLING:
|
|
28135
|
+
return 'ui-cycling';
|
|
28136
|
+
case TRANSPORT_PRIVATE:
|
|
28137
|
+
case TRANSPORT_RENTAL_CAR:
|
|
28138
|
+
case TRANSPORT_CAMPER:
|
|
28139
|
+
case TRANSPORT_CAR:
|
|
28140
|
+
return 'ui-car';
|
|
28141
|
+
case TRANSPORT_TAXI:
|
|
28142
|
+
case TRANSPORT_TRANSFER:
|
|
28143
|
+
return 'ui-transfer';
|
|
28144
|
+
case TRANSPORT_PUBLIC:
|
|
28145
|
+
case TRANSPORT_BUS:
|
|
28146
|
+
return 'ui-bus';
|
|
28147
|
+
case TRANSPORT_TRAIN:
|
|
28148
|
+
return 'ui-train';
|
|
28149
|
+
case TRANSPORT_CRUISE:
|
|
28150
|
+
case TRANSPORT_FERRY:
|
|
28151
|
+
return 'ui-ship';
|
|
28152
|
+
case TRANSPORT_FLIGHT:
|
|
28153
|
+
case TRANSPORT_CHARTER:
|
|
28154
|
+
return 'ui-plane';
|
|
28155
|
+
default:
|
|
28156
|
+
return null;
|
|
28157
|
+
}
|
|
28158
|
+
};
|
|
28007
28159
|
const POI_TRAJECT_NODE_TYPE = 2;
|
|
28008
|
-
|
|
28160
|
+
/**
|
|
28161
|
+
* A point of interest is a place on the map rather than a service, so it gets a marker. Anything
|
|
28162
|
+
* else goes by how it is travelled where the route says so — a leg on foot or by bike is sold as
|
|
28163
|
+
* nothing, and its service type falls back to a transfer — and by what it is where it does not.
|
|
28164
|
+
*/
|
|
28165
|
+
const getTrajectNodeIcon = (node) => {
|
|
28166
|
+
if (node.trajectNodeType === POI_TRAJECT_NODE_TYPE)
|
|
28167
|
+
return 'ui-location';
|
|
28168
|
+
return getTransportTypeIcon(node.transportType) ?? getServiceTypeIcon(node.serviceType);
|
|
28169
|
+
};
|
|
28009
28170
|
const getTrajectNodeBadgeModifier = (node) => node.trajectNodeType === POI_TRAJECT_NODE_TYPE ? 'poi' : getServiceTypeBadgeModifier(node.serviceType);
|
|
28010
28171
|
|
|
28011
28172
|
const REGULAR_TRAJECT_NODE_TYPE = 0;
|
|
@@ -28072,8 +28233,6 @@ const buildTrajectNodeRequest = ({ node, line }, context, productCode, destinati
|
|
|
28072
28233
|
language: context.language,
|
|
28073
28234
|
serviceType: node.serviceType,
|
|
28074
28235
|
fromDate: toDateOnlyString(line.from),
|
|
28075
|
-
// An excursion happens on a day rather than over a span. The traject gives its line an end a day
|
|
28076
|
-
// out, the way a night is counted, which asks the search for a window it does not have.
|
|
28077
28236
|
toDate: toDateOnlyString(node.serviceType === EXCURSION_SERVICE_TYPE ? line.from : line.to),
|
|
28078
28237
|
destination: destination ?? buildDestination(line, node),
|
|
28079
28238
|
productCode,
|
|
@@ -28444,6 +28603,8 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
|
|
|
28444
28603
|
trajectNodeType: REGULAR_TRAJECT_NODE_TYPE,
|
|
28445
28604
|
requirementType: 0,
|
|
28446
28605
|
contentSource: 0,
|
|
28606
|
+
duration: 0,
|
|
28607
|
+
durationType: 0,
|
|
28447
28608
|
alternatives: [],
|
|
28448
28609
|
from: line.from,
|
|
28449
28610
|
to: line.to
|
|
@@ -28477,6 +28638,8 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
|
|
|
28477
28638
|
React__default.createElement("p", null, format$2(new Date(value), 'MMM'))));
|
|
28478
28639
|
const renderConnectingNode = ({ node }) => {
|
|
28479
28640
|
const distance = node.distanceInKm ? `${Math.round(node.distanceInKm)} km` : '';
|
|
28641
|
+
// How long the hop takes and how far it is, the way the traject editor puts them.
|
|
28642
|
+
const journey = [getTrajectNodeDuration(node), distance].filter(Boolean).join(' · ');
|
|
28480
28643
|
return (React__default.createElement("div", { className: "search__filter__itinerary__transport", key: `connect-${node.nodeId}` },
|
|
28481
28644
|
React__default.createElement("div", { className: "search__filter__itinerary__transport-timeline" },
|
|
28482
28645
|
React__default.createElement("div", { className: "search__filter__itinerary__transport-timeline-line" })),
|
|
@@ -28485,8 +28648,8 @@ const TrajectItinerary = ({ trajectEntry, packagingEntry, translations }) => {
|
|
|
28485
28648
|
React__default.createElement("div", { className: badgeClass('transport', getTrajectNodeBadgeModifier(node)) },
|
|
28486
28649
|
React__default.createElement(Icon, { name: getTrajectNodeIcon(node), height: 15 })),
|
|
28487
28650
|
React__default.createElement("div", { className: "search__filter__itinerary__transport-details" },
|
|
28488
|
-
React__default.createElement("h6", null, node.name ||
|
|
28489
|
-
!!node.name && !!
|
|
28651
|
+
React__default.createElement("h6", null, node.name || journey),
|
|
28652
|
+
!!node.name && !!journey && React__default.createElement("p", { className: "search__filter__itinerary__transport-details-time" }, journey)))));
|
|
28490
28653
|
};
|
|
28491
28654
|
const renderOvernight = (item, index) => {
|
|
28492
28655
|
const { dayOrder } = item.node;
|
|
@@ -28630,7 +28793,7 @@ const getServiceTypePriority = (serviceType) => {
|
|
|
28630
28793
|
const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation }) => {
|
|
28631
28794
|
const context = useContext(SearchResultsConfigurationContext);
|
|
28632
28795
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
28633
|
-
const { editablePackagingEntry, priceDetails } = useSelector((state) => state.searchResults);
|
|
28796
|
+
const { editablePackagingEntry, priceDetails, trajectItineraryView } = useSelector((state) => state.searchResults);
|
|
28634
28797
|
const dispatch = useDispatch();
|
|
28635
28798
|
const packagingEntry = editablePackagingEntry ?? context?.packagingEntry;
|
|
28636
28799
|
const sortedLines = useMemo(() => {
|
|
@@ -28673,6 +28836,11 @@ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation })
|
|
|
28673
28836
|
const handleConfirm = () => {
|
|
28674
28837
|
dispatch(setBookPackagingEntry(true));
|
|
28675
28838
|
};
|
|
28839
|
+
const handleTrajectView = (itinerary) => {
|
|
28840
|
+
dispatch(setTrajectItineraryView(itinerary));
|
|
28841
|
+
if (typeof window !== 'undefined')
|
|
28842
|
+
window.scrollTo(0, 0);
|
|
28843
|
+
};
|
|
28676
28844
|
return (React__default.createElement("div", { className: `search__filters--modal ${isOpen ? 'is-open' : ''}` },
|
|
28677
28845
|
React__default.createElement("div", { className: "search__filters--background", onClick: handleSetIsOpen }),
|
|
28678
28846
|
React__default.createElement("button", { className: "search__filters--close", onClick: handleSetIsOpen },
|
|
@@ -28700,7 +28868,8 @@ const Itinerary = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation })
|
|
|
28700
28868
|
" ",
|
|
28701
28869
|
translations.SRP.TOTAL,
|
|
28702
28870
|
")"))),
|
|
28703
|
-
React__default.createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM)
|
|
28871
|
+
React__default.createElement("button", { className: "cta", onClick: handleConfirm }, translations.QSM.CONFIRM),
|
|
28872
|
+
!!context?.trajectEntry && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleTrajectView(!trajectItineraryView) }, trajectItineraryView ? translations.SRP.SHOW_SERVICES : translations.SRP.VIEW_FULL_ITINERARY))))),
|
|
28704
28873
|
React__default.createElement("div", { className: "search__filter__itinerary" },
|
|
28705
28874
|
React__default.createElement("p", null, translations.SRP.DAY_BY_DAY),
|
|
28706
28875
|
firstEntryLine && (React__default.createElement("div", { className: "search__filter__itinerary__country" },
|
|
@@ -30983,7 +31152,7 @@ const Filters = ({ initialFilters, filters, isOpen, handleSetIsOpen, isLoading,
|
|
|
30983
31152
|
const max = filter.max ?? 100;
|
|
30984
31153
|
const selectedMin = filter.selectedMin ?? min;
|
|
30985
31154
|
const selectedMax = filter.selectedMax ?? max;
|
|
30986
|
-
return (React__default.createElement(MultiRangeFilter, { min: min, max: max, selectedMin: selectedMin, selectedMax: selectedMax, valueFormatter: (value) => `${value}
|
|
31155
|
+
return (React__default.createElement(MultiRangeFilter, { min: min, max: max, selectedMin: selectedMin, selectedMax: selectedMax, valueFormatter: (value) => (filter.property === 'price' ? value.toFixed(2).replace('.', ',') : `${value}`), onChange: (newMin, newMax) => {
|
|
30987
31156
|
handleSliderChange(filter, newMin, newMax);
|
|
30988
31157
|
} }));
|
|
30989
31158
|
})(),
|
|
@@ -31686,7 +31855,7 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
|
|
|
31686
31855
|
dispatch(setBookPackagingEntry(true));
|
|
31687
31856
|
}
|
|
31688
31857
|
};
|
|
31689
|
-
return (React__default.createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' || flyInType === 'traject-day-activities' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
|
|
31858
|
+
return (React__default.createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' || flyInType === 'traject-day-activities' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
|
|
31690
31859
|
${flyInType === 'flight-outward-results' || flyInType === 'flight-return-results' || flyInType === 'traject-flight-results' ? 'flyin--flight' : ''}` },
|
|
31691
31860
|
React__default.createElement("div", { className: `flyin__panel ${isOpen ? 'flyin__panel--active' : ''}`, ref: panelRef },
|
|
31692
31861
|
React__default.createElement("div", { className: "flyin__content" },
|
|
@@ -32475,7 +32644,7 @@ const FlightFilters = ({ isOpen, handleSetIsOpen, isLoading }) => {
|
|
|
32475
32644
|
!isEmpty$1(priceRangeValues) &&
|
|
32476
32645
|
(() => {
|
|
32477
32646
|
return (React__default.createElement("div", { className: "search__filter-rows" },
|
|
32478
|
-
React__default.createElement(MultiRangeFilter, { min: minPrice, max: maxPrice, selectedMin: first(priceRangeValues) ?? minPrice, selectedMax: last(priceRangeValues) ?? maxPrice, valueFormatter: (value) => `€${value}`, onChange: (newMin, newMax) => {
|
|
32647
|
+
React__default.createElement(MultiRangeFilter, { min: minPrice, max: maxPrice, selectedMin: first(priceRangeValues) ?? minPrice, selectedMax: last(priceRangeValues) ?? maxPrice, valueFormatter: (value) => `€${value.toFixed(2).replace('.', ',')}`, onChange: (newMin, newMax) => {
|
|
32479
32648
|
handlePriceSliderChange([newMin, newMax]);
|
|
32480
32649
|
} })));
|
|
32481
32650
|
})()))))));
|
|
@@ -33153,6 +33322,27 @@ const getRequestRoomsFromPackagingSegments = (entry, segments) => {
|
|
|
33153
33322
|
}));
|
|
33154
33323
|
};
|
|
33155
33324
|
|
|
33325
|
+
/**
|
|
33326
|
+
* The entry to send to the backend, as opposed to the one the page works with.
|
|
33327
|
+
*
|
|
33328
|
+
* They differ only for a traject: the page keeps the line guids the traject was rendered with,
|
|
33329
|
+
* because that is what joins its nodes to its lines, while pricing and booking need the guids the
|
|
33330
|
+
* searches cached their lines under. Anything else passes through untouched, so this can be used
|
|
33331
|
+
* wherever the entry leaves the component without checking which flow is running.
|
|
33332
|
+
*/
|
|
33333
|
+
const useBookableEntry = () => {
|
|
33334
|
+
const context = useContext(SearchResultsConfigurationContext);
|
|
33335
|
+
const { editablePackagingEntry, trajectNodeAvailability, trajectFlightAvailability } = useSelector((state) => state.searchResults);
|
|
33336
|
+
const trajectEntry = context?.trajectEntry;
|
|
33337
|
+
return useMemo(() => {
|
|
33338
|
+
if (!editablePackagingEntry)
|
|
33339
|
+
return null;
|
|
33340
|
+
if (!trajectEntry)
|
|
33341
|
+
return editablePackagingEntry;
|
|
33342
|
+
return withCachedEntryLineGuids(editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability);
|
|
33343
|
+
}, [editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability]);
|
|
33344
|
+
};
|
|
33345
|
+
|
|
33156
33346
|
const escapeHtml = (value) => {
|
|
33157
33347
|
if (!value)
|
|
33158
33348
|
return '';
|
|
@@ -33211,12 +33401,62 @@ const findAccommodationForDay = (nodes, currentDay) => {
|
|
|
33211
33401
|
}
|
|
33212
33402
|
return null;
|
|
33213
33403
|
};
|
|
33214
|
-
const
|
|
33404
|
+
const formatTime = (time) => (time ? time.slice(0, 5) : '');
|
|
33405
|
+
/**
|
|
33406
|
+
* Whether generated content actually shows something.
|
|
33407
|
+
*
|
|
33408
|
+
* A content view whose data is missing still returns its wrapper markup, or the whitespace left by
|
|
33409
|
+
* a guard around its body — markup that renders as a blank gap. Only text or an image counts as
|
|
33410
|
+
* something the traveller can read.
|
|
33411
|
+
*/
|
|
33412
|
+
const hasVisibleContent = (contents) => {
|
|
33413
|
+
if (!contents)
|
|
33414
|
+
return false;
|
|
33415
|
+
if (/<(img|svg|picture|video|iframe)\b/i.test(contents))
|
|
33416
|
+
return true;
|
|
33417
|
+
return (contents
|
|
33418
|
+
.replace(/<[^>]*>/g, ' ')
|
|
33419
|
+
.replace(/ /gi, ' ')
|
|
33420
|
+
.trim().length > 0);
|
|
33421
|
+
};
|
|
33422
|
+
/** The legs of a flight, as the entry line records them. */
|
|
33423
|
+
const buildFlightHtml = (line) => {
|
|
33424
|
+
const flightLines = line.flightInformation?.flightLines ?? [];
|
|
33425
|
+
if (!flightLines.length)
|
|
33426
|
+
return '';
|
|
33427
|
+
const legs = flightLines
|
|
33428
|
+
.map((leg) => {
|
|
33429
|
+
const from = escapeHtml(leg.departureAirportDescription || leg.departureAirportCode);
|
|
33430
|
+
const to = escapeHtml(leg.arrivalAirportDescription || leg.arrivalAirportCode);
|
|
33431
|
+
const carrier = escapeHtml([leg.airlineDescription, leg.flightNumber].filter(Boolean).join(' '));
|
|
33432
|
+
return `<li>${from} ${formatTime(leg.departureTime)} → ${to} ${formatTime(leg.arrivalTime)}${carrier ? ` · ${carrier}` : ''}</li>`;
|
|
33433
|
+
})
|
|
33434
|
+
.join('');
|
|
33435
|
+
return `<ul class="itinerary-item__legs">${legs}</ul>`;
|
|
33436
|
+
};
|
|
33437
|
+
/**
|
|
33438
|
+
* What to show for an item the generator returned no content for.
|
|
33439
|
+
*
|
|
33440
|
+
* An item comes back with a title and a template but an empty body whenever its template has no
|
|
33441
|
+
* content view of its own — flights, today. Rendering that empty body leaves a blank where a
|
|
33442
|
+
* service should be, so what the entry already knows about the line is drawn instead.
|
|
33443
|
+
*/
|
|
33444
|
+
const buildFallbackHtml = (item, line) => {
|
|
33445
|
+
const details = [line?.accommodationName, line?.regimeName].filter(Boolean).join(' — ');
|
|
33446
|
+
return `
|
|
33447
|
+
<div class="itinerary-item__fallback">
|
|
33448
|
+
<h3 class="itinerary-item__fallback-title">${escapeHtml(item.title)}</h3>
|
|
33449
|
+
${line ? buildFlightHtml(line) : ''}
|
|
33450
|
+
${details ? `<p class="itinerary-item__fallback-details">${escapeHtml(details)}</p>` : ''}
|
|
33451
|
+
</div>
|
|
33452
|
+
`;
|
|
33453
|
+
};
|
|
33454
|
+
const buildItineraryHtml = (itinerary, translations, lines) => {
|
|
33215
33455
|
if (!itinerary) {
|
|
33216
|
-
return `
|
|
33217
|
-
<div class="itinerary-shell">
|
|
33218
|
-
<div class="itinerary-empty">Geen reisroute beschikbaar.</div>
|
|
33219
|
-
</div>
|
|
33456
|
+
return `
|
|
33457
|
+
<div class="itinerary-shell">
|
|
33458
|
+
<div class="itinerary-empty">Geen reisroute beschikbaar.</div>
|
|
33459
|
+
</div>
|
|
33220
33460
|
`;
|
|
33221
33461
|
}
|
|
33222
33462
|
const allNodes = itinerary.nodes ?? [];
|
|
@@ -33230,75 +33470,81 @@ const buildItineraryHtml = (itinerary, translations) => {
|
|
|
33230
33470
|
const hasAccommodationInCurrentNode = uniqueItems.some(isAccommodationItem);
|
|
33231
33471
|
const activeAccommodation = findAccommodationForDay(allNodes, startDay);
|
|
33232
33472
|
const accommodationBanner = !hasAccommodationInCurrentNode && activeAccommodation
|
|
33233
|
-
? `
|
|
33234
|
-
<div class="itinerary-node__accommodation-banner">
|
|
33235
|
-
Accommodatie voor deze dag: <strong>${escapeHtml(getAccommodationName(activeAccommodation))}</strong>
|
|
33236
|
-
</div>
|
|
33473
|
+
? `
|
|
33474
|
+
<div class="itinerary-node__accommodation-banner">
|
|
33475
|
+
Accommodatie voor deze dag: <strong>${escapeHtml(getAccommodationName(activeAccommodation))}</strong>
|
|
33476
|
+
</div>
|
|
33237
33477
|
`
|
|
33238
33478
|
: '';
|
|
33239
33479
|
const itemsHtml = hasItems
|
|
33240
33480
|
? uniqueItems
|
|
33241
|
-
.map((item) => `
|
|
33242
|
-
<article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
|
|
33243
|
-
${item.contents
|
|
33244
|
-
|
|
33481
|
+
.map((item) => `
|
|
33482
|
+
<article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
|
|
33483
|
+
${hasVisibleContent(item.contents)
|
|
33484
|
+
? item.contents
|
|
33485
|
+
: buildFallbackHtml(item, lines.find((line) => line.guid === item.itemGuid))}
|
|
33486
|
+
</article>
|
|
33245
33487
|
`)
|
|
33246
33488
|
.join('')
|
|
33247
33489
|
: `<div class="itinerary-node__empty">${translations.ITINERARY.NO_ITEMS}</div>`;
|
|
33248
|
-
return `
|
|
33249
|
-
<section class="itinerary-node">
|
|
33250
|
-
<header class="itinerary-node__header">
|
|
33251
|
-
|
|
33252
|
-
<div class="itinerary-node__day">
|
|
33253
|
-
<p class="itinerary-node__day-day">${day}</p>
|
|
33254
|
-
<p class="itinerary-node__day-month">${month}</p>
|
|
33255
|
-
</div>
|
|
33256
|
-
|
|
33257
|
-
<div>
|
|
33258
|
-
<h2 class="itinerary-node__title">${escapeHtml(node.title)}</h2>
|
|
33259
|
-
</div>
|
|
33260
|
-
</header>
|
|
33261
|
-
|
|
33262
|
-
<div class="itinerary-node__content">
|
|
33263
|
-
${accommodationBanner}
|
|
33264
|
-
${itemsHtml}
|
|
33265
|
-
</div>
|
|
33266
|
-
</section>
|
|
33490
|
+
return `
|
|
33491
|
+
<section class="itinerary-node">
|
|
33492
|
+
<header class="itinerary-node__header">
|
|
33493
|
+
|
|
33494
|
+
<div class="itinerary-node__day">
|
|
33495
|
+
<p class="itinerary-node__day-day">${day}</p>
|
|
33496
|
+
<p class="itinerary-node__day-month">${month}</p>
|
|
33497
|
+
</div>
|
|
33498
|
+
|
|
33499
|
+
<div>
|
|
33500
|
+
<h2 class="itinerary-node__title">${escapeHtml(node.title)}</h2>
|
|
33501
|
+
</div>
|
|
33502
|
+
</header>
|
|
33503
|
+
|
|
33504
|
+
<div class="itinerary-node__content">
|
|
33505
|
+
${accommodationBanner}
|
|
33506
|
+
${itemsHtml}
|
|
33507
|
+
</div>
|
|
33508
|
+
</section>
|
|
33267
33509
|
`;
|
|
33268
33510
|
})
|
|
33269
33511
|
.join('');
|
|
33270
33512
|
const defaultItemsHtml = itinerary.defaultItems && itinerary.defaultItems.length > 0
|
|
33271
|
-
? `
|
|
33272
|
-
<section class="itinerary-default-items">
|
|
33273
|
-
<h2 class="itinerary-default-items__title">Algemene info</h2>
|
|
33513
|
+
? `
|
|
33514
|
+
<section class="itinerary-default-items">
|
|
33515
|
+
<h2 class="itinerary-default-items__title">Algemene info</h2>
|
|
33274
33516
|
${getUniqueItems(itinerary.defaultItems)
|
|
33275
|
-
.map((item) => `
|
|
33276
|
-
<article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
|
|
33277
|
-
${item.contents
|
|
33278
|
-
|
|
33517
|
+
.map((item) => `
|
|
33518
|
+
<article class="itinerary-item" data-template="${escapeHtml(item.templateName)}">
|
|
33519
|
+
${hasVisibleContent(item.contents)
|
|
33520
|
+
? item.contents
|
|
33521
|
+
: buildFallbackHtml(item, lines.find((line) => line.guid === item.itemGuid))}
|
|
33522
|
+
</article>
|
|
33279
33523
|
`)
|
|
33280
|
-
.join('')}
|
|
33281
|
-
</section>
|
|
33524
|
+
.join('')}
|
|
33525
|
+
</section>
|
|
33282
33526
|
`
|
|
33283
33527
|
: '';
|
|
33284
|
-
return `
|
|
33285
|
-
<div class="itinerary-shell">
|
|
33286
|
-
${itinerary.title ? `<header class="itinerary-shell__header"><h1 class="itinerary-shell__title">${escapeHtml(itinerary.title)}</h1></header>` : ''}
|
|
33287
|
-
|
|
33288
|
-
<div class="itinerary-shell__content">
|
|
33289
|
-
${nodesHtml}
|
|
33290
|
-
${defaultItemsHtml}
|
|
33291
|
-
</div>
|
|
33292
|
-
</div>
|
|
33528
|
+
return `
|
|
33529
|
+
<div class="itinerary-shell">
|
|
33530
|
+
${itinerary.title ? `<header class="itinerary-shell__header"><h1 class="itinerary-shell__title">${escapeHtml(itinerary.title)}</h1></header>` : ''}
|
|
33531
|
+
|
|
33532
|
+
<div class="itinerary-shell__content">
|
|
33533
|
+
${nodesHtml}
|
|
33534
|
+
${defaultItemsHtml}
|
|
33535
|
+
</div>
|
|
33536
|
+
</div>
|
|
33293
33537
|
`;
|
|
33294
33538
|
};
|
|
33295
33539
|
const FullItinerary = ({ isLoading }) => {
|
|
33296
33540
|
const { itinerary } = useSelector((state) => state.searchResults);
|
|
33297
33541
|
const context = useContext(SearchResultsConfigurationContext);
|
|
33542
|
+
// The entry as it was sent: its line guids are the ones the itinerary items carry back.
|
|
33543
|
+
const bookableEntry = useBookableEntry();
|
|
33298
33544
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
33299
33545
|
const hostRef = useRef(null);
|
|
33300
33546
|
const shadowRootRef = useRef(null);
|
|
33301
|
-
const html = useMemo(() => buildItineraryHtml(itinerary, translations), [itinerary, translations]);
|
|
33547
|
+
const html = useMemo(() => buildItineraryHtml(itinerary, translations, bookableEntry?.lines ?? []), [itinerary, translations, bookableEntry]);
|
|
33302
33548
|
useEffect(() => {
|
|
33303
33549
|
if (isLoading) {
|
|
33304
33550
|
return;
|
|
@@ -33309,141 +33555,170 @@ const FullItinerary = ({ isLoading }) => {
|
|
|
33309
33555
|
}
|
|
33310
33556
|
const shadowRoot = host.shadowRoot ?? host.attachShadow({ mode: 'open' });
|
|
33311
33557
|
shadowRootRef.current = shadowRoot;
|
|
33312
|
-
shadowRoot.innerHTML = `
|
|
33313
|
-
<style>
|
|
33314
|
-
:host {
|
|
33315
|
-
all: initial;
|
|
33316
|
-
display: block;
|
|
33317
|
-
width: 100%;
|
|
33318
|
-
}
|
|
33319
|
-
|
|
33320
|
-
*,
|
|
33321
|
-
*::before,
|
|
33322
|
-
*::after {
|
|
33323
|
-
box-sizing: border-box;
|
|
33324
|
-
}
|
|
33325
|
-
|
|
33326
|
-
.itinerary-shell {
|
|
33327
|
-
width: 100%;
|
|
33328
|
-
margin: 0 auto;
|
|
33329
|
-
font-family: 'Outfit', sans-serif;
|
|
33330
|
-
color: #222;
|
|
33331
|
-
}
|
|
33332
|
-
|
|
33333
|
-
.itinerary-shell__header {
|
|
33334
|
-
margin-bottom: 24px;
|
|
33335
|
-
}
|
|
33336
|
-
|
|
33337
|
-
.itinerary-shell__title {
|
|
33338
|
-
margin: 0;
|
|
33339
|
-
font-size: 32px;
|
|
33340
|
-
line-height: 1.2;
|
|
33341
|
-
}
|
|
33342
|
-
|
|
33343
|
-
.itinerary-shell__content {
|
|
33344
|
-
display: grid;
|
|
33345
|
-
gap: 24px;
|
|
33346
|
-
}
|
|
33347
|
-
|
|
33348
|
-
.itinerary-node {
|
|
33349
|
-
border: 1px solid #e5e7eb;
|
|
33350
|
-
border-radius: 16px;
|
|
33351
|
-
overflow: hidden;
|
|
33352
|
-
background: #fff;
|
|
33353
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
|
|
33354
|
-
}
|
|
33355
|
-
|
|
33356
|
-
.itinerary-node__header {
|
|
33357
|
-
display: flex;
|
|
33358
|
-
gap: 16px;
|
|
33359
|
-
align-items: center;
|
|
33360
|
-
border-bottom: 1px solid #eef0f2;
|
|
33361
|
-
background: #fafafa;
|
|
33362
|
-
}
|
|
33363
|
-
|
|
33364
|
-
.itinerary-node__day {
|
|
33365
|
-
flex: 50px 0 0;
|
|
33366
|
-
display: flex;
|
|
33367
|
-
flex-flow: column;
|
|
33368
|
-
align-items: center;
|
|
33369
|
-
justify-content: center;
|
|
33370
|
-
background: #1f9470;
|
|
33371
|
-
color: white;
|
|
33372
|
-
border: 1.5px solid var(--tide-booking-color-secondary);
|
|
33373
|
-
}
|
|
33374
|
-
|
|
33375
|
-
.itinerary-node__day-month {
|
|
33376
|
-
margin: 0px;
|
|
33377
|
-
}
|
|
33378
|
-
|
|
33379
|
-
.itinerary-node__day-day {
|
|
33380
|
-
margin: 0px;
|
|
33381
|
-
font-weight: var(--tide-booking-search-results-label-date-month-font-weight);
|
|
33382
|
-
color: var(--tide-booking-search-results-label-date-month-color);
|
|
33383
|
-
font-size: 24px;
|
|
33384
|
-
}
|
|
33385
|
-
|
|
33386
|
-
.itinerary-node__title {
|
|
33387
|
-
margin: 0;
|
|
33388
|
-
font-size: 22px;
|
|
33389
|
-
line-height: 1.25;
|
|
33390
|
-
}
|
|
33391
|
-
|
|
33392
|
-
.itinerary-node__content {
|
|
33393
|
-
display: grid;
|
|
33394
|
-
gap: 20px;
|
|
33395
|
-
padding: 20px;
|
|
33396
|
-
}
|
|
33397
|
-
|
|
33398
|
-
.itinerary-node__accommodation-banner {
|
|
33399
|
-
padding: 12px 16px;
|
|
33400
|
-
border: 1px solid #dbeafe;
|
|
33401
|
-
border-radius: 12px;
|
|
33402
|
-
background: #eff6ff;
|
|
33403
|
-
color: #1e3a8a;
|
|
33404
|
-
font-size: 14px;
|
|
33405
|
-
line-height: 1.4;
|
|
33406
|
-
}
|
|
33407
|
-
|
|
33408
|
-
.itinerary-item {
|
|
33409
|
-
display: block;
|
|
33410
|
-
border-radius: 12px;
|
|
33411
|
-
overflow: hidden;
|
|
33412
|
-
background: #fff;
|
|
33413
|
-
}
|
|
33414
|
-
|
|
33415
|
-
.
|
|
33416
|
-
.itinerary-
|
|
33417
|
-
padding: 20px;
|
|
33418
|
-
border: 1px
|
|
33419
|
-
border-radius: 12px;
|
|
33420
|
-
|
|
33421
|
-
|
|
33422
|
-
|
|
33423
|
-
|
|
33424
|
-
|
|
33425
|
-
|
|
33426
|
-
|
|
33427
|
-
|
|
33428
|
-
|
|
33429
|
-
|
|
33430
|
-
|
|
33431
|
-
|
|
33432
|
-
|
|
33433
|
-
|
|
33434
|
-
|
|
33435
|
-
|
|
33436
|
-
|
|
33437
|
-
|
|
33438
|
-
|
|
33439
|
-
|
|
33440
|
-
|
|
33441
|
-
|
|
33442
|
-
|
|
33443
|
-
|
|
33444
|
-
|
|
33445
|
-
|
|
33446
|
-
|
|
33558
|
+
shadowRoot.innerHTML = `
|
|
33559
|
+
<style>
|
|
33560
|
+
:host {
|
|
33561
|
+
all: initial;
|
|
33562
|
+
display: block;
|
|
33563
|
+
width: 100%;
|
|
33564
|
+
}
|
|
33565
|
+
|
|
33566
|
+
*,
|
|
33567
|
+
*::before,
|
|
33568
|
+
*::after {
|
|
33569
|
+
box-sizing: border-box;
|
|
33570
|
+
}
|
|
33571
|
+
|
|
33572
|
+
.itinerary-shell {
|
|
33573
|
+
width: 100%;
|
|
33574
|
+
margin: 0 auto;
|
|
33575
|
+
font-family: 'Outfit', sans-serif;
|
|
33576
|
+
color: #222;
|
|
33577
|
+
}
|
|
33578
|
+
|
|
33579
|
+
.itinerary-shell__header {
|
|
33580
|
+
margin-bottom: 24px;
|
|
33581
|
+
}
|
|
33582
|
+
|
|
33583
|
+
.itinerary-shell__title {
|
|
33584
|
+
margin: 0;
|
|
33585
|
+
font-size: 32px;
|
|
33586
|
+
line-height: 1.2;
|
|
33587
|
+
}
|
|
33588
|
+
|
|
33589
|
+
.itinerary-shell__content {
|
|
33590
|
+
display: grid;
|
|
33591
|
+
gap: 24px;
|
|
33592
|
+
}
|
|
33593
|
+
|
|
33594
|
+
.itinerary-node {
|
|
33595
|
+
border: 1px solid #e5e7eb;
|
|
33596
|
+
border-radius: 16px;
|
|
33597
|
+
overflow: hidden;
|
|
33598
|
+
background: #fff;
|
|
33599
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
|
|
33600
|
+
}
|
|
33601
|
+
|
|
33602
|
+
.itinerary-node__header {
|
|
33603
|
+
display: flex;
|
|
33604
|
+
gap: 16px;
|
|
33605
|
+
align-items: center;
|
|
33606
|
+
border-bottom: 1px solid #eef0f2;
|
|
33607
|
+
background: #fafafa;
|
|
33608
|
+
}
|
|
33609
|
+
|
|
33610
|
+
.itinerary-node__day {
|
|
33611
|
+
flex: 50px 0 0;
|
|
33612
|
+
display: flex;
|
|
33613
|
+
flex-flow: column;
|
|
33614
|
+
align-items: center;
|
|
33615
|
+
justify-content: center;
|
|
33616
|
+
background: #1f9470;
|
|
33617
|
+
color: white;
|
|
33618
|
+
border: 1.5px solid var(--tide-booking-color-secondary);
|
|
33619
|
+
}
|
|
33620
|
+
|
|
33621
|
+
.itinerary-node__day-month {
|
|
33622
|
+
margin: 0px;
|
|
33623
|
+
}
|
|
33624
|
+
|
|
33625
|
+
.itinerary-node__day-day {
|
|
33626
|
+
margin: 0px;
|
|
33627
|
+
font-weight: var(--tide-booking-search-results-label-date-month-font-weight);
|
|
33628
|
+
color: var(--tide-booking-search-results-label-date-month-color);
|
|
33629
|
+
font-size: 24px;
|
|
33630
|
+
}
|
|
33631
|
+
|
|
33632
|
+
.itinerary-node__title {
|
|
33633
|
+
margin: 0;
|
|
33634
|
+
font-size: 22px;
|
|
33635
|
+
line-height: 1.25;
|
|
33636
|
+
}
|
|
33637
|
+
|
|
33638
|
+
.itinerary-node__content {
|
|
33639
|
+
display: grid;
|
|
33640
|
+
gap: 20px;
|
|
33641
|
+
padding: 20px;
|
|
33642
|
+
}
|
|
33643
|
+
|
|
33644
|
+
.itinerary-node__accommodation-banner {
|
|
33645
|
+
padding: 12px 16px;
|
|
33646
|
+
border: 1px solid #dbeafe;
|
|
33647
|
+
border-radius: 12px;
|
|
33648
|
+
background: #eff6ff;
|
|
33649
|
+
color: #1e3a8a;
|
|
33650
|
+
font-size: 14px;
|
|
33651
|
+
line-height: 1.4;
|
|
33652
|
+
}
|
|
33653
|
+
|
|
33654
|
+
.itinerary-item {
|
|
33655
|
+
display: block;
|
|
33656
|
+
border-radius: 12px;
|
|
33657
|
+
overflow: hidden;
|
|
33658
|
+
background: #fff;
|
|
33659
|
+
}
|
|
33660
|
+
|
|
33661
|
+
/* An item whose template has no content view of its own still has to read as a service. */
|
|
33662
|
+
.itinerary-item__fallback {
|
|
33663
|
+
padding: 16px 20px;
|
|
33664
|
+
border: 1px solid #e5e7eb;
|
|
33665
|
+
border-radius: 12px;
|
|
33666
|
+
}
|
|
33667
|
+
|
|
33668
|
+
.itinerary-item__fallback-title {
|
|
33669
|
+
margin: 0;
|
|
33670
|
+
font-size: 16px;
|
|
33671
|
+
font-weight: 600;
|
|
33672
|
+
color: #111827;
|
|
33673
|
+
}
|
|
33674
|
+
|
|
33675
|
+
.itinerary-item__legs {
|
|
33676
|
+
margin: 8px 0 0;
|
|
33677
|
+
padding-left: 18px;
|
|
33678
|
+
color: #374151;
|
|
33679
|
+
}
|
|
33680
|
+
|
|
33681
|
+
.itinerary-item__legs li + li {
|
|
33682
|
+
margin-top: 4px;
|
|
33683
|
+
}
|
|
33684
|
+
|
|
33685
|
+
.itinerary-item__fallback-details {
|
|
33686
|
+
margin: 8px 0 0;
|
|
33687
|
+
color: #6b7280;
|
|
33688
|
+
}
|
|
33689
|
+
|
|
33690
|
+
.itinerary-node__empty,
|
|
33691
|
+
.itinerary-empty {
|
|
33692
|
+
padding: 20px;
|
|
33693
|
+
border: 1px dashed #d1d5db;
|
|
33694
|
+
border-radius: 12px;
|
|
33695
|
+
color: #6b7280;
|
|
33696
|
+
background: #fafafa;
|
|
33697
|
+
}
|
|
33698
|
+
|
|
33699
|
+
.itinerary-default-items {
|
|
33700
|
+
border: 1px solid #e5e7eb;
|
|
33701
|
+
border-radius: 16px;
|
|
33702
|
+
padding: 20px;
|
|
33703
|
+
background: #fff;
|
|
33704
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
|
|
33705
|
+
}
|
|
33706
|
+
|
|
33707
|
+
.itinerary-default-items__title {
|
|
33708
|
+
margin: 0 0 16px;
|
|
33709
|
+
font-size: 22px;
|
|
33710
|
+
}
|
|
33711
|
+
|
|
33712
|
+
@media (max-width: 768px) {
|
|
33713
|
+
.itinerary-shell {
|
|
33714
|
+
padding: 16px;
|
|
33715
|
+
}
|
|
33716
|
+
}
|
|
33717
|
+
|
|
33718
|
+
${itinerary?.styleSheetBody ?? ''}
|
|
33719
|
+
</style>
|
|
33720
|
+
|
|
33721
|
+
${html}
|
|
33447
33722
|
`;
|
|
33448
33723
|
}, [html, itinerary?.styleSheetBody, isLoading]);
|
|
33449
33724
|
return (React__default.createElement(React__default.Fragment, null,
|
|
@@ -33547,27 +33822,6 @@ const DayByDayExcursions = () => {
|
|
|
33547
33822
|
})));
|
|
33548
33823
|
};
|
|
33549
33824
|
|
|
33550
|
-
/**
|
|
33551
|
-
* The entry to send to the backend, as opposed to the one the page works with.
|
|
33552
|
-
*
|
|
33553
|
-
* They differ only for a traject: the page keeps the line guids the traject was rendered with,
|
|
33554
|
-
* because that is what joins its nodes to its lines, while pricing and booking need the guids the
|
|
33555
|
-
* searches cached their lines under. Anything else passes through untouched, so this can be used
|
|
33556
|
-
* wherever the entry leaves the component without checking which flow is running.
|
|
33557
|
-
*/
|
|
33558
|
-
const useBookableEntry = () => {
|
|
33559
|
-
const context = useContext(SearchResultsConfigurationContext);
|
|
33560
|
-
const { editablePackagingEntry, trajectNodeAvailability, trajectFlightAvailability } = useSelector((state) => state.searchResults);
|
|
33561
|
-
const trajectEntry = context?.trajectEntry;
|
|
33562
|
-
return useMemo(() => {
|
|
33563
|
-
if (!editablePackagingEntry)
|
|
33564
|
-
return null;
|
|
33565
|
-
if (!trajectEntry)
|
|
33566
|
-
return editablePackagingEntry;
|
|
33567
|
-
return withCachedEntryLineGuids(editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability);
|
|
33568
|
-
}, [editablePackagingEntry, trajectEntry, trajectNodeAvailability, trajectFlightAvailability]);
|
|
33569
|
-
};
|
|
33570
|
-
|
|
33571
33825
|
const renderEditablePackagingEntrySummaryOptions = (editablePackagingEntry, priceDetails, translations, currencyCode) => {
|
|
33572
33826
|
const priceDetailsByProduct = groupBy(priceDetails?.details ?? [], (detail) => `${detail.productCode}|${detail.accommodationCode}`);
|
|
33573
33827
|
return (editablePackagingEntry?.lines ?? []).map((line) => {
|
|
@@ -34058,15 +34312,18 @@ const getNodeIcon = (node) => {
|
|
|
34058
34312
|
const isRenderableNode = (node) => node.trajectNodeType === REGULAR_TRAJECT_NODE_TYPE &&
|
|
34059
34313
|
(node.serviceType === ACCOMMODATION_SERVICE_TYPE || node.serviceType === EXCURSION_SERVICE_TYPE || node.serviceType === FLIGHT_SERVICE_TYPE);
|
|
34060
34314
|
const MAX_DAY_ACTIVITIES = 6;
|
|
34315
|
+
const MAX_HOTEL_RESULTS = 6;
|
|
34061
34316
|
const TrajectResults = ({ isLoading }) => {
|
|
34062
34317
|
const context = useContext(SearchResultsConfigurationContext);
|
|
34063
34318
|
const dispatch = useDispatch();
|
|
34064
34319
|
const loadDay = useTrajectDayActivities();
|
|
34065
34320
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
34066
34321
|
const locale = getLocale(context?.languageCode ?? 'en-GB');
|
|
34067
|
-
const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry
|
|
34322
|
+
const { trajectNodeAvailability, trajectFlightAvailability, trajectDaySuggestions, editablePackagingEntry } = useSelector((state) => state.searchResults);
|
|
34068
34323
|
const trajectEntry = context?.trajectEntry;
|
|
34069
34324
|
const hideShowMoreResults = !!context?.hideShowMoreResults;
|
|
34325
|
+
const loadDayActivitiesOnDemand = !!context?.loadDayActivitiesOnDemand;
|
|
34326
|
+
const showNonPreferredHotels = !!context?.showNonPreferredHotels;
|
|
34070
34327
|
const nodesWithLines = useMemo(() => (trajectEntry ? getTrajectNodesWithLines(trajectEntry) : []), [trajectEntry]);
|
|
34071
34328
|
const lineByNodeId = useMemo(() => new Map(nodesWithLines.map((x) => [x.node.nodeId, x])), [nodesWithLines]);
|
|
34072
34329
|
const nodesByDay = useMemo(() => {
|
|
@@ -34094,6 +34351,24 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34094
34351
|
});
|
|
34095
34352
|
return { stayByDay: byDay, stayStartByNodeId: byNodeId };
|
|
34096
34353
|
}, [nodesWithLines]);
|
|
34354
|
+
/** Whether every node of the trip has an answer, one way or the other. */
|
|
34355
|
+
const tripResolved = useMemo(() => nodesWithLines
|
|
34356
|
+
.filter((x) => isSearchableTrajectNode(x.node) || isTrajectFlightNode(x.node))
|
|
34357
|
+
.every((x) => {
|
|
34358
|
+
const status = isTrajectFlightNode(x.node) ? trajectFlightAvailability[x.line.guid]?.status : trajectNodeAvailability[x.line.guid]?.status;
|
|
34359
|
+
return !!status && status !== 'loading';
|
|
34360
|
+
}), [nodesWithLines, trajectNodeAvailability, trajectFlightAvailability]);
|
|
34361
|
+
/**
|
|
34362
|
+
* Each day's activities are one more search, and a traject has as many as it has days. They go
|
|
34363
|
+
* out together, but only once the trip itself has resolved — sharing the connections with the
|
|
34364
|
+
* searches the trip cannot do without would only make those slower. A portal can turn the
|
|
34365
|
+
* automatic load off, and then each day waits for its own "show activities" click instead.
|
|
34366
|
+
*/
|
|
34367
|
+
useEffect(() => {
|
|
34368
|
+
if (!trajectEntry || !tripResolved || loadDayActivitiesOnDemand)
|
|
34369
|
+
return;
|
|
34370
|
+
(trajectEntry.traject.days ?? []).filter((day) => stayByDay.has(day.order)).forEach((day) => loadDay(day));
|
|
34371
|
+
}, [trajectEntry, tripResolved, stayByDay, loadDayActivitiesOnDemand]);
|
|
34097
34372
|
if (!context || !trajectEntry)
|
|
34098
34373
|
return null;
|
|
34099
34374
|
const handleSelect = (item, code) => {
|
|
@@ -34167,6 +34442,10 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34167
34442
|
const selected = results.find((x) => x.code === availability?.selectedCode) ?? null;
|
|
34168
34443
|
const configured = results.filter((x) => x.code !== selected?.code && !!findCandidateForResult(node, x));
|
|
34169
34444
|
const others = results.filter((x) => x.code !== selected?.code && !findCandidateForResult(node, x));
|
|
34445
|
+
// A hotel row holds the hotels configured on the node; a portal can also let it fill up with
|
|
34446
|
+
// non-preferred hotels found in the area, the rest staying behind "show more".
|
|
34447
|
+
const fill = showNonPreferredHotels && node.serviceType === ACCOMMODATION_SERVICE_TYPE ? others.slice(0, Math.max(MAX_HOTEL_RESULTS - 1 - configured.length, 0)) : [];
|
|
34448
|
+
const remaining = others.length - fill.length;
|
|
34170
34449
|
// No entry yet means the node's search has been queued but not dispatched — still loading.
|
|
34171
34450
|
const status = availability?.status ?? 'loading';
|
|
34172
34451
|
return (React__default.createElement(React__default.Fragment, { key: line.guid },
|
|
@@ -34186,12 +34465,12 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34186
34465
|
node.preferredAccommodationName,
|
|
34187
34466
|
" \u2014 ",
|
|
34188
34467
|
translations.SRP.NO_RESULTS))),
|
|
34189
|
-
React__default.createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured].map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE })))),
|
|
34190
|
-
|
|
34468
|
+
React__default.createElement("div", { className: "search__results__cards search__results__cards--scroll" }, [selected, ...configured, ...fill].map((result) => (React__default.createElement(TrajectNodeCard, { key: result.code, node: node, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE })))),
|
|
34469
|
+
remaining > 0 && !hideShowMoreResults && (React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
34191
34470
|
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
|
|
34192
34471
|
translations.SRP.SHOW_MORE,
|
|
34193
34472
|
" (",
|
|
34194
|
-
|
|
34473
|
+
remaining,
|
|
34195
34474
|
")")))))));
|
|
34196
34475
|
};
|
|
34197
34476
|
const handleSelectFlight = (item, flight) => {
|
|
@@ -34250,11 +34529,6 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34250
34529
|
if (lines.length)
|
|
34251
34530
|
dispatch(addEditableEntryLines(lines));
|
|
34252
34531
|
};
|
|
34253
|
-
const handleShowItinerary = () => {
|
|
34254
|
-
dispatch(setTrajectItineraryView(true));
|
|
34255
|
-
if (typeof window !== 'undefined')
|
|
34256
|
-
window.scrollTo(0, 0);
|
|
34257
|
-
};
|
|
34258
34532
|
const handleShowMoreActivities = (dayOrder) => {
|
|
34259
34533
|
dispatch(setTrajectActivitiesDayOrder(dayOrder));
|
|
34260
34534
|
dispatch(setFlyInType('traject-day-activities'));
|
|
@@ -34279,16 +34553,17 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34279
34553
|
const cards = buildDayActivityCards(items, trajectNodeAvailability, suggestions?.results ?? []);
|
|
34280
34554
|
const nodesResolving = items.some((item) => (trajectNodeAvailability[item.line.guid]?.status ?? 'loading') === 'loading');
|
|
34281
34555
|
const isSearching = suggestions?.status === 'loading';
|
|
34282
|
-
|
|
34556
|
+
// A day is worth filling only if the party is staying somewhere that night. The day they fly
|
|
34557
|
+
// home is covered by no stay — the last night was the night before — and nobody is looking for
|
|
34558
|
+
// something to do on it.
|
|
34559
|
+
const canSearch = stayByDay.has(day.order) && !!getDayDestination(nodesWithLines, trajectNodeAvailability, day.order);
|
|
34283
34560
|
if (!items.length && !canSearch)
|
|
34284
34561
|
return null;
|
|
34285
34562
|
const visible = cards.slice(0, MAX_DAY_ACTIVITIES);
|
|
34286
34563
|
const hidden = cards.length - visible.length;
|
|
34564
|
+
const awaitsRequest = loadDayActivitiesOnDemand && !suggestions && canSearch && !nodesResolving && hidden === 0;
|
|
34287
34565
|
return (React__default.createElement(React__default.Fragment, { key: `activities-${day.order}` },
|
|
34288
|
-
React__default.createElement("div", { className: "search__results__label search__results__label--
|
|
34289
|
-
React__default.createElement("div", { className: "search__results__label__date" },
|
|
34290
|
-
React__default.createElement("p", { className: "search__results__label__date-date" }, format$2(new Date(day.date), 'd', { locale })),
|
|
34291
|
-
React__default.createElement("p", null, format$2(new Date(day.date), 'MMM', { locale }))),
|
|
34566
|
+
React__default.createElement("div", { className: "search__results__label search__results__label--sub" },
|
|
34292
34567
|
React__default.createElement("div", { className: "search__results__label__text" },
|
|
34293
34568
|
React__default.createElement(Icon, { name: "ui-excursion", height: 16 }),
|
|
34294
34569
|
React__default.createElement("h3", null,
|
|
@@ -34297,7 +34572,7 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34297
34572
|
!!cards.length && React__default.createElement("div", { className: "search__results__cards search__results__cards--scroll" }, visible.map(renderActivityCard)),
|
|
34298
34573
|
!nodesResolving && !isSearching && !cards.length && (!!items.length || !!suggestions) && (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)),
|
|
34299
34574
|
React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
34300
|
-
|
|
34575
|
+
awaitsRequest && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => loadDay(day) }, translations.SRP.SHOW_ACTIVITIES)),
|
|
34301
34576
|
hidden > 0 && !hideShowMoreResults && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMoreActivities(day.order) },
|
|
34302
34577
|
translations.SRP.SHOW_MORE,
|
|
34303
34578
|
" (",
|
|
@@ -34314,35 +34589,32 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
34314
34589
|
};
|
|
34315
34590
|
if (isLoading)
|
|
34316
34591
|
return React__default.createElement(Spinner, { label: translations.SRP.LOADING_ITINERARY });
|
|
34317
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
34318
|
-
|
|
34319
|
-
|
|
34320
|
-
|
|
34321
|
-
|
|
34322
|
-
|
|
34323
|
-
|
|
34324
|
-
|
|
34325
|
-
|
|
34326
|
-
|
|
34327
|
-
|
|
34328
|
-
|
|
34329
|
-
|
|
34330
|
-
|
|
34331
|
-
|
|
34332
|
-
|
|
34333
|
-
|
|
34334
|
-
|
|
34335
|
-
|
|
34336
|
-
|
|
34337
|
-
|
|
34338
|
-
|
|
34339
|
-
|
|
34340
|
-
|
|
34341
|
-
|
|
34342
|
-
|
|
34343
|
-
}),
|
|
34344
|
-
React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
34345
|
-
React__default.createElement("button", { type: "button", className: "cta", disabled: trajectResolving, onClick: handleShowItinerary }, translations.STEPS.NEXT))));
|
|
34592
|
+
return (React__default.createElement(React__default.Fragment, null, trajectEntry.traject.days.map((day) => {
|
|
34593
|
+
const stay = stayByDay.get(day.order);
|
|
34594
|
+
const dayNodes = (nodesByDay.get(day.order) ?? []).filter((node) => isRenderableNode(node) && lineByNodeId.has(node.nodeId));
|
|
34595
|
+
const stayLeadsDay = !!stay && (stay.night > 0 || dayNodes[0]?.nodeId === stay.item.node.nodeId);
|
|
34596
|
+
// Where the day's activities belong in the order: with the first excursion it carries.
|
|
34597
|
+
const firstExcursionNodeId = dayNodes.find((node) => node.serviceType === EXCURSION_SERVICE_TYPE)?.nodeId;
|
|
34598
|
+
const showDayHeader = stayLeadsDay || !!day.name?.trim();
|
|
34599
|
+
return (React__default.createElement(React__default.Fragment, { key: `day-${day.order}` },
|
|
34600
|
+
showDayHeader && renderDayHeader(day, stayLeadsDay ? stay : undefined),
|
|
34601
|
+
dayNodes.map((node) => {
|
|
34602
|
+
const item = lineByNodeId.get(node.nodeId);
|
|
34603
|
+
if (node.serviceType === ACCOMMODATION_SERVICE_TYPE) {
|
|
34604
|
+
const stayStart = stayStartByNodeId.get(node.nodeId);
|
|
34605
|
+
const titledByDayHeader = stayLeadsDay && stay.item.node.nodeId === node.nodeId;
|
|
34606
|
+
return renderServiceNode(item, !titledByDayHeader, stayStart && getStayTitle(stayStart));
|
|
34607
|
+
}
|
|
34608
|
+
// Every excursion the day holds is drawn once, in one block, where the first of
|
|
34609
|
+
// them falls in the order — so the activities still sit between the stay and the
|
|
34610
|
+
// flight that follow them.
|
|
34611
|
+
if (node.serviceType === EXCURSION_SERVICE_TYPE) {
|
|
34612
|
+
return node.nodeId === firstExcursionNodeId ? renderDayActivities(day) : null;
|
|
34613
|
+
}
|
|
34614
|
+
return renderFlightNode(item);
|
|
34615
|
+
}),
|
|
34616
|
+
firstExcursionNodeId === undefined && renderDayActivities(day)));
|
|
34617
|
+
})));
|
|
34346
34618
|
};
|
|
34347
34619
|
|
|
34348
34620
|
const useTrajectAvailability = () => {
|
|
@@ -35289,6 +35561,9 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35289
35561
|
setPricesAreLoading(false);
|
|
35290
35562
|
}
|
|
35291
35563
|
};
|
|
35564
|
+
fetchPriceDetails();
|
|
35565
|
+
}, [editablePackagingEntry, bookableEntry, trajectResolving]);
|
|
35566
|
+
useEffect(() => {
|
|
35292
35567
|
const fetchItinerary = async () => {
|
|
35293
35568
|
if (!context || !context.packagingEntry || !editablePackagingEntry || isEmpty$1(editablePackagingEntry.lines))
|
|
35294
35569
|
return;
|
|
@@ -35318,7 +35593,6 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35318
35593
|
setItineraryIsLoading(false);
|
|
35319
35594
|
}
|
|
35320
35595
|
};
|
|
35321
|
-
fetchPriceDetails();
|
|
35322
35596
|
fetchItinerary();
|
|
35323
35597
|
}, [editablePackagingEntry, bookableEntry, trajectResolving, trajectItineraryView]);
|
|
35324
35598
|
// Flight selection
|
|
@@ -35669,11 +35943,6 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35669
35943
|
address: {}
|
|
35670
35944
|
};
|
|
35671
35945
|
};
|
|
35672
|
-
const handleComposeTraject = () => {
|
|
35673
|
-
dispatch(setTrajectItineraryView(false));
|
|
35674
|
-
if (typeof window !== 'undefined')
|
|
35675
|
-
window.scrollTo(0, 0);
|
|
35676
|
-
};
|
|
35677
35946
|
const handleShowMoreFlights = (flyInType) => {
|
|
35678
35947
|
dispatch(setFlyInType(flyInType));
|
|
35679
35948
|
dispatch(setFlyInIsOpen(true));
|
|
@@ -35764,10 +36033,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
35764
36033
|
selectedReturnKey && selectedReturn && (React__default.createElement(IndependentFlightOption, { key: `flight-${selectedReturnKey}`, item: selectedReturn.return, guid: selectedReturn.outwardGuid, selectedGuid: selectedReturn.outwardGuid, isOutward: false, showSelectedState: true, price: selectedReturn.price })),
|
|
35765
36034
|
uniqueReturnFlights.map((result) => (React__default.createElement(IndependentFlightOption, { key: `flight-${result.outwardGuid}`, item: result.return, onSelect: () => dispatch(setSelectedReturnKey(getFlightKey(result.return.segments))), guid: result.outwardGuid, isOutward: false, currentSelectedPrice: selectedReturn?.price, price: result.price })))))),
|
|
35766
36035
|
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && !trajectItineraryView && (React__default.createElement(TrajectResults, { isLoading: isLoading })),
|
|
35767
|
-
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && trajectItineraryView && (React__default.createElement(
|
|
35768
|
-
React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
35769
|
-
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: handleComposeTraject }, translations.STEPS.PREVIOUS)),
|
|
35770
|
-
React__default.createElement(FullItinerary, { isLoading: itineraryIsLoading }))),
|
|
36036
|
+
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.trajectEntry && trajectItineraryView && (React__default.createElement(FullItinerary, { isLoading: itineraryIsLoading })),
|
|
35771
36037
|
context.searchConfiguration.qsmType === build.PortalQsmType.AccommodationAndFlight && context.packagingEntry && !context.trajectEntry && (React__default.createElement(FullItinerary, { isLoading: itineraryIsLoading })))),
|
|
35772
36038
|
React__default.createElement(FlyIn, { srpType: context.searchConfiguration.qsmType, isOpen: flyInIsOpen, setIsOpen: handleFlyInToggle, handleConfirm: () => handleConfirmHotelSwap(), onPanelRef: (el) => (panelRef.current = el), detailsLoading: detailsIsLoading, flyInType: flyInType, isPackageEditFlow: !!context.packagingEntry, sortByTypes: sortByTypes, activeSearchSeed: activeSearchSeed, toggleFilters: () => setFiltersOpen(!filtersOpen), filtersOpen: filtersOpen })))))))));
|
|
35773
36039
|
};
|
|
@@ -38676,20 +38942,20 @@ function ItineraryMapView({ destinations: propDestinations, adults = 2, dateFrom
|
|
|
38676
38942
|
const isStartEnd = dest.isStart || dest.isEnd;
|
|
38677
38943
|
let iconHtml;
|
|
38678
38944
|
if (isStartEnd) {
|
|
38679
|
-
iconHtml = `
|
|
38680
|
-
<div class="map-view__marker map-view__marker--plane">
|
|
38681
|
-
<svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
|
38682
|
-
<path d="M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10.1-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.3-15.8-20.6l49-196.3L112 288 68.8 377.6c-3 6.1-9.2 10.4-16 10.4l-2.8 0c-9.2 0-16-8.8-13.3-17.6L80 256L36.7 141.6C34 132.8 40.8 124 50 124l2.8 0c6.8 0 13 4.3 16 10.4L112 224l102.9 0-49-196.3C163.5 17.3 171.2 7 181.8 7l56.2 0c11.5 0 22.1 6 27.8 16.1L365.7 192l116.6 0z"/>
|
|
38683
|
-
</svg>
|
|
38945
|
+
iconHtml = `
|
|
38946
|
+
<div class="map-view__marker map-view__marker--plane">
|
|
38947
|
+
<svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
|
38948
|
+
<path d="M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10.1-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.3-15.8-20.6l49-196.3L112 288 68.8 377.6c-3 6.1-9.2 10.4-16 10.4l-2.8 0c-9.2 0-16-8.8-13.3-17.6L80 256L36.7 141.6C34 132.8 40.8 124 50 124l2.8 0c6.8 0 13 4.3 16 10.4L112 224l102.9 0-49-196.3C163.5 17.3 171.2 7 181.8 7l56.2 0c11.5 0 22.1 6 27.8 16.1L365.7 192l116.6 0z"/>
|
|
38949
|
+
</svg>
|
|
38684
38950
|
</div>`;
|
|
38685
38951
|
}
|
|
38686
38952
|
else {
|
|
38687
38953
|
stopIndex++;
|
|
38688
38954
|
const imgStyle = dest.imageUrl ? `style="background-image:url('${dest.imageUrl}')"` : '';
|
|
38689
|
-
iconHtml = `
|
|
38690
|
-
<div class="map-view__marker map-view__marker--stop" ${imgStyle}>
|
|
38691
|
-
${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
|
|
38692
|
-
<span class="map-view__marker-badge">${stopIndex}</span>
|
|
38955
|
+
iconHtml = `
|
|
38956
|
+
<div class="map-view__marker map-view__marker--stop" ${imgStyle}>
|
|
38957
|
+
${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
|
|
38958
|
+
<span class="map-view__marker-badge">${stopIndex}</span>
|
|
38693
38959
|
</div>`;
|
|
38694
38960
|
}
|
|
38695
38961
|
const icon = L.divIcon({
|