@rabbitio/ui-kit 1.0.0-beta.7 → 1.0.0-beta.70

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 (319) hide show
  1. package/.gitlab-ci.yml +29 -0
  2. package/.husky/commit-msg +14 -0
  3. package/.husky/pre-push +1 -0
  4. package/CHANGELOG.md +0 -0
  5. package/README.md +27 -18
  6. package/coverage/base.css +224 -0
  7. package/coverage/block-navigation.js +87 -0
  8. package/coverage/clover.xml +11536 -0
  9. package/coverage/coverage-final.json +100 -0
  10. package/coverage/favicon.png +0 -0
  11. package/coverage/index.html +986 -0
  12. package/coverage/prettify.css +1 -0
  13. package/coverage/prettify.js +2 -0
  14. package/coverage/rabbit-ui-kit/index.html +116 -0
  15. package/coverage/rabbit-ui-kit/index.js.html +88 -0
  16. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/arrowIcon.jsx.html +124 -0
  17. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/arrowTosca.jsx.html +127 -0
  18. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/arrowWhite.jsx.html +127 -0
  19. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/darkRectangle.jsx.html +106 -0
  20. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/determinedError.jsx.html +439 -0
  21. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/failedValidationIcon.jsx.html +202 -0
  22. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/index.html +251 -0
  23. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/infoIcon.jsx.html +133 -0
  24. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/noticeQuestionIcon.jsx.html +247 -0
  25. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/successfulValidationIcon.jsx.html +163 -0
  26. package/coverage/rabbit-ui-kit/src/assets/wrappedImages/walletIcon.jsx.html +151 -0
  27. package/coverage/rabbit-ui-kit/src/common/adapters/axiosAdapter.js.html +190 -0
  28. package/coverage/rabbit-ui-kit/src/common/adapters/index.html +131 -0
  29. package/coverage/rabbit-ui-kit/src/common/adapters/qrUtils.js.html +139 -0
  30. package/coverage/rabbit-ui-kit/src/common/amountUtils.js.html +1162 -0
  31. package/coverage/rabbit-ui-kit/src/common/errorUtils.js.html +211 -0
  32. package/coverage/rabbit-ui-kit/src/common/external-apis/apiGroups.js.html +250 -0
  33. package/coverage/rabbit-ui-kit/src/common/external-apis/index.html +131 -0
  34. package/coverage/rabbit-ui-kit/src/common/external-apis/ipAddressProviders.js.html +352 -0
  35. package/coverage/rabbit-ui-kit/src/common/fiatCurrenciesService.js.html +544 -0
  36. package/coverage/rabbit-ui-kit/src/common/index.html +146 -0
  37. package/coverage/rabbit-ui-kit/src/common/models/blockchain.js.html +115 -0
  38. package/coverage/rabbit-ui-kit/src/common/models/coin.js.html +544 -0
  39. package/coverage/rabbit-ui-kit/src/common/models/index.html +146 -0
  40. package/coverage/rabbit-ui-kit/src/common/models/protocol.js.html +100 -0
  41. package/coverage/rabbit-ui-kit/src/common/utils/cache.js.html +811 -0
  42. package/coverage/rabbit-ui-kit/src/common/utils/emailAPI.js.html +133 -0
  43. package/coverage/rabbit-ui-kit/src/common/utils/index.html +161 -0
  44. package/coverage/rabbit-ui-kit/src/common/utils/logging/index.html +131 -0
  45. package/coverage/rabbit-ui-kit/src/common/utils/logging/logger.js.html +208 -0
  46. package/coverage/rabbit-ui-kit/src/common/utils/logging/logsStorage.js.html +268 -0
  47. package/coverage/rabbit-ui-kit/src/common/utils/postponeExecution.js.html +118 -0
  48. package/coverage/rabbit-ui-kit/src/common/utils/safeStringify.js.html +235 -0
  49. package/coverage/rabbit-ui-kit/src/components/atoms/AssetIcon/AssetIcon.jsx.html +247 -0
  50. package/coverage/rabbit-ui-kit/src/components/atoms/AssetIcon/index.html +116 -0
  51. package/coverage/rabbit-ui-kit/src/components/atoms/AssetSelection/AssetSelection.jsx.html +286 -0
  52. package/coverage/rabbit-ui-kit/src/components/atoms/AssetSelection/index.html +116 -0
  53. package/coverage/rabbit-ui-kit/src/components/atoms/BackgroundTitle/BackgroundTitle.jsx.html +187 -0
  54. package/coverage/rabbit-ui-kit/src/components/atoms/BackgroundTitle/index.html +116 -0
  55. package/coverage/rabbit-ui-kit/src/components/atoms/InformationMessage/InformationMessage.jsx.html +235 -0
  56. package/coverage/rabbit-ui-kit/src/components/atoms/InformationMessage/index.html +116 -0
  57. package/coverage/rabbit-ui-kit/src/components/atoms/Input/Input.jsx.html +631 -0
  58. package/coverage/rabbit-ui-kit/src/components/atoms/Input/index.html +116 -0
  59. package/coverage/rabbit-ui-kit/src/components/atoms/LoadingDots/LoadingDots.jsx.html +196 -0
  60. package/coverage/rabbit-ui-kit/src/components/atoms/LoadingDots/index.html +116 -0
  61. package/coverage/rabbit-ui-kit/src/components/atoms/NoticeIcon/NoticeIcon.jsx.html +277 -0
  62. package/coverage/rabbit-ui-kit/src/components/atoms/NoticeIcon/index.html +116 -0
  63. package/coverage/rabbit-ui-kit/src/components/atoms/QrCode/QrCode.jsx.html +187 -0
  64. package/coverage/rabbit-ui-kit/src/components/atoms/QrCode/index.html +116 -0
  65. package/coverage/rabbit-ui-kit/src/components/atoms/RateSelector/RateSelector.jsx.html +172 -0
  66. package/coverage/rabbit-ui-kit/src/components/atoms/RateSelector/index.html +116 -0
  67. package/coverage/rabbit-ui-kit/src/components/atoms/SupportChat/SupportChat.jsx.html +214 -0
  68. package/coverage/rabbit-ui-kit/src/components/atoms/SupportChat/index.html +116 -0
  69. package/coverage/rabbit-ui-kit/src/components/atoms/Textarea/Textarea.jsx.html +523 -0
  70. package/coverage/rabbit-ui-kit/src/components/atoms/Textarea/index.html +116 -0
  71. package/coverage/rabbit-ui-kit/src/components/atoms/TitleBox/TitleBox.jsx.html +508 -0
  72. package/coverage/rabbit-ui-kit/src/components/atoms/TitleBox/index.html +116 -0
  73. package/coverage/rabbit-ui-kit/src/components/atoms/Tooltip/Tooltip.jsx.html +289 -0
  74. package/coverage/rabbit-ui-kit/src/components/atoms/Tooltip/index.html +116 -0
  75. package/coverage/rabbit-ui-kit/src/components/atoms/TwoLinesOfText/LinesOfText.jsx.html +307 -0
  76. package/coverage/rabbit-ui-kit/src/components/atoms/TwoLinesOfText/index.html +116 -0
  77. package/coverage/rabbit-ui-kit/src/components/atoms/Validation/Validation.jsx.html +208 -0
  78. package/coverage/rabbit-ui-kit/src/components/atoms/Validation/index.html +116 -0
  79. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/Button/Button.jsx.html +712 -0
  80. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/Button/index.html +116 -0
  81. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/Close/Close.jsx.html +244 -0
  82. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/Close/index.html +116 -0
  83. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/LinkButton/LinkButton.jsx.html +403 -0
  84. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/LinkButton/index.html +116 -0
  85. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/RadioButtonWithText/RadioButtonWithText.jsx.html +415 -0
  86. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/RadioButtonWithText/index.html +116 -0
  87. package/coverage/rabbit-ui-kit/src/components/hooks/index.html +131 -0
  88. package/coverage/rabbit-ui-kit/src/components/hooks/useCallHandlingErrors.js.html +151 -0
  89. package/coverage/rabbit-ui-kit/src/components/hooks/useReferredState.js.html +157 -0
  90. package/coverage/rabbit-ui-kit/src/components/molecules/AmountInput/AmountInput.jsx.html +997 -0
  91. package/coverage/rabbit-ui-kit/src/components/molecules/AmountInput/index.html +116 -0
  92. package/coverage/rabbit-ui-kit/src/components/molecules/CoinPicker/CoinPicker.jsx.html +1612 -0
  93. package/coverage/rabbit-ui-kit/src/components/molecules/CoinPicker/index.html +116 -0
  94. package/coverage/rabbit-ui-kit/src/components/molecules/LineWithIconLink/LineWithIconLink.jsx.html +190 -0
  95. package/coverage/rabbit-ui-kit/src/components/molecules/LineWithIconLink/index.html +116 -0
  96. package/coverage/rabbit-ui-kit/src/components/molecules/TitledLineWithIconLink/TitledLineWithIconLink.jsx.html +175 -0
  97. package/coverage/rabbit-ui-kit/src/components/molecules/TitledLineWithIconLink/index.html +116 -0
  98. package/coverage/rabbit-ui-kit/src/components/organisms/CoinPickerDialogStep/CoinPickerDialogStep.jsx.html +277 -0
  99. package/coverage/rabbit-ui-kit/src/components/organisms/CoinPickerDialogStep/index.html +116 -0
  100. package/coverage/rabbit-ui-kit/src/components/organisms/Dialog/Dialog.jsx.html +1480 -0
  101. package/coverage/rabbit-ui-kit/src/components/organisms/Dialog/DialogButtons/DialogButtons.jsx.html +451 -0
  102. package/coverage/rabbit-ui-kit/src/components/organisms/Dialog/DialogButtons/index.html +116 -0
  103. package/coverage/rabbit-ui-kit/src/components/organisms/Dialog/DialogStep/DialogStep.jsx.html +1684 -0
  104. package/coverage/rabbit-ui-kit/src/components/organisms/Dialog/DialogStep/index.html +116 -0
  105. package/coverage/rabbit-ui-kit/src/components/organisms/Dialog/index.html +116 -0
  106. package/coverage/rabbit-ui-kit/src/components/organisms/SwapForm/SwapForm.jsx.html +3400 -0
  107. package/coverage/rabbit-ui-kit/src/components/organisms/SwapForm/index.html +116 -0
  108. package/coverage/rabbit-ui-kit/src/components/templates/DeterminedErrorDialogStep/DeterminedErrorDialogStep.jsx.html +316 -0
  109. package/coverage/rabbit-ui-kit/src/components/templates/DeterminedErrorDialogStep/index.html +116 -0
  110. package/coverage/rabbit-ui-kit/src/components/utils/index.html +161 -0
  111. package/coverage/rabbit-ui-kit/src/components/utils/inputValueProviders.js.html +235 -0
  112. package/coverage/rabbit-ui-kit/src/components/utils/textUtils.js.html +139 -0
  113. package/coverage/rabbit-ui-kit/src/components/utils/uiUtils.js.html +121 -0
  114. package/coverage/rabbit-ui-kit/src/components/utils/urlQueryUtils.js.html +271 -0
  115. package/coverage/rabbit-ui-kit/src/constants/atoms/Close/close.jsx.html +100 -0
  116. package/coverage/rabbit-ui-kit/src/constants/atoms/Close/index.html +116 -0
  117. package/coverage/rabbit-ui-kit/src/constants/atoms/LinkButton/index.html +116 -0
  118. package/coverage/rabbit-ui-kit/src/constants/atoms/LinkButton/linkButton.jsx.html +103 -0
  119. package/coverage/rabbit-ui-kit/src/constants/atoms/Tooltip/index.html +116 -0
  120. package/coverage/rabbit-ui-kit/src/constants/atoms/Tooltip/tooltip.jsx.html +109 -0
  121. package/coverage/rabbit-ui-kit/src/constants/globalConstants.jsx.html +94 -0
  122. package/coverage/rabbit-ui-kit/src/constants/index.html +116 -0
  123. package/coverage/rabbit-ui-kit/src/constants/organisms/dialog/DialogStep/dialogStep.js.html +88 -0
  124. package/coverage/rabbit-ui-kit/src/constants/organisms/dialog/DialogStep/index.html +116 -0
  125. package/coverage/rabbit-ui-kit/src/constants/organisms/dialog/dialog.js.html +172 -0
  126. package/coverage/rabbit-ui-kit/src/constants/organisms/dialog/index.html +116 -0
  127. package/coverage/rabbit-ui-kit/src/index.html +116 -0
  128. package/coverage/rabbit-ui-kit/src/index.js.html +349 -0
  129. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cacheAndConcurrentRequestsResolver.js.html +1570 -0
  130. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cachedRobustExternalApiCallerService.js.html +526 -0
  131. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cancelProcessing.js.html +172 -0
  132. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/concurrentCalculationsMetadataHolder.js.html +310 -0
  133. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/externalApiProvider.js.html +553 -0
  134. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/externalServicesStatsCollector.js.html +319 -0
  135. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/index.html +206 -0
  136. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/robustExternalAPICallerService.js.html +997 -0
  137. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/index.html +131 -0
  138. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapProvider.js.html +709 -0
  139. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapspaceSwapProvider.js.html +2197 -0
  140. package/coverage/rabbit-ui-kit/src/swaps-lib/models/baseSwapCreationInfo.js.html +214 -0
  141. package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwap.js.html +304 -0
  142. package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwapWithFiatData.js.html +469 -0
  143. package/coverage/rabbit-ui-kit/src/swaps-lib/models/index.html +146 -0
  144. package/coverage/rabbit-ui-kit/src/swaps-lib/services/index.html +116 -0
  145. package/coverage/rabbit-ui-kit/src/swaps-lib/services/publicSwapService.js.html +1888 -0
  146. package/coverage/rabbit-ui-kit/src/swaps-lib/utils/index.html +116 -0
  147. package/coverage/rabbit-ui-kit/src/swaps-lib/utils/swapUtils.js.html +595 -0
  148. package/coverage/rabbit-ui-kit/stories/atoms/BackgroundTitle.stories.jsx.html +202 -0
  149. package/coverage/rabbit-ui-kit/stories/atoms/LinesOfText.stories.jsx.html +283 -0
  150. package/coverage/rabbit-ui-kit/stories/atoms/LoadingDots.stories.jsx.html +226 -0
  151. package/coverage/rabbit-ui-kit/stories/atoms/QrCode.stories.jsx.html +175 -0
  152. package/coverage/rabbit-ui-kit/stories/atoms/RateSelector.stories.jsx.html +136 -0
  153. package/coverage/rabbit-ui-kit/stories/atoms/Validation.stories.jsx.html +178 -0
  154. package/coverage/rabbit-ui-kit/stories/atoms/buttons/Button.stories.jsx.html +946 -0
  155. package/coverage/rabbit-ui-kit/stories/atoms/buttons/Close.stories.jsx.html +214 -0
  156. package/coverage/rabbit-ui-kit/stories/atoms/buttons/LinkButton.stories.jsx.html +295 -0
  157. package/coverage/rabbit-ui-kit/stories/atoms/buttons/index.html +146 -0
  158. package/coverage/rabbit-ui-kit/stories/atoms/index.html +191 -0
  159. package/coverage/rabbit-ui-kit/stories/molecules/LineWithIconLink.stories.jsx.html +154 -0
  160. package/coverage/rabbit-ui-kit/stories/molecules/TitledLineWithIconLink.stories.jsx.html +160 -0
  161. package/coverage/rabbit-ui-kit/stories/molecules/index.html +131 -0
  162. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/Dialog.stories.jsx.html +589 -0
  163. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogButtons/DialogButtons.stories.jsx.html +328 -0
  164. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogButtons/index.html +116 -0
  165. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogStep/DialogStep.stories.jsx.html +337 -0
  166. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogStep/index.html +116 -0
  167. package/coverage/rabbit-ui-kit/stories/organisms/Dialog/index.html +116 -0
  168. package/coverage/rabbit-ui-kit/stories/stubs/exampleContent.jsx.html +145 -0
  169. package/coverage/rabbit-ui-kit/stories/stubs/index.html +116 -0
  170. package/coverage/rabbit-ui-kit/stories/templates/DeterminedErrorDialogStep.stories.jsx.html +193 -0
  171. package/coverage/rabbit-ui-kit/stories/templates/index.html +116 -0
  172. package/coverage/sort-arrow-sprite.png +0 -0
  173. package/coverage/sorter.js +196 -0
  174. package/dist/index.cjs +10019 -9
  175. package/dist/index.cjs.map +1 -1
  176. package/dist/index.css +71418 -1641
  177. package/dist/index.css.map +1 -1
  178. package/dist/index.modern.js +7716 -11
  179. package/dist/index.modern.js.map +1 -1
  180. package/dist/index.module.js +9939 -11
  181. package/dist/index.module.js.map +1 -1
  182. package/dist/index.umd.js +10010 -12
  183. package/dist/index.umd.js.map +1 -1
  184. package/index.js +1 -1
  185. package/package.json +29 -5
  186. package/src/assets/image/icons/arrow-tosca.svg +3 -0
  187. package/src/assets/wrappedImages/arrowIcon.jsx +13 -0
  188. package/src/assets/wrappedImages/arrowTosca.jsx +14 -0
  189. package/src/assets/wrappedImages/arrowWhite.jsx +14 -0
  190. package/src/assets/wrappedImages/darkRectangle.jsx +7 -0
  191. package/src/assets/wrappedImages/determinedError.jsx +118 -0
  192. package/src/assets/wrappedImages/failedValidationIcon.jsx +39 -0
  193. package/src/assets/wrappedImages/infoIcon.jsx +16 -0
  194. package/src/assets/wrappedImages/noticeQuestionIcon.jsx +54 -0
  195. package/src/assets/wrappedImages/successfulValidationIcon.jsx +26 -0
  196. package/src/assets/wrappedImages/walletIcon.jsx +22 -0
  197. package/src/common/adapters/axiosAdapter.js +35 -0
  198. package/src/common/adapters/qrUtils.js +18 -0
  199. package/src/common/amountUtils.js +359 -0
  200. package/src/common/errorUtils.js +42 -0
  201. package/src/common/external-apis/apiGroups.js +55 -0
  202. package/src/common/external-apis/ipAddressProviders.js +89 -0
  203. package/src/common/fiatCurrenciesService.js +153 -0
  204. package/src/common/models/blockchain.js +10 -0
  205. package/src/common/models/coin.js +153 -0
  206. package/src/common/models/protocol.js +5 -0
  207. package/src/common/tests/amountUtils/composeRateText.test.js +152 -0
  208. package/src/common/tests/integration/external-apis/ipAddressProviders/getClientIpAddress.test.js +12 -0
  209. package/src/common/utils/cache.js +242 -0
  210. package/src/common/utils/emailAPI.js +16 -0
  211. package/src/common/utils/logging/logger.js +41 -0
  212. package/src/common/utils/logging/logsStorage.js +61 -0
  213. package/src/common/utils/postponeExecution.js +11 -0
  214. package/src/common/utils/safeStringify.js +50 -0
  215. package/src/components/atoms/AssetIcon/AssetIcon.jsx +54 -0
  216. package/{stories → src/components}/atoms/AssetIcon/asset-icon.module.scss +1 -1
  217. package/src/components/atoms/AssetSelection/AssetSelection.jsx +67 -0
  218. package/src/components/atoms/AssetSelection/asset-selection.module.scss +56 -0
  219. package/src/components/atoms/BackgroundTitle/BackgroundTitle.jsx +34 -0
  220. package/src/components/atoms/BackgroundTitle/background-title.module.scss +52 -0
  221. package/src/components/atoms/InformationMessage/InformationMessage.jsx +50 -0
  222. package/src/components/atoms/InformationMessage/information-message.module.scss +38 -0
  223. package/src/components/atoms/Input/Input.jsx +182 -0
  224. package/src/components/atoms/Input/input.module.scss +107 -0
  225. package/{stories → src/components}/atoms/LoadingDots/LoadingDots.jsx +8 -28
  226. package/{stories → src/components}/atoms/LoadingDots/LoadingDots.module.scss +1 -1
  227. package/src/components/atoms/NoticeIcon/NoticeIcon.jsx +64 -0
  228. package/src/components/atoms/NoticeIcon/notice-icon.module.scss +14 -0
  229. package/src/components/atoms/QrCode/QrCode.jsx +34 -0
  230. package/src/components/atoms/QrCode/qr-code.module.scss +15 -0
  231. package/src/components/atoms/RateSelector/RateSelector.jsx +29 -0
  232. package/src/components/atoms/RateSelector/rate-selector.module.scss +47 -0
  233. package/{stories/atoms/SupportChat/SupportChat.js → src/components/atoms/SupportChat/SupportChat.jsx} +4 -1
  234. package/src/components/atoms/Textarea/Textarea.jsx +146 -0
  235. package/src/components/atoms/Textarea/textarea.module.scss +71 -0
  236. package/src/components/atoms/TitleBox/TitleBox.jsx +141 -0
  237. package/src/components/atoms/TitleBox/title-box.module.scss +32 -0
  238. package/src/components/atoms/Tooltip/Tooltip.jsx +68 -0
  239. package/src/components/atoms/Tooltip/tooltip.module.scss +237 -0
  240. package/src/components/atoms/TwoLinesOfText/LinesOfText.jsx +74 -0
  241. package/src/components/atoms/TwoLinesOfText/lines-of-text.module.scss +65 -0
  242. package/src/components/atoms/Validation/Validation.jsx +41 -0
  243. package/src/components/atoms/Validation/validation.module.scss +15 -0
  244. package/{stories → src/components}/atoms/buttons/Button/Button.jsx +22 -48
  245. package/{stories → src/components}/atoms/buttons/Button/Button.module.scss +1 -1
  246. package/src/components/atoms/buttons/Close/Close.jsx +53 -0
  247. package/src/components/atoms/buttons/Close/close.module.scss +75 -0
  248. package/src/components/atoms/buttons/LinkButton/LinkButton.jsx +106 -0
  249. package/src/components/atoms/buttons/LinkButton/link-button.module.scss +49 -0
  250. package/src/components/atoms/buttons/RadioButtonWithText/RadioButtonWithText.jsx +110 -0
  251. package/src/components/atoms/buttons/RadioButtonWithText/radio-button-with-text.module.scss +86 -0
  252. package/src/components/hooks/useCallHandlingErrors.js +22 -0
  253. package/src/components/hooks/useReferredState.js +24 -0
  254. package/src/components/molecules/AmountInput/AmountInput.jsx +304 -0
  255. package/src/components/molecules/AmountInput/amount-input.module.scss +189 -0
  256. package/src/components/molecules/CoinPicker/CoinPicker.jsx +509 -0
  257. package/src/components/molecules/CoinPicker/coin-picker.module.scss +207 -0
  258. package/src/components/molecules/LineWithIconLink/LineWithIconLink.jsx +35 -0
  259. package/src/components/molecules/LineWithIconLink/line-with-icon-link.module.scss +25 -0
  260. package/src/components/molecules/TitledLineWithIconLink/TitledLineWithIconLink.jsx +30 -0
  261. package/src/components/organisms/CoinPickerDialogStep/CoinPickerDialogStep.jsx +64 -0
  262. package/src/components/organisms/Dialog/Dialog.jsx +465 -0
  263. package/src/components/organisms/Dialog/DialogButtons/DialogButtons.jsx +122 -0
  264. package/src/components/organisms/Dialog/DialogButtons/dialog-buttons.module.scss +25 -0
  265. package/src/components/organisms/Dialog/DialogStep/DialogStep.jsx +533 -0
  266. package/src/components/organisms/Dialog/DialogStep/dialog-step.module.scss +381 -0
  267. package/src/components/organisms/Dialog/dialog.module.scss +226 -0
  268. package/src/components/organisms/SwapForm/SwapForm.jsx +1105 -0
  269. package/src/components/organisms/SwapForm/swap-form.module.scss +134 -0
  270. package/src/components/templates/DeterminedErrorDialogStep/DeterminedErrorDialogStep.jsx +77 -0
  271. package/src/components/tests/utils/inputValueProviders/provideFormatOfFloatValueByInputString.test.js +132 -0
  272. package/src/components/tests/utils/urlQueryUtils/getQueryParameterValues.test.js +65 -0
  273. package/src/components/tests/utils/urlQueryUtils/saveQueryParameterAndValues.test.js +104 -0
  274. package/src/components/utils/inputValueProviders.js +50 -0
  275. package/src/components/utils/textUtils.js +18 -0
  276. package/src/components/utils/uiUtils.js +12 -0
  277. package/src/components/utils/urlQueryUtils.js +62 -0
  278. package/src/constants/atoms/Close/close.jsx +5 -0
  279. package/src/constants/atoms/LinkButton/linkButton.jsx +6 -0
  280. package/src/constants/atoms/Tooltip/tooltip.jsx +8 -0
  281. package/src/constants/globalConstants.jsx +3 -0
  282. package/src/constants/organisms/dialog/DialogStep/dialogStep.js +1 -0
  283. package/src/constants/organisms/dialog/dialog.js +29 -0
  284. package/src/index.js +88 -0
  285. package/src/robustExteranlApiCallerService/cacheAndConcurrentRequestsResolver.js +495 -0
  286. package/src/robustExteranlApiCallerService/cachedRobustExternalApiCallerService.js +147 -0
  287. package/src/robustExteranlApiCallerService/cancelProcessing.js +29 -0
  288. package/src/robustExteranlApiCallerService/concurrentCalculationsMetadataHolder.js +75 -0
  289. package/src/robustExteranlApiCallerService/externalApiProvider.js +156 -0
  290. package/src/robustExteranlApiCallerService/externalServicesStatsCollector.js +78 -0
  291. package/src/robustExteranlApiCallerService/robustExternalAPICallerService.js +304 -0
  292. package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/_performCallAttempt.test.js +533 -0
  293. package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/callExternalAPI.test.js +532 -0
  294. package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/constructor.test.js +19 -0
  295. package/src/swaps-lib/external-apis/swapProvider.js +208 -0
  296. package/src/swaps-lib/external-apis/swapspaceSwapProvider.js +704 -0
  297. package/src/swaps-lib/models/baseSwapCreationInfo.js +43 -0
  298. package/src/swaps-lib/models/existingSwap.js +73 -0
  299. package/src/swaps-lib/models/existingSwapWithFiatData.js +128 -0
  300. package/src/swaps-lib/services/publicSwapService.js +601 -0
  301. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +538 -0
  302. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/createSwap.test.js +1249 -0
  303. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getAllSupportedCurrencies.test.js +66 -0
  304. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getDepositCurrencies.test.js +76 -0
  305. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getSwapInfo.test.js +1580 -0
  306. package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getWithdrawalCurrencies.test.js +105 -0
  307. package/src/swaps-lib/test/utils/swapUtils/safeHandleRequestsLimitExceeding.test.js +80 -0
  308. package/src/swaps-lib/utils/swapUtils.js +170 -0
  309. package/stories/stubs/exampleContent.jsx +20 -0
  310. package/styles/_placeholder.scss +1 -1
  311. package/styles/fonts/NunitoSans-Bold.ttf +0 -0
  312. package/styles/fonts/NunitoSans-ExtraBold.ttf +0 -0
  313. package/styles/fonts/NunitoSans-Light.ttf +0 -0
  314. package/styles/fonts/NunitoSans-Regular.ttf +0 -0
  315. package/styles/fonts/NunitoSans-SemiBold.ttf +0 -0
  316. package/styles/global-styles-index.scss +1 -1
  317. package/styles/index.scss +5 -3
  318. package/stories/atoms/AssetIcon/AssetIcon.js +0 -55
  319. package/stories/index.js +0 -4
@@ -0,0 +1,1105 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import React, { useEffect, useState } from "react";
3
+ import PropTypes from "prop-types";
4
+
5
+ import s from "./swap-form.module.scss";
6
+
7
+ import { useReferredState } from "../../hooks/useReferredState.js";
8
+ import { useCallHandlingErrors } from "../../hooks/useCallHandlingErrors.js";
9
+
10
+ import { AmountUtils } from "../../../common/amountUtils.js";
11
+ import { TitleBox } from "../../atoms/TitleBox/TitleBox.jsx";
12
+ import { AmountInput } from "../../molecules/AmountInput/AmountInput.jsx";
13
+ import { Validation } from "../../atoms/Validation/Validation.jsx";
14
+ import { Button } from "../../atoms/buttons/Button/Button.jsx";
15
+ import { Textarea } from "../../atoms/Textarea/Textarea.jsx";
16
+ import { TOOLTIP_POSITIONS } from "../../../constants/atoms/Tooltip/tooltip.jsx";
17
+ import { RateSelector } from "../../atoms/RateSelector/RateSelector.jsx";
18
+
19
+ /**
20
+ * This is the type definition of a function used inside SwapForm to compose the URL for the hero button.
21
+ *
22
+ * @function
23
+ * @name composeConfirmButtonTo
24
+ * @param {string} [fromTicker] - Ticker symbol of the asset being sent.
25
+ * @param {string} [toTicker] - Ticker symbol of the asset being received.
26
+ * @param {string} [fromAmount] - Amount of the asset being sent.
27
+ * @return {string} Full URL or relative URL that can be used for <a href="..." />.
28
+ */
29
+
30
+ /**
31
+ * Common click handler without parameters and return value, just your logic execution.
32
+ *
33
+ * @function
34
+ * @name handleClick
35
+ * @return {void}
36
+ */
37
+
38
+ /**
39
+ * Form executes this function when swap creation info retrieval is finished successfully.
40
+ *
41
+ * @function
42
+ * @name setSwapCreationEstimation
43
+ * @param {BaseSwapCreationInfo} details - Details of the swap creation estimation.
44
+ * @return {void}
45
+ */
46
+
47
+ /**
48
+ * Error handler for unexpected errors.
49
+ *
50
+ * @function
51
+ * @name handleUnexpectedError
52
+ * @param {Error} error - The unexpected error encountered.
53
+ * @return {void}
54
+ */
55
+
56
+ /**
57
+ * Should implement the logic with rotating assets (if you want "to" to become "from" and "from" to become "to").
58
+ *
59
+ * @function
60
+ * @name rotateAssets
61
+ * @param {string} sendingAssetTicker - Ticker symbol of the asset being sent.
62
+ * @param {string} receivingAssetTicker - Ticker symbol of the asset being received.
63
+ * @return {void}
64
+ */
65
+
66
+ /**
67
+ * Error handler for standard errors that we can recognize.
68
+ *
69
+ * @function
70
+ * @name handleSwapServiceError
71
+ * @param {string} errorCode - Error code returned as "reason" from your handlers.
72
+ * @param {function} setValidationContent - Function to set the validation error message on the form.
73
+ * @param {function} setBalanceValid - Function to set the balance validity, accepts a boolean.
74
+ * @param {function} setMinimalAmountValid - Function to set the minimal amount validity, accepts a boolean.
75
+ * @param {function} setMaximumAmountValid - Function to set the maximum amount validity, accepts a boolean.
76
+ * @param {function} setIsPairSupported - Function to set the pair support status, accepts a boolean.
77
+ * @param {function} setIsSameCoins - Function to set the status if the same coins are used, accepts a boolean.
78
+ * @return {void}
79
+ */
80
+
81
+ /**
82
+ * Handler for the confirm button click. You should implement errors handling inside it.
83
+ *
84
+ * @function
85
+ * @name handleConfirmButtonClick
86
+ * @param {function} resetButtonLoader - callback resetting the confirm button loader
87
+ * @param {function} setValidationContent - Function to set the validation error message on the form.
88
+ * @param {function} setBalanceValid - Function to set the balance validity, accepts a boolean.
89
+ * @param {function} setMinimalAmountValid - Function to set the minimal amount validity, accepts a boolean.
90
+ * @param {function} setMaximumAmountValid - Function to set the maximum amount validity, accepts a boolean.
91
+ * @param {function} setIsPairSupported - Function to set the pair support status, accepts a boolean.
92
+ * @param {function} setIsSameCoins - Function to set the status if the same coins are used, accepts a boolean.
93
+ * @return {void}
94
+ */
95
+
96
+ /**
97
+ * Async function that retrieves swap creation info by given params.
98
+ *
99
+ * @function
100
+ * @name retrieveSwapDetails
101
+ * @param {string} sendingAssetTicker - Ticker symbol of the asset being sent.
102
+ * @param {string} receivingAssetTicker - Ticker symbol of the asset being received.
103
+ * @param {string} amount - Amount of the asset to be swapped.
104
+ * @param {boolean} [isSwapAll=false] - Indicates if the swap should use all available balance.
105
+ * @return {Promise<{
106
+ * result: false,
107
+ * reason: string,
108
+ * min: (string|null),
109
+ * max: (string|null),
110
+ * rate: (string|undefined),
111
+ * fiatMin: (number|null),
112
+ * fiatMax: (number|null)
113
+ * }|{
114
+ * result: true,
115
+ * swapCreationInfo: BaseSwapCreationInfo
116
+ * }>}
117
+ */
118
+
119
+ /**
120
+ * Async function that retrieves initial swap details for a pair like whether the pair is available, min/max swappable amounts, etc.
121
+ *
122
+ * @function
123
+ * @name retrieveInitialSwapData
124
+ * @param {string} sendingAssetTicker - Ticker symbol of the asset being sent.
125
+ * @param {string} receivingAssetTicker - Ticker symbol of the asset being received.
126
+ * @return {Promise<{
127
+ * result: true,
128
+ * min: string,
129
+ * fiatMin: (number|null),
130
+ * max: string,
131
+ * fiatMax: (number|null),
132
+ * rate: (string|null)
133
+ * }|{
134
+ * result: false,
135
+ * reason: string
136
+ * }>}
137
+ */
138
+
139
+ /**
140
+ * Swap form provides basic functionality for entering to/from amounts both in crypto and fiat, switching assets,
141
+ * selecting assets, showing balance for assets. It gracefully handles unavailable fiat rates and can work
142
+ * both with and without a wallet environment (without balances).
143
+ *
144
+ * @param {object} props - Props object for SwapForm component.
145
+ * @param {string} props.sendingAssetTicker - Rabbit format of the ticker symbol for the asset being sent.
146
+ * @param {string} props.receivingAssetTicker - Rabbit format of the ticker symbol for the asset being received.
147
+ * @param {number} [props.sendingAssetDecimalCount=AmountUtils.significantDecimalCount] - Decimal count for the sending asset.
148
+ * @param {number} [props.receivingAssetDecimalCount=AmountUtils.significantDecimalCount] - Decimal count for the receiving asset.
149
+ * @param {string} props.sendingAssetTickerPrintable - Standard ticker symbol for the sending asset.
150
+ * @param {string} props.receivingAssetTickerPrintable - Standard ticker symbol for the receiving asset.
151
+ * @param {string} [props.sendingAssetProtocol] - Protocol name to be displayed in text on the change asset button.
152
+ * @param {string} [props.receivingAssetProtocol] - Protocol name to be displayed in text on the change asset button.
153
+ * @param {string} props.sendingAssetIconSrc - Source URL for the sending asset icon.
154
+ * @param {string} [props.sendingAssetProtocolIconSrc=null] - Optional source URL for the sending asset protocol icon.
155
+ * @param {string} props.receivingAssetIconSrc - Source URL for the receiving asset icon.
156
+ * @param {string} [props.receivingAssetProtocolIconSrc=null] - Optional source URL for the receiving asset protocol icon.
157
+ * @param {string} [props.fallBackAssetIconSrc=null] - Optional source URL for a fallback icon used when an icon fails to load.
158
+ * @param {string} [props.sendingAssetFeeCoinTickerPrintable] - Optional standard ticker symbol for the fee coin of the sending asset.
159
+ * @param {string} [props.sendingAssetBalance] - Balance of the sending asset.
160
+ * @param {string} [props.receivingAssetBalance] - Balance of the receiving asset.
161
+ * @param {handleClick} props.handleChangeSendingAssetClick - Function to handle clicking on the change sending asset button.
162
+ * @param {handleClick} props.handleChangeReceivingAssetClick - Function to handle clicking on the change receiving asset button.
163
+ * @param {handleConfirmButtonClick} props.handleConfirmButtonClick - Function to handle clicking on the confirm button.
164
+ * @param {composeConfirmButtonTo} props.composeConfirmButtonTo - Function to compose the URL for the confirm button.
165
+ * @param {setSwapCreationEstimation} props.setSwapCreationEstimation - Function to set the swap creation estimation.
166
+ * @param {handleUnexpectedError} props.handleUnexpectedError - Function to handle unexpected errors.
167
+ * @param {rotateAssets} props.rotateAssets - Function to rotate the assets (swap sending and receiving assets).
168
+ * @param {string} [props.preservedAmount=null] - Amount to be preserved.
169
+ * @param {handleSwapServiceError} props.handleSwapServiceError - Function to handle standard errors that we can recognize.
170
+ * @param {boolean} [props.formHasBalance] - Indicates if the form has balance information.
171
+ * @param {retrieveSwapDetails} props.retrieveSwapDetails - Function to retrieve swap details based on the given parameters.
172
+ * @param {retrieveInitialSwapData} props.retrieveInitialSwapData - Function to retrieve initial swap data for a given pair of assets.
173
+ * @param {number} props.triggerDataUpdateResetting - Number to reset interval updating the data periodically.
174
+ * @param {React.Ref} props.fromAssetSelectionButtonRef - Reference to the from asset selection button.
175
+ * @param {React.Ref} props.toAssetSelectionButtonRef - Reference to the to asset selection button.
176
+ * @param {number|string} [props.sendingAssetToFiatRate] - Rate for converting the sending asset to fiat.
177
+ * @param {number|string} [props.receivingAssetToFiatRate] - Rate for converting the receiving asset to fiat.
178
+ * @param {string} [props.fiatCurrencyCode] - Code for the fiat currency.
179
+ * @param {number} [props.fiatCurrencyDecimals] - Decimal places for the fiat currency.
180
+ * @param {boolean} [props.formHasFiat] - Indicates if the form supports fiat currency.
181
+ * @param {string|null} [props.termsOfUseUrl] - Terms of use URL, shown only if both terms & privacy policy passed.
182
+ * @param {string|null} [props.privacyPolicyUrl] - Privacy policy of use URL, shown only if both terms & privacy policy passed.
183
+ * @param {object} [props.translations] - Object containing translations, default English texts will be used if omitted.
184
+ * @param {string} props.swapSeparatorIconSrc - Source URL for the swap separator icon.
185
+ * @param {boolean} props.swapButtonAlwaysActive - Setting that allows the form state to proceed to the next step regardless of validity.
186
+ * @return {JSX.Element} Rendered SwapForm component.
187
+ * @constructor
188
+ */
189
+ export const SwapForm = ({
190
+ sendingAssetTicker,
191
+ receivingAssetTicker,
192
+ sendingAssetDecimalCount = AmountUtils.significantDecimalCount,
193
+ receivingAssetDecimalCount = AmountUtils.significantDecimalCount,
194
+ sendingAssetTickerPrintable,
195
+ receivingAssetTickerPrintable,
196
+ sendingAssetProtocol,
197
+ receivingAssetProtocol,
198
+ sendingAssetIconSrc,
199
+ sendingAssetProtocolIconSrc = null,
200
+ receivingAssetIconSrc,
201
+ receivingAssetProtocolIconSrc = null,
202
+ fallBackAssetIconSrc = null,
203
+ sendingAssetFeeCoinTickerPrintable,
204
+ sendingAssetBalance,
205
+ receivingAssetBalance,
206
+ handleChangeSendingAssetClick,
207
+ handleChangeReceivingAssetClick,
208
+ handleConfirmButtonClick = (
209
+ resetButtonLoader,
210
+ setValidationContent,
211
+ setBalanceValid,
212
+ setMinimalAmountValid,
213
+ setMaximumAmountValid,
214
+ setIsPairSupported,
215
+ setIsSameCoins
216
+ ) => {},
217
+ composeConfirmButtonTo = (fromTicker, toTicker, fromAmount) => "",
218
+ setSwapCreationEstimation = details => {},
219
+ handleUnexpectedError = error => {},
220
+ rotateAssets = (fromTicker, toTicker) => {},
221
+ preservedAmount = null,
222
+ handleSwapServiceError = (
223
+ errorCode,
224
+ setValidationContent,
225
+ setBalanceValid,
226
+ setMinimalAmountValid,
227
+ setMaximumAmountValid,
228
+ setIsPairSupported,
229
+ setIsSameCoins
230
+ ) => {},
231
+ formHasBalance = false,
232
+ retrieveSwapDetails = async (sendingAssetTicker, receivingAssetTicker, amount, isSwapAll = false) => {},
233
+ retrieveInitialSwapData = async (sendingAssetTicker, receivingAssetTicker) => {},
234
+ triggerDataUpdateResetting = 0,
235
+ fromAssetSelectionButtonRef = null,
236
+ toAssetSelectionButtonRef = null,
237
+ sendingAssetToFiatRate = null,
238
+ receivingAssetToFiatRate = null,
239
+ fiatCurrencyCode = null,
240
+ fiatCurrencyDecimals = null,
241
+ formHasFiat = true,
242
+ termsOfUseUrl = null,
243
+ privacyPolicyUrl = null,
244
+ translations = {
245
+ swapAllButtonTitles: {
246
+ enable: "Swap all",
247
+ cancel: "Cancel",
248
+ },
249
+ input: {
250
+ fiatPlaceholder: "Enter fiat amount",
251
+ balanceLoaderText: "Loading balance...",
252
+ },
253
+ consents: {
254
+ consentText: 'By clicking "Swap" you agree with Rabbit Swap\'s',
255
+ termsOfUse: "Terms of Use",
256
+ and: "and",
257
+ privacyPolicy: "Privacy Policy",
258
+ },
259
+ informationBlock: {
260
+ minimumAmount: "Minimal amount: ",
261
+ maximumAmount: "Maximum amount: ",
262
+ transactionFee: "Network fee: ",
263
+ calculatingNetworkFee: "Calculating network fee..",
264
+ loadingMinimalAmount: "Loading minimal amount..",
265
+ swapRate: "Rate: ",
266
+ calculatingSwapRates: "Calculating swap rates..",
267
+ pairNotAvailable: "Pair is not available now. Please, try again later or choose another pair.",
268
+ },
269
+ addressFields: {
270
+ addressTitle: "Recepient address",
271
+ extraIdTitle: "Extra ID (optional)",
272
+ extraIdPlaceholder: "Example: ABC123",
273
+ extraIdNotice:
274
+ "Please check if your recipient address requires a 'Memo' or 'Destination Tag' - sometimes called a tag, ID, label, or a note. Exchanges may require such ID for the deposit. Including this identifier is crucial when required, as omitting or misentering it can result in lost assets.",
275
+ },
276
+ rateSelector: {
277
+ floatingRate: "Floating rate",
278
+ fixedRate: "Fixed rate",
279
+ },
280
+ confirmButtonText: "Swap",
281
+ },
282
+ swapSeparatorIconSrc,
283
+ swapButtonAlwaysActive = false,
284
+ recepientAddress,
285
+ recepientAddressExtraId,
286
+ recepientAddressValid = true,
287
+ recepientAddressExtraIdValid = true,
288
+ setRecepientAddress,
289
+ setRecepientAddressExtraId,
290
+ recepientAddressExtraIdAvailable = false,
291
+ displayRateSelector = false,
292
+ }) => {
293
+ const DETAIL_REFRESH_INTERVAL_MS = 1.5 * 60000;
294
+ const IS_FIXED_BY_DEFAULT = false;
295
+
296
+ // Updating the states below will insert the new value into the send or receive input field
297
+ const [updateSendInputTo, setUpdateSendInputTo] = useState(preservedAmount ?? null);
298
+ const [updateReceiveInputTo, setUpdateReceiveInputTo] = useState(null);
299
+
300
+ const [sendAssetAmount, setSendAssetAmount] = useReferredState(
301
+ preservedAmount == null || preservedAmount === "" ? null : preservedAmount
302
+ );
303
+
304
+ const [swapRate, setSwapRate] = useState();
305
+ const [minimalAmount, setMinimalAmount] = useReferredState(null);
306
+ const [maximumAmount, setMaximumAmount] = useReferredState(null);
307
+ const [validationContent, setValidationContent] = useState();
308
+
309
+ const [minimalAmountValid, setMinimalAmountValid] = useState(true); // Whether the amount is above the minimal amount
310
+ const [maximumAmountValid, setMaximumAmountValid] = useState(true);
311
+ const [isPairSupported, setIsPairSupported] = useState(true);
312
+ const [isSameCoins, setIsSameCoins] = useState(false);
313
+ const [isSwapCalculated, setIsSwapCalculated] = useState(false);
314
+ const [readyToSwap, setReadyToSwap] = useState(false); // Basically a param that enables/disables the "Next" button
315
+ // TODO: [refactoring, moderate] instead of handling preservedAmount at a lot of cases below, just
316
+ // write single useEffect setting sendAssetAmount to the=is passed value and simplify the logic below. task_id=6453251e49b04c5e88a3cc771479ffb5
317
+ const [isAmountZero, setIsAmountZero] = useState(preservedAmount == null || String(preservedAmount) === "0");
318
+ const [isLoading, setIsLoading] = useReferredState(false); // Whether the form is in the progress of loading some data (new rates, for example)
319
+ const [isAddressFieldEnabled, setIsAddressFieldEnabled] = useState(false);
320
+ const [isFixedRate, setIsFixedRate] = useReferredState(null);
321
+
322
+ const [confirmButtonTo, setConfirmButtonTo] = useState(
323
+ composeConfirmButtonTo(sendingAssetTicker, receivingAssetTicker, preservedAmount)
324
+ );
325
+
326
+ const [transactionFee, setTransactionFee] = useState();
327
+ const [balanceValid, setBalanceValid] = useState(true); // Whether the amount is less than total balance
328
+ const [isSwapAll, setIsSwapAll] = useReferredState(null);
329
+ const [swapAllButtonLoaderReSetter, setSwapAllButtonLoaderReSetter] = useState([]);
330
+
331
+ const [dataUpdateTimeoutId, setDataUpdateTimeoutId] = useReferredState(null);
332
+ const [idleDataUpdateTimeoutId, setIdleDataUpdateTimeoutId] = useReferredState(null);
333
+
334
+ const callHandlingErrors = useCallHandlingErrors();
335
+
336
+ const recalculationDelayOnTyping = 1000;
337
+
338
+ const handleSendAssetAmountChange = amount => {
339
+ if (amount != null && amount !== "") {
340
+ setUpdateReceiveInputTo(AmountUtils.trim(BigNumber(amount).times(swapRate), receivingAssetDecimalCount));
341
+ } else {
342
+ setUpdateReceiveInputTo("");
343
+ }
344
+ setSendAssetAmount(amount);
345
+ };
346
+
347
+ const handleReceiveAssetAmountChange = amount => {
348
+ let sendAssetAmount = "";
349
+ if (amount != null && amount !== "") {
350
+ sendAssetAmount = AmountUtils.trim(BigNumber(amount).div(swapRate), sendingAssetDecimalCount);
351
+ }
352
+ setUpdateSendInputTo(sendAssetAmount);
353
+ setSendAssetAmount(sendAssetAmount);
354
+ };
355
+
356
+ const handleMinimalAmountClick = () => {
357
+ if (!minimalAmount.current) return;
358
+
359
+ setUpdateSendInputTo(minimalAmount.current?.crypto);
360
+ handleSendAssetAmountChange(minimalAmount.current?.crypto);
361
+ };
362
+
363
+ const handleMaximumAmountClick = () => {
364
+ if (!maximumAmount.current) return;
365
+
366
+ setUpdateSendInputTo(maximumAmount.current?.crypto);
367
+ handleSendAssetAmountChange(maximumAmount.current?.crypto);
368
+ };
369
+
370
+ const handleSwapAllClick = resetButtonLoader => {
371
+ setIsSwapAll(prev => {
372
+ if (prev) {
373
+ // Setting amount inputs to empty string if we are handling the disabling of previously enabled swap all
374
+ setUpdateSendInputTo("");
375
+ setUpdateReceiveInputTo("");
376
+ setSendAssetAmount(null);
377
+ }
378
+ return !prev;
379
+ });
380
+ setSwapAllButtonLoaderReSetter([resetButtonLoader]);
381
+ };
382
+
383
+ const processMinMaxAmounts = amount => {
384
+ if (amount === null) return;
385
+
386
+ setMaximumAmountValid(
387
+ !maximumAmount.current || BigNumber(amount).eq("0") || BigNumber(amount).lte(maximumAmount.current.crypto)
388
+ );
389
+ setMinimalAmountValid(
390
+ !minimalAmount.current || BigNumber(amount).eq("0") || BigNumber(amount).gte(minimalAmount.current?.crypto)
391
+ );
392
+ };
393
+
394
+ const requestDataRefresh = (amount, immediately = false, isSwapAll = false) => {
395
+ try {
396
+ clearTimeout(dataUpdateTimeoutId.current);
397
+
398
+ if (isSwapAll) {
399
+ loadFullEstimation(null);
400
+ return;
401
+ }
402
+
403
+ if (!amount) {
404
+ return;
405
+ }
406
+
407
+ if (BigNumber(amount).eq("0")) {
408
+ if (immediately) {
409
+ loadMinimalAmountAndSwapRate(true);
410
+ } else {
411
+ setDataUpdateTimeoutId(
412
+ setTimeout(() => loadMinimalAmountAndSwapRate(true), recalculationDelayOnTyping)
413
+ );
414
+ }
415
+ } else {
416
+ if (immediately) {
417
+ loadFullEstimation(amount, preservedAmount && String(preservedAmount) !== "0" ? true : undefined);
418
+ } else {
419
+ setDataUpdateTimeoutId(setTimeout(() => loadFullEstimation(amount), recalculationDelayOnTyping));
420
+ }
421
+ }
422
+ } catch (e) {
423
+ handleUnexpectedError(e);
424
+ }
425
+ };
426
+
427
+ const setAmountLimitsAndRate = details => {
428
+ setSwapRate(details?.rate ?? null);
429
+ setMinimalAmount(details.min == null ? null : { crypto: details.min, fiat: details.fiatMin });
430
+ setMaximumAmount(details.max == null ? null : { crypto: details.max, fiat: details.fiatMax });
431
+ if (details.feeCoins != null) {
432
+ setTransactionFee({
433
+ crypto: details.feeCoins,
434
+ fiat: details.feeFiat,
435
+ });
436
+ } else {
437
+ setTransactionFee(null);
438
+ }
439
+ };
440
+
441
+ const loadFullEstimation = (amount, isForPreserved = false) => {
442
+ (async () => {
443
+ try {
444
+ const dataMemento = {
445
+ rate: swapRate,
446
+ min: minimalAmount.current?.crypto,
447
+ max: maximumAmount.current?.crypto,
448
+ feeCoins: transactionFee?.crypto,
449
+ feeFiat: transactionFee?.fiat,
450
+ };
451
+ setIsLoading(true);
452
+ setMinimalAmount(null);
453
+ setMaximumAmount(null);
454
+ setTransactionFee(null);
455
+ setValidationContent(null);
456
+ setSwapCreationEstimation(null);
457
+ setIsSameCoins(false);
458
+ setIsPairSupported(true);
459
+ setIsSwapCalculated(false);
460
+
461
+ const response = await retrieveSwapDetails(
462
+ sendingAssetTicker,
463
+ receivingAssetTicker,
464
+ amount,
465
+ isSwapAll.current,
466
+ isFixedRate.current ?? IS_FIXED_BY_DEFAULT
467
+ );
468
+
469
+ if (
470
+ !isSwapAll.current &&
471
+ String(amount) !==
472
+ String(
473
+ isForPreserved && sendAssetAmount.current == null
474
+ ? preservedAmount
475
+ : sendAssetAmount.current
476
+ )
477
+ ) {
478
+ // Means amount changed and we no more need to do this exact calculation
479
+ return;
480
+ }
481
+
482
+ if (response.result) {
483
+ const swapCreationInfo = response.swapCreationInfo;
484
+
485
+ setUpdateSendInputTo(swapCreationInfo.fromAmountCoins);
486
+ setUpdateReceiveInputTo(swapCreationInfo.toAmountCoins);
487
+
488
+ if (isSwapAll.current) {
489
+ setIsAmountZero(BigNumber("0").eq(swapCreationInfo.fromAmountCoins));
490
+ }
491
+
492
+ setAmountLimitsAndRate(swapCreationInfo);
493
+ setSwapCreationEstimation(swapCreationInfo);
494
+ processMinMaxAmounts(isSwapAll.current ? swapCreationInfo.fromAmountCoins : amount);
495
+ setIsSwapCalculated(true);
496
+ } else {
497
+ handleSwapServiceError(
498
+ response.reason,
499
+ setValidationContent,
500
+ setBalanceValid,
501
+ setMinimalAmountValid,
502
+ setMaximumAmountValid,
503
+ setIsPairSupported,
504
+ setIsSameCoins
505
+ );
506
+ if (isSwapAll.current) {
507
+ /* We disable swap all if swap all details retrieval fails and set
508
+ * previous limits and rate. We set null to avoid triggering reloading of initial data.
509
+ */
510
+ setIsSwapAll(null);
511
+ setAmountLimitsAndRate(dataMemento);
512
+ } else {
513
+ /* We set returned amount limits and rate only if the failed details retrieval is not
514
+ * for the swap All case.
515
+ */
516
+ setAmountLimitsAndRate(response);
517
+ }
518
+ }
519
+ setIsLoading(false);
520
+ } catch (e) {
521
+ handleUnexpectedError(e);
522
+ }
523
+ })();
524
+ };
525
+
526
+ const loadMinimalAmountAndSwapRate = (isCalledForClearedInput = false) => {
527
+ (async () => {
528
+ try {
529
+ setIsLoading(true);
530
+ setMinimalAmount(null);
531
+ setMaximumAmount(null);
532
+ setSwapRate(null);
533
+ setValidationContent(null);
534
+ setIsPairSupported(true);
535
+ setIsSwapCalculated(false);
536
+
537
+ const swapData = await retrieveInitialSwapData(sendingAssetTicker, receivingAssetTicker);
538
+
539
+ if (sendAssetAmount.current != null && !isCalledForClearedInput) {
540
+ // Means user already entered amount after starting the form initialization
541
+ return;
542
+ }
543
+
544
+ if (swapData.result === true) {
545
+ setAmountLimitsAndRate(swapData);
546
+ } else {
547
+ handleSwapServiceError(
548
+ swapData.reason,
549
+ setValidationContent,
550
+ setBalanceValid,
551
+ setMinimalAmountValid,
552
+ setMaximumAmountValid,
553
+ setIsPairSupported,
554
+ setIsSameCoins
555
+ );
556
+ }
557
+
558
+ setIsLoading(false);
559
+ } catch (e) {
560
+ handleUnexpectedError(e);
561
+ }
562
+ })();
563
+ };
564
+
565
+ const handleChangeAssetsIconClick = e => {
566
+ callHandlingErrors(() => {
567
+ if (!isLoading.current) {
568
+ setIsSwapAll(null);
569
+ setMaximumAmountValid(true);
570
+ setMinimalAmountValid(true);
571
+ rotateAssets(sendingAssetTicker, receivingAssetTicker);
572
+ }
573
+ }, e);
574
+ };
575
+
576
+ const handleRateModeChanged = isFixed => {
577
+ setIsFixedRate(isFixed);
578
+ requestDataRefresh(sendAssetAmount.current, true);
579
+ };
580
+
581
+ useEffect(() => {
582
+ if (isSwapAll.current === true) {
583
+ requestDataRefresh(undefined, true, true);
584
+ } else if (isSwapAll.current === false) {
585
+ loadMinimalAmountAndSwapRate();
586
+ }
587
+ // eslint-disable-next-line react-hooks/exhaustive-deps
588
+ }, [isSwapAll.current]);
589
+
590
+ useEffect(() => {
591
+ setConfirmButtonTo(
592
+ composeConfirmButtonTo(
593
+ sendingAssetTicker,
594
+ receivingAssetTicker,
595
+ sendAssetAmount.current || preservedAmount || null
596
+ )
597
+ );
598
+ // eslint-disable-next-line react-hooks/exhaustive-deps
599
+ }, [sendingAssetTicker, receivingAssetTicker]);
600
+
601
+ useEffect(() => {
602
+ if (!sendingAssetTicker || !receivingAssetTicker) return;
603
+
604
+ const isCurrentAmountNotZero = sendAssetAmount.current && !BigNumber("0").eq(sendAssetAmount.current);
605
+ const isPreservedAmountNotZero = preservedAmount && !BigNumber("0").eq(preservedAmount);
606
+ if (isCurrentAmountNotZero) {
607
+ loadFullEstimation(sendAssetAmount.current);
608
+ } else if (isPreservedAmountNotZero) {
609
+ loadFullEstimation(preservedAmount, true);
610
+ } else {
611
+ loadMinimalAmountAndSwapRate();
612
+ }
613
+
614
+ // eslint-disable-next-line react-hooks/exhaustive-deps
615
+ }, [sendingAssetTicker, receivingAssetTicker]);
616
+
617
+ useEffect(() => {
618
+ if (!minimalAmountValid || isAmountZero) {
619
+ setTransactionFee(null);
620
+ }
621
+ if (isAmountZero) {
622
+ clearTimeout(dataUpdateTimeoutId.current);
623
+ }
624
+
625
+ setReadyToSwap(
626
+ swapButtonAlwaysActive ||
627
+ ((balanceValid || !formHasBalance) &&
628
+ minimalAmountValid &&
629
+ !isAmountZero &&
630
+ isSwapCalculated &&
631
+ (!isSameCoins || !formHasBalance) &&
632
+ isPairSupported &&
633
+ (!isAddressFieldEnabled || recepientAddressValid))
634
+ );
635
+
636
+ // eslint-disable-next-line react-hooks/exhaustive-deps
637
+ }, [
638
+ balanceValid,
639
+ formHasBalance,
640
+ minimalAmountValid,
641
+ isAmountZero,
642
+ isSwapCalculated,
643
+ isSameCoins,
644
+ isPairSupported,
645
+ isAddressFieldEnabled,
646
+ recepientAddressValid,
647
+ ]);
648
+
649
+ useEffect(() => {
650
+ // Here we set up auto recalculations for the swap details if the form is ready to swap but is idle for some time
651
+ let timeoutId = null;
652
+ if (readyToSwap) {
653
+ timeoutId = setTimeout(
654
+ () => requestDataRefresh(sendAssetAmount.current ?? preservedAmount, true),
655
+ DETAIL_REFRESH_INTERVAL_MS
656
+ );
657
+ setIdleDataUpdateTimeoutId(timeoutId);
658
+ } else {
659
+ clearTimeout(idleDataUpdateTimeoutId.current);
660
+ setIdleDataUpdateTimeoutId(null);
661
+ }
662
+ return () => {
663
+ timeoutId != null && clearTimeout(timeoutId);
664
+ };
665
+ // eslint-disable-next-line react-hooks/exhaustive-deps
666
+ }, [readyToSwap]);
667
+
668
+ // TODO: [refactoring, critical] this code looks like a hack related to task_id=6e328d39063142b7b9fa01d497e616da
669
+ useEffect(() => {
670
+ if (triggerDataUpdateResetting) {
671
+ clearTimeout(dataUpdateTimeoutId.current);
672
+ setDataUpdateTimeoutId(null);
673
+
674
+ clearTimeout(idleDataUpdateTimeoutId.current);
675
+ setIdleDataUpdateTimeoutId(null);
676
+ }
677
+ // eslint-disable-next-line react-hooks/exhaustive-deps
678
+ }, [triggerDataUpdateResetting]);
679
+
680
+ // Resets the passed "set value to" param to null, so it can be used multiple times with any value
681
+ useEffect(() => {
682
+ if (!!updateSendInputTo) setUpdateSendInputTo(null);
683
+ if (!!updateReceiveInputTo) setUpdateReceiveInputTo(null);
684
+ // eslint-disable-next-line react-hooks/exhaustive-deps
685
+ }, [updateSendInputTo, updateReceiveInputTo]);
686
+
687
+ useEffect(() => {
688
+ if (swapRate != null && sendAssetAmount.current != null) {
689
+ setUpdateReceiveInputTo(
690
+ AmountUtils.trim(BigNumber(sendAssetAmount.current).times(swapRate), receivingAssetDecimalCount)
691
+ );
692
+ }
693
+ // eslint-disable-next-line react-hooks/exhaustive-deps
694
+ }, [swapRate]);
695
+
696
+ useEffect(() => {
697
+ if (isLoading.current === false && swapAllButtonLoaderReSetter?.length) {
698
+ swapAllButtonLoaderReSetter[0]();
699
+ setSwapAllButtonLoaderReSetter([]);
700
+ }
701
+ // eslint-disable-next-line react-hooks/exhaustive-deps
702
+ }, [isLoading.current, swapAllButtonLoaderReSetter]);
703
+
704
+ // Handlers upon changing the asset amount
705
+ useEffect(() => {
706
+ setConfirmButtonTo(composeConfirmButtonTo(sendingAssetTicker, receivingAssetTicker, sendAssetAmount.current));
707
+
708
+ if (sendAssetAmount.current == null) return;
709
+ let processingAmount = sendAssetAmount.current === "" ? "0" : sendAssetAmount.current;
710
+ requestDataRefresh(processingAmount);
711
+ processMinMaxAmounts(processingAmount);
712
+ setIsAmountZero(BigNumber("0").eq(processingAmount));
713
+ setIsSwapCalculated(false);
714
+ // eslint-disable-next-line react-hooks/exhaustive-deps
715
+ }, [sendAssetAmount.current]);
716
+
717
+ // Checking if all necessary props for address input are passed properly.
718
+ useEffect(() => {
719
+ setIsAddressFieldEnabled(
720
+ recepientAddress !== undefined &&
721
+ recepientAddressExtraId !== undefined &&
722
+ recepientAddressValid !== undefined &&
723
+ setRecepientAddress !== undefined &&
724
+ typeof setRecepientAddress === "function" &&
725
+ setRecepientAddressExtraId !== undefined &&
726
+ typeof setRecepientAddressExtraId === "function"
727
+ );
728
+ // eslint-disable-next-line react-hooks/exhaustive-deps
729
+ }, [
730
+ recepientAddress,
731
+ recepientAddressExtraId,
732
+ recepientAddressValid,
733
+ recepientAddressExtraIdValid,
734
+ setRecepientAddress,
735
+ setRecepientAddressExtraId,
736
+ ]);
737
+
738
+ return (
739
+ <div className={s["swap-form"]}>
740
+ <TitleBox
741
+ linkButtonClick={
742
+ BigNumber(sendingAssetBalance?.assetAmount).eq(0)
743
+ ? null
744
+ : resetButtonLoader => handleSwapAllClick(resetButtonLoader)
745
+ }
746
+ linkText={
747
+ !formHasBalance
748
+ ? ""
749
+ : isSwapAll.current
750
+ ? translations.swapAllButtonTitles.cancel
751
+ : translations.swapAllButtonTitles.enable
752
+ }
753
+ linkButtonLoader={true}
754
+ isLinkButtonDisabled={
755
+ isLoading.current ||
756
+ sendingAssetTicker === receivingAssetTicker ||
757
+ BigNumber(sendingAssetBalance?.assetAmount).eq(0)
758
+ }
759
+ >
760
+ <div className={s["swap-form-inputs"]}>
761
+ <AmountInput
762
+ ticker={sendingAssetTicker}
763
+ tickerPrintable={sendingAssetTickerPrintable}
764
+ assetDecimalPlaces={sendingAssetDecimalCount}
765
+ assetBalance={sendingAssetBalance}
766
+ assetIconSrc={sendingAssetIconSrc}
767
+ assetIconProtocolSrc={sendingAssetProtocolIconSrc}
768
+ fallbackAssetIconSrc={fallBackAssetIconSrc}
769
+ disabled={isSwapAll.current || sendingAssetTicker === null || receivingAssetTicker === null}
770
+ handleCoinAmountChange={handleSendAssetAmountChange}
771
+ handleChangeAssetClick={handleChangeSendingAssetClick}
772
+ handleBalanceValidationChange={isValid => setBalanceValid(!isValid)}
773
+ updateAssetInputTo={updateSendInputTo}
774
+ showBalance={formHasBalance}
775
+ showBalanceValidation={formHasBalance}
776
+ showChangeAssetButton
777
+ changeAssetButtonProtocol={sendingAssetProtocol}
778
+ upperFormPosition
779
+ errorEncountered={!minimalAmountValid}
780
+ ref={fromAssetSelectionButtonRef}
781
+ isLoading={false}
782
+ cryptoAssetToFiatRate={sendingAssetToFiatRate}
783
+ fiatCurrencyCode={formHasFiat ? fiatCurrencyCode : null}
784
+ fiatCurrencyDecimals={fiatCurrencyDecimals}
785
+ balanceLoaderText={translations.input.balanceLoaderText}
786
+ fiatInputPlaceholderText={translations.input.fiatPlaceholder}
787
+ />
788
+ <div
789
+ className={
790
+ s["swap-form-inputs-separator"] +
791
+ " " +
792
+ (isLoading.current || sendingAssetTicker === null || receivingAssetTicker === null
793
+ ? s["disabled"]
794
+ : "")
795
+ }
796
+ >
797
+ <img
798
+ src={swapSeparatorIconSrc}
799
+ alt="swap icon"
800
+ draggable={false}
801
+ onClick={e => callHandlingErrors(handleChangeAssetsIconClick, e)}
802
+ />
803
+ </div>
804
+ <AmountInput
805
+ ticker={receivingAssetTicker}
806
+ tickerPrintable={receivingAssetTickerPrintable}
807
+ assetDecimalPlaces={receivingAssetDecimalCount}
808
+ assetBalance={receivingAssetBalance}
809
+ assetIconSrc={receivingAssetIconSrc}
810
+ assetIconProtocolSrc={receivingAssetProtocolIconSrc}
811
+ fallbackAssetIconSrc={fallBackAssetIconSrc}
812
+ disabled={isSwapAll.current || sendingAssetTicker === null || receivingAssetTicker === null}
813
+ locked={!formHasBalance}
814
+ handleCoinAmountChange={handleReceiveAssetAmountChange}
815
+ handleChangeAssetClick={handleChangeReceivingAssetClick}
816
+ updateAssetInputTo={updateReceiveInputTo}
817
+ showChangeAssetButton
818
+ changeAssetButtonProtocol={receivingAssetProtocol}
819
+ showBalance={formHasBalance}
820
+ lowerFormPosition
821
+ estimateAmount={!isFixedRate.current}
822
+ ref={toAssetSelectionButtonRef}
823
+ isLoading={isLoading.current}
824
+ cryptoAssetToFiatRate={receivingAssetToFiatRate}
825
+ fiatCurrencyCode={formHasFiat ? fiatCurrencyCode : null}
826
+ fiatCurrencyDecimals={fiatCurrencyDecimals}
827
+ balanceLoaderText={translations.input.balanceLoaderText}
828
+ fiatInputPlaceholderText={translations.input.fiatPlaceholder}
829
+ />
830
+ </div>
831
+ <div className={s["swap-form-information-field"]}>
832
+ {/* TODO: [refactoring, moderate] Add flags calculation for each message to avoid this ugly cumbersome implicit unclear logic of message displaying. task_id=8bc31dbcd94d46a598346e8bfb505971 */}
833
+ <p>
834
+ {!isPairSupported ? (
835
+ translations.informationBlock.pairNotAvailable
836
+ ) : transactionFee && minimalAmountValid ? (
837
+ <>
838
+ {translations.informationBlock.transactionFee}
839
+ <span>
840
+ {AmountUtils.crypto(transactionFee?.crypto, sendingAssetFeeCoinTickerPrintable)}
841
+ </span>
842
+ {transactionFee?.fiat != null && transactionFee?.fiat !== "" ? (
843
+ <span className={s["semi-transparent"]}>
844
+ {" ~ " + AmountUtils.fiat(transactionFee?.fiat, fiatCurrencyCode)}
845
+ </span>
846
+ ) : (
847
+ ""
848
+ )}
849
+ </>
850
+ ) : !isLoading.current && (isSwapCalculated || (!minimalAmount.current && swapRate)) ? (
851
+ <>
852
+ {translations.informationBlock.swapRate}
853
+ <span>
854
+ {AmountUtils.composeRateText(
855
+ sendingAssetTickerPrintable,
856
+ receivingAssetTickerPrintable,
857
+ swapRate,
858
+ receivingAssetDecimalCount,
859
+ isFixedRate.current ?? IS_FIXED_BY_DEFAULT
860
+ )}
861
+ </span>
862
+ </>
863
+ ) : minimalAmount.current || maximumAmount.current ? (
864
+ !maximumAmountValid && maximumAmount.current != null ? (
865
+ <>
866
+ {translations.informationBlock.maximumAmount}
867
+ <span
868
+ className={s["interactable"] + " " + s["red"]}
869
+ onClick={
870
+ isLoading.current
871
+ ? () => {}
872
+ : e => callHandlingErrors(handleMaximumAmountClick, e)
873
+ }
874
+ >
875
+ {AmountUtils.crypto(maximumAmount.current?.crypto, sendingAssetTickerPrintable)}
876
+ </span>
877
+ {maximumAmount.current?.fiat != null && maximumAmount.current?.fiat !== "" ? (
878
+ <span className={s["semi-transparent"]}>
879
+ {" ~ " + AmountUtils.fiat(maximumAmount.current.fiat, fiatCurrencyCode)}
880
+ </span>
881
+ ) : (
882
+ ""
883
+ )}
884
+ </>
885
+ ) : (
886
+ <>
887
+ {translations.informationBlock.minimumAmount}
888
+ <span
889
+ className={s["interactable"] + " " + (!minimalAmountValid ? s["red"] : "")}
890
+ onClick={
891
+ isLoading.current
892
+ ? () => {}
893
+ : e => callHandlingErrors(handleMinimalAmountClick, e)
894
+ }
895
+ >
896
+ {AmountUtils.crypto(minimalAmount.current.crypto, sendingAssetTickerPrintable)}
897
+ </span>
898
+ {minimalAmount.current?.fiat != null && minimalAmount.current.fiat !== "" ? (
899
+ <span className={s["semi-transparent"]}>
900
+ {" ~ " + AmountUtils.fiat(minimalAmount.current.fiat, fiatCurrencyCode)}
901
+ </span>
902
+ ) : (
903
+ ""
904
+ )}
905
+ </>
906
+ )
907
+ ) : isLoading.current ? (
908
+ sendAssetAmount.current || isSwapAll.current ? (
909
+ translations.informationBlock[
910
+ formHasBalance ? "calculatingNetworkFee" : "calculatingSwapRates"
911
+ ]
912
+ ) : (
913
+ translations.informationBlock.loadingMinimalAmount
914
+ )
915
+ ) : (
916
+ ""
917
+ )}
918
+ </p>
919
+ </div>
920
+
921
+ {isAddressFieldEnabled ? (
922
+ <div className={s["swap-form-address-field"]}>
923
+ <TitleBox title={translations.addressFields.addressTitle}>
924
+ <Textarea
925
+ type={"text"}
926
+ onChange={e => setRecepientAddress(e.target.value)}
927
+ value={recepientAddress}
928
+ adaptiveHeight={true}
929
+ errorEncountered={!recepientAddressValid && recepientAddress !== ""}
930
+ />
931
+ </TitleBox>
932
+ {recepientAddressExtraIdAvailable ? (
933
+ <TitleBox
934
+ title={translations.addressFields.extraIdTitle}
935
+ titleNoticeText={translations.addressFields.extraIdNotice}
936
+ titleNoticePosition={TOOLTIP_POSITIONS.TOP_LEFT}
937
+ >
938
+ <Textarea
939
+ type={"text"}
940
+ onChange={e => setRecepientAddressExtraId(e.target.value)}
941
+ value={recepientAddressExtraId}
942
+ adaptiveHeight={true}
943
+ errorEncountered={!recepientAddressExtraIdValid}
944
+ placeholder={translations.addressFields.extraIdPlaceholder}
945
+ />
946
+ </TitleBox>
947
+ ) : (
948
+ ""
949
+ )}
950
+ </div>
951
+ ) : (
952
+ ""
953
+ )}
954
+
955
+ {displayRateSelector ? (
956
+ <div className={s["swap-form-rate-selector"]}>
957
+ <RateSelector
958
+ isFixed={isFixedRate.current ?? IS_FIXED_BY_DEFAULT}
959
+ setIsFixed={!isLoading.current ? handleRateModeChanged : () => {}}
960
+ translations={translations.rateSelector}
961
+ />
962
+ </div>
963
+ ) : (
964
+ ""
965
+ )}
966
+
967
+ {validationContent ? (
968
+ <div className={s["swap-form-validation-text"]}>
969
+ <Validation text={validationContent} />
970
+ </div>
971
+ ) : (
972
+ ""
973
+ )}
974
+ <div className={s["swap-form-button-container"]}>
975
+ {!termsOfUseUrl || !privacyPolicyUrl ? null : (
976
+ <p className={s["swap-form-button-container-consent-text"]}>
977
+ {translations.consents.consentText + " "}
978
+ <a
979
+ href={termsOfUseUrl}
980
+ className={s["swap-form-button-container-consent-text-link"]}
981
+ target="_blank"
982
+ >
983
+ {translations.consents.termsOfUse}
984
+ </a>
985
+ {" " + translations.consents.and + " "}
986
+ <a
987
+ href={privacyPolicyUrl}
988
+ className={s["swap-form-button-container-consent-text-link"]}
989
+ target="_blank"
990
+ >
991
+ {translations.consents.privacyPolicy}
992
+ </a>
993
+ .
994
+ </p>
995
+ )}
996
+ <Button
997
+ size="lg"
998
+ mode="primary"
999
+ content={translations.confirmButtonText}
1000
+ onClick={resetButtonLoader =>
1001
+ handleConfirmButtonClick(
1002
+ resetButtonLoader,
1003
+ setValidationContent,
1004
+ setBalanceValid,
1005
+ setMinimalAmountValid,
1006
+ setMaximumAmountValid,
1007
+ setIsPairSupported,
1008
+ setIsSameCoins
1009
+ )
1010
+ }
1011
+ fullWidthOnMobiles
1012
+ isDisabled={!readyToSwap}
1013
+ to={formHasBalance ? "" : confirmButtonTo}
1014
+ loader
1015
+ handleError={callHandlingErrors}
1016
+ />
1017
+ </div>
1018
+ </TitleBox>
1019
+ </div>
1020
+ );
1021
+ };
1022
+
1023
+ SwapForm.propTypes = {
1024
+ sendingAssetTicker: PropTypes.string.isRequired,
1025
+ receivingAssetTicker: PropTypes.string.isRequired,
1026
+ sendingAssetDecimalCount: PropTypes.number,
1027
+ receivingAssetDecimalCount: PropTypes.number,
1028
+ sendingAssetTickerPrintable: PropTypes.string.isRequired,
1029
+ receivingAssetTickerPrintable: PropTypes.string.isRequired,
1030
+ sendingAssetProtocol: PropTypes.string,
1031
+ receivingAssetProtocol: PropTypes.string,
1032
+ sendingAssetIconSrc: PropTypes.string.isRequired,
1033
+ sendingAssetProtocolIconSrc: PropTypes.oneOfType([PropTypes.string, null]),
1034
+ receivingAssetIconSrc: PropTypes.string.isRequired,
1035
+ receivingAssetProtocolIconSrc: PropTypes.oneOfType([PropTypes.string, null]),
1036
+ fallBackAssetIconSrc: PropTypes.oneOfType([PropTypes.string, null]),
1037
+ sendingAssetFeeCoinTickerPrintable: PropTypes.string,
1038
+ sendingAssetBalance: PropTypes.string,
1039
+ receivingAssetBalance: PropTypes.string,
1040
+ handleChangeSendingAssetClick: PropTypes.func.isRequired,
1041
+ handleChangeReceivingAssetClick: PropTypes.func.isRequired,
1042
+ handleConfirmButtonClick: PropTypes.func,
1043
+ composeConfirmButtonTo: PropTypes.func,
1044
+ setSwapCreationEstimation: PropTypes.func,
1045
+ handleUnexpectedError: PropTypes.func,
1046
+ rotateAssets: PropTypes.func,
1047
+ preservedAmount: PropTypes.oneOfType([PropTypes.string, null]),
1048
+ handleSwapServiceError: PropTypes.func.isRequired,
1049
+ formHasBalance: PropTypes.bool,
1050
+ retrieveSwapDetails: PropTypes.func.isRequired,
1051
+ retrieveInitialSwapData: PropTypes.func.isRequired,
1052
+ triggerDataUpdateResetting: PropTypes.number,
1053
+ fromAssetSelectionButtonRef: PropTypes.any,
1054
+ toAssetSelectionButtonRef: PropTypes.any,
1055
+ sendingAssetToFiatRate: PropTypes.oneOfType([PropTypes.number, PropTypes.string, null]),
1056
+ receivingAssetToFiatRate: PropTypes.oneOfType([PropTypes.number, PropTypes.string, null]),
1057
+ fiatCurrencyCode: PropTypes.oneOfType([PropTypes.string, null]),
1058
+ fiatCurrencyDecimals: PropTypes.oneOfType([PropTypes.number, null]),
1059
+ formHasFiat: PropTypes.bool,
1060
+ translations: PropTypes.object,
1061
+ swapSeparatorIconSrc: PropTypes.string.isRequired,
1062
+ swapButtonAlwaysActive: PropTypes.bool,
1063
+ };
1064
+
1065
+ SwapForm.defaultProps = {
1066
+ sendingAssetDecimalCount: AmountUtils.significantDecimalCount,
1067
+ receivingAssetDecimalCount: AmountUtils.significantDecimalCount,
1068
+ sendingAssetProtocolIconSrc: null,
1069
+ receivingAssetProtocolIconSrc: null,
1070
+ fallBackAssetIconSrc: null,
1071
+ handleConfirmButtonClick: (
1072
+ resetButtonLoader,
1073
+ setValidationContent,
1074
+ setBalanceValid,
1075
+ setMinimalAmountValid,
1076
+ setMaximumAmountValid,
1077
+ setIsPairSupported,
1078
+ setIsSameCoins
1079
+ ) => {},
1080
+ composeConfirmButtonTo: (fromTicker, toTicker, fromAmount) => "",
1081
+ setSwapCreationEstimation: details => {},
1082
+ handleUnexpectedError: error => {},
1083
+ rotateAssets: (fromTicker, toTicker) => {},
1084
+ preservedAmount: null,
1085
+ handleSwapServiceError: (
1086
+ errorCode,
1087
+ setValidationContent,
1088
+ setBalanceValid,
1089
+ setMinimalAmountValid,
1090
+ setMaximumAmountValid,
1091
+ setIsPairSupported,
1092
+ setIsSameCoins
1093
+ ) => {},
1094
+ retrieveSwapDetails: async (sendingAssetTicker, receivingAssetTicker, amount, isSwapAll = false) => {},
1095
+ retrieveInitialSwapData: async (sendingAssetTicker, receivingAssetTicker) => {},
1096
+ triggerDataUpdateResetting: 0,
1097
+ fromAssetSelectionButtonRef: null,
1098
+ toAssetSelectionButtonRef: null,
1099
+ sendingAssetToFiatRate: null,
1100
+ receivingAssetToFiatRate: null,
1101
+ fiatCurrencyCode: null,
1102
+ fiatCurrencyDecimals: null,
1103
+ formHasFiat: true,
1104
+ swapButtonAlwaysActive: false,
1105
+ };