@b3dotfun/sdk 0.0.65-alpha.0 → 0.0.65-test.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +77 -35
  2. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +2 -2
  3. package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +1 -1
  4. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +1 -1
  5. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  6. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +5 -3
  7. package/dist/cjs/anyspend/react/components/common/FeeDetailPanel.js +1 -1
  8. package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.js +2 -2
  9. package/dist/cjs/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  10. package/dist/cjs/anyspend/react/components/common/OrderHistory.js +7 -3
  11. package/dist/cjs/anyspend/react/components/common/PanelOnrampPayment.js +1 -1
  12. package/dist/cjs/anyspend/react/components/common/PointsDetailPanel.js +1 -1
  13. package/dist/cjs/anyspend/react/components/common/RecipientSelection.js +1 -1
  14. package/dist/cjs/anyspend/react/hooks/useSigMint.d.ts +1 -1
  15. package/dist/cjs/global-account/react/components/AccountAssets/AccountAssets.js +38 -2
  16. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +184 -35
  17. package/dist/cjs/global-account/react/components/B3DynamicModal.js +23 -12
  18. package/dist/cjs/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  19. package/dist/cjs/global-account/react/components/Deposit/Deposit.js +65 -0
  20. package/dist/cjs/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  21. package/dist/cjs/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +37 -0
  22. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  23. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +113 -279
  24. package/dist/cjs/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  25. package/dist/cjs/global-account/react/components/LinkAccount/LinkNewAccount.js +331 -0
  26. package/dist/cjs/global-account/react/components/ManageAccount/AppsContent.d.ts +6 -0
  27. package/dist/cjs/global-account/react/components/ManageAccount/AppsContent.js +34 -0
  28. package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.js +6 -5
  29. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  30. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.js +23 -0
  31. package/dist/cjs/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  32. package/dist/cjs/global-account/react/components/ManageAccount/Header.js +120 -0
  33. package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  34. package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.js +43 -0
  35. package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  36. package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.js +16 -0
  37. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +24 -193
  38. package/dist/cjs/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  39. package/dist/cjs/global-account/react/components/ManageAccount/NFTContent.js +15 -0
  40. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  41. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +47 -0
  42. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  43. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +50 -0
  44. package/dist/cjs/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  45. package/dist/cjs/global-account/react/components/ManageAccount/SettingsMenuItem.js +8 -0
  46. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  47. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.js +106 -0
  48. package/dist/cjs/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  49. package/dist/cjs/global-account/react/components/ManageAccount/TokenContent.js +22 -0
  50. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.d.ts +10 -0
  51. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.js +12 -0
  52. package/dist/cjs/global-account/react/components/Send/Send.d.ts +5 -0
  53. package/dist/cjs/global-account/react/components/Send/Send.js +187 -0
  54. package/dist/cjs/global-account/react/components/SignInWithB3/SignIn.js +3 -1
  55. package/dist/cjs/global-account/react/components/icons/BellIcon.d.ts +3 -0
  56. package/dist/cjs/global-account/react/components/icons/BellIcon.js +5 -0
  57. package/dist/cjs/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  58. package/dist/cjs/global-account/react/components/icons/ChevronDownIcon.js +7 -0
  59. package/dist/cjs/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  60. package/dist/cjs/global-account/react/components/icons/CopyIcon.js +7 -0
  61. package/dist/cjs/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  62. package/dist/cjs/global-account/react/components/icons/LinkIcon.js +5 -0
  63. package/dist/cjs/global-account/react/components/icons/LockIcon.d.ts +3 -0
  64. package/dist/cjs/global-account/react/components/icons/LockIcon.js +5 -0
  65. package/dist/cjs/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  66. package/dist/cjs/global-account/react/components/icons/WalletIcon.js +7 -0
  67. package/dist/cjs/global-account/react/components/index.d.ts +5 -4
  68. package/dist/cjs/global-account/react/components/index.js +14 -9
  69. package/dist/cjs/global-account/react/components/ui/Tabs.js +2 -2
  70. package/dist/cjs/global-account/react/components/ui/dialog.js +2 -2
  71. package/dist/cjs/global-account/react/hooks/index.d.ts +1 -1
  72. package/dist/cjs/global-account/react/hooks/index.js +3 -1
  73. package/dist/cjs/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  74. package/dist/cjs/global-account/react/hooks/useAccountWallet.js +18 -0
  75. package/dist/cjs/global-account/react/hooks/useAuthentication.d.ts +2 -2
  76. package/dist/cjs/global-account/react/hooks/useB3BalanceFromAddresses.js +1 -0
  77. package/dist/cjs/global-account/react/hooks/useUserQuery.d.ts +2 -2
  78. package/dist/cjs/global-account/react/stores/index.d.ts +1 -0
  79. package/dist/cjs/global-account/react/stores/index.js +3 -1
  80. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +31 -6
  81. package/dist/cjs/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  82. package/dist/cjs/global-account/react/stores/useRecentAddressesStore.js +36 -0
  83. package/dist/cjs/global-account/react/utils/profileDisplay.d.ts +2 -0
  84. package/dist/cjs/global-account/react/utils/profileDisplay.js +2 -2
  85. package/dist/cjs/shared/constants/chains/supported.d.ts +3 -3
  86. package/dist/cjs/shared/utils/ipfs.js +10 -3
  87. package/dist/esm/anyspend/react/components/AnySpend.js +78 -36
  88. package/dist/esm/anyspend/react/components/AnySpendCustom.js +2 -2
  89. package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +1 -1
  90. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +1 -1
  91. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  92. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +5 -3
  93. package/dist/esm/anyspend/react/components/common/FeeDetailPanel.js +1 -1
  94. package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.js +2 -2
  95. package/dist/esm/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  96. package/dist/esm/anyspend/react/components/common/OrderHistory.js +6 -5
  97. package/dist/esm/anyspend/react/components/common/PanelOnrampPayment.js +1 -1
  98. package/dist/esm/anyspend/react/components/common/PointsDetailPanel.js +1 -1
  99. package/dist/esm/anyspend/react/components/common/RecipientSelection.js +1 -1
  100. package/dist/esm/anyspend/react/hooks/useSigMint.d.ts +1 -1
  101. package/dist/esm/global-account/react/components/AccountAssets/AccountAssets.js +38 -2
  102. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +186 -37
  103. package/dist/esm/global-account/react/components/B3DynamicModal.js +23 -12
  104. package/dist/esm/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  105. package/dist/esm/global-account/react/components/Deposit/Deposit.js +59 -0
  106. package/dist/esm/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  107. package/dist/esm/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +34 -0
  108. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  109. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +113 -280
  110. package/dist/esm/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  111. package/dist/esm/global-account/react/components/LinkAccount/LinkNewAccount.js +325 -0
  112. package/dist/esm/global-account/react/components/ManageAccount/AppsContent.d.ts +6 -0
  113. package/dist/esm/global-account/react/components/ManageAccount/AppsContent.js +32 -0
  114. package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.js +6 -5
  115. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  116. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.js +21 -0
  117. package/dist/esm/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  118. package/dist/esm/global-account/react/components/ManageAccount/Header.js +81 -0
  119. package/dist/esm/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  120. package/dist/esm/global-account/react/components/ManageAccount/HomeActions.js +41 -0
  121. package/dist/esm/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  122. package/dist/esm/global-account/react/components/ManageAccount/HomeContent.js +10 -0
  123. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +26 -195
  124. package/dist/esm/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  125. package/dist/esm/global-account/react/components/ManageAccount/NFTContent.js +13 -0
  126. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  127. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +45 -0
  128. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  129. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +45 -0
  130. package/dist/esm/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  131. package/dist/esm/global-account/react/components/ManageAccount/SettingsMenuItem.js +6 -0
  132. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  133. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.js +101 -0
  134. package/dist/esm/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  135. package/dist/esm/global-account/react/components/ManageAccount/TokenContent.js +20 -0
  136. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.d.ts +10 -0
  137. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.js +10 -0
  138. package/dist/esm/global-account/react/components/Send/Send.d.ts +5 -0
  139. package/dist/esm/global-account/react/components/Send/Send.js +181 -0
  140. package/dist/esm/global-account/react/components/SignInWithB3/SignIn.js +4 -2
  141. package/dist/esm/global-account/react/components/icons/BellIcon.d.ts +3 -0
  142. package/dist/esm/global-account/react/components/icons/BellIcon.js +3 -0
  143. package/dist/esm/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  144. package/dist/esm/global-account/react/components/icons/ChevronDownIcon.js +4 -0
  145. package/dist/esm/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  146. package/dist/esm/global-account/react/components/icons/CopyIcon.js +4 -0
  147. package/dist/esm/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  148. package/dist/esm/global-account/react/components/icons/LinkIcon.js +3 -0
  149. package/dist/esm/global-account/react/components/icons/LockIcon.d.ts +3 -0
  150. package/dist/esm/global-account/react/components/icons/LockIcon.js +3 -0
  151. package/dist/esm/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  152. package/dist/esm/global-account/react/components/icons/WalletIcon.js +4 -0
  153. package/dist/esm/global-account/react/components/index.d.ts +5 -4
  154. package/dist/esm/global-account/react/components/index.js +9 -5
  155. package/dist/esm/global-account/react/components/ui/Tabs.js +2 -2
  156. package/dist/esm/global-account/react/components/ui/dialog.js +2 -2
  157. package/dist/esm/global-account/react/hooks/index.d.ts +1 -1
  158. package/dist/esm/global-account/react/hooks/index.js +1 -1
  159. package/dist/esm/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  160. package/dist/esm/global-account/react/hooks/useAccountWallet.js +17 -0
  161. package/dist/esm/global-account/react/hooks/useAuthentication.d.ts +2 -2
  162. package/dist/esm/global-account/react/hooks/useB3BalanceFromAddresses.js +1 -0
  163. package/dist/esm/global-account/react/hooks/useUserQuery.d.ts +2 -2
  164. package/dist/esm/global-account/react/stores/index.d.ts +1 -0
  165. package/dist/esm/global-account/react/stores/index.js +1 -0
  166. package/dist/esm/global-account/react/stores/useModalStore.d.ts +31 -6
  167. package/dist/esm/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  168. package/dist/esm/global-account/react/stores/useRecentAddressesStore.js +33 -0
  169. package/dist/esm/global-account/react/utils/profileDisplay.d.ts +2 -0
  170. package/dist/esm/global-account/react/utils/profileDisplay.js +2 -2
  171. package/dist/esm/shared/constants/chains/supported.d.ts +3 -3
  172. package/dist/esm/shared/utils/ipfs.js +10 -3
  173. package/dist/styles/index.css +1 -1
  174. package/dist/types/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  175. package/dist/types/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  176. package/dist/types/anyspend/react/hooks/useSigMint.d.ts +1 -1
  177. package/dist/types/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  178. package/dist/types/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  179. package/dist/types/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  180. package/dist/types/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  181. package/dist/types/global-account/react/components/ManageAccount/AppsContent.d.ts +6 -0
  182. package/dist/types/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  183. package/dist/types/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  184. package/dist/types/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  185. package/dist/types/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  186. package/dist/types/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  187. package/dist/types/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  188. package/dist/types/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  189. package/dist/types/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  190. package/dist/types/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  191. package/dist/types/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  192. package/dist/types/global-account/react/components/ModalHeader/ModalHeader.d.ts +10 -0
  193. package/dist/types/global-account/react/components/Send/Send.d.ts +5 -0
  194. package/dist/types/global-account/react/components/icons/BellIcon.d.ts +3 -0
  195. package/dist/types/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  196. package/dist/types/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  197. package/dist/types/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  198. package/dist/types/global-account/react/components/icons/LockIcon.d.ts +3 -0
  199. package/dist/types/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  200. package/dist/types/global-account/react/components/index.d.ts +5 -4
  201. package/dist/types/global-account/react/hooks/index.d.ts +1 -1
  202. package/dist/types/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  203. package/dist/types/global-account/react/hooks/useAuthentication.d.ts +2 -2
  204. package/dist/types/global-account/react/hooks/useUserQuery.d.ts +2 -2
  205. package/dist/types/global-account/react/stores/index.d.ts +1 -0
  206. package/dist/types/global-account/react/stores/useModalStore.d.ts +31 -6
  207. package/dist/types/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  208. package/dist/types/global-account/react/utils/profileDisplay.d.ts +2 -0
  209. package/dist/types/shared/constants/chains/supported.d.ts +3 -3
  210. package/package.json +1 -1
  211. package/src/anyspend/react/components/AnySpend.tsx +229 -170
  212. package/src/anyspend/react/components/AnySpendCustom.tsx +1 -3
  213. package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +0 -2
  214. package/src/anyspend/react/components/AnyspendDepositHype.tsx +0 -2
  215. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +7 -14
  216. package/src/anyspend/react/components/common/FeeDetailPanel.tsx +1 -1
  217. package/src/anyspend/react/components/common/FiatPaymentMethod.tsx +2 -2
  218. package/src/anyspend/react/components/common/OrderHistory.tsx +8 -13
  219. package/src/anyspend/react/components/common/PanelOnrampPayment.tsx +1 -1
  220. package/src/anyspend/react/components/common/PointsDetailPanel.tsx +1 -1
  221. package/src/anyspend/react/components/common/RecipientSelection.tsx +1 -1
  222. package/src/global-account/react/components/AccountAssets/AccountAssets.tsx +115 -25
  223. package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +360 -128
  224. package/src/global-account/react/components/B3DynamicModal.tsx +28 -14
  225. package/src/global-account/react/components/Deposit/Deposit.tsx +211 -0
  226. package/src/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.tsx +84 -0
  227. package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +332 -433
  228. package/src/global-account/react/components/LinkAccount/LinkNewAccount.tsx +490 -0
  229. package/src/global-account/react/components/ManageAccount/AppsContent.tsx +79 -0
  230. package/src/global-account/react/components/ManageAccount/BalanceContent.tsx +6 -10
  231. package/src/global-account/react/components/ManageAccount/BottomNavigation.tsx +83 -0
  232. package/src/global-account/react/components/ManageAccount/Header.tsx +230 -0
  233. package/src/global-account/react/components/ManageAccount/HomeActions.tsx +118 -0
  234. package/src/global-account/react/components/ManageAccount/HomeContent.tsx +42 -0
  235. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +73 -589
  236. package/src/global-account/react/components/ManageAccount/NFTContent.tsx +24 -0
  237. package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +72 -0
  238. package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +87 -0
  239. package/src/global-account/react/components/ManageAccount/SettingsMenuItem.tsx +31 -0
  240. package/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +180 -0
  241. package/src/global-account/react/components/ManageAccount/TokenContent.tsx +41 -0
  242. package/src/global-account/react/components/ModalHeader/ModalHeader.tsx +50 -0
  243. package/src/global-account/react/components/Send/Send.tsx +585 -0
  244. package/src/global-account/react/components/SignInWithB3/SignIn.tsx +11 -7
  245. package/src/global-account/react/components/icons/BellIcon.tsx +15 -0
  246. package/src/global-account/react/components/icons/ChevronDownIcon.tsx +17 -0
  247. package/src/global-account/react/components/icons/CopyIcon.tsx +22 -0
  248. package/src/global-account/react/components/icons/LinkIcon.tsx +15 -0
  249. package/src/global-account/react/components/icons/LockIcon.tsx +15 -0
  250. package/src/global-account/react/components/icons/WalletIcon.tsx +21 -0
  251. package/src/global-account/react/components/index.ts +11 -5
  252. package/src/global-account/react/components/ui/Tabs.tsx +5 -13
  253. package/src/global-account/react/components/ui/dialog.tsx +32 -14
  254. package/src/global-account/react/hooks/index.ts +3 -0
  255. package/src/global-account/react/hooks/useAccountWallet.tsx +26 -0
  256. package/src/global-account/react/hooks/useB3BalanceFromAddresses.ts +1 -0
  257. package/src/global-account/react/stores/index.ts +1 -0
  258. package/src/global-account/react/stores/useModalStore.ts +35 -6
  259. package/src/global-account/react/stores/useRecentAddressesStore.ts +55 -0
  260. package/src/global-account/react/utils/profileDisplay.ts +4 -2
  261. package/src/shared/utils/ipfs.ts +10 -3
  262. package/src/styles/index.css +6 -1
  263. package/dist/cjs/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  264. package/dist/cjs/global-account/react/components/ProfileEditor/ProfileEditor.js +0 -141
  265. package/dist/esm/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  266. package/dist/esm/global-account/react/components/ProfileEditor/ProfileEditor.js +0 -135
  267. package/dist/types/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  268. package/src/global-account/react/components/ProfileEditor/ProfileEditor.tsx +0 -265
@@ -1,15 +1,19 @@
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, 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";
7
8
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
8
- import { Check, Loader2, Upload, X } from "lucide-react";
9
+ import { Loader2, Upload, X } from "lucide-react";
9
10
  import { useRef, useState } from "react";
10
11
  import { toast } from "sonner";
11
12
  import { useActiveAccount } from "thirdweb/react";
12
13
  import { upload } from "thirdweb/storage";
14
+ import { useProfileSettings } from "../../hooks/useProfile";
15
+ import { useModalStore } from "../../stores";
16
+ import ModalHeader from "../ModalHeader/ModalHeader";
13
17
 
14
18
  const debug = debugB3React("AvatarEditor");
15
19
 
@@ -18,13 +22,22 @@ interface AvatarEditorProps {
18
22
  className?: string;
19
23
  }
20
24
 
25
+ type ViewStep = "select" | "upload";
26
+
21
27
  export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
28
+ const [viewStep, setViewStep] = useState<ViewStep>("select");
29
+ const [selectedAvatar, setSelectedAvatar] = useState<string | null>(null);
30
+ const [selectedProfileType, setSelectedProfileType] = useState<string | null>(null); // Track which profile was selected
31
+ const [hoveredProfile, setHoveredProfile] = useState<string | null>(null);
22
32
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
23
33
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
24
- const [isUploading, setIsUploading] = useState(false);
25
34
  const [isSaving, setIsSaving] = useState(false);
35
+ const [isDragging, setIsDragging] = useState(false);
26
36
  const fileInputRef = useRef<HTMLInputElement>(null);
27
- const { setUser } = useB3();
37
+ const { setUser, user, partnerId } = useB3();
38
+ const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
39
+ const contentType = useModalStore(state => state.contentType);
40
+ const { setPreference } = useProfileSettings();
28
41
 
29
42
  const account = useActiveAccount();
30
43
  const { data: profile, refetch: refreshProfile } = useProfile({
@@ -32,9 +45,10 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
32
45
  fresh: true,
33
46
  });
34
47
 
35
- // Thirdweb upload function
36
-
37
- const hasAvatar = profile?.avatar;
48
+ // Get raw avatar URLs, convert IPFS URLs, and validate them
49
+ const rawCurrentAvatar = user?.avatar || profile?.avatar;
50
+ const currentAvatar = validateImageUrl(rawCurrentAvatar);
51
+ const safePreviewUrl = validateImageUrl(previewUrl);
38
52
 
39
53
  const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
40
54
  const file = event.target.files?.[0];
@@ -52,14 +66,19 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
52
66
  }
53
67
 
54
68
  setSelectedFile(file);
69
+ // Clear profile type selection when uploading a new file
70
+ setSelectedProfileType(null);
55
71
 
56
72
  // Create preview URL
57
73
  const url = URL.createObjectURL(file);
58
74
  setPreviewUrl(url);
75
+ setSelectedAvatar(url);
59
76
  }
60
77
  };
61
78
 
62
- const handleRemoveFile = () => {
79
+ const handleRemovePreview = () => {
80
+ setSelectedAvatar(currentAvatar || null);
81
+ setSelectedProfileType(null);
63
82
  setSelectedFile(null);
64
83
  if (previewUrl) {
65
84
  URL.revokeObjectURL(previewUrl);
@@ -70,163 +89,376 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
70
89
  }
71
90
  };
72
91
 
73
- const handleUpload = async () => {
74
- if (!selectedFile) {
75
- toast.error("Please select an image first");
92
+ const handleSaveChanges = async () => {
93
+ if (!account?.address) {
94
+ toast.error("No account connected");
76
95
  return;
77
96
  }
78
97
 
79
- setIsUploading(true);
98
+ setIsSaving(true);
80
99
  try {
81
- debug("Starting upload to IPFS", selectedFile);
100
+ let fileToUpload: File | null = null;
82
101
 
83
- // Upload to IPFS using Thirdweb
84
- const ipfsUrl = await upload({
85
- client,
86
- files: [selectedFile],
87
- });
102
+ // If user uploaded a new file
103
+ if (selectedFile) {
104
+ fileToUpload = selectedFile;
105
+ } else if (selectedProfileType && selectedAvatar) {
106
+ // User selected from existing profile avatars
107
+ // Fetch the image from the URL and convert to blob
108
+ debug("Fetching image from social profile:", selectedAvatar);
109
+
110
+ try {
111
+ const response = await fetch(selectedAvatar);
112
+ if (!response.ok) {
113
+ throw new Error("Failed to fetch image");
114
+ }
115
+
116
+ const blob = await response.blob();
117
+ debug("Fetched blob with type:", blob.type);
118
+
119
+ // Determine the correct extension from the blob's MIME type
120
+ // This handles URLs without extensions (like Farcaster images)
121
+ const mimeToExtension: Record<string, string> = {
122
+ "image/jpeg": "jpg",
123
+ "image/jpg": "jpg",
124
+ "image/png": "png",
125
+ "image/gif": "gif",
126
+ "image/webp": "webp",
127
+ "image/svg+xml": "svg",
128
+ };
129
+
130
+ const extension = blob.type ? mimeToExtension[blob.type.toLowerCase()] || "jpg" : "jpg";
131
+ const mimeType = blob.type || `image/${extension}`;
132
+
133
+ fileToUpload = new File([blob], `avatar-${selectedProfileType}.${extension}`, { type: mimeType });
134
+
135
+ debug("Successfully converted social profile image to file with extension:", extension);
136
+ } catch (fetchError) {
137
+ debug("Error fetching social profile image:", fetchError);
138
+ toast.error("Failed to fetch profile image. Please try uploading manually.");
139
+ setIsSaving(false);
140
+ return;
141
+ }
142
+ }
143
+
144
+ // Upload to IPFS if we have a file
145
+ if (fileToUpload) {
146
+ debug("Starting upload to IPFS", fileToUpload);
147
+
148
+ // Upload to IPFS using Thirdweb
149
+ const ipfsUrl = await upload({
150
+ client,
151
+ files: [fileToUpload],
152
+ });
88
153
 
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);
154
+ debug("Upload successful", ipfsUrl);
155
+
156
+ // Save avatar URL using profiles service
157
+ const user = await app.service("users").setAvatar(
158
+ {
159
+ avatar: ipfsUrl,
160
+ },
161
+ // @ts-expect-error - our typed client is expecting context even though it's set elsewhere
162
+ {},
163
+ );
164
+ // update user
165
+ // @ts-expect-error this resolved fine, look into why expect-error needed
166
+ setUser(user);
167
+
168
+ toast.success("Looks great! Your avatar has been saved!");
169
+ }
103
170
 
104
171
  // Refresh profile to get updated avatar
105
172
  await refreshProfile();
106
173
 
107
- toast.success(
108
- hasAvatar ? "Nice look! Your avatar has been updated!" : "Looks great! Your avatar has been saved!",
109
- );
110
-
111
174
  onSetAvatar?.();
112
-
113
- // Clean up
114
- handleRemoveFile();
115
175
  } catch (error) {
116
- debug("Error uploading avatar:", error);
117
- toast.error("Failed to upload avatar. Please try again.");
176
+ debug("Error saving avatar:", error);
177
+ toast.error("Failed to save avatar. Please try again.");
118
178
  } finally {
119
- setIsUploading(false);
120
179
  setIsSaving(false);
121
180
  }
122
181
  };
123
182
 
124
- const handleFileInputClick = () => {
183
+ const handleCancel = () => {
184
+ if (viewStep === "upload") {
185
+ setViewStep("select");
186
+ handleRemovePreview();
187
+ } else {
188
+ setB3ModalContentType({
189
+ type: "manageAccount",
190
+ chain: (contentType as any)?.chain,
191
+ partnerId: partnerId,
192
+ });
193
+ }
194
+ };
195
+
196
+ const handleProfileAvatarSelect = (avatarUrl: string, profileType: string) => {
197
+ setSelectedAvatar(avatarUrl);
198
+ setSelectedProfileType(profileType);
199
+ // Clear any selected file since we're selecting from profile
200
+ setSelectedFile(null);
201
+ if (previewUrl) {
202
+ URL.revokeObjectURL(previewUrl);
203
+ setPreviewUrl(null);
204
+ }
205
+ };
206
+
207
+ const handleUploadImageClick = () => {
208
+ setViewStep("upload");
209
+ };
210
+
211
+ const handleOpenFilePicker = () => {
125
212
  fileInputRef.current?.click();
126
213
  };
127
214
 
128
- const isLoading = isUploading || isSaving;
215
+ const handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
216
+ e.preventDefault();
217
+ e.stopPropagation();
218
+ setIsDragging(true);
219
+ };
220
+
221
+ const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
222
+ e.preventDefault();
223
+ e.stopPropagation();
224
+ setIsDragging(false);
225
+ };
226
+
227
+ const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
228
+ e.preventDefault();
229
+ e.stopPropagation();
230
+ };
231
+
232
+ const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
233
+ e.preventDefault();
234
+ e.stopPropagation();
235
+ setIsDragging(false);
236
+
237
+ const file = e.dataTransfer.files?.[0];
238
+ if (file) {
239
+ // Validate file type
240
+ if (!file.type.startsWith("image/")) {
241
+ toast.error("Please select an image file");
242
+ return;
243
+ }
244
+
245
+ // Validate file size (max 5MB)
246
+ if (file.size > 5 * 1024 * 1024) {
247
+ toast.error("File size must be less than 5MB");
248
+ return;
249
+ }
250
+
251
+ setSelectedFile(file);
252
+ // Clear profile type selection when uploading a new file
253
+ setSelectedProfileType(null);
254
+
255
+ // Create preview URL
256
+ const url = URL.createObjectURL(file);
257
+ setPreviewUrl(url);
258
+ setSelectedAvatar(url);
259
+ }
260
+ };
261
+
262
+ const handleLinkMoreAccount = () => {
263
+ setB3ModalContentType({
264
+ type: "linkAccount",
265
+ chain: (contentType as any)?.chain,
266
+ partnerId: partnerId,
267
+ });
268
+ };
269
+
270
+ const isLoading = isSaving;
271
+
272
+ // Get profile avatars with validated URLs
273
+ const profileAvatars =
274
+ profile?.profiles
275
+ ?.filter(p => p.avatar)
276
+ .map(p => {
277
+ const rawAvatarUrl = p?.avatar || "";
278
+ const validatedUrl = validateImageUrl(rawAvatarUrl);
279
+ return {
280
+ type: p.type,
281
+ avatar: validatedUrl,
282
+ name: p.name || p.type,
283
+ };
284
+ })
285
+ .filter(p => p.avatar !== null) || []; // Filter out profiles with invalid avatars
129
286
 
130
287
  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>
288
+ <div className={cn("flex w-full max-w-md flex-col bg-white", className)}>
289
+ {/* Header */}
290
+ {viewStep === "upload" && <ModalHeader title="Upload Image" />}
140
291
 
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" />
292
+ {/* Content */}
293
+ <div className="flex flex-col items-center p-6">
294
+ {viewStep === "select" ? (
295
+ <>
296
+ {/* Avatar Preview */}
297
+ <div className="relative mb-6">
298
+ <div className="h-32 w-32 overflow-hidden rounded-full">
299
+ {safePreviewUrl || selectedAvatar || currentAvatar ? (
300
+ <IPFSMediaRenderer
301
+ src={safePreviewUrl || selectedAvatar || currentAvatar || ""}
302
+ alt="Avatar preview"
303
+ className="h-full w-full object-cover"
304
+ />
168
305
  ) : (
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>
306
+ <div className="bg-b3-primary-wash h-full w-full" />
172
307
  )}
173
308
  </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>
309
+ {(selectedAvatar !== currentAvatar || selectedFile) && (
310
+ <button
311
+ onClick={handleRemovePreview}
312
+ className="absolute -right-1 -top-1 flex h-8 w-8 items-center justify-center rounded-full bg-[#51525c] text-white transition-colors hover:bg-[#71717a]"
313
+ >
314
+ <X className="h-4 w-4" />
315
+ </button>
316
+ )}
181
317
  </div>
182
318
 
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
319
+ {/* Upload Image Button */}
320
+ <button
321
+ onClick={handleUploadImageClick}
322
+ className="font-inter shadow-xs 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] transition-colors hover:bg-[#f4f4f5]"
323
+ >
324
+ <Upload className="h-4 w-4" />
325
+ Upload image
326
+ </button>
327
+
328
+ {/* Select Profile Image Section */}
329
+ <div className="w-full">
330
+ <h3 className="mb-2 text-base font-semibold text-[#18181b]">Select your profile image</h3>
331
+ <p className="mb-4 text-sm font-semibold text-[#475467]">
332
+ Pick an avatar from your linked profiles, ENS or upload a new one.
188
333
  </p>
189
- </div>
190
- </div>
191
- )}
192
334
 
193
- {/* Hidden file input */}
194
- <input ref={fileInputRef} type="file" accept="image/*" onChange={handleFileSelect} className="hidden" />
195
- </div>
335
+ {/* Profile Avatars */}
336
+ <div className="mb-4 flex gap-3">
337
+ {profileAvatars.map((profileAvatar, index) => {
338
+ // Skip if avatar is null (should not happen due to filter, but TypeScript doesn't know that)
339
+ if (!profileAvatar.avatar) return null;
340
+
341
+ return (
342
+ <div
343
+ key={index}
344
+ className="relative"
345
+ onMouseEnter={() => setHoveredProfile(profileAvatar.type)}
346
+ onMouseLeave={() => setHoveredProfile(null)}
347
+ >
348
+ <button
349
+ onClick={() => handleProfileAvatarSelect(profileAvatar.avatar || "", profileAvatar.type || "")}
350
+ className={cn(
351
+ "h-16 w-16 overflow-hidden rounded-full border-2 transition-all",
352
+ selectedProfileType === profileAvatar.type
353
+ ? "border-[#3368ef] ring-2 ring-[#3368ef]/20"
354
+ : "border-transparent hover:border-[#e4e4e7]",
355
+ )}
356
+ >
357
+ <img
358
+ src={profileAvatar.avatar}
359
+ alt={`${profileAvatar.type} avatar`}
360
+ className="h-full w-full object-cover"
361
+ />
362
+ </button>
196
363
 
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
- </>
364
+ {/* Tooltip */}
365
+ {hoveredProfile === profileAvatar.type && (
366
+ <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">
367
+ {profileAvatar.name}
368
+ </div>
369
+ )}
370
+ </div>
371
+ );
372
+ })}
373
+ </div>
374
+
375
+ {/* Link More Account */}
376
+ <button
377
+ onClick={handleLinkMoreAccount}
378
+ className="font-inter flex items-center gap-2 text-sm font-semibold text-[#3368ef] hover:underline"
379
+ >
380
+ <svg
381
+ width="16"
382
+ height="16"
383
+ viewBox="0 0 16 16"
384
+ fill="none"
385
+ xmlns="http://www.w3.org/2000/svg"
386
+ className="h-4 w-4"
387
+ >
388
+ <path
389
+ 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"
390
+ fill="currentColor"
391
+ />
392
+ </svg>
393
+ Link more account
394
+ </button>
395
+ </div>
396
+ </>
397
+ ) : (
398
+ <>
399
+ {/* Upload View */}
400
+ {!selectedFile ? (
401
+ <div
402
+ onClick={handleOpenFilePicker}
403
+ onDragEnter={handleDragEnter}
404
+ onDragLeave={handleDragLeave}
405
+ onDragOver={handleDragOver}
406
+ onDrop={handleDrop}
407
+ className={cn(
408
+ "mb-6 flex w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-16 transition-colors",
409
+ isDragging
410
+ ? "border-[#3368ef] bg-[#f0f5ff]"
411
+ : "border-[#e4e4e7] hover:border-[#3368ef] hover:bg-[#f0f5ff]",
412
+ )}
413
+ >
414
+ <p className="font-inter mb-1 text-sm">
415
+ <span className="font-semibold text-[#3368ef]">Click to upload</span>
416
+ <span className="text-[#71717a]"> or drag and drop</span>
417
+ </p>
418
+ <p className="text-xs text-[#71717a]">PNG, JPG or GIF (up to 5MB)</p>
419
+ </div>
210
420
  ) : (
211
- <>
212
- <Check className="mr-2 h-4 w-4" />
213
- {hasAvatar ? "Update Avatar" : "Set Avatar"}
214
- </>
421
+ <div className="mb-6 w-full">
422
+ <div className="aspect-square w-full overflow-hidden rounded-xl bg-[#f4f4f5]">
423
+ {safePreviewUrl ? (
424
+ <img src={safePreviewUrl} alt="Preview" className="h-full w-full object-cover" />
425
+ ) : (
426
+ <div className="bg-b3-primary-wash h-full w-full" />
427
+ )}
428
+ </div>
429
+ </div>
215
430
  )}
216
- </Button>
431
+ </>
217
432
  )}
218
433
 
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>
434
+ {/* Hidden file input */}
435
+ <input ref={fileInputRef} type="file" accept="image/*" onChange={handleFileSelect} className="hidden" />
223
436
  </div>
224
437
 
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>
438
+ {/* Footer Buttons */}
439
+ <div className="font-inter flex gap-3 border-t border-[#e4e4e7] p-6 font-semibold">
440
+ <Button
441
+ onClick={handleCancel}
442
+ variant="outline"
443
+ disabled={isLoading}
444
+ className="flex-1 rounded-xl border-[#e4e4e7] text-[#18181b] hover:bg-[#f4f4f5]"
445
+ >
446
+ Cancel
447
+ </Button>
448
+ <Button
449
+ onClick={handleSaveChanges}
450
+ disabled={isLoading || (!selectedFile && !selectedProfileType)}
451
+ className="flex-1 rounded-xl bg-[#3368ef] text-white hover:bg-[#2952cc]"
452
+ >
453
+ {isLoading ? (
454
+ <>
455
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
456
+ Saving...
457
+ </>
458
+ ) : (
459
+ "Save changes"
460
+ )}
461
+ </Button>
230
462
  </div>
231
463
  </div>
232
464
  );