@qite/tide-booking-component 1.3.2 → 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 +16332 -7414
  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 +15926 -7396
  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 -389
  212. package/src/booking-wizard/features/booking/booking-slice.ts +665 -663
  213. package/src/booking-wizard/features/booking/booking.tsx +361 -361
  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 -279
  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,754 +1,754 @@
1
- import { compact, get, sortBy } from "lodash";
2
- import React, { useContext, useEffect, useState } from "react";
3
- import { useSelector } from "react-redux";
4
- import { setCurrentStep } from "../booking/booking-slice";
5
- import {
6
- selectFormRooms,
7
- selectTravelersFormValues,
8
- setFormValues,
9
- } from "./travelers-form-slice";
10
-
11
- import { Link, navigate } from "@reach/router";
12
- import { format, parse } from "date-fns";
13
- import flat from "flat";
14
- import { useFormik } from "formik";
15
- import produce from "immer";
16
- import { buildClassName } from "../../../shared/utils/class-util";
17
- import LabeledInput from "../../components/labeled-input";
18
- import LabeledSelect from "../../components/labeled-select";
19
- import SettingsContext from "../../settings-context";
20
- import { useAppDispatch } from "../../store";
21
- import { TravelersFormValues } from "../../types";
22
- import { setBookingType } from "../booking/booking-slice";
23
- import { OPTIONS_FORM_STEP, SUMMARY_STEP } from "../booking/constants";
24
- import {
25
- selectAgentAdressId,
26
- selectAgents,
27
- selectBookingQueryString,
28
- selectBookingType,
29
- selectStartDate,
30
- selectTranslations,
31
- } from "../booking/selectors";
32
- import { fetchPriceDetails } from "../price-details/price-details-slice";
33
- import TypeAheadInput from "./type-ahead-input";
34
- import validateForm from "./validate-form";
35
-
36
- interface TravelersFormProps {}
37
-
38
- function createTraveler(id: number) {
39
- return { id, firstName: "", lastName: "", birthDate: "", gender: "" };
40
- }
41
-
42
- function createInitialValues(
43
- formRooms: { adults: number[]; children: number[] }[],
44
- startDate?: string,
45
- agentAdressId?: number
46
- ) {
47
- const initialValues = {
48
- startDate: startDate,
49
- rooms: formRooms.map((r) => ({
50
- adults: r.adults.map((id) => createTraveler(id)),
51
- children: r.children.map((id) => createTraveler(id)),
52
- })),
53
- mainBookerId: -1,
54
- street: "",
55
- houseNumber: "",
56
- box: "",
57
- zipCode: "",
58
- place: "",
59
- country: "",
60
- phone: "",
61
- email: "",
62
- emailConfirmation: "",
63
- travelAgentId: agentAdressId ?? 0,
64
- travelAgentName: "",
65
- };
66
-
67
- if (
68
- initialValues.rooms &&
69
- initialValues.rooms.length &&
70
- initialValues.rooms[0].adults &&
71
- initialValues.rooms[0].adults.length
72
- ) {
73
- initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
74
- }
75
-
76
- return initialValues;
77
- }
78
-
79
- const TravelersForm: React.FC<TravelersFormProps> = () => {
80
- const dispatch = useAppDispatch();
81
-
82
- const settings = useContext(SettingsContext);
83
- const bookingQueryString = useSelector(selectBookingQueryString);
84
- const startDate = useSelector(selectStartDate);
85
- const formRooms = useSelector(selectFormRooms);
86
- const bookingType = useSelector(selectBookingType);
87
- const agents = useSelector(selectAgents);
88
- const agentAdressId = useSelector(selectAgentAdressId);
89
- const translations = useSelector(selectTranslations);
90
-
91
- const initialValues =
92
- useSelector(selectTravelersFormValues) ??
93
- createInitialValues(formRooms, startDate, agentAdressId);
94
-
95
- const [showAgents, setShowAgents] = useState<boolean>(
96
- settings.agentRequired ?? false
97
- );
98
- const [showAgentSelection, setShowAgentSelection] = useState<boolean>(
99
- !settings.agentAdressId && !settings.hideAgentSelection
100
- );
101
-
102
- const typeaheadAgents =
103
- sortBy(
104
- agents?.map((x) => ({
105
- key: `${x.id}`,
106
- value: `${x.name} (${x.postalCode} ${x.location})`,
107
- text: `${x.name} (${x.postalCode} ${x.location})`,
108
- })),
109
- "value"
110
- ) ?? [];
111
-
112
- const [filteredAgents, setFilteredAgents] =
113
- useState<{ key: string; value: string; text: string }[]>(typeaheadAgents);
114
-
115
- const formik = useFormik<TravelersFormValues>({
116
- initialValues,
117
- validate: (values) =>
118
- validateForm(values, settings.agentRequired, bookingType, translations),
119
- onSubmit: (values) => {
120
- dispatch(setFormValues(values));
121
- dispatch(fetchPriceDetails());
122
-
123
- if (settings.skipRouter) {
124
- dispatch(setCurrentStep(SUMMARY_STEP));
125
- } else {
126
- navigate(
127
- `${settings.basePath}${settings.summary.pathSuffix}?${bookingQueryString}`
128
- );
129
- }
130
- },
131
- });
132
-
133
- useEffect(() => {
134
- dispatch(fetchPriceDetails());
135
- }, []);
136
-
137
- useEffect(() => {
138
- if (agents && settings.affiliateSlug) {
139
- const agent = agents.find(
140
- (x) => x.affiliateSlug && x.affiliateSlug === settings.affiliateSlug
141
- );
142
- if (!agent) return;
143
-
144
- const formValues = produce(formik.values, (values) => {
145
- (values.travelAgentId = Number(agent.id)),
146
- (values.travelAgentName = agent.name);
147
- });
148
- formik.setValues(formValues, false);
149
- dispatch(setFormValues(formValues));
150
- setShowAgentSelection(false);
151
- }
152
- }, [agents, settings.affiliateSlug]);
153
-
154
- const handleMainBookerChange: React.FormEventHandler<HTMLInputElement> = (
155
- e
156
- ) => {
157
- const id = parseInt(e.currentTarget.value);
158
-
159
- formik.setFieldValue("mainBookerId", id);
160
- };
161
-
162
- const mainBooker = formik.values.rooms
163
- .find((r) =>
164
- r.adults.find((traveler) => traveler.id === formik.values.mainBookerId)
165
- )
166
- ?.adults.find((traveler) => traveler.id === formik.values.mainBookerId);
167
-
168
- const handleAgentChange = (value: string) => {
169
- const filteredAgents = typeaheadAgents.filter(
170
- (x) => x.value.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) > -1
171
- );
172
-
173
- setFilteredAgents(filteredAgents);
174
- formik.setFieldValue("travelAgentName", value);
175
- };
176
-
177
- const handleAgentSelect = (key: string) => {
178
- const agent = typeaheadAgents.find((x) => x.key === key);
179
-
180
- formik.setValues({
181
- ...formik.values,
182
- travelAgentId: Number(agent?.key),
183
- travelAgentName: agent?.value ?? "",
184
- });
185
-
186
- let bookingType = "b2b2c";
187
- if (agentAdressId && agentAdressId != 0) {
188
- bookingType = "b2b";
189
- }
190
- dispatch(setBookingType(bookingType));
191
- };
192
-
193
- const handleAgentClear = () => {
194
- formik.setValues({
195
- ...formik.values,
196
- travelAgentId: 0,
197
- travelAgentName: "",
198
- });
199
-
200
- dispatch(setBookingType("b2c"));
201
- };
202
-
203
- const toggleAgent = (value: boolean) => {
204
- setShowAgents(value);
205
-
206
- if (!value) {
207
- handleAgentClear();
208
- setFilteredAgents([]);
209
- }
210
- };
211
-
212
- const goPrevious = () => {
213
- dispatch(setCurrentStep(OPTIONS_FORM_STEP));
214
- };
215
-
216
- const flatErrors: Record<string, string> = flat(formik.errors);
217
- const hasVisibleError = (key: string) =>
218
- get(formik.errors, key) && get(formik.touched, key);
219
-
220
- return (
221
- <form
222
- className="form form__travelers"
223
- name="booking--travellers"
224
- id="booking--travellers"
225
- noValidate
226
- onSubmit={formik.handleSubmit}
227
- onReset={formik.handleReset}
228
- >
229
- <div className="form__travelers__wrapper">
230
- {formik.values.rooms.map((room, rIndex) => (
231
- <div key={rIndex}>
232
- <div className="form__region">
233
- <div className="form__region-header">
234
- <h5 className="form__region-heading">
235
- {translations.SHARED.ROOM} {rIndex + 1}
236
- </h5>
237
- <p className="form__region-label">
238
- {compact([
239
- room.adults.length,
240
- room.adults.length === 1 &&
241
- ` ${translations.TRAVELERS_FORM.ADULT}`,
242
- room.adults.length > 1 &&
243
- ` ${translations.TRAVELERS_FORM.ADULTS}`,
244
- room.adults &&
245
- room.adults.length &&
246
- room.children &&
247
- room.children.length &&
248
- ", ",
249
- room.children.length,
250
- room.children.length === 1 &&
251
- ` ${translations.TRAVELERS_FORM.CHILD}`,
252
- room.children.length > 1 &&
253
- ` ${translations.TRAVELERS_FORM.CHILDREN}`,
254
- ]).join("")}
255
- </p>
256
- </div>
257
- </div>
258
- {room.adults.map((travelerValues, index) => (
259
- <div className="form__region" key={travelerValues.id}>
260
- <div className="form__region-header">
261
- <h5 className="form__region-heading">
262
- {translations.TRAVELERS_FORM.TRAVELER} {index + 1}
263
- </h5>
264
- <p className="form__region-label">
265
- {translations.TRAVELERS_FORM.ADULT}
266
- </p>
267
-
268
- <div className="radiobutton">
269
- <label className="radiobutton__label">
270
- <input
271
- type="radio"
272
- name="mainBookerId"
273
- onChange={handleMainBookerChange}
274
- onBlur={formik.handleBlur}
275
- value={travelerValues.id}
276
- checked={
277
- formik.values.mainBookerId === travelerValues.id
278
- }
279
- className="radiobutton__input"
280
- />
281
- {translations.TRAVELERS_FORM.MAIN_BOOKER}
282
- </label>
283
- </div>
284
- </div>
285
- <div className="form__row">
286
- <div
287
- className={buildClassName([
288
- "form__group",
289
- hasVisibleError(
290
- `rooms[${rIndex}].adults[${index}].gender`
291
- ) && "form__group--error",
292
- ])}
293
- >
294
- <label className="form__label">
295
- {translations.TRAVELERS_FORM.GENDER} *
296
- </label>
297
- <div className="radiobutton-group">
298
- <div className="radiobutton">
299
- <label className="radiobutton__label">
300
- <input
301
- type="radio"
302
- className="radiobutton__input"
303
- name={`rooms[${rIndex}].adults[${index}].gender`}
304
- onChange={formik.handleChange}
305
- onBlur={formik.handleBlur}
306
- value="m"
307
- checked={travelerValues.gender === "m"}
308
- />
309
- {translations.TRAVELERS_FORM.MALE}
310
- </label>
311
- </div>
312
-
313
- <div className="radiobutton">
314
- <label className="radiobutton__label">
315
- <input
316
- type="radio"
317
- className="radiobutton__input"
318
- name={`rooms[${rIndex}].adults[${index}].gender`}
319
- onChange={formik.handleChange}
320
- onBlur={formik.handleBlur}
321
- value="f"
322
- checked={travelerValues.gender === "f"}
323
- />
324
- {translations.TRAVELERS_FORM.FEMALE}
325
- </label>
326
- </div>
327
-
328
- <div className="radiobutton">
329
- <label className="radiobutton__label">
330
- <input
331
- type="radio"
332
- className="radiobutton__input"
333
- name={`rooms[${rIndex}].adults[${index}].gender`}
334
- onChange={formik.handleChange}
335
- onBlur={formik.handleBlur}
336
- value="x"
337
- checked={travelerValues.gender === "x"}
338
- />
339
- {translations.TRAVELERS_FORM.OTHER}
340
- </label>
341
- </div>
342
- </div>
343
- </div>
344
- </div>
345
- <div className="form__row">
346
- <LabeledInput
347
- hasError={hasVisibleError(
348
- `rooms[${rIndex}].adults[${index}].firstName`
349
- )}
350
- extraClassName="form__group--md-33"
351
- label={translations.TRAVELERS_FORM.FIRST_NAME}
352
- required
353
- name={`rooms[${rIndex}].adults[${index}].firstName`}
354
- onChange={formik.handleChange}
355
- onBlur={formik.handleBlur}
356
- value={travelerValues.firstName}
357
- />
358
- <LabeledInput
359
- hasError={hasVisibleError(
360
- `rooms[${rIndex}].adults[${index}].lastName`
361
- )}
362
- extraClassName="form__group--md-33"
363
- label={translations.TRAVELERS_FORM.LAST_NAME}
364
- required
365
- name={`rooms[${rIndex}].adults[${index}].lastName`}
366
- onChange={formik.handleChange}
367
- onBlur={formik.handleBlur}
368
- value={travelerValues.lastName}
369
- />
370
- <LabeledInput
371
- type="date"
372
- hasError={hasVisibleError(
373
- `rooms[${rIndex}].adults[${index}].birthDate`
374
- )}
375
- extraClassName="form__group--md-33"
376
- label={translations.TRAVELERS_FORM.BIRTHDATE}
377
- required
378
- name={`rooms[${rIndex}].adults[${index}].birthDate`}
379
- onChange={formik.handleChange}
380
- onBlur={formik.handleBlur}
381
- value={travelerValues.birthDate}
382
- />
383
- </div>
384
- </div>
385
- ))}
386
- {room.children.map((travelerValues, index) => (
387
- <div className="form__region" key={travelerValues.id}>
388
- <div className="form__region-header">
389
- <h5 className="form__region-heading">
390
- {translations.TRAVELERS_FORM.TRAVELER}{" "}
391
- {room.adults.length + index + 1}
392
- </h5>
393
- <p className="form__region-label">
394
- {translations.TRAVELERS_FORM.CHILD}
395
- </p>
396
- </div>
397
- <div className="form__row">
398
- <div
399
- className={buildClassName([
400
- "form__group",
401
- hasVisibleError(
402
- `rooms[${rIndex}].children[${index}].gender`
403
- ) && "form__group--error",
404
- ])}
405
- >
406
- <label className="form__label">
407
- {translations.TRAVELERS_FORM.GENDER} *
408
- </label>
409
- <div className="radiobutton-group">
410
- <div className="radiobutton">
411
- <label className="radiobutton__label">
412
- <input
413
- type="radio"
414
- className="radiobutton__input"
415
- name={`rooms[${rIndex}].children[${index}].gender`}
416
- onChange={formik.handleChange}
417
- onBlur={formik.handleBlur}
418
- value="m"
419
- checked={travelerValues.gender === "m"}
420
- />
421
- {translations.TRAVELERS_FORM.MALE}
422
- </label>
423
- </div>
424
-
425
- <div className="radiobutton">
426
- <label className="radiobutton__label">
427
- <input
428
- type="radio"
429
- className="radiobutton__input"
430
- name={`rooms[${rIndex}].children[${index}].gender`}
431
- onChange={formik.handleChange}
432
- onBlur={formik.handleBlur}
433
- value="f"
434
- checked={travelerValues.gender === "f"}
435
- />
436
- {translations.TRAVELERS_FORM.FEMALE}
437
- </label>
438
- </div>
439
-
440
- <div className="radiobutton">
441
- <label className="radiobutton__label">
442
- <input
443
- type="radio"
444
- className="radiobutton__input"
445
- name={`rooms[${rIndex}].children[${index}].gender`}
446
- onChange={formik.handleChange}
447
- onBlur={formik.handleBlur}
448
- value="x"
449
- checked={travelerValues.gender === "x"}
450
- />
451
- {translations.TRAVELERS_FORM.OTHER}
452
- </label>
453
- </div>
454
- </div>
455
- </div>
456
- </div>
457
- <div className="form__row">
458
- <LabeledInput
459
- hasError={hasVisibleError(
460
- `rooms[${rIndex}].children[${index}].firstName`
461
- )}
462
- extraClassName="form__group--md-33"
463
- label={translations.TRAVELERS_FORM.FIRST_NAME}
464
- required
465
- name={`rooms[${rIndex}].children[${index}].firstName`}
466
- onChange={formik.handleChange}
467
- onBlur={formik.handleBlur}
468
- value={travelerValues.firstName}
469
- />
470
- <LabeledInput
471
- hasError={hasVisibleError(
472
- `rooms[${rIndex}].children[${index}].lastName`
473
- )}
474
- extraClassName="form__group--md-33"
475
- label={translations.TRAVELERS_FORM.LAST_NAME}
476
- required
477
- name={`rooms[${rIndex}].children[${index}].lastName`}
478
- onChange={formik.handleChange}
479
- onBlur={formik.handleBlur}
480
- value={travelerValues.lastName}
481
- />
482
- <LabeledInput
483
- type="date"
484
- hasError={hasVisibleError(
485
- `rooms[${rIndex}].children[${index}].birthDate`
486
- )}
487
- extraClassName="form__group--md-33"
488
- label={translations.TRAVELERS_FORM.BIRTHDATE}
489
- required
490
- name={`rooms[${rIndex}].children[${index}].birthDate`}
491
- onChange={formik.handleChange}
492
- onBlur={formik.handleBlur}
493
- value={travelerValues.birthDate}
494
- />
495
- </div>
496
- </div>
497
- ))}
498
- </div>
499
- ))}
500
-
501
- {bookingType != "b2b" ? (
502
- <div className="form__region">
503
- <div className="form__region-header">
504
- <h5 className="form__region-heading">
505
- {translations.TRAVELERS_FORM.MAIN_BOOKER}
506
- </h5>
507
- <p className="form__region-label">
508
- {compact([
509
- compact([mainBooker?.firstName, mainBooker?.lastName]).join(
510
- " "
511
- ),
512
- mainBooker?.birthDate &&
513
- format(
514
- parse(mainBooker.birthDate, "yyyy-MM-dd", new Date()),
515
- "dd-MM-yyyy"
516
- ),
517
- ]).join(", ")}
518
- </p>
519
- </div>
520
- <>
521
- <div className="form__twocolumn">
522
- <div className="form__twocolumn-column">
523
- <div className="form__row">
524
- <LabeledInput
525
- hasError={hasVisibleError("street")}
526
- extraClassName="form__group--50 form__group--sm-60"
527
- label={translations.TRAVELERS_FORM.STREET}
528
- required
529
- name="street"
530
- onChange={formik.handleChange}
531
- onBlur={formik.handleBlur}
532
- value={formik.values.street}
533
- />
534
- <LabeledInput
535
- hasError={hasVisibleError("houseNumber")}
536
- extraClassName="form__group--30 form__group--sm-20"
537
- label={translations.TRAVELERS_FORM.HOUSE_NUMBER}
538
- required
539
- name="houseNumber"
540
- onChange={formik.handleChange}
541
- onBlur={formik.handleBlur}
542
- value={formik.values.houseNumber}
543
- />
544
- <LabeledInput
545
- hasError={hasVisibleError("box")}
546
- extraClassName="form__group--20"
547
- label={translations.TRAVELERS_FORM.POST_BOX}
548
- name="box"
549
- onChange={formik.handleChange}
550
- onBlur={formik.handleBlur}
551
- value={formik.values.box}
552
- />
553
- </div>
554
- </div>
555
- <div className="form__twocolumn-column">
556
- <div className="form__row">
557
- <LabeledInput
558
- hasError={hasVisibleError("zipCode")}
559
- extraClassName="form__group--40 form__group--sm-20"
560
- label={translations.TRAVELERS_FORM.ZIPCODE}
561
- required
562
- name="zipCode"
563
- onChange={formik.handleChange}
564
- onBlur={formik.handleBlur}
565
- value={formik.values.zipCode}
566
- />
567
- <LabeledInput
568
- hasError={hasVisibleError("place")}
569
- extraClassName="form__group--60 form__group--sm-40"
570
- label={translations.TRAVELERS_FORM.CITY}
571
- required
572
- name="place"
573
- onChange={formik.handleChange}
574
- onBlur={formik.handleBlur}
575
- value={formik.values.place}
576
- />
577
- <LabeledSelect
578
- hasError={hasVisibleError("country")}
579
- extraClassName="form__group--sm-40"
580
- label={translations.TRAVELERS_FORM.COUNTRY}
581
- required
582
- name="country"
583
- onChange={formik.handleChange}
584
- onBlur={formik.handleBlur}
585
- value={formik.values.country}
586
- options={[
587
- {
588
- key: "empty",
589
- label: translations.TRAVELERS_FORM.SELECT_COUNTRY,
590
- value: undefined,
591
- },
592
- {
593
- key: "be",
594
- value: "be",
595
- label: translations.TRAVELERS_FORM.COUNTRIES.BELGIUM,
596
- },
597
- {
598
- key: "nl",
599
- value: "nl",
600
- label:
601
- translations.TRAVELERS_FORM.COUNTRIES.NETHERLANDS,
602
- },
603
- {
604
- key: "fr",
605
- value: "fr",
606
- label: translations.TRAVELERS_FORM.COUNTRIES.FRANCE,
607
- },
608
- ]}
609
- />
610
- </div>
611
- </div>
612
- </div>
613
- <div className="form__row">
614
- <LabeledInput
615
- hasError={hasVisibleError("phone")}
616
- extraClassName="form__group--md-33"
617
- label={translations.TRAVELERS_FORM.PHONE}
618
- required
619
- name="phone"
620
- onChange={formik.handleChange}
621
- onBlur={formik.handleBlur}
622
- value={formik.values.phone}
623
- />
624
- <LabeledInput
625
- type="email"
626
- hasError={hasVisibleError("email")}
627
- extraClassName="form__group--md-33"
628
- label={translations.TRAVELERS_FORM.EMAIL}
629
- required
630
- name="email"
631
- onChange={formik.handleChange}
632
- onBlur={formik.handleBlur}
633
- value={formik.values.email}
634
- />
635
- <LabeledInput
636
- type="email"
637
- hasError={hasVisibleError("emailConfirmation")}
638
- extraClassName="form__group--md-33"
639
- label={translations.TRAVELERS_FORM.REPEAT_EMAIL}
640
- required
641
- name="emailConfirmation"
642
- onChange={formik.handleChange}
643
- onBlur={formik.handleBlur}
644
- value={formik.values.emailConfirmation}
645
- />
646
- </div>
647
- </>
648
- </div>
649
- ) : (
650
- <div className="form__region">
651
- <div className="form__row">
652
- <LabeledInput
653
- hasError={hasVisibleError("phone")}
654
- extraClassName="form__group--md-33"
655
- label={translations.TRAVELERS_FORM.PHONE}
656
- required
657
- name="phone"
658
- onChange={formik.handleChange}
659
- onBlur={formik.handleBlur}
660
- value={formik.values.phone}
661
- />
662
- </div>
663
- </div>
664
- )}
665
-
666
- {showAgentSelection && (
667
- <div className="form__region">
668
- <div className="form__region-header">
669
- <h5 className="form__region-heading">
670
- {translations.TRAVELERS_FORM.BOOK_WITH_AGENT}
671
- </h5>
672
- <div className="checkbox" id="cbxChooseOffice">
673
- <label className="checkbox__label">
674
- <input
675
- type="checkbox"
676
- name="booking--mainbooker"
677
- defaultChecked={showAgents}
678
- onClick={() => toggleAgent(!showAgents)}
679
- className="checkbox__input"
680
- />
681
- {translations.TRAVELERS_FORM.CHOOSE_OFFICE}
682
- </label>
683
- </div>
684
- </div>
685
- {showAgents && (
686
- <div className="form__row form__row--choose-office">
687
- <div
688
- className={buildClassName([
689
- "form__group",
690
- "form__group--icon",
691
- hasVisibleError("travelAgentId") && "form__group--error",
692
- ])}
693
- >
694
- <TypeAheadInput
695
- value={formik.values.travelAgentName}
696
- options={filteredAgents}
697
- onChange={handleAgentChange}
698
- onSelect={handleAgentSelect}
699
- onClear={handleAgentClear}
700
- name="travelAgentName"
701
- placeholder={
702
- translations.TRAVELERS_FORM.CHOOSE_AGENT_PLACEHOLDER
703
- }
704
- />
705
- </div>
706
- </div>
707
- )}
708
- </div>
709
- )}
710
- </div>
711
- {Object.keys(flatErrors).length > 0 && (
712
- <div className="form__region form__region--errors">
713
- <div className="form__row">
714
- <div className="form__group">
715
- <p className="form__error-heading">
716
- {translations.TRAVELERS_FORM.VALIDATION_MESSAGE}:
717
- </p>
718
- <ul className="list">
719
- {Object.keys(flatErrors).map((key) => (
720
- <li key={key}>{get(flatErrors, key)}</li>
721
- ))}
722
- </ul>
723
- </div>
724
- </div>
725
- </div>
726
- )}
727
- <div className="booking__navigator">
728
- {settings.skipRouter ? (
729
- <button
730
- type="button"
731
- title={translations.STEPS.PREVIOUS}
732
- onClick={() => goPrevious()}
733
- className="cta cta--secondary"
734
- >
735
- {translations.STEPS.PREVIOUS}
736
- </button>
737
- ) : (
738
- <Link
739
- to={`${settings.basePath}${settings.options.pathSuffix}?${bookingQueryString}`}
740
- title={translations.STEPS.PREVIOUS}
741
- className="cta cta--secondary"
742
- >
743
- {translations.STEPS.PREVIOUS}
744
- </Link>
745
- )}
746
- <button type="submit" title={translations.STEPS.NEXT} className="cta">
747
- {translations.STEPS.NEXT}
748
- </button>
749
- </div>
750
- </form>
751
- );
752
- };
753
-
754
- export default TravelersForm;
1
+ import { compact, get, sortBy } from "lodash";
2
+ import React, { useContext, useEffect, useState } from "react";
3
+ import { useSelector } from "react-redux";
4
+ import { setCurrentStep } from "../booking/booking-slice";
5
+ import {
6
+ selectFormRooms,
7
+ selectTravelersFormValues,
8
+ setFormValues,
9
+ } from "./travelers-form-slice";
10
+
11
+ import { Link, navigate } from "@reach/router";
12
+ import { format, parse } from "date-fns";
13
+ import flat from "flat";
14
+ import { useFormik } from "formik";
15
+ import produce from "immer";
16
+ import { buildClassName } from "../../../shared/utils/class-util";
17
+ import LabeledInput from "../../components/labeled-input";
18
+ import LabeledSelect from "../../components/labeled-select";
19
+ import SettingsContext from "../../settings-context";
20
+ import { useAppDispatch } from "../../store";
21
+ import { TravelersFormValues } from "../../types";
22
+ import { setBookingType } from "../booking/booking-slice";
23
+ import { OPTIONS_FORM_STEP, SUMMARY_STEP } from "../booking/constants";
24
+ import {
25
+ selectAgentAdressId,
26
+ selectAgents,
27
+ selectBookingQueryString,
28
+ selectBookingType,
29
+ selectStartDate,
30
+ selectTranslations,
31
+ } from "../booking/selectors";
32
+ import { fetchPriceDetails } from "../price-details/price-details-slice";
33
+ import TypeAheadInput from "./type-ahead-input";
34
+ import validateForm from "./validate-form";
35
+
36
+ interface TravelersFormProps {}
37
+
38
+ function createTraveler(id: number) {
39
+ return { id, firstName: "", lastName: "", birthDate: "", gender: "" };
40
+ }
41
+
42
+ function createInitialValues(
43
+ formRooms: { adults: number[]; children: number[] }[],
44
+ startDate?: string,
45
+ agentAdressId?: number
46
+ ) {
47
+ const initialValues = {
48
+ startDate: startDate,
49
+ rooms: formRooms.map((r) => ({
50
+ adults: r.adults.map((id) => createTraveler(id)),
51
+ children: r.children.map((id) => createTraveler(id)),
52
+ })),
53
+ mainBookerId: -1,
54
+ street: "",
55
+ houseNumber: "",
56
+ box: "",
57
+ zipCode: "",
58
+ place: "",
59
+ country: "",
60
+ phone: "",
61
+ email: "",
62
+ emailConfirmation: "",
63
+ travelAgentId: agentAdressId ?? 0,
64
+ travelAgentName: "",
65
+ };
66
+
67
+ if (
68
+ initialValues.rooms &&
69
+ initialValues.rooms.length &&
70
+ initialValues.rooms[0].adults &&
71
+ initialValues.rooms[0].adults.length
72
+ ) {
73
+ initialValues.mainBookerId = initialValues.rooms[0].adults[0].id;
74
+ }
75
+
76
+ return initialValues;
77
+ }
78
+
79
+ const TravelersForm: React.FC<TravelersFormProps> = () => {
80
+ const dispatch = useAppDispatch();
81
+
82
+ const settings = useContext(SettingsContext);
83
+ const bookingQueryString = useSelector(selectBookingQueryString);
84
+ const startDate = useSelector(selectStartDate);
85
+ const formRooms = useSelector(selectFormRooms);
86
+ const bookingType = useSelector(selectBookingType);
87
+ const agents = useSelector(selectAgents);
88
+ const agentAdressId = useSelector(selectAgentAdressId);
89
+ const translations = useSelector(selectTranslations);
90
+
91
+ const initialValues =
92
+ useSelector(selectTravelersFormValues) ??
93
+ createInitialValues(formRooms, startDate, agentAdressId);
94
+
95
+ const [showAgents, setShowAgents] = useState<boolean>(
96
+ settings.agentRequired ?? false
97
+ );
98
+ const [showAgentSelection, setShowAgentSelection] = useState<boolean>(
99
+ !settings.agentAdressId && !settings.hideAgentSelection
100
+ );
101
+
102
+ const typeaheadAgents =
103
+ sortBy(
104
+ agents?.map((x) => ({
105
+ key: `${x.id}`,
106
+ value: `${x.name} (${x.postalCode} ${x.location})`,
107
+ text: `${x.name} (${x.postalCode} ${x.location})`,
108
+ })),
109
+ "value"
110
+ ) ?? [];
111
+
112
+ const [filteredAgents, setFilteredAgents] =
113
+ useState<{ key: string; value: string; text: string }[]>(typeaheadAgents);
114
+
115
+ const formik = useFormik<TravelersFormValues>({
116
+ initialValues,
117
+ validate: (values) =>
118
+ validateForm(values, settings.agentRequired, bookingType, translations),
119
+ onSubmit: (values) => {
120
+ dispatch(setFormValues(values));
121
+ dispatch(fetchPriceDetails());
122
+
123
+ if (settings.skipRouter) {
124
+ dispatch(setCurrentStep(SUMMARY_STEP));
125
+ } else {
126
+ navigate(
127
+ `${settings.basePath}${settings.summary.pathSuffix}?${bookingQueryString}`
128
+ );
129
+ }
130
+ },
131
+ });
132
+
133
+ useEffect(() => {
134
+ dispatch(fetchPriceDetails());
135
+ }, []);
136
+
137
+ useEffect(() => {
138
+ if (agents && settings.affiliateSlug) {
139
+ const agent = agents.find(
140
+ (x) => x.affiliateSlug && x.affiliateSlug === settings.affiliateSlug
141
+ );
142
+ if (!agent) return;
143
+
144
+ const formValues = produce(formik.values, (values) => {
145
+ (values.travelAgentId = Number(agent.id)),
146
+ (values.travelAgentName = agent.name);
147
+ });
148
+ formik.setValues(formValues, false);
149
+ dispatch(setFormValues(formValues));
150
+ setShowAgentSelection(false);
151
+ }
152
+ }, [agents, settings.affiliateSlug]);
153
+
154
+ const handleMainBookerChange: React.FormEventHandler<HTMLInputElement> = (
155
+ e
156
+ ) => {
157
+ const id = parseInt(e.currentTarget.value);
158
+
159
+ formik.setFieldValue("mainBookerId", id);
160
+ };
161
+
162
+ const mainBooker = formik.values.rooms
163
+ .find((r) =>
164
+ r.adults.find((traveler) => traveler.id === formik.values.mainBookerId)
165
+ )
166
+ ?.adults.find((traveler) => traveler.id === formik.values.mainBookerId);
167
+
168
+ const handleAgentChange = (value: string) => {
169
+ const filteredAgents = typeaheadAgents.filter(
170
+ (x) => x.value.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) > -1
171
+ );
172
+
173
+ setFilteredAgents(filteredAgents);
174
+ formik.setFieldValue("travelAgentName", value);
175
+ };
176
+
177
+ const handleAgentSelect = (key: string) => {
178
+ const agent = typeaheadAgents.find((x) => x.key === key);
179
+
180
+ formik.setValues({
181
+ ...formik.values,
182
+ travelAgentId: Number(agent?.key),
183
+ travelAgentName: agent?.value ?? "",
184
+ });
185
+
186
+ let bookingType = "b2b2c";
187
+ if (agentAdressId && agentAdressId != 0) {
188
+ bookingType = "b2b";
189
+ }
190
+ dispatch(setBookingType(bookingType));
191
+ };
192
+
193
+ const handleAgentClear = () => {
194
+ formik.setValues({
195
+ ...formik.values,
196
+ travelAgentId: 0,
197
+ travelAgentName: "",
198
+ });
199
+
200
+ dispatch(setBookingType("b2c"));
201
+ };
202
+
203
+ const toggleAgent = (value: boolean) => {
204
+ setShowAgents(value);
205
+
206
+ if (!value) {
207
+ handleAgentClear();
208
+ setFilteredAgents([]);
209
+ }
210
+ };
211
+
212
+ const goPrevious = () => {
213
+ dispatch(setCurrentStep(OPTIONS_FORM_STEP));
214
+ };
215
+
216
+ const flatErrors: Record<string, string> = flat(formik.errors);
217
+ const hasVisibleError = (key: string) =>
218
+ get(formik.errors, key) && get(formik.touched, key);
219
+
220
+ return (
221
+ <form
222
+ className="form form__travelers"
223
+ name="booking--travellers"
224
+ id="booking--travellers"
225
+ noValidate
226
+ onSubmit={formik.handleSubmit}
227
+ onReset={formik.handleReset}
228
+ >
229
+ <div className="form__travelers__wrapper">
230
+ {formik.values.rooms.map((room, rIndex) => (
231
+ <div key={rIndex}>
232
+ <div className="form__region">
233
+ <div className="form__region-header">
234
+ <h5 className="form__region-heading">
235
+ {translations.SHARED.ROOM} {rIndex + 1}
236
+ </h5>
237
+ <p className="form__region-label">
238
+ {compact([
239
+ room.adults.length,
240
+ room.adults.length === 1 &&
241
+ ` ${translations.TRAVELERS_FORM.ADULT}`,
242
+ room.adults.length > 1 &&
243
+ ` ${translations.TRAVELERS_FORM.ADULTS}`,
244
+ room.adults &&
245
+ room.adults.length &&
246
+ room.children &&
247
+ room.children.length &&
248
+ ", ",
249
+ room.children.length,
250
+ room.children.length === 1 &&
251
+ ` ${translations.TRAVELERS_FORM.CHILD}`,
252
+ room.children.length > 1 &&
253
+ ` ${translations.TRAVELERS_FORM.CHILDREN}`,
254
+ ]).join("")}
255
+ </p>
256
+ </div>
257
+ </div>
258
+ {room.adults.map((travelerValues, index) => (
259
+ <div className="form__region" key={travelerValues.id}>
260
+ <div className="form__region-header">
261
+ <h5 className="form__region-heading">
262
+ {translations.TRAVELERS_FORM.TRAVELER} {index + 1}
263
+ </h5>
264
+ <p className="form__region-label">
265
+ {translations.TRAVELERS_FORM.ADULT}
266
+ </p>
267
+
268
+ <div className="radiobutton">
269
+ <label className="radiobutton__label">
270
+ <input
271
+ type="radio"
272
+ name="mainBookerId"
273
+ onChange={handleMainBookerChange}
274
+ onBlur={formik.handleBlur}
275
+ value={travelerValues.id}
276
+ checked={
277
+ formik.values.mainBookerId === travelerValues.id
278
+ }
279
+ className="radiobutton__input"
280
+ />
281
+ {translations.TRAVELERS_FORM.MAIN_BOOKER}
282
+ </label>
283
+ </div>
284
+ </div>
285
+ <div className="form__row">
286
+ <div
287
+ className={buildClassName([
288
+ "form__group",
289
+ hasVisibleError(
290
+ `rooms[${rIndex}].adults[${index}].gender`
291
+ ) && "form__group--error",
292
+ ])}
293
+ >
294
+ <label className="form__label">
295
+ {translations.TRAVELERS_FORM.GENDER} *
296
+ </label>
297
+ <div className="radiobutton-group">
298
+ <div className="radiobutton">
299
+ <label className="radiobutton__label">
300
+ <input
301
+ type="radio"
302
+ className="radiobutton__input"
303
+ name={`rooms[${rIndex}].adults[${index}].gender`}
304
+ onChange={formik.handleChange}
305
+ onBlur={formik.handleBlur}
306
+ value="m"
307
+ checked={travelerValues.gender === "m"}
308
+ />
309
+ {translations.TRAVELERS_FORM.MALE}
310
+ </label>
311
+ </div>
312
+
313
+ <div className="radiobutton">
314
+ <label className="radiobutton__label">
315
+ <input
316
+ type="radio"
317
+ className="radiobutton__input"
318
+ name={`rooms[${rIndex}].adults[${index}].gender`}
319
+ onChange={formik.handleChange}
320
+ onBlur={formik.handleBlur}
321
+ value="f"
322
+ checked={travelerValues.gender === "f"}
323
+ />
324
+ {translations.TRAVELERS_FORM.FEMALE}
325
+ </label>
326
+ </div>
327
+
328
+ <div className="radiobutton">
329
+ <label className="radiobutton__label">
330
+ <input
331
+ type="radio"
332
+ className="radiobutton__input"
333
+ name={`rooms[${rIndex}].adults[${index}].gender`}
334
+ onChange={formik.handleChange}
335
+ onBlur={formik.handleBlur}
336
+ value="x"
337
+ checked={travelerValues.gender === "x"}
338
+ />
339
+ {translations.TRAVELERS_FORM.OTHER}
340
+ </label>
341
+ </div>
342
+ </div>
343
+ </div>
344
+ </div>
345
+ <div className="form__row">
346
+ <LabeledInput
347
+ hasError={hasVisibleError(
348
+ `rooms[${rIndex}].adults[${index}].firstName`
349
+ )}
350
+ extraClassName="form__group--md-33"
351
+ label={translations.TRAVELERS_FORM.FIRST_NAME}
352
+ required
353
+ name={`rooms[${rIndex}].adults[${index}].firstName`}
354
+ onChange={formik.handleChange}
355
+ onBlur={formik.handleBlur}
356
+ value={travelerValues.firstName}
357
+ />
358
+ <LabeledInput
359
+ hasError={hasVisibleError(
360
+ `rooms[${rIndex}].adults[${index}].lastName`
361
+ )}
362
+ extraClassName="form__group--md-33"
363
+ label={translations.TRAVELERS_FORM.LAST_NAME}
364
+ required
365
+ name={`rooms[${rIndex}].adults[${index}].lastName`}
366
+ onChange={formik.handleChange}
367
+ onBlur={formik.handleBlur}
368
+ value={travelerValues.lastName}
369
+ />
370
+ <LabeledInput
371
+ type="date"
372
+ hasError={hasVisibleError(
373
+ `rooms[${rIndex}].adults[${index}].birthDate`
374
+ )}
375
+ extraClassName="form__group--md-33"
376
+ label={translations.TRAVELERS_FORM.BIRTHDATE}
377
+ required
378
+ name={`rooms[${rIndex}].adults[${index}].birthDate`}
379
+ onChange={formik.handleChange}
380
+ onBlur={formik.handleBlur}
381
+ value={travelerValues.birthDate}
382
+ />
383
+ </div>
384
+ </div>
385
+ ))}
386
+ {room.children.map((travelerValues, index) => (
387
+ <div className="form__region" key={travelerValues.id}>
388
+ <div className="form__region-header">
389
+ <h5 className="form__region-heading">
390
+ {translations.TRAVELERS_FORM.TRAVELER}{" "}
391
+ {room.adults.length + index + 1}
392
+ </h5>
393
+ <p className="form__region-label">
394
+ {translations.TRAVELERS_FORM.CHILD}
395
+ </p>
396
+ </div>
397
+ <div className="form__row">
398
+ <div
399
+ className={buildClassName([
400
+ "form__group",
401
+ hasVisibleError(
402
+ `rooms[${rIndex}].children[${index}].gender`
403
+ ) && "form__group--error",
404
+ ])}
405
+ >
406
+ <label className="form__label">
407
+ {translations.TRAVELERS_FORM.GENDER} *
408
+ </label>
409
+ <div className="radiobutton-group">
410
+ <div className="radiobutton">
411
+ <label className="radiobutton__label">
412
+ <input
413
+ type="radio"
414
+ className="radiobutton__input"
415
+ name={`rooms[${rIndex}].children[${index}].gender`}
416
+ onChange={formik.handleChange}
417
+ onBlur={formik.handleBlur}
418
+ value="m"
419
+ checked={travelerValues.gender === "m"}
420
+ />
421
+ {translations.TRAVELERS_FORM.MALE}
422
+ </label>
423
+ </div>
424
+
425
+ <div className="radiobutton">
426
+ <label className="radiobutton__label">
427
+ <input
428
+ type="radio"
429
+ className="radiobutton__input"
430
+ name={`rooms[${rIndex}].children[${index}].gender`}
431
+ onChange={formik.handleChange}
432
+ onBlur={formik.handleBlur}
433
+ value="f"
434
+ checked={travelerValues.gender === "f"}
435
+ />
436
+ {translations.TRAVELERS_FORM.FEMALE}
437
+ </label>
438
+ </div>
439
+
440
+ <div className="radiobutton">
441
+ <label className="radiobutton__label">
442
+ <input
443
+ type="radio"
444
+ className="radiobutton__input"
445
+ name={`rooms[${rIndex}].children[${index}].gender`}
446
+ onChange={formik.handleChange}
447
+ onBlur={formik.handleBlur}
448
+ value="x"
449
+ checked={travelerValues.gender === "x"}
450
+ />
451
+ {translations.TRAVELERS_FORM.OTHER}
452
+ </label>
453
+ </div>
454
+ </div>
455
+ </div>
456
+ </div>
457
+ <div className="form__row">
458
+ <LabeledInput
459
+ hasError={hasVisibleError(
460
+ `rooms[${rIndex}].children[${index}].firstName`
461
+ )}
462
+ extraClassName="form__group--md-33"
463
+ label={translations.TRAVELERS_FORM.FIRST_NAME}
464
+ required
465
+ name={`rooms[${rIndex}].children[${index}].firstName`}
466
+ onChange={formik.handleChange}
467
+ onBlur={formik.handleBlur}
468
+ value={travelerValues.firstName}
469
+ />
470
+ <LabeledInput
471
+ hasError={hasVisibleError(
472
+ `rooms[${rIndex}].children[${index}].lastName`
473
+ )}
474
+ extraClassName="form__group--md-33"
475
+ label={translations.TRAVELERS_FORM.LAST_NAME}
476
+ required
477
+ name={`rooms[${rIndex}].children[${index}].lastName`}
478
+ onChange={formik.handleChange}
479
+ onBlur={formik.handleBlur}
480
+ value={travelerValues.lastName}
481
+ />
482
+ <LabeledInput
483
+ type="date"
484
+ hasError={hasVisibleError(
485
+ `rooms[${rIndex}].children[${index}].birthDate`
486
+ )}
487
+ extraClassName="form__group--md-33"
488
+ label={translations.TRAVELERS_FORM.BIRTHDATE}
489
+ required
490
+ name={`rooms[${rIndex}].children[${index}].birthDate`}
491
+ onChange={formik.handleChange}
492
+ onBlur={formik.handleBlur}
493
+ value={travelerValues.birthDate}
494
+ />
495
+ </div>
496
+ </div>
497
+ ))}
498
+ </div>
499
+ ))}
500
+
501
+ {bookingType != "b2b" ? (
502
+ <div className="form__region">
503
+ <div className="form__region-header">
504
+ <h5 className="form__region-heading">
505
+ {translations.TRAVELERS_FORM.MAIN_BOOKER}
506
+ </h5>
507
+ <p className="form__region-label">
508
+ {compact([
509
+ compact([mainBooker?.firstName, mainBooker?.lastName]).join(
510
+ " "
511
+ ),
512
+ mainBooker?.birthDate &&
513
+ format(
514
+ parse(mainBooker.birthDate, "yyyy-MM-dd", new Date()),
515
+ "dd-MM-yyyy"
516
+ ),
517
+ ]).join(", ")}
518
+ </p>
519
+ </div>
520
+ <>
521
+ <div className="form__twocolumn">
522
+ <div className="form__twocolumn-column">
523
+ <div className="form__row">
524
+ <LabeledInput
525
+ hasError={hasVisibleError("street")}
526
+ extraClassName="form__group--50 form__group--sm-60"
527
+ label={translations.TRAVELERS_FORM.STREET}
528
+ required
529
+ name="street"
530
+ onChange={formik.handleChange}
531
+ onBlur={formik.handleBlur}
532
+ value={formik.values.street}
533
+ />
534
+ <LabeledInput
535
+ hasError={hasVisibleError("houseNumber")}
536
+ extraClassName="form__group--30 form__group--sm-20"
537
+ label={translations.TRAVELERS_FORM.HOUSE_NUMBER}
538
+ required
539
+ name="houseNumber"
540
+ onChange={formik.handleChange}
541
+ onBlur={formik.handleBlur}
542
+ value={formik.values.houseNumber}
543
+ />
544
+ <LabeledInput
545
+ hasError={hasVisibleError("box")}
546
+ extraClassName="form__group--20"
547
+ label={translations.TRAVELERS_FORM.POST_BOX}
548
+ name="box"
549
+ onChange={formik.handleChange}
550
+ onBlur={formik.handleBlur}
551
+ value={formik.values.box}
552
+ />
553
+ </div>
554
+ </div>
555
+ <div className="form__twocolumn-column">
556
+ <div className="form__row">
557
+ <LabeledInput
558
+ hasError={hasVisibleError("zipCode")}
559
+ extraClassName="form__group--40 form__group--sm-20"
560
+ label={translations.TRAVELERS_FORM.ZIPCODE}
561
+ required
562
+ name="zipCode"
563
+ onChange={formik.handleChange}
564
+ onBlur={formik.handleBlur}
565
+ value={formik.values.zipCode}
566
+ />
567
+ <LabeledInput
568
+ hasError={hasVisibleError("place")}
569
+ extraClassName="form__group--60 form__group--sm-40"
570
+ label={translations.TRAVELERS_FORM.CITY}
571
+ required
572
+ name="place"
573
+ onChange={formik.handleChange}
574
+ onBlur={formik.handleBlur}
575
+ value={formik.values.place}
576
+ />
577
+ <LabeledSelect
578
+ hasError={hasVisibleError("country")}
579
+ extraClassName="form__group--sm-40"
580
+ label={translations.TRAVELERS_FORM.COUNTRY}
581
+ required
582
+ name="country"
583
+ onChange={formik.handleChange}
584
+ onBlur={formik.handleBlur}
585
+ value={formik.values.country}
586
+ options={[
587
+ {
588
+ key: "empty",
589
+ label: translations.TRAVELERS_FORM.SELECT_COUNTRY,
590
+ value: undefined,
591
+ },
592
+ {
593
+ key: "be",
594
+ value: "be",
595
+ label: translations.TRAVELERS_FORM.COUNTRIES.BELGIUM,
596
+ },
597
+ {
598
+ key: "nl",
599
+ value: "nl",
600
+ label:
601
+ translations.TRAVELERS_FORM.COUNTRIES.NETHERLANDS,
602
+ },
603
+ {
604
+ key: "fr",
605
+ value: "fr",
606
+ label: translations.TRAVELERS_FORM.COUNTRIES.FRANCE,
607
+ },
608
+ ]}
609
+ />
610
+ </div>
611
+ </div>
612
+ </div>
613
+ <div className="form__row">
614
+ <LabeledInput
615
+ hasError={hasVisibleError("phone")}
616
+ extraClassName="form__group--md-33"
617
+ label={translations.TRAVELERS_FORM.PHONE}
618
+ required
619
+ name="phone"
620
+ onChange={formik.handleChange}
621
+ onBlur={formik.handleBlur}
622
+ value={formik.values.phone}
623
+ />
624
+ <LabeledInput
625
+ type="email"
626
+ hasError={hasVisibleError("email")}
627
+ extraClassName="form__group--md-33"
628
+ label={translations.TRAVELERS_FORM.EMAIL}
629
+ required
630
+ name="email"
631
+ onChange={formik.handleChange}
632
+ onBlur={formik.handleBlur}
633
+ value={formik.values.email}
634
+ />
635
+ <LabeledInput
636
+ type="email"
637
+ hasError={hasVisibleError("emailConfirmation")}
638
+ extraClassName="form__group--md-33"
639
+ label={translations.TRAVELERS_FORM.REPEAT_EMAIL}
640
+ required
641
+ name="emailConfirmation"
642
+ onChange={formik.handleChange}
643
+ onBlur={formik.handleBlur}
644
+ value={formik.values.emailConfirmation}
645
+ />
646
+ </div>
647
+ </>
648
+ </div>
649
+ ) : (
650
+ <div className="form__region">
651
+ <div className="form__row">
652
+ <LabeledInput
653
+ hasError={hasVisibleError("phone")}
654
+ extraClassName="form__group--md-33"
655
+ label={translations.TRAVELERS_FORM.PHONE}
656
+ required
657
+ name="phone"
658
+ onChange={formik.handleChange}
659
+ onBlur={formik.handleBlur}
660
+ value={formik.values.phone}
661
+ />
662
+ </div>
663
+ </div>
664
+ )}
665
+
666
+ {showAgentSelection && (
667
+ <div className="form__region">
668
+ <div className="form__region-header">
669
+ <h5 className="form__region-heading">
670
+ {translations.TRAVELERS_FORM.BOOK_WITH_AGENT}
671
+ </h5>
672
+ <div className="checkbox" id="cbxChooseOffice">
673
+ <label className="checkbox__label">
674
+ <input
675
+ type="checkbox"
676
+ name="booking--mainbooker"
677
+ defaultChecked={showAgents}
678
+ onClick={() => toggleAgent(!showAgents)}
679
+ className="checkbox__input"
680
+ />
681
+ {translations.TRAVELERS_FORM.CHOOSE_OFFICE}
682
+ </label>
683
+ </div>
684
+ </div>
685
+ {showAgents && (
686
+ <div className="form__row form__row--choose-office">
687
+ <div
688
+ className={buildClassName([
689
+ "form__group",
690
+ "form__group--icon",
691
+ hasVisibleError("travelAgentId") && "form__group--error",
692
+ ])}
693
+ >
694
+ <TypeAheadInput
695
+ value={formik.values.travelAgentName}
696
+ options={filteredAgents}
697
+ onChange={handleAgentChange}
698
+ onSelect={handleAgentSelect}
699
+ onClear={handleAgentClear}
700
+ name="travelAgentName"
701
+ placeholder={
702
+ translations.TRAVELERS_FORM.CHOOSE_AGENT_PLACEHOLDER
703
+ }
704
+ />
705
+ </div>
706
+ </div>
707
+ )}
708
+ </div>
709
+ )}
710
+ </div>
711
+ {Object.keys(flatErrors).length > 0 && (
712
+ <div className="form__region form__region--errors">
713
+ <div className="form__row">
714
+ <div className="form__group">
715
+ <p className="form__error-heading">
716
+ {translations.TRAVELERS_FORM.VALIDATION_MESSAGE}:
717
+ </p>
718
+ <ul className="list">
719
+ {Object.keys(flatErrors).map((key) => (
720
+ <li key={key}>{get(flatErrors, key)}</li>
721
+ ))}
722
+ </ul>
723
+ </div>
724
+ </div>
725
+ </div>
726
+ )}
727
+ <div className="booking__navigator">
728
+ {settings.skipRouter ? (
729
+ <button
730
+ type="button"
731
+ title={translations.STEPS.PREVIOUS}
732
+ onClick={() => goPrevious()}
733
+ className="cta cta--secondary"
734
+ >
735
+ {translations.STEPS.PREVIOUS}
736
+ </button>
737
+ ) : (
738
+ <Link
739
+ to={`${settings.basePath}${settings.options.pathSuffix}?${bookingQueryString}`}
740
+ title={translations.STEPS.PREVIOUS}
741
+ className="cta cta--secondary"
742
+ >
743
+ {translations.STEPS.PREVIOUS}
744
+ </Link>
745
+ )}
746
+ <button type="submit" title={translations.STEPS.NEXT} className="cta">
747
+ {translations.STEPS.NEXT}
748
+ </button>
749
+ </div>
750
+ </form>
751
+ );
752
+ };
753
+
754
+ export default TravelersForm;