@qite/tide-booking-component 1.4.33 → 1.4.35
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 +1674 -416
- package/build/build-cjs/qsm/types.d.ts +0 -1
- package/build/build-cjs/search-results/components/filters/filters.d.ts +2 -2
- package/build/build-cjs/search-results/components/flight/flight-results.d.ts +2 -0
- package/build/build-cjs/search-results/components/hotel/hotel-card.d.ts +1 -0
- package/build/build-cjs/search-results/components/itinerary/index.d.ts +2 -2
- package/build/build-cjs/search-results/store/search-results-slice.d.ts +11 -2
- package/build/build-cjs/search-results/types.d.ts +0 -14
- package/build/build-esm/index.js +1674 -416
- package/build/build-esm/qsm/types.d.ts +0 -1
- package/build/build-esm/search-results/components/filters/filters.d.ts +2 -2
- package/build/build-esm/search-results/components/flight/flight-results.d.ts +2 -0
- package/build/build-esm/search-results/components/hotel/hotel-card.d.ts +1 -0
- package/build/build-esm/search-results/components/itinerary/index.d.ts +2 -2
- package/build/build-esm/search-results/store/search-results-slice.d.ts +11 -2
- package/build/build-esm/search-results/types.d.ts +0 -14
- package/package.json +77 -77
- package/src/booking-product/components/product.tsx +26 -22
- package/src/booking-wizard/features/booking/booking-self-contained.tsx +303 -304
- package/src/booking-wizard/features/travelers-form/controls/gender-control.tsx +5 -5
- package/src/booking-wizard/features/travelers-form/travelers-form.tsx +10 -10
- package/src/content/components/icon.tsx +1 -1
- package/src/content/features/content-page/content-page-self-contained.tsx +0 -1
- package/src/qsm/components/QSMContainer/qsm-container.tsx +217 -218
- package/src/qsm/components/mobile-filter-modal/index.tsx +12 -10
- package/src/qsm/components/travel-class-picker/index.tsx +5 -3
- package/src/qsm/components/travel-input/index.tsx +15 -12
- package/src/qsm/components/travel-input-group/index.tsx +14 -3
- package/src/qsm/components/travel-nationality-picker/index.tsx +5 -3
- package/src/qsm/components/travel-type-picker/index.tsx +5 -3
- package/src/qsm/qsm-configuration-context.ts +0 -1
- package/src/qsm/store/qsm-slice.ts +261 -261
- package/src/qsm/types.ts +144 -145
- package/src/search-results/components/filters/filters.tsx +15 -16
- package/src/search-results/components/flight/flight-results.tsx +168 -1099
- package/src/search-results/components/hotel/hotel-accommodation-results.tsx +21 -24
- package/src/search-results/components/hotel/hotel-card.tsx +4 -3
- package/src/search-results/components/icon.tsx +1 -1
- package/src/search-results/components/itinerary/index.tsx +229 -129
- package/src/search-results/components/round-trip/round-trip-results.tsx +1 -1
- package/src/search-results/components/search-results-container/search-results-container.tsx +353 -337
- package/src/search-results/components/spinner/spinner.tsx +3 -1
- package/src/search-results/components/tab-views/index.tsx +13 -7
- package/src/search-results/features/flights/flight-search-results-self-contained.tsx +1 -14
- package/src/search-results/features/hotels/hotel-search-results-self-contained.tsx +1 -14
- package/src/search-results/store/search-results-slice.ts +37 -3
- package/src/search-results/types.ts +0 -15
- package/src/shared/translations/ar-SA.json +70 -0
- package/src/shared/translations/da-DK.json +70 -0
- package/src/shared/translations/de-DE.json +70 -0
- package/src/shared/translations/en-GB.json +71 -1
- package/src/shared/translations/es-ES.json +70 -0
- package/src/shared/translations/fr-BE.json +71 -1
- package/src/shared/translations/fr-FR.json +70 -0
- package/src/shared/translations/is-IS.json +72 -2
- package/src/shared/translations/it-IT.json +70 -0
- package/src/shared/translations/ja-JP.json +72 -2
- package/src/shared/translations/nl-BE.json +70 -0
- package/src/shared/translations/nl-NL.json +70 -0
- package/src/shared/translations/no-NO.json +72 -2
- package/src/shared/translations/pl-PL.json +70 -0
- package/src/shared/translations/pt-PT.json +70 -0
- package/src/shared/translations/sv-SE.json +72 -2
- package/styles/components/_search.scss +7 -1
package/src/qsm/types.ts
CHANGED
|
@@ -1,145 +1,144 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
export interface QSMConfiguration {
|
|
4
|
-
// Type specification and dedicated parameters
|
|
5
|
-
type: 'hotel' | 'roundTrip' | 'flight';
|
|
6
|
-
askRooms?: boolean; // hotel || roundTrip
|
|
7
|
-
askTravelType?: boolean; // hotel || roundTrip
|
|
8
|
-
allowOpenJaw?: boolean; // flight
|
|
9
|
-
allowMultiCity?: boolean; // flight
|
|
10
|
-
askTravelClass?: boolean; // flight
|
|
11
|
-
allowOneWay?: boolean; // flight
|
|
12
|
-
additionalFilters?: AdditionalFilters; // flight
|
|
13
|
-
askTravelers: boolean;
|
|
14
|
-
|
|
15
|
-
// Fields (form)
|
|
16
|
-
searchFields: FieldConfig[];
|
|
17
|
-
|
|
18
|
-
// Origins and destinations
|
|
19
|
-
origins: Origin[];
|
|
20
|
-
originTypeAhead: boolean;
|
|
21
|
-
onOriginChange: (origin: string) => void;
|
|
22
|
-
destinations: Destination[];
|
|
23
|
-
destinationTypeAhead: boolean;
|
|
24
|
-
destinationIcon: ReactNode;
|
|
25
|
-
onDestinationChange: (destination: string) => void;
|
|
26
|
-
|
|
27
|
-
// Airports
|
|
28
|
-
airports: Airport[];
|
|
29
|
-
airportTypeAhead: boolean;
|
|
30
|
-
airportIcon: ReactNode;
|
|
31
|
-
onAirportChange: (airport: string) => void;
|
|
32
|
-
|
|
33
|
-
// Travel types
|
|
34
|
-
travelTypes: TravelType[];
|
|
35
|
-
travelTypeIcon: ReactNode;
|
|
36
|
-
|
|
37
|
-
// Travel classes
|
|
38
|
-
travelClasses: TravelClass[];
|
|
39
|
-
travelClassIcon: ReactNode;
|
|
40
|
-
|
|
41
|
-
// Date flexibility
|
|
42
|
-
dateFlexibility?: DateFlexibility[];
|
|
43
|
-
minDate?: Date;
|
|
44
|
-
maxDate?: Date;
|
|
45
|
-
showReturnDate: boolean;
|
|
46
|
-
datesIcon: ReactNode;
|
|
47
|
-
|
|
48
|
-
// Travelers
|
|
49
|
-
defaultTravelers?: number;
|
|
50
|
-
maxTravelers?: number;
|
|
51
|
-
maxChildAge?: number;
|
|
52
|
-
maxInfantAge?: number;
|
|
53
|
-
|
|
54
|
-
onSubmit: (data: any) => void;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface QSMConfiguration {
|
|
4
|
+
// Type specification and dedicated parameters
|
|
5
|
+
type: 'hotel' | 'roundTrip' | 'flight';
|
|
6
|
+
askRooms?: boolean; // hotel || roundTrip
|
|
7
|
+
askTravelType?: boolean; // hotel || roundTrip
|
|
8
|
+
allowOpenJaw?: boolean; // flight
|
|
9
|
+
allowMultiCity?: boolean; // flight
|
|
10
|
+
askTravelClass?: boolean; // flight
|
|
11
|
+
allowOneWay?: boolean; // flight
|
|
12
|
+
additionalFilters?: AdditionalFilters; // flight
|
|
13
|
+
askTravelers: boolean;
|
|
14
|
+
|
|
15
|
+
// Fields (form)
|
|
16
|
+
searchFields: FieldConfig[];
|
|
17
|
+
|
|
18
|
+
// Origins and destinations
|
|
19
|
+
origins: Origin[];
|
|
20
|
+
originTypeAhead: boolean;
|
|
21
|
+
onOriginChange: (origin: string) => void;
|
|
22
|
+
destinations: Destination[];
|
|
23
|
+
destinationTypeAhead: boolean;
|
|
24
|
+
destinationIcon: ReactNode;
|
|
25
|
+
onDestinationChange: (destination: string) => void;
|
|
26
|
+
|
|
27
|
+
// Airports
|
|
28
|
+
airports: Airport[];
|
|
29
|
+
airportTypeAhead: boolean;
|
|
30
|
+
airportIcon: ReactNode;
|
|
31
|
+
onAirportChange: (airport: string) => void;
|
|
32
|
+
|
|
33
|
+
// Travel types
|
|
34
|
+
travelTypes: TravelType[];
|
|
35
|
+
travelTypeIcon: ReactNode;
|
|
36
|
+
|
|
37
|
+
// Travel classes
|
|
38
|
+
travelClasses: TravelClass[];
|
|
39
|
+
travelClassIcon: ReactNode;
|
|
40
|
+
|
|
41
|
+
// Date flexibility
|
|
42
|
+
dateFlexibility?: DateFlexibility[];
|
|
43
|
+
minDate?: Date;
|
|
44
|
+
maxDate?: Date;
|
|
45
|
+
showReturnDate: boolean;
|
|
46
|
+
datesIcon: ReactNode;
|
|
47
|
+
|
|
48
|
+
// Travelers
|
|
49
|
+
defaultTravelers?: number;
|
|
50
|
+
maxTravelers?: number;
|
|
51
|
+
maxChildAge?: number;
|
|
52
|
+
maxInfantAge?: number;
|
|
53
|
+
|
|
54
|
+
onSubmit: (data: any) => void;
|
|
55
|
+
submitIcon: ReactNode;
|
|
56
|
+
|
|
57
|
+
nationalities: Nationality[];
|
|
58
|
+
languageCode?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface BaseFieldConfig {
|
|
62
|
+
fieldKey: string;
|
|
63
|
+
label: string;
|
|
64
|
+
placeholder: string;
|
|
65
|
+
options: TypeaheadOption[];
|
|
66
|
+
autoComplete?: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface TypeaheadOption {
|
|
70
|
+
key: string;
|
|
71
|
+
value: string;
|
|
72
|
+
iataCode?: string;
|
|
73
|
+
country?: string;
|
|
74
|
+
type: OptionType;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type OptionType = 'country' | 'region' | 'oord' | 'location' | 'airport' | 'hotel' | 'other';
|
|
78
|
+
|
|
79
|
+
export interface SingleFieldConfig extends BaseFieldConfig {
|
|
80
|
+
type: 'single';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface DoubleFieldConfig {
|
|
84
|
+
type: 'double';
|
|
85
|
+
fieldKey: string;
|
|
86
|
+
showReverse?: boolean;
|
|
87
|
+
fields: BaseFieldConfig[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type FieldConfig = SingleFieldConfig | DoubleFieldConfig;
|
|
91
|
+
|
|
92
|
+
export interface AdditionalFilters {
|
|
93
|
+
showDirectFlights: boolean;
|
|
94
|
+
includeLuggage: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface Origin {
|
|
98
|
+
key: string;
|
|
99
|
+
value: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface Destination {
|
|
103
|
+
key: string;
|
|
104
|
+
value: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface Airport {
|
|
108
|
+
key: string;
|
|
109
|
+
value: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface DateFlexibility {
|
|
113
|
+
name: string;
|
|
114
|
+
before: number;
|
|
115
|
+
after: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type MobileFilterType = 'search' | 'date' | 'traveler' | null;
|
|
119
|
+
|
|
120
|
+
export type TravelerType = 'adults' | 'kids' | 'babies';
|
|
121
|
+
|
|
122
|
+
export interface Room {
|
|
123
|
+
adults: number;
|
|
124
|
+
kids: number;
|
|
125
|
+
babies: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface TravelType {
|
|
129
|
+
id: number;
|
|
130
|
+
label: string;
|
|
131
|
+
icon?: ReactNode;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface TravelClass {
|
|
135
|
+
id: number;
|
|
136
|
+
label: string;
|
|
137
|
+
icon?: ReactNode;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface Nationality {
|
|
141
|
+
id: number;
|
|
142
|
+
label: string;
|
|
143
|
+
icon?: ReactNode;
|
|
144
|
+
}
|
|
@@ -6,11 +6,12 @@ import { resetFilters, setFilters } from '../../store/search-results-slice';
|
|
|
6
6
|
import { useDispatch } from 'react-redux';
|
|
7
7
|
import Spinner from '../spinner/spinner';
|
|
8
8
|
import Icon from '../icon';
|
|
9
|
+
import { getTranslations } from '../../../shared/utils/localization-util';
|
|
9
10
|
|
|
10
11
|
interface FiltersProps {
|
|
11
12
|
filters: Filter[];
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
isOpen: boolean;
|
|
14
|
+
handleSetIsOpen: () => void;
|
|
14
15
|
handleApplyFilters: () => void;
|
|
15
16
|
isLoading?: boolean;
|
|
16
17
|
}
|
|
@@ -88,8 +89,9 @@ const initialFilters: Filter[] = [
|
|
|
88
89
|
}
|
|
89
90
|
] as Filter[];
|
|
90
91
|
|
|
91
|
-
const Filters: React.FC<FiltersProps> = ({ filters,
|
|
92
|
+
const Filters: React.FC<FiltersProps> = ({ filters, isOpen, handleSetIsOpen, handleApplyFilters, isLoading }) => {
|
|
92
93
|
const context = useContext(SearchResultsConfigurationContext);
|
|
94
|
+
const translations = getTranslations(context?.languageCode ?? 'en-GB');
|
|
93
95
|
const [visibleFilters, setVisibleFilters] = useState<Record<string, boolean>>({});
|
|
94
96
|
const [pendingFilters, setPendingFilters] = useState<Filter[]>([]);
|
|
95
97
|
useEffect(() => {
|
|
@@ -175,8 +177,8 @@ const Filters: React.FC<FiltersProps> = ({ filters, isMobileFiltersOpen, handleS
|
|
|
175
177
|
context?.onFilterChange?.(pendingFilters);
|
|
176
178
|
handleApplyFilters();
|
|
177
179
|
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
+
if (isOpen) {
|
|
181
|
+
handleSetIsOpen();
|
|
180
182
|
}
|
|
181
183
|
};
|
|
182
184
|
|
|
@@ -204,22 +206,19 @@ const Filters: React.FC<FiltersProps> = ({ filters, isMobileFiltersOpen, handleS
|
|
|
204
206
|
{/* ---------------- Filters ---------------- */}
|
|
205
207
|
|
|
206
208
|
{/* ---------------- Filters desktop ---------------- */}
|
|
207
|
-
<div className={`search__filters--modal ${
|
|
208
|
-
<div className="search__filters--background" onClick={() =>
|
|
209
|
-
<button className="search__filters--close" onClick={() =>
|
|
209
|
+
<div className={`search__filters--modal ${isOpen ? 'is-open' : ''}`}>
|
|
210
|
+
<div className="search__filters--background" onClick={() => handleSetIsOpen()}></div>
|
|
211
|
+
<button className="search__filters--close" onClick={() => handleSetIsOpen()}>
|
|
210
212
|
<Icon name="ui-close" height={24} />
|
|
211
213
|
</button>
|
|
212
214
|
<div className="search__filters">
|
|
213
215
|
<div className="search__filter-row search__filter__header">
|
|
214
216
|
<div className="search__filter-row-flex-title">
|
|
215
|
-
<p className="search__filter-small-title">
|
|
216
|
-
{/* */}
|
|
217
|
-
Your trip summary
|
|
218
|
-
</p>
|
|
217
|
+
<p className="search__filter-small-title">{translations.SRP.FILTERS}</p>
|
|
219
218
|
</div>
|
|
220
219
|
{!isLoading && (
|
|
221
220
|
<a className="search__filter-reset" onClick={() => handleFullReset()}>
|
|
222
|
-
{
|
|
221
|
+
{translations.SRP.RESET}
|
|
223
222
|
</a>
|
|
224
223
|
)}
|
|
225
224
|
{/* <Icon name="ui-info" height={16} /> */}
|
|
@@ -366,13 +365,13 @@ const Filters: React.FC<FiltersProps> = ({ filters, isMobileFiltersOpen, handleS
|
|
|
366
365
|
className="cta--secondary "
|
|
367
366
|
onClick={() => {
|
|
368
367
|
handleResetPendingChanges();
|
|
369
|
-
|
|
368
|
+
handleSetIsOpen();
|
|
370
369
|
}}
|
|
371
370
|
disabled={isLoading}>
|
|
372
|
-
{
|
|
371
|
+
{translations.SRP.CANCEL}
|
|
373
372
|
</button>
|
|
374
373
|
<button className="cta" onClick={() => applyFilters()} disabled={isLoading}>
|
|
375
|
-
{
|
|
374
|
+
{translations.SRP.APPLY}
|
|
376
375
|
</button>
|
|
377
376
|
</div>
|
|
378
377
|
)}
|