@qite/tide-booking-component 0.0.2-preview.8 → 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 (177) hide show
  1. package/README.md +1 -0
  2. package/build/build-cjs/booking-wizard/components/icon.d.ts +7 -7
  3. package/build/build-cjs/booking-wizard/components/labeled-input.d.ts +18 -18
  4. package/build/build-cjs/booking-wizard/components/labeled-select.d.ts +21 -21
  5. package/build/build-cjs/booking-wizard/components/message.d.ts +9 -8
  6. package/build/build-cjs/booking-wizard/components/product-card.d.ts +8 -9
  7. package/build/build-cjs/booking-wizard/components/rating.d.ts +6 -6
  8. package/build/build-cjs/booking-wizard/components/step-indicator.d.ts +6 -6
  9. package/build/build-cjs/booking-wizard/components/step-route.d.ts +9 -9
  10. package/build/build-cjs/booking-wizard/features/booking/api.d.ts +21 -0
  11. package/build/build-cjs/booking-wizard/features/booking/booking-slice.d.ts +124 -18
  12. package/build/build-cjs/booking-wizard/features/booking/booking.d.ts +8 -9
  13. package/build/build-cjs/booking-wizard/features/booking/selectors.d.ts +208 -0
  14. package/build/build-cjs/booking-wizard/features/confirmation/confirmation.d.ts +4 -5
  15. package/build/build-cjs/booking-wizard/features/error/error.d.ts +4 -5
  16. package/build/build-cjs/booking-wizard/features/price-details/price-details-api.d.ts +12 -6
  17. package/build/build-cjs/booking-wizard/features/price-details/price-details-slice.d.ts +105 -10
  18. package/build/build-cjs/booking-wizard/features/price-details/util.d.ts +5 -0
  19. package/build/build-cjs/booking-wizard/features/product-options/no-options.d.ts +2 -0
  20. package/build/build-cjs/booking-wizard/features/product-options/none-option.d.ts +17 -0
  21. package/build/build-cjs/booking-wizard/features/product-options/option-booking-group.d.ts +18 -0
  22. package/build/build-cjs/booking-wizard/features/product-options/option-item.d.ts +11 -0
  23. package/build/build-cjs/booking-wizard/features/product-options/option-pax-card.d.ts +9 -0
  24. package/build/build-cjs/booking-wizard/features/product-options/option-pax-group.d.ts +20 -0
  25. package/build/build-cjs/booking-wizard/features/product-options/option-room.d.ts +16 -0
  26. package/build/build-cjs/booking-wizard/features/product-options/option-unit-group.d.ts +20 -0
  27. package/build/build-cjs/booking-wizard/features/product-options/option-units-card.d.ts +9 -0
  28. package/build/build-cjs/booking-wizard/features/product-options/options-form.d.ts +4 -5
  29. package/build/build-cjs/booking-wizard/features/product-options/validate-form.d.ts +2 -2
  30. package/build/build-cjs/booking-wizard/features/sidebar/index.d.ts +7 -3
  31. package/build/build-cjs/booking-wizard/features/sidebar/sidebar-flight.d.ts +8 -0
  32. package/build/build-cjs/booking-wizard/features/sidebar/sidebar-util.d.ts +28 -4
  33. package/build/build-cjs/booking-wizard/features/sidebar/sidebar.d.ts +29 -21
  34. package/build/build-cjs/booking-wizard/features/summary/summary-booking-option-pax.d.ts +7 -0
  35. package/build/build-cjs/booking-wizard/features/summary/summary-booking-option-unit.d.ts +7 -0
  36. package/build/build-cjs/booking-wizard/features/summary/summary-flight.d.ts +8 -0
  37. package/build/build-cjs/booking-wizard/features/summary/summary-per-booking-option-group.d.ts +10 -0
  38. package/build/build-cjs/booking-wizard/features/summary/summary-per-pax-option-group.d.ts +10 -0
  39. package/build/build-cjs/booking-wizard/features/summary/summary-per-unit-option-group.d.ts +10 -0
  40. package/build/build-cjs/booking-wizard/features/summary/summary-slice.d.ts +14 -17
  41. package/build/build-cjs/booking-wizard/features/summary/summary.d.ts +4 -5
  42. package/build/build-cjs/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +95 -45
  43. package/build/build-cjs/booking-wizard/features/travelers-form/travelers-form.d.ts +4 -5
  44. package/build/build-cjs/booking-wizard/features/travelers-form/type-ahead-input.d.ts +16 -15
  45. package/build/build-cjs/booking-wizard/features/travelers-form/validate-form.d.ts +7 -4
  46. package/build/build-cjs/booking-wizard/index.d.ts +12 -11
  47. package/build/build-cjs/booking-wizard/settings-context.d.ts +5 -6
  48. package/build/build-cjs/booking-wizard/store.d.ts +41 -25
  49. package/build/build-cjs/booking-wizard/types.d.ts +111 -59
  50. package/build/build-cjs/booking-wizard/utils/class-util.d.ts +1 -1
  51. package/build/build-cjs/booking-wizard/utils/localization-util.d.ts +1 -1
  52. package/build/build-cjs/booking-wizard/utils/query-string-util.d.ts +21 -2
  53. package/build/build-cjs/booking-wizard/utils/tide-api-utils.d.ts +2 -2
  54. package/build/build-cjs/index.d.ts +2 -2
  55. package/build/build-cjs/index.js +13642 -1886
  56. package/build/build-esm/booking-wizard/components/icon.d.ts +7 -7
  57. package/build/build-esm/booking-wizard/components/labeled-input.d.ts +18 -18
  58. package/build/build-esm/booking-wizard/components/labeled-select.d.ts +21 -21
  59. package/build/build-esm/booking-wizard/components/message.d.ts +9 -8
  60. package/build/build-esm/booking-wizard/components/product-card.d.ts +8 -9
  61. package/build/build-esm/booking-wizard/components/rating.d.ts +6 -6
  62. package/build/build-esm/booking-wizard/components/step-indicator.d.ts +6 -6
  63. package/build/build-esm/booking-wizard/components/step-route.d.ts +9 -9
  64. package/build/build-esm/booking-wizard/features/booking/api.d.ts +21 -0
  65. package/build/build-esm/booking-wizard/features/booking/booking-slice.d.ts +124 -18
  66. package/build/build-esm/booking-wizard/features/booking/booking.d.ts +8 -9
  67. package/build/build-esm/booking-wizard/features/booking/selectors.d.ts +208 -0
  68. package/build/build-esm/booking-wizard/features/confirmation/confirmation.d.ts +4 -5
  69. package/build/build-esm/booking-wizard/features/error/error.d.ts +4 -5
  70. package/build/build-esm/booking-wizard/features/price-details/price-details-api.d.ts +12 -6
  71. package/build/build-esm/booking-wizard/features/price-details/price-details-slice.d.ts +105 -10
  72. package/build/build-esm/booking-wizard/features/price-details/util.d.ts +5 -0
  73. package/build/build-esm/booking-wizard/features/product-options/no-options.d.ts +2 -0
  74. package/build/build-esm/booking-wizard/features/product-options/none-option.d.ts +17 -0
  75. package/build/build-esm/booking-wizard/features/product-options/option-booking-group.d.ts +18 -0
  76. package/build/build-esm/booking-wizard/features/product-options/option-item.d.ts +11 -0
  77. package/build/build-esm/booking-wizard/features/product-options/option-pax-card.d.ts +9 -0
  78. package/build/build-esm/booking-wizard/features/product-options/option-pax-group.d.ts +20 -0
  79. package/build/build-esm/booking-wizard/features/product-options/option-room.d.ts +16 -0
  80. package/build/build-esm/booking-wizard/features/product-options/option-unit-group.d.ts +20 -0
  81. package/build/build-esm/booking-wizard/features/product-options/option-units-card.d.ts +9 -0
  82. package/build/build-esm/booking-wizard/features/product-options/options-form.d.ts +4 -5
  83. package/build/build-esm/booking-wizard/features/product-options/validate-form.d.ts +2 -2
  84. package/build/build-esm/booking-wizard/features/sidebar/index.d.ts +7 -3
  85. package/build/build-esm/booking-wizard/features/sidebar/sidebar-flight.d.ts +8 -0
  86. package/build/build-esm/booking-wizard/features/sidebar/sidebar-util.d.ts +28 -4
  87. package/build/build-esm/booking-wizard/features/sidebar/sidebar.d.ts +29 -21
  88. package/build/build-esm/booking-wizard/features/summary/summary-booking-option-pax.d.ts +7 -0
  89. package/build/build-esm/booking-wizard/features/summary/summary-booking-option-unit.d.ts +7 -0
  90. package/build/build-esm/booking-wizard/features/summary/summary-flight.d.ts +8 -0
  91. package/build/build-esm/booking-wizard/features/summary/summary-per-booking-option-group.d.ts +10 -0
  92. package/build/build-esm/booking-wizard/features/summary/summary-per-pax-option-group.d.ts +10 -0
  93. package/build/build-esm/booking-wizard/features/summary/summary-per-unit-option-group.d.ts +10 -0
  94. package/build/build-esm/booking-wizard/features/summary/summary-slice.d.ts +14 -17
  95. package/build/build-esm/booking-wizard/features/summary/summary.d.ts +4 -5
  96. package/build/build-esm/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +95 -45
  97. package/build/build-esm/booking-wizard/features/travelers-form/travelers-form.d.ts +4 -5
  98. package/build/build-esm/booking-wizard/features/travelers-form/type-ahead-input.d.ts +16 -15
  99. package/build/build-esm/booking-wizard/features/travelers-form/validate-form.d.ts +7 -4
  100. package/build/build-esm/booking-wizard/index.d.ts +12 -11
  101. package/build/build-esm/booking-wizard/settings-context.d.ts +5 -6
  102. package/build/build-esm/booking-wizard/store.d.ts +41 -25
  103. package/build/build-esm/booking-wizard/types.d.ts +111 -59
  104. package/build/build-esm/booking-wizard/utils/class-util.d.ts +1 -1
  105. package/build/build-esm/booking-wizard/utils/localization-util.d.ts +1 -1
  106. package/build/build-esm/booking-wizard/utils/query-string-util.d.ts +21 -2
  107. package/build/build-esm/booking-wizard/utils/tide-api-utils.d.ts +2 -2
  108. package/build/build-esm/index.d.ts +2 -2
  109. package/build/build-esm/index.js +13478 -1875
  110. package/package.json +8 -4
  111. package/rollup.config.js +1 -6
  112. package/src/booking-wizard/components/message.tsx +14 -8
  113. package/src/booking-wizard/components/product-card.tsx +10 -39
  114. package/src/booking-wizard/components/step-indicator.tsx +1 -1
  115. package/src/booking-wizard/components/step-route.tsx +1 -1
  116. package/src/booking-wizard/features/booking/api.ts +44 -0
  117. package/src/booking-wizard/features/booking/booking-slice.ts +274 -40
  118. package/src/booking-wizard/features/booking/booking.tsx +193 -57
  119. package/src/booking-wizard/features/booking/selectors.ts +328 -0
  120. package/src/booking-wizard/features/confirmation/confirmation.tsx +22 -11
  121. package/src/booking-wizard/features/error/error.tsx +15 -2
  122. package/src/booking-wizard/features/price-details/price-details-api.ts +12 -6
  123. package/src/booking-wizard/features/price-details/price-details-slice.ts +80 -50
  124. package/src/booking-wizard/features/price-details/util.ts +135 -0
  125. package/src/booking-wizard/features/product-options/no-options.tsx +18 -0
  126. package/src/booking-wizard/features/product-options/none-option.tsx +118 -0
  127. package/src/booking-wizard/features/product-options/option-booking-group.tsx +210 -0
  128. package/src/booking-wizard/features/product-options/option-item.tsx +321 -0
  129. package/src/booking-wizard/features/product-options/option-pax-card.tsx +102 -0
  130. package/src/booking-wizard/features/product-options/option-pax-group.tsx +169 -0
  131. package/src/booking-wizard/features/product-options/option-room.tsx +300 -0
  132. package/src/booking-wizard/features/product-options/option-unit-group.tsx +192 -0
  133. package/src/booking-wizard/features/product-options/option-units-card.tsx +100 -0
  134. package/src/booking-wizard/features/product-options/options-form.tsx +226 -48
  135. package/src/booking-wizard/features/sidebar/index.tsx +43 -20
  136. package/src/booking-wizard/features/sidebar/sidebar-flight.tsx +66 -0
  137. package/src/booking-wizard/features/sidebar/sidebar-util.ts +81 -39
  138. package/src/booking-wizard/features/sidebar/sidebar.tsx +150 -100
  139. package/src/booking-wizard/features/summary/summary-booking-option-pax.tsx +25 -0
  140. package/src/booking-wizard/features/summary/summary-booking-option-unit.tsx +25 -0
  141. package/src/booking-wizard/features/summary/summary-flight.tsx +35 -0
  142. package/src/booking-wizard/features/summary/summary-per-booking-option-group.tsx +57 -0
  143. package/src/booking-wizard/features/summary/summary-per-pax-option-group.tsx +51 -0
  144. package/src/booking-wizard/features/summary/summary-per-unit-option-group.tsx +54 -0
  145. package/src/booking-wizard/features/summary/summary-slice.ts +1 -134
  146. package/src/booking-wizard/features/summary/summary.tsx +521 -134
  147. package/src/booking-wizard/features/travelers-form/travelers-form-slice.ts +55 -56
  148. package/src/booking-wizard/features/travelers-form/travelers-form.tsx +202 -94
  149. package/src/booking-wizard/features/travelers-form/type-ahead-input.tsx +23 -3
  150. package/src/booking-wizard/features/travelers-form/validate-form.ts +40 -3
  151. package/src/booking-wizard/index.tsx +5 -6
  152. package/src/booking-wizard/settings-context.ts +33 -5
  153. package/src/booking-wizard/store.ts +5 -4
  154. package/src/booking-wizard/translations/translations.json +95 -61
  155. package/src/booking-wizard/types.ts +67 -10
  156. package/src/booking-wizard/utils/query-string-util.ts +42 -0
  157. package/build/build-cjs/booking-wizard/features/product-options/checkbox.d.ts +0 -11
  158. package/build/build-cjs/booking-wizard/features/product-options/option-details.d.ts +0 -11
  159. package/build/build-cjs/booking-wizard/features/product-options/product-options-api.d.ts +0 -26
  160. package/build/build-cjs/booking-wizard/features/product-options/product-options-slice.d.ts +0 -37
  161. package/build/build-cjs/booking-wizard/features/product-options/radio-button.d.ts +0 -10
  162. package/build/build-cjs/booking-wizard/features/product-options/rooms-slice.d.ts +0 -12
  163. package/build/build-cjs/booking-wizard/features/product-options/tree-level.d.ts +0 -7
  164. package/build/build-esm/booking-wizard/features/product-options/checkbox.d.ts +0 -11
  165. package/build/build-esm/booking-wizard/features/product-options/option-details.d.ts +0 -11
  166. package/build/build-esm/booking-wizard/features/product-options/product-options-api.d.ts +0 -26
  167. package/build/build-esm/booking-wizard/features/product-options/product-options-slice.d.ts +0 -37
  168. package/build/build-esm/booking-wizard/features/product-options/radio-button.d.ts +0 -10
  169. package/build/build-esm/booking-wizard/features/product-options/rooms-slice.d.ts +0 -12
  170. package/build/build-esm/booking-wizard/features/product-options/tree-level.d.ts +0 -7
  171. package/src/booking-wizard/features/product-options/checkbox.tsx +0 -38
  172. package/src/booking-wizard/features/product-options/option-details.tsx +0 -65
  173. package/src/booking-wizard/features/product-options/product-options-api.ts +0 -148
  174. package/src/booking-wizard/features/product-options/product-options-slice.ts +0 -149
  175. package/src/booking-wizard/features/product-options/radio-button.tsx +0 -35
  176. package/src/booking-wizard/features/product-options/rooms-slice.ts +0 -28
  177. 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