@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
|
@@ -1,304 +1,303 @@
|
|
|
1
|
-
import React, { useContext } from 'react';
|
|
2
|
-
import { useSelector } from 'react-redux';
|
|
3
|
-
import {
|
|
4
|
-
getDateFromParams,
|
|
5
|
-
getFlightsFromParams,
|
|
6
|
-
getNumberFromParams,
|
|
7
|
-
getNumbersFromParams,
|
|
8
|
-
getRoomsFromParams,
|
|
9
|
-
getStringFromParams
|
|
10
|
-
} from '../../../shared/utils/query-string-util';
|
|
11
|
-
import {
|
|
12
|
-
fetchPackage,
|
|
13
|
-
setAccommodationViewId,
|
|
14
|
-
setAgentAdressId,
|
|
15
|
-
setBookingAttributes,
|
|
16
|
-
setBookingNumber,
|
|
17
|
-
setBookingOptions,
|
|
18
|
-
setBookingType,
|
|
19
|
-
setCalculateDeposit,
|
|
20
|
-
setCurrentStep,
|
|
21
|
-
setGeneratePaymentUrl,
|
|
22
|
-
setLanguageCode,
|
|
23
|
-
setOfficeId,
|
|
24
|
-
setProductAttributes,
|
|
25
|
-
setSkipPayment,
|
|
26
|
-
setTagIds,
|
|
27
|
-
setTranslations
|
|
28
|
-
} from './booking-slice';
|
|
29
|
-
|
|
30
|
-
import { isNil } from 'lodash';
|
|
31
|
-
import { useEffect } from 'react';
|
|
32
|
-
import Loader from '../../../shared/components/loader';
|
|
33
|
-
import { setApiKey, setApiUrl } from '../../api-settings-slice';
|
|
34
|
-
import StepRoute from '../../components/step-route';
|
|
35
|
-
import SettingsContext from '../../settings-context';
|
|
36
|
-
import { useAppDispatch } from '../../store';
|
|
37
|
-
import Confirmation from '../confirmation/confirmation';
|
|
38
|
-
import Error from '../error/error';
|
|
39
|
-
import FlightOptionsForm from '../flight-options';
|
|
40
|
-
import OptionsForm from '../product-options/options-form';
|
|
41
|
-
import RoomOptionsForm from '../room-options';
|
|
42
|
-
import Sidebar from '../sidebar';
|
|
43
|
-
import Summary from '../summary/summary';
|
|
44
|
-
import TravelersForm from '../travelers-form/travelers-form';
|
|
45
|
-
import {
|
|
46
|
-
CONFIRMATION_STEP,
|
|
47
|
-
ERROR_STEP,
|
|
48
|
-
FLIGHT_OPTIONS_FORM_STEP,
|
|
49
|
-
OPTIONS_FORM_STEP,
|
|
50
|
-
ROOM_OPTIONS_FORM_STEP,
|
|
51
|
-
SUMMARY_STEP,
|
|
52
|
-
TRAVELERS_FORM_STEP
|
|
53
|
-
} from './constants';
|
|
54
|
-
import {
|
|
55
|
-
selectApiSettings,
|
|
56
|
-
selectBookingAttributes,
|
|
57
|
-
selectBookingNumber,
|
|
58
|
-
selectBookingRooms,
|
|
59
|
-
selectCurrentStep,
|
|
60
|
-
selectIsUnavailable,
|
|
61
|
-
selectPackageDetails,
|
|
62
|
-
selectProductAttributes,
|
|
63
|
-
selectTranslations
|
|
64
|
-
} from './selectors';
|
|
65
|
-
|
|
66
|
-
interface BookingProps {
|
|
67
|
-
productCode: string;
|
|
68
|
-
productName: string;
|
|
69
|
-
thumbnailUrl?: string;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const BookingSelfContained: React.FC<BookingProps> = ({ productCode, productName, thumbnailUrl }) => {
|
|
73
|
-
const {
|
|
74
|
-
officeId,
|
|
75
|
-
bookingOptions,
|
|
76
|
-
showSidebarDeposit,
|
|
77
|
-
includeFlights,
|
|
78
|
-
skipPaymentWithAgent,
|
|
79
|
-
generatePaymentUrl,
|
|
80
|
-
tagIds,
|
|
81
|
-
agentAdressId,
|
|
82
|
-
language,
|
|
83
|
-
apiUrl,
|
|
84
|
-
apiKey,
|
|
85
|
-
translationFiles,
|
|
86
|
-
roomOptions,
|
|
87
|
-
flightOptions,
|
|
88
|
-
accommodationViewId,
|
|
89
|
-
isOffer,
|
|
90
|
-
allowOption,
|
|
91
|
-
travellers
|
|
92
|
-
} = useContext(SettingsContext);
|
|
93
|
-
|
|
94
|
-
const dispatch = useAppDispatch();
|
|
95
|
-
|
|
96
|
-
const productAttributes = useSelector(selectProductAttributes);
|
|
97
|
-
const bookingAttributes = useSelector(selectBookingAttributes);
|
|
98
|
-
const rooms = useSelector(selectBookingRooms);
|
|
99
|
-
const bookingNumber = useSelector(selectBookingNumber);
|
|
100
|
-
const packageDetails = useSelector(selectPackageDetails);
|
|
101
|
-
const isUnvailable = useSelector(selectIsUnavailable);
|
|
102
|
-
const currentStep = useSelector(selectCurrentStep);
|
|
103
|
-
const apiSettings = useSelector(selectApiSettings);
|
|
104
|
-
const translations = useSelector(selectTranslations);
|
|
105
|
-
|
|
106
|
-
useEffect(() => {
|
|
107
|
-
dispatch(setSkipPayment(skipPaymentWithAgent ?? false));
|
|
108
|
-
dispatch(setGeneratePaymentUrl(generatePaymentUrl ?? false));
|
|
109
|
-
}, [skipPaymentWithAgent, generatePaymentUrl]);
|
|
110
|
-
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
if (!isNil(apiUrl) && !isNil(apiKey)) {
|
|
113
|
-
dispatch(setApiUrl(apiUrl));
|
|
114
|
-
dispatch(setApiKey(apiKey));
|
|
115
|
-
}
|
|
116
|
-
}, [apiUrl, apiKey]);
|
|
117
|
-
|
|
118
|
-
useEffect(() => {
|
|
119
|
-
const params = new URLSearchParams(location.search);
|
|
120
|
-
const startDate = getDateFromParams(params, 'startDate');
|
|
121
|
-
const endDate = getDateFromParams(params, 'endDate');
|
|
122
|
-
const catalogueId = getNumberFromParams(params, 'catalogueId') ?? getNumberFromParams(params, 'catalog');
|
|
123
|
-
const rooms = getRoomsFromParams(params, 'rooms');
|
|
124
|
-
const flight = getFlightsFromParams(params, 'flight');
|
|
125
|
-
const flightRouteId = getStringFromParams(params, 'flightRouteId');
|
|
126
|
-
const vendorConfigurationId = getNumberFromParams(params, 'vendorConfigurationId');
|
|
127
|
-
const allotmentName = getStringFromParams(params, 'allotmentName');
|
|
128
|
-
const allotmentIds = getNumbersFromParams(params, 'allotmentId');
|
|
129
|
-
const tourCode = getStringFromParams(params, 'tourCode');
|
|
130
|
-
const bookingNumber = params.get('bookingNr') ?? undefined;
|
|
131
|
-
|
|
132
|
-
if (typeof window !== 'undefined') {
|
|
133
|
-
window.scrollTo(0, 0);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (!isNil(bookingNumber)) {
|
|
137
|
-
dispatch(setBookingNumber(bookingNumber));
|
|
138
|
-
dispatch(setCurrentStep(CONFIRMATION_STEP));
|
|
139
|
-
} else if (travellers.travelersFirstStep) {
|
|
140
|
-
dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
|
|
141
|
-
} else if (!flightOptions.isHidden) {
|
|
142
|
-
dispatch(setCurrentStep(FLIGHT_OPTIONS_FORM_STEP));
|
|
143
|
-
} else if (!roomOptions.isHidden) {
|
|
144
|
-
dispatch(setCurrentStep(ROOM_OPTIONS_FORM_STEP));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (!isNil(startDate) && !isNil(endDate) && !isNil(catalogueId) && !isNil(rooms)) {
|
|
148
|
-
dispatch(
|
|
149
|
-
setBookingAttributes({
|
|
150
|
-
startDate,
|
|
151
|
-
endDate,
|
|
152
|
-
catalogueId,
|
|
153
|
-
rooms,
|
|
154
|
-
flight,
|
|
155
|
-
includeFlights,
|
|
156
|
-
allotmentName,
|
|
157
|
-
allotmentIds,
|
|
158
|
-
tourCode,
|
|
159
|
-
flightRouteId,
|
|
160
|
-
vendorConfigurationId
|
|
161
|
-
})
|
|
162
|
-
);
|
|
163
|
-
} else {
|
|
164
|
-
console.error('Failure when setting booking attributes', startDate, endDate, catalogueId, rooms);
|
|
165
|
-
}
|
|
166
|
-
}, [location.search, setBookingAttributes, setBookingNumber, includeFlights]);
|
|
167
|
-
|
|
168
|
-
useEffect(() => {
|
|
169
|
-
if (!isNil(productCode) && !isNil(productName)) {
|
|
170
|
-
dispatch(
|
|
171
|
-
setProductAttributes({
|
|
172
|
-
productCode,
|
|
173
|
-
productName
|
|
174
|
-
})
|
|
175
|
-
);
|
|
176
|
-
} else {
|
|
177
|
-
console.error('Failure when setting product attributes', productCode, productName);
|
|
178
|
-
}
|
|
179
|
-
}, [productCode, productName, setProductAttributes]);
|
|
180
|
-
|
|
181
|
-
const getTranslations = async () => {
|
|
182
|
-
const translations = translationFiles?.map((x) =>
|
|
183
|
-
fetch(x.path)
|
|
184
|
-
.then((y) => y.json())
|
|
185
|
-
.then((z) => ({ language: x.language, value: z }))
|
|
186
|
-
);
|
|
187
|
-
return translations && (await Promise.all(translations));
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
useEffect(() => {
|
|
191
|
-
const loadTranslations = async () => {
|
|
192
|
-
const translations = await getTranslations();
|
|
193
|
-
dispatch(setTranslations(translations)); // Now dispatch the resolved value
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
loadTranslations();
|
|
197
|
-
|
|
198
|
-
dispatch(setOfficeId(officeId));
|
|
199
|
-
dispatch(setLanguageCode(language));
|
|
200
|
-
dispatch(setBookingOptions(bookingOptions));
|
|
201
|
-
dispatch(setCalculateDeposit(showSidebarDeposit));
|
|
202
|
-
if (tagIds && tagIds.length > 0) {
|
|
203
|
-
dispatch(setTagIds(tagIds ?? undefined));
|
|
204
|
-
}
|
|
205
|
-
dispatch(setAgentAdressId(agentAdressId ?? undefined));
|
|
206
|
-
if (agentAdressId && agentAdressId != 0) {
|
|
207
|
-
dispatch(setBookingType('b2b'));
|
|
208
|
-
}
|
|
209
|
-
if (accommodationViewId && accommodationViewId != 0) {
|
|
210
|
-
dispatch(setAccommodationViewId(accommodationViewId));
|
|
211
|
-
}
|
|
212
|
-
}, [officeId, language, bookingOptions, showSidebarDeposit, setOfficeId, setLanguageCode, setCalculateDeposit, tagIds, agentAdressId, accommodationViewId]);
|
|
213
|
-
|
|
214
|
-
useEffect(() => {
|
|
215
|
-
if (!productAttributes || !bookingAttributes || !rooms?.length || !isNil(bookingNumber) || !isNil(packageDetails)) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Fetch data
|
|
220
|
-
const promise = dispatch(fetchPackage());
|
|
221
|
-
return () => {
|
|
222
|
-
promise.abort();
|
|
223
|
-
};
|
|
224
|
-
}, [productAttributes, bookingAttributes, rooms, bookingNumber, packageDetails, apiSettings.apiUrl, apiSettings.apiKey]);
|
|
225
|
-
|
|
226
|
-
const renderStep = () => {
|
|
227
|
-
switch (currentStep) {
|
|
228
|
-
case FLIGHT_OPTIONS_FORM_STEP:
|
|
229
|
-
return <StepRoute number={1} title={translations.STEPS.FLIGHT_OPTIONS} component={<FlightOptionsForm />} />;
|
|
230
|
-
case ROOM_OPTIONS_FORM_STEP:
|
|
231
|
-
return <StepRoute number={1 + (flightOptions.isHidden ? 0 : 1)} title={translations.STEPS.ROOM_OPTIONS} component={<RoomOptionsForm />} />;
|
|
232
|
-
case OPTIONS_FORM_STEP:
|
|
233
|
-
return (
|
|
234
|
-
<StepRoute
|
|
235
|
-
number={1 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)}
|
|
236
|
-
title={translations.STEPS.EXTRA_OPTIONS}
|
|
237
|
-
component={<OptionsForm />}
|
|
238
|
-
/>
|
|
239
|
-
);
|
|
240
|
-
case TRAVELERS_FORM_STEP:
|
|
241
|
-
return (
|
|
242
|
-
<StepRoute
|
|
243
|
-
number={2 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)}
|
|
244
|
-
title={translations.STEPS.PERSONAL_DETAILS}
|
|
245
|
-
component={<TravelersForm />}
|
|
246
|
-
/>
|
|
247
|
-
);
|
|
248
|
-
case SUMMARY_STEP:
|
|
249
|
-
return (
|
|
250
|
-
<StepRoute
|
|
251
|
-
number={3 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)}
|
|
252
|
-
title={translations.STEPS.SUMMARY}
|
|
253
|
-
component={<Summary />}
|
|
254
|
-
/>
|
|
255
|
-
);
|
|
256
|
-
case CONFIRMATION_STEP:
|
|
257
|
-
return (
|
|
258
|
-
<StepRoute
|
|
259
|
-
number={4 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)}
|
|
260
|
-
title={translations.STEPS.CONFIRMATION}
|
|
261
|
-
component={<Confirmation />}
|
|
262
|
-
/>
|
|
263
|
-
);
|
|
264
|
-
case ERROR_STEP:
|
|
265
|
-
return (
|
|
266
|
-
<StepRoute number={5 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)} title={translations.STEPS.ERROR} component={<Error />} />
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
return (
|
|
272
|
-
<>
|
|
273
|
-
{((productAttributes && bookingAttributes && packageDetails) || bookingNumber) && (
|
|
274
|
-
<div className="booking">
|
|
275
|
-
<div className="booking__content">
|
|
276
|
-
<div className="booking__panel">{renderStep()}</div>
|
|
277
|
-
<div className="backdrop" id="backdrop"></div>
|
|
278
|
-
{packageDetails && <Sidebar productName={productName} thumbnailUrl={thumbnailUrl} />}
|
|
279
|
-
</div>
|
|
280
|
-
</div>
|
|
281
|
-
)}
|
|
282
|
-
{!packageDetails && !bookingNumber && !isUnvailable && (
|
|
283
|
-
<div className="booking">
|
|
284
|
-
<div className="booking__loader">
|
|
285
|
-
<Loader />
|
|
286
|
-
<p className="booking__loader-text">
|
|
287
|
-
{allowOption ? translations.MAIN.PREPARING_DOSSIER : isOffer ? translations.MAIN.PREPARING_OFFER : translations.MAIN.PREPARING_BOOKING}
|
|
288
|
-
</p>
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
export default BookingSelfContained;
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
import { useSelector } from 'react-redux';
|
|
3
|
+
import {
|
|
4
|
+
getDateFromParams,
|
|
5
|
+
getFlightsFromParams,
|
|
6
|
+
getNumberFromParams,
|
|
7
|
+
getNumbersFromParams,
|
|
8
|
+
getRoomsFromParams,
|
|
9
|
+
getStringFromParams
|
|
10
|
+
} from '../../../shared/utils/query-string-util';
|
|
11
|
+
import {
|
|
12
|
+
fetchPackage,
|
|
13
|
+
setAccommodationViewId,
|
|
14
|
+
setAgentAdressId,
|
|
15
|
+
setBookingAttributes,
|
|
16
|
+
setBookingNumber,
|
|
17
|
+
setBookingOptions,
|
|
18
|
+
setBookingType,
|
|
19
|
+
setCalculateDeposit,
|
|
20
|
+
setCurrentStep,
|
|
21
|
+
setGeneratePaymentUrl,
|
|
22
|
+
setLanguageCode,
|
|
23
|
+
setOfficeId,
|
|
24
|
+
setProductAttributes,
|
|
25
|
+
setSkipPayment,
|
|
26
|
+
setTagIds,
|
|
27
|
+
setTranslations
|
|
28
|
+
} from './booking-slice';
|
|
29
|
+
|
|
30
|
+
import { isNil } from 'lodash';
|
|
31
|
+
import { useEffect } from 'react';
|
|
32
|
+
import Loader from '../../../shared/components/loader';
|
|
33
|
+
import { setApiKey, setApiUrl } from '../../api-settings-slice';
|
|
34
|
+
import StepRoute from '../../components/step-route';
|
|
35
|
+
import SettingsContext from '../../settings-context';
|
|
36
|
+
import { useAppDispatch } from '../../store';
|
|
37
|
+
import Confirmation from '../confirmation/confirmation';
|
|
38
|
+
import Error from '../error/error';
|
|
39
|
+
import FlightOptionsForm from '../flight-options';
|
|
40
|
+
import OptionsForm from '../product-options/options-form';
|
|
41
|
+
import RoomOptionsForm from '../room-options';
|
|
42
|
+
import Sidebar from '../sidebar';
|
|
43
|
+
import Summary from '../summary/summary';
|
|
44
|
+
import TravelersForm from '../travelers-form/travelers-form';
|
|
45
|
+
import {
|
|
46
|
+
CONFIRMATION_STEP,
|
|
47
|
+
ERROR_STEP,
|
|
48
|
+
FLIGHT_OPTIONS_FORM_STEP,
|
|
49
|
+
OPTIONS_FORM_STEP,
|
|
50
|
+
ROOM_OPTIONS_FORM_STEP,
|
|
51
|
+
SUMMARY_STEP,
|
|
52
|
+
TRAVELERS_FORM_STEP
|
|
53
|
+
} from './constants';
|
|
54
|
+
import {
|
|
55
|
+
selectApiSettings,
|
|
56
|
+
selectBookingAttributes,
|
|
57
|
+
selectBookingNumber,
|
|
58
|
+
selectBookingRooms,
|
|
59
|
+
selectCurrentStep,
|
|
60
|
+
selectIsUnavailable,
|
|
61
|
+
selectPackageDetails,
|
|
62
|
+
selectProductAttributes,
|
|
63
|
+
selectTranslations
|
|
64
|
+
} from './selectors';
|
|
65
|
+
|
|
66
|
+
interface BookingProps {
|
|
67
|
+
productCode: string;
|
|
68
|
+
productName: string;
|
|
69
|
+
thumbnailUrl?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const BookingSelfContained: React.FC<BookingProps> = ({ productCode, productName, thumbnailUrl }) => {
|
|
73
|
+
const {
|
|
74
|
+
officeId,
|
|
75
|
+
bookingOptions,
|
|
76
|
+
showSidebarDeposit,
|
|
77
|
+
includeFlights,
|
|
78
|
+
skipPaymentWithAgent,
|
|
79
|
+
generatePaymentUrl,
|
|
80
|
+
tagIds,
|
|
81
|
+
agentAdressId,
|
|
82
|
+
language,
|
|
83
|
+
apiUrl,
|
|
84
|
+
apiKey,
|
|
85
|
+
translationFiles,
|
|
86
|
+
roomOptions,
|
|
87
|
+
flightOptions,
|
|
88
|
+
accommodationViewId,
|
|
89
|
+
isOffer,
|
|
90
|
+
allowOption,
|
|
91
|
+
travellers
|
|
92
|
+
} = useContext(SettingsContext);
|
|
93
|
+
|
|
94
|
+
const dispatch = useAppDispatch();
|
|
95
|
+
|
|
96
|
+
const productAttributes = useSelector(selectProductAttributes);
|
|
97
|
+
const bookingAttributes = useSelector(selectBookingAttributes);
|
|
98
|
+
const rooms = useSelector(selectBookingRooms);
|
|
99
|
+
const bookingNumber = useSelector(selectBookingNumber);
|
|
100
|
+
const packageDetails = useSelector(selectPackageDetails);
|
|
101
|
+
const isUnvailable = useSelector(selectIsUnavailable);
|
|
102
|
+
const currentStep = useSelector(selectCurrentStep);
|
|
103
|
+
const apiSettings = useSelector(selectApiSettings);
|
|
104
|
+
const translations = useSelector(selectTranslations);
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
dispatch(setSkipPayment(skipPaymentWithAgent ?? false));
|
|
108
|
+
dispatch(setGeneratePaymentUrl(generatePaymentUrl ?? false));
|
|
109
|
+
}, [skipPaymentWithAgent, generatePaymentUrl]);
|
|
110
|
+
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (!isNil(apiUrl) && !isNil(apiKey)) {
|
|
113
|
+
dispatch(setApiUrl(apiUrl));
|
|
114
|
+
dispatch(setApiKey(apiKey));
|
|
115
|
+
}
|
|
116
|
+
}, [apiUrl, apiKey]);
|
|
117
|
+
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
const params = new URLSearchParams(location.search);
|
|
120
|
+
const startDate = getDateFromParams(params, 'startDate');
|
|
121
|
+
const endDate = getDateFromParams(params, 'endDate');
|
|
122
|
+
const catalogueId = getNumberFromParams(params, 'catalogueId') ?? getNumberFromParams(params, 'catalog');
|
|
123
|
+
const rooms = getRoomsFromParams(params, 'rooms');
|
|
124
|
+
const flight = getFlightsFromParams(params, 'flight');
|
|
125
|
+
const flightRouteId = getStringFromParams(params, 'flightRouteId');
|
|
126
|
+
const vendorConfigurationId = getNumberFromParams(params, 'vendorConfigurationId');
|
|
127
|
+
const allotmentName = getStringFromParams(params, 'allotmentName');
|
|
128
|
+
const allotmentIds = getNumbersFromParams(params, 'allotmentId');
|
|
129
|
+
const tourCode = getStringFromParams(params, 'tourCode');
|
|
130
|
+
const bookingNumber = params.get('bookingNr') ?? undefined;
|
|
131
|
+
|
|
132
|
+
if (typeof window !== 'undefined') {
|
|
133
|
+
window.scrollTo(0, 0);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!isNil(bookingNumber)) {
|
|
137
|
+
dispatch(setBookingNumber(bookingNumber));
|
|
138
|
+
dispatch(setCurrentStep(CONFIRMATION_STEP));
|
|
139
|
+
} else if (travellers.travelersFirstStep) {
|
|
140
|
+
dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
|
|
141
|
+
} else if (!flightOptions.isHidden) {
|
|
142
|
+
dispatch(setCurrentStep(FLIGHT_OPTIONS_FORM_STEP));
|
|
143
|
+
} else if (!roomOptions.isHidden) {
|
|
144
|
+
dispatch(setCurrentStep(ROOM_OPTIONS_FORM_STEP));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!isNil(startDate) && !isNil(endDate) && !isNil(catalogueId) && !isNil(rooms)) {
|
|
148
|
+
dispatch(
|
|
149
|
+
setBookingAttributes({
|
|
150
|
+
startDate,
|
|
151
|
+
endDate,
|
|
152
|
+
catalogueId,
|
|
153
|
+
rooms,
|
|
154
|
+
flight,
|
|
155
|
+
includeFlights,
|
|
156
|
+
allotmentName,
|
|
157
|
+
allotmentIds,
|
|
158
|
+
tourCode,
|
|
159
|
+
flightRouteId,
|
|
160
|
+
vendorConfigurationId
|
|
161
|
+
})
|
|
162
|
+
);
|
|
163
|
+
} else {
|
|
164
|
+
console.error('Failure when setting booking attributes', startDate, endDate, catalogueId, rooms);
|
|
165
|
+
}
|
|
166
|
+
}, [location.search, setBookingAttributes, setBookingNumber, includeFlights]);
|
|
167
|
+
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
if (!isNil(productCode) && !isNil(productName)) {
|
|
170
|
+
dispatch(
|
|
171
|
+
setProductAttributes({
|
|
172
|
+
productCode,
|
|
173
|
+
productName
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
console.error('Failure when setting product attributes', productCode, productName);
|
|
178
|
+
}
|
|
179
|
+
}, [productCode, productName, setProductAttributes]);
|
|
180
|
+
|
|
181
|
+
const getTranslations = async () => {
|
|
182
|
+
const translations = translationFiles?.map((x) =>
|
|
183
|
+
fetch(x.path)
|
|
184
|
+
.then((y) => y.json())
|
|
185
|
+
.then((z) => ({ language: x.language, value: z }))
|
|
186
|
+
);
|
|
187
|
+
return translations && (await Promise.all(translations));
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
const loadTranslations = async () => {
|
|
192
|
+
const translations = await getTranslations();
|
|
193
|
+
dispatch(setTranslations(translations)); // Now dispatch the resolved value
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
loadTranslations();
|
|
197
|
+
|
|
198
|
+
dispatch(setOfficeId(officeId));
|
|
199
|
+
dispatch(setLanguageCode(language));
|
|
200
|
+
dispatch(setBookingOptions(bookingOptions));
|
|
201
|
+
dispatch(setCalculateDeposit(showSidebarDeposit));
|
|
202
|
+
if (tagIds && tagIds.length > 0) {
|
|
203
|
+
dispatch(setTagIds(tagIds ?? undefined));
|
|
204
|
+
}
|
|
205
|
+
dispatch(setAgentAdressId(agentAdressId ?? undefined));
|
|
206
|
+
if (agentAdressId && agentAdressId != 0) {
|
|
207
|
+
dispatch(setBookingType('b2b'));
|
|
208
|
+
}
|
|
209
|
+
if (accommodationViewId && accommodationViewId != 0) {
|
|
210
|
+
dispatch(setAccommodationViewId(accommodationViewId));
|
|
211
|
+
}
|
|
212
|
+
}, [officeId, language, bookingOptions, showSidebarDeposit, setOfficeId, setLanguageCode, setCalculateDeposit, tagIds, agentAdressId, accommodationViewId]);
|
|
213
|
+
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
if (!productAttributes || !bookingAttributes || !rooms?.length || !isNil(bookingNumber) || !isNil(packageDetails)) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Fetch data
|
|
220
|
+
const promise = dispatch(fetchPackage());
|
|
221
|
+
return () => {
|
|
222
|
+
promise.abort();
|
|
223
|
+
};
|
|
224
|
+
}, [productAttributes, bookingAttributes, rooms, bookingNumber, packageDetails, apiSettings.apiUrl, apiSettings.apiKey]);
|
|
225
|
+
|
|
226
|
+
const renderStep = () => {
|
|
227
|
+
switch (currentStep) {
|
|
228
|
+
case FLIGHT_OPTIONS_FORM_STEP:
|
|
229
|
+
return <StepRoute number={1} title={translations.STEPS.FLIGHT_OPTIONS} component={<FlightOptionsForm />} />;
|
|
230
|
+
case ROOM_OPTIONS_FORM_STEP:
|
|
231
|
+
return <StepRoute number={1 + (flightOptions.isHidden ? 0 : 1)} title={translations.STEPS.ROOM_OPTIONS} component={<RoomOptionsForm />} />;
|
|
232
|
+
case OPTIONS_FORM_STEP:
|
|
233
|
+
return (
|
|
234
|
+
<StepRoute
|
|
235
|
+
number={1 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)}
|
|
236
|
+
title={translations.STEPS.EXTRA_OPTIONS}
|
|
237
|
+
component={<OptionsForm />}
|
|
238
|
+
/>
|
|
239
|
+
);
|
|
240
|
+
case TRAVELERS_FORM_STEP:
|
|
241
|
+
return (
|
|
242
|
+
<StepRoute
|
|
243
|
+
number={2 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)}
|
|
244
|
+
title={translations.STEPS.PERSONAL_DETAILS}
|
|
245
|
+
component={<TravelersForm />}
|
|
246
|
+
/>
|
|
247
|
+
);
|
|
248
|
+
case SUMMARY_STEP:
|
|
249
|
+
return (
|
|
250
|
+
<StepRoute
|
|
251
|
+
number={3 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)}
|
|
252
|
+
title={translations.STEPS.SUMMARY}
|
|
253
|
+
component={<Summary />}
|
|
254
|
+
/>
|
|
255
|
+
);
|
|
256
|
+
case CONFIRMATION_STEP:
|
|
257
|
+
return (
|
|
258
|
+
<StepRoute
|
|
259
|
+
number={4 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)}
|
|
260
|
+
title={translations.STEPS.CONFIRMATION}
|
|
261
|
+
component={<Confirmation />}
|
|
262
|
+
/>
|
|
263
|
+
);
|
|
264
|
+
case ERROR_STEP:
|
|
265
|
+
return (
|
|
266
|
+
<StepRoute number={5 + (roomOptions.isHidden ? 0 : 1) + (flightOptions.isHidden ? 0 : 1)} title={translations.STEPS.ERROR} component={<Error />} />
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
return (
|
|
272
|
+
<>
|
|
273
|
+
{((productAttributes && bookingAttributes && packageDetails) || bookingNumber) && (
|
|
274
|
+
<div className="booking">
|
|
275
|
+
<div className="booking__content">
|
|
276
|
+
<div className="booking__panel">{renderStep()}</div>
|
|
277
|
+
<div className="backdrop" id="backdrop"></div>
|
|
278
|
+
{packageDetails && <Sidebar productName={productName} thumbnailUrl={thumbnailUrl} />}
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
)}
|
|
282
|
+
{!packageDetails && !bookingNumber && !isUnvailable && (
|
|
283
|
+
<div className="booking">
|
|
284
|
+
<div className="booking__loader">
|
|
285
|
+
<Loader />
|
|
286
|
+
<p className="booking__loader-text">
|
|
287
|
+
{allowOption ? translations.MAIN.PREPARING_DOSSIER : isOffer ? translations.MAIN.PREPARING_OFFER : translations.MAIN.PREPARING_BOOKING}
|
|
288
|
+
</p>
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
)}
|
|
292
|
+
{isUnvailable && (
|
|
293
|
+
<div className="booking">
|
|
294
|
+
<div className="booking__loader">
|
|
295
|
+
<p className="booking__loader-text">{translations.MAIN.PRODUCT_UNAVAILABLE}</p>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
)}
|
|
299
|
+
</>
|
|
300
|
+
);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
export default BookingSelfContained;
|
|
@@ -6,7 +6,7 @@ import { ControlProps, hasVisibleError } from '../travelers-form-util';
|
|
|
6
6
|
const GenderControl: React.FC<ControlProps<Traveler>> = ({ translations, value, formik, name }) => {
|
|
7
7
|
return (
|
|
8
8
|
<div className={buildClassName(['form__group', hasVisibleError(formik, name) && 'form__group--error'])}>
|
|
9
|
-
<label className="form__label">{translations.TRAVELERS_FORM.
|
|
9
|
+
<label className="form__label">{translations.TRAVELERS_FORM.GENDER_ID} *</label>
|
|
10
10
|
<div className="radiobutton-group">
|
|
11
11
|
<div className="radiobutton">
|
|
12
12
|
<label className="radiobutton__label">
|
|
@@ -19,7 +19,7 @@ const GenderControl: React.FC<ControlProps<Traveler>> = ({ translations, value,
|
|
|
19
19
|
value="m"
|
|
20
20
|
checked={value.gender === 'm'}
|
|
21
21
|
/>
|
|
22
|
-
{translations.TRAVELERS_FORM.
|
|
22
|
+
{translations.TRAVELERS_FORM.MALE_GENDER}
|
|
23
23
|
</label>
|
|
24
24
|
</div>
|
|
25
25
|
|
|
@@ -34,11 +34,11 @@ const GenderControl: React.FC<ControlProps<Traveler>> = ({ translations, value,
|
|
|
34
34
|
value="f"
|
|
35
35
|
checked={value.gender === 'f'}
|
|
36
36
|
/>
|
|
37
|
-
{translations.TRAVELERS_FORM.
|
|
37
|
+
{translations.TRAVELERS_FORM.FEMALE_GENDER}
|
|
38
38
|
</label>
|
|
39
39
|
</div>
|
|
40
40
|
|
|
41
|
-
<div className="radiobutton">
|
|
41
|
+
{/* <div className="radiobutton">
|
|
42
42
|
<label className="radiobutton__label">
|
|
43
43
|
<input
|
|
44
44
|
type="radio"
|
|
@@ -51,7 +51,7 @@ const GenderControl: React.FC<ControlProps<Traveler>> = ({ translations, value,
|
|
|
51
51
|
/>
|
|
52
52
|
{translations.TRAVELERS_FORM.OTHER}
|
|
53
53
|
</label>
|
|
54
|
-
</div>
|
|
54
|
+
</div> */}
|
|
55
55
|
</div>
|
|
56
56
|
</div>
|
|
57
57
|
);
|