@qite/tide-booking-component 1.4.109 → 1.4.111

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 (106) hide show
  1. package/build/build-cjs/index.js +3613 -2276
  2. package/build/build-cjs/src/booking-wizard/components/step-route.d.ts +2 -2
  3. package/build/build-cjs/src/booking-wizard/features/sidebar/sidebar-flight.d.ts +1 -0
  4. package/build/build-cjs/src/booking-wizard/features/sidebar/sidebar-util.d.ts +2 -1
  5. package/build/build-cjs/src/booking-wizard/features/sidebar/sidebar.d.ts +0 -31
  6. package/build/build-cjs/src/booking-wizard/features/travelers-form/travelers-form.d.ts +1 -2
  7. package/build/build-cjs/src/search-results/components/book-packaging-entry/index.d.ts +8 -0
  8. package/build/build-cjs/src/search-results/components/book-packaging-entry/wl-sidebar.d.ts +7 -0
  9. package/build/build-cjs/src/search-results/components/spinner/spinner.d.ts +4 -1
  10. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +7 -1
  11. package/build/build-cjs/src/search-results/types.d.ts +3 -0
  12. package/build/build-cjs/src/shared/booking/booking-panel.d.ts +13 -0
  13. package/build/build-cjs/src/shared/booking/shared-confirmation.d.ts +25 -0
  14. package/build/build-cjs/src/shared/booking/shared-sidebar.d.ts +34 -0
  15. package/build/build-cjs/src/shared/booking/step-indicators.d.ts +7 -0
  16. package/build/build-cjs/src/shared/booking/summary.d.ts +43 -0
  17. package/build/build-cjs/src/shared/booking/travelers-form.d.ts +93 -0
  18. package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +2 -0
  19. package/build/build-cjs/src/shared/components/flyin/packaging-flights-flyin.d.ts +2 -0
  20. package/build/build-cjs/src/shared/utils/booking-summary.d.ts +1 -0
  21. package/build/build-cjs/src/shared/utils/localization-util.d.ts +7 -0
  22. package/build/build-esm/index.js +3572 -2247
  23. package/build/build-esm/src/booking-wizard/components/step-route.d.ts +2 -2
  24. package/build/build-esm/src/booking-wizard/features/sidebar/sidebar-flight.d.ts +1 -0
  25. package/build/build-esm/src/booking-wizard/features/sidebar/sidebar-util.d.ts +2 -1
  26. package/build/build-esm/src/booking-wizard/features/sidebar/sidebar.d.ts +0 -31
  27. package/build/build-esm/src/booking-wizard/features/travelers-form/travelers-form.d.ts +1 -2
  28. package/build/build-esm/src/search-results/components/book-packaging-entry/index.d.ts +8 -0
  29. package/build/build-esm/src/search-results/components/book-packaging-entry/wl-sidebar.d.ts +7 -0
  30. package/build/build-esm/src/search-results/components/spinner/spinner.d.ts +4 -1
  31. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +7 -1
  32. package/build/build-esm/src/search-results/types.d.ts +3 -0
  33. package/build/build-esm/src/shared/booking/booking-panel.d.ts +13 -0
  34. package/build/build-esm/src/shared/booking/shared-confirmation.d.ts +25 -0
  35. package/build/build-esm/src/shared/booking/shared-sidebar.d.ts +34 -0
  36. package/build/build-esm/src/shared/booking/step-indicators.d.ts +7 -0
  37. package/build/build-esm/src/shared/booking/summary.d.ts +43 -0
  38. package/build/build-esm/src/shared/booking/travelers-form.d.ts +93 -0
  39. package/build/build-esm/src/shared/components/flyin/flyin.d.ts +2 -0
  40. package/build/build-esm/src/shared/components/flyin/packaging-flights-flyin.d.ts +2 -0
  41. package/build/build-esm/src/shared/utils/booking-summary.d.ts +1 -0
  42. package/build/build-esm/src/shared/utils/localization-util.d.ts +7 -0
  43. package/package.json +2 -2
  44. package/src/booking-wizard/components/step-indicator.tsx +10 -31
  45. package/src/booking-wizard/components/step-route.tsx +39 -14
  46. package/src/booking-wizard/features/confirmation/confirmation.tsx +11 -55
  47. package/src/booking-wizard/features/sidebar/index.tsx +10 -4
  48. package/src/booking-wizard/features/sidebar/sidebar-flight.tsx +2 -2
  49. package/src/booking-wizard/features/sidebar/sidebar-util.ts +1 -5
  50. package/src/booking-wizard/features/sidebar/sidebar.tsx +331 -326
  51. package/src/booking-wizard/features/summary/summary.tsx +1 -1
  52. package/src/booking-wizard/features/travelers-form/travelers-form.tsx +84 -1010
  53. package/src/search-results/components/book-packaging-entry/index.tsx +229 -0
  54. package/src/search-results/components/book-packaging-entry/wl-sidebar.tsx +162 -0
  55. package/src/search-results/components/excursions/day-by-day-excursions.tsx +6 -2
  56. package/src/search-results/components/excursions/excursion-results.tsx +1 -1
  57. package/src/search-results/components/flight/flight-selection/independent-flight-selection.tsx +12 -3
  58. package/src/search-results/components/group-tour/group-tour-card.tsx +1 -1
  59. package/src/search-results/components/group-tour/group-tour-results.tsx +1 -1
  60. package/src/search-results/components/hotel/hotel-accommodation-results.tsx +6 -3
  61. package/src/search-results/components/itinerary/full-itinerary.tsx +1 -1
  62. package/src/search-results/components/itinerary/index.tsx +13 -12
  63. package/src/search-results/components/search-results-container/flight-search-results.tsx +1 -1
  64. package/src/search-results/components/search-results-container/search-results-container.tsx +280 -217
  65. package/src/search-results/components/spinner/spinner.tsx +12 -4
  66. package/src/search-results/store/search-results-slice.ts +22 -2
  67. package/src/search-results/types.ts +4 -0
  68. package/src/shared/booking/booking-panel.tsx +25 -0
  69. package/src/shared/booking/shared-confirmation.tsx +105 -0
  70. package/src/shared/booking/shared-sidebar.tsx +432 -0
  71. package/src/shared/booking/step-indicators.tsx +30 -0
  72. package/src/shared/booking/summary.tsx +380 -0
  73. package/src/shared/booking/travelers-form.tsx +870 -0
  74. package/src/shared/components/flyin/accommodation-flyin.tsx +3 -4
  75. package/src/shared/components/flyin/flights-flyin.tsx +1 -1
  76. package/src/shared/components/flyin/flyin.tsx +16 -9
  77. package/src/shared/components/flyin/group-tour-flyin.tsx +3 -4
  78. package/src/shared/components/flyin/packaging-flights-flyin.tsx +11 -4
  79. package/src/shared/components/icon.tsx +13 -0
  80. package/src/shared/translations/ar-SA.json +7 -1
  81. package/src/shared/translations/da-DK.json +7 -1
  82. package/src/shared/translations/de-DE.json +7 -1
  83. package/src/shared/translations/en-GB.json +8 -2
  84. package/src/shared/translations/es-ES.json +7 -1
  85. package/src/shared/translations/fr-BE.json +7 -1
  86. package/src/shared/translations/fr-FR.json +7 -1
  87. package/src/shared/translations/is-IS.json +7 -1
  88. package/src/shared/translations/it-IT.json +7 -1
  89. package/src/shared/translations/ja-JP.json +7 -1
  90. package/src/shared/translations/nl-BE.json +7 -1
  91. package/src/shared/translations/nl-NL.json +7 -1
  92. package/src/shared/translations/no-NO.json +7 -1
  93. package/src/shared/translations/pl-PL.json +7 -1
  94. package/src/shared/translations/pt-PT.json +7 -1
  95. package/src/shared/translations/sv-SE.json +7 -1
  96. package/src/shared/utils/booking-summary.tsx +46 -0
  97. package/src/shared/utils/localization-util.ts +8 -0
  98. package/src/shared/utils/tide-api-utils.ts +2 -2
  99. package/styles/components/_dropdown.scss +5 -0
  100. package/styles/components/_flyin.scss +43 -0
  101. package/styles/components/_loader.scss +82 -0
  102. package/styles/components/_search.scss +14 -2
  103. package/styles/content-blocks-variables.scss +14 -14
  104. /package/build/build-cjs/src/{booking-wizard/components → shared/booking}/product-card.d.ts +0 -0
  105. /package/build/build-esm/src/{booking-wizard/components → shared/booking}/product-card.d.ts +0 -0
  106. /package/src/{booking-wizard/components → shared/booking}/product-card.tsx +0 -0
@@ -1,100 +1,37 @@
1
- import { compact, get, sortBy } from 'lodash';
2
1
  import React, { useContext, useEffect, useState } from 'react';
3
2
  import { useSelector } from 'react-redux';
4
- import { fetchPackage, setCurrentStep, setHasMounted, setIsFetching } from '../booking/booking-slice';
3
+ import { Link, useNavigate } from 'react-router-dom';
4
+ import produce from 'immer';
5
+ import { useFormik } from 'formik';
6
+ import SettingsContext from '../../settings-context';
7
+ import { useAppDispatch } from '../../store';
8
+ import { TravelersFormValues } from '../../types';
9
+ import { fetchPackage, setBookingType, setCurrentStep, setHasMounted, setIsFetching } from '../booking/booking-slice';
10
+ import { FLIGHT_OPTIONS_FORM_STEP, OPTIONS_FORM_STEP, SUMMARY_STEP } from '../booking/constants';
5
11
  import {
12
+ selectAgentAdressId,
13
+ selectAgents,
6
14
  selectBookingAttributes,
15
+ selectBookingQueryString,
16
+ selectBookingType,
7
17
  selectCountries,
8
18
  selectHasMounted,
9
19
  selectIsFetching,
10
20
  selectIsUnavailable,
21
+ selectStartDate,
22
+ selectTranslations,
11
23
  selectTravelersFirstStep
12
24
  } from '../booking/selectors';
13
- import { selectFormRooms, selectTravelersFormValues, setFormValues } from './travelers-form-slice';
14
-
15
- import { Link, useNavigate } from 'react-router-dom';
16
- import { format, parse } from 'date-fns';
17
- import flat from 'flat';
18
- import { useFormik } from 'formik';
19
- import produce from 'immer';
20
- import { buildClassName } from '../../../shared/utils/class-util';
21
- import LabeledInput from '../../components/labeled-input';
22
- import LabeledSelect from '../../components/labeled-select';
23
- import SettingsContext from '../../settings-context';
24
- import { useAppDispatch } from '../../store';
25
- import { RoomTraveler, Traveler, TravelersFormValues } from '../../types';
26
- import { setBookingType } from '../booking/booking-slice';
27
- import { FLIGHT_OPTIONS_FORM_STEP, OPTIONS_FORM_STEP, SUMMARY_STEP } from '../booking/constants';
28
- import { selectAgentAdressId, selectAgents, selectBookingQueryString, selectBookingType, selectStartDate, selectTranslations } from '../booking/selectors';
29
25
  import { fetchPriceDetails } from '../price-details/price-details-slice';
30
- import GenderControl from './controls/gender-control';
31
- import TypeAheadInput from './type-ahead-input';
26
+ import { selectFormRooms, selectTravelersFormValues, setFormValues } from './travelers-form-slice';
32
27
  import validateForm from './validate-form';
33
- import PhoneInput from '../../components/phone-input';
34
-
35
- interface TravelersFormProps {}
36
-
37
- function createTraveler(traveler: RoomTraveler, followNumber: { number: number }, personTranslation?: string, isCompact?: boolean) {
38
- if (isCompact) {
39
- return {
40
- id: traveler.id,
41
- firstName: personTranslation,
42
- lastName: `${followNumber.number++}`,
43
- birthDate: '',
44
- gender: '',
45
- age: traveler.age || 30
46
- } as Traveler;
47
- } else {
48
- return {
49
- id: traveler.id,
50
- firstName: '',
51
- lastName: '',
52
- birthDate: '',
53
- gender: ''
54
- } as Traveler;
55
- }
56
- }
57
-
58
- function createInitialValues(
59
- formRooms: { adults: RoomTraveler[]; children: RoomTraveler[] }[],
60
- startDate?: string,
61
- agentAdressId?: number,
62
- personTranslation?: string,
63
- isCompact?: boolean
64
- ) {
65
- let followNumber = { number: 1 };
28
+ import SharedTravelersForm, { createInitialValuesFromRooms } from '../../../shared/booking/travelers-form';
66
29
 
67
- const initialValues = {
68
- startDate: startDate,
69
- rooms: formRooms.map((r) => ({
70
- adults: r.adults.map((x) => createTraveler(x, followNumber, personTranslation, isCompact)),
71
- children: r.children.map((x) => createTraveler(x, followNumber, personTranslation, isCompact))
72
- })),
73
- mainBookerId: -1,
74
- street: '',
75
- houseNumber: '',
76
- box: '',
77
- zipCode: '',
78
- place: '',
79
- country: '',
80
- phone: '',
81
- email: '',
82
- emailConfirmation: '',
83
- travelAgentId: agentAdressId ?? 0,
84
- travelAgentName: ''
85
- };
86
-
87
- if (initialValues.rooms && initialValues.rooms.length && initialValues.rooms[0].adults && initialValues.rooms[0].adults.length) {
88
- initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
89
- }
90
-
91
- return initialValues;
92
- }
93
-
94
- const TravelersForm: React.FC<TravelersFormProps> = () => {
30
+ const TravelersForm: React.FC = () => {
95
31
  const dispatch = useAppDispatch();
96
32
  const settings = useContext(SettingsContext);
97
33
  const navigate = settings.skipRouter ? () => {} : useNavigate();
34
+
98
35
  const bookingQueryString = useSelector(selectBookingQueryString);
99
36
  const startDate = useSelector(selectStartDate);
100
37
  const formRooms = useSelector(selectFormRooms);
@@ -111,71 +48,45 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
111
48
 
112
49
  const useCompactForm = !!settings.travellers.compactForm && !!settings.agentAdressId;
113
50
  const showAllCountries = !!settings.travellers.showAllCountries;
114
-
115
51
  const initialValues =
116
- useSelector(selectTravelersFormValues) ?? createInitialValues(formRooms, startDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm);
52
+ useSelector(selectTravelersFormValues) ??
53
+ createInitialValuesFromRooms(formRooms, startDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm);
117
54
 
118
- const [showAgents, setShowAgents] = useState<boolean>(settings.agentRequired ?? false);
119
55
  const [showAgentSelection, setShowAgentSelection] = useState<boolean>(!settings.agentAdressId && !settings.hideAgentSelection);
120
56
 
121
- const typeaheadAgents =
122
- sortBy(
123
- agents?.map((x) => ({
124
- key: `${x.id}`,
125
- value: `${x.name} (${x.postalCode} ${x.location})`,
126
- text: `${x.name} (${x.postalCode} ${x.location})`
127
- })),
128
- 'value'
129
- ) ?? [];
130
-
131
- const [filteredAgents, setFilteredAgents] = useState<{ key: string; value: string; text: string }[]>(typeaheadAgents);
132
-
133
- const formik = useCompactForm
134
- ? useFormik<TravelersFormValues>({
135
- initialValues,
136
- validate: (values) => {},
137
- onSubmit: (values) => {
138
- dispatch(setFormValues(values));
139
- dispatch(fetchPriceDetails());
140
-
141
- if (settings.skipRouter) {
142
- dispatch(setCurrentStep(SUMMARY_STEP));
143
- } else {
144
- navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.summary.pathSuffix}?${bookingQueryString}`);
145
- }
146
- }
147
- })
148
- : useFormik<TravelersFormValues>({
149
- initialValues,
150
- validate: (values) =>
57
+ const formik = useFormik<TravelersFormValues>({
58
+ initialValues,
59
+ validate: useCompactForm
60
+ ? () => {}
61
+ : (values) =>
151
62
  validateForm(values, settings.agentRequired, bookingType, translations, settings.travellers.formFields, settings.travellers.mainBookerFormFields),
152
- onSubmit: (values) => {
153
- dispatch(setFormValues(values));
154
- dispatch(fetchPackage());
63
+ onSubmit: (values) => {
64
+ dispatch(setFormValues(values));
65
+
66
+ if (useCompactForm) {
67
+ dispatch(fetchPriceDetails());
68
+ if (settings.skipRouter) dispatch(setCurrentStep(SUMMARY_STEP));
69
+ else navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.summary.pathSuffix}?${bookingQueryString}`);
70
+ return;
71
+ }
155
72
 
156
- if (settings.skipRouter) {
157
- if (travelersFirstStep) {
158
- dispatch(setCurrentStep(FLIGHT_OPTIONS_FORM_STEP));
159
- } else {
160
- dispatch(setCurrentStep(SUMMARY_STEP));
161
- }
162
- } else {
163
- if (travelersFirstStep) {
164
- navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.flightOptions.pathSuffix}?${bookingQueryString}`);
165
- } else {
166
- navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.summary.pathSuffix}?${bookingQueryString}`);
167
- }
168
- }
169
- }
170
- });
73
+ dispatch(fetchPackage());
74
+ if (settings.skipRouter) dispatch(setCurrentStep(travelersFirstStep ? FLIGHT_OPTIONS_FORM_STEP : SUMMARY_STEP));
75
+ else
76
+ navigate(
77
+ `${!settings.skipBasePathInRouting ? settings.basePath : ''}${
78
+ travelersFirstStep ? settings.flightOptions.pathSuffix : settings.summary.pathSuffix
79
+ }?${bookingQueryString}`
80
+ );
81
+ }
82
+ });
171
83
 
172
84
  useEffect(() => {
173
85
  dispatch(fetchPriceDetails());
174
- }, []);
86
+ }, [dispatch]);
175
87
 
176
88
  useEffect(() => {
177
89
  if (!bookingAttributes?.rooms?.length || isFetching) return;
178
-
179
90
  if (!hasMounted) {
180
91
  dispatch(setHasMounted(true));
181
92
  return;
@@ -183,7 +94,6 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
183
94
 
184
95
  const fetchAll = async () => {
185
96
  dispatch(setIsFetching(true));
186
-
187
97
  try {
188
98
  await dispatch(fetchPackage());
189
99
  await dispatch(fetchPriceDetails());
@@ -193,893 +103,60 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
193
103
  };
194
104
 
195
105
  fetchAll();
196
- }, [bookingAttributes?.rooms]);
106
+ }, [bookingAttributes?.rooms, dispatch, hasMounted, isFetching]);
197
107
 
198
- // Update URL querystring when form data changes
199
108
  useEffect(() => {
200
109
  if (settings.skipRouter || !travelersFirstStep) return;
110
+
201
111
  const params = new URLSearchParams(bookingQueryString);
202
112
  params.delete('rooms');
203
113
  const roomsString = formik.values.rooms
204
114
  .map((room) => {
205
115
  const adults = room.adults ? room.adults.length : 0;
206
- const childAges = room.children && room.children.length ? room.children.map((c) => c.age).join(',') : '';
116
+ const childAges = room.children?.length ? room.children.map((child) => child.age).join(',') : '';
207
117
  return `adults:${adults},childAges:(${childAges})`;
208
118
  })
209
- .map((s) => `(${s})`)
119
+ .map((room) => `(${room})`)
210
120
  .join(',');
211
- let query = params.toString();
212
- if (query) {
213
- query += `&rooms=(${roomsString})`;
214
- } else {
215
- query = `rooms=(${roomsString})`;
216
- }
217
- const newUrl = `${window.location.pathname}?${query}`;
218
- navigate(newUrl, { replace: true });
219
- }, [formik.values]);
220
121
 
221
- useEffect(() => {
222
- if (agents && settings.affiliateSlug) {
223
- const agent = agents.find((x) => x.affiliateSlug && x.affiliateSlug === settings.affiliateSlug);
224
- if (!agent) return;
225
-
226
- const formValues = produce(formik.values, (values) => {
227
- (values.travelAgentId = Number(agent.id)), (values.travelAgentName = agent.name);
228
- });
229
- formik.setValues(formValues, false);
230
- dispatch(setFormValues(formValues));
231
- setShowAgentSelection(false);
232
- }
233
- }, [agents, settings.affiliateSlug]);
234
-
235
- const handleMainBookerChange: React.FormEventHandler<HTMLInputElement> = (e) => {
236
- const id = parseInt(e.currentTarget.value);
237
-
238
- formik.setFieldValue('mainBookerId', id);
239
- };
240
-
241
- const mainBooker = formik.values.rooms
242
- .find((r) => r.adults.find((traveler) => traveler.id === formik.values.mainBookerId))
243
- ?.adults.find((traveler) => traveler.id === formik.values.mainBookerId);
244
-
245
- const handleAgentChange = (value: string) => {
246
- const filteredAgents = typeaheadAgents.filter((x) => x.value.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) > -1);
247
-
248
- setFilteredAgents(filteredAgents);
249
- formik.setFieldValue('travelAgentName', value);
250
- };
251
-
252
- const handleAgentSelect = (key: string) => {
253
- const agent = typeaheadAgents.find((x) => x.key === key);
254
-
255
- formik.setValues({
256
- ...formik.values,
257
- travelAgentId: Number(agent?.key),
258
- travelAgentName: agent?.value ?? ''
259
- });
122
+ const nextQuery = `${params.toString()}${params.toString() ? '&' : ''}rooms=(${roomsString})`;
123
+ navigate(`${window.location.pathname}?${nextQuery}`, { replace: true });
124
+ }, [formik.values.rooms, bookingQueryString, navigate, settings.skipRouter, travelersFirstStep]);
260
125
 
261
- let bookingType = 'b2b2c';
262
- if (agentAdressId && agentAdressId != 0) {
263
- bookingType = 'b2b';
264
- }
265
- dispatch(setBookingType(bookingType));
266
- };
126
+ useEffect(() => {
127
+ if (!agents || !settings.affiliateSlug) return;
128
+ const agent = agents.find((x) => x.affiliateSlug && x.affiliateSlug === settings.affiliateSlug);
129
+ if (!agent) return;
267
130
 
268
- const handleAgentClear = () => {
269
- formik.setValues({
270
- ...formik.values,
271
- travelAgentId: 0,
272
- travelAgentName: ''
131
+ const formValues = produce(formik.values, (values) => {
132
+ values.travelAgentId = Number(agent.id);
133
+ values.travelAgentName = agent.name;
273
134
  });
274
135
 
275
- dispatch(setBookingType('b2c'));
276
- };
277
-
278
- const handleAddTraveler = (roomIndex: number) => {
279
- const rooms = [...formik.values.rooms];
280
- const newAdult = {
281
- id: Date.now(),
282
- firstName: '',
283
- lastName: '',
284
- birthDate: '',
285
- gender: ''
286
- };
287
- rooms[roomIndex] = {
288
- ...rooms[roomIndex],
289
- adults: [...rooms[roomIndex].adults, newAdult]
290
- };
291
- formik.setFieldValue('rooms', rooms);
292
- };
293
-
294
- const handleRemoveTraveler = (roomIndex: number, travelerIndex: number) => {
295
- const rooms = [...formik.values.rooms];
296
- const adults = [...rooms[roomIndex].adults];
297
- if (adults.length <= 1) {
298
- return;
299
- }
300
- adults.splice(travelerIndex, 1);
301
- rooms[roomIndex] = {
302
- ...rooms[roomIndex],
303
- adults
304
- };
305
- formik.setFieldValue('rooms', rooms);
306
- };
307
-
308
- const handleAddRoom = () => {
309
- const rooms = [...formik.values.rooms];
310
- const newAdult = {
311
- id: Date.now(),
312
- firstName: '',
313
- lastName: '',
314
- birthDate: '',
315
- gender: ''
316
- };
317
- rooms.push({ adults: [newAdult], children: [] });
318
- formik.setFieldValue('rooms', rooms);
319
- };
320
-
321
- const handleRemoveRoom = (roomIndex: number) => {
322
- const rooms = [...formik.values.rooms];
323
- rooms.splice(roomIndex, 1);
324
- formik.setFieldValue('rooms', rooms);
325
- };
326
-
327
- const toggleAgent = (value: boolean) => {
328
- setShowAgents(value);
329
-
330
- if (!value) {
331
- handleAgentClear();
332
- setFilteredAgents([]);
333
- }
334
- };
335
-
336
- const goPrevious = () => {
337
- dispatch(setCurrentStep(OPTIONS_FORM_STEP));
338
- };
339
-
340
- const flatErrors: Record<string, string> = flat(formik.errors);
341
- const errorKeys = Object.keys(flatErrors).filter((key) => get(formik.touched, key));
342
-
343
- const hasVisibleError = (key: string) => get(formik.errors, key) && get(formik.touched, key);
344
-
345
- const getControl = (type: string, value: Traveler, name: string) => {
346
- switch (type) {
347
- case 'gender': {
348
- return <GenderControl translations={translations} value={value} formik={formik} name={name} />;
349
- }
350
- case 'firstName': {
351
- return (
352
- <LabeledInput
353
- hasError={hasVisibleError(name)}
354
- extraClassName="form__group--md-33"
355
- label={translations.TRAVELERS_FORM.FIRST_NAME}
356
- required
357
- name={name}
358
- onChange={formik.handleChange}
359
- onBlur={formik.handleBlur}
360
- value={value.firstName}
361
- />
362
- );
363
- }
364
- case 'lastName': {
365
- return (
366
- <LabeledInput
367
- hasError={hasVisibleError(name)}
368
- extraClassName="form__group--md-33"
369
- label={translations.TRAVELERS_FORM.LAST_NAME}
370
- required
371
- name={name}
372
- onChange={formik.handleChange}
373
- onBlur={formik.handleBlur}
374
- value={value.lastName}
375
- />
376
- );
377
- }
378
- case 'birthDate': {
379
- return (
380
- <LabeledInput
381
- type="date"
382
- hasError={hasVisibleError(name)}
383
- extraClassName="form__group--md-33"
384
- label={translations.TRAVELERS_FORM.BIRTHDATE}
385
- required
386
- name={name}
387
- onChange={formik.handleChange}
388
- onBlur={formik.handleBlur}
389
- value={value.birthDate}
390
- />
391
- );
392
- }
393
- case 'country': {
394
- return (
395
- <LabeledSelect
396
- hasError={hasVisibleError('country')}
397
- label={translations.TRAVELERS_FORM.COUNTRY}
398
- required
399
- name="country"
400
- onChange={formik.handleChange}
401
- onBlur={formik.handleBlur}
402
- value={formik.values.country}
403
- options={[
404
- {
405
- key: 'empty',
406
- value: undefined,
407
- label: translations.TRAVELERS_FORM.SELECT_COUNTRY
408
- },
409
- ...(showAllCountries
410
- ? countries?.map((country) => ({
411
- key: country.iso2,
412
- value: country.iso2,
413
- label: country.name
414
- })) ?? []
415
- : settings.travellers?.countries?.map((country) => ({
416
- key: country.iso2,
417
- value: country.iso2,
418
- label: country.name
419
- })) ?? [])
420
- ]}
421
- />
422
- );
423
- }
424
- case 'phone': {
425
- return (
426
- <PhoneInput
427
- countries={settings.travellers?.countries ?? []}
428
- countryIso2={formik.values.country}
429
- hasError={hasVisibleError('phone')}
430
- label={translations.TRAVELERS_FORM.PHONE}
431
- required
432
- name="phone"
433
- onChange={formik.handleChange}
434
- onBlur={formik.handleBlur}
435
- value={formik.values.phone}
436
- />
437
- );
438
- }
439
- case 'email': {
440
- return (
441
- <>
442
- <LabeledInput
443
- type="email"
444
- hasError={hasVisibleError('email')}
445
- extraClassName="form__group--md-33"
446
- label={translations.TRAVELERS_FORM.EMAIL}
447
- required
448
- name="email"
449
- onChange={formik.handleChange}
450
- onBlur={formik.handleBlur}
451
- value={formik.values.email}
452
- />
453
- <LabeledInput
454
- type="email"
455
- hasError={hasVisibleError('emailConfirmation')}
456
- extraClassName="form__group--md-33"
457
- label={translations.TRAVELERS_FORM.REPEAT_EMAIL}
458
- required
459
- name="emailConfirmation"
460
- onChange={formik.handleChange}
461
- onBlur={formik.handleBlur}
462
- value={formik.values.emailConfirmation}
463
- />
464
- </>
465
- );
466
- }
467
- }
468
- };
136
+ formik.setValues(formValues, false);
137
+ dispatch(setFormValues(formValues));
138
+ setShowAgentSelection(false);
139
+ }, [agents, settings.affiliateSlug]);
469
140
 
470
141
  return (
471
- <form
472
- className="form form__travelers"
473
- name="booking--travellers"
474
- id="booking--travellers"
475
- noValidate
476
- onSubmit={formik.handleSubmit}
477
- onReset={formik.handleReset}>
478
- {useCompactForm ? (
479
- <div className="form__travelers__wrapper">
480
- {formik.values.rooms.map((room, rIndex) => (
481
- <div key={rIndex}>
482
- {formik.values.rooms.length > 1 && (
483
- <div className="form__region">
484
- <div className="form__region-header">
485
- <h5 className="form__region-heading">
486
- {translations.SHARED.ROOM} {rIndex + 1}
487
- </h5>
488
- <p className="form__region-label">
489
- {compact([
490
- room.adults.length,
491
- room.adults.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
492
- room.adults.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
493
- room.adults && room.adults.length && room.children && room.children.length && ', ',
494
- room.children.length,
495
- room.children.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
496
- room.children.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`
497
- ]).join('')}
498
- </p>
499
- </div>
500
- </div>
501
- )}
502
- {room.adults.map((travelerValues, index) => (
503
- <div className="form__region" key={travelerValues.id}>
504
- <div className="form__region-header">
505
- <h5 className="form__region-heading">
506
- {translations.TRAVELERS_FORM.TRAVELER} {index + 1}
507
- </h5>
508
- <p className="form__region-label">{translations.TRAVELERS_FORM.ADULT}</p>
509
-
510
- <div className="radiobutton">
511
- <label className="radiobutton__label">
512
- <input
513
- type="radio"
514
- name="mainBookerId"
515
- onChange={handleMainBookerChange}
516
- onBlur={formik.handleBlur}
517
- value={travelerValues.id}
518
- checked={formik.values.mainBookerId === travelerValues.id}
519
- className="radiobutton__input"
520
- />
521
- {translations.TRAVELERS_FORM.MAIN_BOOKER}
522
- </label>
523
- </div>
524
- </div>
525
- <div className="form__row">
526
- <LabeledInput
527
- hasError={hasVisibleError(`rooms[${rIndex}].adults[${index}].age`)}
528
- extraClassName="form__group--md-33"
529
- label={translations.TRAVELERS_FORM.AGE}
530
- required
531
- name={`rooms[${rIndex}].adults[${index}].age`}
532
- onChange={formik.handleChange}
533
- onBlur={formik.handleBlur}
534
- value={travelerValues.age}
535
- />
536
- </div>
537
- </div>
538
- ))}
539
- {room.children.map((travelerValues, index) => (
540
- <div className="form__region" key={travelerValues.id}>
541
- <div className="form__region-header">
542
- <h5 className="form__region-heading">
543
- {translations.TRAVELERS_FORM.TRAVELER} {room.adults.length + index + 1}
544
- </h5>
545
- <p className="form__region-label">{translations.TRAVELERS_FORM.CHILD}</p>
546
- </div>
547
- <div className="form__row">
548
- <LabeledInput
549
- hasError={hasVisibleError(`rooms[${rIndex}].children[${index}].age`)}
550
- extraClassName="form__group--md-33"
551
- label={translations.TRAVELERS_FORM.AGE}
552
- required
553
- name={`rooms[${rIndex}].children[${index}].age`}
554
- onChange={formik.handleChange}
555
- onBlur={formik.handleBlur}
556
- value={travelerValues.age}
557
- />
558
- </div>
559
- </div>
560
- ))}
561
- </div>
562
- ))}
563
- </div>
564
- ) : (
565
- <>
566
- <div className="form__travelers__wrapper">
567
- {/* map each room */}
568
- {formik.values.rooms.map((room, rIndex) => (
569
- <div key={rIndex}>
570
- {formik.values.rooms.length > 1 && (
571
- <div className="form__region">
572
- <div className="form__region-header">
573
- <h5 className="form__region-heading">
574
- {translations.SHARED.ROOM} {rIndex + 1}
575
- </h5>
576
- <p className="form__region-label">
577
- {compact([
578
- room.adults.length,
579
- room.adults.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
580
- room.adults.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
581
- room.adults && room.adults.length && room.children && room.children.length && ', ',
582
- room.children.length,
583
- room.children.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
584
- room.children.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`
585
- ]).join('')}
586
- </p>
587
- </div>
588
- {travelersFirstStep && formik.values.rooms.length > 1 && (
589
- <button type="button" className="cta cta--secondary" onClick={() => handleRemoveRoom(rIndex)}>
590
- Verwijder reisgezelschap
591
- </button>
592
- )}
593
- </div>
594
- )}
595
- {/* map adults here for the room */}
596
- {room.adults.map((travelerValues, index) => (
597
- <div className="form__region" key={travelerValues.id}>
598
- <div className="form__region-header">
599
- <h5 className="form__region-heading">
600
- {translations.TRAVELERS_FORM.TRAVELER} {index + 1}
601
- </h5>
602
- <p className="form__region-label">{translations.TRAVELERS_FORM.ADULT}</p>
603
-
604
- <div className="radiobutton">
605
- <label className="radiobutton__label">
606
- <input
607
- type="radio"
608
- name="mainBookerId"
609
- onChange={handleMainBookerChange}
610
- onBlur={formik.handleBlur}
611
- value={travelerValues.id}
612
- checked={formik.values.mainBookerId === travelerValues.id}
613
- className="radiobutton__input"
614
- />
615
- {translations.TRAVELERS_FORM.MAIN_BOOKER}
616
- </label>
617
- </div>
618
- </div>
619
- {settings.travellers.formFields?.length ? (
620
- <>
621
- <div className="travelers-form__grid">
622
- {settings.travellers.formFields.map((field, fIndex) => (
623
- <div key={fIndex} className={`control control--${field.type}`}>
624
- {getControl(field.type, travelerValues, `rooms[${rIndex}].adults[${index}].${field.type}`)}
625
- </div>
626
- ))}
627
- </div>
628
- </>
629
- ) : (
630
- <>
631
- <div className="form__row">
632
- <div className={buildClassName(['form__group', hasVisibleError(`rooms[${rIndex}].adults[${index}].gender`) && 'form__group--error'])}>
633
- <label className="form__label">{translations.TRAVELERS_FORM.GENDER_ID} *</label>
634
- <div className="radiobutton-group">
635
- <div className="radiobutton">
636
- <label className="radiobutton__label">
637
- <input
638
- type="radio"
639
- className="radiobutton__input"
640
- name={`rooms[${rIndex}].adults[${index}].gender`}
641
- onChange={formik.handleChange}
642
- onBlur={formik.handleBlur}
643
- value="m"
644
- checked={travelerValues.gender === 'm'}
645
- />
646
- {translations.TRAVELERS_FORM.MALE_GENDER}
647
- </label>
648
- </div>
649
-
650
- <div className="radiobutton">
651
- <label className="radiobutton__label">
652
- <input
653
- type="radio"
654
- className="radiobutton__input"
655
- name={`rooms[${rIndex}].adults[${index}].gender`}
656
- onChange={formik.handleChange}
657
- onBlur={formik.handleBlur}
658
- value="f"
659
- checked={travelerValues.gender === 'f'}
660
- />
661
- {translations.TRAVELERS_FORM.FEMALE_GENDER}
662
- </label>
663
- </div>
664
-
665
- {/* <div className="radiobutton">
666
- <label className="radiobutton__label">
667
- <input
668
- type="radio"
669
- className="radiobutton__input"
670
- name={`rooms[${rIndex}].adults[${index}].gender`}
671
- onChange={formik.handleChange}
672
- onBlur={formik.handleBlur}
673
- value="x"
674
- checked={travelerValues.gender === 'x'}
675
- />
676
- {translations.TRAVELERS_FORM.OTHER}
677
- </label>
678
- </div> */}
679
- </div>
680
- </div>
681
- </div>
682
- <div className="form__row">
683
- <LabeledInput
684
- hasError={hasVisibleError(`rooms[${rIndex}].adults[${index}].firstName`)}
685
- extraClassName="form__group--md-33"
686
- label={translations.TRAVELERS_FORM.FIRST_NAME}
687
- required
688
- name={`rooms[${rIndex}].adults[${index}].firstName`}
689
- onChange={formik.handleChange}
690
- onBlur={formik.handleBlur}
691
- value={travelerValues.firstName}
692
- />
693
- <LabeledInput
694
- hasError={hasVisibleError(`rooms[${rIndex}].adults[${index}].lastName`)}
695
- extraClassName="form__group--md-33"
696
- label={translations.TRAVELERS_FORM.LAST_NAME}
697
- required
698
- name={`rooms[${rIndex}].adults[${index}].lastName`}
699
- onChange={formik.handleChange}
700
- onBlur={formik.handleBlur}
701
- value={travelerValues.lastName}
702
- />
703
- <LabeledInput
704
- type="date"
705
- hasError={hasVisibleError(`rooms[${rIndex}].adults[${index}].birthDate`)}
706
- extraClassName="form__group--md-33"
707
- label={translations.TRAVELERS_FORM.BIRTHDATE}
708
- required
709
- name={`rooms[${rIndex}].adults[${index}].birthDate`}
710
- onChange={formik.handleChange}
711
- onBlur={formik.handleBlur}
712
- value={travelerValues.birthDate}
713
- />
714
- </div>
715
- {travelersFirstStep && room.adults.length > 1 && (
716
- <button type="button" className="cta cta--secondary" onClick={() => handleRemoveTraveler(rIndex, index)}>
717
- {translations.TRAVELERS_FORM.REMOVE_TRAVELER}
718
- </button>
719
- )}
720
- </>
721
- )}
722
- </div>
723
- ))}
724
- {room.children.map((travelerValues, index) => (
725
- <div className="form__region" key={travelerValues.id}>
726
- <div className="form__region-header">
727
- <h5 className="form__region-heading">
728
- {translations.TRAVELERS_FORM.TRAVELER} {room.adults.length + index + 1}
729
- </h5>
730
- <p className="form__region-label">{translations.TRAVELERS_FORM.CHILD}</p>
731
- </div>
732
- {settings.travellers.formFields?.length ? (
733
- <>
734
- <div className="travelers-form__grid">
735
- {settings.travellers.formFields.map((field, fIndex) => (
736
- <div key={fIndex} className={`control control--${field.type}`}>
737
- {getControl(field.type, travelerValues, `rooms[${rIndex}].children[${index}].${field.type}`)}
738
- </div>
739
- ))}
740
- </div>
741
- </>
742
- ) : (
743
- <>
744
- <div className="form__row">
745
- <div
746
- className={buildClassName(['form__group', hasVisibleError(`rooms[${rIndex}].children[${index}].gender`) && 'form__group--error'])}>
747
- <label className="form__label">{translations.TRAVELERS_FORM.GENDER_ID} *</label>
748
- <div className="radiobutton-group">
749
- <div className="radiobutton">
750
- <label className="radiobutton__label">
751
- <input
752
- type="radio"
753
- className="radiobutton__input"
754
- name={`rooms[${rIndex}].children[${index}].gender`}
755
- onChange={formik.handleChange}
756
- onBlur={formik.handleBlur}
757
- value="m"
758
- checked={travelerValues.gender === 'm'}
759
- />
760
- {translations.TRAVELERS_FORM.MALE_GENDER}
761
- </label>
762
- </div>
763
-
764
- <div className="radiobutton">
765
- <label className="radiobutton__label">
766
- <input
767
- type="radio"
768
- className="radiobutton__input"
769
- name={`rooms[${rIndex}].children[${index}].gender`}
770
- onChange={formik.handleChange}
771
- onBlur={formik.handleBlur}
772
- value="f"
773
- checked={travelerValues.gender === 'f'}
774
- />
775
- {translations.TRAVELERS_FORM.FEMALE_GENDER}
776
- </label>
777
- </div>
778
-
779
- {/* <div className="radiobutton">
780
- <label className="radiobutton__label">
781
- <input
782
- type="radio"
783
- className="radiobutton__input"
784
- name={`rooms[${rIndex}].children[${index}].gender`}
785
- onChange={formik.handleChange}
786
- onBlur={formik.handleBlur}
787
- value="x"
788
- checked={travelerValues.gender === 'x'}
789
- />
790
- {translations.TRAVELERS_FORM.OTHER}
791
- </label>
792
- </div> */}
793
- </div>
794
- </div>
795
- </div>
796
- <div className="form__row">
797
- <LabeledInput
798
- hasError={hasVisibleError(`rooms[${rIndex}].children[${index}].firstName`)}
799
- extraClassName="form__group--md-33"
800
- label={translations.TRAVELERS_FORM.FIRST_NAME}
801
- required
802
- name={`rooms[${rIndex}].children[${index}].firstName`}
803
- onChange={formik.handleChange}
804
- onBlur={formik.handleBlur}
805
- value={travelerValues.firstName}
806
- />
807
- <LabeledInput
808
- hasError={hasVisibleError(`rooms[${rIndex}].children[${index}].lastName`)}
809
- extraClassName="form__group--md-33"
810
- label={translations.TRAVELERS_FORM.LAST_NAME}
811
- required
812
- name={`rooms[${rIndex}].children[${index}].lastName`}
813
- onChange={formik.handleChange}
814
- onBlur={formik.handleBlur}
815
- value={travelerValues.lastName}
816
- />
817
- <LabeledInput
818
- type="date"
819
- hasError={hasVisibleError(`rooms[${rIndex}].children[${index}].birthDate`)}
820
- extraClassName="form__group--md-33"
821
- label={translations.TRAVELERS_FORM.BIRTHDATE}
822
- required
823
- name={`rooms[${rIndex}].children[${index}].birthDate`}
824
- onChange={formik.handleChange}
825
- onBlur={formik.handleBlur}
826
- value={travelerValues.birthDate}
827
- />
828
- </div>
829
- </>
830
- )}
831
- </div>
832
- ))}
833
- {travelersFirstStep && (
834
- <div className="form__region">
835
- <button type="button" className="cta cta--select" onClick={() => handleAddTraveler(rIndex)}>
836
- {translations.TRAVELERS_FORM.ADD_TRAVELER}
837
- </button>
838
- </div>
839
- )}
840
- </div>
841
- ))}
842
-
843
- {bookingType != 'b2b' || settings.travellers?.mainBookerFormFields?.length ? (
844
- <div className="form__region">
845
- <div className="form__region-header">
846
- <h5 className="form__region-heading">{translations.TRAVELERS_FORM.MAIN_BOOKER}</h5>
847
- <p className="form__region-label">
848
- {compact([
849
- compact([mainBooker?.firstName, mainBooker?.lastName]).join(' '),
850
- mainBooker?.birthDate && format(parse(mainBooker.birthDate, 'yyyy-MM-dd', new Date()), 'dd-MM-yyyy')
851
- ]).join(', ')}
852
- </p>
853
- </div>
854
- <>
855
- {settings.travellers?.mainBookerFormFields?.length ? (
856
- <>
857
- <div className="main-booker-form__grid">
858
- {settings.travellers.mainBookerFormFields.map((field, fIndex) => (
859
- <div key={fIndex} className={`control control--${field.type}`}>
860
- {getControl(field.type, {} as Traveler, field.type)}
861
- </div>
862
- ))}
863
- </div>
864
- </>
865
- ) : (
866
- <>
867
- <div className="form__twocolumn">
868
- <div className="form__twocolumn-column">
869
- <div className="form__row">
870
- <LabeledInput
871
- hasError={hasVisibleError('street')}
872
- extraClassName="form__group--50 form__group--sm-60"
873
- label={translations.TRAVELERS_FORM.STREET}
874
- required
875
- name="street"
876
- onChange={formik.handleChange}
877
- onBlur={formik.handleBlur}
878
- value={formik.values.street}
879
- />
880
- <LabeledInput
881
- hasError={hasVisibleError('houseNumber')}
882
- extraClassName="form__group--30 form__group--sm-20"
883
- label={translations.TRAVELERS_FORM.HOUSE_NUMBER}
884
- required
885
- name="houseNumber"
886
- onChange={formik.handleChange}
887
- onBlur={formik.handleBlur}
888
- value={formik.values.houseNumber}
889
- />
890
- <LabeledInput
891
- hasError={hasVisibleError('box')}
892
- extraClassName="form__group--20"
893
- label={translations.TRAVELERS_FORM.POST_BOX}
894
- name="box"
895
- onChange={formik.handleChange}
896
- onBlur={formik.handleBlur}
897
- value={formik.values.box}
898
- />
899
- </div>
900
- </div>
901
- <div className="form__twocolumn-column">
902
- <div className="form__row">
903
- <LabeledInput
904
- hasError={hasVisibleError('zipCode')}
905
- extraClassName="form__group--40 form__group--sm-20"
906
- label={translations.TRAVELERS_FORM.ZIPCODE}
907
- required
908
- name="zipCode"
909
- onChange={formik.handleChange}
910
- onBlur={formik.handleBlur}
911
- value={formik.values.zipCode}
912
- />
913
- <LabeledInput
914
- hasError={hasVisibleError('place')}
915
- extraClassName="form__group--60 form__group--sm-40"
916
- label={translations.TRAVELERS_FORM.CITY}
917
- required
918
- name="place"
919
- onChange={formik.handleChange}
920
- onBlur={formik.handleBlur}
921
- value={formik.values.place}
922
- />
923
- <LabeledSelect
924
- hasError={hasVisibleError('country')}
925
- extraClassName="form__group--sm-40"
926
- label={translations.TRAVELERS_FORM.COUNTRY}
927
- required
928
- name="country"
929
- onChange={formik.handleChange}
930
- onBlur={formik.handleBlur}
931
- value={formik.values.country}
932
- options={[
933
- {
934
- key: 'empty',
935
- value: undefined,
936
- label: translations.TRAVELERS_FORM.SELECT_COUNTRY
937
- },
938
- ...(showAllCountries
939
- ? countries?.map((country) => ({
940
- key: country.iso2,
941
- value: country.iso2,
942
- label: country.name
943
- })) ?? []
944
- : [
945
- {
946
- key: 'be',
947
- value: 'be',
948
- label: translations.TRAVELERS_FORM.COUNTRIES.BELGIUM
949
- },
950
- {
951
- key: 'nl',
952
- value: 'nl',
953
- label: translations.TRAVELERS_FORM.COUNTRIES.NETHERLANDS
954
- },
955
- {
956
- key: 'fr',
957
- value: 'fr',
958
- label: translations.TRAVELERS_FORM.COUNTRIES.FRANCE
959
- }
960
- ])
961
- ]}
962
- />
963
- </div>
964
- </div>
965
- </div>
966
- <div className="form__row">
967
- <LabeledInput
968
- hasError={hasVisibleError('phone')}
969
- extraClassName="form__group--md-33"
970
- label={translations.TRAVELERS_FORM.PHONE}
971
- required
972
- name="phone"
973
- onChange={formik.handleChange}
974
- onBlur={formik.handleBlur}
975
- value={formik.values.phone}
976
- />
977
- <LabeledInput
978
- type="email"
979
- hasError={hasVisibleError('email')}
980
- extraClassName="form__group--md-33"
981
- label={translations.TRAVELERS_FORM.EMAIL}
982
- required
983
- name="email"
984
- onChange={formik.handleChange}
985
- onBlur={formik.handleBlur}
986
- value={formik.values.email}
987
- />
988
- <LabeledInput
989
- type="email"
990
- hasError={hasVisibleError('emailConfirmation')}
991
- extraClassName="form__group--md-33"
992
- label={translations.TRAVELERS_FORM.REPEAT_EMAIL}
993
- required
994
- name="emailConfirmation"
995
- onChange={formik.handleChange}
996
- onBlur={formik.handleBlur}
997
- value={formik.values.emailConfirmation}
998
- />
999
- </div>
1000
- </>
1001
- )}
1002
- </>
1003
- </div>
1004
- ) : (
1005
- <div className="form__region">
1006
- <div className="form__row">
1007
- <LabeledInput
1008
- hasError={hasVisibleError('phone')}
1009
- extraClassName="form__group--md-33"
1010
- label={translations.TRAVELERS_FORM.PHONE}
1011
- required
1012
- name="phone"
1013
- onChange={formik.handleChange}
1014
- onBlur={formik.handleBlur}
1015
- value={formik.values.phone}
1016
- />
1017
- </div>
1018
- </div>
1019
- )}
1020
-
1021
- {showAgentSelection && (
1022
- <div className="form__region">
1023
- <div className="form__region-header">
1024
- <h5 className="form__region-heading">{translations.TRAVELERS_FORM.BOOK_WITH_AGENT}</h5>
1025
- <div className="checkbox" id="cbxChooseOffice">
1026
- <label className="checkbox__label">
1027
- <input
1028
- type="checkbox"
1029
- name="booking--mainbooker"
1030
- defaultChecked={showAgents}
1031
- onClick={() => toggleAgent(!showAgents)}
1032
- className="checkbox__input"
1033
- />
1034
- {translations.TRAVELERS_FORM.CHOOSE_OFFICE}
1035
- </label>
1036
- </div>
1037
- </div>
1038
- {showAgents && (
1039
- <div className="form__row form__row--choose-office">
1040
- <div className={buildClassName(['form__group', 'form__group--icon', hasVisibleError('travelAgentId') && 'form__group--error'])}>
1041
- <TypeAheadInput
1042
- value={formik.values.travelAgentName}
1043
- options={filteredAgents}
1044
- onChange={handleAgentChange}
1045
- onSelect={handleAgentSelect}
1046
- onClear={handleAgentClear}
1047
- name="travelAgentName"
1048
- placeholder={translations.TRAVELERS_FORM.CHOOSE_AGENT_PLACEHOLDER}
1049
- />
1050
- </div>
1051
- </div>
1052
- )}
1053
- </div>
1054
- )}
1055
- </div>
1056
- {errorKeys.length > 0 && (
1057
- <div className="form__region form__region--errors">
1058
- <div className="form__row">
1059
- <div className="form__group">
1060
- <p className="form__error-heading">{translations.TRAVELERS_FORM.VALIDATION_MESSAGE}:</p>
1061
- <ul className="list">
1062
- {errorKeys.map((key) => (
1063
- <li key={key}>{get(flatErrors, key)}</li>
1064
- ))}
1065
- </ul>
1066
- </div>
1067
- </div>
1068
- </div>
1069
- )}
1070
- </>
1071
- )}
1072
- {travelersFirstStep && (
1073
- <div className="booking__navigator">
1074
- <button type="button" className="cta cta--select" onClick={handleAddRoom}>
1075
- {translations.TRAVELERS_FORM.ADD_ROOM}
1076
- </button>
1077
- </div>
1078
- )}
1079
-
1080
- <div className="booking__navigator">
1081
- {!travelersFirstStep && settings.skipRouter ? (
1082
- <button type="button" title={translations.STEPS.PREVIOUS} onClick={() => goPrevious()} className="cta cta--secondary">
142
+ <SharedTravelersForm
143
+ formik={formik}
144
+ translations={translations}
145
+ travellersSettings={settings.travellers}
146
+ countries={countries}
147
+ agents={agents}
148
+ bookingType={bookingType}
149
+ agentAdressId={agentAdressId}
150
+ travelersFirstStep={travelersFirstStep}
151
+ isUnavailable={isUnavailable}
152
+ useCompactForm={useCompactForm}
153
+ showAllCountries={showAllCountries}
154
+ showAgentSelection={showAgentSelection}
155
+ initialShowAgents={settings.agentRequired ?? false}
156
+ onBookingTypeChange={(nextBookingType) => dispatch(setBookingType(nextBookingType))}
157
+ renderPreviousButton={() =>
158
+ !travelersFirstStep && settings.skipRouter ? (
159
+ <button type="button" title={translations.STEPS.PREVIOUS} onClick={() => dispatch(setCurrentStep(OPTIONS_FORM_STEP))} className="cta cta--secondary">
1083
160
  {translations.STEPS.PREVIOUS}
1084
161
  </button>
1085
162
  ) : !travelersFirstStep ? (
@@ -1089,12 +166,9 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
1089
166
  className="cta cta--secondary">
1090
167
  {translations.STEPS.PREVIOUS}
1091
168
  </Link>
1092
- ) : null}
1093
- <button type="submit" title={translations.STEPS.NEXT} className={'cta' + (isUnavailable ? ' cta--disabled' : '')}>
1094
- {translations.STEPS.NEXT}
1095
- </button>
1096
- </div>
1097
- </form>
169
+ ) : null
170
+ }
171
+ />
1098
172
  );
1099
173
  };
1100
174