@qite/tide-booking-component 1.4.97 → 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.
Files changed (30) hide show
  1. package/build/build-cjs/index.js +1423 -975
  2. package/build/build-cjs/src/search-results/components/itinerary/index.d.ts +2 -0
  3. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +9 -10
  4. package/build/build-cjs/src/search-results/types.d.ts +24 -1
  5. package/build/build-cjs/src/search-results/utils/packaging-utils.d.ts +7 -0
  6. package/build/build-cjs/src/search-results/utils/query-utils.d.ts +11 -0
  7. package/build/build-cjs/src/shared/components/flyin/accommodation-flyin.d.ts +1 -2
  8. package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +4 -0
  9. package/build/build-cjs/src/shared/utils/localization-util.d.ts +1 -0
  10. package/build/build-esm/index.js +1419 -965
  11. package/build/build-esm/src/search-results/components/itinerary/index.d.ts +2 -0
  12. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +9 -10
  13. package/build/build-esm/src/search-results/types.d.ts +24 -1
  14. package/build/build-esm/src/search-results/utils/packaging-utils.d.ts +7 -0
  15. package/build/build-esm/src/search-results/utils/query-utils.d.ts +11 -0
  16. package/build/build-esm/src/shared/components/flyin/accommodation-flyin.d.ts +1 -2
  17. package/build/build-esm/src/shared/components/flyin/flyin.d.ts +4 -0
  18. package/build/build-esm/src/shared/utils/localization-util.d.ts +1 -0
  19. package/package.json +2 -2
  20. package/src/qsm/components/search-input-group/index.tsx +0 -1
  21. package/src/search-results/components/itinerary/index.tsx +331 -234
  22. package/src/search-results/components/search-results-container/search-results-container.tsx +444 -383
  23. package/src/search-results/store/search-results-slice.ts +22 -10
  24. package/src/search-results/types.ts +26 -1
  25. package/src/search-results/utils/packaging-utils.ts +75 -0
  26. package/src/search-results/utils/query-utils.ts +152 -0
  27. package/src/shared/components/flyin/accommodation-flyin.tsx +10 -11
  28. package/src/shared/components/flyin/flyin.tsx +52 -4
  29. package/styles/components/_flyin.scss +25 -0
  30. package/styles/components/_search.scss +28 -1
@@ -1,309 +1,406 @@
1
- import React, { useContext } from 'react';
2
- import Icon from '../icon';
3
- import Spinner from '../spinner/spinner';
4
- import { SearchResultsRootState } from '../../store/search-results-store';
5
- import { useSelector } from 'react-redux';
6
- import { first, isEmpty, last } from 'lodash';
7
- import { formatPrice, getTranslations } from '../../../shared/utils/localization-util';
1
+ import React, { useContext, useMemo } from 'react';
8
2
  import { differenceInCalendarDays, format } from 'date-fns';
9
- import { EntryLineLight } from '@qite/tide-client';
3
+ import { first, groupBy, isEmpty, last } from 'lodash';
4
+ import { PackagingEntryLine, PackagingEntryLineFlightLine } from '@qite/tide-client';
5
+ import Icon from '../icon';
10
6
  import SearchResultsConfigurationContext from '../../search-results-configuration-context';
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';
11
11
 
12
12
  interface ItineraryProps {
13
13
  isOpen: boolean;
14
14
  handleSetIsOpen: () => void;
15
15
  isLoading?: boolean;
16
+ onEditAccommodation?: (segments: PackagingEntryLine[]) => void;
16
17
  }
17
18
 
18
- const getDepartureTime = (flight?: EntryLineLight): string => {
19
- if (isEmpty(flight?.metaDatas)) return '';
20
-
21
- try {
22
- const config = first(flight?.metaDatas)?.configuration;
23
- if (!config) return '';
19
+ const getFlightLines = (flight?: PackagingEntryLine): PackagingEntryLineFlightLine[] => {
20
+ return flight?.flightInformation?.flightLines ?? [];
21
+ };
24
22
 
25
- const parsed = JSON.parse(config);
26
- const line = first(parsed?.FlightLines);
23
+ const getDepartureTime = (flight?: PackagingEntryLine): string => {
24
+ const firstLine = first(getFlightLines(flight));
25
+ if (!firstLine?.departureTime) return '';
27
26
 
28
- return (line as any)?.DepartureTime ?? '';
29
- } catch {
30
- return '';
31
- }
27
+ return firstLine.departureTime.slice(0, 5);
32
28
  };
33
29
 
34
- const getArrivalTime = (flight?: EntryLineLight): string => {
35
- if (isEmpty(flight?.metaDatas)) return '';
30
+ const getArrivalTime = (flight?: PackagingEntryLine): string => {
31
+ const lastLine = last(getFlightLines(flight));
32
+ if (!lastLine?.arrivalTime) return '';
36
33
 
37
- try {
38
- const config = first(flight?.metaDatas)?.configuration;
39
- if (!config) return '';
34
+ return lastLine.arrivalTime.slice(0, 5);
35
+ };
40
36
 
41
- const parsed = JSON.parse(config);
42
- const line = last(parsed?.FlightLines);
37
+ const getDuration = (flight?: PackagingEntryLine): string => {
38
+ const lines = getFlightLines(flight);
39
+ if (!lines.length) return '';
43
40
 
44
- return (line as any)?.ArrivalTime ?? '';
45
- } catch {
46
- return '';
47
- }
48
- };
41
+ const totalTicks = lines.reduce((sum, line) => sum + (line.durationInTicks ?? 0), 0) || 0;
49
42
 
50
- const getDuration = (flight?: EntryLineLight): string => {
51
- if (isEmpty(flight?.metaDatas)) return '';
43
+ if (!totalTicks) return '';
52
44
 
53
- try {
54
- const config = first(flight?.metaDatas)?.configuration;
55
- if (!config) return '';
45
+ const seconds = totalTicks / 10_000_000;
46
+ const hours = Math.floor(seconds / 3600);
47
+ const minutes = Math.floor((seconds % 3600) / 60);
56
48
 
57
- const parsed = JSON.parse(config);
58
- const ticks = parsed?.DurationInTicks;
49
+ return `${hours}h ${minutes.toString().padStart(2, '0')}m`;
50
+ };
59
51
 
60
- if (!ticks) return '';
52
+ const numberOfNights = (segment: PackagingEntryLine) => {
53
+ return differenceInCalendarDays(new Date(segment.to), new Date(segment.from));
54
+ };
61
55
 
62
- const seconds = ticks / 10_000_000;
63
- const hours = Math.floor(seconds / 3600);
64
- const minutes = Math.floor((seconds % 3600) / 60);
56
+ const getSegmentIcon = (segment: PackagingEntryLine) => {
57
+ switch (segment.serviceType) {
58
+ case 3:
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
+ );
64
+ case 4:
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
+ );
70
+ case 11:
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
+ );
76
+ case 13:
77
+ case 17:
78
+ case 22:
79
+ return (
80
+ <div className="search__filter__itinerary__transport-badge">
81
+ <Icon name="ui-car" width={15} height={15} />
82
+ </div>
83
+ );
84
+ default:
85
+ return (
86
+ <div className="search__filter__itinerary__segment-badge">
87
+ <Icon name="ui-location" width={15} height={15} />
88
+ </div>
89
+ );
90
+ }
91
+ };
65
92
 
66
- return `${hours}h ${minutes.toString().padStart(2, '0')}m`;
67
- } catch {
68
- return '';
93
+ const canEdit = (segment: PackagingEntryLine) => {
94
+ if (segment.serviceType === ACCOMMODATION_SERVICE_TYPE) {
95
+ return true;
69
96
  }
97
+ return false;
70
98
  };
71
99
 
72
- const numberOfNights = (segment: EntryLineLight) => {
73
- return differenceInCalendarDays(new Date(segment.endDate), new Date(segment.startDate));
100
+ const getSegmentTitle = (segment: PackagingEntryLine) => {
101
+ return segment.productName ?? segment.accommodationName;
74
102
  };
75
103
 
76
- const Itinerary: React.FC<ItineraryProps> = ({ isOpen, handleSetIsOpen, isLoading }) => {
104
+ const Itinerary: React.FC<ItineraryProps> = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation }) => {
77
105
  const context = useContext(SearchResultsConfigurationContext);
78
106
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
107
+ const { editablePackagingEntry } = useSelector((state: SearchResultsRootState) => state.searchResults);
108
+
109
+ const packagingEntry = editablePackagingEntry ?? context?.packagingEntry;
110
+
111
+ const sortedLines = useMemo(() => {
112
+ return [...(packagingEntry?.lines ?? [])].sort((a, b) => {
113
+ const orderA = a.order ?? Infinity;
114
+ const orderB = b.order ?? Infinity;
79
115
 
80
- const { entry } = useSelector((state: SearchResultsRootState) => state.searchResults);
116
+ // First sort by order
117
+ if (orderA !== orderB) {
118
+ return orderA - orderB;
119
+ }
81
120
 
82
- if (isLoading || !entry) {
121
+ // Fallback to date
122
+ return new Date(a.from).getTime() - new Date(b.from).getTime();
123
+ });
124
+ }, [packagingEntry]);
125
+
126
+ if (!packagingEntry) {
83
127
  return null;
84
128
  }
85
129
 
86
- const firstEntryLine = first(entry?.items);
87
- const lastEntryLine = last(entry?.items);
130
+ const firstEntryLine = first(sortedLines);
131
+ const lastEntryLine = last(sortedLines);
132
+
133
+ const accommodationLine = sortedLines.find((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE) ?? firstEntryLine;
134
+
135
+ const country = accommodationLine?.country?.name ?? firstEntryLine?.country?.name;
136
+ const location = accommodationLine?.location?.name ?? accommodationLine?.oord?.name ?? accommodationLine?.region?.name ?? firstEntryLine?.location?.name;
88
137
 
89
- const country = firstEntryLine?.countryName;
90
- const location = firstEntryLine?.locationName;
138
+ const flightSegments = sortedLines.filter((item) => item.serviceType === FLIGHT_SERVICE_TYPE);
139
+ const outboundFlight = first(flightSegments);
140
+ const returnFlight = flightSegments.length > 1 ? last(flightSegments) : undefined;
91
141
 
92
- const outboundFlight = entry?.items.find((item) => item.productType === 7 && !item.isReturnFlight);
93
- const returnFlight = entry?.items.find((item) => item.productType === 7 && item.isReturnFlight);
94
- const otherSegments = entry?.items.filter((item) => item.productType !== 7);
142
+ const otherSegments = sortedLines.filter((item) => item.serviceType !== FLIGHT_SERVICE_TYPE);
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);
152
+
153
+ const numberOfPax = packagingEntry.pax?.length || 1;
154
+ const totalPrice = packagingEntry.price || 0;
155
+ const pricePerPerson = totalPrice / numberOfPax;
95
156
 
96
157
  return (
97
- <>
98
- {/* ---------------- Filters ---------------- */}
99
-
100
- {/* ---------------- Filters desktop ---------------- */}
101
- <div className={`search__filters--modal ${isOpen ? 'is-open' : ''}`}>
102
- <div className="search__filters--background" onClick={() => handleSetIsOpen()}></div>
103
- <button className="search__filters--close" onClick={() => handleSetIsOpen()}>
104
- <Icon name="ui-close" height={24} />
105
- </button>
106
- <div className="search__filters">
107
- <div className="search__filter-row search__filter__header">
108
- <div className="search__filter-row-flex-title">
109
- <p className="search__filter-small-title">{translations.SRP.ITINERARY_TITLE}</p>
110
- </div>
158
+ <div className={`search__filters--modal ${isOpen ? 'is-open' : ''}`}>
159
+ <div className="search__filters--background" onClick={handleSetIsOpen}></div>
160
+
161
+ <button className="search__filters--close" onClick={handleSetIsOpen}>
162
+ <Icon name="ui-close" height={24} />
163
+ </button>
164
+
165
+ <div className="search__filters">
166
+ <div className="search__filter-row search__filter__header">
167
+ <div className="search__filter-row-flex-title">
168
+ <p className="search__filter-small-title">{translations.SRP.ITINERARY_TITLE}</p>
111
169
  </div>
112
- {isLoading ? (
113
- <Spinner />
114
- ) : (
115
- <>
116
- <div className="search__filter-group">
117
- {context?.destinationImage && (
118
- <div className="search__filter__image__wrapper">
119
- <img src={context.destinationImage.url} alt={context.destinationImage.alt} className="search__filter__image" />
120
- {entry?.number && (
121
- <span className="search__filter__image__text">
122
- {translations.SRP.DOSSIER_NUMBER}: {entry?.number}
123
- </span>
124
- )}
125
- <h4 className="search__filter__image__title">{(location || '') + (location && country ? ' - ' : '') + (country || '')}</h4>
126
- </div>
170
+ </div>
171
+
172
+ <>
173
+ <div className="search__filter-group">
174
+ {context?.destinationImage && (
175
+ <div className="search__filter__image__wrapper">
176
+ <img src={context.destinationImage.url} alt={context.destinationImage.alt} className="search__filter__image" />
177
+
178
+ {packagingEntry?.dossierNumber && (
179
+ <span className="search__filter__image__text">
180
+ {translations.SRP.DOSSIER_NUMBER}: {packagingEntry.dossierNumber}
181
+ </span>
127
182
  )}
183
+
184
+ <h4 className="search__filter__image__title">{(location || '') + (location && country ? ' - ' : '') + (country || '')}</h4>
128
185
  </div>
186
+ )}
187
+ </div>
188
+
189
+ <div className="search__filter__prices">
190
+ <div className="search__filter__prices__wrapper">
191
+ <h3 className="search__filter__prices--amount">{formatPrice(pricePerPerson, 'EUR')}</h3>
192
+ <p>{translations.SRP.PACKAGE_PRICE_PER_PERSON}</p>
193
+ <p>
194
+ <strong>
195
+ ({formatPrice(totalPrice, 'EUR')} {translations.SRP.TOTAL})
196
+ </strong>
197
+ </p>
198
+ </div>
199
+ <button className="cta">{translations.QSM.CONFIRM}</button>
200
+ </div>
201
+
202
+ <div className="search__filter__itinerary">
203
+ <p>{translations.SRP.DAY_BY_DAY}</p>
129
204
 
130
- <div className="search__filter__prices">
131
- <div className="search__filter__prices__wrapper">
132
- <h3 className="search__filter__prices--amount">
133
- {formatPrice((entry?.sellingPrice || 0) / (entry?.numberOfPax || 1), entry?.currencyCode || 'EUR')}
134
- </h3>
135
- <p>{translations.SRP.PACKAGE_PRICE_PER_PERSON}</p>
205
+ {firstEntryLine && (
206
+ <div className="search__filter__itinerary__country">
207
+ <div className="search__filter__itinerary__country-icon">
208
+ <Icon name="ui-flag" width={17.5} height={20} />
209
+ </div>
210
+ <div className="search__filter__itinerary__country-content">
136
211
  <p>
137
- <strong>
138
- ({formatPrice(entry?.sellingPrice || 0, entry?.currencyCode || 'EUR')} {translations.SRP.TOTAL})
139
- </strong>
212
+ {format(new Date(firstEntryLine.from), 'EEE. d MMM yyyy')} - <strong>{translations.SRP.START}</strong>
140
213
  </p>
141
214
  </div>
142
- <button className="cta">{translations.QSM.CONFIRM}</button>
143
215
  </div>
216
+ )}
217
+
218
+ {outboundFlight && (
219
+ <div className="search__filter__itinerary__transport">
220
+ <div className="search__filter__itinerary__transport-timeline">
221
+ <div className="search__filter__itinerary__transport-timeline-line"></div>
222
+ </div>
223
+
224
+ <div className="search__filter__itinerary__transport-item">
225
+ <div className="search__filter__itinerary__transport-date">
226
+ <p className="search__filter__itinerary__transport-date-date">
227
+ <strong>{format(new Date(outboundFlight.from), 'd')}</strong>
228
+ </p>
229
+ <p>{format(new Date(outboundFlight.from), 'MMM')}</p>
230
+ </div>
144
231
 
145
- <div className="search__filter__itinerary">
146
- <p>{translations.SRP.DAY_BY_DAY}</p>
147
- <div className="search__filter__itinerary__country">
148
- <div className="search__filter__itinerary__country-icon">
149
- <Icon name="ui-flag" width={17.5} height={20} />
232
+ <div className="search__filter__itinerary__transport-badge">
233
+ <Icon name="ui-plane" height={15} />
150
234
  </div>
151
- <div className="search__filter__itinerary__country-content">
152
- <p>
153
- {format(new Date(firstEntryLine?.startDate || ''), 'EEE. d MMM yyyy')} - <strong>{translations.SRP.START}</strong>
235
+
236
+ <div className="search__filter__itinerary__transport-details">
237
+ <h6>{outboundFlight.productName}</h6>
238
+ <p className="search__filter__itinerary__transport-details-plane">
239
+ <span>
240
+ <Icon name="ui-plane-depart" height={14} /> <strong>{getDepartureTime(outboundFlight)}</strong>
241
+ </span>{' '}
242
+ -{' '}
243
+ <span>
244
+ <Icon name="ui-plane-arrive" height={14} /> <strong>{getArrivalTime(outboundFlight)}</strong>
245
+ </span>
246
+ </p>
247
+ <p className="search__filter__itinerary__transport-details-time">
248
+ <span>
249
+ <Icon name="ui-clock" height={20} /> {getDuration(outboundFlight)}
250
+ </span>
154
251
  </p>
155
252
  </div>
156
253
  </div>
254
+ </div>
255
+ )}
157
256
 
158
- {outboundFlight && (
159
- <div className="search__filter__itinerary__transport">
160
- <div className="search__filter__itinerary__transport-timeline">
161
- <div className="search__filter__itinerary__transport-timeline-line"></div>
162
- </div>
163
- <div className="search__filter__itinerary__transport-item">
164
- <div className="search__filter__itinerary__transport-date">
165
- <p className="search__filter__itinerary__transport-date-date">
166
- <strong>{format(new Date(outboundFlight?.startDate || ''), 'd')}</strong>
167
- </p>
168
- <p>{format(new Date(outboundFlight?.startDate || ''), 'MMM')}</p>
169
- </div>
170
- <div className="search__filter__itinerary__transport-badge">
171
- <Icon name="ui-plane" height={15} />
172
- </div>
173
- <div className="search__filter__itinerary__transport-details">
174
- <h6>{outboundFlight.productName}</h6>
175
- <p className="search__filter__itinerary__transport-details-plane">
176
- <span>
177
- <Icon name="ui-plane-depart" height={14} /> <strong>{getDepartureTime(outboundFlight)}</strong>
178
- </span>{' '}
179
- -{' '}
180
- <span>
181
- <Icon name="ui-plane-arrive" height={14} /> <strong>{getArrivalTime(outboundFlight)}</strong>
182
- </span>
183
- </p>
184
- <p className="search__filter__itinerary__transport-details-time">
185
- <span>
186
- <Icon name="ui-clock" height={20} /> {getDuration(outboundFlight)}
187
- </span>
188
- </p>
189
- </div>
190
- </div>
191
- </div>
192
- )}
193
- {!isEmpty(otherSegments) && (
257
+ {!isEmpty(groupedOtherSegments) &&
258
+ groupedOtherSegments.map((group) => {
259
+ const firstSegment = first(group.segments);
260
+ if (!firstSegment) return null;
261
+
262
+ return (
194
263
  <div className="search__filter__itinerary__segments">
195
- {otherSegments?.map((segment, index) => (
196
- <div className="search__filter__itinerary__segments__wrapper" key={`segment-${index}`}>
197
- <div className="search__filter__itinerary__segments-timeline">
198
- <div className="search__filter__itinerary__segments-timeline-line"></div>
199
- </div>
200
- <div className="search__filter__itinerary__segment">
201
- <div className="search__filter__itinerary__segment-item search__filter__itinerary__segment-item--start">
202
- <div className="search__filter__itinerary__transport-date">
203
- <p className="search__filter__itinerary__transport-date-date">
204
- <strong>{format(new Date(segment?.startDate || ''), 'd')}</strong>
205
- </p>
206
- <p>{format(new Date(segment?.startDate || ''), 'MMM')}</p>
207
- </div>
208
- <div className="search__filter__itinerary__segment-badge">
209
- <Icon name="ui-location" width={15} height={15} />
210
- </div>
211
- <div className="search__filter__itinerary__segment-details">
212
- <h6>
213
- {segment?.locationName}, {segment?.countryName}
214
- </h6>
215
- <p className="search__filter__itinerary__segment-details-text">
216
- {format(new Date(segment?.startDate || ''), 'EEE. d MMM yyyy')}
217
- &gt; {format(new Date(segment?.endDate || ''), 'EEE. d MMM yyyy')}
218
- </p>
219
- </div>
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>
267
+ </div>
268
+
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
+ &gt; {format(new Date(firstSegment.to), 'EEE. d MMM yyyy')}
291
+ </p>
220
292
  </div>
221
293
  </div>
222
- <div className="search__filter__itinerary__segment">
223
- <div className="search__filter__itinerary__segment-item">
224
- {segment.productType === 3 && (
225
- <div className="search__filter__itinerary__segment-date search__filter__itinerary__segment-nights">
294
+ </div>
295
+
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
+ <>
226
309
  <p className="search__filter__itinerary__segment-date-date">
227
- <strong>{numberOfNights(segment)}</strong>
310
+ <strong>{numberOfNights(firstSegment)}</strong>
228
311
  </p>
229
312
  <Icon name="ui-moon" width={16} height={16} />
230
- </div>
313
+ </>
231
314
  )}
232
- <div className="search__filter__itinerary__segment-badge search__filter__itinerary__segment-badge--secondary">
233
- {segment.productType === 3 && <Icon name="ui-bed" width={15} height={15} />}
234
- {segment.productType === 4 && <Icon name="ui-ticket" width={15} height={15} />}
235
- {(segment.productType === 17 || segment.productType === 22) && <Icon name="ui-car" width={15} height={15} />}
236
- {segment.productType === 11 && <Icon name="ui-ship" width={15} height={15} />}
237
- </div>
238
- <div className="search__filter__itinerary__segment-details">
239
- <h6>{segment?.productName}</h6>
240
- {/* <div className="rating">
241
- <Icon name="ui-star" key={`rating-star-1`} width={14} height={14} />
242
- <Icon name="ui-star" key={`rating-star-2`} width={14} height={14} />
243
- <Icon name="ui-star" key={`rating-star-3`} width={14} height={14} />
244
- <Icon name="ui-star" key={`rating-star-4`} width={14} height={14} />
245
- <Icon name="ui-star" key={`rating-star-5`} width={14} height={14} />
246
- </div> */}
247
- </div>
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}&nbsp;{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
+ ))}
248
341
  </div>
249
342
  </div>
250
343
  </div>
251
- ))}
344
+ </div>
252
345
  </div>
253
- )}
346
+ );
347
+ })}
254
348
 
255
- {returnFlight && (
256
- <div className="search__filter__itinerary__transport">
257
- <div className="search__filter__itinerary__transport-timeline">
258
- <div className="search__filter__itinerary__transport-timeline-line"></div>
259
- </div>
260
- <div className="search__filter__itinerary__transport-item">
261
- <div className="search__filter__itinerary__transport-date">
262
- <p className="search__filter__itinerary__transport-date-date">
263
- <strong>{format(new Date(returnFlight?.startDate || ''), 'd')}</strong>
264
- </p>
265
- <p>{format(new Date(returnFlight?.startDate || ''), 'MMM')}</p>
266
- </div>
267
- <div className="search__filter__itinerary__transport-badge">
268
- <Icon name="ui-plane" height={15} />
269
- </div>
270
- <div className="search__filter__itinerary__transport-details">
271
- <h6>{returnFlight?.productName}</h6>
272
- <p className="search__filter__itinerary__transport-details-plane">
273
- <span>
274
- <Icon name="ui-plane-depart" height={14} /> <strong>{getDepartureTime(returnFlight)}</strong>
275
- </span>{' '}
276
- -{' '}
277
- <span>
278
- <Icon name="ui-plane-arrive" height={14} /> <strong>{getArrivalTime(returnFlight)}</strong>
279
- </span>
280
- </p>
281
- <p className="search__filter__itinerary__transport-details-time">
282
- <span>
283
- <Icon name="ui-clock" height={20} /> {getDuration(returnFlight)}
284
- </span>
285
- </p>
286
- </div>
287
- </div>
349
+ {returnFlight && returnFlight !== outboundFlight && (
350
+ <div className="search__filter__itinerary__transport">
351
+ <div className="search__filter__itinerary__transport-timeline">
352
+ <div className="search__filter__itinerary__transport-timeline-line"></div>
353
+ </div>
354
+
355
+ <div className="search__filter__itinerary__transport-item">
356
+ <div className="search__filter__itinerary__transport-date">
357
+ <p className="search__filter__itinerary__transport-date-date">
358
+ <strong>{format(new Date(returnFlight.from), 'd')}</strong>
359
+ </p>
360
+ <p>{format(new Date(returnFlight.from), 'MMM')}</p>
288
361
  </div>
289
- )}
290
362
 
291
- <div className="search__filter__itinerary__country">
292
- <div className="search__filter__itinerary__country-icon">
293
- <Icon name="ui-flag" width={17.5} height={20} />
363
+ <div className="search__filter__itinerary__transport-badge">
364
+ <Icon name="ui-plane" height={15} />
294
365
  </div>
295
- <div className="search__filter__itinerary__country-content">
296
- <p>
297
- {format(new Date(lastEntryLine?.startDate || ''), 'EEE. d MMM yyyy')} - <strong>{translations.SRP.END}</strong>
366
+
367
+ <div className="search__filter__itinerary__transport-details">
368
+ <h6>{returnFlight.productName}</h6>
369
+ <p className="search__filter__itinerary__transport-details-plane">
370
+ <span>
371
+ <Icon name="ui-plane-depart" height={14} /> <strong>{getDepartureTime(returnFlight)}</strong>
372
+ </span>{' '}
373
+ -{' '}
374
+ <span>
375
+ <Icon name="ui-plane-arrive" height={14} /> <strong>{getArrivalTime(returnFlight)}</strong>
376
+ </span>
377
+ </p>
378
+ <p className="search__filter__itinerary__transport-details-time">
379
+ <span>
380
+ <Icon name="ui-clock" height={20} /> {getDuration(returnFlight)}
381
+ </span>
298
382
  </p>
299
383
  </div>
300
384
  </div>
301
385
  </div>
302
- </>
303
- )}
304
- </div>
386
+ )}
387
+
388
+ {lastEntryLine && (
389
+ <div className="search__filter__itinerary__country">
390
+ <div className="search__filter__itinerary__country-icon">
391
+ <Icon name="ui-flag" width={17.5} height={20} />
392
+ </div>
393
+ <div className="search__filter__itinerary__country-content">
394
+ <p>
395
+ {format(new Date(lastEntryLine.to), 'EEE. d MMM yyyy')} - <strong>{translations.SRP.END}</strong>
396
+ </p>
397
+ </div>
398
+ </div>
399
+ )}
400
+ </div>
401
+ </>
305
402
  </div>
306
- </>
403
+ </div>
307
404
  );
308
405
  };
309
406