@qite/tide-booking-component 1.4.98 → 1.4.99
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 +1088 -637
- package/build/build-cjs/src/search-results/components/itinerary/index.d.ts +2 -0
- package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +9 -10
- package/build/build-cjs/src/search-results/types.d.ts +23 -1
- package/build/build-cjs/src/search-results/utils/packaging-utils.d.ts +7 -0
- package/build/build-cjs/src/search-results/utils/query-utils.d.ts +11 -0
- package/build/build-cjs/src/shared/components/flyin/accommodation-flyin.d.ts +1 -2
- package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +4 -0
- package/build/build-cjs/src/shared/utils/localization-util.d.ts +1 -0
- package/build/build-esm/index.js +1088 -637
- package/build/build-esm/src/search-results/components/itinerary/index.d.ts +2 -0
- package/build/build-esm/src/search-results/store/search-results-slice.d.ts +9 -10
- package/build/build-esm/src/search-results/types.d.ts +23 -1
- package/build/build-esm/src/search-results/utils/packaging-utils.d.ts +7 -0
- package/build/build-esm/src/search-results/utils/query-utils.d.ts +11 -0
- package/build/build-esm/src/shared/components/flyin/accommodation-flyin.d.ts +1 -2
- package/build/build-esm/src/shared/components/flyin/flyin.d.ts +4 -0
- package/build/build-esm/src/shared/utils/localization-util.d.ts +1 -0
- package/package.json +2 -2
- package/src/qsm/components/search-input-group/index.tsx +0 -1
- package/src/search-results/components/itinerary/index.tsx +132 -70
- package/src/search-results/components/search-results-container/search-results-container.tsx +444 -383
- package/src/search-results/store/search-results-slice.ts +22 -10
- package/src/search-results/types.ts +25 -1
- package/src/search-results/utils/packaging-utils.ts +75 -0
- package/src/search-results/utils/query-utils.ts +152 -0
- package/src/shared/components/flyin/accommodation-flyin.tsx +10 -11
- package/src/shared/components/flyin/flyin.tsx +52 -4
- package/styles/components/_flyin.scss +25 -0
- package/styles/components/_search.scss +26 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { PackagingEntryLine } from '@qite/tide-client';
|
|
2
3
|
interface ItineraryProps {
|
|
3
4
|
isOpen: boolean;
|
|
4
5
|
handleSetIsOpen: () => void;
|
|
5
6
|
isLoading?: boolean;
|
|
7
|
+
onEditAccommodation?: (segments: PackagingEntryLine[]) => void;
|
|
6
8
|
}
|
|
7
9
|
declare const Itinerary: React.FC<ItineraryProps>;
|
|
8
10
|
export default Itinerary;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ExtendedFlightSearchResponseItem, Filter, SortByType } from '../types';
|
|
2
|
-
import { BookingPackage, BookingPackageItem,
|
|
1
|
+
import { AccommodationFlyInStep, ExtendedFlightSearchResponseItem, Filter, SortByType } from '../types';
|
|
2
|
+
import { BookingPackage, BookingPackageItem, PackagingAccommodationResponse, PackagingEntry } from '@qite/tide-client/build/types';
|
|
3
3
|
export interface SearchResultsState {
|
|
4
4
|
results: BookingPackageItem[];
|
|
5
5
|
filteredResults: BookingPackageItem[];
|
|
@@ -11,13 +11,15 @@ export interface SearchResultsState {
|
|
|
11
11
|
selectedFlight: ExtendedFlightSearchResponseItem | null;
|
|
12
12
|
selectedFlightDetails: ExtendedFlightSearchResponseItem | null;
|
|
13
13
|
bookingPackageDetails: BookingPackage | null;
|
|
14
|
-
entry: EntryLight | null;
|
|
15
14
|
isLoading: boolean;
|
|
16
15
|
filters: Filter[];
|
|
17
16
|
selectedSortType: SortByType | null;
|
|
18
17
|
activeTab: string | null;
|
|
19
18
|
currentPage: number;
|
|
20
19
|
flyInIsOpen: boolean;
|
|
20
|
+
editablePackagingEntry: PackagingEntry | null;
|
|
21
|
+
transactionId: string | null;
|
|
22
|
+
accommodationFlyInStep: AccommodationFlyInStep;
|
|
21
23
|
}
|
|
22
24
|
export declare const setResults: import('@reduxjs/toolkit').ActionCreatorWithPayload<BookingPackageItem[], 'searchResults/setResults'>,
|
|
23
25
|
setFilteredResults: import('@reduxjs/toolkit').ActionCreatorWithPayload<BookingPackageItem[], 'searchResults/setFilteredResults'>,
|
|
@@ -43,12 +45,6 @@ export declare const setResults: import('@reduxjs/toolkit').ActionCreatorWithPay
|
|
|
43
45
|
},
|
|
44
46
|
'searchResults/setBookingPackageDetails'
|
|
45
47
|
>,
|
|
46
|
-
setEntry: import('@reduxjs/toolkit').ActionCreatorWithPayload<
|
|
47
|
-
{
|
|
48
|
-
entry: EntryLight;
|
|
49
|
-
},
|
|
50
|
-
'searchResults/setEntry'
|
|
51
|
-
>,
|
|
52
48
|
selectFlight: import('@reduxjs/toolkit').ActionCreatorWithPayload<
|
|
53
49
|
{
|
|
54
50
|
flightOptionId: string;
|
|
@@ -63,6 +59,9 @@ export declare const setResults: import('@reduxjs/toolkit').ActionCreatorWithPay
|
|
|
63
59
|
setActiveTab: import('@reduxjs/toolkit').ActionCreatorWithPayload<string | null, 'searchResults/setActiveTab'>,
|
|
64
60
|
setCurrentPage: import('@reduxjs/toolkit').ActionCreatorWithPayload<number, 'searchResults/setCurrentPage'>,
|
|
65
61
|
resetSearchState: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<'searchResults/resetSearchState'>,
|
|
66
|
-
setFlyInIsOpen: import('@reduxjs/toolkit').ActionCreatorWithPayload<boolean, 'searchResults/setFlyInIsOpen'
|
|
62
|
+
setFlyInIsOpen: import('@reduxjs/toolkit').ActionCreatorWithPayload<boolean, 'searchResults/setFlyInIsOpen'>,
|
|
63
|
+
setEditablePackagingEntry: import('@reduxjs/toolkit').ActionCreatorWithPayload<PackagingEntry | null, 'searchResults/setEditablePackagingEntry'>,
|
|
64
|
+
setTransactionId: import('@reduxjs/toolkit').ActionCreatorWithPayload<string | null, 'searchResults/setTransactionId'>,
|
|
65
|
+
setAccommodationFlyInStep: import('@reduxjs/toolkit').ActionCreatorWithPayload<AccommodationFlyInStep, 'searchResults/setAccommodationFlyInStep'>;
|
|
67
66
|
declare const _default: import('@reduxjs/toolkit').Reducer<SearchResultsState>;
|
|
68
67
|
export default _default;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BookingPackage,
|
|
3
|
+
BookingPackageRequestRoom,
|
|
4
|
+
FlightSearchResponseItem,
|
|
5
|
+
PackagingEntry,
|
|
6
|
+
WebsiteConfigurationSearchConfiguration
|
|
7
|
+
} from '@qite/tide-client';
|
|
2
8
|
import { ReactNode } from 'react';
|
|
3
9
|
export type FlightSelectionMode = 'paired' | 'independent';
|
|
4
10
|
export interface SearchResultsConfiguration {
|
|
@@ -143,3 +149,19 @@ export interface TideTag {
|
|
|
143
149
|
id: number;
|
|
144
150
|
name: string;
|
|
145
151
|
}
|
|
152
|
+
export type SearchSeed = {
|
|
153
|
+
fromDate: string;
|
|
154
|
+
toDate: string;
|
|
155
|
+
country?: number | null;
|
|
156
|
+
region?: number | null;
|
|
157
|
+
oord?: number | null;
|
|
158
|
+
location?: number | null;
|
|
159
|
+
hotel?: number | null;
|
|
160
|
+
hotelCode?: string | null;
|
|
161
|
+
tagId?: number | null;
|
|
162
|
+
departureAirport?: string | null;
|
|
163
|
+
returnAirport?: string | null;
|
|
164
|
+
destinationAirport?: string | null;
|
|
165
|
+
rooms: BookingPackageRequestRoom[];
|
|
166
|
+
};
|
|
167
|
+
export type AccommodationFlyInStep = 'results' | 'details';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BookingPackageRequestRoom, PackagingAccommodationResponse, PackagingEntry, PackagingEntryLine } from '@qite/tide-client';
|
|
2
|
+
export declare const getSelectedOptionsPerRoom: (details: PackagingAccommodationResponse[]) => {
|
|
3
|
+
roomIndex: number;
|
|
4
|
+
option: import('@qite/tide-client').PackageMainOption;
|
|
5
|
+
}[];
|
|
6
|
+
export declare const getRoomIndexFromLine: (line: PackagingEntryLine) => number;
|
|
7
|
+
export declare const getRequestRoomsFromPackagingSegments: (entry: PackagingEntry, segments: PackagingEntryLine[]) => BookingPackageRequestRoom[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PackagingEntryLine, PackagingEntry, BookingPackageRequestRoom, PackagingRoom } from '@qite/tide-client';
|
|
2
|
+
export declare const GROUP_TOUR_SERVICE_TYPE = 1;
|
|
3
|
+
export declare const ACCOMMODATION_SERVICE_TYPE = 3;
|
|
4
|
+
export declare const FLIGHT_SERVICE_TYPE = 7;
|
|
5
|
+
export declare const toDateOnlyString: (value: string | Date) => string;
|
|
6
|
+
export declare const getPrimaryAccommodationLine: (lines: PackagingEntryLine[]) => PackagingEntryLine | undefined;
|
|
7
|
+
export declare const getDepartureAirportFromEntry: (lines: PackagingEntryLine[]) => string | null;
|
|
8
|
+
export declare const getDestinationAirportFromEntry: (lines: PackagingEntryLine[]) => string | null;
|
|
9
|
+
export declare const getRequestRoomsFromPackagingEntry: (entry: PackagingEntry) => BookingPackageRequestRoom[];
|
|
10
|
+
export declare const parseHotelId: (line?: PackagingEntryLine) => number | null;
|
|
11
|
+
export declare const getPackagingRequestRoomsFromBookingRooms: (rooms: BookingPackageRequestRoom[] | null) => PackagingRoom[];
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
type AccommodationFlyInProps = {
|
|
3
3
|
isLoading: boolean;
|
|
4
|
-
|
|
5
|
-
setIsOpen: (open: boolean) => void;
|
|
4
|
+
handleConfirm: () => void;
|
|
6
5
|
};
|
|
7
6
|
declare const AccommodationFlyIn: React.FC<AccommodationFlyInProps>;
|
|
8
7
|
export default AccommodationFlyIn;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { PortalQsmType } from '@qite/tide-client';
|
|
3
|
+
import { AccommodationFlyInStep } from '../../../search-results/types';
|
|
3
4
|
type FlyInProps = {
|
|
4
5
|
title: string;
|
|
5
6
|
srpType: PortalQsmType;
|
|
@@ -8,6 +9,9 @@ type FlyInProps = {
|
|
|
8
9
|
className?: string;
|
|
9
10
|
onPanelRef?: (el: HTMLDivElement | null) => void;
|
|
10
11
|
detailsLoading: boolean;
|
|
12
|
+
handleConfirm?: () => void;
|
|
13
|
+
accommodationStep?: AccommodationFlyInStep;
|
|
14
|
+
isPackageEditFlow?: boolean;
|
|
11
15
|
};
|
|
12
16
|
declare const FlyIn: React.FC<FlyInProps>;
|
|
13
17
|
export default FlyIn;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qite/tide-booking-component",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.99",
|
|
4
4
|
"description": "React Booking wizard & Booking product component for Tide",
|
|
5
5
|
"main": "build/build-cjs/index.js",
|
|
6
6
|
"types": "build/build-cjs/src/index.d.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@jsonurl/jsonurl": "^1.1.4",
|
|
31
31
|
"@popperjs/core": "^2.10.2",
|
|
32
|
-
"@qite/tide-client": "^1.1.
|
|
32
|
+
"@qite/tide-client": "^1.1.155",
|
|
33
33
|
"@reduxjs/toolkit": "^2.8.2",
|
|
34
34
|
"@rollup/plugin-commonjs": "^19.0.1",
|
|
35
35
|
"@rollup/plugin-json": "^4.1.0",
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import React, { useContext, useMemo } from 'react';
|
|
2
2
|
import { differenceInCalendarDays, format } from 'date-fns';
|
|
3
|
-
import { first, isEmpty, last } from 'lodash';
|
|
3
|
+
import { first, groupBy, isEmpty, last } from 'lodash';
|
|
4
4
|
import { PackagingEntryLine, PackagingEntryLineFlightLine } from '@qite/tide-client';
|
|
5
|
-
|
|
6
5
|
import Icon from '../icon';
|
|
7
|
-
import Spinner from '../spinner/spinner';
|
|
8
6
|
import SearchResultsConfigurationContext from '../../search-results-configuration-context';
|
|
9
7
|
import { formatPrice, getTranslations } from '../../../shared/utils/localization-util';
|
|
8
|
+
import { useSelector } from 'react-redux';
|
|
9
|
+
import { SearchResultsRootState } from '../../store/search-results-store';
|
|
10
|
+
import { ACCOMMODATION_SERVICE_TYPE, FLIGHT_SERVICE_TYPE } from '../../utils/query-utils';
|
|
10
11
|
|
|
11
12
|
interface ItineraryProps {
|
|
12
13
|
isOpen: boolean;
|
|
13
14
|
handleSetIsOpen: () => void;
|
|
14
15
|
isLoading?: boolean;
|
|
16
|
+
onEditAccommodation?: (segments: PackagingEntryLine[]) => void;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
const FLIGHT_SERVICE_TYPE = 7;
|
|
18
|
-
const ACCOMMODATION_SERVICE_TYPE = 3;
|
|
19
|
-
|
|
20
19
|
const getFlightLines = (flight?: PackagingEntryLine): PackagingEntryLineFlightLine[] => {
|
|
21
20
|
return flight?.flightInformation?.flightLines ?? [];
|
|
22
21
|
};
|
|
@@ -57,30 +56,57 @@ const numberOfNights = (segment: PackagingEntryLine) => {
|
|
|
57
56
|
const getSegmentIcon = (segment: PackagingEntryLine) => {
|
|
58
57
|
switch (segment.serviceType) {
|
|
59
58
|
case 3:
|
|
60
|
-
return
|
|
59
|
+
return (
|
|
60
|
+
<div className="search__filter__itinerary__segment-badge search__filter__itinerary__segment-badge--secondary">
|
|
61
|
+
<Icon name="ui-bed" width={15} height={15} />
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
61
64
|
case 4:
|
|
62
|
-
return
|
|
65
|
+
return (
|
|
66
|
+
<div className="search__filter__itinerary__segment-badge search__filter__itinerary__segment-badge--secondary">
|
|
67
|
+
<Icon name="ui-ticket" width={15} height={15} />
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
63
70
|
case 11:
|
|
64
|
-
return
|
|
71
|
+
return (
|
|
72
|
+
<div className="search__filter__itinerary__segment-badge search__filter__itinerary__segment-badge--secondary">
|
|
73
|
+
<Icon name="ui-ship" width={15} height={15} />
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
65
76
|
case 13:
|
|
66
77
|
case 17:
|
|
67
78
|
case 22:
|
|
68
|
-
return
|
|
79
|
+
return (
|
|
80
|
+
<div className="search__filter__itinerary__transport-badge">
|
|
81
|
+
<Icon name="ui-car" width={15} height={15} />
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
69
84
|
default:
|
|
70
|
-
return
|
|
85
|
+
return (
|
|
86
|
+
<div className="search__filter__itinerary__segment-badge">
|
|
87
|
+
<Icon name="ui-location" width={15} height={15} />
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const canEdit = (segment: PackagingEntryLine) => {
|
|
94
|
+
if (segment.serviceType === ACCOMMODATION_SERVICE_TYPE) {
|
|
95
|
+
return true;
|
|
71
96
|
}
|
|
97
|
+
return false;
|
|
72
98
|
};
|
|
73
99
|
|
|
74
100
|
const getSegmentTitle = (segment: PackagingEntryLine) => {
|
|
75
|
-
|
|
76
|
-
return segment.productName;
|
|
101
|
+
return segment.productName ?? segment.accommodationName;
|
|
77
102
|
};
|
|
78
103
|
|
|
79
|
-
const Itinerary: React.FC<ItineraryProps> = ({ isOpen, handleSetIsOpen, isLoading }) => {
|
|
104
|
+
const Itinerary: React.FC<ItineraryProps> = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation }) => {
|
|
80
105
|
const context = useContext(SearchResultsConfigurationContext);
|
|
81
106
|
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
107
|
+
const { editablePackagingEntry } = useSelector((state: SearchResultsRootState) => state.searchResults);
|
|
82
108
|
|
|
83
|
-
const packagingEntry = context?.packagingEntry;
|
|
109
|
+
const packagingEntry = editablePackagingEntry ?? context?.packagingEntry;
|
|
84
110
|
|
|
85
111
|
const sortedLines = useMemo(() => {
|
|
86
112
|
return [...(packagingEntry?.lines ?? [])].sort((a, b) => {
|
|
@@ -114,8 +140,15 @@ const Itinerary: React.FC<ItineraryProps> = ({ isOpen, handleSetIsOpen, isLoadin
|
|
|
114
140
|
const returnFlight = flightSegments.length > 1 ? last(flightSegments) : undefined;
|
|
115
141
|
|
|
116
142
|
const otherSegments = sortedLines.filter((item) => item.serviceType !== FLIGHT_SERVICE_TYPE);
|
|
117
|
-
|
|
118
|
-
|
|
143
|
+
const grouped = groupBy(otherSegments, (segment) => {
|
|
144
|
+
return `${segment.productCode}-${segment.from}-${segment.to}`;
|
|
145
|
+
});
|
|
146
|
+
const groupedOtherSegments = Object.entries(grouped).map(([key, segments]) => ({
|
|
147
|
+
key,
|
|
148
|
+
segments
|
|
149
|
+
}));
|
|
150
|
+
console.log('otherSegments', otherSegments);
|
|
151
|
+
console.log('groupedOtherSegments', groupedOtherSegments);
|
|
119
152
|
|
|
120
153
|
const numberOfPax = packagingEntry.pax?.length || 1;
|
|
121
154
|
const totalPrice = packagingEntry.price || 0;
|
|
@@ -221,68 +254,97 @@ const Itinerary: React.FC<ItineraryProps> = ({ isOpen, handleSetIsOpen, isLoadin
|
|
|
221
254
|
</div>
|
|
222
255
|
)}
|
|
223
256
|
|
|
224
|
-
{!isEmpty(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
<div className="search__filter__itinerary__segments-timeline">
|
|
229
|
-
<div className="search__filter__itinerary__segments-timeline-line"></div>
|
|
230
|
-
</div>
|
|
257
|
+
{!isEmpty(groupedOtherSegments) &&
|
|
258
|
+
groupedOtherSegments.map((group) => {
|
|
259
|
+
const firstSegment = first(group.segments);
|
|
260
|
+
if (!firstSegment) return null;
|
|
231
261
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
</p>
|
|
238
|
-
<p>{format(new Date(segment.from), 'MMM')}</p>
|
|
239
|
-
</div>
|
|
240
|
-
|
|
241
|
-
<div className="search__filter__itinerary__segment-badge">
|
|
242
|
-
<Icon name="ui-location" width={15} height={15} />
|
|
243
|
-
</div>
|
|
244
|
-
|
|
245
|
-
<div className="search__filter__itinerary__segment-details">
|
|
246
|
-
<h6>
|
|
247
|
-
{segment.location?.name || segment.oord?.name || segment.region?.name}
|
|
248
|
-
{(segment.location?.name || segment.oord?.name || segment.region?.name) && segment.country?.name ? ', ' : ''}
|
|
249
|
-
{segment.country?.name}
|
|
250
|
-
</h6>
|
|
251
|
-
<p className="search__filter__itinerary__segment-details-text">
|
|
252
|
-
{format(new Date(segment.from), 'EEE. d MMM yyyy')}
|
|
253
|
-
> {format(new Date(segment.to), 'EEE. d MMM yyyy')}
|
|
254
|
-
</p>
|
|
255
|
-
</div>
|
|
262
|
+
return (
|
|
263
|
+
<div className="search__filter__itinerary__segments">
|
|
264
|
+
<div className="search__filter__itinerary__segments__wrapper" key={group.key}>
|
|
265
|
+
<div className="search__filter__itinerary__segments-timeline">
|
|
266
|
+
<div className="search__filter__itinerary__segments-timeline-line"></div>
|
|
256
267
|
</div>
|
|
257
|
-
</div>
|
|
258
268
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
269
|
+
<div className="search__filter__itinerary__segment">
|
|
270
|
+
<div className="search__filter__itinerary__segment-item search__filter__itinerary__segment-item--start">
|
|
271
|
+
<div className="search__filter__itinerary__transport-date">
|
|
272
|
+
<p className="search__filter__itinerary__transport-date-date">
|
|
273
|
+
<strong>{format(new Date(firstSegment.from), 'd')}</strong>
|
|
274
|
+
</p>
|
|
275
|
+
<p>{format(new Date(firstSegment.from), 'MMM')}</p>
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
<div className="search__filter__itinerary__segment-badge">
|
|
279
|
+
<Icon name="ui-location" width={15} height={15} />
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<div className="search__filter__itinerary__segment-details">
|
|
283
|
+
<h6>
|
|
284
|
+
{firstSegment.location?.name || firstSegment.oord?.name || firstSegment.region?.name}
|
|
285
|
+
{(firstSegment.location?.name || firstSegment.oord?.name || firstSegment.region?.name) && firstSegment.country?.name ? ', ' : ''}
|
|
286
|
+
{firstSegment.country?.name}
|
|
287
|
+
</h6>
|
|
288
|
+
<p className="search__filter__itinerary__segment-details-text">
|
|
289
|
+
{format(new Date(firstSegment.from), 'EEE. d MMM yyyy')}
|
|
290
|
+
> {format(new Date(firstSegment.to), 'EEE. d MMM yyyy')}
|
|
291
|
+
</p>
|
|
292
|
+
</div>
|
|
274
293
|
</div>
|
|
294
|
+
</div>
|
|
275
295
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
{
|
|
296
|
+
<div className="search__filter__itinerary__segment">
|
|
297
|
+
<div
|
|
298
|
+
className={`search__filter__itinerary__segment-item ${
|
|
299
|
+
canEdit(firstSegment) ? 'search__filter__itinerary__segment-item--editable' : ''
|
|
300
|
+
}`}
|
|
301
|
+
onClick={() => {
|
|
302
|
+
if (canEdit(firstSegment) && onEditAccommodation) {
|
|
303
|
+
onEditAccommodation(group.segments);
|
|
304
|
+
}
|
|
305
|
+
}}>
|
|
306
|
+
<div className="search__filter__itinerary__segment-date search__filter__itinerary__segment-nights">
|
|
307
|
+
{firstSegment.serviceType === ACCOMMODATION_SERVICE_TYPE && (
|
|
308
|
+
<>
|
|
309
|
+
<p className="search__filter__itinerary__segment-date-date">
|
|
310
|
+
<strong>{numberOfNights(firstSegment)}</strong>
|
|
311
|
+
</p>
|
|
312
|
+
<Icon name="ui-moon" width={16} height={16} />
|
|
313
|
+
</>
|
|
314
|
+
)}
|
|
315
|
+
</div>
|
|
316
|
+
|
|
317
|
+
{getSegmentIcon(firstSegment)}
|
|
318
|
+
|
|
319
|
+
<div className="search__filter__itinerary__segment-details">
|
|
320
|
+
<h6>{getSegmentTitle(firstSegment)}</h6>
|
|
321
|
+
{firstSegment.serviceType === ACCOMMODATION_SERVICE_TYPE &&
|
|
322
|
+
group.segments.map((segment, index) => (
|
|
323
|
+
<React.Fragment key={segment.guid}>
|
|
324
|
+
<strong>
|
|
325
|
+
{translations.SHARED.ROOM} {index + 1}
|
|
326
|
+
</strong>
|
|
327
|
+
{segment.productName && segment.accommodationName && (
|
|
328
|
+
<div className="search__filter__itinerary__segment-details__room">
|
|
329
|
+
<Icon name="ui-bed" width={12} height={12} />
|
|
330
|
+
{segment.accommodationName}
|
|
331
|
+
</div>
|
|
332
|
+
)}
|
|
333
|
+
{segment.regimeName && (
|
|
334
|
+
<div className="search__filter__itinerary__segment-details__room">
|
|
335
|
+
<Icon name="ui-utensils" width={12} height={12} />
|
|
336
|
+
{segment.regimeName}
|
|
337
|
+
</div>
|
|
338
|
+
)}
|
|
339
|
+
</React.Fragment>
|
|
340
|
+
))}
|
|
341
|
+
</div>
|
|
279
342
|
</div>
|
|
280
343
|
</div>
|
|
281
344
|
</div>
|
|
282
345
|
</div>
|
|
283
|
-
)
|
|
284
|
-
|
|
285
|
-
)}
|
|
346
|
+
);
|
|
347
|
+
})}
|
|
286
348
|
|
|
287
349
|
{returnFlight && returnFlight !== outboundFlight && (
|
|
288
350
|
<div className="search__filter__itinerary__transport">
|