@b3dotfun/sdk 0.0.73 → 0.0.74-alpha.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 (461) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +75 -50
  2. package/dist/cjs/anyspend/react/components/AnySpendBuySpin.js +9 -10
  3. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +41 -41
  4. package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.d.ts +1 -0
  5. package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +17 -9
  6. package/dist/cjs/anyspend/react/components/AnySpendStakeB3.js +7 -8
  7. package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.js +7 -8
  8. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.d.ts +2 -1
  9. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +2 -2
  10. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  11. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +18 -14
  12. package/dist/cjs/anyspend/react/components/common/FeeDetailPanel.js +1 -1
  13. package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.js +2 -2
  14. package/dist/cjs/anyspend/react/components/common/InsufficientDepositPayment.js +6 -6
  15. package/dist/cjs/anyspend/react/components/common/OrderDetails.js +35 -35
  16. package/dist/cjs/anyspend/react/components/common/OrderDetailsCollapsible.js +1 -2
  17. package/dist/cjs/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  18. package/dist/cjs/anyspend/react/components/common/OrderHistory.js +7 -3
  19. package/dist/cjs/anyspend/react/components/common/OrderHistoryItem.js +1 -1
  20. package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +4 -4
  21. package/dist/cjs/anyspend/react/components/common/PanelOnrampPayment.js +8 -9
  22. package/dist/cjs/anyspend/react/components/common/PointsDetailPanel.js +1 -1
  23. package/dist/cjs/anyspend/react/components/common/RecipientSelection.js +1 -1
  24. package/dist/cjs/anyspend/react/components/common/TransferCryptoDetails.js +2 -3
  25. package/dist/cjs/anyspend/react/components/webview/WebviewOnrampOrderStatus.js +1 -2
  26. package/dist/cjs/anyspend/react/components/webview/WebviewOnrampPayment.js +12 -12
  27. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +4 -5
  28. package/dist/cjs/anyspend/react/hooks/useConnectedWalletDisplay.js +3 -2
  29. package/dist/cjs/anyspend/react/hooks/usePhantomTransfer.js +17 -17
  30. package/dist/cjs/anyspend/react/utils/toast.d.ts +6 -0
  31. package/dist/cjs/anyspend/react/utils/toast.js +9 -0
  32. package/dist/cjs/global-account/react/components/AccountAssets/AccountAssets.js +38 -2
  33. package/dist/cjs/global-account/react/components/AvatarCreator/AvatarCreator.js +2 -3
  34. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
  35. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +275 -39
  36. package/dist/cjs/global-account/react/components/B3DynamicModal.js +40 -13
  37. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.d.ts +1 -1
  38. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +19 -3
  39. package/dist/cjs/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  40. package/dist/cjs/global-account/react/components/Deposit/Deposit.js +61 -0
  41. package/dist/cjs/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  42. package/dist/cjs/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +34 -0
  43. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  44. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +104 -283
  45. package/dist/cjs/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  46. package/dist/cjs/global-account/react/components/LinkAccount/LinkNewAccount.js +320 -0
  47. package/dist/cjs/global-account/react/components/LinkAccount/LinkedAccountItem.d.ts +16 -0
  48. package/dist/cjs/global-account/react/components/LinkAccount/LinkedAccountItem.js +44 -0
  49. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  50. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.js +23 -0
  51. package/dist/cjs/global-account/react/components/ManageAccount/ContentTokens.js +1 -2
  52. package/dist/cjs/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  53. package/dist/cjs/global-account/react/components/ManageAccount/Header.js +120 -0
  54. package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  55. package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.js +43 -0
  56. package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  57. package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.js +16 -0
  58. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +16 -194
  59. package/dist/cjs/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  60. package/dist/cjs/global-account/react/components/ManageAccount/NFTContent.js +15 -0
  61. package/dist/cjs/global-account/react/components/ManageAccount/NotificationChannel.d.ts +16 -0
  62. package/dist/cjs/global-account/react/components/ManageAccount/NotificationChannel.js +13 -0
  63. package/dist/cjs/global-account/react/components/ManageAccount/NotificationsContent.d.ts +8 -0
  64. package/dist/cjs/global-account/react/components/ManageAccount/NotificationsContent.js +152 -0
  65. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  66. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +47 -0
  67. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  68. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +60 -0
  69. package/dist/cjs/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  70. package/dist/cjs/global-account/react/components/ManageAccount/SettingsMenuItem.js +8 -0
  71. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  72. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.js +116 -0
  73. package/dist/cjs/global-account/react/components/ManageAccount/TokenBalanceRow.d.ts +3 -3
  74. package/dist/cjs/global-account/react/components/ManageAccount/TokenBalanceRow.js +2 -2
  75. package/dist/cjs/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  76. package/dist/cjs/global-account/react/components/ManageAccount/TokenContent.js +44 -0
  77. package/dist/cjs/global-account/react/components/ManageAccount/channels/DiscordChannel.d.ts +11 -0
  78. package/dist/cjs/global-account/react/components/ManageAccount/channels/DiscordChannel.js +48 -0
  79. package/dist/cjs/global-account/react/components/ManageAccount/channels/EmailChannel.d.ts +11 -0
  80. package/dist/cjs/global-account/react/components/ManageAccount/channels/EmailChannel.js +68 -0
  81. package/dist/cjs/global-account/react/components/ManageAccount/channels/PhoneChannel.d.ts +14 -0
  82. package/dist/cjs/global-account/react/components/ManageAccount/channels/PhoneChannel.js +79 -0
  83. package/dist/cjs/global-account/react/components/ManageAccount/channels/TelegramChannel.d.ts +11 -0
  84. package/dist/cjs/global-account/react/components/ManageAccount/channels/TelegramChannel.js +79 -0
  85. package/dist/cjs/global-account/react/components/ManageAccount/channels/index.d.ts +4 -0
  86. package/dist/cjs/global-account/react/components/ManageAccount/channels/index.js +11 -0
  87. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.d.ts +11 -0
  88. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.js +12 -0
  89. package/dist/cjs/global-account/react/components/Send/Send.d.ts +5 -0
  90. package/dist/cjs/global-account/react/components/Send/Send.js +195 -0
  91. package/dist/cjs/global-account/react/components/SignInWithB3/SignIn.js +5 -4
  92. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -1
  93. package/dist/cjs/global-account/react/components/Toast/ToastComponents.d.ts +15 -0
  94. package/dist/cjs/global-account/react/components/Toast/ToastComponents.js +54 -0
  95. package/dist/cjs/global-account/react/components/Toast/ToastContext.d.ts +19 -0
  96. package/dist/cjs/global-account/react/components/Toast/ToastContext.js +59 -0
  97. package/dist/cjs/global-account/react/components/Toast/index.d.ts +4 -0
  98. package/dist/cjs/global-account/react/components/Toast/index.js +12 -0
  99. package/dist/cjs/global-account/react/components/Toast/toastApi.d.ts +21 -0
  100. package/dist/cjs/global-account/react/components/Toast/toastApi.js +93 -0
  101. package/dist/cjs/global-account/react/components/WalletImage/WalletImage.d.ts +4 -0
  102. package/dist/cjs/global-account/react/components/WalletImage/WalletImage.js +13 -0
  103. package/dist/cjs/global-account/react/components/icons/BellIcon.d.ts +3 -0
  104. package/dist/cjs/global-account/react/components/icons/BellIcon.js +5 -0
  105. package/dist/cjs/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  106. package/dist/cjs/global-account/react/components/icons/ChevronDownIcon.js +7 -0
  107. package/dist/cjs/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  108. package/dist/cjs/global-account/react/components/icons/CopyIcon.js +7 -0
  109. package/dist/cjs/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  110. package/dist/cjs/global-account/react/components/icons/LinkIcon.js +5 -0
  111. package/dist/cjs/global-account/react/components/icons/LockIcon.d.ts +3 -0
  112. package/dist/cjs/global-account/react/components/icons/LockIcon.js +5 -0
  113. package/dist/cjs/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  114. package/dist/cjs/global-account/react/components/icons/WalletIcon.js +7 -0
  115. package/dist/cjs/global-account/react/components/index.d.ts +10 -4
  116. package/dist/cjs/global-account/react/components/index.js +29 -9
  117. package/dist/cjs/global-account/react/components/ui/Tabs.js +2 -2
  118. package/dist/cjs/global-account/react/components/ui/dialog.js +2 -2
  119. package/dist/cjs/global-account/react/components/ui/drawer.js +1 -1
  120. package/dist/cjs/global-account/react/hooks/index.d.ts +3 -2
  121. package/dist/cjs/global-account/react/hooks/index.js +7 -3
  122. package/dist/cjs/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  123. package/dist/cjs/global-account/react/hooks/useAccountWallet.js +18 -0
  124. package/dist/cjs/global-account/react/hooks/useB3BalanceFromAddresses.js +1 -0
  125. package/dist/cjs/global-account/react/hooks/useChainSwitchWithAction.js +11 -11
  126. package/dist/cjs/global-account/react/hooks/useNativeBalance.js +2 -2
  127. package/dist/cjs/global-account/react/hooks/useNotifications.d.ts +48 -0
  128. package/dist/cjs/global-account/react/hooks/useNotifications.js +189 -0
  129. package/dist/cjs/global-account/react/hooks/useSimBalance.js +3 -3
  130. package/dist/cjs/global-account/react/hooks/useTokenBalanceDirect.d.ts +1 -0
  131. package/dist/cjs/global-account/react/hooks/useTokenBalanceDirect.js +1 -0
  132. package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +17 -17
  133. package/dist/cjs/global-account/react/stores/index.d.ts +1 -0
  134. package/dist/cjs/global-account/react/stores/index.js +3 -1
  135. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +47 -6
  136. package/dist/cjs/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  137. package/dist/cjs/global-account/react/stores/useRecentAddressesStore.js +36 -0
  138. package/dist/cjs/global-account/react/utils/index.d.ts +4 -0
  139. package/dist/cjs/global-account/react/utils/index.js +20 -0
  140. package/dist/cjs/global-account/react/utils/notificationsAPI.d.ts +80 -0
  141. package/dist/cjs/global-account/react/utils/notificationsAPI.js +257 -0
  142. package/dist/cjs/global-account/react/utils/profileDisplay.d.ts +3 -0
  143. package/dist/cjs/global-account/react/utils/profileDisplay.js +8 -4
  144. package/dist/cjs/global-account/react/utils/toast.d.ts +6 -0
  145. package/dist/cjs/global-account/react/utils/toast.js +9 -0
  146. package/dist/cjs/shared/constants/chains/supported.d.ts +3 -2
  147. package/dist/cjs/shared/constants/chains/supported.js +4 -0
  148. package/dist/cjs/shared/utils/ipfs.js +10 -3
  149. package/dist/esm/anyspend/react/components/AnySpend.js +67 -42
  150. package/dist/esm/anyspend/react/components/AnySpendBuySpin.js +1 -2
  151. package/dist/esm/anyspend/react/components/AnySpendCustom.js +10 -10
  152. package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.d.ts +1 -0
  153. package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +12 -4
  154. package/dist/esm/anyspend/react/components/AnySpendStakeB3.js +1 -2
  155. package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.js +1 -2
  156. package/dist/esm/anyspend/react/components/AnyspendDepositHype.d.ts +2 -1
  157. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +2 -2
  158. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  159. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +9 -5
  160. package/dist/esm/anyspend/react/components/common/FeeDetailPanel.js +1 -1
  161. package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.js +2 -2
  162. package/dist/esm/anyspend/react/components/common/InsufficientDepositPayment.js +1 -1
  163. package/dist/esm/anyspend/react/components/common/OrderDetails.js +2 -2
  164. package/dist/esm/anyspend/react/components/common/OrderDetailsCollapsible.js +1 -2
  165. package/dist/esm/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  166. package/dist/esm/anyspend/react/components/common/OrderHistory.js +6 -5
  167. package/dist/esm/anyspend/react/components/common/OrderHistoryItem.js +2 -2
  168. package/dist/esm/anyspend/react/components/common/PanelOnramp.js +4 -4
  169. package/dist/esm/anyspend/react/components/common/PanelOnrampPayment.js +2 -3
  170. package/dist/esm/anyspend/react/components/common/PointsDetailPanel.js +1 -1
  171. package/dist/esm/anyspend/react/components/common/RecipientSelection.js +1 -1
  172. package/dist/esm/anyspend/react/components/common/TransferCryptoDetails.js +1 -2
  173. package/dist/esm/anyspend/react/components/webview/WebviewOnrampOrderStatus.js +1 -2
  174. package/dist/esm/anyspend/react/components/webview/WebviewOnrampPayment.js +1 -1
  175. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +1 -2
  176. package/dist/esm/anyspend/react/hooks/useConnectedWalletDisplay.js +3 -2
  177. package/dist/esm/anyspend/react/hooks/usePhantomTransfer.js +1 -1
  178. package/dist/esm/anyspend/react/utils/toast.d.ts +6 -0
  179. package/dist/esm/anyspend/react/utils/toast.js +5 -0
  180. package/dist/esm/global-account/react/components/AccountAssets/AccountAssets.js +38 -2
  181. package/dist/esm/global-account/react/components/AvatarCreator/AvatarCreator.js +1 -2
  182. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
  183. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +276 -40
  184. package/dist/esm/global-account/react/components/B3DynamicModal.js +37 -13
  185. package/dist/esm/global-account/react/components/B3Provider/B3Provider.d.ts +1 -1
  186. package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +19 -3
  187. package/dist/esm/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  188. package/dist/esm/global-account/react/components/Deposit/Deposit.js +55 -0
  189. package/dist/esm/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  190. package/dist/esm/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +31 -0
  191. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  192. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +103 -283
  193. package/dist/esm/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  194. package/dist/esm/global-account/react/components/LinkAccount/LinkNewAccount.js +314 -0
  195. package/dist/esm/global-account/react/components/LinkAccount/LinkedAccountItem.d.ts +16 -0
  196. package/dist/esm/global-account/react/components/LinkAccount/LinkedAccountItem.js +42 -0
  197. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  198. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.js +21 -0
  199. package/dist/esm/global-account/react/components/ManageAccount/ContentTokens.js +1 -2
  200. package/dist/esm/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  201. package/dist/esm/global-account/react/components/ManageAccount/Header.js +81 -0
  202. package/dist/esm/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  203. package/dist/esm/global-account/react/components/ManageAccount/HomeActions.js +41 -0
  204. package/dist/esm/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  205. package/dist/esm/global-account/react/components/ManageAccount/HomeContent.js +10 -0
  206. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +18 -196
  207. package/dist/esm/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  208. package/dist/esm/global-account/react/components/ManageAccount/NFTContent.js +13 -0
  209. package/dist/esm/global-account/react/components/ManageAccount/NotificationChannel.d.ts +16 -0
  210. package/dist/esm/global-account/react/components/ManageAccount/NotificationChannel.js +9 -0
  211. package/dist/esm/global-account/react/components/ManageAccount/NotificationsContent.d.ts +8 -0
  212. package/dist/esm/global-account/react/components/ManageAccount/NotificationsContent.js +147 -0
  213. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  214. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +45 -0
  215. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  216. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +55 -0
  217. package/dist/esm/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  218. package/dist/esm/global-account/react/components/ManageAccount/SettingsMenuItem.js +6 -0
  219. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  220. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.js +111 -0
  221. package/dist/esm/global-account/react/components/ManageAccount/TokenBalanceRow.d.ts +3 -3
  222. package/dist/esm/global-account/react/components/ManageAccount/TokenBalanceRow.js +3 -3
  223. package/dist/esm/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  224. package/dist/esm/global-account/react/components/ManageAccount/TokenContent.js +42 -0
  225. package/dist/esm/global-account/react/components/ManageAccount/channels/DiscordChannel.d.ts +11 -0
  226. package/dist/esm/global-account/react/components/ManageAccount/channels/DiscordChannel.js +44 -0
  227. package/dist/esm/global-account/react/components/ManageAccount/channels/EmailChannel.d.ts +11 -0
  228. package/dist/esm/global-account/react/components/ManageAccount/channels/EmailChannel.js +64 -0
  229. package/dist/esm/global-account/react/components/ManageAccount/channels/PhoneChannel.d.ts +14 -0
  230. package/dist/esm/global-account/react/components/ManageAccount/channels/PhoneChannel.js +75 -0
  231. package/dist/esm/global-account/react/components/ManageAccount/channels/TelegramChannel.d.ts +11 -0
  232. package/dist/esm/global-account/react/components/ManageAccount/channels/TelegramChannel.js +75 -0
  233. package/dist/esm/global-account/react/components/ManageAccount/channels/index.d.ts +4 -0
  234. package/dist/esm/global-account/react/components/ManageAccount/channels/index.js +4 -0
  235. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.d.ts +11 -0
  236. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.js +10 -0
  237. package/dist/esm/global-account/react/components/Send/Send.d.ts +5 -0
  238. package/dist/esm/global-account/react/components/Send/Send.js +189 -0
  239. package/dist/esm/global-account/react/components/SignInWithB3/SignIn.js +7 -6
  240. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -1
  241. package/dist/esm/global-account/react/components/Toast/ToastComponents.d.ts +15 -0
  242. package/dist/esm/global-account/react/components/Toast/ToastComponents.js +50 -0
  243. package/dist/esm/global-account/react/components/Toast/ToastContext.d.ts +19 -0
  244. package/dist/esm/global-account/react/components/Toast/ToastContext.js +55 -0
  245. package/dist/esm/global-account/react/components/Toast/index.d.ts +4 -0
  246. package/dist/esm/global-account/react/components/Toast/index.js +3 -0
  247. package/dist/esm/global-account/react/components/Toast/toastApi.d.ts +21 -0
  248. package/dist/esm/global-account/react/components/Toast/toastApi.js +89 -0
  249. package/dist/esm/global-account/react/components/WalletImage/WalletImage.d.ts +4 -0
  250. package/dist/esm/global-account/react/components/WalletImage/WalletImage.js +11 -0
  251. package/dist/esm/global-account/react/components/icons/BellIcon.d.ts +3 -0
  252. package/dist/esm/global-account/react/components/icons/BellIcon.js +3 -0
  253. package/dist/esm/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  254. package/dist/esm/global-account/react/components/icons/ChevronDownIcon.js +4 -0
  255. package/dist/esm/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  256. package/dist/esm/global-account/react/components/icons/CopyIcon.js +4 -0
  257. package/dist/esm/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  258. package/dist/esm/global-account/react/components/icons/LinkIcon.js +3 -0
  259. package/dist/esm/global-account/react/components/icons/LockIcon.d.ts +3 -0
  260. package/dist/esm/global-account/react/components/icons/LockIcon.js +3 -0
  261. package/dist/esm/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  262. package/dist/esm/global-account/react/components/icons/WalletIcon.js +4 -0
  263. package/dist/esm/global-account/react/components/index.d.ts +10 -4
  264. package/dist/esm/global-account/react/components/index.js +14 -5
  265. package/dist/esm/global-account/react/components/ui/Tabs.js +2 -2
  266. package/dist/esm/global-account/react/components/ui/dialog.js +2 -2
  267. package/dist/esm/global-account/react/components/ui/drawer.js +1 -1
  268. package/dist/esm/global-account/react/hooks/index.d.ts +3 -2
  269. package/dist/esm/global-account/react/hooks/index.js +3 -2
  270. package/dist/esm/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  271. package/dist/esm/global-account/react/hooks/useAccountWallet.js +17 -0
  272. package/dist/esm/global-account/react/hooks/useB3BalanceFromAddresses.js +1 -0
  273. package/dist/esm/global-account/react/hooks/useChainSwitchWithAction.js +2 -2
  274. package/dist/esm/global-account/react/hooks/useNativeBalance.js +1 -1
  275. package/dist/esm/global-account/react/hooks/useNotifications.d.ts +48 -0
  276. package/dist/esm/global-account/react/hooks/useNotifications.js +186 -0
  277. package/dist/esm/global-account/react/hooks/useSimBalance.js +3 -3
  278. package/dist/esm/global-account/react/hooks/useTokenBalanceDirect.d.ts +1 -0
  279. package/dist/esm/global-account/react/hooks/useTokenBalanceDirect.js +1 -0
  280. package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +2 -2
  281. package/dist/esm/global-account/react/stores/index.d.ts +1 -0
  282. package/dist/esm/global-account/react/stores/index.js +1 -0
  283. package/dist/esm/global-account/react/stores/useModalStore.d.ts +47 -6
  284. package/dist/esm/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  285. package/dist/esm/global-account/react/stores/useRecentAddressesStore.js +33 -0
  286. package/dist/esm/global-account/react/utils/index.d.ts +4 -0
  287. package/dist/esm/global-account/react/utils/index.js +4 -0
  288. package/dist/esm/global-account/react/utils/notificationsAPI.d.ts +80 -0
  289. package/dist/esm/global-account/react/utils/notificationsAPI.js +254 -0
  290. package/dist/esm/global-account/react/utils/profileDisplay.d.ts +3 -0
  291. package/dist/esm/global-account/react/utils/profileDisplay.js +8 -4
  292. package/dist/esm/global-account/react/utils/toast.d.ts +6 -0
  293. package/dist/esm/global-account/react/utils/toast.js +5 -0
  294. package/dist/esm/shared/constants/chains/supported.d.ts +3 -2
  295. package/dist/esm/shared/constants/chains/supported.js +3 -0
  296. package/dist/esm/shared/utils/ipfs.js +10 -3
  297. package/dist/styles/index.css +1 -1
  298. package/dist/types/anyspend/react/components/AnySpendCustomExactIn.d.ts +1 -0
  299. package/dist/types/anyspend/react/components/AnyspendDepositHype.d.ts +2 -1
  300. package/dist/types/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  301. package/dist/types/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  302. package/dist/types/anyspend/react/utils/toast.d.ts +6 -0
  303. package/dist/types/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
  304. package/dist/types/global-account/react/components/B3Provider/B3Provider.d.ts +1 -1
  305. package/dist/types/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  306. package/dist/types/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  307. package/dist/types/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  308. package/dist/types/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  309. package/dist/types/global-account/react/components/LinkAccount/LinkedAccountItem.d.ts +16 -0
  310. package/dist/types/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  311. package/dist/types/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  312. package/dist/types/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  313. package/dist/types/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  314. package/dist/types/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  315. package/dist/types/global-account/react/components/ManageAccount/NotificationChannel.d.ts +16 -0
  316. package/dist/types/global-account/react/components/ManageAccount/NotificationsContent.d.ts +8 -0
  317. package/dist/types/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  318. package/dist/types/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  319. package/dist/types/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  320. package/dist/types/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  321. package/dist/types/global-account/react/components/ManageAccount/TokenBalanceRow.d.ts +3 -3
  322. package/dist/types/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  323. package/dist/types/global-account/react/components/ManageAccount/channels/DiscordChannel.d.ts +11 -0
  324. package/dist/types/global-account/react/components/ManageAccount/channels/EmailChannel.d.ts +11 -0
  325. package/dist/types/global-account/react/components/ManageAccount/channels/PhoneChannel.d.ts +14 -0
  326. package/dist/types/global-account/react/components/ManageAccount/channels/TelegramChannel.d.ts +11 -0
  327. package/dist/types/global-account/react/components/ManageAccount/channels/index.d.ts +4 -0
  328. package/dist/types/global-account/react/components/ModalHeader/ModalHeader.d.ts +11 -0
  329. package/dist/types/global-account/react/components/Send/Send.d.ts +5 -0
  330. package/dist/types/global-account/react/components/Toast/ToastComponents.d.ts +15 -0
  331. package/dist/types/global-account/react/components/Toast/ToastContext.d.ts +19 -0
  332. package/dist/types/global-account/react/components/Toast/index.d.ts +4 -0
  333. package/dist/types/global-account/react/components/Toast/toastApi.d.ts +21 -0
  334. package/dist/types/global-account/react/components/WalletImage/WalletImage.d.ts +4 -0
  335. package/dist/types/global-account/react/components/icons/BellIcon.d.ts +3 -0
  336. package/dist/types/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  337. package/dist/types/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  338. package/dist/types/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  339. package/dist/types/global-account/react/components/icons/LockIcon.d.ts +3 -0
  340. package/dist/types/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  341. package/dist/types/global-account/react/components/index.d.ts +10 -4
  342. package/dist/types/global-account/react/hooks/index.d.ts +3 -2
  343. package/dist/types/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  344. package/dist/types/global-account/react/hooks/useNotifications.d.ts +48 -0
  345. package/dist/types/global-account/react/hooks/useTokenBalanceDirect.d.ts +1 -0
  346. package/dist/types/global-account/react/stores/index.d.ts +1 -0
  347. package/dist/types/global-account/react/stores/useModalStore.d.ts +47 -6
  348. package/dist/types/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  349. package/dist/types/global-account/react/utils/index.d.ts +4 -0
  350. package/dist/types/global-account/react/utils/notificationsAPI.d.ts +80 -0
  351. package/dist/types/global-account/react/utils/profileDisplay.d.ts +3 -0
  352. package/dist/types/global-account/react/utils/toast.d.ts +6 -0
  353. package/dist/types/shared/constants/chains/supported.d.ts +3 -2
  354. package/package.json +2 -1
  355. package/src/anyspend/react/components/AnySpend.tsx +213 -173
  356. package/src/anyspend/react/components/AnySpendBuySpin.tsx +2 -1
  357. package/src/anyspend/react/components/AnySpendCustom.tsx +80 -77
  358. package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +20 -4
  359. package/src/anyspend/react/components/AnySpendStakeB3.tsx +2 -1
  360. package/src/anyspend/react/components/AnySpendStakeB3ExactIn.tsx +2 -1
  361. package/src/anyspend/react/components/AnyspendDepositHype.tsx +3 -0
  362. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +56 -22
  363. package/src/anyspend/react/components/common/FeeDetailPanel.tsx +1 -1
  364. package/src/anyspend/react/components/common/FiatPaymentMethod.tsx +2 -2
  365. package/src/anyspend/react/components/common/InsufficientDepositPayment.tsx +1 -1
  366. package/src/anyspend/react/components/common/OrderDetails.tsx +6 -2
  367. package/src/anyspend/react/components/common/OrderDetailsCollapsible.tsx +2 -2
  368. package/src/anyspend/react/components/common/OrderHistory.tsx +8 -13
  369. package/src/anyspend/react/components/common/OrderHistoryItem.tsx +69 -25
  370. package/src/anyspend/react/components/common/PanelOnramp.tsx +6 -4
  371. package/src/anyspend/react/components/common/PanelOnrampPayment.tsx +3 -3
  372. package/src/anyspend/react/components/common/PointsDetailPanel.tsx +1 -1
  373. package/src/anyspend/react/components/common/RecipientSelection.tsx +1 -1
  374. package/src/anyspend/react/components/common/TransferCryptoDetails.tsx +2 -2
  375. package/src/anyspend/react/components/webview/WebviewOnrampOrderStatus.tsx +3 -3
  376. package/src/anyspend/react/components/webview/WebviewOnrampPayment.tsx +2 -1
  377. package/src/anyspend/react/hooks/useAnyspendFlow.ts +2 -1
  378. package/src/anyspend/react/hooks/useConnectedWalletDisplay.ts +3 -2
  379. package/src/anyspend/react/hooks/usePhantomTransfer.ts +1 -1
  380. package/src/anyspend/react/utils/toast.ts +6 -0
  381. package/src/global-account/react/components/AccountAssets/AccountAssets.tsx +115 -25
  382. package/src/global-account/react/components/AvatarCreator/AvatarCreator.tsx +2 -2
  383. package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +491 -130
  384. package/src/global-account/react/components/B3DynamicModal.tsx +76 -17
  385. package/src/global-account/react/components/B3Provider/B3Provider.tsx +40 -20
  386. package/src/global-account/react/components/Deposit/Deposit.tsx +208 -0
  387. package/src/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.tsx +84 -0
  388. package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +269 -434
  389. package/src/global-account/react/components/LinkAccount/LinkNewAccount.tsx +480 -0
  390. package/src/global-account/react/components/LinkAccount/LinkedAccountItem.tsx +135 -0
  391. package/src/global-account/react/components/ManageAccount/BottomNavigation.tsx +83 -0
  392. package/src/global-account/react/components/ManageAccount/ContentTokens.tsx +2 -1
  393. package/src/global-account/react/components/ManageAccount/Header.tsx +230 -0
  394. package/src/global-account/react/components/ManageAccount/HomeActions.tsx +118 -0
  395. package/src/global-account/react/components/ManageAccount/HomeContent.tsx +42 -0
  396. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +74 -597
  397. package/src/global-account/react/components/ManageAccount/NFTContent.tsx +24 -0
  398. package/src/global-account/react/components/ManageAccount/NotificationChannel.tsx +94 -0
  399. package/src/global-account/react/components/ManageAccount/NotificationsContent.tsx +268 -0
  400. package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +79 -0
  401. package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +106 -0
  402. package/src/global-account/react/components/ManageAccount/SettingsMenuItem.tsx +31 -0
  403. package/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +197 -0
  404. package/src/global-account/react/components/ManageAccount/TokenBalanceRow.tsx +20 -5
  405. package/src/global-account/react/components/ManageAccount/TokenContent.tsx +66 -0
  406. package/src/global-account/react/components/ManageAccount/channels/DiscordChannel.tsx +119 -0
  407. package/src/global-account/react/components/ManageAccount/channels/EmailChannel.tsx +168 -0
  408. package/src/global-account/react/components/ManageAccount/channels/PhoneChannel.tsx +227 -0
  409. package/src/global-account/react/components/ManageAccount/channels/TelegramChannel.tsx +150 -0
  410. package/src/global-account/react/components/ManageAccount/channels/index.ts +4 -0
  411. package/src/global-account/react/components/ModalHeader/ModalHeader.tsx +61 -0
  412. package/src/global-account/react/components/Send/Send.tsx +621 -0
  413. package/src/global-account/react/components/SignInWithB3/SignIn.tsx +13 -12
  414. package/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx +1 -1
  415. package/src/global-account/react/components/Toast/README.md +350 -0
  416. package/src/global-account/react/components/Toast/ToastComponents.tsx +159 -0
  417. package/src/global-account/react/components/Toast/ToastContext.tsx +86 -0
  418. package/src/global-account/react/components/Toast/index.ts +4 -0
  419. package/src/global-account/react/components/Toast/toastApi.ts +98 -0
  420. package/src/global-account/react/components/WalletImage/WalletImage.tsx +12 -0
  421. package/src/global-account/react/components/icons/BellIcon.tsx +15 -0
  422. package/src/global-account/react/components/icons/ChevronDownIcon.tsx +17 -0
  423. package/src/global-account/react/components/icons/CopyIcon.tsx +22 -0
  424. package/src/global-account/react/components/icons/LinkIcon.tsx +15 -0
  425. package/src/global-account/react/components/icons/LockIcon.tsx +15 -0
  426. package/src/global-account/react/components/icons/WalletIcon.tsx +21 -0
  427. package/src/global-account/react/components/index.ts +19 -5
  428. package/src/global-account/react/components/ui/Tabs.tsx +5 -13
  429. package/src/global-account/react/components/ui/dialog.tsx +23 -14
  430. package/src/global-account/react/components/ui/drawer.tsx +1 -1
  431. package/src/global-account/react/hooks/index.ts +5 -1
  432. package/src/global-account/react/hooks/useAccountWallet.tsx +26 -0
  433. package/src/global-account/react/hooks/useB3BalanceFromAddresses.ts +1 -0
  434. package/src/global-account/react/hooks/useChainSwitchWithAction.ts +3 -2
  435. package/src/global-account/react/hooks/useNativeBalance.tsx +2 -1
  436. package/src/global-account/react/hooks/useNotifications.ts +229 -0
  437. package/src/global-account/react/hooks/useSimBalance.ts +3 -3
  438. package/src/global-account/react/hooks/useTokenBalanceDirect.tsx +2 -0
  439. package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +3 -2
  440. package/src/global-account/react/stores/index.ts +1 -0
  441. package/src/global-account/react/stores/useModalStore.ts +53 -6
  442. package/src/global-account/react/stores/useRecentAddressesStore.ts +54 -0
  443. package/src/global-account/react/utils/index.ts +4 -0
  444. package/src/global-account/react/utils/notificationsAPI.ts +305 -0
  445. package/src/global-account/react/utils/profileDisplay.ts +12 -4
  446. package/src/global-account/react/utils/toast.ts +6 -0
  447. package/src/shared/constants/chains/supported.ts +4 -0
  448. package/src/shared/utils/ipfs.ts +10 -3
  449. package/src/styles/index.css +12 -1
  450. package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.d.ts +0 -7
  451. package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.js +0 -107
  452. package/dist/cjs/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  453. package/dist/cjs/global-account/react/components/ProfileEditor/ProfileEditor.js +0 -151
  454. package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.d.ts +0 -7
  455. package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.js +0 -104
  456. package/dist/esm/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  457. package/dist/esm/global-account/react/components/ProfileEditor/ProfileEditor.js +0 -145
  458. package/dist/types/global-account/react/components/ManageAccount/BalanceContent.d.ts +0 -7
  459. package/dist/types/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  460. package/src/global-account/react/components/ManageAccount/BalanceContent.tsx +0 -258
  461. package/src/global-account/react/components/ProfileEditor/ProfileEditor.tsx +0 -279
@@ -1,30 +1,58 @@
1
1
  "use client";
2
2
 
3
3
  import app from "@b3dotfun/sdk/global-account/app";
4
- import { Button, useB3, useProfile } from "@b3dotfun/sdk/global-account/react";
4
+ import { Button, IPFSMediaRenderer, toast, useB3, useProfile } from "@b3dotfun/sdk/global-account/react";
5
+ import { validateImageUrl } from "@b3dotfun/sdk/global-account/react/utils/profileDisplay";
5
6
  import { cn } from "@b3dotfun/sdk/shared/utils/cn";
6
7
  import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
8
+ import { getIpfsUrl } from "@b3dotfun/sdk/shared/utils/ipfs";
7
9
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
8
- import { Check, Loader2, Upload, X } from "lucide-react";
9
- import { useRef, useState } from "react";
10
- import { toast } from "sonner";
10
+ import { Loader2, Upload, X } from "lucide-react";
11
+ import { useCallback, useRef, useState } from "react";
12
+ import type { Area } from "react-easy-crop";
13
+ import Cropper from "react-easy-crop";
14
+ import "react-easy-crop/react-easy-crop.css";
15
+
11
16
  import { useActiveAccount } from "thirdweb/react";
12
17
  import { upload } from "thirdweb/storage";
18
+ import { useModalStore } from "../../stores";
19
+ import ModalHeader from "../ModalHeader/ModalHeader";
13
20
 
14
21
  const debug = debugB3React("AvatarEditor");
15
22
 
23
+ // Helper function to create an image element from a URL
24
+ const createImage = (url: string): Promise<HTMLImageElement> =>
25
+ new Promise((resolve, reject) => {
26
+ const image = new Image();
27
+ image.addEventListener("load", () => resolve(image));
28
+ image.addEventListener("error", error => reject(error));
29
+ image.setAttribute("crossOrigin", "anonymous");
30
+ image.src = url;
31
+ });
32
+
16
33
  interface AvatarEditorProps {
17
34
  onSetAvatar?: () => void;
18
35
  className?: string;
19
36
  }
20
37
 
38
+ type ViewStep = "select" | "upload";
39
+
21
40
  export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
41
+ const [viewStep, setViewStep] = useState<ViewStep>("select");
42
+ const [selectedAvatar, setSelectedAvatar] = useState<string | null>(null);
43
+ const [selectedProfileType, setSelectedProfileType] = useState<string | null>(null); // Track which profile was selected
44
+ const [hoveredProfile, setHoveredProfile] = useState<string | null>(null);
22
45
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
23
46
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
24
- const [isUploading, setIsUploading] = useState(false);
25
47
  const [isSaving, setIsSaving] = useState(false);
48
+ const [isDragging, setIsDragging] = useState(false);
49
+ const [crop, setCrop] = useState({ x: 0, y: 0 });
50
+ const [zoom, setZoom] = useState(1);
51
+ const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>(null);
26
52
  const fileInputRef = useRef<HTMLInputElement>(null);
27
- const { setUser } = useB3();
53
+ const { setUser, user, partnerId } = useB3();
54
+ const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
55
+ const contentType = useModalStore(state => state.contentType);
28
56
 
29
57
  const account = useActiveAccount();
30
58
  const { data: profile, refetch: refreshProfile } = useProfile({
@@ -32,9 +60,52 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
32
60
  fresh: true,
33
61
  });
34
62
 
35
- // Thirdweb upload function
63
+ // Get raw avatar URLs, convert IPFS URLs, and validate them
64
+ const rawCurrentAvatar = user?.avatar || profile?.avatar;
65
+ const currentAvatar = validateImageUrl(rawCurrentAvatar);
66
+ const safePreviewUrl = validateImageUrl(previewUrl);
36
67
 
37
- const hasAvatar = profile?.avatar;
68
+ const onCropComplete = useCallback((_croppedArea: Area, croppedAreaPixels: Area) => {
69
+ setCroppedAreaPixels(croppedAreaPixels);
70
+ }, []);
71
+
72
+ const createCroppedImage = async (imageSrc: string, pixelCrop: Area): Promise<Blob> => {
73
+ const image = await createImage(imageSrc);
74
+ const canvas = document.createElement("canvas");
75
+ const ctx = canvas.getContext("2d");
76
+
77
+ if (!ctx) {
78
+ throw new Error("Failed to get canvas context");
79
+ }
80
+
81
+ // Set canvas size to the crop area
82
+ canvas.width = pixelCrop.width;
83
+ canvas.height = pixelCrop.height;
84
+
85
+ // Draw the cropped image
86
+ ctx.drawImage(
87
+ image,
88
+ pixelCrop.x,
89
+ pixelCrop.y,
90
+ pixelCrop.width,
91
+ pixelCrop.height,
92
+ 0,
93
+ 0,
94
+ pixelCrop.width,
95
+ pixelCrop.height,
96
+ );
97
+
98
+ // Return as blob
99
+ return new Promise((resolve, reject) => {
100
+ canvas.toBlob(blob => {
101
+ if (!blob) {
102
+ reject(new Error("Canvas is empty"));
103
+ return;
104
+ }
105
+ resolve(blob);
106
+ }, "image/jpeg");
107
+ });
108
+ };
38
109
 
39
110
  const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
40
111
  const file = event.target.files?.[0];
@@ -52,181 +123,471 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
52
123
  }
53
124
 
54
125
  setSelectedFile(file);
126
+ // Clear profile type selection when uploading a new file
127
+ setSelectedProfileType(null);
55
128
 
56
129
  // Create preview URL
57
130
  const url = URL.createObjectURL(file);
58
131
  setPreviewUrl(url);
132
+ setSelectedAvatar(url);
59
133
  }
60
134
  };
61
135
 
62
- const handleRemoveFile = () => {
136
+ const handleRemovePreview = () => {
137
+ setSelectedAvatar(currentAvatar || null);
138
+ setSelectedProfileType(null);
63
139
  setSelectedFile(null);
64
140
  if (previewUrl) {
65
- URL.revokeObjectURL(previewUrl);
141
+ // Only revoke blob URLs (from file uploads), not regular URLs (from social profiles)
142
+ if (previewUrl.startsWith("blob:")) {
143
+ URL.revokeObjectURL(previewUrl);
144
+ }
66
145
  setPreviewUrl(null);
67
146
  }
68
147
  if (fileInputRef.current) {
69
148
  fileInputRef.current.value = "";
70
149
  }
150
+ // Reset crop state
151
+ setCrop({ x: 0, y: 0 });
152
+ setZoom(1);
153
+ setCroppedAreaPixels(null);
71
154
  };
72
155
 
73
- const handleUpload = async () => {
74
- if (!selectedFile) {
75
- toast.error("Please select an image first");
156
+ const handleSaveChanges = async () => {
157
+ if (!account?.address) {
158
+ toast.error("No account connected");
76
159
  return;
77
160
  }
78
161
 
79
- setIsUploading(true);
162
+ setIsSaving(true);
80
163
  try {
81
- debug("Starting upload to IPFS", selectedFile);
164
+ let fileToUpload: File | null = null;
82
165
 
83
- // Upload to IPFS using Thirdweb
84
- const ipfsUrl = await upload({
85
- client,
86
- files: [selectedFile],
87
- });
166
+ // If user uploaded a new file and cropped it
167
+ if (selectedFile && previewUrl && croppedAreaPixels) {
168
+ try {
169
+ const croppedBlob = await createCroppedImage(previewUrl, croppedAreaPixels);
170
+ const extension = selectedFile.name.split(".").pop() || "jpg";
171
+ fileToUpload = new File([croppedBlob], `avatar-cropped.${extension}`, { type: "image/jpeg" });
172
+ } catch (error) {
173
+ debug("Error cropping image:", error);
174
+ toast.error("Failed to crop image. Please try again.");
175
+ setIsSaving(false);
176
+ return;
177
+ }
178
+ } else if (selectedFile) {
179
+ // Fallback if no crop was made
180
+ fileToUpload = selectedFile;
181
+ } else if (selectedProfileType && previewUrl && croppedAreaPixels) {
182
+ // User selected from social profile and cropped it
183
+ debug("Cropping social profile image:", previewUrl);
184
+
185
+ try {
186
+ const croppedBlob = await createCroppedImage(previewUrl, croppedAreaPixels);
187
+ fileToUpload = new File([croppedBlob], `avatar-${selectedProfileType}-cropped.jpg`, { type: "image/jpeg" });
188
+ debug("Successfully cropped social profile image");
189
+ } catch (error) {
190
+ debug("Error cropping social profile image:", error);
191
+ toast.error("Failed to crop image. Please try again.");
192
+ setIsSaving(false);
193
+ return;
194
+ }
195
+ } else if (selectedProfileType && selectedAvatar) {
196
+ // User selected from existing profile avatars without cropping
197
+ // Fetch the image from the URL and convert to blob
198
+ debug("Fetching image from social profile:", selectedAvatar);
199
+
200
+ try {
201
+ // Convert IPFS URLs to gateway URLs for fetching
202
+ const httpUrl = getIpfsUrl(selectedAvatar);
203
+ const response = await fetch(httpUrl);
204
+ if (!response.ok) {
205
+ throw new Error("Failed to fetch image");
206
+ }
207
+
208
+ const blob = await response.blob();
209
+ debug("Fetched blob with type:", blob.type);
210
+
211
+ // Determine the correct extension from the blob's MIME type
212
+ // This handles URLs without extensions (like Farcaster images)
213
+ const mimeToExtension: Record<string, string> = {
214
+ "image/jpeg": "jpg",
215
+ "image/jpg": "jpg",
216
+ "image/png": "png",
217
+ "image/gif": "gif",
218
+ "image/webp": "webp",
219
+ "image/svg+xml": "svg",
220
+ };
221
+
222
+ const extension = blob.type ? mimeToExtension[blob.type.toLowerCase()] || "jpg" : "jpg";
223
+ const mimeType = blob.type || `image/${extension}`;
224
+
225
+ fileToUpload = new File([blob], `avatar-${selectedProfileType}.${extension}`, { type: mimeType });
226
+
227
+ debug("Successfully converted social profile image to file with extension:", extension);
228
+ } catch (fetchError) {
229
+ debug("Error fetching social profile image:", fetchError);
230
+ toast.error("Failed to fetch profile image. Please try uploading manually.");
231
+ setIsSaving(false);
232
+ return;
233
+ }
234
+ }
235
+
236
+ // Upload to IPFS if we have a file
237
+ if (fileToUpload) {
238
+ debug("Starting upload to IPFS", fileToUpload);
239
+
240
+ // Upload to IPFS using Thirdweb
241
+ const ipfsUrl = await upload({
242
+ client,
243
+ files: [fileToUpload],
244
+ });
245
+
246
+ debug("Upload successful", ipfsUrl);
247
+
248
+ // Save avatar URL using profiles service
249
+ const user = await app.service("users").setAvatar(
250
+ {
251
+ avatar: ipfsUrl,
252
+ },
253
+ // @ts-expect-error - our typed client is expecting context even though it's set elsewhere
254
+ {},
255
+ );
256
+ // update user
257
+ // @ts-expect-error this resolved fine, look into why expect-error needed
258
+ setUser(user);
88
259
 
89
- debug("Upload successful", ipfsUrl);
90
-
91
- // Save avatar URL using profiles service
92
- setIsSaving(true);
93
- const user = await app.service("users").setAvatar(
94
- {
95
- avatar: ipfsUrl,
96
- },
97
- // @ts-expect-error - our typed client is expecting context even though it's set elsewhere
98
- {},
99
- );
100
- // update user
101
- // @ts-expect-error this resolved fine, look into why expect-error needed
102
- setUser(user);
260
+ toast.success("Looks great! Your avatar has been saved!");
261
+ }
103
262
 
104
263
  // Refresh profile to get updated avatar
105
264
  await refreshProfile();
106
265
 
107
- toast.success(
108
- hasAvatar ? "Nice look! Your avatar has been updated!" : "Looks great! Your avatar has been saved!",
109
- );
110
-
111
266
  onSetAvatar?.();
112
-
113
- // Clean up
114
- handleRemoveFile();
115
267
  } catch (error) {
116
- debug("Error uploading avatar:", error);
117
- toast.error("Failed to upload avatar. Please try again.");
268
+ debug("Error saving avatar:", error);
269
+ toast.error("Failed to save avatar. Please try again.");
118
270
  } finally {
119
- setIsUploading(false);
120
271
  setIsSaving(false);
121
272
  }
122
273
  };
123
274
 
124
- const handleFileInputClick = () => {
275
+ const handleCancel = () => {
276
+ if (viewStep === "upload") {
277
+ setViewStep("select");
278
+ handleRemovePreview();
279
+ } else {
280
+ setB3ModalContentType({
281
+ type: "manageAccount",
282
+ chain: (contentType as any)?.chain,
283
+ partnerId: partnerId,
284
+ });
285
+ }
286
+ };
287
+
288
+ const handleProfileAvatarSelect = (avatarUrl: string, profileType: string) => {
289
+ setSelectedAvatar(avatarUrl);
290
+ setSelectedProfileType(profileType);
291
+ // Convert IPFS URLs to gateway URLs so the cropper can load them
292
+ const httpUrl = getIpfsUrl(avatarUrl, 1);
293
+ // Set preview URL to the avatar so it shows in the cropper
294
+ setPreviewUrl(httpUrl);
295
+ // Clear any selected file since we're selecting from profile
296
+ setSelectedFile(null);
297
+ // Move to upload/crop view
298
+ setViewStep("upload");
299
+ };
300
+
301
+ const handleUploadImageClick = () => {
302
+ setViewStep("upload");
303
+ };
304
+
305
+ const handleOpenFilePicker = () => {
125
306
  fileInputRef.current?.click();
126
307
  };
127
308
 
128
- const isLoading = isUploading || isSaving;
309
+ const handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
310
+ e.preventDefault();
311
+ e.stopPropagation();
312
+ setIsDragging(true);
313
+ };
314
+
315
+ const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
316
+ e.preventDefault();
317
+ e.stopPropagation();
318
+ setIsDragging(false);
319
+ };
320
+
321
+ const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
322
+ e.preventDefault();
323
+ e.stopPropagation();
324
+ };
325
+
326
+ const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
327
+ e.preventDefault();
328
+ e.stopPropagation();
329
+ setIsDragging(false);
330
+
331
+ const file = e.dataTransfer.files?.[0];
332
+ if (file) {
333
+ // Validate file type
334
+ if (!file.type.startsWith("image/")) {
335
+ toast.error("Please select an image file");
336
+ return;
337
+ }
338
+
339
+ // Validate file size (max 5MB)
340
+ if (file.size > 5 * 1024 * 1024) {
341
+ toast.error("File size must be less than 5MB");
342
+ return;
343
+ }
344
+
345
+ setSelectedFile(file);
346
+ // Clear profile type selection when uploading a new file
347
+ setSelectedProfileType(null);
348
+
349
+ // Create preview URL
350
+ const url = URL.createObjectURL(file);
351
+ setPreviewUrl(url);
352
+ setSelectedAvatar(url);
353
+ }
354
+ };
355
+
356
+ const handleLinkMoreAccount = () => {
357
+ setB3ModalContentType({
358
+ type: "linkAccount",
359
+ chain: (contentType as any)?.chain,
360
+ partnerId: partnerId,
361
+ });
362
+ };
363
+
364
+ const isLoading = isSaving;
365
+
366
+ // Get profile avatars with validated URLs
367
+ const profileAvatars =
368
+ profile?.profiles
369
+ ?.filter(p => p.avatar)
370
+ .map(p => {
371
+ const rawAvatarUrl = p?.avatar || "";
372
+ const validatedUrl = validateImageUrl(rawAvatarUrl);
373
+ return {
374
+ type: p.type,
375
+ avatar: validatedUrl,
376
+ name: p.name || p.type,
377
+ };
378
+ })
379
+ .filter(p => p.avatar !== null) || []; // Filter out profiles with invalid avatars
129
380
 
130
381
  return (
131
- <div className={cn("flex flex-col items-center justify-center space-y-6 p-8", className)}>
132
- <div className="space-y-2 text-center">
133
- <h2 className="font-neue-montreal-semibold text-b3-grey text-2xl">
134
- {hasAvatar ? "Update Your Avatar" : "Set Your Avatar"}
135
- </h2>
136
- <p className="text-b3-foreground-muted font-neue-montreal-medium">
137
- Upload an image to personalize your profile
138
- </p>
139
- </div>
382
+ <div className={cn("b3-modal-avatar-editor flex w-full max-w-md flex-col bg-white", className)}>
383
+ {/* Header */}
384
+ {viewStep === "upload" && <ModalHeader title="Upload Image" />}
140
385
 
141
- {/* Current Avatar Display */}
142
- {hasAvatar && !previewUrl && (
143
- <div className="relative">
144
- <div className="border-b3-primary-blue h-32 w-32 overflow-hidden rounded-full border-4">
145
- <img src={profile.avatar} alt="Current avatar" className="h-full w-full object-cover" />
146
- </div>
147
- </div>
148
- )}
149
-
150
- {/* File Upload Area */}
151
- <div className="w-full max-w-md">
152
- {!selectedFile ? (
153
- <div
154
- onClick={handleFileInputClick}
155
- className="border-b3-line hover:border-b3-primary-blue hover:bg-b3-primary-wash/20 cursor-pointer rounded-xl border-2 border-dashed p-8 text-center transition-colors"
156
- >
157
- <Upload className="text-b3-grey mx-auto mb-4 h-12 w-12" />
158
- <p className="text-b3-grey font-neue-montreal-semibold mb-2">Click to select an image</p>
159
- <p className="text-b3-foreground-muted font-neue-montreal-medium text-sm">PNG, JPG, or GIF up to 5MB</p>
160
- </div>
161
- ) : (
162
- <div className="space-y-4">
163
- {/* Preview */}
164
- <div className="relative">
165
- <div className="border-b3-primary-blue mx-auto h-32 w-32 overflow-hidden rounded-full border-4">
166
- {previewUrl ? (
167
- <img src={previewUrl} alt="Preview" className="h-full w-full object-cover" />
386
+ {/* Content */}
387
+ <div className="flex flex-col items-center p-6">
388
+ {viewStep === "select" ? (
389
+ <>
390
+ {/* Avatar Preview */}
391
+ <div className="relative mb-6">
392
+ <div className="h-32 w-32 overflow-hidden rounded-full">
393
+ {safePreviewUrl || selectedAvatar || currentAvatar ? (
394
+ <IPFSMediaRenderer
395
+ src={safePreviewUrl || selectedAvatar || currentAvatar || ""}
396
+ alt="Avatar preview"
397
+ className="h-full w-full object-cover"
398
+ />
168
399
  ) : (
169
- <div className="bg-b3-primary-wash flex h-full w-full items-center justify-center rounded-full">
170
- <p className="text-b3-grey font-neue-montreal-semibold text-sm">No file selected</p>
171
- </div>
400
+ <div className="bg-b3-primary-wash h-full w-full" />
172
401
  )}
173
402
  </div>
174
- <button
175
- onClick={handleRemoveFile}
176
- className="bg-b3-negative absolute -right-2 -top-2 flex h-8 w-8 items-center justify-center rounded-full text-white transition-colors hover:bg-red-600"
177
- disabled={isLoading}
178
- >
179
- <X size={16} />
180
- </button>
181
403
  </div>
182
404
 
183
- {/* File Info */}
184
- <div className="space-y-1 text-center">
185
- <p className="text-b3-grey font-neue-montreal-semibold text-sm">{selectedFile.name}</p>
186
- <p className="text-b3-foreground-muted font-neue-montreal-medium text-xs">
187
- {(selectedFile.size / 1024 / 1024).toFixed(2)} MB
405
+ {/* Upload Image Button */}
406
+ <button
407
+ onClick={handleUploadImageClick}
408
+ className="font-inter mb-6 flex w-full items-center justify-center gap-2 rounded-xl border border-[#e4e4e7] bg-white px-4 py-3 text-sm font-semibold text-[#18181b] shadow-sm transition-colors hover:bg-[#f4f4f5]"
409
+ >
410
+ <Upload className="h-4 w-4" />
411
+ Upload image
412
+ </button>
413
+
414
+ {/* Select Profile Image Section */}
415
+ <div className="w-full">
416
+ <h3 className="mb-2 text-base font-semibold text-[#18181b]">Select your profile image</h3>
417
+ <p className="mb-4 text-sm font-semibold text-[#475467]">
418
+ Pick an avatar from your linked profiles, ENS or upload a new one.
188
419
  </p>
189
- </div>
190
- </div>
191
- )}
192
420
 
193
- {/* Hidden file input */}
194
- <input ref={fileInputRef} type="file" accept="image/*" onChange={handleFileSelect} className="hidden" />
195
- </div>
421
+ {/* Profile Avatars */}
422
+ <div className="mb-4 flex gap-3">
423
+ {profileAvatars.map((profileAvatar, index) => {
424
+ // Skip if avatar is null (should not happen due to filter, but TypeScript doesn't know that)
425
+ if (!profileAvatar.avatar) return null;
426
+
427
+ return (
428
+ <div
429
+ key={profileAvatar.type + "-" + index}
430
+ className="relative"
431
+ onMouseEnter={() => setHoveredProfile(profileAvatar.type)}
432
+ onMouseLeave={() => setHoveredProfile(null)}
433
+ >
434
+ <button
435
+ onClick={() => handleProfileAvatarSelect(profileAvatar.avatar || "", profileAvatar.type || "")}
436
+ className={cn(
437
+ "h-16 w-16 overflow-hidden rounded-full border-2 transition-all",
438
+ selectedProfileType === profileAvatar.type
439
+ ? "border-[#3368ef] ring-2 ring-[#3368ef]/20"
440
+ : "border-transparent hover:border-[#e4e4e7]",
441
+ )}
442
+ >
443
+ <IPFSMediaRenderer
444
+ src={profileAvatar.avatar || ""}
445
+ alt={`${profileAvatar.type} avatar`}
446
+ className="h-full w-full object-cover"
447
+ />
448
+ </button>
196
449
 
197
- {/* Action Buttons */}
198
- <div className="flex w-full max-w-md gap-3">
199
- {selectedFile && (
200
- <Button
201
- onClick={handleUpload}
202
- disabled={isLoading}
203
- className="bg-b3-primary-blue hover:bg-b3-primary-blue/90 flex-1 text-white"
204
- >
205
- {isLoading ? (
206
- <>
207
- <Loader2 className="mr-2 h-4 w-4 animate-spin" />
208
- {isUploading ? "Uploading..." : "Saving..."}
209
- </>
450
+ {/* Tooltip */}
451
+ {hoveredProfile === profileAvatar.type && (
452
+ <div className="absolute -top-10 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md bg-[#18181b] px-3 py-1.5 text-xs text-white">
453
+ {profileAvatar.name}
454
+ </div>
455
+ )}
456
+ </div>
457
+ );
458
+ })}
459
+ </div>
460
+
461
+ {/* Link More Account */}
462
+ <button
463
+ onClick={handleLinkMoreAccount}
464
+ className="b3-modal-link-more-account font-inter flex items-center gap-2 text-sm font-semibold text-[#3368ef] hover:underline"
465
+ >
466
+ <svg
467
+ width="16"
468
+ height="16"
469
+ viewBox="0 0 16 16"
470
+ fill="none"
471
+ xmlns="http://www.w3.org/2000/svg"
472
+ className="h-4 w-4"
473
+ >
474
+ <path
475
+ d="M8.75 2.75C8.75 2.33579 8.41421 2 8 2C7.58579 2 7.25 2.33579 7.25 2.75V7.25H2.75C2.33579 7.25 2 7.58579 2 8C2 8.41421 2.33579 8.75 2.75 8.75H7.25V13.25C7.25 13.6642 7.58579 14 8 14C8.41421 14 8.75 13.6642 8.75 13.25V8.75H13.25C13.6642 8.75 14 8.41421 14 8C14 7.58579 13.6642 7.25 13.25 7.25H8.75V2.75Z"
476
+ fill="currentColor"
477
+ />
478
+ </svg>
479
+ Link more accounts
480
+ </button>
481
+ </div>
482
+ </>
483
+ ) : (
484
+ <>
485
+ {/* Upload View */}
486
+ {!selectedFile && !previewUrl ? (
487
+ <div
488
+ onClick={handleOpenFilePicker}
489
+ onDragEnter={handleDragEnter}
490
+ onDragLeave={handleDragLeave}
491
+ onDragOver={handleDragOver}
492
+ onDrop={handleDrop}
493
+ className={cn(
494
+ "b3-modal-upload-view mb-6 flex w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-16 transition-colors",
495
+ isDragging
496
+ ? "border-[#3368ef] bg-[#f0f5ff]"
497
+ : "border-[#e4e4e7] hover:border-[#3368ef] hover:bg-[#f0f5ff]",
498
+ )}
499
+ >
500
+ <p className="font-inter mb-1 text-sm">
501
+ <span className="font-semibold text-[#3368ef]">Click to upload</span>
502
+ <span className="text-[#71717a]"> or drag and drop</span>
503
+ </p>
504
+ <p className="text-xs text-[#71717a]">PNG, JPG or GIF (up to 5MB)</p>
505
+ </div>
210
506
  ) : (
211
- <>
212
- <Check className="mr-2 h-4 w-4" />
213
- {hasAvatar ? "Update Avatar" : "Set Avatar"}
214
- </>
507
+ <div className="mb-6 w-full">
508
+ <div className="relative aspect-square w-full overflow-hidden rounded-xl bg-[#f4f4f5]">
509
+ {safePreviewUrl ? (
510
+ <>
511
+ <Cropper
512
+ image={safePreviewUrl}
513
+ crop={crop}
514
+ zoom={zoom}
515
+ aspect={1}
516
+ onCropChange={setCrop}
517
+ onCropComplete={onCropComplete}
518
+ onZoomChange={setZoom}
519
+ cropShape="rect"
520
+ showGrid={false}
521
+ style={{
522
+ containerStyle: {
523
+ width: "100%",
524
+ height: "100%",
525
+ backgroundColor: "#f4f4f5",
526
+ },
527
+ cropAreaStyle: {
528
+ border: "2px solid #3368ef",
529
+ borderRadius: "0px",
530
+ },
531
+ }}
532
+ />
533
+ <button
534
+ onClick={handleRemovePreview}
535
+ className="absolute right-4 top-4 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-[#51525c] text-white transition-colors hover:bg-[#71717a]"
536
+ >
537
+ <X className="h-4 w-4" />
538
+ </button>
539
+ </>
540
+ ) : (
541
+ <div className="bg-b3-primary-wash h-full w-full" />
542
+ )}
543
+ </div>
544
+ {safePreviewUrl && (
545
+ <div className="mt-4 flex items-center gap-3">
546
+ <label className="shrink-0 text-sm font-semibold text-[#475467]">Zoom</label>
547
+ <input
548
+ type="range"
549
+ min={1}
550
+ max={3}
551
+ step={0.1}
552
+ value={zoom}
553
+ onChange={e => setZoom(Number(e.target.value))}
554
+ className="flex-1 accent-[#3368ef]"
555
+ />
556
+ </div>
557
+ )}
558
+ </div>
215
559
  )}
216
- </Button>
560
+ </>
217
561
  )}
218
562
 
219
- <Button variant="outline" onClick={handleFileInputClick} disabled={isLoading} className="flex-1">
220
- <Upload className="mr-2 h-4 w-4" />
221
- {selectedFile ? "Change Image" : "Select Image"}
222
- </Button>
563
+ {/* Hidden file input */}
564
+ <input ref={fileInputRef} type="file" accept="image/*" onChange={handleFileSelect} className="hidden" />
223
565
  </div>
224
566
 
225
- {/* Help Text */}
226
- <div className="text-b3-foreground-muted font-neue-montreal-medium max-w-md text-center text-xs">
227
- <p>
228
- Your avatar will be uploaded to IPFS and stored securely. Make sure you have the rights to use this image.
229
- </p>
567
+ {/* Footer Buttons */}
568
+ <div className="font-inter flex gap-3 border-t border-[#e4e4e7] p-6 font-semibold">
569
+ <Button
570
+ onClick={handleCancel}
571
+ variant="outline"
572
+ disabled={isLoading}
573
+ className="flex-1 rounded-xl border-[#e4e4e7] text-[#18181b] hover:bg-[#f4f4f5]"
574
+ >
575
+ Cancel
576
+ </Button>
577
+ <Button
578
+ onClick={handleSaveChanges}
579
+ disabled={isLoading || (!selectedFile && !selectedProfileType)}
580
+ className="b3-modal-save-button flex-1 rounded-xl bg-[#3368ef] text-white hover:bg-[#2952cc]"
581
+ >
582
+ {isLoading ? (
583
+ <>
584
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
585
+ Saving...
586
+ </>
587
+ ) : (
588
+ "Save changes"
589
+ )}
590
+ </Button>
230
591
  </div>
231
592
  </div>
232
593
  );