@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-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, isSameDay, differenceInCalendarDays, addMonths, addDays, formatISO, addYears, differenceInYears, parseISO, differenceInMinutes, parse, startOfToday
|
|
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, isSameDay, 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';
|
|
@@ -22861,6 +22861,10 @@ const NAME_CHARACTERS_REGEX = /^[\p{L}\s-]+$/u;
|
|
|
22861
22861
|
function hasInvalidNameCharacters(name) {
|
|
22862
22862
|
return !NAME_CHARACTERS_REGEX.test(name);
|
|
22863
22863
|
}
|
|
22864
|
+
// Rejects values like a 5-digit year, which the native date input allows while typing
|
|
22865
|
+
function isValidBirthDate(birthDateText) {
|
|
22866
|
+
return isValid(parse(birthDateText, 'yyyy-MM-dd', new Date()));
|
|
22867
|
+
}
|
|
22864
22868
|
function getAge(birthDateText, startDateText) {
|
|
22865
22869
|
var birthDate = new Date(birthDateText);
|
|
22866
22870
|
var startDate = new Date(startDateText);
|
|
@@ -22928,7 +22932,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
22928
22932
|
}
|
|
22929
22933
|
}
|
|
22930
22934
|
if (isFormFieldPresent('birthDate')) {
|
|
22931
|
-
if (isEmpty$1(adult.birthDate)) {
|
|
22935
|
+
if (isEmpty$1(adult.birthDate) || !isValidBirthDate(adult.birthDate)) {
|
|
22932
22936
|
set(errors, `rooms[${rIndex}].adults[${index}].birthDate`, formatTravelerField(rIndex + 1, index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
|
|
22933
22937
|
}
|
|
22934
22938
|
else if (values.endDate) {
|
|
@@ -22961,7 +22965,7 @@ const validateForm$1 = (values, agentRequired, bookingType, translations, formFi
|
|
|
22961
22965
|
}
|
|
22962
22966
|
}
|
|
22963
22967
|
if (isFormFieldPresent('birthDate')) {
|
|
22964
|
-
if (isEmpty$1(child.birthDate)) {
|
|
22968
|
+
if (isEmpty$1(child.birthDate) || !isValidBirthDate(child.birthDate)) {
|
|
22965
22969
|
set(errors, `rooms[${rIndex}].children[${index}].birthDate`, formatTravelerField(rIndex + 1, r.adults.length + index + 1, translations.TRAVELERS_FORM.BIRTHDATE));
|
|
22966
22970
|
}
|
|
22967
22971
|
else if (child.isBaby && values.startDate) {
|
|
@@ -23186,6 +23190,13 @@ const TypeAheadInput = ({ name, value, placeholder, options, onChange, onSelect,
|
|
|
23186
23190
|
function isBabyAge(age, maxBabyAge = BABY_MAX_AGE) {
|
|
23187
23191
|
return typeof age === 'number' && age <= maxBabyAge;
|
|
23188
23192
|
}
|
|
23193
|
+
// The native date input can hold values format() throws on (e.g. a 5+ digit year while typing), so never format an unvalidated birthDate
|
|
23194
|
+
function formatBirthDate$1(birthDate) {
|
|
23195
|
+
if (!birthDate)
|
|
23196
|
+
return '';
|
|
23197
|
+
const parsed = parse(birthDate, 'yyyy-MM-dd', new Date());
|
|
23198
|
+
return isValid(parsed) ? format$2(parsed, 'dd-MM-yyyy') : '';
|
|
23199
|
+
}
|
|
23189
23200
|
function createTraveler(traveler, followNumber, personTranslation, isCompact, maxBabyAge) {
|
|
23190
23201
|
if (isCompact) {
|
|
23191
23202
|
return {
|
|
@@ -23493,10 +23504,7 @@ const SharedTravelersForm = ({ formik, translations, travellersSettings, countri
|
|
|
23493
23504
|
!useCompactForm && (bookingType !== 'b2b' || travellersSettings?.mainBookerFormFields?.length) ? (React__default.createElement("div", { className: "form__region" },
|
|
23494
23505
|
React__default.createElement("div", { className: "form__region-header" },
|
|
23495
23506
|
React__default.createElement("h5", { className: "form__region-heading" }, translations.TRAVELERS_FORM.MAIN_BOOKER),
|
|
23496
|
-
React__default.createElement("p", { className: "form__region-label" }, compact([
|
|
23497
|
-
compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '),
|
|
23498
|
-
mainBooker?.birthDate && format$2(parse(mainBooker.birthDate, 'yyyy-MM-dd', new Date()), 'dd-MM-yyyy')
|
|
23499
|
-
]).join(', '))),
|
|
23507
|
+
React__default.createElement("p", { className: "form__region-label" }, compact([compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '), formatBirthDate$1(mainBooker?.birthDate)]).join(', '))),
|
|
23500
23508
|
travellersSettings?.mainBookerFormFields?.length ? (React__default.createElement("div", { className: "main-booker-form__grid" }, travellersSettings.mainBookerFormFields.map((field, index) => (React__default.createElement("div", { key: index, className: `control control--${field.type}` }, getControl(field.type, {}, field.type)))))) : (React__default.createElement(React__default.Fragment, null,
|
|
23501
23509
|
React__default.createElement("div", { className: "form__twocolumn" },
|
|
23502
23510
|
React__default.createElement("div", { className: "form__twocolumn-column" },
|
|
@@ -27341,7 +27349,8 @@ const initialState$1 = {
|
|
|
27341
27349
|
currentStep: 0,
|
|
27342
27350
|
bookingNumber: undefined,
|
|
27343
27351
|
trajectNodeAvailability: {},
|
|
27344
|
-
trajectFlightAvailability: {}
|
|
27352
|
+
trajectFlightAvailability: {},
|
|
27353
|
+
trajectEditLineGuid: null
|
|
27345
27354
|
};
|
|
27346
27355
|
const searchResultsSlice = createSlice({
|
|
27347
27356
|
name: 'searchResults',
|
|
@@ -27588,13 +27597,26 @@ const searchResultsSlice = createSlice({
|
|
|
27588
27597
|
flight.selectedGuid = action.payload.guid;
|
|
27589
27598
|
flight.status = 'resolved';
|
|
27590
27599
|
},
|
|
27600
|
+
setTrajectEditLineGuid(state, action) {
|
|
27601
|
+
state.trajectEditLineGuid = action.payload;
|
|
27602
|
+
},
|
|
27603
|
+
updateTrajectNodeResult(state, action) {
|
|
27604
|
+
const { lineGuid, result } = action.payload;
|
|
27605
|
+
const node = state.trajectNodeAvailability[lineGuid];
|
|
27606
|
+
if (!node)
|
|
27607
|
+
return;
|
|
27608
|
+
node.results = node.results.map((x) => (x.code === result.code ? result : x));
|
|
27609
|
+
node.selectedCode = result.code;
|
|
27610
|
+
node.status = 'resolved';
|
|
27611
|
+
},
|
|
27591
27612
|
resetTrajectAvailability(state) {
|
|
27592
27613
|
state.trajectNodeAvailability = {};
|
|
27593
27614
|
state.trajectFlightAvailability = {};
|
|
27615
|
+
state.trajectEditLineGuid = null;
|
|
27594
27616
|
}
|
|
27595
27617
|
}
|
|
27596
27618
|
});
|
|
27597
|
-
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;
|
|
27619
|
+
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;
|
|
27598
27620
|
var searchResultsReducer = searchResultsSlice.reducer;
|
|
27599
27621
|
|
|
27600
27622
|
const ItemPicker = ({ items, selection, selectedSortByType, label, placeholder, classModifier, onPick, valueFormatter }) => {
|
|
@@ -30574,6 +30596,293 @@ const ExcursionDetails = () => {
|
|
|
30574
30596
|
React__default.createElement("button", { type: "button", className: "cta cta--primary", onClick: handleConfirm }, translations?.QSM.CONFIRM))));
|
|
30575
30597
|
};
|
|
30576
30598
|
|
|
30599
|
+
const REGULAR_TRAJECT_NODE_TYPE = 0;
|
|
30600
|
+
const isSearchableTrajectNode = (node) => node.serviceType === ACCOMMODATION_SERVICE_TYPE || node.serviceType === EXCURSION_SERVICE_TYPE;
|
|
30601
|
+
const isTrajectFlightNode = (node) => node.serviceType === FLIGHT_SERVICE_TYPE;
|
|
30602
|
+
const getTrajectNodesWithLines = (trajectEntry) => {
|
|
30603
|
+
const linesByGuid = new Map((trajectEntry.entry.lines ?? []).map((line) => [line.guid, line]));
|
|
30604
|
+
return [...(trajectEntry.nodes ?? [])]
|
|
30605
|
+
.sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
|
|
30606
|
+
.map((node) => {
|
|
30607
|
+
const guids = node.lineGuids?.length ? node.lineGuids : [node.lineGuid];
|
|
30608
|
+
const lines = guids.map((guid) => linesByGuid.get(guid)).filter((x) => !!x);
|
|
30609
|
+
return { node, line: lines[0], lines };
|
|
30610
|
+
})
|
|
30611
|
+
.filter((x) => !!x.line);
|
|
30612
|
+
};
|
|
30613
|
+
const buildDestination = (line) => {
|
|
30614
|
+
if (line.location?.id)
|
|
30615
|
+
return { id: line.location.id, isLocation: true };
|
|
30616
|
+
if (line.oord?.id)
|
|
30617
|
+
return { id: line.oord.id, isOord: true };
|
|
30618
|
+
if (line.region?.id)
|
|
30619
|
+
return { id: line.region.id, isRegion: true };
|
|
30620
|
+
if (line.country?.id)
|
|
30621
|
+
return { id: line.country.id, isCountry: true };
|
|
30622
|
+
if (line.latitude && line.longitude)
|
|
30623
|
+
return { latitude: line.latitude, longitude: line.longitude };
|
|
30624
|
+
return { id: 0 };
|
|
30625
|
+
};
|
|
30626
|
+
const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
|
|
30627
|
+
transactionId: context.transactionId,
|
|
30628
|
+
officeId: context.officeId,
|
|
30629
|
+
agentId: context.agentId ?? null,
|
|
30630
|
+
catalogueId: context.catalogueId,
|
|
30631
|
+
searchConfigurationId: context.searchConfigurationId,
|
|
30632
|
+
portalId: context.portalId ?? null,
|
|
30633
|
+
vendorConfigurationId: node.externalVendorId ?? null,
|
|
30634
|
+
language: context.language,
|
|
30635
|
+
serviceType: node.serviceType,
|
|
30636
|
+
fromDate: toDateOnlyString(line.from),
|
|
30637
|
+
toDate: toDateOnlyString(line.to),
|
|
30638
|
+
destination: buildDestination(line),
|
|
30639
|
+
productCode,
|
|
30640
|
+
rooms: context.rooms,
|
|
30641
|
+
tagIds: []
|
|
30642
|
+
});
|
|
30643
|
+
const getNodeCandidates = (node) => {
|
|
30644
|
+
const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
|
|
30645
|
+
if (configured.length)
|
|
30646
|
+
return configured;
|
|
30647
|
+
const fallbackCode = node.code ?? node.preferredAccommodationCode;
|
|
30648
|
+
if (!fallbackCode || !fallbackCode.trim().length)
|
|
30649
|
+
return [];
|
|
30650
|
+
return [
|
|
30651
|
+
{
|
|
30652
|
+
code: fallbackCode,
|
|
30653
|
+
name: node.name,
|
|
30654
|
+
description: node.description,
|
|
30655
|
+
imageUrl: node.imageUrl,
|
|
30656
|
+
contentSource: node.contentSource,
|
|
30657
|
+
vendor: node.vendor,
|
|
30658
|
+
externalVendorId: node.externalVendorId,
|
|
30659
|
+
isPreferred: true
|
|
30660
|
+
}
|
|
30661
|
+
];
|
|
30662
|
+
};
|
|
30663
|
+
const findCandidateForResult = (node, result) => getNodeCandidates(node).find((candidate) => matchesCode(result, candidate.code)) ?? null;
|
|
30664
|
+
const matchesCode = (result, code) => {
|
|
30665
|
+
if (result.code === code)
|
|
30666
|
+
return true;
|
|
30667
|
+
return (result.rooms ?? []).some((room) => (room.options ?? []).some((option) => option.accommodationCode === code));
|
|
30668
|
+
};
|
|
30669
|
+
const getPackagingRoomsFromEntry = (entry) => {
|
|
30670
|
+
const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));
|
|
30671
|
+
const rooms = (entry.rooms ?? []).map((room) => ({
|
|
30672
|
+
travellers: (room.paxIds ?? []).map((paxId) => {
|
|
30673
|
+
const pax = paxById.get(paxId);
|
|
30674
|
+
return {
|
|
30675
|
+
id: paxId,
|
|
30676
|
+
age: pax?.age ?? null,
|
|
30677
|
+
dateOfBirth: pax?.dateOfBirth ?? null
|
|
30678
|
+
};
|
|
30679
|
+
})
|
|
30680
|
+
}));
|
|
30681
|
+
return rooms.filter((room) => room.travellers.length > 0);
|
|
30682
|
+
};
|
|
30683
|
+
const pickCheapest = (results) => [...results].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
30684
|
+
const applyResultToLines = (lines, result) => lines.map((line, index) => applyResultToLine(line, result, index));
|
|
30685
|
+
const getOptionForRoom = (result, roomIndex) => {
|
|
30686
|
+
const room = (result.rooms ?? [])[roomIndex];
|
|
30687
|
+
if (room)
|
|
30688
|
+
return (room.options ?? []).find((x) => x.isSelected) ?? (room.options ?? [])[0];
|
|
30689
|
+
return (result.rooms ?? []).flatMap((x) => x.options ?? []).find((x) => x.isSelected) ?? (result.rooms ?? [])[0]?.options?.[0];
|
|
30690
|
+
};
|
|
30691
|
+
const applyResultToLine = (line, result, roomIndex = 0) => {
|
|
30692
|
+
const option = getOptionForRoom(result, roomIndex);
|
|
30693
|
+
return {
|
|
30694
|
+
...line,
|
|
30695
|
+
productName: result.name ?? line.productName,
|
|
30696
|
+
productCode: result.code ?? line.productCode,
|
|
30697
|
+
accommodationCode: option?.accommodationCode ?? line.accommodationCode,
|
|
30698
|
+
accommodationName: option?.accommodationName ?? line.accommodationName,
|
|
30699
|
+
regimeCode: option?.regimeCode ?? line.regimeCode,
|
|
30700
|
+
regimeName: option?.regimeName ?? line.regimeName,
|
|
30701
|
+
latitude: result.latitude ?? line.latitude,
|
|
30702
|
+
longitude: result.longitude ?? line.longitude,
|
|
30703
|
+
isChanged: true
|
|
30704
|
+
};
|
|
30705
|
+
};
|
|
30706
|
+
const toDateOnlyUtcString = (value) => {
|
|
30707
|
+
const date = new Date(value);
|
|
30708
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
|
|
30709
|
+
};
|
|
30710
|
+
const toTimeOnlyString = (value) => {
|
|
30711
|
+
const date = new Date(value);
|
|
30712
|
+
const hh = String(date.getUTCHours()).padStart(2, '0');
|
|
30713
|
+
const mm = String(date.getUTCMinutes()).padStart(2, '0');
|
|
30714
|
+
const ss = String(date.getUTCSeconds()).padStart(2, '0');
|
|
30715
|
+
return `${hh}:${mm}:${ss}`;
|
|
30716
|
+
};
|
|
30717
|
+
const mapFlightSegmentsToFlightLines = (segments) => segments.map((segment) => ({
|
|
30718
|
+
airlineCode: segment.marketingAirlineCode,
|
|
30719
|
+
airlineDescription: segment.marketingAirlineName,
|
|
30720
|
+
operatingAirlineCode: segment.operatingAirlineCode,
|
|
30721
|
+
operatingAirlineDescription: segment.operatingAirlineName,
|
|
30722
|
+
flightNumber: segment.flightNumber,
|
|
30723
|
+
operatingFlightNumber: segment.operatingFlightNumber ?? null,
|
|
30724
|
+
departureDate: toDateOnlyUtcString(segment.departureDateTime),
|
|
30725
|
+
departureTime: toTimeOnlyString(segment.departureDateTime),
|
|
30726
|
+
departureAirportCode: segment.departureAirportCode,
|
|
30727
|
+
departureAirportDescription: segment.departureAirportName,
|
|
30728
|
+
arrivalDate: toDateOnlyUtcString(segment.arrivalDateTime),
|
|
30729
|
+
arrivalTime: toTimeOnlyString(segment.arrivalDateTime),
|
|
30730
|
+
arrivalAirportCode: segment.arrivalAirportCode,
|
|
30731
|
+
arrivalAirportDescription: segment.arrivalAirportName,
|
|
30732
|
+
durationInTicks: segment.durationInTicks
|
|
30733
|
+
}));
|
|
30734
|
+
const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
30735
|
+
transactionId: context.transactionId,
|
|
30736
|
+
officeId: context.officeId,
|
|
30737
|
+
catalogueId: context.catalogueId,
|
|
30738
|
+
agentId: context.agentId ?? null,
|
|
30739
|
+
language: context.language,
|
|
30740
|
+
departureAirportCode: node.departureAirportCode ?? '',
|
|
30741
|
+
arrivalAirportCode: node.arrivalAirportCode ?? '',
|
|
30742
|
+
returnAirportCode: null,
|
|
30743
|
+
luggageIncluded: null,
|
|
30744
|
+
maxStops: null,
|
|
30745
|
+
travelClass: null,
|
|
30746
|
+
vendorConfigurationId: node.externalVendorId ?? null,
|
|
30747
|
+
pax,
|
|
30748
|
+
outward: { date: dateToDateStruct(new Date(line.from)) },
|
|
30749
|
+
return: null
|
|
30750
|
+
});
|
|
30751
|
+
const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
30752
|
+
const applyFlightToLine = (line, flight) => {
|
|
30753
|
+
const segments = flight.outward?.segments ?? [];
|
|
30754
|
+
if (!segments.length)
|
|
30755
|
+
return line;
|
|
30756
|
+
const firstSegment = segments[0];
|
|
30757
|
+
const lastSegment = segments[segments.length - 1];
|
|
30758
|
+
return {
|
|
30759
|
+
...line,
|
|
30760
|
+
from: new Date(firstSegment.departureDateTime).toISOString(),
|
|
30761
|
+
to: new Date(lastSegment.arrivalDateTime).toISOString(),
|
|
30762
|
+
productName: `${firstSegment.departureAirportName} - ${lastSegment.arrivalAirportName} (${firstSegment.marketingAirlineName})`,
|
|
30763
|
+
productCode: `${firstSegment.departureAirportCode} ${lastSegment.arrivalAirportCode}/${firstSegment.marketingAirlineCode}`,
|
|
30764
|
+
accommodationName: firstSegment.metaData?.farePriceClassName ?? line.accommodationName,
|
|
30765
|
+
accommodationCode: firstSegment.metaData?.fareCode ?? line.accommodationCode,
|
|
30766
|
+
flightInformation: {
|
|
30767
|
+
pnr: '',
|
|
30768
|
+
flightLines: mapFlightSegmentsToFlightLines(segments)
|
|
30769
|
+
},
|
|
30770
|
+
isChanged: true
|
|
30771
|
+
};
|
|
30772
|
+
};
|
|
30773
|
+
|
|
30774
|
+
const getLocation = (result) => {
|
|
30775
|
+
const place = result.locationName || result.regionName || result.oordName;
|
|
30776
|
+
if (!place)
|
|
30777
|
+
return result.countryName ?? '';
|
|
30778
|
+
return result.countryName ? `${place}, ${result.countryName}` : place;
|
|
30779
|
+
};
|
|
30780
|
+
const toPlainText = (value) => {
|
|
30781
|
+
if (!value)
|
|
30782
|
+
return '';
|
|
30783
|
+
return he
|
|
30784
|
+
.decode(value.replace(/<[^>]*>/g, ' '))
|
|
30785
|
+
.replace(/\s+/g, ' ')
|
|
30786
|
+
.trim();
|
|
30787
|
+
};
|
|
30788
|
+
const TrajectNodeCard = ({ item, result, isSelected, languageCode, translations, onSelect, onEditOptions, showNights }) => {
|
|
30789
|
+
const { node } = item;
|
|
30790
|
+
const selectedPerRoom = (result.rooms ?? []).map((room) => (room.options ?? []).find((x) => x.isSelected) ?? (room.options ?? [])[0]);
|
|
30791
|
+
const isMultiRoom = selectedPerRoom.length > 1;
|
|
30792
|
+
const price = formatPrice$3(result.price, result.currencyCode, languageCode);
|
|
30793
|
+
const nights = calculateNights(new Date(result.fromDate), new Date(result.toDate));
|
|
30794
|
+
const candidate = findCandidateForResult(node, result);
|
|
30795
|
+
const image = candidate?.imageUrl ?? null;
|
|
30796
|
+
const description = toPlainText(candidate?.description);
|
|
30797
|
+
const title = candidate?.name ?? result.name;
|
|
30798
|
+
const priceBlock = (React__default.createElement("div", { className: "search__result-card__price__wrapper" },
|
|
30799
|
+
React__default.createElement("span", { className: "search__result-card__price__label" }, translations?.SHARED.TOTAL_PRICE),
|
|
30800
|
+
React__default.createElement("span", { className: "search__result-card__price" }, price)));
|
|
30801
|
+
const canEditOptions = isSelected && !!onEditOptions && (result.rooms ?? []).some((room) => (room.options ?? []).length > 1);
|
|
30802
|
+
const selectButton = (React__default.createElement(React__default.Fragment, null,
|
|
30803
|
+
React__default.createElement("button", { type: "button", className: `cta ${isSelected ? 'cta--selected' : 'cta--select'}`, onClick: onSelect }, isSelected ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT),
|
|
30804
|
+
canEditOptions && (React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: onEditOptions },
|
|
30805
|
+
translations?.SRP.SELECT,
|
|
30806
|
+
" ",
|
|
30807
|
+
translations?.SRP.ACCOMMODATION))));
|
|
30808
|
+
if (result.contents?.length) {
|
|
30809
|
+
return (React__default.createElement("div", { className: `search__result-card__wrapper search__result-card__wrapper--custom ${isSelected ? 'search__result-card__wrapper--selected' : ''}` },
|
|
30810
|
+
React__default.createElement("div", { className: "search__result-card__top", dangerouslySetInnerHTML: { __html: he.decode(result.contents) } }),
|
|
30811
|
+
React__default.createElement("div", { className: "search__result-card__footer" }, selectButton)));
|
|
30812
|
+
}
|
|
30813
|
+
return (React__default.createElement("div", { className: `search__result-card__wrapper ${isSelected ? 'search__result-card__wrapper--selected' : ''}` },
|
|
30814
|
+
image && (React__default.createElement("div", { className: "search__result-card__img-wrapper" },
|
|
30815
|
+
React__default.createElement("img", { src: image, alt: title, className: "search__result-card__img" }),
|
|
30816
|
+
priceBlock)),
|
|
30817
|
+
React__default.createElement("div", { className: "search__result-card__content" },
|
|
30818
|
+
React__default.createElement("div", { className: "search__result-card__content__wrapper" },
|
|
30819
|
+
React__default.createElement("div", { className: "search__result-card__header" },
|
|
30820
|
+
React__default.createElement("div", { className: "search__result-card__header__wrapper" },
|
|
30821
|
+
!!result.stars && (React__default.createElement("div", { className: "rating" }, [...Array(result.stars)].map((_, index) => (React__default.createElement(Icon, { name: "ui-star", key: `rating-star-${index + 1}`, width: 14, height: 14 }))))),
|
|
30822
|
+
React__default.createElement("h3", { className: "search__result-card__title" }, title)),
|
|
30823
|
+
!image && priceBlock),
|
|
30824
|
+
React__default.createElement("span", { className: "search__result-card__location" },
|
|
30825
|
+
React__default.createElement(Icon, { name: "ui-location", height: 16 }),
|
|
30826
|
+
getLocation(result)),
|
|
30827
|
+
React__default.createElement("div", { className: "search__result-card__options" },
|
|
30828
|
+
showNights && nights > 0 && (React__default.createElement("div", { className: "search__result-card__option" },
|
|
30829
|
+
React__default.createElement(Icon, { name: "ui-moon", height: 16 }),
|
|
30830
|
+
nights,
|
|
30831
|
+
" ",
|
|
30832
|
+
translations?.SRP.NIGHTS)),
|
|
30833
|
+
selectedPerRoom.map((option, roomIndex) => (React__default.createElement(React__default.Fragment, { key: `room-${roomIndex}` },
|
|
30834
|
+
option?.accommodationName && (React__default.createElement("div", { className: "search__result-card__option" },
|
|
30835
|
+
React__default.createElement(Icon, { name: "ui-bed", height: 16 }),
|
|
30836
|
+
isMultiRoom && `${translations?.SHARED.ROOM} ${roomIndex + 1}: `,
|
|
30837
|
+
option.accommodationName)),
|
|
30838
|
+
option?.regimeName && (React__default.createElement("div", { className: "search__result-card__option" },
|
|
30839
|
+
React__default.createElement(Icon, { name: "ui-utensils", height: 16 }),
|
|
30840
|
+
option.regimeName)))))),
|
|
30841
|
+
description && React__default.createElement("p", { className: "search__result-card__description" }, description)),
|
|
30842
|
+
React__default.createElement("div", { className: "search__result-card__footer" }, selectButton))));
|
|
30843
|
+
};
|
|
30844
|
+
|
|
30845
|
+
const TrajectResultsFlyIn = ({ isLoading }) => {
|
|
30846
|
+
const context = useContext(SearchResultsConfigurationContext);
|
|
30847
|
+
const dispatch = useDispatch();
|
|
30848
|
+
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
30849
|
+
const { trajectNodeAvailability, trajectEditLineGuid } = useSelector((state) => state.searchResults);
|
|
30850
|
+
const trajectEntry = context?.trajectEntry;
|
|
30851
|
+
const item = useMemo(() => {
|
|
30852
|
+
if (!trajectEntry || !trajectEditLineGuid)
|
|
30853
|
+
return null;
|
|
30854
|
+
return getTrajectNodesWithLines(trajectEntry).find((x) => x.line.guid === trajectEditLineGuid) ?? null;
|
|
30855
|
+
}, [trajectEntry, trajectEditLineGuid]);
|
|
30856
|
+
if (!context || !item)
|
|
30857
|
+
return null;
|
|
30858
|
+
const availability = trajectNodeAvailability[item.line.guid];
|
|
30859
|
+
const results = availability?.results ?? [];
|
|
30860
|
+
const ordered = [...results].sort((a, b) => {
|
|
30861
|
+
const aConfigured = findCandidateForResult(item.node, a) ? 0 : 1;
|
|
30862
|
+
const bConfigured = findCandidateForResult(item.node, b) ? 0 : 1;
|
|
30863
|
+
return aConfigured - bConfigured || a.price - b.price;
|
|
30864
|
+
});
|
|
30865
|
+
const handleSelect = (code) => {
|
|
30866
|
+
const result = results.find((x) => x.code === code);
|
|
30867
|
+
if (!result)
|
|
30868
|
+
return;
|
|
30869
|
+
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
|
|
30870
|
+
applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
30871
|
+
dispatch(setTrajectEditLineGuid(null));
|
|
30872
|
+
dispatch(setFlyInIsOpen(false));
|
|
30873
|
+
};
|
|
30874
|
+
if (isLoading) {
|
|
30875
|
+
return React__default.createElement(React__default.Fragment, null, context.customSpinner ?? React__default.createElement(Spinner, { label: translations.SRP.LOADING_ACCOMMODATIONS }));
|
|
30876
|
+
}
|
|
30877
|
+
return (React__default.createElement("div", { className: "flyin__content" },
|
|
30878
|
+
React__default.createElement("div", { className: "search__result-row" },
|
|
30879
|
+
React__default.createElement("span", { className: "search__result-row-text" },
|
|
30880
|
+
ordered.length,
|
|
30881
|
+
"\u00A0",
|
|
30882
|
+
translations.SRP.TOTAL_RESULTS_LABEL)),
|
|
30883
|
+
ordered.length === 0 ? (React__default.createElement("div", { className: "no-results" }, translations.SRP.NO_RESULTS)) : (React__default.createElement("div", { className: "search__results__cards search__results__cards--compact" }, ordered.map((result) => (React__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 })))))));
|
|
30884
|
+
};
|
|
30885
|
+
|
|
30577
30886
|
const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, detailsLoading, flyInType, isPackageEditFlow, handleConfirm, sortByTypes, activeSearchSeed, toggleFilters, filtersOpen }) => {
|
|
30578
30887
|
const dispatch = useDispatch();
|
|
30579
30888
|
const context = useContext(SearchResultsConfigurationContext);
|
|
@@ -30619,6 +30928,10 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
|
|
|
30619
30928
|
}
|
|
30620
30929
|
};
|
|
30621
30930
|
const handleGoBack = () => {
|
|
30931
|
+
if (context?.trajectEntry) {
|
|
30932
|
+
handleClose();
|
|
30933
|
+
return;
|
|
30934
|
+
}
|
|
30622
30935
|
if (flyInType === 'acco-details') {
|
|
30623
30936
|
dispatch(setFlyInType('acco-results'));
|
|
30624
30937
|
}
|
|
@@ -30642,7 +30955,7 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
|
|
|
30642
30955
|
dispatch(setBookPackagingEntry(true));
|
|
30643
30956
|
}
|
|
30644
30957
|
};
|
|
30645
|
-
return (React__default.createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
|
|
30958
|
+
return (React__default.createElement("div", { className: `flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' ? 'flyin--large' : ''} ${flyInType === 'excursion-results' || flyInType === 'excursion-details' ? 'flyin--medium' : ''}
|
|
30646
30959
|
${flyInType === 'flight-outward-results' || flyInType === 'flight-return-results' ? 'flyin--flight' : ''}` },
|
|
30647
30960
|
React__default.createElement("div", { className: `flyin__panel ${isOpen ? 'flyin__panel--active' : ''}`, ref: panelRef },
|
|
30648
30961
|
React__default.createElement("div", { className: "flyin__content" },
|
|
@@ -30668,7 +30981,10 @@ const FlyIn = ({ srpType, isOpen, setIsOpen, className = '', onPanelRef, details
|
|
|
30668
30981
|
React__default.createElement(Icon, { name: "ui-chevron", width: 14, height: 14, "aria-hidden": "true" }),
|
|
30669
30982
|
"Go Back")))),
|
|
30670
30983
|
srpType === build.PortalQsmType.Flight && React__default.createElement(FlightsFlyIn, { isOpen: isOpen, setIsOpen: setIsOpen }),
|
|
30671
|
-
|
|
30984
|
+
context?.trajectEntry && flyInType === 'acco-results' && React__default.createElement(TrajectResultsFlyIn, { isLoading: detailsLoading }),
|
|
30985
|
+
!context?.trajectEntry &&
|
|
30986
|
+
(srpType === build.PortalQsmType.Accommodation || srpType === build.PortalQsmType.AccommodationAndFlight) &&
|
|
30987
|
+
flyInType === 'acco-results' && (React__default.createElement("div", { className: "flyin__content flyin__content--columns" },
|
|
30672
30988
|
React__default.createElement(Filters, { initialFilters: initialFilters, filters: filters, isOpen: filtersOpen, handleSetIsOpen: () => toggleFilters && toggleFilters(),
|
|
30673
30989
|
// handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
|
|
30674
30990
|
isLoading: isLoading, setFilters: (filters) => dispatch(setFilters(filters)), resetFilters: (filters) => dispatch(resetFilters(filters)) }),
|
|
@@ -32941,232 +33257,6 @@ const BookPackagingEntry = ({ activeSearchSeed, isLoading, isConfirmationPage })
|
|
|
32941
33257
|
React__default.createElement(WLSidebar, { activeSearchSeed: activeSearchSeed, packagingAccoResult: selectedPackagingAccoResult }))));
|
|
32942
33258
|
};
|
|
32943
33259
|
|
|
32944
|
-
const REGULAR_TRAJECT_NODE_TYPE = 0;
|
|
32945
|
-
const isSearchableTrajectNode = (node) => node.serviceType === ACCOMMODATION_SERVICE_TYPE || node.serviceType === EXCURSION_SERVICE_TYPE;
|
|
32946
|
-
const isTrajectFlightNode = (node) => node.serviceType === FLIGHT_SERVICE_TYPE;
|
|
32947
|
-
const getTrajectNodesWithLines = (trajectEntry) => {
|
|
32948
|
-
const linesByGuid = new Map((trajectEntry.entry.lines ?? []).map((line) => [line.guid, line]));
|
|
32949
|
-
return [...(trajectEntry.nodes ?? [])]
|
|
32950
|
-
.sort((a, b) => a.dayOrder - b.dayOrder || a.order - b.order)
|
|
32951
|
-
.map((node) => ({ node, line: linesByGuid.get(node.lineGuid) }))
|
|
32952
|
-
.filter((x) => !!x.line);
|
|
32953
|
-
};
|
|
32954
|
-
const buildDestination = (line) => {
|
|
32955
|
-
if (line.location?.id)
|
|
32956
|
-
return { id: line.location.id, isLocation: true };
|
|
32957
|
-
if (line.oord?.id)
|
|
32958
|
-
return { id: line.oord.id, isOord: true };
|
|
32959
|
-
if (line.region?.id)
|
|
32960
|
-
return { id: line.region.id, isRegion: true };
|
|
32961
|
-
if (line.country?.id)
|
|
32962
|
-
return { id: line.country.id, isCountry: true };
|
|
32963
|
-
if (line.latitude && line.longitude)
|
|
32964
|
-
return { latitude: line.latitude, longitude: line.longitude };
|
|
32965
|
-
return { id: 0 };
|
|
32966
|
-
};
|
|
32967
|
-
const buildTrajectNodeRequest = ({ node, line }, context, productCode) => ({
|
|
32968
|
-
transactionId: context.transactionId,
|
|
32969
|
-
officeId: context.officeId,
|
|
32970
|
-
agentId: context.agentId ?? null,
|
|
32971
|
-
catalogueId: context.catalogueId,
|
|
32972
|
-
searchConfigurationId: context.searchConfigurationId,
|
|
32973
|
-
portalId: context.portalId ?? null,
|
|
32974
|
-
vendorConfigurationId: node.externalVendorId ?? null,
|
|
32975
|
-
language: context.language,
|
|
32976
|
-
serviceType: node.serviceType,
|
|
32977
|
-
fromDate: toDateOnlyString(line.from),
|
|
32978
|
-
toDate: toDateOnlyString(line.to),
|
|
32979
|
-
destination: buildDestination(line),
|
|
32980
|
-
productCode,
|
|
32981
|
-
rooms: context.rooms,
|
|
32982
|
-
tagIds: []
|
|
32983
|
-
});
|
|
32984
|
-
const getNodeCandidates = (node) => {
|
|
32985
|
-
const configured = (node.alternatives ?? []).filter((x) => !!x.code && x.code.trim().length > 0);
|
|
32986
|
-
if (configured.length)
|
|
32987
|
-
return configured;
|
|
32988
|
-
const fallbackCode = node.code ?? node.preferredAccommodationCode;
|
|
32989
|
-
if (!fallbackCode || !fallbackCode.trim().length)
|
|
32990
|
-
return [];
|
|
32991
|
-
return [
|
|
32992
|
-
{
|
|
32993
|
-
code: fallbackCode,
|
|
32994
|
-
name: node.name,
|
|
32995
|
-
description: node.description,
|
|
32996
|
-
imageUrl: node.imageUrl,
|
|
32997
|
-
contentSource: node.contentSource,
|
|
32998
|
-
vendor: node.vendor,
|
|
32999
|
-
externalVendorId: node.externalVendorId,
|
|
33000
|
-
isPreferred: true
|
|
33001
|
-
}
|
|
33002
|
-
];
|
|
33003
|
-
};
|
|
33004
|
-
const findCandidateForResult = (node, result) => getNodeCandidates(node).find((candidate) => matchesCode(result, candidate.code)) ?? null;
|
|
33005
|
-
const matchesCode = (result, code) => {
|
|
33006
|
-
if (result.code === code)
|
|
33007
|
-
return true;
|
|
33008
|
-
return (result.rooms ?? []).some((room) => (room.options ?? []).some((option) => option.accommodationCode === code));
|
|
33009
|
-
};
|
|
33010
|
-
const getPackagingRoomsFromEntry = (entry) => {
|
|
33011
|
-
const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));
|
|
33012
|
-
const rooms = (entry.rooms ?? []).map((room) => ({
|
|
33013
|
-
travellers: (room.paxIds ?? []).map((paxId) => {
|
|
33014
|
-
const pax = paxById.get(paxId);
|
|
33015
|
-
return {
|
|
33016
|
-
id: paxId,
|
|
33017
|
-
age: pax?.age ?? null,
|
|
33018
|
-
dateOfBirth: pax?.dateOfBirth ?? null
|
|
33019
|
-
};
|
|
33020
|
-
})
|
|
33021
|
-
}));
|
|
33022
|
-
return rooms.filter((room) => room.travellers.length > 0);
|
|
33023
|
-
};
|
|
33024
|
-
const pickCheapest = (results) => [...results].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
33025
|
-
const applyResultToLine = (line, result) => {
|
|
33026
|
-
const option = (result.rooms ?? []).flatMap((room) => room.options ?? []).find((x) => x.isSelected) ?? (result.rooms ?? [])[0]?.options?.[0];
|
|
33027
|
-
return {
|
|
33028
|
-
...line,
|
|
33029
|
-
productName: result.name ?? line.productName,
|
|
33030
|
-
productCode: result.code ?? line.productCode,
|
|
33031
|
-
accommodationCode: option?.accommodationCode ?? line.accommodationCode,
|
|
33032
|
-
accommodationName: option?.accommodationName ?? line.accommodationName,
|
|
33033
|
-
regimeCode: option?.regimeCode ?? line.regimeCode,
|
|
33034
|
-
regimeName: option?.regimeName ?? line.regimeName,
|
|
33035
|
-
latitude: result.latitude ?? line.latitude,
|
|
33036
|
-
longitude: result.longitude ?? line.longitude,
|
|
33037
|
-
isChanged: true
|
|
33038
|
-
};
|
|
33039
|
-
};
|
|
33040
|
-
const toDateOnlyUtcString = (value) => {
|
|
33041
|
-
const date = new Date(value);
|
|
33042
|
-
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())).toISOString();
|
|
33043
|
-
};
|
|
33044
|
-
const toTimeOnlyString = (value) => {
|
|
33045
|
-
const date = new Date(value);
|
|
33046
|
-
const hh = String(date.getUTCHours()).padStart(2, '0');
|
|
33047
|
-
const mm = String(date.getUTCMinutes()).padStart(2, '0');
|
|
33048
|
-
const ss = String(date.getUTCSeconds()).padStart(2, '0');
|
|
33049
|
-
return `${hh}:${mm}:${ss}`;
|
|
33050
|
-
};
|
|
33051
|
-
const mapFlightSegmentsToFlightLines = (segments) => segments.map((segment) => ({
|
|
33052
|
-
airlineCode: segment.marketingAirlineCode,
|
|
33053
|
-
airlineDescription: segment.marketingAirlineName,
|
|
33054
|
-
operatingAirlineCode: segment.operatingAirlineCode,
|
|
33055
|
-
operatingAirlineDescription: segment.operatingAirlineName,
|
|
33056
|
-
flightNumber: segment.flightNumber,
|
|
33057
|
-
operatingFlightNumber: segment.operatingFlightNumber ?? null,
|
|
33058
|
-
departureDate: toDateOnlyUtcString(segment.departureDateTime),
|
|
33059
|
-
departureTime: toTimeOnlyString(segment.departureDateTime),
|
|
33060
|
-
departureAirportCode: segment.departureAirportCode,
|
|
33061
|
-
departureAirportDescription: segment.departureAirportName,
|
|
33062
|
-
arrivalDate: toDateOnlyUtcString(segment.arrivalDateTime),
|
|
33063
|
-
arrivalTime: toTimeOnlyString(segment.arrivalDateTime),
|
|
33064
|
-
arrivalAirportCode: segment.arrivalAirportCode,
|
|
33065
|
-
arrivalAirportDescription: segment.arrivalAirportName,
|
|
33066
|
-
durationInTicks: segment.durationInTicks
|
|
33067
|
-
}));
|
|
33068
|
-
const buildTrajectFlightRequest = ({ node, line }, context, pax) => ({
|
|
33069
|
-
transactionId: context.transactionId,
|
|
33070
|
-
officeId: context.officeId,
|
|
33071
|
-
catalogueId: context.catalogueId,
|
|
33072
|
-
agentId: context.agentId ?? null,
|
|
33073
|
-
language: context.language,
|
|
33074
|
-
departureAirportCode: node.departureAirportCode ?? '',
|
|
33075
|
-
arrivalAirportCode: node.arrivalAirportCode ?? '',
|
|
33076
|
-
returnAirportCode: null,
|
|
33077
|
-
luggageIncluded: null,
|
|
33078
|
-
maxStops: null,
|
|
33079
|
-
travelClass: null,
|
|
33080
|
-
vendorConfigurationId: node.externalVendorId ?? null,
|
|
33081
|
-
pax,
|
|
33082
|
-
outward: { date: dateToDateStruct(new Date(line.from)) },
|
|
33083
|
-
return: null
|
|
33084
|
-
});
|
|
33085
|
-
const pickCheapestFlight = (flights) => [...flights].sort((a, b) => a.price - b.price)[0] ?? null;
|
|
33086
|
-
const applyFlightToLine = (line, flight) => {
|
|
33087
|
-
const segments = flight.outward?.segments ?? [];
|
|
33088
|
-
if (!segments.length)
|
|
33089
|
-
return line;
|
|
33090
|
-
const firstSegment = segments[0];
|
|
33091
|
-
const lastSegment = segments[segments.length - 1];
|
|
33092
|
-
return {
|
|
33093
|
-
...line,
|
|
33094
|
-
from: new Date(firstSegment.departureDateTime).toISOString(),
|
|
33095
|
-
to: new Date(lastSegment.arrivalDateTime).toISOString(),
|
|
33096
|
-
productName: `${firstSegment.departureAirportName} - ${lastSegment.arrivalAirportName} (${firstSegment.marketingAirlineName})`,
|
|
33097
|
-
productCode: `${firstSegment.departureAirportCode} ${lastSegment.arrivalAirportCode}/${firstSegment.marketingAirlineCode}`,
|
|
33098
|
-
accommodationName: firstSegment.metaData?.farePriceClassName ?? line.accommodationName,
|
|
33099
|
-
accommodationCode: firstSegment.metaData?.fareCode ?? line.accommodationCode,
|
|
33100
|
-
flightInformation: {
|
|
33101
|
-
pnr: '',
|
|
33102
|
-
flightLines: mapFlightSegmentsToFlightLines(segments)
|
|
33103
|
-
},
|
|
33104
|
-
isChanged: true
|
|
33105
|
-
};
|
|
33106
|
-
};
|
|
33107
|
-
|
|
33108
|
-
const getLocation = (result) => {
|
|
33109
|
-
const place = result.locationName || result.regionName || result.oordName;
|
|
33110
|
-
if (!place)
|
|
33111
|
-
return result.countryName ?? '';
|
|
33112
|
-
return result.countryName ? `${place}, ${result.countryName}` : place;
|
|
33113
|
-
};
|
|
33114
|
-
const toPlainText = (value) => {
|
|
33115
|
-
if (!value)
|
|
33116
|
-
return '';
|
|
33117
|
-
return he
|
|
33118
|
-
.decode(value.replace(/<[^>]*>/g, ' '))
|
|
33119
|
-
.replace(/\s+/g, ' ')
|
|
33120
|
-
.trim();
|
|
33121
|
-
};
|
|
33122
|
-
const TrajectNodeCard = ({ item, result, isSelected, languageCode, translations, onSelect, showNights }) => {
|
|
33123
|
-
const { node } = item;
|
|
33124
|
-
const selectedOption = first(result.rooms)?.options?.find((x) => x.isSelected) ?? first(result.rooms)?.options?.[0];
|
|
33125
|
-
const price = formatPrice$3(result.price, result.currencyCode, languageCode);
|
|
33126
|
-
const nights = calculateNights(new Date(result.fromDate), new Date(result.toDate));
|
|
33127
|
-
const candidate = findCandidateForResult(node, result);
|
|
33128
|
-
const image = candidate?.imageUrl ?? null;
|
|
33129
|
-
const description = toPlainText(candidate?.description);
|
|
33130
|
-
const title = candidate?.name ?? result.name;
|
|
33131
|
-
const priceBlock = (React__default.createElement("div", { className: "search__result-card__price__wrapper" },
|
|
33132
|
-
React__default.createElement("span", { className: "search__result-card__price__label" }, translations?.SHARED.TOTAL_PRICE),
|
|
33133
|
-
React__default.createElement("span", { className: "search__result-card__price" }, price)));
|
|
33134
|
-
const selectButton = (React__default.createElement("button", { type: "button", className: `cta ${isSelected ? 'cta--selected' : 'cta--select'}`, onClick: onSelect }, isSelected ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT));
|
|
33135
|
-
if (result.contents?.length) {
|
|
33136
|
-
return (React__default.createElement("div", { className: `search__result-card__wrapper search__result-card__wrapper--custom ${isSelected ? 'search__result-card__wrapper--selected' : ''}` },
|
|
33137
|
-
React__default.createElement("div", { className: "search__result-card__top", dangerouslySetInnerHTML: { __html: he.decode(result.contents) } }),
|
|
33138
|
-
React__default.createElement("div", { className: "search__result-card__footer" }, selectButton)));
|
|
33139
|
-
}
|
|
33140
|
-
return (React__default.createElement("div", { className: `search__result-card__wrapper ${isSelected ? 'search__result-card__wrapper--selected' : ''}` },
|
|
33141
|
-
image && (React__default.createElement("div", { className: "search__result-card__img-wrapper" },
|
|
33142
|
-
React__default.createElement("img", { src: image, alt: title, className: "search__result-card__img" }),
|
|
33143
|
-
priceBlock)),
|
|
33144
|
-
React__default.createElement("div", { className: "search__result-card__content" },
|
|
33145
|
-
React__default.createElement("div", { className: "search__result-card__content__wrapper" },
|
|
33146
|
-
React__default.createElement("div", { className: "search__result-card__header" },
|
|
33147
|
-
React__default.createElement("div", { className: "search__result-card__header__wrapper" },
|
|
33148
|
-
!!result.stars && (React__default.createElement("div", { className: "rating" }, [...Array(result.stars)].map((_, index) => (React__default.createElement(Icon, { name: "ui-star", key: `rating-star-${index + 1}`, width: 14, height: 14 }))))),
|
|
33149
|
-
React__default.createElement("h3", { className: "search__result-card__title" }, title)),
|
|
33150
|
-
!image && priceBlock),
|
|
33151
|
-
React__default.createElement("span", { className: "search__result-card__location" },
|
|
33152
|
-
React__default.createElement(Icon, { name: "ui-location", height: 16 }),
|
|
33153
|
-
getLocation(result)),
|
|
33154
|
-
React__default.createElement("div", { className: "search__result-card__options" },
|
|
33155
|
-
showNights && nights > 0 && (React__default.createElement("div", { className: "search__result-card__option" },
|
|
33156
|
-
React__default.createElement(Icon, { name: "ui-moon", height: 16 }),
|
|
33157
|
-
nights,
|
|
33158
|
-
" ",
|
|
33159
|
-
translations?.SRP.NIGHTS)),
|
|
33160
|
-
selectedOption?.accommodationName && (React__default.createElement("div", { className: "search__result-card__option" },
|
|
33161
|
-
React__default.createElement(Icon, { name: "ui-bed", height: 16 }),
|
|
33162
|
-
selectedOption.accommodationName)),
|
|
33163
|
-
selectedOption?.regimeName && (React__default.createElement("div", { className: "search__result-card__option" },
|
|
33164
|
-
React__default.createElement(Icon, { name: "ui-utensils", height: 16 }),
|
|
33165
|
-
selectedOption.regimeName))),
|
|
33166
|
-
description && React__default.createElement("p", { className: "search__result-card__description" }, description)),
|
|
33167
|
-
React__default.createElement("div", { className: "search__result-card__footer" }, selectButton))));
|
|
33168
|
-
};
|
|
33169
|
-
|
|
33170
33260
|
const getNodeIcon = (node) => {
|
|
33171
33261
|
if (isTrajectFlightNode(node))
|
|
33172
33262
|
return 'ui-flight';
|
|
@@ -33206,13 +33296,28 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33206
33296
|
if (!result)
|
|
33207
33297
|
return;
|
|
33208
33298
|
dispatch(setTrajectNodeSelection({ lineGuid: item.line.guid, code }));
|
|
33209
|
-
|
|
33299
|
+
applyResultToLines(item.lines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
33300
|
+
};
|
|
33301
|
+
const handleShowMore = (item) => {
|
|
33302
|
+
dispatch(setTrajectEditLineGuid(item.line.guid));
|
|
33303
|
+
dispatch(setFlyInType('acco-results'));
|
|
33304
|
+
dispatch(setFlyInIsOpen(true));
|
|
33305
|
+
};
|
|
33306
|
+
const handleEditOptions = (item) => {
|
|
33307
|
+
const availability = trajectNodeAvailability[item.line.guid];
|
|
33308
|
+
const result = availability?.results.find((x) => x.code === availability?.selectedCode);
|
|
33309
|
+
if (!result)
|
|
33310
|
+
return;
|
|
33311
|
+
dispatch(setPackagingAccoSearchDetails([result]));
|
|
33312
|
+
dispatch(setSelectedPackagingAccoResult(result.code));
|
|
33313
|
+
dispatch(setTrajectEditLineGuid(item.line.guid));
|
|
33314
|
+
dispatch(setFlyInType('acco-details'));
|
|
33315
|
+
dispatch(setFlyInIsOpen(true));
|
|
33210
33316
|
};
|
|
33211
33317
|
const renderServiceNode = (item) => {
|
|
33212
33318
|
console.log('renderServiceNode', item);
|
|
33213
33319
|
const { node, line } = item;
|
|
33214
33320
|
const availability = trajectNodeAvailability[line.guid];
|
|
33215
|
-
const isExpanded = !!expandedNodes[line.guid];
|
|
33216
33321
|
const results = availability?.results ?? [];
|
|
33217
33322
|
const selected = results.find((x) => x.code === availability?.selectedCode) ?? null;
|
|
33218
33323
|
const configured = results.filter((x) => x.code !== selected?.code && !!findCandidateForResult(node, x));
|
|
@@ -33234,9 +33339,13 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33234
33339
|
node.preferredAccommodationName,
|
|
33235
33340
|
" \u2014 ",
|
|
33236
33341
|
translations.SRP.NO_RESULTS))),
|
|
33237
|
-
React__default.createElement("div", { className: "search__results__cards search__results__cards--
|
|
33342
|
+
React__default.createElement("div", { className: "search__results__cards search__results__cards--compact" }, [selected, ...configured].map((result) => (React__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 })))),
|
|
33238
33343
|
others.length > 0 && (React__default.createElement("div", { className: "search__results__cards__actions" },
|
|
33239
|
-
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () =>
|
|
33344
|
+
React__default.createElement("button", { type: "button", className: "cta cta--secondary", onClick: () => handleShowMore(item) },
|
|
33345
|
+
translations.SRP.SHOW_MORE,
|
|
33346
|
+
" (",
|
|
33347
|
+
others.length,
|
|
33348
|
+
")")))))));
|
|
33240
33349
|
};
|
|
33241
33350
|
const handleSelectFlight = (item, flight) => {
|
|
33242
33351
|
dispatch(setTrajectFlightSelection({ lineGuid: item.line.guid, guid: flight.outwardGuid }));
|
|
@@ -33281,6 +33390,8 @@ const TrajectResults = ({ isLoading }) => {
|
|
|
33281
33390
|
if (!dayNodes.length)
|
|
33282
33391
|
return null;
|
|
33283
33392
|
return (React__default.createElement(React__default.Fragment, { key: `day-${day.order}` }, dayNodes.map((node) => {
|
|
33393
|
+
if (node.serviceType !== ACCOMMODATION_SERVICE_TYPE && node.serviceType !== EXCURSION_SERVICE_TYPE && node.serviceType !== FLIGHT_SERVICE_TYPE)
|
|
33394
|
+
return null;
|
|
33284
33395
|
// if (node.trajectNodeType === CONNECTING_TRAJECT_NODE_TYPE) return null;
|
|
33285
33396
|
// if (node.trajectNodeType !== REGULAR_TRAJECT_NODE_TYPE) return renderContextNode(node);
|
|
33286
33397
|
if (node.trajectNodeType !== REGULAR_TRAJECT_NODE_TYPE)
|
|
@@ -33298,6 +33409,7 @@ const useTrajectAvailability = () => {
|
|
|
33298
33409
|
const context = useContext(SearchResultsConfigurationContext);
|
|
33299
33410
|
const dispatch = useDispatch();
|
|
33300
33411
|
const trajectEntry = context?.trajectEntry;
|
|
33412
|
+
const showNonPreferredItems = !!context?.showNonPreferredItems;
|
|
33301
33413
|
useEffect(() => {
|
|
33302
33414
|
if (!context || !trajectEntry)
|
|
33303
33415
|
return;
|
|
@@ -33342,18 +33454,20 @@ const useTrajectAvailability = () => {
|
|
|
33342
33454
|
return null;
|
|
33343
33455
|
}
|
|
33344
33456
|
}));
|
|
33345
|
-
|
|
33346
|
-
|
|
33457
|
+
const configuredResults = attempts
|
|
33458
|
+
.filter((x) => !!x)
|
|
33459
|
+
.filter((x, i, all) => all.findIndex((y) => y.code === x.code) === i);
|
|
33347
33460
|
const preferredCandidate = candidates.find((x) => x.isPreferred) ?? candidates[0];
|
|
33348
|
-
let preferredUnavailable = !!preferredCandidate && !
|
|
33349
|
-
|
|
33350
|
-
|
|
33351
|
-
|
|
33352
|
-
|
|
33461
|
+
let preferredUnavailable = !!preferredCandidate && !configuredResults.some((x) => matchesCode(x, preferredCandidate.code));
|
|
33462
|
+
const destinationResults = showNonPreferredItems
|
|
33463
|
+
? ((await search(config, buildTrajectNodeRequest(item, searchContext, ''), controller.signal)) ?? []).filter((x) => !configuredResults.some((configured) => configured.code === x.code))
|
|
33464
|
+
: [];
|
|
33465
|
+
const results = [...configuredResults, ...destinationResults];
|
|
33466
|
+
const picked = configuredResults[0] ?? pickCheapest(destinationResults);
|
|
33467
|
+
if (!configuredResults.length)
|
|
33353
33468
|
preferredUnavailable = candidates.length > 0;
|
|
33354
|
-
}
|
|
33355
33469
|
if (controller.signal.aborted)
|
|
33356
|
-
return
|
|
33470
|
+
return [];
|
|
33357
33471
|
dispatch(setTrajectNodeAvailability({
|
|
33358
33472
|
lineGuid,
|
|
33359
33473
|
results,
|
|
@@ -33361,58 +33475,58 @@ const useTrajectAvailability = () => {
|
|
|
33361
33475
|
preferredUnavailable
|
|
33362
33476
|
}));
|
|
33363
33477
|
if (!picked)
|
|
33364
|
-
return
|
|
33365
|
-
|
|
33366
|
-
return
|
|
33478
|
+
return item.lines.map((x) => x.guid);
|
|
33479
|
+
applyResultToLines(item.lines, picked).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
33480
|
+
return [];
|
|
33367
33481
|
}
|
|
33368
33482
|
catch (error) {
|
|
33369
33483
|
if (controller.signal.aborted)
|
|
33370
|
-
return
|
|
33484
|
+
return [];
|
|
33371
33485
|
console.error('Failed to resolve traject node availability', item.node.name, error);
|
|
33372
33486
|
dispatch(setTrajectNodeAvailability({ lineGuid, results: [], selectedCode: null, preferredUnavailable: false }));
|
|
33373
|
-
return
|
|
33487
|
+
return item.lines.map((x) => x.guid);
|
|
33374
33488
|
}
|
|
33375
33489
|
};
|
|
33376
33490
|
const resolveFlightNode = async (item) => {
|
|
33377
33491
|
const lineGuid = item.line.guid;
|
|
33378
33492
|
if (!item.node.departureAirportCode || !item.node.arrivalAirportCode) {
|
|
33379
33493
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
33380
|
-
return
|
|
33494
|
+
return item.lines.map((x) => x.guid);
|
|
33381
33495
|
}
|
|
33382
33496
|
dispatch(setTrajectFlightLoading(lineGuid));
|
|
33383
33497
|
try {
|
|
33384
33498
|
const flights = (await build.searchPackagingFlights(config, buildTrajectFlightRequest(item, searchContext, flightPax), controller.signal)) ?? [];
|
|
33385
33499
|
if (controller.signal.aborted)
|
|
33386
|
-
return
|
|
33500
|
+
return [];
|
|
33387
33501
|
const picked = pickCheapestFlight(flights);
|
|
33388
33502
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: flights, selectedGuid: picked?.outwardGuid ?? null }));
|
|
33389
33503
|
if (!picked)
|
|
33390
|
-
return
|
|
33504
|
+
return item.lines.map((x) => x.guid);
|
|
33391
33505
|
dispatch(updateEditableEntryLine(applyFlightToLine(item.line, picked)));
|
|
33392
|
-
return
|
|
33506
|
+
return [];
|
|
33393
33507
|
}
|
|
33394
33508
|
catch (error) {
|
|
33395
33509
|
if (controller.signal.aborted)
|
|
33396
|
-
return
|
|
33510
|
+
return [];
|
|
33397
33511
|
console.error('Failed to resolve traject flight', item.node.name, error);
|
|
33398
33512
|
dispatch(setTrajectFlightAvailability({ lineGuid, results: [], selectedGuid: null }));
|
|
33399
|
-
return
|
|
33513
|
+
return item.lines.map((x) => x.guid);
|
|
33400
33514
|
}
|
|
33401
33515
|
};
|
|
33402
33516
|
(async () => {
|
|
33403
33517
|
const searchable = nodesWithLines.filter((x) => isSearchableTrajectNode(x.node));
|
|
33404
33518
|
const flightNodes = nodesWithLines.filter((x) => isTrajectFlightNode(x.node));
|
|
33405
|
-
const unresolved = await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)]);
|
|
33519
|
+
const unresolved = (await Promise.all([...searchable.map(resolveNode), ...flightNodes.map(resolveFlightNode)])).flat();
|
|
33406
33520
|
if (controller.signal.aborted)
|
|
33407
33521
|
return;
|
|
33408
33522
|
// A node with no availability anywhere cannot be priced or booked, so its line comes off
|
|
33409
33523
|
// the entry. The card stays visible and reports the gap.
|
|
33410
|
-
const emptyLineGuids = unresolved.filter(
|
|
33524
|
+
const emptyLineGuids = unresolved.filter(Boolean);
|
|
33411
33525
|
if (emptyLineGuids.length)
|
|
33412
33526
|
dispatch(removeEditableEntryLines(emptyLineGuids));
|
|
33413
33527
|
})();
|
|
33414
33528
|
return () => controller.abort();
|
|
33415
|
-
}, [trajectEntry]);
|
|
33529
|
+
}, [trajectEntry, showNonPreferredItems]);
|
|
33416
33530
|
};
|
|
33417
33531
|
|
|
33418
33532
|
const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
@@ -33420,7 +33534,7 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
33420
33534
|
const dispatch = useDispatch();
|
|
33421
33535
|
const context = useContext(SearchResultsConfigurationContext);
|
|
33422
33536
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
33423
|
-
const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry } = useSelector((state) => state.searchResults);
|
|
33537
|
+
const { results, filteredResults, packagingAccoResults, filteredPackagingAccoResults, isLoading, flightsLoading, initialFilters, filters, flightFilters, selectedSortType, selectedFlightSortType, selectedSearchResult, selectedPackagingAccoResultCode, flyInIsOpen, packagingAccoSearchDetails, editablePackagingEntry, transactionId, flyInType, packagingFlightResults, confirmedExcursionsByDay, bookPackagingEntry, trajectEditLineGuid } = useSelector((state) => state.searchResults);
|
|
33424
33538
|
const isMobile = useMediaQuery('(max-width: 1200px)');
|
|
33425
33539
|
// Resolves live availability per traject node; no-op unless a traject entry is configured.
|
|
33426
33540
|
useTrajectAvailability();
|
|
@@ -33709,6 +33823,20 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
33709
33823
|
setDetailsIsLoading(false);
|
|
33710
33824
|
};
|
|
33711
33825
|
const handleConfirmHotelSwap = () => {
|
|
33826
|
+
if (context?.trajectEntry && trajectEditLineGuid) {
|
|
33827
|
+
const item = getTrajectNodesWithLines(context.trajectEntry).find((x) => x.line.guid === trajectEditLineGuid);
|
|
33828
|
+
const result = packagingAccoSearchDetails.find((x) => x.code === selectedPackagingAccoResultCode);
|
|
33829
|
+
if (item && result) {
|
|
33830
|
+
const currentLines = item.lines
|
|
33831
|
+
.map((line) => editablePackagingEntry?.lines?.find((x) => x.guid === line.guid))
|
|
33832
|
+
.filter((x) => !!x);
|
|
33833
|
+
applyResultToLines(currentLines, result).forEach((line) => dispatch(updateEditableEntryLine(line)));
|
|
33834
|
+
dispatch(updateTrajectNodeResult({ lineGuid: trajectEditLineGuid, result }));
|
|
33835
|
+
}
|
|
33836
|
+
dispatch(setTrajectEditLineGuid(null));
|
|
33837
|
+
handleFlyInToggle(false);
|
|
33838
|
+
return;
|
|
33839
|
+
}
|
|
33712
33840
|
const updatedEntry = swapHotelInPackagingEntry();
|
|
33713
33841
|
if (!updatedEntry)
|
|
33714
33842
|
return;
|
|
@@ -34057,6 +34185,10 @@ const SearchResultsContainer = ({ onBookingStarted }) => {
|
|
|
34057
34185
|
const fetchPackagingAccoSearchDetails = async () => {
|
|
34058
34186
|
if (!selectedPackagingAccoResultCode || !context)
|
|
34059
34187
|
return;
|
|
34188
|
+
// A traject node already resolved its own availability, options per room included, and hands
|
|
34189
|
+
// that result straight to the fly-in.
|
|
34190
|
+
if (context.trajectEntry)
|
|
34191
|
+
return;
|
|
34060
34192
|
if (skipInitialPackagingAccoDetailsRef.current) {
|
|
34061
34193
|
skipInitialPackagingAccoDetailsRef.current = false;
|
|
34062
34194
|
return;
|
|
@@ -37571,20 +37703,20 @@ function ItineraryMapView({ destinations: propDestinations, adults = 2, dateFrom
|
|
|
37571
37703
|
const isStartEnd = dest.isStart || dest.isEnd;
|
|
37572
37704
|
let iconHtml;
|
|
37573
37705
|
if (isStartEnd) {
|
|
37574
|
-
iconHtml = `
|
|
37575
|
-
<div class="map-view__marker map-view__marker--plane">
|
|
37576
|
-
<svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
|
37577
|
-
<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"/>
|
|
37578
|
-
</svg>
|
|
37706
|
+
iconHtml = `
|
|
37707
|
+
<div class="map-view__marker map-view__marker--plane">
|
|
37708
|
+
<svg viewBox="0 0 576 512" fill="currentColor" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
|
37709
|
+
<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"/>
|
|
37710
|
+
</svg>
|
|
37579
37711
|
</div>`;
|
|
37580
37712
|
}
|
|
37581
37713
|
else {
|
|
37582
37714
|
stopIndex++;
|
|
37583
37715
|
const imgStyle = dest.imageUrl ? `style="background-image:url('${dest.imageUrl}')"` : '';
|
|
37584
|
-
iconHtml = `
|
|
37585
|
-
<div class="map-view__marker map-view__marker--stop" ${imgStyle}>
|
|
37586
|
-
${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
|
|
37587
|
-
<span class="map-view__marker-badge">${stopIndex}</span>
|
|
37716
|
+
iconHtml = `
|
|
37717
|
+
<div class="map-view__marker map-view__marker--stop" ${imgStyle}>
|
|
37718
|
+
${!dest.imageUrl ? `<span class="map-view__marker-number">${stopIndex}</span>` : ''}
|
|
37719
|
+
<span class="map-view__marker-badge">${stopIndex}</span>
|
|
37588
37720
|
</div>`;
|
|
37589
37721
|
}
|
|
37590
37722
|
const icon = L.divIcon({
|