@qite/tide-components 1.0.4 → 1.0.6
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 +405 -273
- package/build/build-cjs/src/search-results/components/traject/traject-node-card.d.ts +1 -0
- package/build/build-cjs/src/search-results/components/traject/traject-results-flyin.d.ts +6 -0
- package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +5 -1
- package/build/build-cjs/src/search-results/types.d.ts +1 -0
- package/build/build-cjs/src/search-results/utils/traject-utils.d.ts +3 -1
- package/build/build-cjs/src/shared/booking/travelers-form.d.ts +1 -0
- package/build/build-esm/index.js +406 -274
- package/build/build-esm/src/search-results/components/traject/traject-node-card.d.ts +1 -0
- package/build/build-esm/src/search-results/components/traject/traject-results-flyin.d.ts +6 -0
- package/build/build-esm/src/search-results/store/search-results-slice.d.ts +5 -1
- package/build/build-esm/src/search-results/types.d.ts +1 -0
- package/build/build-esm/src/search-results/utils/traject-utils.d.ts +3 -1
- package/build/build-esm/src/shared/booking/travelers-form.d.ts +1 -0
- package/package.json +2 -2
package/build/build-cjs/index.js
CHANGED
|
@@ -22890,6 +22890,10 @@ const NAME_CHARACTERS_REGEX = /^[\p{L}\s-]+$/u;
|
|
|
22890
22890
|
function hasInvalidNameCharacters(name) {
|
|
22891
22891
|
return !NAME_CHARACTERS_REGEX.test(name);
|
|
22892
22892
|
}
|
|
22893
|
+
// Rejects values like a 5-digit year, which the native date input allows while typing
|
|
22894
|
+
function isValidBirthDate(birthDateText) {
|
|
22895
|
+
return dateFns.isValid(dateFns.parse(birthDateText, 'yyyy-MM-dd', new Date()));
|
|
22896
|
+
}
|
|
22893
22897
|
function getAge(birthDateText, startDateText) {
|
|
22894
22898
|
var birthDate = new Date(birthDateText);
|
|
22895
22899
|
var startDate = new Date(startDateText);
|
|
@@ -22957,7 +22961,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
22957
22961
|
}
|
|
22958
22962
|
}
|
|
22959
22963
|
if (isFormFieldPresent('birthDate')) {
|
|
22960
|
-
if (lodash.isEmpty(adult.birthDate)) {
|
|
22964
|
+
if (lodash.isEmpty(adult.birthDate) || !isValidBirthDate(adult.birthDate)) {
|
|
22961
22965
|
lodash.set(errors, `rooms[${rIndex}].adults[${index}].birthDate`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
|
|
22962
22966
|
}
|
|
22963
22967
|
else if (values.endDate) {
|
|
@@ -22990,7 +22994,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
22990
22994
|
}
|
|
22991
22995
|
}
|
|
22992
22996
|
if (isFormFieldPresent('birthDate')) {
|
|
22993
|
-
if (lodash.isEmpty(child.birthDate)) {
|
|
22997
|
+
if (lodash.isEmpty(child.birthDate) || !isValidBirthDate(child.birthDate)) {
|
|
22994
22998
|
lodash.set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
|
|
22995
22999
|
}
|
|
22996
23000
|
else if (child.isBaby && values.startDate) {
|
|
@@ -23215,6 +23219,13 @@ const TypeAheadInput = ({ name, value, placeholder, options, onChange, onSelect,
|
|
|
23215
23219
|
function isBabyAge(age, maxBabyAge = BABY_MAX_AGE) {
|
|
23216
23220
|
return typeof age === 'number' && age <= maxBabyAge;
|
|
23217
23221
|
}
|
|
23222
|
+
// The native date input can hold values format() throws on (e.g. a 5+ digit year while typing), so never format an unvalidated birthDate
|
|
23223
|
+
function formatBirthDate$1(birthDate) {
|
|
23224
|
+
if (!birthDate)
|
|
23225
|
+
return '';
|
|
23226
|
+
const parsed = dateFns.parse(birthDate, 'yyyy-MM-dd', new Date());
|
|
23227
|
+
return dateFns.isValid(parsed) ? dateFns.format(parsed, 'dd-MM-yyyy') : '';
|
|
23228
|
+
}
|
|
23218
23229
|
function createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge) {
|
|
23219
23230
|
if (isCompact) {
|
|
23220
23231
|
return {
|
|
@@ -23522,10 +23533,7 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
|
|
|
23522
23533
|
!useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default["default"].createElement("div", { className: "form__region" },
|
|
23523
23534
|
React__default["default"].createElement("div", { className: "form__region-header" },
|
|
23524
23535
|
React__default["default"].createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
|
|
23525
|
-
React__default["default"].createElement("p", { className: "form__region-label" }, lodash.compact([
|
|
23526
|
-
lodash.compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '),
|
|
23527
|
-
mainBooker?.birthDate && dateFns.format(dateFns.parse(mainBooker.birthDate, 'yyyy-MM-dd', new Date()), 'dd-MM-yyyy')
|
|
23528
|
-
]).join(', '))),
|
|
23536
|
+
React__default["default"].createElement("p", { className: "form__region-label" }, lodash.compact([lodash.compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
|
|
23529
23537
|
travellersSettings?.mainBookerFormFields?.length ? (React__default["default"].createElement("div", { className: "main-booker-form__grid" }, travellersSettings.mainBookerFormFields.map((field, index) => (React__default["default"].createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, {}, field.type)))))) : (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
23530
23538
|
React__default["default"].createElement("div", { className: "form__twocolumn" },
|
|
23531
23539
|
React__default["default"].createElement("div", { className: "form__twocolumn-column" },
|
|
@@ -27370,7 +27378,8 @@ const initialState$1 = {
|
|
|
27370
27378
|
currentStep: 0,
|
|
27371
27379
|
bookingNumber: undefined,
|
|
27372
27380
|
trajectNodeAvailability: {},
|
|
27373
|
-
trajectFlightAvailability: {}
|
|
27381
|
+
trajectFlightAvailability: {},
|
|
27382
|
+
trajectEditLineGuid: null
|
|
27374
27383
|
};
|
|
27375
27384
|
const searchResultsSlice = toolkit.createSlice({
|
|
27376
27385
|
name: 'searchResults',
|
|
@@ -27617,13 +27626,26 @@ const searchResultsSlice = toolkit.createSlice({
|
|
|
27617
27626
|
flight.selectedGuid = action.payload.guid;
|
|
27618
27627
|
flight.status = 'resolved';
|
|
27619
27628
|
},
|
|
27629
|
+
setTrajectEditLineGuid(state, action) {
|
|
27630
|
+
state.trajectEditLineGuid = action.payload;
|
|
27631
|
+
},
|
|
27632
|
+
updateTrajectNodeResult(state, action) {
|
|
27633
|
+
const { lineGuid, result } = action.payload;
|
|
27634
|
+
const node = state.trajectNodeAvailability[lineGuid];
|
|
27635
|
+
if (!node)
|
|
27636
|
+
return;
|
|
27637
|
+
node.results = node.results.map((x) => (x.code === result.code ? result : x));
|
|
27638
|
+
node.selectedCode = result.code;
|
|
27639
|
+
node.status = 'resolved';
|
|
27640
|
+
},
|
|
27620
27641
|
resetTrajectAvailability(state) {
|
|
27621
27642
|
state.trajectNodeAvailability = {};
|
|
27622
27643
|
state.trajectFlightAvailability = {};
|
|
27644
|
+
state.trajectEditLineGuid = null;
|
|
27623
27645
|
}
|
|
27624
27646
|
}
|
|
27625
27647
|
});
|
|
27626
|
-
const { setResults, setFilteredResults, setSelectedSearchResult, setPackagingAccoResults, setFilteredPackagingAccoResults, setFilteredPackagingFlightResults, setPackagingAccoSearchDetails, setSelectedPackagingAccoResult, setPackagingFlightResults, setSelectedPackagingFlight, setSelectedFlight, setSelectedFlightDetails, setBookingPackageDetails, selectFlight, setIsLoading, setFlightsLoading, setInitialFilters, setFilters, resetFilters, setInitialFlightFilters, setFlightFilters, resetFlightFilters, setSortType, setFlightSortType, setActiveTab, setCurrentPage, resetSearchState, setFlyInIsOpen, setEditablePackagingEntry, setTransactionId, setFlyInType, setPriceDetails, setItinerary, setSelectedOutwardKey, setSelectedReturnKey, resetFlightSelection, setExcursionSearchParams, setSelectedExcursionSearchResult, confirmExcursionForDay, removeConfirmedExcursionForDay, clearConfirmedExcursionsForDay, setBookPackagingEntry, setCurrentStep, setBookingNumber, setTrajectNodeLoading, setTrajectNodeAvailability, setTrajectNodeSelection, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
|
|
27648
|
+
const { setResults, setFilteredResults, setSelectedSearchResult, setPackagingAccoResults, setFilteredPackagingAccoResults, setFilteredPackagingFlightResults, setPackagingAccoSearchDetails, setSelectedPackagingAccoResult, setPackagingFlightResults, setSelectedPackagingFlight, setSelectedFlight, setSelectedFlightDetails, setBookingPackageDetails, selectFlight, setIsLoading, setFlightsLoading, setInitialFilters, setFilters, resetFilters, setInitialFlightFilters, setFlightFilters, resetFlightFilters, setSortType, setFlightSortType, setActiveTab, setCurrentPage, resetSearchState, setFlyInIsOpen, setEditablePackagingEntry, setTransactionId, setFlyInType, setPriceDetails, setItinerary, setSelectedOutwardKey, setSelectedReturnKey, resetFlightSelection, setExcursionSearchParams, setSelectedExcursionSearchResult, confirmExcursionForDay, removeConfirmedExcursionForDay, clearConfirmedExcursionsForDay, setBookPackagingEntry, setCurrentStep, setBookingNumber, setTrajectNodeLoading, setTrajectNodeAvailability, setTrajectNodeSelection, setTrajectFlightLoading, setTrajectFlightAvailability, setTrajectFlightSelection, setTrajectEditLineGuid, updateTrajectNodeResult, resetTrajectAvailability, updateEditableEntryLine, removeEditableEntryLines } = searchResultsSlice.actions;
|
|
27627
27649
|
var searchResultsReducer = searchResultsSlice.reducer;
|
|
27628
27650
|
|
|
27629
27651
|
const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
|
|
@@ -30603,6 +30625,293 @@ const ExcursionDetails = () => {
|
|
|
30603
30625
|
React__default["default"].createElement("button", { type: "button", className: "cta cta--primary", onClick: handleConfirm }, translations?.QSM.CONFIRM))));
|
|
30604
30626
|
};
|
|
30605
30627
|
|
|
30628
|
+
const REGULAR_TRAJECT_NODE_TYPE = 0;
|
|
30629
|
+
const isSearchableTrajectNode = (node) => node.serviceType === ACCOMMODATION_SERVICE_TYPE || node.serviceType === EXCURSION_SERVICE_TYPE;
|
|
30630
|
+
const isTrajectFlightNode = (node) => node.serviceType === FLIGHT_SERVICE_TYPE;
|
|
30631
|
+
const getTrajectNodesWithLines = (trajectEntry) => {
|
|
30632
|
+
const linesByGuid = new Map((trajectEntry.entry.lines ?? []).map((line) => [line.guid, line]));
|
|
30633
|
+
return [...(trajectEntry.nodes ?? [])]
|
|
30634
|
+
.sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
|
|
30635
|
+
.map((node) => {
|
|
30636
|
+
const guids = node.lineGuids?.length ? node.lineGuids : [node.lineGuid];
|
|
30637
|
+
const lines = guids.map((guid) => linesByGuid.get(guid)).filter((x) => !!x);
|
|
30638
|
+
return { node, line: lines[0], lines };
|
|
30639
|
+
})
|
|
30640
|
+
.filter((x) => !!x.line);
|
|
30641
|
+
};
|
|
30642
|
+
const buildDestination = (line) => {
|
|
30643
|
+
if (line.location?.id)
|
|
30644
|
+
return { id: line.location.id, isLocation: true };
|
|
30645
|
+
if (line.oord?.id)
|
|
30646
|
+
return { id: line.oord.id, isOord: true };
|
|
30647
|
+
if (line.region?.id)
|
|
30648
|
+
return { id: line.region.id, isRegion: true };
|
|
30649
|
+
if (line.country?.id)
|
|
30650
|
+
return { id: line.country.id, isCountry: true };
|
|
30651
|
+
if (line.latitude && line.longitude)
|
|
30652
|
+
return { latitude: line.latitude, longitude: line.longitude };
|
|
30653
|
+
return { id: 0 };
|
|
30654
|
+
};
|
|
30655
|
+
const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
|
|
30656
|
+
transactionId: context.transactionId,
|
|
30657
|
+
officeId: context.officeId,
|
|
30658
|
+
agentId: context.agentId ?? null,
|
|
30659
|
+
catalogueId: context.catalogueId,
|
|
30660
|
+
searchConfigurationId: context.searchConfigurationId,
|
|
30661
|
+
portalId: context.portalId ?? null,
|
|
30662
|
+
vendorConfigurationId: node.externalVendorId ?? null,
|
|
30663
|
+
language: context.language,
|
|
30664
|
+
serviceType: node.serviceType,
|
|
30665
|
+
fromDate: toDateOnlyString(line.from),
|
|
30666
|
+
toDate: toDateOnlyString(line.to),
|
|
30667
|
+
destination: buildDestination(line),
|
|
30668
|
+
productCode,
|
|
30669
|
+
rooms: context.rooms,
|
|
30670
|
+
tagIds: []
|
|
30671
|
+
});
|
|
30672
|
+
const getNodeCandidates = (node) => {
|
|
30673
|
+
const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
|
|
30674
|
+
if (configured.length)
|
|
30675
|
+
return configured;
|
|
30676
|
+
const fallbackCode = node.code ?? node.preferredAccommodationCode;
|
|
30677
|
+
if (!fallbackCode || !fallbackCode.trim().length)
|
|
30678
|
+
return [];
|
|
30679
|
+
return [
|
|
30680
|
+
{
|
|
30681
|
+
code: fallbackCode,
|
|
30682
|
+
name: node.name,
|
|
30683
|
+
description: node.description,
|
|
30684
|
+
imageUrl: node.imageUrl,
|
|
30685
|
+
contentSource: node.contentSource,
|
|
30686
|
+
vendor: node.vendor,
|
|
30687
|
+
externalVendorId: node.externalVendorId,
|
|
30688
|
+
isPreferred: true
|
|
30689
|
+
}
|
|
30690
|
+
];
|
|
30691
|
+
};
|
|
30692
|
+
const findCandidateForResult = (node, result) => getNodeCandidates(node).find((candidate) => matchesCode(result, candidate.code)) ?? null;
|
|
30693
|
+
const matchesCode = (result, code) => {
|
|
30694
|
+
if (result.code === code)
|
|
30695
|
+
return true;
|
|
30696
|
+
return (result.rooms ?? []).some((room) => (room.options ?? []).some((option) => option.accommodationCode === code));
|
|
30697
|
+
};
|
|
30698
|
+
const getPackagingRoomsFromEntry = (entry) => {
|
|
30699
|
+
const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));
|
|
30700
|
+
const rooms = (entry.rooms ?? []).map((room) => ({
|
|
30701
|
+
travellers: (room.paxIds ?? []).map((paxId) => {
|
|
30702
|
+
const pax = paxById.get(paxId);
|
|
30703
|
+
return {
|
|
30704
|
+
id: paxId,
|
|
30705
|
+
age: pax?.age ?? null,
|
|
30706
|
+
dateOfBirth: pax?.dateOfBirth ?? null
|
|
30707
|
+
};
|
|
30708
|
+
})
|
|
30709
|
+
}));
|
|
30710
|
+
return rooms.filter((room) => room.travellers.length > 0);
|
|
30711
|
+
};
|
|
30712
|
+
const pickCheapest = (results) => [...results].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
30713
|
+
const applyResultToLines = (lines, result) => lines.map((line, index) => applyResultToLine(line, result, index));
|
|
30714
|
+
const getOptionForRoom = (result, roomIndex) => {
|
|
30715
|
+
const room = (result.rooms ?? [])[roomIndex];
|
|
30716
|
+
if (room)
|
|
30717
|
+
return (room.options ?? []).find((x) => x.isSelected) ?? (room.options ?? [])[0];
|
|
30718
|
+
return (result.rooms ?? []).flatMap((x) => x.options ?? []).find((x) => x.isSelected) ?? (result.rooms ?? [])[0]?.options?.[0];
|
|
30719
|
+
};
|
|
30720
|
+
const applyResultToLine = (line, result, roomIndex = 0) => {
|
|
30721
|
+
const option = getOptionForRoom(result, roomIndex);
|
|
30722
|
+
return {
|
|
30723
|
+
...line,
|
|
30724
|
+
productName: result.name ?? line.productName,
|
|
30725
|
+
productCode: result.code ?? line.productCode,
|
|
30726
|
+
accommodationCode: option?.accommodationCode ?? line.accommodationCode,
|
|
30727
|
+
accommodationName: option?.accommodationName ?? line.accommodationName,
|
|
30728
|
+
regimeCode: option?.regimeCode ?? line.regimeCode,
|
|
30729
|
+
regimeName: option?.regimeName ?? line.regimeName,
|
|
30730
|
+
latitude: result.latitude ?? line.latitude,
|
|
30731
|
+
longitude: result.longitude ?? line.longitude,
|
|
30732
|
+
isChanged: true
|
|
30733
|
+
};
|
|
30734
|
+
};
|
|
30735
|
+
const toDateOnlyUtcString = (value) => {
|
|
30736
|
+
const date = new Date(value);
|
|
30737
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
|
|
30738
|
+
};
|
|
30739
|
+
const toTimeOnlyString = (value) => {
|
|
30740
|
+
const date = new Date(value);
|
|
30741
|
+
const hh = String(date.getUTCHours()).padStart(2, '0');
|
|
30742
|
+
const mm = String(date.getUTCMinutes()).padStart(2, '0');
|
|
30743
|
+
const ss = String(date.getUTCSeconds()).padStart(2, '0');
|
|
30744
|
+
return `${hh}:${mm}:${ss}`;
|
|
30745
|
+
};
|
|
30746
|
+
const mapFlightSegmentsToFlightLines = (segments) => segments.map((segment) => ({
|
|
30747
|
+
airlineCode: segment.marketingAirlineCode,
|
|
30748
|
+
airlineDescription: segment.marketingAirlineName,
|
|
30749
|
+
operatingAirlineCode: segment.operatingAirlineCode,
|
|
30750
|
+
operatingAirlineDescription: segment.operatingAirlineName,
|
|
30751
|
+
flightNumber: segment.flightNumber,
|
|
30752
|
+
operatingFlightNumber: segment.operatingFlightNumber ?? null,
|
|
30753
|
+
departureDate: toDateOnlyUtcString(segment.departureDateTime),
|
|
30754
|
+
departureTime: toTimeOnlyString(segment.departureDateTime),
|
|
30755
|
+
departureAirportCode: segment.departureAirportCode,
|
|
30756
|
+
departureAirportDescription: segment.departureAirportName,
|
|
30757
|
+
arrivalDate: toDateOnlyUtcString(segment.arrivalDateTime),
|
|
30758
|
+
arrivalTime: toTimeOnlyString(segment.arrivalDateTime),
|
|
30759
|
+
arrivalAirportCode: segment.arrivalAirportCode,
|
|
30760
|
+
arrivalAirportDescription: segment.arrivalAirportName,
|
|
30761
|
+
durationInTicks: segment.durationInTicks
|
|
30762
|
+
}));
|
|
30763
|
+
const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
30764
|
+
transactionId: context.transactionId,
|
|
30765
|
+
officeId: context.officeId,
|
|
30766
|
+
catalogueId: context.catalogueId,
|
|
30767
|
+
agentId: context.agentId ?? null,
|
|
30768
|
+
language: context.language,
|
|
30769
|
+
departureAirportCode: node.departureAirportCode ?? '',
|
|
30770
|
+
arrivalAirportCode: node.arrivalAirportCode ?? '',
|
|
30771
|
+
returnAirportCode: null,
|
|
30772
|
+
luggageIncluded: null,
|
|
30773
|
+
maxStops: null,
|
|
30774
|
+
travelClass: null,
|
|
30775
|
+
vendorConfigurationId: node.externalVendorId ?? null,
|
|
30776
|
+
pax,
|
|
30777
|
+
outward: { date: dateToDateStruct(new Date(line.from)) },
|
|
30778
|
+
return: null
|
|
30779
|
+
});
|
|
30780
|
+
const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
30781
|
+
const applyFlightToLine = (line, flight) => {
|
|
30782
|
+
const segments = flight.outward?.segments ?? [];
|
|
30783
|
+
if (!segments.length)
|
|
30784
|
+
return line;
|
|
30785
|
+
const firstSegment = segments[0];
|
|
30786
|
+
const lastSegment = segments[segments.length - 1];
|
|
30787
|
+
return {
|
|
30788
|
+
...line,
|
|
30789
|
+
from: new Date(firstSegment.departureDateTime).toISOString(),
|
|
30790
|
+
to: new Date(lastSegment.arrivalDateTime).toISOString(),
|
|
30791
|
+
productName: `${firstSegment.departureAirportName} - ${lastSegment.arrivalAirportName} (${firstSegment.marketingAirlineName})`,
|
|
30792
|
+
productCode: `${firstSegment.departureAirportCode} ${lastSegment.arrivalAirportCode}/${firstSegment.marketingAirlineCode}`,
|
|
30793
|
+
accommodationName: firstSegment.metaData?.farePriceClassName ?? line.accommodationName,
|
|
30794
|
+
accommodationCode: firstSegment.metaData?.fareCode ?? line.accommodationCode,
|
|
30795
|
+
flightInformation: {
|
|
30796
|
+
pnr: '',
|
|
30797
|
+
flightLines: mapFlightSegmentsToFlightLines(segments)
|
|
30798
|
+
},
|
|
30799
|
+
isChanged: true
|
|
30800
|
+
};
|
|
30801
|
+
};
|
|
30802
|
+
|
|
30803
|
+
const getLocation = (result) => {
|
|
30804
|
+
const place = result.locationName || result.regionName || result.oordName;
|
|
30805
|
+
if (!place)
|
|
30806
|
+
return result.countryName ?? '';
|
|
30807
|
+
return result.countryName ? `${place}, ${result.countryName}` : place;
|
|
30808
|
+
};
|
|
30809
|
+
const toPlainText = (value) => {
|
|
30810
|
+
if (!value)
|
|
30811
|
+
return '';
|
|
30812
|
+
return he
|
|
30813
|
+
.decode(value.replace(/<[^>]*>/g, ' '))
|
|
30814
|
+
.replace(/\s+/g, ' ')
|
|
30815
|
+
.trim();
|
|
30816
|
+
};
|
|
30817
|
+
const TrajectNodeCard = ({ item, result, isSelected, languageCode, translations, onSelect, onEditOptions, showNights }) => {
|
|
30818
|
+
const { node } = item;
|
|
30819
|
+
const selectedPerRoom = (result.rooms ?? []).map((room) => (room.options ?? []).find((x) => x.isSelected) ?? (room.options ?? [])[0]);
|
|
30820
|
+
const isMultiRoom = selectedPerRoom.length > 1;
|
|
30821
|
+
const price = formatPrice$3(result.price, result.currencyCode, languageCode);
|
|
30822
|
+
const nights = calculateNights(new Date(result.fromDate), new Date(result.toDate));
|
|
30823
|
+
const candidate = findCandidateForResult(node, result);
|
|
30824
|
+
const image = candidate?.imageUrl ?? null;
|
|
30825
|
+
const description = toPlainText(candidate?.description);
|
|
30826
|
+
const title = candidate?.name ?? result.name;
|
|
30827
|
+
const priceBlock = (React__default["default"].createElement("div", { className: "search__result-card__price__wrapper" },
|
|
30828
|
+
React__default["default"].createElement("span", { className: "search__result-card__price__label" }, translations?.SHARED.TOTAL_PRICE),
|
|
30829
|
+
React__default["default"].createElement("span", { className: "search__result-card__price" }, price)));
|
|
30830
|
+
const canEditOptions = isSelected && !!onEditOptions && (result.rooms ?? []).some((room) => (room.options ?? []).length > 1);
|
|
30831
|
+
const selectButton = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
30832
|
+
React__default["default"].createElement("button", { type: "button", className: `cta ${isSelected ? 'cta--selected' : 'cta--select'}`, onClick: onSelect }, isSelected ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT),
|
|
30833
|
+
canEditOptions && (React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: onEditOptions },
|
|
30834
|
+
translations?.SRP.SELECT,
|
|
30835
|
+
" ",
|
|
30836
|
+
translations?.SRP.ACCOMMODATION))));
|
|
30837
|
+
if (result.contents?.length) {
|
|
30838
|
+
return (React__default["default"].createElement("div", { className: `search__result-card__wrapper search__result-card__wrapper--custom ${isSelected ? 'search__result-card__wrapper--selected' : ''}` },
|
|
30839
|
+
React__default["default"].createElement("div", { className: "search__result-card__top", dangerouslySetInnerHTML: { __html: he.decode(result.contents) } }),
|
|
30840
|
+
React__default["default"].createElement("div", { className: "search__result-card__footer" }, selectButton)));
|
|
30841
|
+
}
|
|
30842
|
+
return (React__default["default"].createElement("div", { className: `search__result-card__wrapper ${isSelected ? 'search__result-card__wrapper--selected' : ''}` },
|
|
30843
|
+
image && (React__default["default"].createElement("div", { className: "search__result-card__img-wrapper" },
|
|
30844
|
+
React__default["default"].createElement("img", { src: image, alt: title, className: "search__result-card__img" }),
|
|
30845
|
+
priceBlock)),
|
|
30846
|
+
React__default["default"].createElement("div", { className: "search__result-card__content" },
|
|
30847
|
+
React__default["default"].createElement("div", { className: "search__result-card__content__wrapper" },
|
|
30848
|
+
React__default["default"].createElement("div", { className: "search__result-card__header" },
|
|
30849
|
+
React__default["default"].createElement("div", { className: "search__result-card__header__wrapper" },
|
|
30850
|
+
!!result.stars && (React__default["default"].createElement("div", { className: "rating" }, [...Array(result.stars)].map((_, index) => (React__default["default"].createElement(Icon, { name: "ui-star", key: `rating-star-${index + 1}`, width: 14, height: 14 }))))),
|
|
30851
|
+
React__default["default"].createElement("h3", { className: "search__result-card__title" }, title)),
|
|
30852
|
+
!image && priceBlock),
|
|
30853
|
+
React__default["default"].createElement("span", { className: "search__result-card__location" },
|
|
30854
|
+
React__default["default"].createElement(Icon, { name: "ui-location", height: 16 }),
|
|
30855
|
+
getLocation(result)),
|
|
30856
|
+
React__default["default"].createElement("div", { className: "search__result-card__options" },
|
|
30857
|
+
showNights && nights > 0 && (React__default["default"].createElement("div", { className: "search__result-card__option" },
|
|
30858
|
+
React__default["default"].createElement(Icon, { name: "ui-moon", height: 16 }),
|
|
30859
|
+
nights,
|
|
30860
|
+
" ",
|
|
30861
|
+
translations?.SRP.NIGHTS)),
|
|
30862
|
+
selectedPerRoom.map((option, roomIndex) => (React__default["default"].createElement(React__default["default"].Fragment, { key: `room-${roomIndex}` },
|
|
30863
|
+
option?.accommodationName && (React__default["default"].createElement("div", { className: "search__result-card__option" },
|
|
30864
|
+
React__default["default"].createElement(Icon, { name: "ui-bed", height: 16 }),
|
|
30865
|
+
isMultiRoom && `${translations?.SHARED.ROOM} ${roomIndex + 1}: `,
|
|
30866
|
+
option.accommodationName)),
|
|
30867
|
+
option?.regimeName && (React__default["default"].createElement("div", { className: "search__result-card__option" },
|
|
30868
|
+
React__default["default"].createElement(Icon, { name: "ui-utensils", height: 16 }),
|
|
30869
|
+
option.regimeName)))))),
|
|
30870
|
+
description && React__default["default"].createElement("p", { className: "search__result-card__description" }, description)),
|
|
30871
|
+
React__default["default"].createElement("div", { className: "search__result-card__footer" }, selectButton))));
|
|
30872
|
+
};
|
|
30873
|
+
|
|
30874
|
+
const TrajectResultsFlyIn = ({ isLoading }) => {
|
|
30875
|
+
const context = React.useContext(SearchResultsConfigurationContext);
|
|
30876
|
+
const dispatch = reactRedux.useDispatch();
|
|
30877
|
+
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
30878
|
+
const { trajectNodeAvailability, trajectEditLineGuid } = reactRedux.useSelector((state) => state.searchResults);
|
|
30879
|
+
const trajectEntry = context?.trajectEntry;
|
|
30880
|
+
const item = React.useMemo(() => {
|
|
30881
|
+
if (!trajectEntry || !trajectEditLineGuid)
|
|
30882
|
+
return null;
|
|
30883
|
+
return getTrajectNodesWithLines(trajectEntry).find((x) => x.line.guid === trajectEditLineGuid) ?? null;
|
|
30884
|
+
}, [trajectEntry, trajectEditLineGuid]);
|
|
30885
|
+
if (!context || !item)
|
|
30886
|
+
return null;
|
|
30887
|
+
const availability = trajectNodeAvailability[item.line.guid];
|
|
30888
|
+
const results = availability?.results ?? [];
|
|
30889
|
+
const ordered = [...results].sort((a, b) => {
|
|
30890
|
+
const aConfigured = findCandidateForResult(item.node, a) ? 0 : 1;
|
|
30891
|
+
const bConfigured = findCandidateForResult(item.node, b) ? 0 : 1;
|
|
30892
|
+
return aConfigured - bConfigured || a.price - b.price;
|
|
30893
|
+
});
|
|
30894
|
+
const handleSelect = (code) => {
|
|
30895
|
+
const result = results.find((x) => x.code === code);
|
|
30896
|
+
if (!result)
|
|
30897
|
+
return;
|
|
30898
|
+
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
|
|
30899
|
+
applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
30900
|
+
dispatch(setTrajectEditLineGuid(null));
|
|
30901
|
+
dispatch(setFlyInIsOpen(false));
|
|
30902
|
+
};
|
|
30903
|
+
if (isLoading) {
|
|
30904
|
+
return React__default["default"].createElement(React__default["default"].Fragment, null, context.customSpinner ?? React__default["default"].createElement(Spinner, { label: translations.SRP.LOADING_ACCOMMODATIONS }));
|
|
30905
|
+
}
|
|
30906
|
+
return (React__default["default"].createElement("div", { className: "flyin__content" },
|
|
30907
|
+
React__default["default"].createElement("div", { className: "search__result-row" },
|
|
30908
|
+
React__default["default"].createElement("span", { className: "search__result-row-text" },
|
|
30909
|
+
ordered.length,
|
|
30910
|
+
"\u00A0",
|
|
30911
|
+
translations.SRP.TOTAL_RESULTS_LABEL)),
|
|
30912
|
+
ordered.length === 0 ? (React__default["default"].createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--compact" }, ordered.map((result) => (React__default["default"].createElement(TrajectNodeCard, { key: result.code, item: item, result: result, isSelected: result.code === availability?.selectedCode, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(result.code), showNights: item.node.serviceType === ACCOMMODATION_SERVICE_TYPE })))))));
|
|
30913
|
+
};
|
|
30914
|
+
|
|
30606
30915
|
const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, detailsLoading, flyInType, isPackageEditFlow, handleConfirm, sortByTypes, activeSearchSeed, toggleFilters, filtersOpen }) => {
|
|
30607
30916
|
const dispatch = reactRedux.useDispatch();
|
|
30608
30917
|
const context = React.useContext(SearchResultsConfigurationContext);
|
|
@@ -30648,6 +30957,10 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
|
|
|
30648
30957
|
}
|
|
30649
30958
|
};
|
|
30650
30959
|
const handleGoBack = () => {
|
|
30960
|
+
if (context?.trajectEntry) {
|
|
30961
|
+
handleClose();
|
|
30962
|
+
return;
|
|
30963
|
+
}
|
|
30651
30964
|
if (flyInType === 'acco-details') {
|
|
30652
30965
|
dispatch(setFlyInType('acco-results'));
|
|
30653
30966
|
}
|
|
@@ -30671,7 +30984,7 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
|
|
|
30671
30984
|
dispatch(setBookPackagingEntry(true));
|
|
30672
30985
|
}
|
|
30673
30986
|
};
|
|
30674
|
-
return (React__default["default"].createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
|
|
30987
|
+
return (React__default["default"].createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
|
|
30675
30988
|
${flyInType === 'flight-outward-results' || flyInType === 'flight-return-results' ? 'flyin--flight' : ''}` },
|
|
30676
30989
|
React__default["default"].createElement("div", { className: `flyin__panel ${isOpen ? 'flyin__panel--active' : ''}`, ref: panelRef },
|
|
30677
30990
|
React__default["default"].createElement("div", { className: "flyin__content" },
|
|
@@ -30697,7 +31010,10 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
|
|
|
30697
31010
|
React__default["default"].createElement(Icon, { name: "ui-chevron", width: 14, height: 14, "aria-hidden": "true" }),
|
|
30698
31011
|
"Go Back")))),
|
|
30699
31012
|
srpType === build.PortalQsmType.Flight && React__default["default"].createElement(FlightsFlyIn, { isOpen: isOpen, setIsOpen: setIsOpen }),
|
|
30700
|
-
|
|
31013
|
+
context?.trajectEntry && flyInType === 'acco-results' && React__default["default"].createElement(TrajectResultsFlyIn, { isLoading: detailsLoading }),
|
|
31014
|
+
!context?.trajectEntry &&
|
|
31015
|
+
(srpType === build.PortalQsmType.Accommodation || srpType === build.PortalQsmType.AccommodationAndFlight) &&
|
|
31016
|
+
flyInType === 'acco-results' && (React__default["default"].createElement("div", { className: "flyin__content flyin__content--columns" },
|
|
30701
31017
|
React__default["default"].createElement(Filters, { initialFilters: initialFilters, filters: filters, isOpen: filtersOpen, handleSetIsOpen: () => toggleFilters && toggleFilters(),
|
|
30702
31018
|
// handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
|
|
30703
31019
|
isLoading: isLoading, setFilters: (filters) => dispatch(setFilters(filters)), resetFilters: (filters) => dispatch(resetFilters(filters)) }),
|
|
@@ -32970,232 +33286,6 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
32970
33286
|
React__default["default"].createElement(WLSidebar, { activeSearchSeed: activeSearchSeed, packagingAccoResult: selectedPackagingAccoResult }))));
|
|
32971
33287
|
};
|
|
32972
33288
|
|
|
32973
|
-
const REGULAR_TRAJECT_NODE_TYPE = 0;
|
|
32974
|
-
const isSearchableTrajectNode = (node) => node.serviceType === ACCOMMODATION_SERVICE_TYPE || node.serviceType === EXCURSION_SERVICE_TYPE;
|
|
32975
|
-
const isTrajectFlightNode = (node) => node.serviceType === FLIGHT_SERVICE_TYPE;
|
|
32976
|
-
const getTrajectNodesWithLines = (trajectEntry) => {
|
|
32977
|
-
const linesByGuid = new Map((trajectEntry.entry.lines ?? []).map((line) => [line.guid, line]));
|
|
32978
|
-
return [...(trajectEntry.nodes ?? [])]
|
|
32979
|
-
.sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
|
|
32980
|
-
.map((node) => ({ node, line: linesByGuid.get(node.lineGuid) }))
|
|
32981
|
-
.filter((x) => !!x.line);
|
|
32982
|
-
};
|
|
32983
|
-
const buildDestination = (line) => {
|
|
32984
|
-
if (line.location?.id)
|
|
32985
|
-
return { id: line.location.id, isLocation: true };
|
|
32986
|
-
if (line.oord?.id)
|
|
32987
|
-
return { id: line.oord.id, isOord: true };
|
|
32988
|
-
if (line.region?.id)
|
|
32989
|
-
return { id: line.region.id, isRegion: true };
|
|
32990
|
-
if (line.country?.id)
|
|
32991
|
-
return { id: line.country.id, isCountry: true };
|
|
32992
|
-
if (line.latitude && line.longitude)
|
|
32993
|
-
return { latitude: line.latitude, longitude: line.longitude };
|
|
32994
|
-
return { id: 0 };
|
|
32995
|
-
};
|
|
32996
|
-
const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
|
|
32997
|
-
transactionId: context.transactionId,
|
|
32998
|
-
officeId: context.officeId,
|
|
32999
|
-
agentId: context.agentId ?? null,
|
|
33000
|
-
catalogueId: context.catalogueId,
|
|
33001
|
-
searchConfigurationId: context.searchConfigurationId,
|
|
33002
|
-
portalId: context.portalId ?? null,
|
|
33003
|
-
vendorConfigurationId: node.externalVendorId ?? null,
|
|
33004
|
-
language: context.language,
|
|
33005
|
-
serviceType: node.serviceType,
|
|
33006
|
-
fromDate: toDateOnlyString(line.from),
|
|
33007
|
-
toDate: toDateOnlyString(line.to),
|
|
33008
|
-
destination: buildDestination(line),
|
|
33009
|
-
productCode,
|
|
33010
|
-
rooms: context.rooms,
|
|
33011
|
-
tagIds: []
|
|
33012
|
-
});
|
|
33013
|
-
const getNodeCandidates = (node) => {
|
|
33014
|
-
const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
|
|
33015
|
-
if (configured.length)
|
|
33016
|
-
return configured;
|
|
33017
|
-
const fallbackCode = node.code ?? node.preferredAccommodationCode;
|
|
33018
|
-
if (!fallbackCode || !fallbackCode.trim().length)
|
|
33019
|
-
return [];
|
|
33020
|
-
return [
|
|
33021
|
-
{
|
|
33022
|
-
code: fallbackCode,
|
|
33023
|
-
name: node.name,
|
|
33024
|
-
description: node.description,
|
|
33025
|
-
imageUrl: node.imageUrl,
|
|
33026
|
-
contentSource: node.contentSource,
|
|
33027
|
-
vendor: node.vendor,
|
|
33028
|
-
externalVendorId: node.externalVendorId,
|
|
33029
|
-
isPreferred: true
|
|
33030
|
-
}
|
|
33031
|
-
];
|
|
33032
|
-
};
|
|
33033
|
-
const findCandidateForResult = (node, result) => getNodeCandidates(node).find((candidate) => matchesCode(result, candidate.code)) ?? null;
|
|
33034
|
-
const matchesCode = (result, code) => {
|
|
33035
|
-
if (result.code === code)
|
|
33036
|
-
return true;
|
|
33037
|
-
return (result.rooms ?? []).some((room) => (room.options ?? []).some((option) => option.accommodationCode === code));
|
|
33038
|
-
};
|
|
33039
|
-
const getPackagingRoomsFromEntry = (entry) => {
|
|
33040
|
-
const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));
|
|
33041
|
-
const rooms = (entry.rooms ?? []).map((room) => ({
|
|
33042
|
-
travellers: (room.paxIds ?? []).map((paxId) => {
|
|
33043
|
-
const pax = paxById.get(paxId);
|
|
33044
|
-
return {
|
|
33045
|
-
id: paxId,
|
|
33046
|
-
age: pax?.age ?? null,
|
|
33047
|
-
dateOfBirth: pax?.dateOfBirth ?? null
|
|
33048
|
-
};
|
|
33049
|
-
})
|
|
33050
|
-
}));
|
|
33051
|
-
return rooms.filter((room) => room.travellers.length > 0);
|
|
33052
|
-
};
|
|
33053
|
-
const pickCheapest = (results) => [...results].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
33054
|
-
const applyResultToLine = (line, result) => {
|
|
33055
|
-
const option = (result.rooms ?? []).flatMap((room) => room.options ?? []).find((x) => x.isSelected) ?? (result.rooms ?? [])[0]?.options?.[0];
|
|
33056
|
-
return {
|
|
33057
|
-
...line,
|
|
33058
|
-
productName: result.name ?? line.productName,
|
|
33059
|
-
productCode: result.code ?? line.productCode,
|
|
33060
|
-
accommodationCode: option?.accommodationCode ?? line.accommodationCode,
|
|
33061
|
-
accommodationName: option?.accommodationName ?? line.accommodationName,
|
|
33062
|
-
regimeCode: option?.regimeCode ?? line.regimeCode,
|
|
33063
|
-
regimeName: option?.regimeName ?? line.regimeName,
|
|
33064
|
-
latitude: result.latitude ?? line.latitude,
|
|
33065
|
-
longitude: result.longitude ?? line.longitude,
|
|
33066
|
-
isChanged: true
|
|
33067
|
-
};
|
|
33068
|
-
};
|
|
33069
|
-
const toDateOnlyUtcString = (value) => {
|
|
33070
|
-
const date = new Date(value);
|
|
33071
|
-
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
|
|
33072
|
-
};
|
|
33073
|
-
const toTimeOnlyString = (value) => {
|
|
33074
|
-
const date = new Date(value);
|
|
33075
|
-
const hh = String(date.getUTCHours()).padStart(2, '0');
|
|
33076
|
-
const mm = String(date.getUTCMinutes()).padStart(2, '0');
|
|
33077
|
-
const ss = String(date.getUTCSeconds()).padStart(2, '0');
|
|
33078
|
-
return `${hh}:${mm}:${ss}`;
|
|
33079
|
-
};
|
|
33080
|
-
const mapFlightSegmentsToFlightLines = (segments) => segments.map((segment) => ({
|
|
33081
|
-
airlineCode: segment.marketingAirlineCode,
|
|
33082
|
-
airlineDescription: segment.marketingAirlineName,
|
|
33083
|
-
operatingAirlineCode: segment.operatingAirlineCode,
|
|
33084
|
-
operatingAirlineDescription: segment.operatingAirlineName,
|
|
33085
|
-
flightNumber: segment.flightNumber,
|
|
33086
|
-
operatingFlightNumber: segment.operatingFlightNumber ?? null,
|
|
33087
|
-
departureDate: toDateOnlyUtcString(segment.departureDateTime),
|
|
33088
|
-
departureTime: toTimeOnlyString(segment.departureDateTime),
|
|
33089
|
-
departureAirportCode: segment.departureAirportCode,
|
|
33090
|
-
departureAirportDescription: segment.departureAirportName,
|
|
33091
|
-
arrivalDate: toDateOnlyUtcString(segment.arrivalDateTime),
|
|
33092
|
-
arrivalTime: toTimeOnlyString(segment.arrivalDateTime),
|
|
33093
|
-
arrivalAirportCode: segment.arrivalAirportCode,
|
|
33094
|
-
arrivalAirportDescription: segment.arrivalAirportName,
|
|
33095
|
-
durationInTicks: segment.durationInTicks
|
|
33096
|
-
}));
|
|
33097
|
-
const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
33098
|
-
transactionId: context.transactionId,
|
|
33099
|
-
officeId: context.officeId,
|
|
33100
|
-
catalogueId: context.catalogueId,
|
|
33101
|
-
agentId: context.agentId ?? null,
|
|
33102
|
-
language: context.language,
|
|
33103
|
-
departureAirportCode: node.departureAirportCode ?? '',
|
|
33104
|
-
arrivalAirportCode: node.arrivalAirportCode ?? '',
|
|
33105
|
-
returnAirportCode: null,
|
|
33106
|
-
luggageIncluded: null,
|
|
33107
|
-
maxStops: null,
|
|
33108
|
-
travelClass: null,
|
|
33109
|
-
vendorConfigurationId: node.externalVendorId ?? null,
|
|
33110
|
-
pax,
|
|
33111
|
-
outward: { date: dateToDateStruct(new Date(line.from)) },
|
|
33112
|
-
return: null
|
|
33113
|
-
});
|
|
33114
|
-
const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
33115
|
-
const applyFlightToLine = (line, flight) => {
|
|
33116
|
-
const segments = flight.outward?.segments ?? [];
|
|
33117
|
-
if (!segments.length)
|
|
33118
|
-
return line;
|
|
33119
|
-
const firstSegment = segments[0];
|
|
33120
|
-
const lastSegment = segments[segments.length - 1];
|
|
33121
|
-
return {
|
|
33122
|
-
...line,
|
|
33123
|
-
from: new Date(firstSegment.departureDateTime).toISOString(),
|
|
33124
|
-
to: new Date(lastSegment.arrivalDateTime).toISOString(),
|
|
33125
|
-
productName: `${firstSegment.departureAirportName} - ${lastSegment.arrivalAirportName} (${firstSegment.marketingAirlineName})`,
|
|
33126
|
-
productCode: `${firstSegment.departureAirportCode} ${lastSegment.arrivalAirportCode}/${firstSegment.marketingAirlineCode}`,
|
|
33127
|
-
accommodationName: firstSegment.metaData?.farePriceClassName ?? line.accommodationName,
|
|
33128
|
-
accommodationCode: firstSegment.metaData?.fareCode ?? line.accommodationCode,
|
|
33129
|
-
flightInformation: {
|
|
33130
|
-
pnr: '',
|
|
33131
|
-
flightLines: mapFlightSegmentsToFlightLines(segments)
|
|
33132
|
-
},
|
|
33133
|
-
isChanged: true
|
|
33134
|
-
};
|
|
33135
|
-
};
|
|
33136
|
-
|
|
33137
|
-
const getLocation = (result) => {
|
|
33138
|
-
const place = result.locationName || result.regionName || result.oordName;
|
|
33139
|
-
if (!place)
|
|
33140
|
-
return result.countryName ?? '';
|
|
33141
|
-
return result.countryName ? `${place}, ${result.countryName}` : place;
|
|
33142
|
-
};
|
|
33143
|
-
const toPlainText = (value) => {
|
|
33144
|
-
if (!value)
|
|
33145
|
-
return '';
|
|
33146
|
-
return he
|
|
33147
|
-
.decode(value.replace(/<[^>]*>/g, ' '))
|
|
33148
|
-
.replace(/\s+/g, ' ')
|
|
33149
|
-
.trim();
|
|
33150
|
-
};
|
|
33151
|
-
const TrajectNodeCard = ({ item, result, isSelected, languageCode, translations, onSelect, showNights }) => {
|
|
33152
|
-
const { node } = item;
|
|
33153
|
-
const selectedOption = lodash.first(result.rooms)?.options?.find((x) => x.isSelected) ?? lodash.first(result.rooms)?.options?.[0];
|
|
33154
|
-
const price = formatPrice$3(result.price, result.currencyCode, languageCode);
|
|
33155
|
-
const nights = calculateNights(new Date(result.fromDate), new Date(result.toDate));
|
|
33156
|
-
const candidate = findCandidateForResult(node, result);
|
|
33157
|
-
const image = candidate?.imageUrl ?? null;
|
|
33158
|
-
const description = toPlainText(candidate?.description);
|
|
33159
|
-
const title = candidate?.name ?? result.name;
|
|
33160
|
-
const priceBlock = (React__default["default"].createElement("div", { className: "search__result-card__price__wrapper" },
|
|
33161
|
-
React__default["default"].createElement("span", { className: "search__result-card__price__label" }, translations?.SHARED.TOTAL_PRICE),
|
|
33162
|
-
React__default["default"].createElement("span", { className: "search__result-card__price" }, price)));
|
|
33163
|
-
const selectButton = (React__default["default"].createElement("button", { type: "button", className: `cta ${isSelected ? 'cta--selected' : 'cta--select'}`, onClick: onSelect }, isSelected ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT));
|
|
33164
|
-
if (result.contents?.length) {
|
|
33165
|
-
return (React__default["default"].createElement("div", { className: `search__result-card__wrapper search__result-card__wrapper--custom ${isSelected ? 'search__result-card__wrapper--selected' : ''}` },
|
|
33166
|
-
React__default["default"].createElement("div", { className: "search__result-card__top", dangerouslySetInnerHTML: { __html: he.decode(result.contents) } }),
|
|
33167
|
-
React__default["default"].createElement("div", { className: "search__result-card__footer" }, selectButton)));
|
|
33168
|
-
}
|
|
33169
|
-
return (React__default["default"].createElement("div", { className: `search__result-card__wrapper ${isSelected ? 'search__result-card__wrapper--selected' : ''}` },
|
|
33170
|
-
image && (React__default["default"].createElement("div", { className: "search__result-card__img-wrapper" },
|
|
33171
|
-
React__default["default"].createElement("img", { src: image, alt: title, className: "search__result-card__img" }),
|
|
33172
|
-
priceBlock)),
|
|
33173
|
-
React__default["default"].createElement("div", { className: "search__result-card__content" },
|
|
33174
|
-
React__default["default"].createElement("div", { className: "search__result-card__content__wrapper" },
|
|
33175
|
-
React__default["default"].createElement("div", { className: "search__result-card__header" },
|
|
33176
|
-
React__default["default"].createElement("div", { className: "search__result-card__header__wrapper" },
|
|
33177
|
-
!!result.stars && (React__default["default"].createElement("div", { className: "rating" }, [...Array(result.stars)].map((_, index) => (React__default["default"].createElement(Icon, { name: "ui-star", key: `rating-star-${index + 1}`, width: 14, height: 14 }))))),
|
|
33178
|
-
React__default["default"].createElement("h3", { className: "search__result-card__title" }, title)),
|
|
33179
|
-
!image && priceBlock),
|
|
33180
|
-
React__default["default"].createElement("span", { className: "search__result-card__location" },
|
|
33181
|
-
React__default["default"].createElement(Icon, { name: "ui-location", height: 16 }),
|
|
33182
|
-
getLocation(result)),
|
|
33183
|
-
React__default["default"].createElement("div", { className: "search__result-card__options" },
|
|
33184
|
-
showNights && nights > 0 && (React__default["default"].createElement("div", { className: "search__result-card__option" },
|
|
33185
|
-
React__default["default"].createElement(Icon, { name: "ui-moon", height: 16 }),
|
|
33186
|
-
nights,
|
|
33187
|
-
" ",
|
|
33188
|
-
translations?.SRP.NIGHTS)),
|
|
33189
|
-
selectedOption?.accommodationName && (React__default["default"].createElement("div", { className: "search__result-card__option" },
|
|
33190
|
-
React__default["default"].createElement(Icon, { name: "ui-bed", height: 16 }),
|
|
33191
|
-
selectedOption.accommodationName)),
|
|
33192
|
-
selectedOption?.regimeName && (React__default["default"].createElement("div", { className: "search__result-card__option" },
|
|
33193
|
-
React__default["default"].createElement(Icon, { name: "ui-utensils", height: 16 }),
|
|
33194
|
-
selectedOption.regimeName))),
|
|
33195
|
-
description && React__default["default"].createElement("p", { className: "search__result-card__description" }, description)),
|
|
33196
|
-
React__default["default"].createElement("div", { className: "search__result-card__footer" }, selectButton))));
|
|
33197
|
-
};
|
|
33198
|
-
|
|
33199
33289
|
const getNodeIcon = (node) => {
|
|
33200
33290
|
if (isTrajectFlightNode(node))
|
|
33201
33291
|
return 'ui-flight';
|
|
@@ -33235,13 +33325,28 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33235
33325
|
if (!result)
|
|
33236
33326
|
return;
|
|
33237
33327
|
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
|
|
33238
|
-
|
|
33328
|
+
applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
33329
|
+
};
|
|
33330
|
+
const handleShowMore = (item) => {
|
|
33331
|
+
dispatch(setTrajectEditLineGuid(item.line.guid));
|
|
33332
|
+
dispatch(setFlyInType('acco-results'));
|
|
33333
|
+
dispatch(setFlyInIsOpen(true));
|
|
33334
|
+
};
|
|
33335
|
+
const handleEditOptions = (item) => {
|
|
33336
|
+
const availability = trajectNodeAvailability[item.line.guid];
|
|
33337
|
+
const result = availability?.results.find((x) => x.code === availability?.selectedCode);
|
|
33338
|
+
if (!result)
|
|
33339
|
+
return;
|
|
33340
|
+
dispatch(setPackagingAccoSearchDetails([result]));
|
|
33341
|
+
dispatch(setSelectedPackagingAccoResult(result.code));
|
|
33342
|
+
dispatch(setTrajectEditLineGuid(item.line.guid));
|
|
33343
|
+
dispatch(setFlyInType('acco-details'));
|
|
33344
|
+
dispatch(setFlyInIsOpen(true));
|
|
33239
33345
|
};
|
|
33240
33346
|
const renderServiceNode = (item) => {
|
|
33241
33347
|
console.log('renderServiceNode', item);
|
|
33242
33348
|
const { node, line } = item;
|
|
33243
33349
|
const availability = trajectNodeAvailability[line.guid];
|
|
33244
|
-
const isExpanded = !!expandedNodes[line.guid];
|
|
33245
33350
|
const results = availability?.results ?? [];
|
|
33246
33351
|
const selected = results.find((x) => x.code === availability?.selectedCode) ?? null;
|
|
33247
33352
|
const configured = results.filter((x) => x.code !== selected?.code && !!findCandidateForResult(node, x));
|
|
@@ -33263,9 +33368,13 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33263
33368
|
node.preferredAccommodationName,
|
|
33264
33369
|
" \u2014 ",
|
|
33265
33370
|
translations.SRP.NO_RESULTS))),
|
|
33266
|
-
React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--
|
|
33371
|
+
React__default["default"].createElement("div", { className: "search__results__cards search__results__cards--compact" }, [selected, ...configured].map((result) => (React__default["default"].createElement(TrajectNodeCard, { key: result.code, item: item, result: result, isSelected: result.code === selected.code, languageCode: context.languageCode, translations: translations, onSelect: () => handleSelect(item, result.code), onEditOptions: node.serviceType === ACCOMMODATION_SERVICE_TYPE ? () => handleEditOptions(item) : undefined, showNights: node.serviceType === ACCOMMODATION_SERVICE_TYPE })))),
|
|
33267
33372
|
others.length > 0 && (React__default["default"].createElement("div", { className: "search__results__cards__actions" },
|
|
33268
|
-
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () =>
|
|
33373
|
+
React__default["default"].createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
|
|
33374
|
+
translations.SRP.SHOW_MORE,
|
|
33375
|
+
" (",
|
|
33376
|
+
others.length,
|
|
33377
|
+
")")))))));
|
|
33269
33378
|
};
|
|
33270
33379
|
const handleSelectFlight = (item, flight) => {
|
|
33271
33380
|
dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
|
|
@@ -33310,6 +33419,8 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33310
33419
|
if (!dayNodes.length)
|
|
33311
33420
|
return null;
|
|
33312
33421
|
return (React__default["default"].createElement(React__default["default"].Fragment, { key: `day-${day.order}` }, dayNodes.map((node) => {
|
|
33422
|
+
if (node.serviceType !== ACCOMMODATION_SERVICE_TYPE && node.serviceType !== EXCURSION_SERVICE_TYPE && node.serviceType !== FLIGHT_SERVICE_TYPE)
|
|
33423
|
+
return null;
|
|
33313
33424
|
// if (node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE) return null;
|
|
33314
33425
|
// if (node.trajectNodeType !== REGULAR_TRAJECT_NODE_TYPE) return renderContextNode(node);
|
|
33315
33426
|
if (node.trajectNodeType !== REGULAR_TRAJECT_NODE_TYPE)
|
|
@@ -33327,6 +33438,7 @@ const useTrajectAvailability = () => {
|
|
|
33327
33438
|
const context = React.useContext(SearchResultsConfigurationContext);
|
|
33328
33439
|
const dispatch = reactRedux.useDispatch();
|
|
33329
33440
|
const trajectEntry = context?.trajectEntry;
|
|
33441
|
+
const showNonPreferredItems = !!context?.showNonPreferredItems;
|
|
33330
33442
|
React.useEffect(() => {
|
|
33331
33443
|
if (!context || !trajectEntry)
|
|
33332
33444
|
return;
|
|
@@ -33371,18 +33483,20 @@ const useTrajectAvailability = () => {
|
|
|
33371
33483
|
return null;
|
|
33372
33484
|
}
|
|
33373
33485
|
}));
|
|
33374
|
-
|
|
33375
|
-
|
|
33486
|
+
const configuredResults = attempts
|
|
33487
|
+
.filter((x) => !!x)
|
|
33488
|
+
.filter((x, i, all) => all.findIndex((y) => y.code === x.code) === i);
|
|
33376
33489
|
const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
|
|
33377
|
-
let preferredUnavailable = !!preferredCandidate && !
|
|
33378
|
-
|
|
33379
|
-
|
|
33380
|
-
|
|
33381
|
-
|
|
33490
|
+
let preferredUnavailable = !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code));
|
|
33491
|
+
const destinationResults = showNonPreferredItems
|
|
33492
|
+
? ((await search(config, buildTrajectNodeRequest(item, searchContext, ''), controller.signal)) ?? []).filter((x) => !configuredResults.some((configured) => configured.code === x.code))
|
|
33493
|
+
: [];
|
|
33494
|
+
const results = [...configuredResults, ...destinationResults];
|
|
33495
|
+
const picked = configuredResults[0] ?? pickCheapest(destinationResults);
|
|
33496
|
+
if (!configuredResults.length)
|
|
33382
33497
|
preferredUnavailable = candidates.length > 0;
|
|
33383
|
-
}
|
|
33384
33498
|
if (controller.signal.aborted)
|
|
33385
|
-
return
|
|
33499
|
+
return [];
|
|
33386
33500
|
dispatch(setTrajectNodeAvailability({
|
|
33387
33501
|
lineGuid,
|
|
33388
33502
|
results,
|
|
@@ -33390,58 +33504,58 @@ const useTrajectAvailability = () => {
|
|
|
33390
33504
|
preferredUnavailable
|
|
33391
33505
|
}));
|
|
33392
33506
|
if (!picked)
|
|
33393
|
-
return
|
|
33394
|
-
|
|
33395
|
-
return
|
|
33507
|
+
return item.lines.map((x) => x.guid);
|
|
33508
|
+
applyResultToLines(item.lines, picked).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
33509
|
+
return [];
|
|
33396
33510
|
}
|
|
33397
33511
|
catch (error) {
|
|
33398
33512
|
if (controller.signal.aborted)
|
|
33399
|
-
return
|
|
33513
|
+
return [];
|
|
33400
33514
|
console.error('Failed to resolve traject node availability', item.node.name, error);
|
|
33401
33515
|
dispatch(setTrajectNodeAvailability({ lineGuid, results: [], selectedCode: null, preferredUnavailable: false }));
|
|
33402
|
-
return
|
|
33516
|
+
return item.lines.map((x) => x.guid);
|
|
33403
33517
|
}
|
|
33404
33518
|
};
|
|
33405
33519
|
const resolveFlightNode = async (item) => {
|
|
33406
33520
|
const lineGuid = item.line.guid;
|
|
33407
33521
|
if (!item.node.departureAirportCode || !item.node.arrivalAirportCode) {
|
|
33408
33522
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
33409
|
-
return
|
|
33523
|
+
return item.lines.map((x) => x.guid);
|
|
33410
33524
|
}
|
|
33411
33525
|
dispatch(setTrajectFlightLoading(lineGuid));
|
|
33412
33526
|
try {
|
|
33413
33527
|
const flights = (await build.searchPackagingFlights(config, buildTrajectFlightRequest(item, searchContext, flightPax), controller.signal)) ?? [];
|
|
33414
33528
|
if (controller.signal.aborted)
|
|
33415
|
-
return
|
|
33529
|
+
return [];
|
|
33416
33530
|
const picked = pickCheapestFlight(flights);
|
|
33417
33531
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: flights, selectedGuid: picked?.outwardGuid ?? null }));
|
|
33418
33532
|
if (!picked)
|
|
33419
|
-
return
|
|
33533
|
+
return item.lines.map((x) => x.guid);
|
|
33420
33534
|
dispatch(updateEditableEntryLine(applyFlightToLine(item.line, picked)));
|
|
33421
|
-
return
|
|
33535
|
+
return [];
|
|
33422
33536
|
}
|
|
33423
33537
|
catch (error) {
|
|
33424
33538
|
if (controller.signal.aborted)
|
|
33425
|
-
return
|
|
33539
|
+
return [];
|
|
33426
33540
|
console.error('Failed to resolve traject flight', item.node.name, error);
|
|
33427
33541
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
33428
|
-
return
|
|
33542
|
+
return item.lines.map((x) => x.guid);
|
|
33429
33543
|
}
|
|
33430
33544
|
};
|
|
33431
33545
|
(async () => {
|
|
33432
33546
|
const searchable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node));
|
|
33433
33547
|
const flightNodes = nodesWithLines.filter((x) => isTrajectFlightNode(x.node));
|
|
33434
|
-
const unresolved = await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)]);
|
|
33548
|
+
const unresolved = (await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)])).flat();
|
|
33435
33549
|
if (controller.signal.aborted)
|
|
33436
33550
|
return;
|
|
33437
33551
|
// A node with no availability anywhere cannot be priced or booked, so its line comes off
|
|
33438
33552
|
// the entry. The card stays visible and reports the gap.
|
|
33439
|
-
const emptyLineGuids = unresolved.filter(
|
|
33553
|
+
const emptyLineGuids = unresolved.filter(Boolean);
|
|
33440
33554
|
if (emptyLineGuids.length)
|
|
33441
33555
|
dispatch(removeEditableEntryLines(emptyLineGuids));
|
|
33442
33556
|
})();
|
|
33443
33557
|
return () => controller.abort();
|
|
33444
|
-
}, [trajectEntry]);
|
|
33558
|
+
}, [trajectEntry, showNonPreferredItems]);
|
|
33445
33559
|
};
|
|
33446
33560
|
|
|
33447
33561
|
const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
@@ -33449,7 +33563,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
33449
33563
|
const dispatch = reactRedux.useDispatch();
|
|
33450
33564
|
const context = React.useContext(SearchResultsConfigurationContext);
|
|
33451
33565
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
33452
|
-
const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry } = reactRedux.useSelector((state) => state.searchResults);
|
|
33566
|
+
const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry, trajectEditLineGuid } = reactRedux.useSelector((state) => state.searchResults);
|
|
33453
33567
|
const isMobile = useMediaQuery('(max-width: 1200px)');
|
|
33454
33568
|
// Resolves live availability per traject node; no-op unless a traject entry is configured.
|
|
33455
33569
|
useTrajectAvailability();
|
|
@@ -33738,6 +33852,20 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
33738
33852
|
setDetailsIsLoading(false);
|
|
33739
33853
|
};
|
|
33740
33854
|
const handleConfirmHotelSwap = () => {
|
|
33855
|
+
if (context?.trajectEntry && trajectEditLineGuid) {
|
|
33856
|
+
const item = getTrajectNodesWithLines(context.trajectEntry).find((x) => x.line.guid === trajectEditLineGuid);
|
|
33857
|
+
const result = packagingAccoSearchDetails.find((x) => x.code === selectedPackagingAccoResultCode);
|
|
33858
|
+
if (item && result) {
|
|
33859
|
+
const currentLines = item.lines
|
|
33860
|
+
.map((line) => editablePackagingEntry?.lines?.find((x) => x.guid === line.guid))
|
|
33861
|
+
.filter((x) => !!x);
|
|
33862
|
+
applyResultToLines(currentLines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
33863
|
+
dispatch(updateTrajectNodeResult({ lineGuid: trajectEditLineGuid, result }));
|
|
33864
|
+
}
|
|
33865
|
+
dispatch(setTrajectEditLineGuid(null));
|
|
33866
|
+
handleFlyInToggle(false);
|
|
33867
|
+
return;
|
|
33868
|
+
}
|
|
33741
33869
|
const updatedEntry = swapHotelInPackagingEntry();
|
|
33742
33870
|
if (!updatedEntry)
|
|
33743
33871
|
return;
|
|
@@ -34086,6 +34214,10 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
34086
34214
|
const fetchPackagingAccoSearchDetails = async () => {
|
|
34087
34215
|
if (!selectedPackagingAccoResultCode || !context)
|
|
34088
34216
|
return;
|
|
34217
|
+
// A traject node already resolved its own availability, options per room included, and hands
|
|
34218
|
+
// that result straight to the fly-in.
|
|
34219
|
+
if (context.trajectEntry)
|
|
34220
|
+
return;
|
|
34089
34221
|
if (skipInitialPackagingAccoDetailsRef.current) {
|
|
34090
34222
|
skipInitialPackagingAccoDetailsRef.current = false;
|
|
34091
34223
|
return;
|
|
@@ -37600,20 +37732,20 @@ function ItineraryMapView({ destinations: propDestinations, adults = 2, dateFrom
|
|
|
37600
37732
|
const isStartEnd = dest.isStart || dest.isEnd;
|
|
37601
37733
|
let iconHtml;
|
|
37602
37734
|
if (isStartEnd) {
|
|
37603
|
-
iconHtml = `
|
|
37604
|
-
<div class="map-view__marker map-view__marker--plane">
|
|
37605
|
-
<svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
|
37606
|
-
<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"/>
|
|
37607
|
-
</svg>
|
|
37735
|
+
iconHtml = `
|
|
37736
|
+
<div class="map-view__marker map-view__marker--plane">
|
|
37737
|
+
<svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
|
37738
|
+
<path d="M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10.1-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.3-15.8-20.6l49-196.3L112 288 68.8 377.6c-3 6.1-9.2 10.4-16 10.4l-2.8 0c-9.2 0-16-8.8-13.3-17.6L80 256L36.7 141.6C34 132.8 40.8 124 50 124l2.8 0c6.8 0 13 4.3 16 10.4L112 224l102.9 0-49-196.3C163.5 17.3 171.2 7 181.8 7l56.2 0c11.5 0 22.1 6 27.8 16.1L365.7 192l116.6 0z"/>
|
|
37739
|
+
</svg>
|
|
37608
37740
|
</div>`;
|
|
37609
37741
|
}
|
|
37610
37742
|
else {
|
|
37611
37743
|
stopIndex++;
|
|
37612
37744
|
const imgStyle = dest.imageUrl ? `style="background-image:url('${dest.imageUrl}')"` : '';
|
|
37613
|
-
iconHtml = `
|
|
37614
|
-
<div class="map-view__marker map-view__marker--stop" ${imgStyle}>
|
|
37615
|
-
${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
|
|
37616
|
-
<span class="map-view__marker-badge">${stopIndex}</span>
|
|
37745
|
+
iconHtml = `
|
|
37746
|
+
<div class="map-view__marker map-view__marker--stop" ${imgStyle}>
|
|
37747
|
+
${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
|
|
37748
|
+
<span class="map-view__marker-badge">${stopIndex}</span>
|
|
37617
37749
|
</div>`;
|
|
37618
37750
|
}
|
|
37619
37751
|
const icon = L.divIcon({
|