@duffel/components 3.1.3 → 3.1.4

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 (330) hide show
  1. package/components/DuffelAncillaries/Card.d.ts +14 -0
  2. package/components/DuffelAncillaries/Counter.d.ts +10 -0
  3. package/components/DuffelAncillaries/DuffelAncillaries.d.ts +3 -0
  4. package/components/DuffelAncillaries/DuffelAncillariesCustomElement.d.ts +12 -0
  5. package/components/DuffelAncillaries/bags/BaggageSelectionCard.d.ts +11 -0
  6. package/components/DuffelAncillaries/bags/BaggageSelectionController.d.ts +13 -0
  7. package/components/DuffelAncillaries/bags/BaggageSelectionModal.d.ts +11 -0
  8. package/components/DuffelAncillaries/bags/BaggageSelectionModalBody.d.ts +11 -0
  9. package/components/DuffelAncillaries/bags/BaggageSelectionModalBodyPassenger.d.ts +13 -0
  10. package/components/DuffelAncillaries/bags/BaggageSelectionModalFooter.d.ts +14 -0
  11. package/components/DuffelAncillaries/bags/BaggageSelectionModalHeader.d.ts +9 -0
  12. package/components/DuffelAncillaries/bags/IncludedBaggageBanner.d.ts +7 -0
  13. package/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionCard.d.ts +10 -0
  14. package/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModal.d.ts +11 -0
  15. package/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModalBody.d.ts +7 -0
  16. package/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModalBodyListItem.d.ts +4 -0
  17. package/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModalFooter.d.ts +11 -0
  18. package/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModalHeader.d.ts +2 -0
  19. package/components/DuffelAncillaries/seats/Amenity.d.ts +6 -0
  20. package/components/DuffelAncillaries/seats/DeckSelect.d.ts +15 -0
  21. package/components/DuffelAncillaries/seats/Element.d.ts +15 -0
  22. package/components/DuffelAncillaries/seats/EmptyElement.d.ts +2 -0
  23. package/components/DuffelAncillaries/seats/ExitElement.d.ts +6 -0
  24. package/components/DuffelAncillaries/seats/Legend.d.ts +12 -0
  25. package/components/DuffelAncillaries/seats/Row.d.ts +13 -0
  26. package/components/DuffelAncillaries/seats/RowSection.d.ts +17 -0
  27. package/components/DuffelAncillaries/seats/SeatElement.d.ts +13 -0
  28. package/components/DuffelAncillaries/seats/SeatInfo.d.ts +7 -0
  29. package/components/DuffelAncillaries/seats/SeatMap.d.ts +12 -0
  30. package/components/DuffelAncillaries/seats/SeatMapUnavailable.d.ts +2 -0
  31. package/components/DuffelAncillaries/seats/SeatSelectionCard.d.ts +13 -0
  32. package/components/DuffelAncillaries/seats/SeatSelectionModal.d.ts +13 -0
  33. package/components/DuffelAncillaries/seats/SeatSelectionModalBody.d.ts +4 -0
  34. package/components/DuffelAncillaries/seats/SeatSelectionModalFooter.d.ts +16 -0
  35. package/components/DuffelAncillaries/seats/SeatSelectionModalHeader.d.ts +10 -0
  36. package/components/DuffelAncillaries/seats/SeatUnavailable.d.ts +5 -0
  37. package/components/DuffelPayments/DuffelPayments.d.ts +11 -0
  38. package/components/DuffelPayments/DuffelPaymentsCustomElement.d.ts +13 -0
  39. package/components/PlacesLookup/PlacesLookup.d.ts +20 -0
  40. package/components/shared/AnimatedLoaderEllipsis.d.ts +2 -0
  41. package/components/shared/Button.d.ts +23 -0
  42. package/components/shared/ErrorBoundary.d.ts +13 -0
  43. package/components/shared/FetchOfferErrorState.d.ts +5 -0
  44. package/components/shared/Icon.d.ts +46 -0
  45. package/components/shared/IconButton.d.ts +16 -0
  46. package/components/shared/Modal.d.ts +11 -0
  47. package/components/shared/NonIdealState.d.ts +4 -0
  48. package/components/shared/Stamp.d.ts +7 -0
  49. package/components/shared/Tabs.d.ts +16 -0
  50. package/custom-elements.d.ts +6 -0
  51. package/custom-elements.js +40 -0
  52. package/custom-elements.js.map +7 -0
  53. package/index.js +40 -0
  54. package/index.js.map +7 -0
  55. package/lib/captureErrorInSentry.d.ts +1 -0
  56. package/lib/compileCreateOrderPayload.d.ts +14 -0
  57. package/lib/createPriceFormatters.d.ts +12 -0
  58. package/lib/fetchFromDuffelAPI.d.ts +8 -0
  59. package/lib/fetchFromFixtures.d.ts +4 -0
  60. package/lib/formatAvailableServices.d.ts +12 -0
  61. package/lib/formatDate.d.ts +2 -0
  62. package/lib/formatSeatMaps.d.ts +4 -0
  63. package/lib/getBaggageServiceDescription.d.ts +2 -0
  64. package/lib/getCabinsForSegmentAndDeck.d.ts +2 -0
  65. package/lib/getCurrencyForSeatMaps.d.ts +10 -0
  66. package/lib/getCurrencyForServices.d.ts +11 -0
  67. package/lib/getFirstSeatElementMatchingCriteria.d.ts +3 -0
  68. package/lib/getPassengerBySegmentList.d.ts +6 -0
  69. package/lib/getPassengerInitials.d.ts +1 -0
  70. package/lib/getPassengerMapById.d.ts +3 -0
  71. package/lib/getPassengerName.d.ts +3 -0
  72. package/lib/getRowNumber.d.ts +2 -0
  73. package/lib/getSegmentList.d.ts +2 -0
  74. package/lib/getServicePriceMapById.d.ts +3 -0
  75. package/lib/getSymbols.d.ts +2 -0
  76. package/lib/getTotalAmountForServices.d.ts +6 -0
  77. package/lib/getTotalQuantity.d.ts +2 -0
  78. package/lib/hasHighLuminance.d.ts +1 -0
  79. package/lib/hasService.d.ts +2 -0
  80. package/lib/hasServiceOfSameMetadataTypeAlreadyBeenSelected.d.ts +3 -0
  81. package/lib/hasWings.d.ts +2 -0
  82. package/lib/isBaggageService.d.ts +2 -0
  83. package/lib/isCancelForAnyReasonService.d.ts +2 -0
  84. package/lib/isFixtureOfferId.d.ts +2 -0
  85. package/lib/isPayloadComplete.d.ts +2 -0
  86. package/lib/isSeatElement.d.ts +2 -0
  87. package/lib/logging.d.ts +46 -0
  88. package/lib/moneyStringFormatter.d.ts +8 -0
  89. package/lib/offerIsExpired.d.ts +2 -0
  90. package/lib/retrieveOffer.d.ts +2 -0
  91. package/lib/retrieveOfferFromDuffelAPI.d.ts +1 -0
  92. package/lib/retrieveSeatMaps.d.ts +2 -0
  93. package/lib/retrieveSeatMapsFromDuffelAPI.d.ts +1 -0
  94. package/lib/setBodyScrollability.d.ts +1 -0
  95. package/lib/validateProps.d.ts +7 -0
  96. package/lib/withPlural.d.ts +1 -0
  97. package/package.json +84 -134
  98. package/tsconfig.tsbuildinfo +1 -0
  99. package/types/Aircraft.d.ts +14 -0
  100. package/types/Airline.d.ts +14 -0
  101. package/types/Airport.d.ts +44 -0
  102. package/types/City.d.ts +18 -0
  103. package/types/CreateOrderPayload.d.ts +72 -0
  104. package/types/CurrencyConversion.d.ts +10 -0
  105. package/types/DuffelAncillariesProps.d.ts +70 -0
  106. package/types/Offer.d.ts +711 -0
  107. package/types/Order.d.ts +8 -0
  108. package/types/Place.d.ts +8 -0
  109. package/types/SeatMap.d.ts +190 -0
  110. package/.circleci/config.yml +0 -67
  111. package/.eslintrc.js +0 -47
  112. package/.github/CODEOWNERS +0 -4
  113. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -29
  114. package/.github/renovate.json +0 -12
  115. package/.github/workflows/autoapprove.yml +0 -18
  116. package/.github/workflows/release.yml +0 -89
  117. package/.husky/post-commit +0 -4
  118. package/.husky/pre-commit +0 -4
  119. package/.nvmrc +0 -1
  120. package/.prettierignore +0 -2
  121. package/.storybook/Storyshots.test.js +0 -3
  122. package/.storybook/__snapshots__/Storyshots.test.js.snap +0 -67984
  123. package/.storybook/main.ts +0 -33
  124. package/.storybook/preview.tsx +0 -28
  125. package/.tool-versions +0 -1
  126. package/CONTRIBUTING.md +0 -83
  127. package/README.md +0 -68
  128. package/__mocks__/styleMock.js +0 -6
  129. package/babel.config.js +0 -20
  130. package/commitlint.config.js +0 -4
  131. package/config/esbuild.base.config.js +0 -18
  132. package/config/esbuild.cdn.config.js +0 -51
  133. package/config/esbuild.dev.config.js +0 -46
  134. package/config/esbuild.react.config.js +0 -42
  135. package/data/airports.csv +0 -9084
  136. package/data/cities.csv +0 -256
  137. package/jest.config.ts +0 -14
  138. package/react-dist/index.js +0 -37
  139. package/scripts/generate-fixture.ts +0 -200
  140. package/scripts/setup-suggestion-data.ts +0 -100
  141. package/scripts/upload-to-cdn.sh +0 -34
  142. package/scripts.tsconfig.json +0 -11
  143. package/src/components/DuffelAncillaries/Card.tsx +0 -126
  144. package/src/components/DuffelAncillaries/Counter.tsx +0 -40
  145. package/src/components/DuffelAncillaries/DuffelAncillaries.tsx +0 -350
  146. package/src/components/DuffelAncillaries/DuffelAncillariesCustomElement.tsx +0 -124
  147. package/src/components/DuffelAncillaries/bags/BaggageSelectionCard.tsx +0 -101
  148. package/src/components/DuffelAncillaries/bags/BaggageSelectionController.tsx +0 -88
  149. package/src/components/DuffelAncillaries/bags/BaggageSelectionModal.tsx +0 -81
  150. package/src/components/DuffelAncillaries/bags/BaggageSelectionModalBody.tsx +0 -60
  151. package/src/components/DuffelAncillaries/bags/BaggageSelectionModalBodyPassenger.tsx +0 -122
  152. package/src/components/DuffelAncillaries/bags/BaggageSelectionModalFooter.tsx +0 -88
  153. package/src/components/DuffelAncillaries/bags/BaggageSelectionModalHeader.tsx +0 -82
  154. package/src/components/DuffelAncillaries/bags/IncludedBaggageBanner.tsx +0 -51
  155. package/src/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionCard.tsx +0 -90
  156. package/src/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModal.tsx +0 -63
  157. package/src/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModalBody.tsx +0 -56
  158. package/src/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModalBodyListItem.tsx +0 -11
  159. package/src/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModalFooter.tsx +0 -74
  160. package/src/components/DuffelAncillaries/cancel_for_any_reason/CfarSelectionModalHeader.tsx +0 -9
  161. package/src/components/DuffelAncillaries/seats/Amenity.tsx +0 -21
  162. package/src/components/DuffelAncillaries/seats/DeckSelect.tsx +0 -27
  163. package/src/components/DuffelAncillaries/seats/Element.tsx +0 -52
  164. package/src/components/DuffelAncillaries/seats/EmptyElement.tsx +0 -5
  165. package/src/components/DuffelAncillaries/seats/ExitElement.tsx +0 -17
  166. package/src/components/DuffelAncillaries/seats/Legend.tsx +0 -60
  167. package/src/components/DuffelAncillaries/seats/Row.tsx +0 -47
  168. package/src/components/DuffelAncillaries/seats/RowSection.tsx +0 -78
  169. package/src/components/DuffelAncillaries/seats/SeatElement.tsx +0 -120
  170. package/src/components/DuffelAncillaries/seats/SeatInfo.tsx +0 -32
  171. package/src/components/DuffelAncillaries/seats/SeatMap.tsx +0 -85
  172. package/src/components/DuffelAncillaries/seats/SeatMapUnavailable.tsx +0 -21
  173. package/src/components/DuffelAncillaries/seats/SeatSelectionCard.tsx +0 -103
  174. package/src/components/DuffelAncillaries/seats/SeatSelectionModal.tsx +0 -142
  175. package/src/components/DuffelAncillaries/seats/SeatSelectionModalBody.tsx +0 -13
  176. package/src/components/DuffelAncillaries/seats/SeatSelectionModalFooter.tsx +0 -89
  177. package/src/components/DuffelAncillaries/seats/SeatSelectionModalHeader.tsx +0 -97
  178. package/src/components/DuffelAncillaries/seats/SeatUnavailable.tsx +0 -14
  179. package/src/components/DuffelPayments/DuffelPayments.tsx +0 -224
  180. package/src/components/DuffelPayments/DuffelPaymentsCustomElement.tsx +0 -130
  181. package/src/components/PlacesLookup/PlacesLookup.tsx +0 -123
  182. package/src/components/shared/AnimatedLoaderEllipsis.tsx +0 -5
  183. package/src/components/shared/Button.tsx +0 -63
  184. package/src/components/shared/ErrorBoundary.tsx +0 -54
  185. package/src/components/shared/FetchOfferErrorState.tsx +0 -35
  186. package/src/components/shared/Icon.tsx +0 -151
  187. package/src/components/shared/IconButton.tsx +0 -42
  188. package/src/components/shared/Modal.tsx +0 -40
  189. package/src/components/shared/NonIdealState.tsx +0 -28
  190. package/src/components/shared/Stamp.tsx +0 -29
  191. package/src/components/shared/Tabs.tsx +0 -36
  192. package/src/custom-elements.ts +0 -13
  193. package/src/examples/client-side/README.md +0 -30
  194. package/src/examples/client-side/index.html +0 -57
  195. package/src/examples/full-stack/README.md +0 -34
  196. package/src/examples/full-stack/index.html +0 -48
  197. package/src/examples/full-stack/server.mjs +0 -158
  198. package/src/examples/just-typescript/README.md +0 -37
  199. package/src/examples/just-typescript/package.json +0 -16
  200. package/src/examples/just-typescript/src/index.html +0 -23
  201. package/src/examples/just-typescript/src/index.ts +0 -36
  202. package/src/examples/next/README.md +0 -28
  203. package/src/examples/next/next-env.d.ts +0 -5
  204. package/src/examples/next/next.config.js +0 -4
  205. package/src/examples/next/package.json +0 -24
  206. package/src/examples/next/src/app/DuffelComponents.tsx +0 -40
  207. package/src/examples/next/src/app/layout.tsx +0 -18
  208. package/src/examples/next/src/app/page.tsx +0 -9
  209. package/src/examples/next/tsconfig.json +0 -27
  210. package/src/examples/payments-custom-element/README.md +0 -17
  211. package/src/examples/payments-custom-element/index.html +0 -43
  212. package/src/examples/payments-just-typescript/README.md +0 -37
  213. package/src/examples/payments-just-typescript/package.json +0 -16
  214. package/src/examples/payments-just-typescript/src/index.html +0 -23
  215. package/src/examples/payments-just-typescript/src/index.ts +0 -18
  216. package/src/examples/react-app/README.md +0 -37
  217. package/src/examples/react-app/package.json +0 -20
  218. package/src/examples/react-app/src/index.html +0 -19
  219. package/src/examples/react-app/src/index.tsx +0 -48
  220. package/src/fixtures/offers/off_0000AUde3KwTztSRK1cznH.json +0 -497
  221. package/src/fixtures/offers/off_0000AVx4lUFFKW8PsPeQeQ.json +0 -307
  222. package/src/fixtures/offers/off_1.json +0 -488
  223. package/src/fixtures/passengers/mock_passengers.ts +0 -26
  224. package/src/fixtures/seat-maps/off_0000AUde3KwTztSRK1cznH.json +0 -6852
  225. package/src/fixtures/seat-maps/off_0000AVx4lUFFKW8PsPeQeQ.json +0 -1
  226. package/src/fixtures/seat-maps/off_1.json +0 -6852
  227. package/src/lib/captureErrorInSentry.ts +0 -42
  228. package/src/lib/compileCreateOrderPayload.ts +0 -63
  229. package/src/lib/createPriceFormatters.ts +0 -73
  230. package/src/lib/fetchFromDuffelAPI.ts +0 -54
  231. package/src/lib/fetchFromFixtures.ts +0 -18
  232. package/src/lib/formatAvailableServices.ts +0 -91
  233. package/src/lib/formatDate.ts +0 -20
  234. package/src/lib/formatSeatMaps.ts +0 -81
  235. package/src/lib/getBaggageServiceDescription.ts +0 -39
  236. package/src/lib/getCabinsForSegmentAndDeck.ts +0 -4
  237. package/src/lib/getCurrencyForSeatMaps.ts +0 -22
  238. package/src/lib/getCurrencyForServices.ts +0 -24
  239. package/src/lib/getFirstSeatElementMatchingCriteria.ts +0 -22
  240. package/src/lib/getPassengerBySegmentList.ts +0 -10
  241. package/src/lib/getPassengerInitials.ts +0 -6
  242. package/src/lib/getPassengerMapById.ts +0 -17
  243. package/src/lib/getPassengerName.ts +0 -41
  244. package/src/lib/getRowNumber.ts +0 -16
  245. package/src/lib/getSegmentList.ts +0 -7
  246. package/src/lib/getServicePriceMapById.ts +0 -20
  247. package/src/lib/getSymbols.ts +0 -22
  248. package/src/lib/getTotalAmountForServices.ts +0 -72
  249. package/src/lib/getTotalQuantity.ts +0 -5
  250. package/src/lib/hasHighLuminance.ts +0 -9
  251. package/src/lib/hasService.ts +0 -24
  252. package/src/lib/hasServiceOfSameMetadataTypeAlreadyBeenSelected.ts +0 -35
  253. package/src/lib/hasWings.ts +0 -8
  254. package/src/lib/isBaggageService.ts +0 -8
  255. package/src/lib/isCancelForAnyReasonService.ts +0 -9
  256. package/src/lib/isFixtureOfferId.ts +0 -4
  257. package/src/lib/isPayloadComplete.ts +0 -11
  258. package/src/lib/isSeatElement.ts +0 -10
  259. package/src/lib/logging.ts +0 -120
  260. package/src/lib/moneyStringFormatter.ts +0 -34
  261. package/src/lib/offerIsExpired.ts +0 -5
  262. package/src/lib/retrieveOffer.ts +0 -56
  263. package/src/lib/retrieveOfferFromDuffelAPI.ts +0 -13
  264. package/src/lib/retrieveSeatMaps.ts +0 -55
  265. package/src/lib/retrieveSeatMapsFromDuffelAPI.ts +0 -13
  266. package/src/lib/setBodyScrollability.ts +0 -7
  267. package/src/lib/validateProps.ts +0 -37
  268. package/src/lib/withPlural.ts +0 -8
  269. package/src/stories/BaggageSelectionModalHeader.stories.tsx +0 -21
  270. package/src/stories/Button.stories.tsx +0 -91
  271. package/src/stories/DuffelAncillaries.stories.tsx +0 -166
  272. package/src/stories/DuffelPayments.stories.tsx +0 -34
  273. package/src/stories/Icon.stories.tsx +0 -35
  274. package/src/stories/IconButton.stories.tsx +0 -25
  275. package/src/stories/PlacesLookup.stories.tsx +0 -22
  276. package/src/styles/colors.css +0 -22
  277. package/src/styles/components/Amenity.css +0 -23
  278. package/src/styles/components/BaggageDisplay.css +0 -25
  279. package/src/styles/components/Button.css +0 -169
  280. package/src/styles/components/Card.css +0 -52
  281. package/src/styles/components/CfarSelectionModal.css +0 -34
  282. package/src/styles/components/Counter.css +0 -18
  283. package/src/styles/components/DuffelPayments.css +0 -42
  284. package/src/styles/components/IconButton.css +0 -63
  285. package/src/styles/components/Legend.css +0 -62
  286. package/src/styles/components/Loader.css +0 -37
  287. package/src/styles/components/LoadingState.css +0 -87
  288. package/src/styles/components/Modal.css +0 -84
  289. package/src/styles/components/PassengerSelect.css +0 -99
  290. package/src/styles/components/PassengersLayout.css +0 -90
  291. package/src/styles/components/PlacesLookup.css +0 -36
  292. package/src/styles/components/Row.css +0 -70
  293. package/src/styles/components/Seat.css +0 -59
  294. package/src/styles/components/SeatInfo.css +0 -61
  295. package/src/styles/components/SeatMap.css +0 -24
  296. package/src/styles/components/SeatSelect.css +0 -92
  297. package/src/styles/components/Segment.css +0 -17
  298. package/src/styles/components/SelectionSegment.css +0 -10
  299. package/src/styles/components/Summary.css +0 -70
  300. package/src/styles/components/Tabs.css +0 -52
  301. package/src/styles/flex.css +0 -5
  302. package/src/styles/font-families.css +0 -47
  303. package/src/styles/global.css +0 -52
  304. package/src/styles/margin.css +0 -3
  305. package/src/styles/spacing.css +0 -18
  306. package/src/styles/transitions.css +0 -3
  307. package/src/styles/typography.css +0 -13
  308. package/src/tests/components/DuffelAncillaries.test.tsx +0 -342
  309. package/src/tests/lib/createPriceFormatters.test.tsx +0 -152
  310. package/src/tests/lib/formatAvailableServices.test.tsx +0 -79
  311. package/src/tests/lib/formatSeatMaps.test.tsx +0 -49
  312. package/src/tests/lib/getCurrencyForServices.test.tsx +0 -44
  313. package/src/tests/lib/hasServiceOfSameMetadataTypeAlreadyBeenSelected.test.ts +0 -86
  314. package/src/tests/lib/logging.test.tsx +0 -32
  315. package/src/tests/lib/moneyStringFormatter.test.tsx +0 -12
  316. package/src/tests/lib/validateProps.test.tsx +0 -57
  317. package/src/types/Aircraft.ts +0 -16
  318. package/src/types/Airline.ts +0 -16
  319. package/src/types/Airport.ts +0 -54
  320. package/src/types/City.ts +0 -21
  321. package/src/types/CreateOrderPayload.ts +0 -99
  322. package/src/types/CurrencyConversion.ts +0 -10
  323. package/src/types/DuffelAncillariesProps.ts +0 -108
  324. package/src/types/Offer.ts +0 -851
  325. package/src/types/Order.ts +0 -6
  326. package/src/types/Place.ts +0 -6
  327. package/src/types/SeatMap.ts +0 -231
  328. package/tsconfig.json +0 -52
  329. /package/{src/index.ts → index.d.ts} +0 -0
  330. /package/{src/types/index.ts → types/index.d.ts} +0 -0
@@ -1,350 +0,0 @@
1
- import { ErrorBoundary } from "@components/shared/ErrorBoundary";
2
- import { FetchOfferErrorState } from "@components/shared/FetchOfferErrorState";
3
- import { compileCreateOrderPayload } from "@lib/compileCreateOrderPayload";
4
- import { createPriceFormatters } from "@lib/createPriceFormatters";
5
- import { formatAvailableServices } from "@lib/formatAvailableServices";
6
- import { formatSeatMaps } from "@lib/formatSeatMaps";
7
- import { hasHighLuminance } from "@lib/hasHighLuminance";
8
- import { isPayloadComplete } from "@lib/isPayloadComplete";
9
- import { initializeLogger, logGroup } from "@lib/logging";
10
- import { offerIsExpired } from "@lib/offerIsExpired";
11
- import { retrieveOffer } from "@lib/retrieveOffer";
12
- import { retrieveSeatMaps } from "@lib/retrieveSeatMaps";
13
- import {
14
- areDuffelAncillariesPropsValid,
15
- isDuffelAncillariesPropsWithClientKeyAndOfferId,
16
- isDuffelAncillariesPropsWithOfferAndClientKey,
17
- isDuffelAncillariesPropsWithOfferAndSeatMaps,
18
- isDuffelAncillariesPropsWithOfferIdForFixture,
19
- } from "@lib/validateProps";
20
- import * as Sentry from "@sentry/browser";
21
- import * as React from "react";
22
- import {
23
- CreateOrderPayloadPassengers,
24
- CreateOrderPayloadService,
25
- } from "../../types/CreateOrderPayload";
26
- import { DuffelAncillariesProps } from "../../types/DuffelAncillariesProps";
27
- import { Offer } from "../../types/Offer";
28
- import { SeatMap } from "../../types/SeatMap";
29
- import { BaggageSelectionCard } from "./bags/BaggageSelectionCard";
30
- import { CfarSelectionCard } from "./cancel_for_any_reason/CfarSelectionCard";
31
- import { SeatSelectionCard } from "./seats/SeatSelectionCard";
32
-
33
- const COMPONENT_CDN = process.env.COMPONENT_CDN || "";
34
- const hrefToComponentStyles = `${COMPONENT_CDN}/global.css`;
35
-
36
- export const DuffelAncillaries: React.FC<DuffelAncillariesProps> = (props) => {
37
- initializeLogger(props.debug || false);
38
-
39
- logGroup("Properties passed into the component:", props);
40
-
41
- if (!areDuffelAncillariesPropsValid(props)) {
42
- throw new Error(
43
- `The props (${Object.keys(
44
- props
45
- )}) passed to DuffelAncillaries are invalid. ` +
46
- "`onPayloadReady`, `passengers` and `services` are always required. " +
47
- "Then, depending on your use case you may have one of the following combinations of required props: " +
48
- "`offer_id` and `client_key`, `offer` and `seat_maps` or `offer` and `client_key`." +
49
- "Please refer to the documentation for more information and working examples: " +
50
- "https://duffel.com/docs/guides/ancillaries-component"
51
- );
52
- }
53
- if (props.services.length === 0) {
54
- throw new Error(
55
- `You must provide at least one service in the "services" prop. Valid services: ["bags", "seats", "cancel_for_any_reason"]`
56
- );
57
- }
58
-
59
- const isPropsWithOfferIdForFixture =
60
- isDuffelAncillariesPropsWithOfferIdForFixture(props);
61
-
62
- const isPropsWithClientKeyAndOfferId =
63
- isDuffelAncillariesPropsWithClientKeyAndOfferId(props);
64
-
65
- const isPropsWithOfferAndSeatMaps =
66
- isDuffelAncillariesPropsWithOfferAndSeatMaps(props);
67
-
68
- const isPropsWithOfferAndClientKey =
69
- isDuffelAncillariesPropsWithOfferAndClientKey(props);
70
-
71
- const shouldRetrieveSeatMaps =
72
- props.services.includes("seats") &&
73
- !("seat_maps" in props) &&
74
- (isPropsWithOfferIdForFixture ||
75
- isPropsWithClientKeyAndOfferId ||
76
- isPropsWithOfferAndClientKey);
77
-
78
- const [passengers, setPassengers] =
79
- React.useState<CreateOrderPayloadPassengers>(props.passengers);
80
-
81
- const [offer, setOffer] = React.useState<Offer | undefined>(
82
- (props as any).offer
83
- );
84
-
85
- const [isOfferLoading, setIsOfferLoading] = React.useState(
86
- isPropsWithClientKeyAndOfferId
87
- );
88
-
89
- const [seatMaps, setSeatMaps] = React.useState<SeatMap[] | undefined>(
90
- isPropsWithOfferAndSeatMaps ? props.seat_maps : undefined
91
- );
92
- const [isSeatMapLoading, setIsSeatMapLoading] = React.useState(
93
- shouldRetrieveSeatMaps
94
- );
95
-
96
- const [error, setError] = React.useState<null | string>(null);
97
-
98
- const [baggageSelectedServices, setBaggageSelectedServices] = React.useState(
99
- new Array<CreateOrderPayloadService>()
100
- );
101
- const [seatSelectedServices, setSeatSelectedServices] = React.useState(
102
- new Array<CreateOrderPayloadService>()
103
- );
104
- const [cfarSelectedServices, setCfarSelectedServices] = React.useState(
105
- new Array<CreateOrderPayloadService>()
106
- );
107
-
108
- const priceFormatters = createPriceFormatters(
109
- props.markup,
110
- props.priceFormatters
111
- );
112
-
113
- const updateOffer = (offer: Offer) => {
114
- const expiryErrorMessage = "This offer has expired.";
115
- if (offerIsExpired(offer)) {
116
- setError(expiryErrorMessage);
117
- return;
118
- } else {
119
- const msUntilExpiry = new Date(offer?.expires_at)?.getTime() - Date.now();
120
-
121
- // Only show the expiry error message if the offer expires in less than a day,
122
- // to prevent buffer overflows when showing offers for fixtures, which expire in
123
- // years.
124
- const milisecondsInOneDay = 1000 * 60 * 60 * 24;
125
- if (msUntilExpiry < milisecondsInOneDay) {
126
- setTimeout(() => setError(expiryErrorMessage), msUntilExpiry);
127
- }
128
- }
129
-
130
- const offerWithFormattedServices = formatAvailableServices(
131
- offer,
132
- priceFormatters
133
- );
134
- setOffer(offerWithFormattedServices);
135
- };
136
-
137
- const updateSeatMaps = (seatMaps: SeatMap[]) => {
138
- const formattedSeatMaps = formatSeatMaps(seatMaps, priceFormatters.seats);
139
- setSeatMaps(formattedSeatMaps);
140
- };
141
-
142
- React.useEffect(() => {
143
- // whenever the props change, we'll set the sentry context to thse values
144
- // so that we can see them in the sentry logs and better support the users of the component library
145
- Sentry.setContext("props", {
146
- "props.services": props.services,
147
- "props.passengers.length": (props as any).passengers.length,
148
- "props.offer_id": (props as any).offer_id,
149
- "props.client_key": (props as any).client_key,
150
- "props.offer?.id": (props as any).offer?.id,
151
- "props.seat_maps?.[0]?.id": (props as any).seat_maps?.[0]?.id,
152
- });
153
-
154
- if (isPropsWithClientKeyAndOfferId || isPropsWithOfferIdForFixture) {
155
- retrieveOffer(
156
- props.offer_id,
157
- !isPropsWithOfferIdForFixture ? props.client_key : null,
158
- setError,
159
- setIsOfferLoading,
160
- (offer) => {
161
- updateOffer(offer);
162
-
163
- if (offer.passengers.length !== passengers.length) {
164
- throw new Error(
165
- `The number of passengers given to \`duffel-ancillaries\` (${props.passengers.length}) doesn't match ` +
166
- `the number of passengers on the given offer (${offer.passengers.length}).`
167
- );
168
- }
169
-
170
- if (isPropsWithOfferIdForFixture) {
171
- // There's no way the component users will know the passenger IDs for the fixture offer
172
- // so we'll need to add them here
173
- setPassengers(
174
- props.passengers.map((passenger, index) => ({
175
- ...passenger,
176
- id: offer.passengers[index].id,
177
- }))
178
- );
179
- }
180
- }
181
- );
182
- }
183
-
184
- if (shouldRetrieveSeatMaps) {
185
- retrieveSeatMaps(
186
- isPropsWithClientKeyAndOfferId || isPropsWithOfferIdForFixture
187
- ? props.offer_id
188
- : props.offer.id,
189
- !isPropsWithOfferIdForFixture ? props.client_key : null,
190
- () => updateSeatMaps([]),
191
- setIsSeatMapLoading,
192
- updateSeatMaps
193
- );
194
- }
195
-
196
- if (isPropsWithOfferAndClientKey) {
197
- updateOffer(props.offer);
198
- }
199
-
200
- if (isPropsWithOfferAndSeatMaps) {
201
- updateOffer(props.offer);
202
- updateSeatMaps(props.seat_maps);
203
- }
204
- }, [
205
- // `as any` is needed here because the list
206
- // of dependencies is different for each combination of props.
207
- // To satisfy typescript, we'd need to conditionally assign
208
- // the dependencies to the hook after checking its type,
209
- // however that is not possible in a react hook.
210
- (props as any).offer_id,
211
- (props as any).client_key,
212
- (props as any).offer?.id,
213
- (props as any).seat_maps?.[0]?.id,
214
- ]);
215
-
216
- React.useEffect(() => {
217
- if (!offer) return;
218
-
219
- const createOrderPayload = compileCreateOrderPayload({
220
- baggageSelectedServices,
221
- seatSelectedServices,
222
- cfarSelectedServices,
223
- offer,
224
- passengers,
225
- seatMaps,
226
- });
227
-
228
- if (isPayloadComplete(createOrderPayload)) {
229
- const metadata = {
230
- offer_total_amount: offer.total_amount,
231
- offer_total_currency: offer.total_currency,
232
- offer_tax_amount: offer.tax_amount,
233
- offer_tax_currency: offer.tax_currency,
234
- baggage_services: baggageSelectedServices,
235
- seat_services: seatSelectedServices,
236
- cancel_for_any_reason_services: cfarSelectedServices,
237
- };
238
-
239
- logGroup("Payload ready", {
240
- "Order creation payload": createOrderPayload,
241
- "Services metadata": metadata,
242
- });
243
-
244
- props.onPayloadReady(createOrderPayload, metadata);
245
- }
246
- }, [baggageSelectedServices, seatSelectedServices, cfarSelectedServices]);
247
-
248
- if (!areDuffelAncillariesPropsValid(props)) {
249
- return null;
250
- }
251
-
252
- const nonIdealStateHeight = `${
253
- // 72 (card height) + 32 gap between cards
254
- 72 * props.services.length + 32 * (props.services.length - 1)
255
- }px`;
256
-
257
- const duffelComponentsStyle = {
258
- // Adding inline styles here to avoid the cards jumping down
259
- // before the css is loaded duet to the missing "row gap".
260
- display: "flex",
261
- width: "100%",
262
- flexDirection: "column",
263
- rowGap: "12px",
264
- ...(props.styles?.accentColor && {
265
- "--ACCENT": props.styles.accentColor,
266
- }),
267
- ...(props.styles?.accentColor &&
268
- hasHighLuminance(props.styles.accentColor) && {
269
- "--SECONDARY": "var(--GREY-900)",
270
- "--TERTIARY": "var(--GREY-400)",
271
- }),
272
- ...(props.styles?.fontFamily && {
273
- "--FONT-FAMILY": props.styles.fontFamily,
274
- }),
275
- ...(props.styles?.buttonCornerRadius && {
276
- "--BUTTON-RADIUS": props.styles.buttonCornerRadius,
277
- }),
278
- // `as any` is needed here is needed because we want to set css variables
279
- // that are not part of the css properties type
280
- } as any;
281
-
282
- const state = {
283
- isOfferLoading,
284
- isSeatMapLoading,
285
- baggageSelectedServices,
286
- seatSelectedServices,
287
- cfarSelectedServices,
288
- offer,
289
- seatMaps,
290
- error,
291
- };
292
-
293
- logGroup("Component's internal state:", state);
294
-
295
- return (
296
- <>
297
- <link rel="stylesheet" href={hrefToComponentStyles}></link>
298
-
299
- <div className="duffel-components" style={duffelComponentsStyle}>
300
- <ErrorBoundary>
301
- {error && (
302
- <FetchOfferErrorState
303
- height={nonIdealStateHeight}
304
- message={error}
305
- />
306
- )}
307
-
308
- {!error &&
309
- props.services.map((ancillaryName) => {
310
- if (ancillaryName === "bags")
311
- return (
312
- <BaggageSelectionCard
313
- key="bags"
314
- isLoading={isOfferLoading}
315
- offer={offer}
316
- passengers={passengers}
317
- selectedServices={baggageSelectedServices}
318
- setSelectedServices={setBaggageSelectedServices}
319
- />
320
- );
321
-
322
- if (ancillaryName === "seats")
323
- return (
324
- <SeatSelectionCard
325
- key="seats"
326
- isLoading={isOfferLoading || isSeatMapLoading}
327
- seatMaps={seatMaps}
328
- offer={offer}
329
- passengers={passengers}
330
- selectedServices={seatSelectedServices}
331
- setSelectedServices={setSeatSelectedServices}
332
- />
333
- );
334
-
335
- if (ancillaryName === "cancel_for_any_reason")
336
- return (
337
- <CfarSelectionCard
338
- key="cancel_for_any_reason"
339
- isLoading={isOfferLoading}
340
- offer={offer}
341
- selectedServices={cfarSelectedServices}
342
- setSelectedServices={setCfarSelectedServices}
343
- />
344
- );
345
- })}
346
- </ErrorBoundary>
347
- </div>
348
- </>
349
- );
350
- };
@@ -1,124 +0,0 @@
1
- import { createRoot, Root } from "react-dom/client";
2
- import { CreateOrderPayload } from "../../types/CreateOrderPayload";
3
- import {
4
- DuffelAncillariesPropsWithClientKeyAndOfferId,
5
- DuffelAncillariesPropsWithOfferIdForFixture,
6
- DuffelAncillariesPropsWithOffersAndSeatMaps,
7
- DuffelAncillariesPropWithOfferAndClientKey,
8
- OnPayloadReady,
9
- OnPayloadReadyMetadata,
10
- } from "../../types/DuffelAncillariesProps";
11
- import { DuffelAncillaries } from "./DuffelAncillaries";
12
-
13
- declare global {
14
- // eslint-disable-next-line @typescript-eslint/no-namespace
15
- namespace JSX {
16
- interface IntrinsicElements {
17
- "duffel-ancillaries": React.DetailedHTMLProps<
18
- React.HTMLAttributes<HTMLElement>,
19
- HTMLElement
20
- >;
21
- }
22
- }
23
- }
24
-
25
- const CUSTOM_ELEMENT_TAG = "duffel-ancillaries";
26
-
27
- // A bit reptitive but typescript is not clever enough
28
- // to infer the correct type if we just use
29
- // `Omit<DuffelAncillariesProps, 'onPayloadReady'>`
30
- type DuffelAncillariesCustomElementRenderArguments =
31
- | Omit<DuffelAncillariesPropsWithOfferIdForFixture, "onPayloadReady">
32
- | Omit<DuffelAncillariesPropsWithClientKeyAndOfferId, "onPayloadReady">
33
- | Omit<DuffelAncillariesPropWithOfferAndClientKey, "onPayloadReady">
34
- | Omit<DuffelAncillariesPropsWithOffersAndSeatMaps, "onPayloadReady">;
35
-
36
- class DuffelAncillariesCustomElement extends HTMLElement {
37
- /**
38
- * The React root for displaying content inside a browser DOM element.
39
- */
40
- private root!: Root;
41
-
42
- /**
43
- * `connectedCallback` is called to initialise the custom element
44
- */
45
- connectedCallback() {
46
- const container = document.createElement("div");
47
- this.attachShadow({ mode: "open" }).appendChild(container);
48
-
49
- this.root = createRoot(container);
50
- }
51
-
52
- /**
53
- * When this function is called, it will render/re-render
54
- * the `DuffelAncillaries` component with the given props.
55
- */
56
- public render(withProps: DuffelAncillariesCustomElementRenderArguments) {
57
- if (!this.root) {
58
- throw "It was not possible to render `duffel-ancillaries` because `this.root` is missing.";
59
- }
60
-
61
- this.root.render(
62
- <DuffelAncillaries
63
- {...withProps}
64
- onPayloadReady={(data, metadata) => {
65
- this.dispatchEvent(
66
- new CustomEvent("onPayloadReady", {
67
- detail: { data, metadata },
68
- composed: true,
69
- })
70
- );
71
- }}
72
- />
73
- );
74
- }
75
- }
76
-
77
- window.customElements.get(CUSTOM_ELEMENT_TAG) ||
78
- window.customElements.define(
79
- CUSTOM_ELEMENT_TAG,
80
- DuffelAncillariesCustomElement
81
- );
82
-
83
- function tryToGetDuffelAncillariesCustomElement(
84
- caller: string
85
- ): DuffelAncillariesCustomElement {
86
- const element =
87
- document.querySelector<DuffelAncillariesCustomElement>(CUSTOM_ELEMENT_TAG);
88
- if (!element) {
89
- throw new Error(
90
- `Could not find duffel-ancillaries element in the DOM. Maybe you need to call ${caller} after 'window.onload'?`
91
- );
92
- }
93
- return element;
94
- }
95
-
96
- export function renderDuffelAncillariesCustomElement(
97
- props: DuffelAncillariesCustomElementRenderArguments
98
- ) {
99
- const element = tryToGetDuffelAncillariesCustomElement(
100
- "renderDuffelAncillariesCustomElement"
101
- );
102
- element.render(props);
103
- }
104
-
105
- type OnPayloadReadyCustomEvent = CustomEvent<{
106
- data: CreateOrderPayload;
107
- metadata: OnPayloadReadyMetadata;
108
- }>;
109
-
110
- export function onDuffelAncillariesPayloadReady(
111
- onPayloadReady: OnPayloadReady
112
- ) {
113
- const element = tryToGetDuffelAncillariesCustomElement(
114
- "onDuffelAncillariesPayloadReady"
115
- );
116
- const eventListener = (event: OnPayloadReadyCustomEvent) => {
117
- onPayloadReady(event.detail.data, event.detail.metadata);
118
- };
119
-
120
- // using `as EventListener` here because typescript doesn't know the event type for `onPayloadReady`
121
- // There's a few different suggestions to resolve this seemed good enough
122
- // You can learn more here: https://github.com/microsoft/TypeScript/issues/28357
123
- element.addEventListener("onPayloadReady", eventListener as EventListener);
124
- }
@@ -1,101 +0,0 @@
1
- import { AnimatedLoaderEllipsis } from "@components/shared/AnimatedLoaderEllipsis";
2
- import { Stamp } from "@components/shared/Stamp";
3
- import { getCurrencyForServices } from "@lib/getCurrencyForServices";
4
- import { getTotalAmountForServices } from "@lib/getTotalAmountForServices";
5
- import { getTotalQuantity } from "@lib/getTotalQuantity";
6
- import { hasService } from "@lib/hasService";
7
- import { moneyStringFormatter } from "@lib/moneyStringFormatter";
8
- import { withPlural } from "@lib/withPlural";
9
- import React from "react";
10
- import {
11
- CreateOrderPayload,
12
- CreateOrderPayloadServices,
13
- } from "../../../types/CreateOrderPayload";
14
- import { Offer } from "../../../types/Offer";
15
- import { Card } from "../Card";
16
- import { BaggageSelectionModal } from "./BaggageSelectionModal";
17
-
18
- export interface BaggageSelectionCardProps {
19
- isLoading: boolean;
20
- offer?: Offer;
21
- passengers: CreateOrderPayload["passengers"];
22
- selectedServices: CreateOrderPayloadServices;
23
- setSelectedServices: (selectedServices: CreateOrderPayloadServices) => void;
24
- }
25
-
26
- export const BaggageSelectionCard: React.FC<BaggageSelectionCardProps> = ({
27
- isLoading,
28
- offer,
29
- passengers,
30
- selectedServices,
31
- setSelectedServices,
32
- }) => {
33
- const [isOpen, setIsOpen] = React.useState(false);
34
-
35
- const containsBaggageService = hasService(offer, "baggage");
36
- const totalQuantity = getTotalQuantity(selectedServices);
37
- const isBaggageAdded = totalQuantity > 0;
38
-
39
- const totalAmount = getTotalAmountForServices(offer!, selectedServices);
40
-
41
- let currencyToUse = offer?.base_currency || "";
42
- if (containsBaggageService) {
43
- currencyToUse = getCurrencyForServices(offer!, "baggage");
44
- }
45
-
46
- const totalAmountFormatted = offer
47
- ? moneyStringFormatter(currencyToUse)(totalAmount)
48
- : "0";
49
-
50
- const copy =
51
- containsBaggageService && isBaggageAdded
52
- ? `${withPlural(
53
- totalQuantity,
54
- "bag",
55
- "bags"
56
- )} added for ${totalAmountFormatted}`
57
- : "Add any extra baggage you need for your trip";
58
-
59
- return (
60
- <>
61
- <Card
62
- buttonTitle="Select extra baggage"
63
- title="Extra baggage"
64
- copy={copy}
65
- icon="cabin_bag"
66
- onClick={containsBaggageService ? () => setIsOpen(true) : null}
67
- isLoading={isLoading}
68
- disabled={!isLoading && !containsBaggageService}
69
- isSelected={isBaggageAdded}
70
- >
71
- {isLoading && (
72
- <Stamp color="var(--GREY-900)" backgroundColor="var(--GREY-100)">
73
- Loading
74
- <AnimatedLoaderEllipsis />
75
- </Stamp>
76
- )}
77
- {!isLoading && !containsBaggageService && (
78
- <Stamp color="var(--GREY-700)" backgroundColor="var(--GREY-200)">
79
- Not available
80
- </Stamp>
81
- )}
82
- </Card>
83
-
84
- <BaggageSelectionModal
85
- isOpen={Boolean(isOpen && offer)}
86
- offer={offer}
87
- passengers={passengers}
88
- onClose={(newSelectedServices) => {
89
- // We need to do a deep copy here because otherwise the modal changing the quantity
90
- // will affect the selected services regardless of whether it's saved or not
91
- const newSelectedServicesDeepCopy = JSON.parse(
92
- JSON.stringify(newSelectedServices)
93
- );
94
- setSelectedServices(newSelectedServicesDeepCopy);
95
- setIsOpen(false);
96
- }}
97
- selectedServices={selectedServices}
98
- />
99
- </>
100
- );
101
- };
@@ -1,88 +0,0 @@
1
- import { getBaggageServiceDescription } from "@lib/getBaggageServiceDescription";
2
- import { hasServiceOfSameMetadataTypeAlreadyBeenSelected } from "@lib/hasServiceOfSameMetadataTypeAlreadyBeenSelected";
3
- import { moneyStringFormatter } from "@lib/moneyStringFormatter";
4
- import React from "react";
5
- import { CreateOrderPayloadServices } from "../../../types/CreateOrderPayload";
6
- import { OfferAvailableServiceBaggage } from "../../../types/Offer";
7
- import { Counter } from "../Counter";
8
-
9
- interface BaggageSelectionControllerProps {
10
- segmentId: string;
11
- passengerId: string;
12
- availableService: OfferAvailableServiceBaggage;
13
- selectedServices: CreateOrderPayloadServices;
14
- quantity: number;
15
- onQuantityChanged: (quantity: number) => void;
16
- }
17
-
18
- export const BaggageSelectionController: React.FC<
19
- BaggageSelectionControllerProps
20
- > = ({
21
- segmentId,
22
- passengerId,
23
- availableService,
24
- quantity,
25
- onQuantityChanged,
26
- selectedServices,
27
- }) => {
28
- const serviceName =
29
- availableService.metadata.type === "carry_on" ? "Cabin bag" : "Checked bag";
30
-
31
- const servicePrice = moneyStringFormatter(availableService.total_currency)(
32
- +availableService.total_amount
33
- );
34
- const serviceDescription = getBaggageServiceDescription(
35
- availableService.metadata
36
- );
37
-
38
- const shouldDisableController =
39
- hasServiceOfSameMetadataTypeAlreadyBeenSelected(
40
- selectedServices,
41
- segmentId,
42
- passengerId,
43
- availableService
44
- );
45
-
46
- return (
47
- <div
48
- style={{
49
- display: "flex",
50
- justifyContent: "space-between",
51
- alignItems: "center",
52
- }}
53
- >
54
- <div>
55
- <p style={{ margin: 0 }} className="p2--regular">
56
- {serviceName}
57
- <span
58
- style={{
59
- marginInline: "4px",
60
- color: "var(--GREY-400)",
61
- }}
62
- >
63
-
64
- </span>
65
- <span
66
- className="p2--semibold"
67
- data-testid={`price-label--${availableService.id}--${passengerId}`}
68
- >
69
- {servicePrice}
70
- </span>
71
- </p>
72
- <p
73
- style={{ margin: 0, color: "var(--GREY-600)" }}
74
- className="p3--regular"
75
- >
76
- {serviceDescription}
77
- </p>
78
- </div>
79
- <Counter
80
- id={`counter--${availableService.id}--${passengerId}`}
81
- min={0}
82
- value={quantity}
83
- onChange={onQuantityChanged}
84
- max={shouldDisableController ? 0 : availableService.maximum_quantity}
85
- />
86
- </div>
87
- );
88
- };