@qite/tide-booking-component 1.4.104 → 1.4.106

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 (58) hide show
  1. package/build/build-cjs/index.js +1312 -187
  2. package/build/build-cjs/src/search-results/components/excursions/day-by-day-excursions.d.ts +4 -0
  3. package/build/build-cjs/src/search-results/components/excursions/excursion-details.d.ts +3 -0
  4. package/build/build-cjs/src/search-results/components/excursions/excursion-results.d.ts +8 -0
  5. package/build/build-cjs/src/search-results/store/search-results-selectors.d.ts +122 -0
  6. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +30 -2
  7. package/build/build-cjs/src/search-results/types.d.ts +27 -1
  8. package/build/build-cjs/src/search-results/utils/query-utils.d.ts +1 -0
  9. package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +2 -1
  10. package/build/build-cjs/src/shared/utils/localization-util.d.ts +3 -0
  11. package/build/build-cjs/src/shared/utils/tide-api-utils.d.ts +6 -0
  12. package/build/build-esm/index.js +1304 -187
  13. package/build/build-esm/src/search-results/components/excursions/day-by-day-excursions.d.ts +4 -0
  14. package/build/build-esm/src/search-results/components/excursions/excursion-details.d.ts +3 -0
  15. package/build/build-esm/src/search-results/components/excursions/excursion-results.d.ts +8 -0
  16. package/build/build-esm/src/search-results/store/search-results-selectors.d.ts +122 -0
  17. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +30 -2
  18. package/build/build-esm/src/search-results/types.d.ts +27 -1
  19. package/build/build-esm/src/search-results/utils/query-utils.d.ts +1 -0
  20. package/build/build-esm/src/shared/components/flyin/flyin.d.ts +2 -1
  21. package/build/build-esm/src/shared/utils/localization-util.d.ts +3 -0
  22. package/build/build-esm/src/shared/utils/tide-api-utils.d.ts +6 -0
  23. package/package.json +2 -2
  24. package/src/search-results/components/excursions/day-by-day-excursions.tsx +169 -0
  25. package/src/search-results/components/excursions/excursion-details.tsx +340 -0
  26. package/src/search-results/components/excursions/excursion-results.tsx +186 -0
  27. package/src/search-results/components/hotel/hotel-card.tsx +0 -3
  28. package/src/search-results/components/icon.tsx +1 -4
  29. package/src/search-results/components/itinerary/full-itinerary.tsx +161 -53
  30. package/src/search-results/components/itinerary/index.tsx +31 -7
  31. package/src/search-results/components/search-results-container/search-results-container.tsx +90 -28
  32. package/src/search-results/store/search-results-selectors.ts +11 -0
  33. package/src/search-results/store/search-results-slice.ts +46 -3
  34. package/src/search-results/types.ts +42 -1
  35. package/src/search-results/utils/query-utils.ts +1 -0
  36. package/src/shared/components/flyin/accommodation-flyin.tsx +4 -2
  37. package/src/shared/components/flyin/flights-flyin.tsx +3 -1
  38. package/src/shared/components/flyin/flyin.tsx +18 -6
  39. package/src/shared/components/flyin/group-tour-flyin.tsx +3 -1
  40. package/src/shared/translations/ar-SA.json +8 -2
  41. package/src/shared/translations/da-DK.json +8 -2
  42. package/src/shared/translations/de-DE.json +8 -2
  43. package/src/shared/translations/en-GB.json +8 -2
  44. package/src/shared/translations/es-ES.json +8 -2
  45. package/src/shared/translations/fr-BE.json +8 -2
  46. package/src/shared/translations/fr-FR.json +8 -2
  47. package/src/shared/translations/is-IS.json +8 -2
  48. package/src/shared/translations/it-IT.json +8 -2
  49. package/src/shared/translations/ja-JP.json +8 -2
  50. package/src/shared/translations/nl-BE.json +8 -2
  51. package/src/shared/translations/nl-NL.json +8 -2
  52. package/src/shared/translations/no-NO.json +8 -2
  53. package/src/shared/translations/pl-PL.json +8 -2
  54. package/src/shared/translations/pt-PT.json +8 -2
  55. package/src/shared/translations/sv-SE.json +8 -2
  56. package/src/shared/utils/localization-util.ts +14 -0
  57. package/src/shared/utils/tide-api-utils.ts +8 -0
  58. package/styles/components/_search.scss +11 -1
@@ -0,0 +1,340 @@
1
+ import React, { useContext, useMemo } from 'react';
2
+ import { useDispatch, useSelector } from 'react-redux';
3
+ import { first } from 'lodash';
4
+ import { SearchResultsRootState } from '../../store/search-results-store';
5
+ import { getTranslations } from '../../../shared/utils/localization-util';
6
+ import SearchResultsConfigurationContext from '../../search-results-configuration-context';
7
+ import { PackagingAccommodationResponse } from '@qite/tide-client';
8
+ import { confirmExcursionForDay, setFlyInIsOpen, setSelectedExcursionSearchResult } from '../../store/search-results-slice';
9
+ import { format, parseISO } from 'date-fns';
10
+
11
+ type ExcursionOption = PackagingAccommodationResponse['rooms'][number]['options'][number];
12
+
13
+ type GroupedExcursion = {
14
+ accommodationCode: string;
15
+ accommodationName: string;
16
+ options: ExcursionOption[];
17
+ };
18
+
19
+ const formatPrice = (price?: number, currencyCode?: string | null) => {
20
+ if (typeof price !== 'number') return '';
21
+
22
+ return new Intl.NumberFormat('nl-BE', {
23
+ style: 'currency',
24
+ currency: currencyCode ?? 'EUR'
25
+ }).format(price);
26
+ };
27
+
28
+ const getExcursionDayKey = (date: string | Date) => {
29
+ const parsed = typeof date === 'string' ? parseISO(date) : date;
30
+ return format(parsed, 'yyyy-MM-dd');
31
+ };
32
+
33
+ const getOptionPaxIds = (option: ExcursionOption): number[] => {
34
+ return Array.isArray(option.paxIds) ? Array.from(new Set(option.paxIds)).sort((a, b) => a - b) : [];
35
+ };
36
+
37
+ const optionAppliesToPax = (option: ExcursionOption, paxId: number) => {
38
+ return getOptionPaxIds(option).includes(paxId);
39
+ };
40
+
41
+ const optionAppliesToAllTravellers = (option: ExcursionOption, travellerCount: number) => {
42
+ const paxIds = getOptionPaxIds(option);
43
+ const expected = Array.from({ length: travellerCount }, (_, i) => i);
44
+
45
+ return paxIds.length === expected.length && paxIds.every((id, index) => id === expected[index]);
46
+ };
47
+
48
+ const groupOptionsByExcursion = (options: ExcursionOption[]): GroupedExcursion[] => {
49
+ const groupedMap = new Map<string, GroupedExcursion>();
50
+
51
+ options.forEach((option) => {
52
+ const key = option.accommodationCode;
53
+
54
+ if (!groupedMap.has(key)) {
55
+ groupedMap.set(key, {
56
+ accommodationCode: option.accommodationCode,
57
+ accommodationName: option.accommodationName,
58
+ options: []
59
+ });
60
+ }
61
+
62
+ groupedMap.get(key)!.options.push(option);
63
+ });
64
+
65
+ return Array.from(groupedMap.values());
66
+ };
67
+
68
+ const ExcursionDetails: React.FC = () => {
69
+ const context = useContext(SearchResultsConfigurationContext);
70
+ const dispatch = useDispatch();
71
+
72
+ const { selectedExcursionSearchResult, editablePackagingEntry, excursionSearchParams } = useSelector((state: SearchResultsRootState) => state.searchResults);
73
+
74
+ if (!context || !selectedExcursionSearchResult || !editablePackagingEntry || !excursionSearchParams?.date) {
75
+ return null;
76
+ }
77
+
78
+ const translations = getTranslations(context.languageCode ?? 'en-GB');
79
+ const travellerCount = editablePackagingEntry.pax.length;
80
+
81
+ const allOptions = useMemo(() => {
82
+ return selectedExcursionSearchResult.rooms.flatMap((room) => room.options ?? []);
83
+ }, [selectedExcursionSearchResult]);
84
+
85
+ const sharedOptions = useMemo(() => {
86
+ return allOptions.filter((option) => optionAppliesToAllTravellers(option, travellerCount));
87
+ }, [allOptions, travellerCount]);
88
+
89
+ const sharedExcursions = useMemo(() => {
90
+ return groupOptionsByExcursion(sharedOptions);
91
+ }, [sharedOptions]);
92
+
93
+ const paxGroups = useMemo(() => {
94
+ return editablePackagingEntry.pax.map((pax) => {
95
+ const paxOptions = allOptions.filter((option) => optionAppliesToPax(option, pax.id) && !optionAppliesToAllTravellers(option, travellerCount));
96
+
97
+ return {
98
+ pax,
99
+ paxId: pax.id,
100
+ excursions: groupOptionsByExcursion(paxOptions)
101
+ };
102
+ });
103
+ }, [editablePackagingEntry.pax, allOptions, travellerCount]);
104
+
105
+ const getSelectedSharedOption = () => {
106
+ return sharedOptions.find((option) => option.isSelected);
107
+ };
108
+
109
+ const getSelectedSharedOptionForExcursion = (accommodationCode: string) => {
110
+ return sharedOptions.find((option) => option.accommodationCode === accommodationCode && option.isSelected);
111
+ };
112
+
113
+ const getSelectedOptionForPax = (paxId: number) => {
114
+ return allOptions.find((option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerCount) && option.isSelected);
115
+ };
116
+
117
+ const getSelectedOptionForExcursion = (paxId: number, accommodationCode: string) => {
118
+ return allOptions.find(
119
+ (option) =>
120
+ optionAppliesToPax(option, paxId) &&
121
+ !optionAppliesToAllTravellers(option, travellerCount) &&
122
+ option.accommodationCode === accommodationCode &&
123
+ option.isSelected
124
+ );
125
+ };
126
+
127
+ const handlePick = (selectedGuid?: string, paxId?: number) => {
128
+ const updatedExcursionSearchResult: PackagingAccommodationResponse = {
129
+ ...selectedExcursionSearchResult,
130
+ rooms: selectedExcursionSearchResult.rooms.map((room) => ({
131
+ ...room,
132
+ options: room.options.map((option) => {
133
+ const isSharedOption = optionAppliesToAllTravellers(option, travellerCount);
134
+
135
+ if (paxId === undefined) {
136
+ if (!isSharedOption) {
137
+ return option;
138
+ }
139
+
140
+ return {
141
+ ...option,
142
+ isSelected: option.guid === selectedGuid
143
+ };
144
+ }
145
+
146
+ if (isSharedOption || !optionAppliesToPax(option, paxId)) {
147
+ return option;
148
+ }
149
+
150
+ return {
151
+ ...option,
152
+ isSelected: option.guid === selectedGuid
153
+ };
154
+ })
155
+ }))
156
+ };
157
+
158
+ dispatch(setSelectedExcursionSearchResult(updatedExcursionSearchResult));
159
+ };
160
+
161
+ const calculateTotalPrice = () => {
162
+ const selectedOptions = allOptions.filter((option) => option.isSelected);
163
+ const totalPrice = selectedOptions.reduce((total, option) => total + (option.price || 0), 0);
164
+
165
+ return formatPrice(totalPrice, selectedExcursionSearchResult.currencyCode);
166
+ };
167
+
168
+ const getSharedPriceDifference = (accommodationCode: string) => {
169
+ const currentSelectedShared = getSelectedSharedOption();
170
+
171
+ let targetPrice = 0;
172
+
173
+ const selectedOption = getSelectedSharedOptionForExcursion(accommodationCode);
174
+
175
+ if (selectedOption?.price) {
176
+ targetPrice = selectedOption.price;
177
+ } else {
178
+ const firstOption = sharedOptions.find((option) => option.accommodationCode === accommodationCode);
179
+ targetPrice = firstOption?.price || 0;
180
+ }
181
+
182
+ return targetPrice - (currentSelectedShared?.price || 0);
183
+ };
184
+
185
+ const getPriceDifference = (currentSelectedPrice: number | undefined, paxId: number, accommodationCode: string) => {
186
+ let targetPrice = 0;
187
+
188
+ const selectedOption = getSelectedOptionForExcursion(paxId, accommodationCode);
189
+
190
+ if (selectedOption?.price) {
191
+ targetPrice = selectedOption.price;
192
+ } else {
193
+ const firstOption = allOptions.find(
194
+ (option) => optionAppliesToPax(option, paxId) && !optionAppliesToAllTravellers(option, travellerCount) && option.accommodationCode === accommodationCode
195
+ );
196
+
197
+ targetPrice = firstOption?.price || 0;
198
+ }
199
+
200
+ return targetPrice - (currentSelectedPrice || 0);
201
+ };
202
+
203
+ const formatPriceDifference = (difference: number, currencyCode: string) => {
204
+ if (difference === 0) {
205
+ return null;
206
+ }
207
+
208
+ const formattedAbsoluteValue = formatPrice(Math.abs(difference), currencyCode);
209
+ return `${difference > 0 ? '+' : '-'} ${formattedAbsoluteValue}`;
210
+ };
211
+
212
+ const getPriceDifferenceClassName = (difference: number) => {
213
+ if (difference < 0) {
214
+ return 'flyin__acco__price flyin__acco__price--decrease';
215
+ }
216
+
217
+ if (difference > 0) {
218
+ return 'flyin__acco__price flyin__acco__price--increase';
219
+ }
220
+
221
+ return 'flyin__acco__price';
222
+ };
223
+
224
+ const handleConfirm = () => {
225
+ const dayKey = getExcursionDayKey(excursionSearchParams.date);
226
+
227
+ dispatch(
228
+ confirmExcursionForDay({
229
+ dayKey,
230
+ excursion: selectedExcursionSearchResult
231
+ })
232
+ );
233
+
234
+ dispatch(setFlyInIsOpen(false));
235
+ };
236
+
237
+ return (
238
+ <>
239
+ <div className="flyin__content">
240
+ {sharedExcursions.length > 0 && (
241
+ <div className="flyin__acco">
242
+ <h3 className="flyin__acco__room-title">{translations.QSM.ALL_TRAVELERS}</h3>
243
+
244
+ <div className="flyin__acco__cards">
245
+ {sharedExcursions.map((excursion) => {
246
+ const selectedOption = getSelectedSharedOptionForExcursion(excursion.accommodationCode);
247
+ const priceDifference = getSharedPriceDifference(excursion.accommodationCode);
248
+
249
+ return (
250
+ <div className="flyin__acco__card" key={`all-${excursion.accommodationCode}`}>
251
+ <div className="flyin__acco__content">
252
+ <h4 className="flyin__acco__title">{excursion.accommodationName}</h4>
253
+ </div>
254
+
255
+ <div className="flyin__acco__footer">
256
+ <div className="flyin__acco__footer__actions">
257
+ <button
258
+ className={selectedOption ? 'cta cta--select cta--selected' : 'cta cta--select'}
259
+ onClick={() => handlePick(selectedOption ? selectedOption.guid : first(excursion.options)?.guid)}>
260
+ {selectedOption ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT}
261
+ </button>
262
+
263
+ <div className="flyin__acco__price__wrapper">
264
+ <span className={getPriceDifferenceClassName(priceDifference)}>
265
+ {formatPriceDifference(priceDifference, selectedExcursionSearchResult.currencyCode)}
266
+ </span>
267
+ </div>
268
+ </div>
269
+ </div>
270
+ </div>
271
+ );
272
+ })}
273
+ </div>
274
+ </div>
275
+ )}
276
+
277
+ {paxGroups.map(({ pax, paxId, excursions }) => {
278
+ if (excursions.length === 0) {
279
+ return null;
280
+ }
281
+
282
+ const selectedPaxOption = getSelectedOptionForPax(paxId);
283
+
284
+ return (
285
+ <div className="flyin__acco" key={`pax-${pax.id}`}>
286
+ <h3 className="flyin__acco__room-title">
287
+ {translations.SUMMARY.TRAVELER} {pax.id + 1}
288
+ </h3>
289
+
290
+ <div className="flyin__acco__cards">
291
+ {excursions.map((excursion) => {
292
+ const selectedOption = getSelectedOptionForExcursion(paxId, excursion.accommodationCode);
293
+ const priceDifference = getPriceDifference(selectedPaxOption?.price, paxId, excursion.accommodationCode);
294
+
295
+ return (
296
+ <div className="flyin__acco__card" key={`${pax.id}-${excursion.accommodationCode}`}>
297
+ <div className="flyin__acco__content">
298
+ <h4 className="flyin__acco__title">{excursion.accommodationName}</h4>
299
+ </div>
300
+
301
+ <div className="flyin__acco__footer">
302
+ <div className="flyin__acco__footer__actions">
303
+ <button
304
+ className={
305
+ selectedPaxOption?.accommodationCode === excursion.accommodationCode ? 'cta cta--select cta--selected' : 'cta cta--select'
306
+ }
307
+ onClick={() => handlePick(selectedOption ? selectedOption.guid : first(excursion.options)?.guid, paxId)}>
308
+ {selectedPaxOption?.accommodationCode === excursion.accommodationCode ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT}
309
+ </button>
310
+
311
+ <div className="flyin__acco__price__wrapper">
312
+ <span className={getPriceDifferenceClassName(priceDifference)}>
313
+ {formatPriceDifference(priceDifference, selectedExcursionSearchResult.currencyCode)}
314
+ </span>
315
+ </div>
316
+ </div>
317
+ </div>
318
+ </div>
319
+ );
320
+ })}
321
+ </div>
322
+ </div>
323
+ );
324
+ })}
325
+ </div>
326
+
327
+ <div className="flyin__footer">
328
+ <div className="flyin__footer__price">
329
+ {translations.SHARED.TOTAL_PRICE}: {calculateTotalPrice()}
330
+ </div>
331
+
332
+ <button type="button" className="cta cta--primary" onClick={handleConfirm}>
333
+ {translations?.QSM.CONFIRM}
334
+ </button>
335
+ </div>
336
+ </>
337
+ );
338
+ };
339
+
340
+ export default ExcursionDetails;
@@ -0,0 +1,186 @@
1
+ import React, { useContext, useEffect, useState } from 'react';
2
+ import Spinner from '../spinner/spinner';
3
+ import { useDispatch, useSelector } from 'react-redux';
4
+ import { SearchResultsRootState } from '../../store/search-results-store';
5
+ import { getTranslations } from '../../../shared/utils/localization-util';
6
+ import SearchResultsConfigurationContext from '../../search-results-configuration-context';
7
+ import {
8
+ PackagingAccommodationRequest,
9
+ PackagingAccommodationResponse,
10
+ PackagingDestination,
11
+ searchPackagingExcursions,
12
+ TideClientConfig
13
+ } from '@qite/tide-client';
14
+ import { EXCURSION_SERVICE_TYPE } from '../../utils/query-utils';
15
+ import { SearchSeed } from '../../types';
16
+ import he from 'he';
17
+ import { setFlyInType, setSelectedExcursionSearchResult } from '../../store/search-results-slice';
18
+
19
+ interface ExcursionResultsProps {
20
+ isFlyIn?: boolean;
21
+ activeSearchSeed?: SearchSeed | null;
22
+ }
23
+
24
+ const ExcursionResults: React.FC<ExcursionResultsProps> = ({ isFlyIn, activeSearchSeed }) => {
25
+ const context = useContext(SearchResultsConfigurationContext);
26
+ const dispatch = useDispatch();
27
+ const [isLoading, setIsLoading] = useState(false);
28
+ const [excursions, setExcursions] = useState<PackagingAccommodationResponse[] | null>(null);
29
+
30
+ const { flyInIsOpen, flyInType, excursionSearchParams, transactionId } = useSelector((state: SearchResultsRootState) => state.searchResults);
31
+
32
+ useEffect(() => {
33
+ if (!context || !activeSearchSeed || !excursionSearchParams) return;
34
+
35
+ (async () => {
36
+ try {
37
+ setIsLoading(true);
38
+ console.log('Excursion search params changed, fetching excursions...', excursionSearchParams);
39
+
40
+ const config: TideClientConfig = {
41
+ host: context.tideConnection.host,
42
+ apiKey: context.tideConnection.apiKey
43
+ };
44
+
45
+ const destination = excursionSearchParams.locationId
46
+ ? { id: Number(excursionSearchParams.locationId), type: 'location' }
47
+ : excursionSearchParams.oordId
48
+ ? { id: Number(excursionSearchParams.oordId), type: 'oord' }
49
+ : excursionSearchParams.regionId
50
+ ? { id: Number(excursionSearchParams.regionId), type: 'region' }
51
+ : excursionSearchParams.countryId
52
+ ? { id: Number(excursionSearchParams.countryId), type: 'country' }
53
+ : { id: 0, type: null };
54
+
55
+ const allPax = activeSearchSeed.rooms.flatMap((room) => room.pax);
56
+
57
+ const searchRequest: PackagingAccommodationRequest = {
58
+ transactionId: transactionId ?? '',
59
+ officeId: context.tideConnection.officeId ?? 1,
60
+ agentId: context.agentId ?? null,
61
+ portalId: context.portalId ?? null,
62
+ catalogueId: context.searchConfiguration.defaultCatalogueId ?? 0,
63
+ searchConfigurationId: context.searchConfiguration.id,
64
+ language: context.languageCode ?? 'en-GB',
65
+ serviceType: EXCURSION_SERVICE_TYPE,
66
+ fromDate: excursionSearchParams.fromDate,
67
+ toDate: excursionSearchParams.toDate,
68
+ destination: {
69
+ id: destination.id,
70
+ isCountry: destination.type === 'country',
71
+ isRegion: destination.type === 'region',
72
+ isOord: destination.type === 'oord',
73
+ isLocation: destination.type === 'location',
74
+ isAirport: false,
75
+ code: ''
76
+ } as PackagingDestination,
77
+ productCode: '',
78
+ // rooms: activeSearchSeed.rooms.map((room) => ({
79
+ // travellers: room.pax.map((pax) => ({
80
+ // id: pax.id,
81
+ // age: pax.age,
82
+ // dateOfBirth: pax.dateOfBirth
83
+ // }))
84
+ // })),
85
+ rooms: [
86
+ {
87
+ travellers: allPax.map((pax) => ({
88
+ id: pax.id,
89
+ age: pax.age,
90
+ dateOfBirth: pax.dateOfBirth
91
+ }))
92
+ }
93
+ ],
94
+ tagIds: []
95
+ };
96
+
97
+ const packageExcursionSearchResults = await searchPackagingExcursions(config, searchRequest);
98
+ console.log('Excursion search results', packageExcursionSearchResults);
99
+ setExcursions(packageExcursionSearchResults);
100
+ } catch (err) {
101
+ console.error('Excursion search failed', err);
102
+ } finally {
103
+ setIsLoading(false);
104
+ }
105
+ })();
106
+ }, [context, activeSearchSeed, excursionSearchParams, transactionId]);
107
+
108
+ if (!context || !activeSearchSeed) {
109
+ return null;
110
+ }
111
+
112
+ if (!flyInIsOpen || flyInType !== 'excursion-results') {
113
+ return null;
114
+ }
115
+
116
+ const translations = getTranslations(context.languageCode ?? 'en-GB');
117
+
118
+ const handleChange = (excursion: PackagingAccommodationResponse): void => {
119
+ console.log('Selected excursion', excursion);
120
+ dispatch(setFlyInType('excursion-details'));
121
+ dispatch(setSelectedExcursionSearchResult(excursion));
122
+ };
123
+
124
+ return isLoading ? (
125
+ <Spinner />
126
+ ) : (
127
+ <div className="flyin__content flyin__content--columns">
128
+ {/* <Filters
129
+ initialFilters={initialFilters}
130
+ filters={filters}
131
+ isOpen={false}
132
+ handleSetIsOpen={() => { }}
133
+ // handleApplyFilters={() => setSearchTrigger((prev) => prev + 1)}
134
+ isLoading={isLoading}
135
+ setFilters={(filters) => dispatch(setFilters(filters))}
136
+ resetFilters={(filters) => dispatch(resetFilters(filters))}
137
+ /> */}
138
+ <div className="search__results__wrapper">
139
+ <div className="search__result-row">
140
+ <span className="search__result-row-text">
141
+ {!isLoading && (
142
+ <>
143
+ {excursions?.length && excursions.length}
144
+ &nbsp;{translations.SRP.TOTAL_RESULTS_LABEL}
145
+ </>
146
+ )}
147
+ </span>
148
+ {/* {sortByTypes && sortByTypes.length > 0 && (
149
+ <div className="search__result-row-filter">
150
+ <ItemPicker
151
+ items={sortByTypes}
152
+ selection={selectedSortType?.label || undefined}
153
+ selectedSortByType={selectedSortType}
154
+ label={translations.SRP.SORTBY}
155
+ placeholder={translations.SRP.SORTBY}
156
+ classModifier="travel-class-picker__items"
157
+ valueFormatter={(value, direction) => getSortingName(translations, findSortByType(sortByTypes, value, direction ?? 'asc'))}
158
+ onPick={(newSortKey, direction) => handleSortChange(newSortKey, direction)}
159
+ />
160
+ </div>
161
+ )} */}
162
+ </div>
163
+ <div className="search__results__cards search__results__cards--compact">
164
+ {excursions &&
165
+ excursions.length > 0 &&
166
+ excursions.map((excursion) => (
167
+ <div
168
+ key={excursion.code}
169
+ className="search__result-card__wrapper search__result-card__wrapper--custom"
170
+ onMouseEnter={(e) => (e.currentTarget.style.transform = 'scale(1.02)')}
171
+ onMouseLeave={(e) => (e.currentTarget.style.transform = 'scale(1)')}>
172
+ {excursion.contents ? <div dangerouslySetInnerHTML={{ __html: he.decode(excursion.contents) }}></div> : 'no contents'}
173
+ <div className="search__result-card__footer">
174
+ <button type="button" className="cta cta--select" onClick={() => handleChange(excursion)}>
175
+ {translations?.SHARED.SELECT}
176
+ </button>
177
+ </div>
178
+ </div>
179
+ ))}
180
+ </div>
181
+ </div>
182
+ </div>
183
+ );
184
+ };
185
+
186
+ export default ExcursionResults;
@@ -34,9 +34,6 @@ const HotelCard: React.FC<HotelCardProps> = ({ result, translations }) => {
34
34
  onClick={() => handleChange(result.code)}>
35
35
  {selectedPackagingAccoResultCode === result.code ? translations?.SHARED.SELECTED : translations?.SHARED.SELECT}
36
36
  </button>
37
- {/* <button type="button" className="cta cta--select" onClick={() => console.log('Clicked on customCard with id:', result.id)}>
38
- {translations?.SRP.VIEW_DETAILS}
39
- </button> */}
40
37
  </div>
41
38
  </div>
42
39
  );
@@ -315,10 +315,7 @@ const Icon: React.FC<IconProps> = ({ name, className, title, width, height, fill
315
315
  fill={fill ?? 'currentColor'}>
316
316
  <HTMLComment text="!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc." />
317
317
  {title && <title>{title}</title>}
318
- <path
319
- d="M64 64C28.7 64 0 92.7 0 128l0 64C0 200.8 7.4 207.7 15.7 210.6 34.5 217.1 48 235 48 256s-13.5 38.9-32.3 45.4C7.4 304.3 0 311.2 0 320l0 64c0 35.3 28.7 64 64 64l448 0c35.3 0 64-28.7 64-64l0-64c0-8.8-7.4-15.7-15.7-18.6-18.8-6.5-32.3-24.4-32.3-45.4s13.5-38.9 32.3-45.4c8.3-2.9 15.7-9.8 15.7-18.6l0-64c0-35.3-28.7-64-64-64L64 64zM416 336l0-160-256 0 0 160 256 0zM112 160c0-17.7 14.3-32 32-32l288 0c17.7 0 32 14.3 32 32l0 192c0 17.7-14.3 32-32 32l-288 0c-17.7 0-32-14.3-32-32l0-192z"
320
- fill="currentColor"
321
- />
318
+ <path d="M64 64C28.7 64 0 92.7 0 128l0 64C0 200.8 7.4 207.7 15.7 210.6 34.5 217.1 48 235 48 256s-13.5 38.9-32.3 45.4C7.4 304.3 0 311.2 0 320l0 64c0 35.3 28.7 64 64 64l448 0c35.3 0 64-28.7 64-64l0-64c0-8.8-7.4-15.7-15.7-18.6-18.8-6.5-32.3-24.4-32.3-45.4s13.5-38.9 32.3-45.4c8.3-2.9 15.7-9.8 15.7-18.6l0-64c0-35.3-28.7-64-64-64L64 64zM416 336l0-160-256 0 0 160 256 0zM112 160c0-17.7 14.3-32 32-32l288 0c17.7 0 32 14.3 32 32l0 192c0 17.7-14.3 32-32 32l-288 0c-17.7 0-32-14.3-32-32l0-192z" />
322
319
  </svg>
323
320
  );
324
321