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