@qite/tide-booking-component 1.3.1 → 1.3.3

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