@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
@@ -0,0 +1,210 @@
1
+ import {
2
+ BookingOptionGroup,
3
+ BookingOptionPax,
4
+ BookingOptionUnit,
5
+ PerBookingPackageOption,
6
+ PerPackageOption,
7
+ } from "@qite/tide-client/build/types";
8
+ import { isEmpty } from "lodash";
9
+ import React from "react";
10
+ import { buildClassName } from "../../utils/class-util";
11
+ import NoneOption from "./none-option";
12
+ import OptionItem from "./option-item";
13
+ import OptionPaxCard from "./option-pax-card";
14
+ import OptionUnitsCard from "./option-units-card";
15
+
16
+ interface OptionBookingGroupProps {
17
+ optionId?: string;
18
+ group: BookingOptionGroup<PerBookingPackageOption>;
19
+ firstClassName: string;
20
+ secondClassName: string;
21
+ parentId: string;
22
+ onGroupChange?: (
23
+ group: BookingOptionGroup<PerBookingPackageOption>,
24
+ optionId?: string
25
+ ) => void;
26
+ }
27
+
28
+ const OptionBookingGroup: React.FC<OptionBookingGroupProps> = ({
29
+ optionId,
30
+ group,
31
+ firstClassName,
32
+ secondClassName,
33
+ parentId,
34
+ onGroupChange,
35
+ }) => {
36
+ const handleOptionChange = (option: PerPackageOption, index: number) => {
37
+ const updatedGroup = {
38
+ ...group,
39
+ options: group.options.map((o, i) => {
40
+ return i === index
41
+ ? option
42
+ : {
43
+ ...o,
44
+ isSelected: option.requirementType === 2 ? false : o.isSelected,
45
+ };
46
+ }),
47
+ } as BookingOptionGroup<PerBookingPackageOption>;
48
+
49
+ if (onGroupChange) onGroupChange(updatedGroup, optionId);
50
+ };
51
+
52
+ const handleChildGroupChange = (
53
+ childGroup: BookingOptionGroup<PerBookingPackageOption>,
54
+ optionId?: string
55
+ ) => {
56
+ const updatedGroup = {
57
+ ...group,
58
+ options: group.options.map((groupOption) => {
59
+ return groupOption.line.entryLineGuid === optionId
60
+ ? {
61
+ ...groupOption,
62
+ groups: groupOption.groups.map((optionGroup) => {
63
+ return optionGroup.name === childGroup.name
64
+ ? childGroup
65
+ : optionGroup;
66
+ }),
67
+ }
68
+ : groupOption;
69
+ }),
70
+ };
71
+
72
+ if (onGroupChange) onGroupChange(updatedGroup, optionId);
73
+ };
74
+
75
+ const handleOnPaxChange = (pax: BookingOptionPax[], index?: number) => {
76
+ const updatedGroup = {
77
+ ...group,
78
+ options: group.options.map((groupOption, i) => {
79
+ return {
80
+ ...groupOption,
81
+ pax: i === index ? pax : groupOption.pax,
82
+ };
83
+ }),
84
+ };
85
+
86
+ if (onGroupChange) onGroupChange(updatedGroup, optionId);
87
+ };
88
+
89
+ const handleOnUnitsChange = (units: BookingOptionUnit[], index?: number) => {
90
+ const updatedGroup = {
91
+ ...group,
92
+ options: group.options.map((groupOption, i) => {
93
+ return {
94
+ ...groupOption,
95
+ units: i === index ? units : groupOption.units,
96
+ };
97
+ }),
98
+ };
99
+
100
+ if (onGroupChange) onGroupChange(updatedGroup, optionId);
101
+ };
102
+
103
+ const handleNoneSelectionChanged = () => {
104
+ const updatedGroup = {
105
+ ...group,
106
+ options: group.options.map((groupOption) => ({
107
+ ...groupOption,
108
+ isSelected: false,
109
+ })),
110
+ };
111
+
112
+ if (onGroupChange) onGroupChange(updatedGroup, optionId);
113
+ };
114
+
115
+ const selectedPrice =
116
+ group.name === ""
117
+ ? 0
118
+ : group.options.find((x) => x.isSelected)?.line.price ?? 0;
119
+
120
+ return (
121
+ <div className={firstClassName}>
122
+ {group.title && <h4 className={secondClassName}>{group.title}</h4>}
123
+ <table className={buildClassName(["table", "table--striped"])}>
124
+ <tbody>
125
+ {group.options.map((option, index) => (
126
+ <tr key={option.line.entryLineGuid}>
127
+ <td>
128
+ <div
129
+ className={buildClassName([
130
+ "tree",
131
+ option.isSelected && "tree--selected",
132
+ ])}
133
+ >
134
+ <div className="tree__level">
135
+ <div className="tree__header">
136
+ <div className="tree__description-collapse">
137
+ <div
138
+ className={buildClassName([
139
+ (option.requirementType === 0 ||
140
+ option.requirementType === 1) &&
141
+ "checkbox",
142
+ option.requirementType === 2 && "radiobutton",
143
+ ])}
144
+ >
145
+ <label
146
+ htmlFor={`${parentId}_${index}`}
147
+ className={buildClassName([
148
+ (option.requirementType === 0 ||
149
+ option.requirementType === 1) &&
150
+ "checkbox__label",
151
+ option.requirementType === 2 &&
152
+ "radiobutton__label",
153
+ ])}
154
+ >
155
+ <OptionItem
156
+ option={option}
157
+ parentId={parentId}
158
+ index={index}
159
+ selectedPrice={selectedPrice}
160
+ onOptionChange={handleOptionChange}
161
+ />
162
+ {!isEmpty(option.groups) && (
163
+ <div className="tree__body">
164
+ {option.groups.map((optionGroup) => (
165
+ <OptionBookingGroup
166
+ optionId={option.line.entryLineGuid}
167
+ group={optionGroup}
168
+ firstClassName={"tree__level"}
169
+ secondClassName={"tree__level-heading"}
170
+ parentId={`${parentId}_${optionGroup.name}`}
171
+ onGroupChange={handleChildGroupChange}
172
+ />
173
+ ))}
174
+ </div>
175
+ )}
176
+ {!isEmpty(option.units) && (
177
+ <OptionUnitsCard
178
+ units={option.units}
179
+ parentIndex={index}
180
+ onUnitsChange={handleOnUnitsChange}
181
+ />
182
+ )}
183
+ {!isEmpty(option.pax) && (
184
+ <OptionPaxCard
185
+ pax={option.pax}
186
+ parentIndex={index}
187
+ onPaxChange={handleOnPaxChange}
188
+ />
189
+ )}
190
+ </label>
191
+ </div>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </td>
197
+ </tr>
198
+ ))}
199
+ <NoneOption
200
+ group={group}
201
+ parentId={parentId}
202
+ handleNoneSelectionChanged={handleNoneSelectionChanged}
203
+ />
204
+ </tbody>
205
+ </table>
206
+ </div>
207
+ );
208
+ };
209
+
210
+ export default OptionBookingGroup;
@@ -0,0 +1,321 @@
1
+ import {
2
+ BookingPackageLine,
3
+ PerPackageOption,
4
+ } from "@qite/tide-client/build/types";
5
+ import { compact, first, isEmpty, sortBy, uniqBy } from "lodash";
6
+ import React from "react";
7
+ import { buildClassName } from "../../utils/class-util";
8
+ import { formatPrice } from "../../utils/localization-util";
9
+ import { getDateText } from "../sidebar/sidebar-util";
10
+
11
+ interface OptionItemProps {
12
+ option: PerPackageOption;
13
+ parentId: string;
14
+ index: number;
15
+ selectedPrice: number;
16
+ onOptionChange?: (option: PerPackageOption, index: number) => void;
17
+ }
18
+
19
+ const OptionItem: React.FC<OptionItemProps> = ({
20
+ option,
21
+ parentId,
22
+ index,
23
+ selectedPrice,
24
+ onOptionChange,
25
+ }) => {
26
+ const priceDifference =
27
+ option.requirementType === 1
28
+ ? option.isSelected
29
+ ? -option.line.price
30
+ : option.line.price
31
+ : option.requirementType === 2
32
+ ? option.line.price - selectedPrice
33
+ : 0;
34
+
35
+ const accommodations = uniqBy(
36
+ compact(
37
+ [option.line, ...option.alternatives].map((option) => {
38
+ if (!option.accommodationCode) {
39
+ return undefined;
40
+ }
41
+
42
+ return {
43
+ accommodationCode: option.accommodationCode,
44
+ accommodationName: option.accommodationName,
45
+ };
46
+ })
47
+ ),
48
+ "accommodationCode"
49
+ );
50
+
51
+ const regimes = uniqBy(
52
+ compact(
53
+ [option.line, ...option.alternatives].map((option) => {
54
+ return {
55
+ regimeCode: option.regimeCode,
56
+ regimeName: option.regimeName,
57
+ };
58
+ })
59
+ ),
60
+ "regimeCode"
61
+ );
62
+
63
+ const handleAccommodationChange: React.FormEventHandler<HTMLSelectElement> = (
64
+ e
65
+ ) => {
66
+ const accommodationCode = e.currentTarget.value;
67
+
68
+ var accommodationAlternatives = option.alternatives.filter(
69
+ (x) => x.accommodationCode == accommodationCode
70
+ );
71
+
72
+ if (accommodationAlternatives) {
73
+ const alternative =
74
+ accommodationAlternatives.find(
75
+ (x) => x.regimeCode == option.line.regimeCode
76
+ ) ?? accommodationAlternatives[0];
77
+
78
+ updateOption(alternative);
79
+ }
80
+
81
+ e.preventDefault();
82
+ };
83
+
84
+ const handleRegimeChange: React.FormEventHandler<HTMLSelectElement> = (e) => {
85
+ const regimeCode = e.currentTarget.value;
86
+ const alternative = option.alternatives.find(
87
+ (x) =>
88
+ x.accommodationCode === option.line.accommodationCode &&
89
+ x.regimeCode == regimeCode
90
+ );
91
+
92
+ updateOption(alternative);
93
+
94
+ e.preventDefault();
95
+ };
96
+
97
+ const handleSelectionChange: React.FormEventHandler<HTMLInputElement> = (
98
+ e
99
+ ) => {
100
+ const updatedOption = {
101
+ ...option,
102
+ isSelected: e.currentTarget.checked,
103
+ };
104
+
105
+ // Bubble up option changes
106
+ if (onOptionChange) onOptionChange(updatedOption, index);
107
+ };
108
+
109
+ const updateOption = (alternative?: BookingPackageLine) => {
110
+ if (alternative) {
111
+ const updatedAlternatives = [option.line, ...option.alternatives]
112
+ .filter((x) => x != alternative)
113
+ .sort((x, y) => x.price - y.price);
114
+
115
+ const updatedOption = {
116
+ ...option,
117
+ line: alternative,
118
+ alternatives: updatedAlternatives,
119
+ };
120
+
121
+ // Bubble up option changes
122
+ if (onOptionChange) onOptionChange(updatedOption, index);
123
+ }
124
+ };
125
+
126
+ const getPriceDifferenceText = (price: number) => {
127
+ return price > 0
128
+ ? `+ ${formatPrice(Math.abs(price))}`
129
+ : `- ${formatPrice(Math.abs(price))}`;
130
+ };
131
+
132
+ const getAccommodationPriceDifference = (accommodation: {
133
+ accommodationCode: string;
134
+ accommodationName: string;
135
+ }) => {
136
+ if (option.line.accommodationCode === accommodation.accommodationCode)
137
+ return "";
138
+
139
+ var currentPrice = option.line.price;
140
+ var accommodationPrice = first(
141
+ sortBy(
142
+ option.alternatives.filter(
143
+ (x) => x.accommodationCode === accommodation.accommodationCode
144
+ ),
145
+ (x) => x.price
146
+ )
147
+ )?.price;
148
+
149
+ const priceDifference = (accommodationPrice ?? 0) - currentPrice;
150
+ if (priceDifference !== 0) {
151
+ return `(${getPriceDifferenceText(priceDifference)})`;
152
+ } else {
153
+ return "";
154
+ }
155
+ };
156
+
157
+ const getRegimePriceDifference = (regime: {
158
+ regimeCode: string;
159
+ regimeName: string;
160
+ }) => {
161
+ if (option.line.regimeCode === regime.regimeCode) return "";
162
+
163
+ var currentPrice = option.line.price;
164
+ var regimePrice = option.alternatives.find(
165
+ (x) =>
166
+ x.accommodationCode === option.line.accommodationCode &&
167
+ x.regimeCode === regime.regimeCode
168
+ )?.price;
169
+
170
+ const priceDifference = (regimePrice ?? 0) - currentPrice;
171
+ if (priceDifference !== 0) {
172
+ return `(${getPriceDifferenceText(priceDifference)})`;
173
+ } else {
174
+ return "";
175
+ }
176
+ };
177
+
178
+ return (
179
+ <>
180
+ {option.requirementType === 0 && (
181
+ <input
182
+ type="checkbox"
183
+ id={`${parentId}_${index}`}
184
+ className={buildClassName([
185
+ "checkbox__input",
186
+ "checkbox__input--parent",
187
+ ])}
188
+ defaultChecked={true}
189
+ disabled={true}
190
+ ></input>
191
+ )}
192
+ {option.requirementType === 1 && (
193
+ <input
194
+ type="checkbox"
195
+ id={`${parentId}_${index}`}
196
+ className={buildClassName([
197
+ "checkbox__input",
198
+ "checkbox__input--parent",
199
+ ])}
200
+ defaultChecked={option.isSelected}
201
+ onChange={handleSelectionChange}
202
+ ></input>
203
+ )}
204
+ {option.requirementType === 2 && (
205
+ <input
206
+ type="radio"
207
+ value={index}
208
+ id={`${parentId}_${index}`}
209
+ name={parentId}
210
+ className={buildClassName([
211
+ "radiobutton__input",
212
+ "radiobutton__input--parent",
213
+ ])}
214
+ defaultChecked={option.isSelected}
215
+ onChange={handleSelectionChange}
216
+ ></input>
217
+ )}
218
+ <span className="radiobutton__label-text">
219
+ <div className="date-list">
220
+ <span className="date-list__item">
221
+ {getDateText(option.line.startDate)}
222
+ </span>
223
+ <span className="date-list__item">
224
+ {getDateText(option.line.endDate)}
225
+ </span>
226
+ </div>
227
+ </span>
228
+ <div className="tree__columns-actions">
229
+ <div className="tree__columns">
230
+ <div className="tree__column">
231
+ <div className="tree__product-name">{option.line.productName}</div>
232
+ </div>
233
+ {isEmpty(option.alternatives) && (
234
+ <>
235
+ <div className="tree__column">
236
+ <span className="tree__product-name">
237
+ {option.line.accommodationName}
238
+ </span>
239
+ </div>
240
+ <div className="tree__column">
241
+ <span className="tree__product-name">
242
+ {option.line.regimeName}
243
+ </span>
244
+ </div>
245
+ </>
246
+ )}
247
+ {!isEmpty(option.alternatives) && (
248
+ <>
249
+ <div className="tree__column">
250
+ <div className="select-wrapper">
251
+ <div className="select-wrapper__select">
252
+ <select onChange={handleAccommodationChange}>
253
+ {accommodations.map((accommodation) => (
254
+ <option
255
+ defaultValue={option.line.accommodationCode}
256
+ key={accommodation.accommodationCode}
257
+ value={accommodation.accommodationCode}
258
+ >
259
+ {accommodation.accommodationName}{" "}
260
+ {getAccommodationPriceDifference(accommodation)}
261
+ </option>
262
+ ))}
263
+ </select>
264
+ </div>
265
+ </div>
266
+ </div>
267
+ <div className="tree__column">
268
+ <div className="select-wrapper">
269
+ {regimes?.length > 1 && (
270
+ <div className="select-wrapper__select">
271
+ <select
272
+ defaultValue={option.line.regimeCode}
273
+ onChange={handleRegimeChange}
274
+ >
275
+ {regimes.map((regime) => (
276
+ <option
277
+ key={regime.regimeCode}
278
+ value={regime.regimeCode}
279
+ >
280
+ {regime.regimeName}{" "}
281
+ {getRegimePriceDifference(regime)}
282
+ </option>
283
+ ))}
284
+ </select>
285
+ </div>
286
+ )}
287
+ {regimes.length === 1 && (
288
+ <>
289
+ {
290
+ regimes.find(
291
+ (x) => x.regimeCode == option.line.regimeCode
292
+ )?.regimeName
293
+ }
294
+ </>
295
+ )}
296
+ </div>
297
+ </div>
298
+ </>
299
+ )}
300
+ <div
301
+ className={buildClassName(["tree__column", "tree__column--price"])}
302
+ >
303
+ {!option.isSelected && (
304
+ <span
305
+ className={buildClassName([
306
+ "price",
307
+ priceDifference > 0 && "price--increase",
308
+ priceDifference < 0 && "price--decrease",
309
+ ])}
310
+ >
311
+ {getPriceDifferenceText(priceDifference)}
312
+ </span>
313
+ )}
314
+ </div>
315
+ </div>
316
+ </div>
317
+ </>
318
+ );
319
+ };
320
+
321
+ export default OptionItem;
@@ -0,0 +1,102 @@
1
+ import {
2
+ BookingOptionGroup,
3
+ BookingOptionPax,
4
+ PerPaxPackageOption,
5
+ } from "@qite/tide-client/build/types";
6
+ import React, { useEffect, useState } from "react";
7
+ import { useSelector } from "react-redux";
8
+ import { buildClassName } from "../../utils/class-util";
9
+ import { selectBookingPackagePax } from "../booking/selectors";
10
+ import OptionPaxGroup from "./option-pax-group";
11
+
12
+ interface OptionPaxCardProps {
13
+ pax: BookingOptionPax[];
14
+ parentIndex?: number;
15
+ onPaxChange?: (pax: BookingOptionPax[], index?: number) => void;
16
+ }
17
+
18
+ const OptionPaxCard: React.FC<OptionPaxCardProps> = ({
19
+ pax,
20
+ parentIndex,
21
+ onPaxChange,
22
+ }) => {
23
+ const [toggleStates, setToggleStates] = useState<boolean[]>();
24
+
25
+ useEffect(() => {
26
+ if (!toggleStates || toggleStates.length !== pax.length) {
27
+ setToggleStates(pax.map(() => true));
28
+ }
29
+ }, [pax, toggleStates, setToggleStates]);
30
+
31
+ const bookingPax = useSelector(selectBookingPackagePax);
32
+
33
+ const getPaxName = (id: number) => {
34
+ const item = bookingPax.find((x) => x.id === id);
35
+ return `${item?.firstName} ${item?.lastName}`;
36
+ };
37
+
38
+ const onGroupChange = (
39
+ group: BookingOptionGroup<PerPaxPackageOption>,
40
+ paxId: number
41
+ ) => {
42
+ const updatedPax = pax.map((p) => {
43
+ return p.id !== paxId
44
+ ? p
45
+ : {
46
+ ...p,
47
+ groups: p.groups.map((pg) => {
48
+ return pg.name !== group.name ? pg : group;
49
+ }),
50
+ };
51
+ });
52
+
53
+ if (onPaxChange) onPaxChange(updatedPax, parentIndex);
54
+ };
55
+
56
+ return (
57
+ <>
58
+ {pax.map((p, i) => (
59
+ <div
60
+ key={i}
61
+ className={buildClassName([
62
+ "booking-card__group",
63
+ toggleStates && toggleStates[i] && "booking-card__group--active",
64
+ ])}
65
+ >
66
+ <div className="booking-card__group-header">
67
+ <h3 className="booking-card__body-heading">{getPaxName(p.id)}</h3>
68
+ <div className="booking-card__actions">
69
+ <button
70
+ type="button"
71
+ className="booking-card__toggle"
72
+ onClick={() => {
73
+ setToggleStates(
74
+ toggleStates?.map((s, si) => (si == i ? !s : s))
75
+ );
76
+ }}
77
+ ></button>
78
+ </div>
79
+ </div>
80
+ {toggleStates &&
81
+ toggleStates[i] &&
82
+ p.groups.map(
83
+ (pg) =>
84
+ pg && (
85
+ <OptionPaxGroup
86
+ key={pg.name}
87
+ paxId={p.id}
88
+ group={pg}
89
+ firstClassName={"booking-card__group-body"}
90
+ secondClassName={"booking-card__group-heading"}
91
+ parentId={`${p.id}_${pg.name}`}
92
+ onGroupChange={onGroupChange}
93
+ />
94
+ )
95
+ )}
96
+ </div>
97
+ ))}
98
+ </>
99
+ );
100
+ };
101
+
102
+ export default OptionPaxCard;