@qite/tide-booking-component 0.0.2-preview.9 → 1.0.0-preview

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 (143) hide show
  1. package/README.md +1 -0
  2. package/build/build-cjs/booking-wizard/components/message.d.ts +1 -0
  3. package/build/build-cjs/booking-wizard/components/product-card.d.ts +1 -2
  4. package/build/build-cjs/booking-wizard/features/booking/api.d.ts +21 -0
  5. package/build/build-cjs/booking-wizard/features/booking/booking-slice.d.ts +95 -19
  6. package/build/build-cjs/booking-wizard/features/booking/booking.d.ts +1 -2
  7. package/build/build-cjs/booking-wizard/features/booking/selectors.d.ts +208 -0
  8. package/build/build-cjs/booking-wizard/features/price-details/price-details-api.d.ts +8 -6
  9. package/build/build-cjs/booking-wizard/features/price-details/price-details-slice.d.ts +98 -30
  10. package/build/build-cjs/booking-wizard/features/price-details/util.d.ts +5 -0
  11. package/build/build-cjs/booking-wizard/features/product-options/no-options.d.ts +2 -0
  12. package/build/build-cjs/booking-wizard/features/product-options/none-option.d.ts +17 -0
  13. package/build/build-cjs/booking-wizard/features/product-options/option-booking-group.d.ts +18 -0
  14. package/build/build-cjs/booking-wizard/features/product-options/option-item.d.ts +11 -0
  15. package/build/build-cjs/booking-wizard/features/product-options/option-pax-card.d.ts +9 -0
  16. package/build/build-cjs/booking-wizard/features/product-options/option-pax-group.d.ts +20 -0
  17. package/build/build-cjs/booking-wizard/features/product-options/option-room.d.ts +16 -0
  18. package/build/build-cjs/booking-wizard/features/product-options/option-unit-group.d.ts +20 -0
  19. package/build/build-cjs/booking-wizard/features/product-options/option-units-card.d.ts +9 -0
  20. package/build/build-cjs/booking-wizard/features/sidebar/index.d.ts +5 -1
  21. package/build/build-cjs/booking-wizard/features/sidebar/sidebar-flight.d.ts +8 -0
  22. package/build/build-cjs/booking-wizard/features/sidebar/sidebar-util.d.ts +22 -5
  23. package/build/build-cjs/booking-wizard/features/sidebar/sidebar.d.ts +16 -8
  24. package/build/build-cjs/booking-wizard/features/summary/summary-booking-option-pax.d.ts +7 -0
  25. package/build/build-cjs/booking-wizard/features/summary/summary-booking-option-unit.d.ts +7 -0
  26. package/build/build-cjs/booking-wizard/features/summary/summary-flight.d.ts +8 -0
  27. package/build/build-cjs/booking-wizard/features/summary/summary-per-booking-option-group.d.ts +10 -0
  28. package/build/build-cjs/booking-wizard/features/summary/summary-per-pax-option-group.d.ts +10 -0
  29. package/build/build-cjs/booking-wizard/features/summary/summary-per-unit-option-group.d.ts +10 -0
  30. package/build/build-cjs/booking-wizard/features/summary/summary-slice.d.ts +0 -28
  31. package/build/build-cjs/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +82 -88
  32. package/build/build-cjs/booking-wizard/features/travelers-form/type-ahead-input.d.ts +1 -0
  33. package/build/build-cjs/booking-wizard/features/travelers-form/validate-form.d.ts +2 -1
  34. package/build/build-cjs/booking-wizard/index.d.ts +3 -2
  35. package/build/build-cjs/booking-wizard/store.d.ts +23 -45
  36. package/build/build-cjs/booking-wizard/types.d.ts +63 -11
  37. package/build/build-cjs/booking-wizard/utils/query-string-util.d.ts +13 -0
  38. package/build/build-cjs/index.js +12065 -2381
  39. package/build/build-esm/booking-wizard/components/message.d.ts +1 -0
  40. package/build/build-esm/booking-wizard/components/product-card.d.ts +1 -2
  41. package/build/build-esm/booking-wizard/features/booking/api.d.ts +21 -0
  42. package/build/build-esm/booking-wizard/features/booking/booking-slice.d.ts +95 -19
  43. package/build/build-esm/booking-wizard/features/booking/booking.d.ts +1 -2
  44. package/build/build-esm/booking-wizard/features/booking/selectors.d.ts +208 -0
  45. package/build/build-esm/booking-wizard/features/price-details/price-details-api.d.ts +8 -6
  46. package/build/build-esm/booking-wizard/features/price-details/price-details-slice.d.ts +98 -30
  47. package/build/build-esm/booking-wizard/features/price-details/util.d.ts +5 -0
  48. package/build/build-esm/booking-wizard/features/product-options/no-options.d.ts +2 -0
  49. package/build/build-esm/booking-wizard/features/product-options/none-option.d.ts +17 -0
  50. package/build/build-esm/booking-wizard/features/product-options/option-booking-group.d.ts +18 -0
  51. package/build/build-esm/booking-wizard/features/product-options/option-item.d.ts +11 -0
  52. package/build/build-esm/booking-wizard/features/product-options/option-pax-card.d.ts +9 -0
  53. package/build/build-esm/booking-wizard/features/product-options/option-pax-group.d.ts +20 -0
  54. package/build/build-esm/booking-wizard/features/product-options/option-room.d.ts +16 -0
  55. package/build/build-esm/booking-wizard/features/product-options/option-unit-group.d.ts +20 -0
  56. package/build/build-esm/booking-wizard/features/product-options/option-units-card.d.ts +9 -0
  57. package/build/build-esm/booking-wizard/features/sidebar/index.d.ts +5 -1
  58. package/build/build-esm/booking-wizard/features/sidebar/sidebar-flight.d.ts +8 -0
  59. package/build/build-esm/booking-wizard/features/sidebar/sidebar-util.d.ts +22 -5
  60. package/build/build-esm/booking-wizard/features/sidebar/sidebar.d.ts +16 -8
  61. package/build/build-esm/booking-wizard/features/summary/summary-booking-option-pax.d.ts +7 -0
  62. package/build/build-esm/booking-wizard/features/summary/summary-booking-option-unit.d.ts +7 -0
  63. package/build/build-esm/booking-wizard/features/summary/summary-flight.d.ts +8 -0
  64. package/build/build-esm/booking-wizard/features/summary/summary-per-booking-option-group.d.ts +10 -0
  65. package/build/build-esm/booking-wizard/features/summary/summary-per-pax-option-group.d.ts +10 -0
  66. package/build/build-esm/booking-wizard/features/summary/summary-per-unit-option-group.d.ts +10 -0
  67. package/build/build-esm/booking-wizard/features/summary/summary-slice.d.ts +0 -28
  68. package/build/build-esm/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +82 -88
  69. package/build/build-esm/booking-wizard/features/travelers-form/type-ahead-input.d.ts +1 -0
  70. package/build/build-esm/booking-wizard/features/travelers-form/validate-form.d.ts +2 -1
  71. package/build/build-esm/booking-wizard/index.d.ts +3 -2
  72. package/build/build-esm/booking-wizard/store.d.ts +23 -45
  73. package/build/build-esm/booking-wizard/types.d.ts +63 -11
  74. package/build/build-esm/booking-wizard/utils/query-string-util.d.ts +13 -0
  75. package/build/build-esm/index.js +11888 -2330
  76. package/package.json +8 -4
  77. package/rollup.config.js +1 -6
  78. package/src/booking-wizard/components/message.tsx +14 -8
  79. package/src/booking-wizard/components/product-card.tsx +10 -39
  80. package/src/booking-wizard/components/step-indicator.tsx +1 -1
  81. package/src/booking-wizard/components/step-route.tsx +1 -1
  82. package/src/booking-wizard/features/booking/api.ts +44 -0
  83. package/src/booking-wizard/features/booking/booking-slice.ts +274 -40
  84. package/src/booking-wizard/features/booking/booking.tsx +193 -57
  85. package/src/booking-wizard/features/booking/selectors.ts +328 -0
  86. package/src/booking-wizard/features/confirmation/confirmation.tsx +22 -11
  87. package/src/booking-wizard/features/error/error.tsx +15 -2
  88. package/src/booking-wizard/features/price-details/price-details-api.ts +12 -6
  89. package/src/booking-wizard/features/price-details/price-details-slice.ts +80 -50
  90. package/src/booking-wizard/features/price-details/util.ts +135 -0
  91. package/src/booking-wizard/features/product-options/no-options.tsx +18 -0
  92. package/src/booking-wizard/features/product-options/none-option.tsx +118 -0
  93. package/src/booking-wizard/features/product-options/option-booking-group.tsx +210 -0
  94. package/src/booking-wizard/features/product-options/option-item.tsx +321 -0
  95. package/src/booking-wizard/features/product-options/option-pax-card.tsx +102 -0
  96. package/src/booking-wizard/features/product-options/option-pax-group.tsx +169 -0
  97. package/src/booking-wizard/features/product-options/option-room.tsx +300 -0
  98. package/src/booking-wizard/features/product-options/option-unit-group.tsx +192 -0
  99. package/src/booking-wizard/features/product-options/option-units-card.tsx +100 -0
  100. package/src/booking-wizard/features/product-options/options-form.tsx +226 -48
  101. package/src/booking-wizard/features/sidebar/index.tsx +43 -20
  102. package/src/booking-wizard/features/sidebar/sidebar-flight.tsx +66 -0
  103. package/src/booking-wizard/features/sidebar/sidebar-util.ts +81 -39
  104. package/src/booking-wizard/features/sidebar/sidebar.tsx +150 -100
  105. package/src/booking-wizard/features/summary/summary-booking-option-pax.tsx +25 -0
  106. package/src/booking-wizard/features/summary/summary-booking-option-unit.tsx +25 -0
  107. package/src/booking-wizard/features/summary/summary-flight.tsx +35 -0
  108. package/src/booking-wizard/features/summary/summary-per-booking-option-group.tsx +57 -0
  109. package/src/booking-wizard/features/summary/summary-per-pax-option-group.tsx +51 -0
  110. package/src/booking-wizard/features/summary/summary-per-unit-option-group.tsx +54 -0
  111. package/src/booking-wizard/features/summary/summary-slice.ts +1 -134
  112. package/src/booking-wizard/features/summary/summary.tsx +521 -134
  113. package/src/booking-wizard/features/travelers-form/travelers-form-slice.ts +54 -55
  114. package/src/booking-wizard/features/travelers-form/travelers-form.tsx +202 -94
  115. package/src/booking-wizard/features/travelers-form/type-ahead-input.tsx +23 -3
  116. package/src/booking-wizard/features/travelers-form/validate-form.ts +40 -3
  117. package/src/booking-wizard/index.tsx +5 -6
  118. package/src/booking-wizard/settings-context.ts +33 -5
  119. package/src/booking-wizard/store.ts +5 -4
  120. package/src/booking-wizard/translations/translations.json +95 -61
  121. package/src/booking-wizard/types.ts +67 -10
  122. package/src/booking-wizard/utils/query-string-util.ts +42 -0
  123. package/build/build-cjs/booking-wizard/features/product-options/checkbox.d.ts +0 -11
  124. package/build/build-cjs/booking-wizard/features/product-options/option-details.d.ts +0 -11
  125. package/build/build-cjs/booking-wizard/features/product-options/product-options-api.d.ts +0 -29
  126. package/build/build-cjs/booking-wizard/features/product-options/product-options-slice.d.ts +0 -75
  127. package/build/build-cjs/booking-wizard/features/product-options/radio-button.d.ts +0 -10
  128. package/build/build-cjs/booking-wizard/features/product-options/rooms-slice.d.ts +0 -23
  129. package/build/build-cjs/booking-wizard/features/product-options/tree-level.d.ts +0 -7
  130. package/build/build-esm/booking-wizard/features/product-options/checkbox.d.ts +0 -11
  131. package/build/build-esm/booking-wizard/features/product-options/option-details.d.ts +0 -11
  132. package/build/build-esm/booking-wizard/features/product-options/product-options-api.d.ts +0 -29
  133. package/build/build-esm/booking-wizard/features/product-options/product-options-slice.d.ts +0 -75
  134. package/build/build-esm/booking-wizard/features/product-options/radio-button.d.ts +0 -10
  135. package/build/build-esm/booking-wizard/features/product-options/rooms-slice.d.ts +0 -23
  136. package/build/build-esm/booking-wizard/features/product-options/tree-level.d.ts +0 -7
  137. package/src/booking-wizard/features/product-options/checkbox.tsx +0 -38
  138. package/src/booking-wizard/features/product-options/option-details.tsx +0 -65
  139. package/src/booking-wizard/features/product-options/product-options-api.ts +0 -148
  140. package/src/booking-wizard/features/product-options/product-options-slice.ts +0 -149
  141. package/src/booking-wizard/features/product-options/radio-button.tsx +0 -35
  142. package/src/booking-wizard/features/product-options/rooms-slice.ts +0 -28
  143. package/src/booking-wizard/features/product-options/tree-level.tsx +0 -118
@@ -1,55 +1,103 @@
1
- import { createPackageOfferWithShortResponse } from "@qite/tide-client";
1
+ import { book, validateVoucher } from "@qite/tide-client";
2
2
  import {
3
- selectAdultCount,
4
3
  selectAdults,
5
- selectChildCount,
6
4
  selectChildren,
7
5
  selectTravelersFormValues,
8
6
  } from "../travelers-form/travelers-form-slice";
7
+ import { selectUserValidated, setUserValidated } from "./summary-slice";
9
8
  import {
10
- selectBookRequest,
11
- selectUserValidated,
12
- setUserValidated,
13
- } from "./summary-slice";
14
- import {
15
- selectBookingQueryString,
16
9
  setBookingNumber,
10
+ setBookingRemarks,
11
+ setVoucherCodes,
17
12
  } from "../booking/booking-slice";
18
- import { useDispatch, useSelector } from "react-redux";
19
-
13
+ import { useSelector } from "react-redux";
14
+ import { useLocation } from "@reach/router";
20
15
  import Icon from "../../components/icon";
21
- import React from "react";
16
+ import React, { useEffect } from "react";
22
17
  import SettingsContext from "../../settings-context";
23
18
  import { buildClassName } from "../../utils/class-util";
24
- import { compact } from "lodash";
19
+ import { compact, findIndex, isEmpty, isNil } from "lodash";
25
20
  import { Link, navigate } from "@reach/router";
26
21
  import translations from "../../translations/translations.json";
27
22
  import { useContext } from "react";
28
23
  import { useState } from "react";
29
24
  import { buildTideClientConfig } from "../../utils/tide-api-utils";
25
+ import { useAppDispatch } from "../../store";
26
+ import { SummaryCheckbox } from "../../types";
27
+ import {
28
+ selectActiveOption,
29
+ selectBookingPackageBookRequest,
30
+ selectBookingPackageRequest,
31
+ selectBookingQueryString,
32
+ selectPackageDetails,
33
+ } from "../booking/selectors";
34
+ import { getDateText } from "../sidebar/sidebar-util";
35
+ import SummaryFlight from "./summary-flight";
36
+ import {
37
+ fetchPriceDetails,
38
+ selectNotifications,
39
+ setNotifications,
40
+ } from "../price-details/price-details-slice";
41
+ import SummaryBookingOptionUnit from "./summary-booking-option-unit";
42
+ import SummaryBookingOptionPax from "./summary-booking-option-pax";
43
+ import SummaryBookingOption from "./summary-per-booking-option-group";
44
+ import {
45
+ BookingPackageRequest,
46
+ BookingPackageVoucherRequest,
47
+ } from "@qite/tide-client/build/types";
48
+
49
+ interface VoucherProps {
50
+ code?: string;
51
+ isValidated?: boolean;
52
+ isValid?: boolean;
53
+ }
30
54
 
31
55
  interface SummaryProps {}
32
56
 
33
57
  const Summary: React.FC<SummaryProps> = () => {
34
- const [isSubmitting, setIsSubmitting] = useState(false);
35
-
36
- const dispatch = useDispatch();
58
+ const dispatch = useAppDispatch();
37
59
 
38
60
  const settings = useContext(SettingsContext);
39
61
 
40
- const bookingQueryString = useSelector(selectBookingQueryString);
62
+ const [isSubmitting, setIsSubmitting] = useState(false);
63
+ const [checkboxes, setCheckboxes] = useState<
64
+ SummaryCheckbox[] | undefined | null
65
+ >(settings.summary.checkboxes);
66
+ const [remarks, setRemarks] = useState<string>("");
67
+
68
+ const [voucher, setVoucher] = useState<VoucherProps>({});
41
69
 
70
+ const bookingQueryString = useSelector(selectBookingQueryString);
42
71
  const travelerFormValues = useSelector(selectTravelersFormValues);
72
+ const packageDetails = useSelector(selectPackageDetails);
73
+ const activeOption = useSelector(selectActiveOption);
43
74
 
44
- const adultCount = useSelector(selectAdultCount);
45
- const childCount = useSelector(selectChildCount);
75
+ if (!travelerFormValues)
76
+ navigate(`${settings.basePath}?${bookingQueryString}`);
46
77
 
47
78
  const adults = useSelector(selectAdults);
48
79
  const children = useSelector(selectChildren);
49
80
 
50
81
  const userValidated = useSelector(selectUserValidated);
82
+ const notifications = useSelector(selectNotifications);
83
+
84
+ const bookRequest = useSelector(selectBookingPackageBookRequest);
85
+ const location = useLocation();
86
+
87
+ useEffect(() => {
88
+ // Every checkbox should be checked, or no checkboxes
89
+ const checkboxesValidated = !isNil(checkboxes)
90
+ ? checkboxes.every((checkbox) => checkbox.isSelected)
91
+ : true;
51
92
 
52
- const bookRequest = useSelector(selectBookRequest);
93
+ const notificationsValidated = !isNil(notifications)
94
+ ? notifications
95
+ .filter((x) => x.hasToBeConfirmed)
96
+ .every((checkbox) => checkbox.isConfirmed)
97
+ : true;
98
+
99
+ dispatch(setUserValidated(checkboxesValidated && notificationsValidated));
100
+ }, [checkboxes, notifications]);
53
101
 
54
102
  const handleSubmit: React.FormEventHandler<HTMLFormElement> = async (e) => {
55
103
  e.preventDefault();
@@ -61,147 +109,486 @@ const Summary: React.FC<SummaryProps> = () => {
61
109
  return;
62
110
  }
63
111
 
112
+ if (bookRequest.payload.returnPaymentUrl) {
113
+ bookRequest.payload.redirectUrl = `${location.protocol}//${location.host}${settings.basePath}`;
114
+ }
115
+
64
116
  try {
65
- const bookingResponse = await createPackageOfferWithShortResponse(
66
- tideClientConfig,
67
- bookRequest
68
- );
117
+ const bookingResponse = await book(tideClientConfig, bookRequest);
118
+
119
+ // Booking successfull
120
+ dispatch(setBookingNumber(bookingResponse.number));
69
121
 
70
- if (bookingResponse.hasErrors) {
71
- // Booking not successful
122
+ if (bookingResponse.paymentUrl) {
123
+ window.location.href = bookingResponse.paymentUrl;
124
+ } else {
72
125
  navigate(
73
- `${settings.basePath}${settings.errorPathSuffix}?${bookingQueryString}`
126
+ `${settings.basePath}${settings.confirmation.pathSuffix}?${bookingQueryString}`
74
127
  );
75
128
  }
76
-
77
- // Booking successful
78
- dispatch(setBookingNumber(bookingResponse.dossierNumber));
79
- navigate(
80
- `${settings.basePath}${settings.confirmationPathSuffix}?${bookingQueryString}`
81
- );
82
129
  } catch (error) {
83
130
  // Booking not successful
84
131
  navigate(
85
- `${settings.basePath}${settings.errorPathSuffix}?${bookingQueryString}`
132
+ `${settings.basePath}${settings.error.pathSuffix}?${bookingQueryString}`
86
133
  );
87
134
  } finally {
88
135
  setIsSubmitting(false);
89
136
  }
90
137
  };
91
138
 
139
+ const handleNotificationChange = (id: number, checked: boolean) => {
140
+ const updatedNotifications = notifications.map((notification) =>
141
+ notification.id === id
142
+ ? { ...notification, isConfirmed: checked }
143
+ : notification
144
+ );
145
+
146
+ dispatch(setNotifications(updatedNotifications));
147
+ };
148
+
149
+ const handleCheckboxChange = (id: string, checked: boolean) => {
150
+ if (isNil(checkboxes)) {
151
+ return;
152
+ }
153
+
154
+ const newCheckboxes = [...checkboxes];
155
+
156
+ const index = findIndex(checkboxes, (checkbox) => checkbox.id === id);
157
+ newCheckboxes[index].isSelected = !newCheckboxes[index].isSelected;
158
+
159
+ setCheckboxes(newCheckboxes);
160
+ };
161
+
162
+ const handleRemarksChange = (text: string) => {
163
+ dispatch(setBookingRemarks(text));
164
+
165
+ setRemarks(text);
166
+ };
167
+
168
+ const handleValidateVoucher: React.MouseEventHandler<
169
+ HTMLButtonElement
170
+ > = async (event) => {
171
+ if (!voucher?.code) return;
172
+
173
+ const request = useSelector(
174
+ selectBookingPackageRequest
175
+ ) as BookingPackageRequest<BookingPackageVoucherRequest>;
176
+ request.payload = {
177
+ code: voucher.code,
178
+ otherCodes: bookRequest?.payload.voucherCodes ?? [],
179
+ } as BookingPackageVoucherRequest;
180
+
181
+ const tideClientConfig = buildTideClientConfig();
182
+
183
+ if (!tideClientConfig) return;
184
+
185
+ const result = await validateVoucher(tideClientConfig, request);
186
+
187
+ if (result?.payload) {
188
+ setVoucher({
189
+ ...voucher,
190
+ isValidated: true,
191
+ isValid: result.payload.isValid,
192
+ });
193
+ }
194
+ };
195
+
196
+ const handleAddVoucher: React.MouseEventHandler<HTMLButtonElement> = (
197
+ event
198
+ ) => {
199
+ if (!voucher.isValid) return;
200
+
201
+ dispatch(
202
+ setVoucherCodes(
203
+ [
204
+ ...(bookRequest?.payload.voucherCodes ?? []),
205
+ voucher.code ?? "",
206
+ ].filter((x) => x !== "")
207
+ )
208
+ );
209
+
210
+ dispatch(fetchPriceDetails());
211
+
212
+ setVoucher({});
213
+ };
214
+
215
+ const handleRemoveVoucher = (code: string) => {
216
+ dispatch(
217
+ setVoucherCodes(
218
+ bookRequest?.payload.voucherCodes?.filter((x) => x !== code) ?? []
219
+ )
220
+ );
221
+
222
+ dispatch(fetchPriceDetails());
223
+ };
224
+
92
225
  return (
93
- <form
94
- className="form"
95
- name="booking--step3"
96
- id="booking--step3"
97
- onSubmit={handleSubmit}
98
- >
99
- <div className="form__region">
100
- <div className="form__row">
101
- <div className="form__group">
102
- <div className="form__region-header">
103
- <h5 className="form__region-heading">
104
- {translations.STEPS.PERSONAL_DETAILS}
105
- </h5>
106
- <p className="form__region-label">
107
- {adultCount + childCount} {translations.SUMMARY.TRAVELERS}:{" "}
108
- {compact([
109
- adultCount && `${adultCount} volwassenen`,
110
- childCount && `${childCount} kinderen`,
111
- ]).join(", ")}
112
- </p>
226
+ <>
227
+ {isSubmitting && settings.loaderComponent}
228
+ {!isSubmitting && (
229
+ <form
230
+ className="form"
231
+ name="booking--step3"
232
+ id="booking--step3"
233
+ onSubmit={handleSubmit}
234
+ >
235
+ <div className="form__region">
236
+ <div className="form__row">
237
+ <div className="form__group">
238
+ <div className="form__region-header">
239
+ <h5 className="form__region-heading">
240
+ {translations.SUMMARY.PERSONAL_DETAILS}
241
+ </h5>
242
+ <p className="form__region-label">
243
+ {`${adults.length + children.length} ${
244
+ adults.length + children.length === 1
245
+ ? translations.SUMMARY.TRAVELER
246
+ : translations.SUMMARY.TRAVELERS
247
+ }: ${compact([
248
+ adults.length,
249
+ adults.length === 1 && ` ${translations.SUMMARY.ADULT}`,
250
+ adults.length > 1 && ` ${translations.SUMMARY.ADULTS}`,
251
+ adults &&
252
+ adults.length &&
253
+ children &&
254
+ children.length &&
255
+ ", ",
256
+ children.length,
257
+ children.length === 1 && ` ${translations.SUMMARY.CHILD}`,
258
+ children.length > 1 &&
259
+ ` ${translations.SUMMARY.CHILDREN}`,
260
+ ]).join("")}`}
261
+ </p>
262
+ </div>
263
+ </div>
113
264
  </div>
114
- </div>
115
- </div>
116
- <div className="form__row">
117
- {[...adults, ...children].map((traveler) => {
118
- const isMainBooker =
119
- traveler.id === travelerFormValues?.mainBookerId;
120
- return (
121
- <div className="form__group form__group--sm-50" key={traveler.id}>
122
- <ul className="list list--plain">
123
- <li className="list__item">
124
- <strong>
125
- {traveler.firstName} {traveler.lastName}
126
- </strong>{" "}
127
- {isMainBooker && (
128
- <em>({translations.TRAVELERS_FORM.MAIN_BOOKER})</em>
129
- )}
130
- </li>
131
- <li className="list__item">
132
- {traveler.birthDate.split("-").reverse().join("/")}
133
- </li>
134
- {isMainBooker && (
135
- <>
136
- <li className="list__item">{`${
137
- travelerFormValues?.street
138
- } ${compact([
139
- travelerFormValues?.houseNumber,
140
- travelerFormValues?.box,
141
- ]).join(" ")}, ${travelerFormValues?.zipCode} ${
142
- travelerFormValues?.place
143
- }`}</li>
265
+ <div className="form__row">
266
+ {[...adults, ...children].map((traveler) => {
267
+ const isMainBooker =
268
+ traveler.id === travelerFormValues?.mainBookerId;
269
+ return (
270
+ <div
271
+ className="form__group form__group--sm-50"
272
+ key={traveler.id}
273
+ >
274
+ <ul className="list list--plain">
144
275
  <li className="list__item">
145
- {travelerFormValues?.phone}
276
+ <strong>
277
+ {traveler.firstName} {traveler.lastName}
278
+ </strong>{" "}
279
+ {isMainBooker && (
280
+ <em>({translations.SUMMARY.MAIN_BOOKER})</em>
281
+ )}
146
282
  </li>
147
283
  <li className="list__item">
148
- {travelerFormValues?.email}
284
+ {traveler.birthDate.split("-").reverse().join("/")}
149
285
  </li>
150
- </>
286
+ {isMainBooker && (
287
+ <>
288
+ <li className="list__item">{`${
289
+ travelerFormValues?.street
290
+ } ${compact([
291
+ travelerFormValues?.houseNumber,
292
+ travelerFormValues?.box,
293
+ ]).join(" ")}, ${travelerFormValues?.zipCode} ${
294
+ travelerFormValues?.place
295
+ }`}</li>
296
+ <li className="list__item">
297
+ {travelerFormValues?.phone}
298
+ </li>
299
+ <li className="list__item">
300
+ {travelerFormValues?.email}
301
+ </li>
302
+ </>
303
+ )}
304
+ </ul>
305
+ </div>
306
+ );
307
+ })}
308
+ </div>
309
+ </div>
310
+
311
+ <div className="form__region">
312
+ <div className="form__row">
313
+ <div className="form__group">
314
+ <div className="form__region-header">
315
+ <h5 className="form__region-heading">
316
+ {translations.SUMMARY.OPTIONS}
317
+ </h5>
318
+ </div>
319
+ </div>
320
+ </div>
321
+ <div className="form__row">
322
+ <div className="form__group">
323
+ <ul className="list list--booking-summary">
324
+ <li>
325
+ <h6>{activeOption?.name}</h6>
326
+ <ul>
327
+ {activeOption?.rooms.map((r, ri) => {
328
+ const roomOption = r.options.find((x) => x.isSelected);
329
+ return (
330
+ <li key={ri} className="list__item">
331
+ {roomOption?.accommodationName}
332
+ {!isNil(roomOption?.regimeName) && ", "}
333
+ {roomOption?.regimeName}
334
+ </li>
335
+ );
336
+ })}
337
+ </ul>
338
+ <p>
339
+ ({getDateText(activeOption?.fromDate)} &gt;{" "}
340
+ {getDateText(activeOption?.toDate)})
341
+ </p>
342
+ </li>
343
+ {!isEmpty(activeOption?.groups) &&
344
+ activeOption?.groups.map((x, i) => {
345
+ if (!x.options.some((y) => y.isSelected)) return;
346
+
347
+ return <SummaryBookingOption key={i} group={x} />;
348
+ })}
349
+ {!isEmpty(activeOption?.optionUnits) &&
350
+ activeOption?.optionUnits.map((x) => (
351
+ <SummaryBookingOptionUnit unit={x} />
352
+ ))}
353
+ {!isEmpty(activeOption?.optionPax) &&
354
+ activeOption?.optionPax.map((x) => (
355
+ <SummaryBookingOptionPax pax={x} />
356
+ ))}
357
+ {packageDetails?.outwardFlights &&
358
+ packageDetails.outwardFlights
359
+ .filter((x) => x.isSelected)
360
+ .map((flight, i) => (
361
+ <SummaryFlight
362
+ key={i}
363
+ flight={flight}
364
+ header={translations.SIDEBAR.DEPARTURE_FLIGHT}
365
+ />
366
+ ))}
367
+ {packageDetails?.returnFlights &&
368
+ packageDetails.returnFlights
369
+ .filter((x) => x.isSelected)
370
+ .map((flight, i) => (
371
+ <SummaryFlight
372
+ key={i}
373
+ flight={flight}
374
+ header={translations.SIDEBAR.ARRIVAL_FLIGHT}
375
+ />
376
+ ))}
377
+ </ul>
378
+ </div>
379
+ </div>
380
+ </div>
381
+
382
+ {settings.enableVoucher && (
383
+ <div className="form__region">
384
+ <div className="form__row">
385
+ <div className="form__group">
386
+ <div className="form__region-header">
387
+ <h5 className="form__region-heading">
388
+ {translations.SUMMARY.VOUCHERS}
389
+ </h5>
390
+ </div>
391
+ </div>
392
+ </div>
393
+ <div className="form__row">
394
+ <div className="form__group">
395
+ <input
396
+ type="text"
397
+ className="form__input"
398
+ defaultValue={voucher.code}
399
+ onChange={(e) => setVoucher({ code: e.target.value })}
400
+ />
401
+ <button
402
+ type="button"
403
+ className={buildClassName([
404
+ "cta",
405
+ !voucher.code && "cta--disabled",
406
+ ])}
407
+ onClick={handleValidateVoucher}
408
+ >
409
+ {translations.SUMMARY.VOUCHER_VALIDATE}
410
+ </button>
411
+ </div>
412
+ </div>
413
+ <div className="form__row">
414
+ <div className="form__group">
415
+ {voucher.isValid && voucher.isValidated && (
416
+ <div className="info-message">
417
+ {translations.SUMMARY.VOUCHER_VALID}
418
+ <button
419
+ type="button"
420
+ className="cta"
421
+ onClick={handleAddVoucher}
422
+ >
423
+ {translations.SUMMARY.ADD_VOUCHER}
424
+ </button>
425
+ </div>
151
426
  )}
427
+ {!voucher.isValid && voucher.isValidated && (
428
+ <div className="info-message--error">
429
+ {translations.SUMMARY.VOUCHER_INVALID}
430
+ </div>
431
+ )}
432
+ </div>
433
+ </div>
434
+ <div className="form__row">
435
+ <ul>
436
+ {!isEmpty(bookRequest?.payload.voucherCodes) &&
437
+ bookRequest?.payload.voucherCodes?.map((y) => (
438
+ <li>
439
+ {y}{" "}
440
+ <button
441
+ type="button"
442
+ className="cat--add-remove"
443
+ onClick={(e) => handleRemoveVoucher(y)}
444
+ ></button>
445
+ </li>
446
+ ))}
152
447
  </ul>
153
448
  </div>
154
- );
155
- })}
156
- </div>
157
- </div>
158
-
159
- <div className="form__region">
160
- <div className="form__row">
161
- <div className="form__group">
162
- <div className="info-message">
163
- <Icon name="ui-tooltip" className="icon--secondary-color" />
164
- <div className="info-message__copy">
165
- <h5>{translations.SUMMARY.VALIDATE_TITLE}</h5>
166
- <p>{translations.SUMMARY.VALIDATE_TEXT}</p>
167
- <div className="checkbox">
168
- <label className="checkbox__label">
169
- <input
170
- type="checkbox"
171
- className="checkbox__input"
172
- checked={userValidated}
173
- onChange={(e) =>
174
- dispatch(setUserValidated(e.target.checked))
175
- }
176
- />
177
- <span className="checkbox__label-text">
178
- {translations.SUMMARY.VALIDATE_CONFIRM} *
179
- </span>
180
- </label>
449
+ </div>
450
+ )}
451
+
452
+ {!isEmpty(notifications) && (
453
+ <div className="form__region">
454
+ <div className="form__row">
455
+ <div className="form__group">
456
+ <div className="info-message">
457
+ <Icon name="ui-tooltip" className="icon--secondary-color" />
458
+ <div className="info-message__copy">
459
+ <h5>{translations.SUMMARY.NOTIFICATIONS_TITLE}</h5>
460
+ <>
461
+ {notifications
462
+ .filter((x) => !x.hasToBeConfirmed)
463
+ .map((notification) => (
464
+ <span
465
+ key={notification.id}
466
+ className="checkbox__label-text"
467
+ >
468
+ <strong className="checkbox__label-text--title">
469
+ {notification.title}
470
+ </strong>
471
+ <span className="checkbox__label-text--description">
472
+ {notification.description}
473
+ </span>
474
+ </span>
475
+ ))}
476
+ {notifications
477
+ .filter((x) => x.hasToBeConfirmed)
478
+ .map((notification) => (
479
+ <div className="checkbox" key={notification.id}>
480
+ <label className="checkbox__label">
481
+ <input
482
+ type="checkbox"
483
+ className="checkbox__input"
484
+ checked={notification.isConfirmed}
485
+ onChange={(e) =>
486
+ handleNotificationChange(
487
+ notification.id,
488
+ e.target.checked
489
+ )
490
+ }
491
+ />
492
+ <span className="checkbox__label-text">
493
+ <strong className="checkbox__label-text--title">
494
+ {notification.title}
495
+ </strong>
496
+ <span className="checkbox__label-text--description">
497
+ {notification.description}
498
+ </span>
499
+ </span>
500
+ </label>
501
+ </div>
502
+ ))}
503
+ </>
504
+ </div>
505
+ </div>
506
+ </div>
507
+ </div>
508
+ </div>
509
+ )}
510
+
511
+ <div className="form__region">
512
+ <div className="form__row">
513
+ <div className="form__group">
514
+ <div className="form__region-header">
515
+ <h5 className="form__region-heading">
516
+ {translations.SUMMARY.REMARKS}
517
+ </h5>
518
+ </div>
519
+ </div>
520
+ </div>
521
+ <div className="form__row">
522
+ <div className="form__group">
523
+ <textarea
524
+ className="form__input"
525
+ defaultValue={remarks}
526
+ onChange={(e) => handleRemarksChange(e.target.value)}
527
+ ></textarea>
528
+ </div>
529
+ </div>
530
+ </div>
531
+
532
+ <div className="form__region">
533
+ <div className="form__row">
534
+ <div className="form__group">
535
+ <div className="info-message">
536
+ <Icon name="ui-tooltip" className="icon--secondary-color" />
537
+ <div className="info-message__copy">
538
+ <h5>{translations.SUMMARY.VALIDATE_TITLE}</h5>
539
+ <p>{translations.SUMMARY.VALIDATE_TEXT}</p>
540
+ {checkboxes &&
541
+ checkboxes.map((checkbox) => (
542
+ <div className="checkbox" key={checkbox.id}>
543
+ <label className="checkbox__label">
544
+ <input
545
+ type="checkbox"
546
+ className="checkbox__input"
547
+ checked={checkbox.isSelected}
548
+ onChange={(e) =>
549
+ handleCheckboxChange(
550
+ checkbox.id,
551
+ e.target.checked
552
+ )
553
+ }
554
+ />
555
+ <span
556
+ className="checkbox__label-text"
557
+ dangerouslySetInnerHTML={{
558
+ __html: checkbox.text,
559
+ }}
560
+ />
561
+ </label>
562
+ </div>
563
+ ))}
564
+ </div>
181
565
  </div>
182
566
  </div>
183
567
  </div>
184
568
  </div>
185
- </div>
186
- </div>
187
-
188
- <div className="booking__navigator">
189
- <Link
190
- to={`${settings.basePath}${settings.optionsPathSuffix}?${bookingQueryString}`}
191
- title={translations.STEPS.PREVIOUS}
192
- className="cta cta--secondary"
193
- >
194
- {translations.STEPS.PREVIOUS}
195
- </Link>
196
- <button
197
- title="Bevestig boeking"
198
- className={buildClassName(["cta", !userValidated && "cta--disabled"])}
199
- disabled={!userValidated || isSubmitting}
200
- >
201
- {translations.STEPS.SUBMIT}
202
- </button>
203
- </div>
204
- </form>
569
+
570
+ <div className="booking__navigator">
571
+ <Link
572
+ to={`${settings.basePath}${settings.options.pathSuffix}?${bookingQueryString}`}
573
+ title={translations.STEPS.PREVIOUS}
574
+ className="cta cta--secondary"
575
+ >
576
+ {translations.STEPS.PREVIOUS}
577
+ </Link>
578
+ <button
579
+ title="Bevestig boeking"
580
+ className={buildClassName([
581
+ "cta",
582
+ !userValidated && "cta--disabled",
583
+ ])}
584
+ disabled={!userValidated}
585
+ >
586
+ {translations.STEPS.SUBMIT}
587
+ </button>
588
+ </div>
589
+ </form>
590
+ )}
591
+ </>
205
592
  );
206
593
  };
207
594