@0xsequence/marketplace-sdk 0.9.0 → 0.10.0

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 (326) hide show
  1. package/.storybook/main.ts +63 -0
  2. package/.storybook/preview.ts +24 -0
  3. package/.storybook/vitest.setup.ts +6 -0
  4. package/CHANGELOG.md +77 -8
  5. package/dist/{CalendarIcon-DbQ7Vxcw.js → CalendarIcon-CqsuAuCm.js} +4 -51
  6. package/dist/CalendarIcon-CqsuAuCm.js.map +1 -0
  7. package/dist/{CollectibleCard-C8Ae64Ab.d.ts → CollectibleCard-Dd-CG6dE.d.ts} +8 -7
  8. package/dist/InfoIcon-v0w_Lu7t.js +53 -0
  9. package/dist/InfoIcon-v0w_Lu7t.js.map +1 -0
  10. package/dist/{_internal-BgWcRIak.js → _internal-C75gOSNo.js} +2 -10
  11. package/dist/_internal-C75gOSNo.js.map +1 -0
  12. package/dist/actionModal-CMUeVsFX.js +116 -0
  13. package/dist/actionModal-CMUeVsFX.js.map +1 -0
  14. package/dist/{alien_swap-B_76IMma.js → alien_swap-CYv6YlOF.js} +1 -1
  15. package/dist/{alien_swap-B_76IMma.js.map → alien_swap-CYv6YlOF.js.map} +1 -1
  16. package/dist/{api-DTIan01C.js → api-BiMGqWdz.js} +17 -34
  17. package/dist/api-BiMGqWdz.js.map +1 -0
  18. package/dist/{aqua-xyz-CMN_TFY5.js → aqua-xyz-Bzn5baeH.js} +1 -1
  19. package/dist/{aqua-xyz-CMN_TFY5.js.map → aqua-xyz-Bzn5baeH.js.map} +1 -1
  20. package/dist/{aura-Cye_TuHj.js → aura-DzIWh8WT.js} +1 -1
  21. package/dist/{aura-Cye_TuHj.js.map → aura-DzIWh8WT.js.map} +1 -1
  22. package/dist/base-DqaJPvfN.js +22 -0
  23. package/dist/base-DqaJPvfN.js.map +1 -0
  24. package/dist/{blur-DWDMyMpK.js → blur-DSH-Cbpj.js} +1 -1
  25. package/dist/{blur-DWDMyMpK.js.map → blur-DSH-Cbpj.js.map} +1 -1
  26. package/dist/{coinbase-ByA_XRB0.js → coinbase-Df8URNxq.js} +1 -1
  27. package/dist/{coinbase-ByA_XRB0.js.map → coinbase-Df8URNxq.js.map} +1 -1
  28. package/dist/{new-marketplace-types-Bfis0U4J.d.ts → create-config-DKJ-F0jc.d.ts} +402 -41
  29. package/dist/{wagmi-CDzEQbfk.js → create-config-fQ-jbJD1.js} +20 -10
  30. package/dist/create-config-fQ-jbJD1.js.map +1 -0
  31. package/dist/{element-b77CyXIZ.js → element-Cx6uJu5N.js} +1 -1
  32. package/dist/{element-b77CyXIZ.js.map → element-Cx6uJu5N.js.map} +1 -1
  33. package/dist/{foundation-DbOrKP9Y.js → foundation-D6U4aRLN.js} +1 -1
  34. package/dist/{foundation-DbOrKP9Y.js.map → foundation-D6U4aRLN.js.map} +1 -1
  35. package/dist/get-provider-CYYHfrlg.js +10 -0
  36. package/dist/get-provider-CYYHfrlg.js.map +1 -0
  37. package/dist/get-query-client-D19vvfJo.js +23 -0
  38. package/dist/get-query-client-D19vvfJo.js.map +1 -0
  39. package/dist/hooks-4pxIbLbM.js +4044 -0
  40. package/dist/hooks-4pxIbLbM.js.map +1 -0
  41. package/dist/{index-BL9RUSEK.d.ts → index-136YrWDH.d.ts} +1 -1
  42. package/dist/{index-D5v5iluA.d.ts → index-BAhaEfqY.d.ts} +1 -1
  43. package/dist/index-BKBin-rq.d.ts +979 -0
  44. package/dist/{index-BQsgAvtX.d.ts → index-BUWB_RXp.d.ts} +776 -570
  45. package/dist/{index-21LE7OhL.d.ts → index-BhVFc2rX.d.ts} +6 -3
  46. package/dist/{index-DXMfTZ1F.d.ts → index-C5aqo8xu.d.ts} +1 -1
  47. package/dist/{index-ByznONYE.d.ts → index-CKrYP7ot.d.ts} +20 -48
  48. package/dist/{index-DaE5ZNHb.d.ts → index-CUwMH7Ht.d.ts} +5 -5
  49. package/dist/{index-CLy8y5hm.d.ts → index-Cu70Lw-w.d.ts} +1 -1
  50. package/dist/index.css +414 -1
  51. package/dist/index.d.ts +8 -10
  52. package/dist/index.js +13 -9
  53. package/dist/{looks-rare-C1VqNcSM.js → looks-rare-ChBRBY-p.js} +1 -1
  54. package/dist/{looks-rare-C1VqNcSM.js.map → looks-rare-ChBRBY-p.js.map} +1 -1
  55. package/dist/{magic-eden-ea_AGCZr.js → magic-eden-D5U7N1xL.js} +1 -1
  56. package/dist/{magic-eden-ea_AGCZr.js.map → magic-eden-D5U7N1xL.js.map} +1 -1
  57. package/dist/{manifold-8y8J2sjT.js → manifold-CtLF52zU.js} +1 -1
  58. package/dist/{manifold-8y8J2sjT.js.map → manifold-CtLF52zU.js.map} +1 -1
  59. package/dist/{marketplace-nwnZv9Cb.js → marketplace-DmFiyBoS.js} +1 -1
  60. package/dist/{marketplace-nwnZv9Cb.js.map → marketplace-DmFiyBoS.js.map} +1 -1
  61. package/dist/{marketplace-logos-CSeGcPW4.js → marketplace-logos-Cd6W-qOq.js} +21 -21
  62. package/dist/{marketplace-logos-CSeGcPW4.js.map → marketplace-logos-Cd6W-qOq.js.map} +1 -1
  63. package/dist/{marketplace.gen-BSDIX7NZ.js → marketplace.gen-HpnpL5xU.js} +3 -3
  64. package/dist/marketplace.gen-HpnpL5xU.js.map +1 -0
  65. package/dist/{marketplaceConfig-C6X1SUik.js → marketplaceConfig-GQTTmihy.js} +3 -3
  66. package/dist/marketplaceConfig-GQTTmihy.js.map +1 -0
  67. package/dist/{mintify-LA68TzWg.js → mintify-Bi3Bce68.js} +1 -1
  68. package/dist/{mintify-LA68TzWg.js.map → mintify-Bi3Bce68.js.map} +1 -1
  69. package/dist/network-CGD0oKtS.js +15 -0
  70. package/dist/network-CGD0oKtS.js.map +1 -0
  71. package/dist/{nftx-D3Tc8nzd.js → nftx-BDQZjtkX.js} +1 -1
  72. package/dist/{nftx-D3Tc8nzd.js.map → nftx-BDQZjtkX.js.map} +1 -1
  73. package/dist/{okx-hbqg6oIJ.js → okx-D4meadLe.js} +1 -1
  74. package/dist/{okx-hbqg6oIJ.js.map → okx-D4meadLe.js.map} +1 -1
  75. package/dist/{open-sea-BccuK8-t.js → open-sea-DN0hgfVw.js} +1 -1
  76. package/dist/{open-sea-BccuK8-t.js.map → open-sea-DN0hgfVw.js.map} +1 -1
  77. package/dist/{primary-sale-C55ALnfQ.js → primary-sale-CmWxSfFQ.js} +1 -1
  78. package/dist/{primary-sale-C55ALnfQ.js.map → primary-sale-CmWxSfFQ.js.map} +1 -1
  79. package/dist/provider-DPGUA10G.js +125 -0
  80. package/dist/provider-DPGUA10G.js.map +1 -0
  81. package/dist/{queries-CUU65uYZ.js → queries-Ce_2othB.js} +165 -7
  82. package/dist/queries-Ce_2othB.js.map +1 -0
  83. package/dist/{rarible-BgTwwj9g.js → rarible-B0xlD88A.js} +1 -1
  84. package/dist/{rarible-BgTwwj9g.js.map → rarible-B0xlD88A.js.map} +1 -1
  85. package/dist/react/_internal/api/index.d.ts +2 -4
  86. package/dist/react/_internal/api/index.js +7 -4
  87. package/dist/react/_internal/databeat/index.d.ts +2 -73
  88. package/dist/react/_internal/databeat/index.js +4 -21
  89. package/dist/react/_internal/index.d.ts +2 -7
  90. package/dist/react/_internal/index.js +11 -6
  91. package/dist/react/_internal/wagmi/index.d.ts +2 -4
  92. package/dist/react/_internal/wagmi/index.js +5 -3
  93. package/dist/react/hooks/index.d.ts +12 -17
  94. package/dist/react/hooks/index.js +23 -19
  95. package/dist/react/hooks/options/index.d.ts +2 -3
  96. package/dist/react/hooks/options/index.js +12 -7
  97. package/dist/react/index.d.ts +12 -17
  98. package/dist/react/index.js +28 -19
  99. package/dist/react/queries/index.d.ts +9 -8
  100. package/dist/react/queries/index.js +20 -15
  101. package/dist/react/ssr/index.d.ts +7 -9
  102. package/dist/react/ssr/index.js +11 -6
  103. package/dist/react/ssr/index.js.map +1 -1
  104. package/dist/react/ui/components/marketplace-collectible-card/index.d.ts +3 -8
  105. package/dist/react/ui/components/marketplace-collectible-card/index.js +27 -18
  106. package/dist/react/ui/components/marketplace-collectible-card/utils/index.d.ts +2 -7
  107. package/dist/react/ui/components/marketplace-collectible-card/utils/index.js +11 -6
  108. package/dist/react/ui/components/marketplace-logos/index.d.ts +21 -21
  109. package/dist/react/ui/components/marketplace-logos/index.js +1 -1
  110. package/dist/react/ui/icons/index.js +13 -9
  111. package/dist/react/ui/index.d.ts +3 -8
  112. package/dist/react/ui/index.js +27 -18
  113. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +2 -2
  114. package/dist/react/ui/modals/_internal/components/actionModal/index.js +23 -18
  115. package/dist/{react-DAIicQPT.js → react-DP0M2Wfm.js} +799 -4306
  116. package/dist/react-DP0M2Wfm.js.map +1 -0
  117. package/dist/{react-BbHBl6gg.css → react-DeDyTgo7.css} +1 -1
  118. package/dist/{react-BbHBl6gg.css.map → react-DeDyTgo7.css.map} +1 -1
  119. package/dist/{sequence-Do3kzb4J.js → sequence-BIrOVRXO.js} +1 -1
  120. package/dist/{sequence-Do3kzb4J.js.map → sequence-BIrOVRXO.js.map} +1 -1
  121. package/dist/{sudo-swap-B6vPKxBz.js → sudo-swap-BPMon-M5.js} +1 -1
  122. package/dist/{sudo-swap-B6vPKxBz.js.map → sudo-swap-BPMon-M5.js.map} +1 -1
  123. package/dist/{super-rare-eCm1SE6O.js → super-rare-kPN6Ua8i.js} +1 -1
  124. package/dist/{super-rare-eCm1SE6O.js.map → super-rare-kPN6Ua8i.js.map} +1 -1
  125. package/dist/{token-Da4TdyUk.js → token-CHSBPYVG.js} +1 -1
  126. package/dist/{token-Da4TdyUk.js.map → token-CHSBPYVG.js.map} +1 -1
  127. package/dist/{transaction-CcVViHEL.js → transaction-CnctdNzS.js} +3 -21
  128. package/dist/transaction-CnctdNzS.js.map +1 -0
  129. package/dist/types/index.d.ts +2 -3
  130. package/dist/types/index.js +2 -2
  131. package/dist/{types-DwWE6xOF.js → types-Yw2ywj6j.js} +1 -1
  132. package/dist/{types-DwWE6xOF.js.map → types-Yw2ywj6j.js.map} +1 -1
  133. package/dist/utils/abi/index.d.ts +4 -4
  134. package/dist/utils/abi/index.js +4 -4
  135. package/dist/utils/abi/marketplace/index.d.ts +1 -1
  136. package/dist/utils/abi/marketplace/index.js +1 -1
  137. package/dist/utils/abi/primary-sale/index.d.ts +1 -1
  138. package/dist/utils/abi/primary-sale/index.js +1 -1
  139. package/dist/utils/abi/token/index.d.ts +1 -1
  140. package/dist/utils/abi/token/index.js +1 -1
  141. package/dist/utils/index.d.ts +7 -8
  142. package/dist/utils/index.js +12 -9
  143. package/dist/{utils-CW2NA5KG.js → utils-9RXDgcBl.js} +4 -11
  144. package/dist/utils-9RXDgcBl.js.map +1 -0
  145. package/dist/{utils-BPYfgDSL.js → utils-DjVJ9tov.js} +5 -6
  146. package/dist/utils-DjVJ9tov.js.map +1 -0
  147. package/dist/wagmi-Do_KW5ke.js +0 -0
  148. package/dist/{x2y2-DD17tT91.js → x2y2-BLz-_Q2O.js} +1 -1
  149. package/dist/{x2y2-DD17tT91.js.map → x2y2-BLz-_Q2O.js.map} +1 -1
  150. package/dist/{zora-BpSG9UzS.js → zora-UGhKs-aL.js} +1 -1
  151. package/dist/{zora-BpSG9UzS.js.map → zora-UGhKs-aL.js.map} +1 -1
  152. package/eslint.config.mjs +4 -0
  153. package/package.json +27 -14
  154. package/postcss.config.mjs +6 -0
  155. package/src/index.css +5 -4
  156. package/src/index.ts +1 -0
  157. package/src/react/__tests__/provider.test.tsx +4 -3
  158. package/src/react/_internal/api/__mocks__/indexer.msw.ts +16 -0
  159. package/src/react/_internal/api/__mocks__/laos.msw.ts +387 -0
  160. package/src/react/_internal/api/__mocks__/marketplace.msw.ts +2 -0
  161. package/src/react/_internal/api/__tests__/laos-api.test.ts +756 -0
  162. package/src/react/_internal/api/laos-api.ts +3 -0
  163. package/src/react/_internal/api/marketplace.gen.ts +5 -3
  164. package/src/react/_internal/api/query-keys.ts +12 -4
  165. package/src/react/_internal/api/services.ts +2 -14
  166. package/src/react/_internal/databeat/index.ts +15 -14
  167. package/src/react/_internal/databeat/types.ts +22 -0
  168. package/src/react/_internal/databeat/utils.ts +26 -0
  169. package/src/react/_internal/utils.ts +4 -4
  170. package/src/react/_internal/wagmi/create-config.ts +28 -13
  171. package/src/react/_internal/wallet/wallet.ts +4 -4
  172. package/src/react/hooks/__tests__/useBalanceOfCollectible.laos.test.tsx +367 -0
  173. package/src/react/hooks/__tests__/useCheckoutOptions.test.tsx +158 -0
  174. package/src/react/hooks/__tests__/useCheckoutOptionsSalesContract.test.tsx +42 -65
  175. package/src/react/hooks/__tests__/useCollectionBalanceDetails.test.tsx +17 -0
  176. package/src/react/hooks/__tests__/useCollectionDetailsPolling.test.tsx +11 -3
  177. package/src/react/hooks/__tests__/useConvertPriceToUSD.test.tsx +3 -3
  178. package/src/react/hooks/__tests__/useCurrencyBalance.test.tsx +7 -3
  179. package/src/react/hooks/__tests__/useFilters.test.tsx +2 -2
  180. package/src/react/hooks/__tests__/useGetTokenRanges.test.tsx +111 -0
  181. package/src/react/hooks/__tests__/useListTokenMetadata.test.tsx +83 -57
  182. package/src/react/hooks/__tests__/useTransferTokens.test.tsx +469 -0
  183. package/src/react/hooks/index.ts +3 -1
  184. package/src/react/hooks/useCheckoutOptions.tsx +96 -0
  185. package/src/react/hooks/useCheckoutOptionsSalesContract.tsx +98 -57
  186. package/src/react/hooks/useCollectionBalanceDetails.tsx +95 -68
  187. package/src/react/hooks/useCollectionDetailsPolling.tsx +3 -7
  188. package/src/react/hooks/useComparePrices.tsx +90 -82
  189. package/src/react/hooks/useConvertPriceToUSD.tsx +85 -71
  190. package/src/react/hooks/useCurrencyBalance.tsx +132 -46
  191. package/src/react/hooks/useERC721SaleMintedTokens.tsx +8 -5
  192. package/src/react/hooks/useFilters.tsx +154 -111
  193. package/src/react/hooks/useGetCountOfPrimarySaleItems.tsx +48 -0
  194. package/src/react/hooks/useGetTokenRanges.tsx +83 -22
  195. package/src/react/hooks/useList1155ShopCardData.tsx +2 -0
  196. package/src/react/hooks/useList721ShopCardData.tsx +12 -7
  197. package/src/react/hooks/useListCollections.tsx +25 -25
  198. package/src/react/hooks/useListMarketCardData.tsx +2 -1
  199. package/src/react/hooks/useListPrimarySaleItems.tsx +66 -0
  200. package/src/react/hooks/useListTokenMetadata.ts +71 -0
  201. package/src/react/hooks/useOpenConnectModal.tsx +9 -0
  202. package/src/react/hooks/useTokenSaleDetailsBatch.tsx +3 -7
  203. package/src/react/hooks/useTokenSupplies.ts +81 -0
  204. package/src/react/hooks/useTransferTokens.tsx +2 -2
  205. package/src/react/provider.tsx +73 -9
  206. package/src/react/queries/__tests__/balanceOfCollectible.laos.test.ts +123 -0
  207. package/src/react/queries/__tests__/inventory.laos.test.ts +496 -0
  208. package/src/react/queries/balanceOfCollectible.ts +7 -4
  209. package/src/react/queries/checkoutOptions.ts +85 -0
  210. package/src/react/queries/checkoutOptionsSalesContract.ts +89 -0
  211. package/src/react/queries/collectionBalanceDetails.ts +92 -0
  212. package/src/react/queries/comparePrices.ts +108 -0
  213. package/src/react/queries/convertPriceToUSD.ts +92 -0
  214. package/src/react/queries/filters.ts +138 -0
  215. package/src/react/queries/getTokenRanges.ts +62 -0
  216. package/src/react/queries/index.ts +3 -0
  217. package/src/react/queries/inventory.ts +6 -0
  218. package/src/react/queries/listBalances.ts +4 -3
  219. package/src/react/queries/listCollections.ts +7 -3
  220. package/src/react/queries/listTokenMetadata.ts +2 -2
  221. package/src/react/queries/marketplaceConfig.ts +1 -1
  222. package/src/react/queries/primarySaleItems.ts +85 -0
  223. package/src/react/queries/primarySaleItemsCount.ts +64 -0
  224. package/src/react/queries/tokenSupplies.ts +93 -0
  225. package/src/react/ui/components/_internals/action-button/ActionButton.tsx +66 -66
  226. package/src/react/ui/components/_internals/action-button/__tests__/ActionButtonBody.test.tsx +22 -4
  227. package/src/react/ui/components/_internals/action-button/components/ActionButtonBody.tsx +5 -4
  228. package/src/react/ui/components/_internals/action-button/components/NonOwnerActions.tsx +3 -0
  229. package/src/react/ui/components/_internals/action-button/components/OwnerActions.tsx +4 -4
  230. package/src/react/ui/components/_internals/action-button/hooks/useActionButtonLogic.ts +13 -8
  231. package/src/react/ui/components/_internals/action-button/store.ts +44 -34
  232. package/src/react/ui/components/_internals/custom-select/CustomSelect.stories.tsx +582 -0
  233. package/src/react/ui/components/_internals/pill/Pill.stories.tsx +83 -0
  234. package/src/react/ui/components/marketplace-collectible-card/Footer.tsx +11 -4
  235. package/src/react/ui/components/marketplace-collectible-card/components/ActionButtonWrapper.tsx +7 -4
  236. package/src/react/ui/components/marketplace-collectible-card/types.ts +4 -3
  237. package/src/react/ui/components/marketplace-collectible-card/utils/supplyStatus.ts +4 -7
  238. package/src/react/ui/components/marketplace-collectible-card/variants/ShopCard.tsx +5 -1
  239. package/src/react/ui/components/marketplace-logos/marketplace-logos.stories.tsx +199 -0
  240. package/src/react/ui/components/media/Media.stories.tsx +642 -0
  241. package/src/react/ui/components/media/Media.tsx +24 -19
  242. package/src/react/ui/components/media/types.ts +6 -0
  243. package/src/react/ui/modals/BuyModal/__tests__/BuyModalRouter.test.tsx +15 -0
  244. package/src/react/ui/modals/BuyModal/__tests__/ERC1155ShopModal.test.tsx +6 -0
  245. package/src/react/ui/modals/BuyModal/__tests__/Modal1155.test.tsx +7 -1
  246. package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +9 -1
  247. package/src/react/ui/modals/BuyModal/components/ERC1155QuantityModal.tsx +15 -8
  248. package/src/react/ui/modals/BuyModal/components/ERC1155ShopModal.tsx +3 -0
  249. package/src/react/ui/modals/BuyModal/hooks/__tests__/useERC1155Checkout.test.tsx +30 -27
  250. package/src/react/ui/modals/BuyModal/hooks/useCheckoutOptions.ts +2 -2
  251. package/src/react/ui/modals/BuyModal/hooks/useERC1155Checkout.ts +11 -2
  252. package/src/react/ui/modals/BuyModal/hooks/useERC721SalePaymentParams.ts +1 -1
  253. package/src/react/ui/modals/BuyModal/hooks/usePaymentModalParams.ts +7 -0
  254. package/src/react/ui/modals/BuyModal/index.tsx +9 -1
  255. package/src/react/ui/modals/BuyModal/store.ts +26 -0
  256. package/src/react/ui/modals/CreateListingModal/Modal.tsx +28 -11
  257. package/src/react/ui/modals/CreateListingModal/store.ts +3 -3
  258. package/src/react/ui/modals/MakeOfferModal/Modal.tsx +30 -13
  259. package/src/react/ui/modals/MakeOfferModal/store.ts +3 -3
  260. package/src/react/ui/modals/SellModal/Modal.tsx +11 -8
  261. package/src/react/ui/modals/SellModal/store.ts +3 -3
  262. package/src/react/ui/modals/TransferModal/__tests__/__snapshots__/store.test.ts.snap +17 -0
  263. package/src/react/ui/modals/TransferModal/__tests__/store.test.ts +366 -0
  264. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/__tests__/useHandleTransfer.test.tsx +402 -0
  265. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/TokenQuantityInput.tsx +51 -48
  266. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/TransferButton.tsx +39 -47
  267. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/WalletAddressInput.tsx +9 -8
  268. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/index.tsx +31 -35
  269. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/useHandleTransfer.tsx +19 -10
  270. package/src/react/ui/modals/TransferModal/index.tsx +28 -31
  271. package/src/react/ui/modals/TransferModal/messages.ts +1 -1
  272. package/src/react/ui/modals/TransferModal/store.ts +122 -0
  273. package/src/react/ui/modals/_internal/components/calendar/index.tsx +0 -1
  274. package/src/react/ui/modals/_internal/components/currencyImage/index.tsx +10 -14
  275. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +5 -2
  276. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +23 -17
  277. package/src/react/ui/modals/_internal/components/expirationDateSelect/index.tsx +10 -10
  278. package/src/react/ui/modals/_internal/components/floorPriceText/__tests__/FloorPriceText.test.tsx +6 -6
  279. package/src/react/ui/modals/_internal/components/priceInput/__tests__/PriceInput.test.tsx +13 -5
  280. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +41 -26
  281. package/src/react/ui/modals/_internal/components/quantityInput/__tests__/index.test.tsx +68 -59
  282. package/src/react/ui/modals/_internal/components/quantityInput/index.tsx +155 -20
  283. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/SelectWaasFeeOptions.test.tsx +339 -40
  284. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/index.tsx +95 -101
  285. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/store.ts +72 -14
  286. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/useWaasFeeOptionManager.tsx +29 -13
  287. package/src/react/ui/modals/_internal/components/tokenPreview/index.tsx +2 -2
  288. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +2 -2
  289. package/src/react/ui/modals/_internal/components/transactionPreview/index.tsx +88 -89
  290. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +36 -10
  291. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +32 -20
  292. package/src/react/ui/modals/_internal/components/transactionStatusModal/store.ts +91 -62
  293. package/src/react/ui/modals/_internal/components/waasFeeOptionsSelect/WaasFeeOptionsSelect.tsx +43 -44
  294. package/src/react/ui/modals/_internal/types.ts +2 -2
  295. package/src/types/sdk-config.ts +6 -1
  296. package/src/utils/network.ts +15 -0
  297. package/test/test-utils.tsx +2 -0
  298. package/vitest.shims.d.ts +2 -0
  299. package/vitest.storybook.config.js +33 -0
  300. package/dist/CalendarIcon-DbQ7Vxcw.js.map +0 -1
  301. package/dist/_internal-BgWcRIak.js.map +0 -1
  302. package/dist/api-DTIan01C.js.map +0 -1
  303. package/dist/builder-api-C_zj5mr3.d.ts +0 -12
  304. package/dist/index-BUVWziLP.d.ts +0 -60
  305. package/dist/index-COt10OgI.d.ts +0 -24
  306. package/dist/index-DPNWNa7t.d.ts +0 -414
  307. package/dist/index-DsfCs3-x.d.ts +0 -122
  308. package/dist/index-dUb6wb4Y.d.ts +0 -22
  309. package/dist/marketplace.gen-BSDIX7NZ.js.map +0 -1
  310. package/dist/marketplaceConfig-C6X1SUik.js.map +0 -1
  311. package/dist/queries-CUU65uYZ.js.map +0 -1
  312. package/dist/react-DAIicQPT.js.map +0 -1
  313. package/dist/transaction-CcVViHEL.js.map +0 -1
  314. package/dist/utils-BPYfgDSL.js.map +0 -1
  315. package/dist/utils-CW2NA5KG.js.map +0 -1
  316. package/dist/wagmi-CDzEQbfk.js.map +0 -1
  317. package/src/react/hooks/__tests__/useGetTokenSuppliesMap.test.tsx +0 -104
  318. package/src/react/hooks/useGetTokenSuppliesMap.tsx +0 -73
  319. package/src/react/hooks/useListPrimarySaleItems.ts +0 -102
  320. package/src/react/queries/getTokenSuppliesMap.ts +0 -77
  321. package/src/react/ui/modals/TransferModal/_store.ts +0 -66
  322. package/src/react/ui/modals/_internal/components/quantityInput/QuantityInputBase.tsx +0 -166
  323. package/src/react/ui/modals/_internal/stores/accountModal.ts +0 -3
  324. /package/dist/{abi-BKyRjVcZ.js → abi-BMvgNbKQ.js} +0 -0
  325. /package/dist/{index-C39K_8SG.d.ts → index-CD2bj_xW.d.ts} +0 -0
  326. /package/dist/{options-B4QN7Xou.js → options-BBBR8u_4.js} +0 -0
@@ -1,37 +1,172 @@
1
1
  'use client';
2
2
 
3
- import type { Observable } from '@legendapp/state';
4
- import { observer } from '@legendapp/state/react';
5
- import { QuantityInputBase } from './QuantityInputBase';
3
+ import {
4
+ AddIcon,
5
+ IconButton,
6
+ NumericInput,
7
+ SubtractIcon,
8
+ } from '@0xsequence/design-system';
9
+ import * as dn from 'dnum';
10
+ import { useEffect, useState } from 'react';
11
+ import { cn } from '../../../../../../utils';
6
12
 
7
13
  type QuantityInputProps = {
8
- $quantity: Observable<string>;
9
- $invalidQuantity: Observable<boolean>;
14
+ quantity: string;
15
+ invalidQuantity: boolean;
16
+ onQuantityChange: (quantity: string) => void;
17
+ onInvalidQuantityChange: (invalid: boolean) => void;
10
18
  decimals: number;
11
19
  maxQuantity: string;
12
20
  className?: string;
13
21
  disabled?: boolean;
14
22
  };
15
23
 
16
- // Using observer to ensure re-render on observable changes
17
- export default observer(function QuantityInput({
18
- $quantity,
19
- $invalidQuantity,
24
+ export default function QuantityInput({
25
+ quantity,
26
+ invalidQuantity,
27
+ onQuantityChange,
28
+ onInvalidQuantityChange,
20
29
  decimals,
21
30
  maxQuantity,
22
31
  className,
23
32
  disabled,
24
33
  }: QuantityInputProps) {
34
+ const dnMaxQuantity = dn.from(maxQuantity, decimals);
35
+ const dnOne = dn.from('1', decimals);
36
+ const min = decimals > 0 ? Number(`0.${'1'.padStart(decimals, '0')}`) : 0;
37
+ const dnMin = dn.from(min, decimals);
38
+
39
+ const [dnQuantity, setDnQuantity] = useState(dn.from(quantity, decimals));
40
+
41
+ const [localQuantity, setLocalQuantity] = useState(quantity);
42
+
43
+ // Sync internal state with external prop changes
44
+ useEffect(() => {
45
+ setLocalQuantity(quantity);
46
+ setDnQuantity(dn.from(quantity, decimals));
47
+ }, [quantity, decimals]);
48
+
49
+ const setQuantity = ({
50
+ value,
51
+ isValid,
52
+ }: {
53
+ value: string;
54
+ isValid: boolean;
55
+ }) => {
56
+ setLocalQuantity(value);
57
+ if (isValid) {
58
+ onQuantityChange(value);
59
+ setDnQuantity(dn.from(value, decimals));
60
+ onInvalidQuantityChange(false);
61
+ } else {
62
+ onInvalidQuantityChange(true);
63
+ }
64
+ };
65
+
66
+ function handleChangeQuantity(value: string) {
67
+ if (!value || Number.isNaN(Number(value)) || value.endsWith('.')) {
68
+ setQuantity({
69
+ value: value,
70
+ isValid: false,
71
+ });
72
+ return;
73
+ }
74
+ const dnValue = dn.from(value, decimals);
75
+ const isBiggerThanMax = dn.greaterThan(dnValue, dnMaxQuantity);
76
+ const isLessThanMin = dn.lessThan(dnValue, dnMin);
77
+
78
+ if (isLessThanMin) {
79
+ setQuantity({
80
+ value: value, // Trying to enter fraction starting with 0
81
+ isValid: false,
82
+ });
83
+ return;
84
+ }
85
+
86
+ if (isBiggerThanMax) {
87
+ setQuantity({
88
+ value: maxQuantity,
89
+ isValid: true, // Is vaid is true because we override the value
90
+ });
91
+ return;
92
+ }
93
+
94
+ setQuantity({
95
+ value: dn.toString(dnValue, decimals),
96
+ isValid: true,
97
+ });
98
+ }
99
+
100
+ function handleIncrement() {
101
+ const newValue = dn.add(dnQuantity, dnOne);
102
+ if (dn.greaterThanOrEqual(newValue, dnMaxQuantity)) {
103
+ setQuantity({
104
+ value: maxQuantity,
105
+ isValid: true,
106
+ });
107
+ } else {
108
+ setQuantity({
109
+ value: dn.toString(newValue, decimals),
110
+ isValid: true,
111
+ });
112
+ }
113
+ }
114
+
115
+ function handleDecrement() {
116
+ const newValue = dn.subtract(dnQuantity, dnOne);
117
+ if (dn.lessThanOrEqual(newValue, dnMin)) {
118
+ setQuantity({
119
+ value: String(min),
120
+ isValid: true,
121
+ });
122
+ } else {
123
+ setQuantity({
124
+ value: dn.toString(newValue, decimals),
125
+ isValid: true,
126
+ });
127
+ }
128
+ }
129
+
25
130
  return (
26
- <QuantityInputBase
27
- value={$quantity.get()}
28
- onChange={(value) => $quantity.set(value)}
29
- isInvalid={$invalidQuantity.get()}
30
- onInvalidChange={(isInvalid) => $invalidQuantity.set(isInvalid)}
31
- decimals={decimals}
32
- maxQuantity={maxQuantity}
33
- className={className}
34
- disabled={disabled}
35
- />
131
+ <div
132
+ className={cn(
133
+ 'flex w-full flex-col [&>label>div>div>div:has(:disabled):hover]:opacity-100 [&>label>div>div>div:has(:disabled)]:opacity-100 [&>label>div>div>div>input]:text-xs [&>label>div>div>div]:h-9 [&>label>div>div>div]:rounded [&>label>div>div>div]:pr-0 [&>label>div>div>div]:pl-3 [&>label>div>div>div]:text-xs [&>label]:gap-[2px]',
134
+ className,
135
+ disabled && 'pointer-events-none opacity-50',
136
+ )}
137
+ >
138
+ <NumericInput
139
+ className="w-full pl-1"
140
+ name={'quantity'}
141
+ decimals={decimals || 0}
142
+ label={'Enter quantity'}
143
+ labelLocation="top"
144
+ controls={
145
+ <div className="mr-2 flex items-center gap-1">
146
+ <IconButton
147
+ disabled={dn.lessThanOrEqual(dnQuantity, dnMin)}
148
+ onClick={handleDecrement}
149
+ size="xs"
150
+ icon={SubtractIcon}
151
+ />
152
+
153
+ <IconButton
154
+ disabled={dn.greaterThanOrEqual(dnQuantity, dnMaxQuantity)}
155
+ onClick={handleIncrement}
156
+ size="xs"
157
+ icon={AddIcon}
158
+ />
159
+ </div>
160
+ }
161
+ value={localQuantity}
162
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
163
+ handleChangeQuantity(e.target.value)
164
+ }
165
+ width={'full'}
166
+ />
167
+ {invalidQuantity && (
168
+ <div className="text-negative text-sm">Invalid quantity</div>
169
+ )}
170
+ </div>
36
171
  );
37
- });
172
+ }
@@ -1,18 +1,16 @@
1
1
  import { TokenType } from '@0xsequence/api';
2
- import * as useNetworkModule from '@0xsequence/connect';
3
- import * as useWaasFeeOptionsModule from '@0xsequence/connect';
2
+ import * as sequenceConnect from '@0xsequence/connect';
4
3
  import { NetworkType } from '@0xsequence/network';
5
- import { observable } from '@legendapp/state';
6
- import { render, screen } from '@test';
4
+ import { fireEvent, render, screen, waitFor } from '@test';
7
5
  import { TEST_CURRENCY } from '@test/const';
8
6
  import { beforeEach, describe, expect, it, vi } from 'vitest';
9
7
  import type {
10
- FeeOption,
11
8
  FeeOptionExtended,
12
9
  WaasFeeOptionConfirmation,
13
10
  } from '../../../../../../../types/waas-types';
14
11
  import SelectWaasFeeOptions from '..';
15
- import { selectWaasFeeOptions$ } from '../store';
12
+ import * as storeModule from '../store';
13
+ import { selectWaasFeeOptionsStore } from '../store';
16
14
  import * as useWaasFeeOptionManagerModule from '../useWaasFeeOptionManager';
17
15
 
18
16
  const mockFeeOption: FeeOptionExtended = {
@@ -34,12 +32,37 @@ const mockFeeOption: FeeOptionExtended = {
34
32
  hasEnoughBalanceForFee: true,
35
33
  };
36
34
 
35
+ const mockFeeOption2: FeeOptionExtended = {
36
+ gasLimit: 21000,
37
+ to: '0x456',
38
+ value: '2000000000000000',
39
+ token: {
40
+ chainId: 1,
41
+ contractAddress: '0x456',
42
+ decimals: 6,
43
+ logoURL: 'https://example.com/usdc.png',
44
+ name: 'USD Coin',
45
+ symbol: 'USDC',
46
+ tokenID: null,
47
+ type: TokenType.ERC20,
48
+ },
49
+ balance: '2000000000000000',
50
+ balanceFormatted: '2',
51
+ hasEnoughBalanceForFee: true,
52
+ };
53
+
37
54
  const mockPendingFeeOptionConfirmation: WaasFeeOptionConfirmation = {
38
55
  id: 'fee-confirmation-id',
39
56
  options: [mockFeeOption],
40
57
  chainId: 1,
41
58
  };
42
59
 
60
+ const mockPendingFeeOptionConfirmationMultiple: WaasFeeOptionConfirmation = {
61
+ id: 'fee-confirmation-id-multiple',
62
+ options: [mockFeeOption, mockFeeOption2],
63
+ chainId: 1,
64
+ };
65
+
43
66
  // Mock currency balance with formatted value
44
67
  const mockCurrencyBalance = {
45
68
  value: 2000000000000000n,
@@ -54,19 +77,21 @@ describe('SelectWaasFeeOptions', () => {
54
77
  vi.resetAllMocks();
55
78
  vi.resetModules();
56
79
 
57
- selectWaasFeeOptions$.isVisible.set(true);
58
- selectWaasFeeOptions$.selectedFeeOption.set(undefined);
59
- selectWaasFeeOptions$.pendingFeeOptionConfirmation.set(undefined);
80
+ selectWaasFeeOptionsStore.send({ type: 'show' });
81
+ selectWaasFeeOptionsStore.send({
82
+ type: 'setSelectedFeeOption',
83
+ feeOption: undefined,
84
+ });
85
+ selectWaasFeeOptionsStore.send({
86
+ type: 'setPendingFeeOptionConfirmation',
87
+ confirmation: undefined,
88
+ });
60
89
  });
61
90
 
62
91
  it('should not render when isVisible is false', () => {
63
92
  vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
64
- selectedFeeOption$: observable<FeeOptionExtended | undefined>(
65
- mockFeeOption,
66
- ),
67
93
  selectedFeeOption: mockFeeOption,
68
- // @ts-expect-error - types are not compatible
69
- pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation,
94
+ pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation as any,
70
95
  currencyBalance: mockCurrencyBalance,
71
96
  currencyBalanceLoading: false,
72
97
  insufficientBalance: false,
@@ -75,7 +100,7 @@ describe('SelectWaasFeeOptions', () => {
75
100
  });
76
101
 
77
102
  // Set isVisible to false
78
- selectWaasFeeOptions$.isVisible.set(false);
103
+ selectWaasFeeOptionsStore.send({ type: 'hide' });
79
104
 
80
105
  const { container } = render(
81
106
  <SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />,
@@ -92,9 +117,7 @@ describe('SelectWaasFeeOptions', () => {
92
117
  };
93
118
 
94
119
  vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
95
- selectedFeeOption$: observable<FeeOption | undefined>(undefined),
96
120
  selectedFeeOption: undefined,
97
- // @ts-expect-error - types are not compatible
98
121
  pendingFeeOptionConfirmation: sponsoredFeeOptionConfirmation,
99
122
  currencyBalance: mockCurrencyBalance,
100
123
  currencyBalanceLoading: false,
@@ -103,17 +126,18 @@ describe('SelectWaasFeeOptions', () => {
103
126
  handleConfirmFeeOption: mockHandleConfirmFeeOption,
104
127
  });
105
128
 
106
- vi.spyOn(useNetworkModule, 'getNetwork').mockReturnValue({
129
+ vi.spyOn(sequenceConnect, 'getNetwork').mockReturnValue({
107
130
  type: NetworkType.MAINNET,
108
131
  chainId: 1,
109
132
  name: 'Mainnet',
110
133
  nativeToken: TEST_CURRENCY,
111
134
  });
112
- vi.spyOn(useWaasFeeOptionsModule, 'useWaasFeeOptions').mockReturnValue([
113
- // @ts-expect-error - types are not compatible
114
- sponsoredFeeOptionConfirmation,
135
+ vi.spyOn(sequenceConnect, 'useWaasFeeOptions').mockReturnValue([
136
+ sponsoredFeeOptionConfirmation as any,
115
137
  vi.fn(),
116
- ]);
138
+ false,
139
+ false,
140
+ ] as any);
117
141
 
118
142
  const { container } = render(
119
143
  <SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />,
@@ -125,7 +149,6 @@ describe('SelectWaasFeeOptions', () => {
125
149
  it('should render loading skeleton when fee options are loading', () => {
126
150
  // Mock the hook with loading state
127
151
  vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
128
- selectedFeeOption$: observable<FeeOption | undefined>(undefined),
129
152
  selectedFeeOption: mockFeeOption,
130
153
  pendingFeeOptionConfirmation: undefined,
131
154
  currencyBalance: undefined,
@@ -134,12 +157,12 @@ describe('SelectWaasFeeOptions', () => {
134
157
  feeOptionsConfirmed: false,
135
158
  handleConfirmFeeOption: mockHandleConfirmFeeOption,
136
159
  });
137
- vi.spyOn(useWaasFeeOptionsModule, 'useWaasFeeOptions').mockReturnValue([
138
- // @ts-expect-error - types are not compatible
139
- mockPendingFeeOptionConfirmation,
160
+ vi.spyOn(sequenceConnect, 'useWaasFeeOptions').mockReturnValue([
161
+ mockPendingFeeOptionConfirmation as any,
140
162
  vi.fn(),
141
- ]);
142
- vi.spyOn(useNetworkModule, 'getNetwork').mockReturnValue({
163
+ false,
164
+ ] as any);
165
+ vi.spyOn(sequenceConnect, 'getNetwork').mockReturnValue({
143
166
  type: NetworkType.MAINNET,
144
167
  chainId: 1,
145
168
  name: 'Mainnet',
@@ -157,28 +180,30 @@ describe('SelectWaasFeeOptions', () => {
157
180
  });
158
181
 
159
182
  it('should render fee options when loaded', () => {
160
- selectWaasFeeOptions$.pendingFeeOptionConfirmation.set(
161
- mockPendingFeeOptionConfirmation,
162
- );
163
- selectWaasFeeOptions$.selectedFeeOption.set(mockFeeOption);
183
+ selectWaasFeeOptionsStore.send({
184
+ type: 'setPendingFeeOptionConfirmation',
185
+ confirmation: mockPendingFeeOptionConfirmation as any,
186
+ });
187
+ selectWaasFeeOptionsStore.send({
188
+ type: 'setSelectedFeeOption',
189
+ feeOption: mockFeeOption,
190
+ });
164
191
 
165
192
  vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
166
- selectedFeeOption$: selectWaasFeeOptions$.selectedFeeOption,
167
193
  selectedFeeOption: mockFeeOption,
168
- // @ts-expect-error - types are not compatible
169
- pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation,
194
+ pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation as any,
170
195
  currencyBalance: mockCurrencyBalance,
171
196
  currencyBalanceLoading: false,
172
197
  insufficientBalance: false,
173
198
  feeOptionsConfirmed: false,
174
199
  handleConfirmFeeOption: mockHandleConfirmFeeOption,
175
200
  });
176
- vi.spyOn(useWaasFeeOptionsModule, 'useWaasFeeOptions').mockReturnValue([
177
- // @ts-expect-error - types are not compatible
178
- mockPendingFeeOptionConfirmation,
201
+ vi.spyOn(sequenceConnect, 'useWaasFeeOptions').mockReturnValue([
202
+ mockPendingFeeOptionConfirmation as any,
179
203
  vi.fn(),
180
- ]);
181
- vi.spyOn(useNetworkModule, 'getNetwork').mockReturnValue({
204
+ false,
205
+ ] as any);
206
+ vi.spyOn(sequenceConnect, 'getNetwork').mockReturnValue({
182
207
  type: NetworkType.MAINNET,
183
208
  chainId: 1,
184
209
  name: 'Mainnet',
@@ -196,4 +221,278 @@ describe('SelectWaasFeeOptions', () => {
196
221
  expect(screen.getByText('Select a fee option')).toBeInTheDocument();
197
222
  expect(screen.queryByText('Confirm fee option')).not.toBeInTheDocument();
198
223
  });
224
+
225
+ it('should select a fee option from multiple options', async () => {
226
+ const mockSetSelectedFeeOption = vi.fn();
227
+
228
+ vi.spyOn(storeModule, 'useSelectWaasFeeOptionsStore').mockReturnValue({
229
+ isVisible: true,
230
+ selectedFeeOption: mockFeeOption,
231
+ pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmationMultiple,
232
+ show: vi.fn(),
233
+ hide: vi.fn(),
234
+ setSelectedFeeOption: mockSetSelectedFeeOption,
235
+ setPendingFeeOptionConfirmation: vi.fn(),
236
+ });
237
+
238
+ vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
239
+ selectedFeeOption: mockFeeOption,
240
+ pendingFeeOptionConfirmation:
241
+ mockPendingFeeOptionConfirmationMultiple as any,
242
+ currencyBalance: mockCurrencyBalance,
243
+ currencyBalanceLoading: false,
244
+ insufficientBalance: false,
245
+ feeOptionsConfirmed: false,
246
+ handleConfirmFeeOption: mockHandleConfirmFeeOption,
247
+ });
248
+
249
+ vi.spyOn(sequenceConnect, 'useWaasFeeOptions').mockReturnValue([
250
+ mockPendingFeeOptionConfirmationMultiple as any,
251
+ vi.fn(),
252
+ false,
253
+ ] as any);
254
+ vi.spyOn(sequenceConnect, 'getNetwork').mockReturnValue({
255
+ type: NetworkType.MAINNET,
256
+ chainId: 1,
257
+ name: 'Mainnet',
258
+ nativeToken: TEST_CURRENCY,
259
+ });
260
+
261
+ render(<SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />);
262
+
263
+ // Find the select dropdown (fee option selector)
264
+ const selectTrigger = screen.getByRole('combobox');
265
+ expect(selectTrigger).toBeInTheDocument();
266
+ expect(selectTrigger).toHaveAttribute('id', 'fee-option');
267
+
268
+ // Click to open the dropdown
269
+ fireEvent.click(selectTrigger);
270
+
271
+ // Look for the USDC option in the dropdown
272
+ await waitFor(() => {
273
+ const usdcOption = screen.getByText(/USDC/);
274
+ expect(usdcOption).toBeInTheDocument();
275
+
276
+ // Select the USDC option
277
+ fireEvent.click(usdcOption);
278
+ });
279
+
280
+ // Verify the setSelectedFeeOption was called with the USDC option
281
+ await waitFor(() => {
282
+ expect(mockSetSelectedFeeOption).toHaveBeenCalledWith(mockFeeOption2);
283
+ });
284
+ });
285
+
286
+ it('should close the modal when cancel button is clicked', async () => {
287
+ const mockHide = vi.fn();
288
+
289
+ vi.spyOn(storeModule, 'useSelectWaasFeeOptionsStore').mockReturnValue({
290
+ isVisible: true,
291
+ selectedFeeOption: mockFeeOption,
292
+ pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation,
293
+ show: vi.fn(),
294
+ hide: mockHide,
295
+ setSelectedFeeOption: vi.fn(),
296
+ setPendingFeeOptionConfirmation: vi.fn(),
297
+ });
298
+
299
+ vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
300
+ selectedFeeOption: mockFeeOption,
301
+ pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation as any,
302
+ currencyBalance: mockCurrencyBalance,
303
+ currencyBalanceLoading: false,
304
+ insufficientBalance: false,
305
+ feeOptionsConfirmed: false,
306
+ handleConfirmFeeOption: mockHandleConfirmFeeOption,
307
+ });
308
+
309
+ vi.spyOn(sequenceConnect, 'useWaasFeeOptions').mockReturnValue([
310
+ mockPendingFeeOptionConfirmation as any,
311
+ vi.fn(),
312
+ false,
313
+ ] as any);
314
+ vi.spyOn(sequenceConnect, 'getNetwork').mockReturnValue({
315
+ type: NetworkType.MAINNET,
316
+ chainId: 1,
317
+ name: 'Mainnet',
318
+ nativeToken: TEST_CURRENCY,
319
+ });
320
+
321
+ render(<SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />);
322
+
323
+ const cancelButton = screen.getByText('Cancel');
324
+ expect(cancelButton).toBeInTheDocument();
325
+
326
+ fireEvent.click(cancelButton);
327
+
328
+ expect(mockHide).toHaveBeenCalledTimes(1);
329
+ expect(mockOnCancel).toHaveBeenCalledTimes(1);
330
+ });
331
+
332
+ it('should confirm fee option when confirm button is clicked', async () => {
333
+ selectWaasFeeOptionsStore.send({
334
+ type: 'setPendingFeeOptionConfirmation',
335
+ confirmation: mockPendingFeeOptionConfirmation as any,
336
+ });
337
+ selectWaasFeeOptionsStore.send({
338
+ type: 'setSelectedFeeOption',
339
+ feeOption: mockFeeOption,
340
+ });
341
+
342
+ vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
343
+ selectedFeeOption: mockFeeOption,
344
+ pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation as any,
345
+ currencyBalance: mockCurrencyBalance,
346
+ currencyBalanceLoading: false,
347
+ insufficientBalance: false,
348
+ feeOptionsConfirmed: false,
349
+ handleConfirmFeeOption: mockHandleConfirmFeeOption,
350
+ });
351
+
352
+ vi.spyOn(sequenceConnect, 'useWaasFeeOptions').mockReturnValue([
353
+ mockPendingFeeOptionConfirmation as any,
354
+ vi.fn(),
355
+ false,
356
+ ] as any);
357
+ vi.spyOn(sequenceConnect, 'getNetwork').mockReturnValue({
358
+ type: NetworkType.MAINNET,
359
+ chainId: 1,
360
+ name: 'Mainnet',
361
+ nativeToken: TEST_CURRENCY,
362
+ });
363
+
364
+ render(<SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />);
365
+
366
+ const confirmButton = screen.getByText(
367
+ `Continue with ${mockFeeOption.token.symbol}`,
368
+ );
369
+ expect(confirmButton).toBeInTheDocument();
370
+
371
+ fireEvent.click(confirmButton);
372
+
373
+ expect(mockHandleConfirmFeeOption).toHaveBeenCalledTimes(1);
374
+ });
375
+
376
+ it('should disable confirm button when insufficient balance', () => {
377
+ selectWaasFeeOptionsStore.send({
378
+ type: 'setPendingFeeOptionConfirmation',
379
+ confirmation: mockPendingFeeOptionConfirmation as any,
380
+ });
381
+ selectWaasFeeOptionsStore.send({
382
+ type: 'setSelectedFeeOption',
383
+ feeOption: mockFeeOption,
384
+ });
385
+
386
+ vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
387
+ selectedFeeOption: mockFeeOption,
388
+ pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation as any,
389
+ currencyBalance: mockCurrencyBalance,
390
+ currencyBalanceLoading: false,
391
+ insufficientBalance: true, // Insufficient balance
392
+ feeOptionsConfirmed: false,
393
+ handleConfirmFeeOption: mockHandleConfirmFeeOption,
394
+ });
395
+
396
+ vi.spyOn(sequenceConnect, 'useWaasFeeOptions').mockReturnValue([
397
+ mockPendingFeeOptionConfirmation as any,
398
+ vi.fn(),
399
+ false,
400
+ ] as any);
401
+ vi.spyOn(sequenceConnect, 'getNetwork').mockReturnValue({
402
+ type: NetworkType.MAINNET,
403
+ chainId: 1,
404
+ name: 'Mainnet',
405
+ nativeToken: TEST_CURRENCY,
406
+ });
407
+
408
+ render(<SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />);
409
+
410
+ const confirmButton = screen
411
+ .getByText(`Continue with ${mockFeeOption.token.symbol}`)
412
+ .closest('button');
413
+ expect(confirmButton).toBeDisabled();
414
+
415
+ // Try to click it and verify handleConfirmFeeOption is not called
416
+ if (confirmButton) {
417
+ fireEvent.click(confirmButton);
418
+ }
419
+ expect(mockHandleConfirmFeeOption).not.toHaveBeenCalled();
420
+ });
421
+
422
+ it('should show confirmed state when fee options are confirmed', () => {
423
+ selectWaasFeeOptionsStore.send({
424
+ type: 'setPendingFeeOptionConfirmation',
425
+ confirmation: mockPendingFeeOptionConfirmation as any,
426
+ });
427
+ selectWaasFeeOptionsStore.send({
428
+ type: 'setSelectedFeeOption',
429
+ feeOption: mockFeeOption,
430
+ });
431
+
432
+ vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
433
+ selectedFeeOption: mockFeeOption,
434
+ pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation as any,
435
+ currencyBalance: mockCurrencyBalance,
436
+ currencyBalanceLoading: false,
437
+ insufficientBalance: false,
438
+ feeOptionsConfirmed: true, // Options confirmed
439
+ handleConfirmFeeOption: mockHandleConfirmFeeOption,
440
+ });
441
+
442
+ vi.spyOn(sequenceConnect, 'useWaasFeeOptions').mockReturnValue([
443
+ mockPendingFeeOptionConfirmation as any,
444
+ vi.fn(),
445
+ false,
446
+ ] as any);
447
+ vi.spyOn(sequenceConnect, 'getNetwork').mockReturnValue({
448
+ type: NetworkType.MAINNET,
449
+ chainId: 1,
450
+ name: 'Mainnet',
451
+ nativeToken: TEST_CURRENCY,
452
+ });
453
+
454
+ render(
455
+ <SelectWaasFeeOptions
456
+ chainId={1}
457
+ onCancel={mockOnCancel}
458
+ titleOnConfirm="Confirm fee option"
459
+ />,
460
+ );
461
+
462
+ expect(screen.getByText('Confirm fee option')).toBeInTheDocument();
463
+
464
+ // Should show "Confirming" state in button
465
+ expect(screen.getByText('Confirming')).toBeInTheDocument();
466
+
467
+ // Fee options selector should be disabled (pointer-events-none)
468
+ const feeOptionsContainer = document.querySelector('.pointer-events-none');
469
+ expect(feeOptionsContainer).toBeInTheDocument();
470
+ });
471
+
472
+ it('should reset store state when modal is hidden via cancel', () => {
473
+ selectWaasFeeOptionsStore.send({
474
+ type: 'setPendingFeeOptionConfirmation',
475
+ confirmation: mockPendingFeeOptionConfirmation as any,
476
+ });
477
+ selectWaasFeeOptionsStore.send({
478
+ type: 'setSelectedFeeOption',
479
+ feeOption: mockFeeOption,
480
+ });
481
+
482
+ expect(selectWaasFeeOptionsStore.getSnapshot().context.isVisible).toBe(
483
+ true,
484
+ );
485
+ expect(
486
+ selectWaasFeeOptionsStore.getSnapshot().context.selectedFeeOption,
487
+ ).toBe(mockFeeOption);
488
+
489
+ // Hide the modal (simulating cancel action)
490
+ selectWaasFeeOptionsStore.send({ type: 'hide' });
491
+
492
+ // Verify state is reset
493
+ const state = selectWaasFeeOptionsStore.getSnapshot().context;
494
+ expect(state.isVisible).toBe(false);
495
+ expect(state.selectedFeeOption).toBeUndefined();
496
+ expect(state.pendingFeeOptionConfirmation).toBeUndefined();
497
+ });
199
498
  });