@qite/tide-booking-component 1.4.33 → 1.4.34
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 +48 -43
- package/build/build-esm/index.js +48 -43
- package/package.json +77 -77
- package/src/booking-product/components/product.tsx +26 -22
- package/src/booking-wizard/features/booking/booking-self-contained.tsx +304 -304
- package/src/qsm/components/QSMContainer/qsm-container.tsx +215 -218
- package/src/qsm/store/qsm-slice.ts +261 -261
- package/src/qsm/types.ts +145 -145
- package/src/search-results/components/search-results-container/search-results-container.tsx +341 -337
|
@@ -1,218 +1,215 @@
|
|
|
1
|
-
import React, { useContext, useEffect, useMemo } from 'react';
|
|
2
|
-
import { useDispatch, useSelector } from 'react-redux';
|
|
3
|
-
import { QSMRootState } from '../../store/qsm-store';
|
|
4
|
-
import QSMConfigurationContext from '../../qsm-configuration-context';
|
|
5
|
-
import useMediaQuery from '../../../shared/utils/use-media-query-util';
|
|
6
|
-
import MobileFilterModal from '../mobile-filter-modal';
|
|
7
|
-
import SearchInputGroup from '../search-input-group';
|
|
8
|
-
import DoubleSearchInputGroup from '../double-search-input-group';
|
|
9
|
-
import Dates from '../../../booking-product/components/dates';
|
|
10
|
-
import TravelInputGroup from '../travel-input-group';
|
|
11
|
-
import TravelClassPicker from '../travel-class-picker';
|
|
12
|
-
import TravelTypePicker from '../travel-type-picker';
|
|
13
|
-
import Icon from '../icon';
|
|
14
|
-
import TravelNationalityPicker from '../travel-nationality-picker';
|
|
15
|
-
import { addDays, addMonths } from 'date-fns';
|
|
16
|
-
import { DateRange } from '../../../booking-product/types';
|
|
17
|
-
import { QSMState, setFromDate, setToDate } from '../../store/qsm-slice';
|
|
18
|
-
import { FieldConfig } from '../../types';
|
|
19
|
-
|
|
20
|
-
const QSMContainer: React.FC = () => {
|
|
21
|
-
const dispatch = useDispatch();
|
|
22
|
-
const isMobile = useMediaQuery('(max-width: 768px)');
|
|
23
|
-
const qsmState = useSelector((state: QSMRootState) => state.qsm);
|
|
24
|
-
const { mobileFilterType, fromDate, toDate } = qsmState;
|
|
25
|
-
const { searchFields, askTravelers, submitIcon, submitLabel, onSubmit } = useContext(QSMConfigurationContext);
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
if (fromDate || toDate) return;
|
|
29
|
-
|
|
30
|
-
const startDate = addMonths(new Date(), 1);
|
|
31
|
-
const endDate = addDays(startDate, 7);
|
|
32
|
-
|
|
33
|
-
dispatch(setFromDate(startDate.toISOString()));
|
|
34
|
-
dispatch(setToDate(endDate.toISOString()));
|
|
35
|
-
}, [fromDate, toDate, dispatch]);
|
|
36
|
-
|
|
37
|
-
const dateRange = useMemo<DateRange | undefined>(() => {
|
|
38
|
-
if (!fromDate || !toDate) return undefined;
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
fromDate: new Date(fromDate),
|
|
42
|
-
toDate: new Date(toDate)
|
|
43
|
-
};
|
|
44
|
-
}, [fromDate, toDate]);
|
|
45
|
-
|
|
46
|
-
const handleDateChange = (value: DateRange) => {
|
|
47
|
-
dispatch(setFromDate(value.fromDate?.toISOString()));
|
|
48
|
-
dispatch(setToDate(value.toDate?.toISOString()));
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const handleSubmit = () => {
|
|
52
|
-
if (!onSubmit) return;
|
|
53
|
-
|
|
54
|
-
const { fromDate, toDate, travelers, selectedTravelClass, selectedTravelType, selectedNationality, adults, kids, babies, rooms, selectedFlexRange } =
|
|
55
|
-
qsmState;
|
|
56
|
-
|
|
57
|
-
const
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
export default QSMContainer;
|
|
1
|
+
import React, { useContext, useEffect, useMemo } from 'react';
|
|
2
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
3
|
+
import { QSMRootState } from '../../store/qsm-store';
|
|
4
|
+
import QSMConfigurationContext from '../../qsm-configuration-context';
|
|
5
|
+
import useMediaQuery from '../../../shared/utils/use-media-query-util';
|
|
6
|
+
import MobileFilterModal from '../mobile-filter-modal';
|
|
7
|
+
import SearchInputGroup from '../search-input-group';
|
|
8
|
+
import DoubleSearchInputGroup from '../double-search-input-group';
|
|
9
|
+
import Dates from '../../../booking-product/components/dates';
|
|
10
|
+
import TravelInputGroup from '../travel-input-group';
|
|
11
|
+
import TravelClassPicker from '../travel-class-picker';
|
|
12
|
+
import TravelTypePicker from '../travel-type-picker';
|
|
13
|
+
import Icon from '../icon';
|
|
14
|
+
import TravelNationalityPicker from '../travel-nationality-picker';
|
|
15
|
+
import { addDays, addMonths } from 'date-fns';
|
|
16
|
+
import { DateRange } from '../../../booking-product/types';
|
|
17
|
+
import { QSMState, setFromDate, setToDate } from '../../store/qsm-slice';
|
|
18
|
+
import { FieldConfig } from '../../types';
|
|
19
|
+
|
|
20
|
+
const QSMContainer: React.FC = () => {
|
|
21
|
+
const dispatch = useDispatch();
|
|
22
|
+
const isMobile = useMediaQuery('(max-width: 768px)');
|
|
23
|
+
const qsmState = useSelector((state: QSMRootState) => state.qsm);
|
|
24
|
+
const { mobileFilterType, fromDate, toDate } = qsmState;
|
|
25
|
+
const { searchFields, askTravelers, submitIcon, submitLabel, onSubmit, travelTypes } = useContext(QSMConfigurationContext);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (fromDate || toDate) return;
|
|
29
|
+
|
|
30
|
+
const startDate = addMonths(new Date(), 1);
|
|
31
|
+
const endDate = addDays(startDate, 7);
|
|
32
|
+
|
|
33
|
+
dispatch(setFromDate(startDate.toISOString()));
|
|
34
|
+
dispatch(setToDate(endDate.toISOString()));
|
|
35
|
+
}, [fromDate, toDate, dispatch]);
|
|
36
|
+
|
|
37
|
+
const dateRange = useMemo<DateRange | undefined>(() => {
|
|
38
|
+
if (!fromDate || !toDate) return undefined;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
fromDate: new Date(fromDate),
|
|
42
|
+
toDate: new Date(toDate)
|
|
43
|
+
};
|
|
44
|
+
}, [fromDate, toDate]);
|
|
45
|
+
|
|
46
|
+
const handleDateChange = (value: DateRange) => {
|
|
47
|
+
dispatch(setFromDate(value.fromDate?.toISOString()));
|
|
48
|
+
dispatch(setToDate(value.toDate?.toISOString()));
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const handleSubmit = () => {
|
|
52
|
+
if (!onSubmit) return;
|
|
53
|
+
|
|
54
|
+
const { fromDate, toDate, travelers, selectedTravelClass, selectedTravelType, selectedNationality, adults, kids, babies, rooms, selectedFlexRange } =
|
|
55
|
+
qsmState;
|
|
56
|
+
|
|
57
|
+
const selectedTravelTypeValue = travelTypes.find((t) => t.label === selectedTravelType);
|
|
58
|
+
|
|
59
|
+
const payload = {
|
|
60
|
+
fromDate,
|
|
61
|
+
toDate,
|
|
62
|
+
travelClass: selectedTravelClass,
|
|
63
|
+
travelType: selectedTravelTypeValue,
|
|
64
|
+
nationality: selectedNationality,
|
|
65
|
+
rooms
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
addSearchFieldsToPayload(payload, searchFields, qsmState);
|
|
69
|
+
onSubmit(payload);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const addSearchFieldsToPayload = (payload: any, fields: FieldConfig[], state: QSMState) => {
|
|
73
|
+
fields.forEach((field) => {
|
|
74
|
+
if (field.type === 'single') {
|
|
75
|
+
const key = field.fieldKey;
|
|
76
|
+
const option = field.options.find((opt) => opt.value === state[key]);
|
|
77
|
+
payload[key] = option ?? state[key];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (field.type === 'double' && field.fields) {
|
|
81
|
+
// recursively add each nested field
|
|
82
|
+
field.fields.forEach((nestedField) => {
|
|
83
|
+
const key = nestedField.fieldKey;
|
|
84
|
+
const option = nestedField.options.find((opt) => opt.value === state[key]);
|
|
85
|
+
payload[key] = option ?? state[key];
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div className="qsm">
|
|
93
|
+
<div className="qsm__content">
|
|
94
|
+
<div className="qsm__tabs">
|
|
95
|
+
<button type="button" className="qsm__tab">
|
|
96
|
+
<span className="qsm__tab__icons">
|
|
97
|
+
<Icon name="ui-location" height={16} />
|
|
98
|
+
</span>
|
|
99
|
+
Multidestination
|
|
100
|
+
</button>
|
|
101
|
+
<button type="button" className="qsm__tab">
|
|
102
|
+
<span className="qsm__tab__icons">
|
|
103
|
+
<Icon name="ui-suitcase" height={16} />
|
|
104
|
+
</span>
|
|
105
|
+
Packages
|
|
106
|
+
</button>
|
|
107
|
+
<button type="button" className="qsm__tab qsm__tab--active">
|
|
108
|
+
<span className="qsm__tab__icons">
|
|
109
|
+
<Icon name="ui-backforward" height={14} />
|
|
110
|
+
+
|
|
111
|
+
<Icon name="ui-bed" height={14} />
|
|
112
|
+
</span>
|
|
113
|
+
Transport + hotel
|
|
114
|
+
</button>
|
|
115
|
+
<button type="button" className="qsm__tab">
|
|
116
|
+
<span className="qsm__tab__icons">
|
|
117
|
+
<Icon name="ui-bed" height={16} />
|
|
118
|
+
</span>
|
|
119
|
+
Accommodation
|
|
120
|
+
</button>
|
|
121
|
+
<button type="button" className="qsm__tab">
|
|
122
|
+
<span className="qsm__tab__icons">
|
|
123
|
+
<Icon name="ui-flight" height={16} />
|
|
124
|
+
</span>
|
|
125
|
+
Transports
|
|
126
|
+
</button>
|
|
127
|
+
<button type="button" className="qsm__tab">
|
|
128
|
+
<span className="qsm__tab__icons">
|
|
129
|
+
<Icon name="ui-ticket" height={16} />
|
|
130
|
+
</span>
|
|
131
|
+
Ticket Only
|
|
132
|
+
</button>
|
|
133
|
+
<button type="button" className="qsm__tab">
|
|
134
|
+
<span className="qsm__tab__icons">
|
|
135
|
+
<Icon name="ui-car" height={16} />
|
|
136
|
+
</span>
|
|
137
|
+
Rent a car
|
|
138
|
+
</button>
|
|
139
|
+
<button type="button" className="qsm__tab">
|
|
140
|
+
<span className="qsm__tab__icons">
|
|
141
|
+
<Icon name="ui-backforward" height={16} />
|
|
142
|
+
</span>
|
|
143
|
+
Transfers
|
|
144
|
+
</button>
|
|
145
|
+
<button type="button" className="qsm__tab">
|
|
146
|
+
<span className="qsm__tab__icons">
|
|
147
|
+
<Icon name="ui-ship" height={16} />
|
|
148
|
+
</span>
|
|
149
|
+
Cruises
|
|
150
|
+
</button>
|
|
151
|
+
</div>
|
|
152
|
+
<div className="qsm__filter">
|
|
153
|
+
<div className="radiobutton-group qsm__filter__inputgroup">
|
|
154
|
+
<div className="radiobutton">
|
|
155
|
+
<label className="radiobutton__label">
|
|
156
|
+
<input
|
|
157
|
+
type="radio"
|
|
158
|
+
name="mainBookerId"
|
|
159
|
+
// onChange={handleMainBookerChange}
|
|
160
|
+
// onBlur={formik.handleBlur}
|
|
161
|
+
value=""
|
|
162
|
+
// checked={formik.values.mainBookerId === travelerValues.id}
|
|
163
|
+
checked={true}
|
|
164
|
+
readOnly
|
|
165
|
+
className="radiobutton__input"
|
|
166
|
+
/>
|
|
167
|
+
<span>One accommodation</span>
|
|
168
|
+
</label>
|
|
169
|
+
</div>
|
|
170
|
+
<div className="radiobutton">
|
|
171
|
+
<label className="radiobutton__label">
|
|
172
|
+
<input
|
|
173
|
+
type="radio"
|
|
174
|
+
name="mainBookerId"
|
|
175
|
+
// onChange={handleMainBookerChange}
|
|
176
|
+
// onBlur={formik.handleBlur}
|
|
177
|
+
value=""
|
|
178
|
+
// checked={formik.values.mainBookerId === travelerValues.id}
|
|
179
|
+
className="radiobutton__input"
|
|
180
|
+
disabled={true}
|
|
181
|
+
/>
|
|
182
|
+
<span>Multiple accommodations</span>
|
|
183
|
+
</label>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
<div className="qsm__filter__classgroup">
|
|
187
|
+
<TravelClassPicker />
|
|
188
|
+
<TravelTypePicker />
|
|
189
|
+
<TravelNationalityPicker />
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
<div className="qsm__input-group">
|
|
193
|
+
{searchFields.map((field, idx) => {
|
|
194
|
+
if (field.type === 'double') {
|
|
195
|
+
return <DoubleSearchInputGroup key={idx} fieldKey={field.fieldKey} showReverse={field.showReverse} />;
|
|
196
|
+
}
|
|
197
|
+
return <SearchInputGroup key={idx} fieldKey={field.fieldKey} />;
|
|
198
|
+
})}
|
|
199
|
+
|
|
200
|
+
<Dates value={dateRange} onChange={handleDateChange} />
|
|
201
|
+
|
|
202
|
+
{askTravelers && <TravelInputGroup />}
|
|
203
|
+
|
|
204
|
+
<button type="button" className="cta" onClick={handleSubmit}>
|
|
205
|
+
{submitIcon && submitIcon.toString().length > 0 && <span>{submitIcon}</span>}
|
|
206
|
+
<span>{submitLabel}</span>
|
|
207
|
+
</button>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
{isMobile && mobileFilterType && <MobileFilterModal />}
|
|
211
|
+
</div>
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export default QSMContainer;
|