@b3dotfun/sdk 0.0.64-alpha.2 → 0.0.65-test.1

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 (229) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +73 -33
  2. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +1 -1
  3. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +1 -1
  4. package/dist/cjs/anyspend/react/components/common/FeeDetailPanel.js +1 -1
  5. package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.js +2 -2
  6. package/dist/cjs/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  7. package/dist/cjs/anyspend/react/components/common/OrderHistory.js +7 -3
  8. package/dist/cjs/anyspend/react/components/common/PanelOnrampPayment.js +1 -1
  9. package/dist/cjs/anyspend/react/components/common/PointsDetailPanel.js +1 -1
  10. package/dist/cjs/anyspend/react/components/common/RecipientSelection.js +1 -1
  11. package/dist/cjs/global-account/react/components/AccountAssets/AccountAssets.js +38 -2
  12. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +139 -33
  13. package/dist/cjs/global-account/react/components/B3DynamicModal.js +25 -6
  14. package/dist/cjs/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  15. package/dist/cjs/global-account/react/components/Deposit/Deposit.js +65 -0
  16. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  17. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +113 -279
  18. package/dist/cjs/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  19. package/dist/cjs/global-account/react/components/LinkAccount/LinkNewAccount.js +331 -0
  20. package/dist/cjs/global-account/react/components/ManageAccount/AppsContent.d.ts +6 -0
  21. package/dist/cjs/global-account/react/components/ManageAccount/AppsContent.js +34 -0
  22. package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.js +2 -2
  23. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  24. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.js +23 -0
  25. package/dist/cjs/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  26. package/dist/cjs/global-account/react/components/ManageAccount/Header.js +120 -0
  27. package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  28. package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.js +43 -0
  29. package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  30. package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.js +16 -0
  31. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +24 -193
  32. package/dist/cjs/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  33. package/dist/cjs/global-account/react/components/ManageAccount/NFTContent.js +15 -0
  34. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  35. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +44 -0
  36. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  37. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +50 -0
  38. package/dist/cjs/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  39. package/dist/cjs/global-account/react/components/ManageAccount/SettingsMenuItem.js +8 -0
  40. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  41. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.js +38 -0
  42. package/dist/cjs/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  43. package/dist/cjs/global-account/react/components/ManageAccount/TokenContent.js +22 -0
  44. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.d.ts +10 -0
  45. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.js +12 -0
  46. package/dist/cjs/global-account/react/components/Send/Send.d.ts +5 -0
  47. package/dist/cjs/global-account/react/components/Send/Send.js +187 -0
  48. package/dist/cjs/global-account/react/components/icons/BellIcon.d.ts +3 -0
  49. package/dist/cjs/global-account/react/components/icons/BellIcon.js +5 -0
  50. package/dist/cjs/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  51. package/dist/cjs/global-account/react/components/icons/ChevronDownIcon.js +7 -0
  52. package/dist/cjs/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  53. package/dist/cjs/global-account/react/components/icons/CopyIcon.js +7 -0
  54. package/dist/cjs/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  55. package/dist/cjs/global-account/react/components/icons/LinkIcon.js +5 -0
  56. package/dist/cjs/global-account/react/components/icons/LockIcon.d.ts +3 -0
  57. package/dist/cjs/global-account/react/components/icons/LockIcon.js +5 -0
  58. package/dist/cjs/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  59. package/dist/cjs/global-account/react/components/icons/WalletIcon.js +7 -0
  60. package/dist/cjs/global-account/react/components/index.d.ts +4 -2
  61. package/dist/cjs/global-account/react/components/index.js +11 -4
  62. package/dist/cjs/global-account/react/components/ui/Tabs.js +2 -2
  63. package/dist/cjs/global-account/react/components/ui/dialog.js +2 -2
  64. package/dist/cjs/global-account/react/hooks/index.d.ts +1 -1
  65. package/dist/cjs/global-account/react/hooks/index.js +3 -1
  66. package/dist/cjs/global-account/react/hooks/useB3BalanceFromAddresses.js +1 -0
  67. package/dist/cjs/global-account/react/stores/index.d.ts +1 -0
  68. package/dist/cjs/global-account/react/stores/index.js +3 -1
  69. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +34 -3
  70. package/dist/cjs/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  71. package/dist/cjs/global-account/react/stores/useRecentAddressesStore.js +36 -0
  72. package/dist/cjs/global-account/react/utils/profileDisplay.d.ts +2 -0
  73. package/dist/cjs/global-account/react/utils/profileDisplay.js +2 -2
  74. package/dist/cjs/shared/constants/chains/supported.d.ts +2 -2
  75. package/dist/cjs/shared/utils/ipfs.js +1 -1
  76. package/dist/esm/anyspend/react/components/AnySpend.js +74 -34
  77. package/dist/esm/anyspend/react/components/AnySpendCustom.js +1 -1
  78. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +1 -1
  79. package/dist/esm/anyspend/react/components/common/FeeDetailPanel.js +1 -1
  80. package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.js +2 -2
  81. package/dist/esm/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  82. package/dist/esm/anyspend/react/components/common/OrderHistory.js +6 -5
  83. package/dist/esm/anyspend/react/components/common/PanelOnrampPayment.js +1 -1
  84. package/dist/esm/anyspend/react/components/common/PointsDetailPanel.js +1 -1
  85. package/dist/esm/anyspend/react/components/common/RecipientSelection.js +1 -1
  86. package/dist/esm/global-account/react/components/AccountAssets/AccountAssets.js +38 -2
  87. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +140 -34
  88. package/dist/esm/global-account/react/components/B3DynamicModal.js +25 -6
  89. package/dist/esm/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  90. package/dist/esm/global-account/react/components/Deposit/Deposit.js +59 -0
  91. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  92. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +113 -280
  93. package/dist/esm/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  94. package/dist/esm/global-account/react/components/LinkAccount/LinkNewAccount.js +325 -0
  95. package/dist/esm/global-account/react/components/ManageAccount/AppsContent.d.ts +6 -0
  96. package/dist/esm/global-account/react/components/ManageAccount/AppsContent.js +32 -0
  97. package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.js +2 -2
  98. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  99. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.js +21 -0
  100. package/dist/esm/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  101. package/dist/esm/global-account/react/components/ManageAccount/Header.js +81 -0
  102. package/dist/esm/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  103. package/dist/esm/global-account/react/components/ManageAccount/HomeActions.js +41 -0
  104. package/dist/esm/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  105. package/dist/esm/global-account/react/components/ManageAccount/HomeContent.js +10 -0
  106. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +26 -195
  107. package/dist/esm/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  108. package/dist/esm/global-account/react/components/ManageAccount/NFTContent.js +13 -0
  109. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  110. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +42 -0
  111. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  112. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +45 -0
  113. package/dist/esm/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  114. package/dist/esm/global-account/react/components/ManageAccount/SettingsMenuItem.js +6 -0
  115. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  116. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.js +36 -0
  117. package/dist/esm/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  118. package/dist/esm/global-account/react/components/ManageAccount/TokenContent.js +20 -0
  119. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.d.ts +10 -0
  120. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.js +10 -0
  121. package/dist/esm/global-account/react/components/Send/Send.d.ts +5 -0
  122. package/dist/esm/global-account/react/components/Send/Send.js +181 -0
  123. package/dist/esm/global-account/react/components/icons/BellIcon.d.ts +3 -0
  124. package/dist/esm/global-account/react/components/icons/BellIcon.js +3 -0
  125. package/dist/esm/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  126. package/dist/esm/global-account/react/components/icons/ChevronDownIcon.js +4 -0
  127. package/dist/esm/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  128. package/dist/esm/global-account/react/components/icons/CopyIcon.js +4 -0
  129. package/dist/esm/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  130. package/dist/esm/global-account/react/components/icons/LinkIcon.js +3 -0
  131. package/dist/esm/global-account/react/components/icons/LockIcon.d.ts +3 -0
  132. package/dist/esm/global-account/react/components/icons/LockIcon.js +3 -0
  133. package/dist/esm/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  134. package/dist/esm/global-account/react/components/icons/WalletIcon.js +4 -0
  135. package/dist/esm/global-account/react/components/index.d.ts +4 -2
  136. package/dist/esm/global-account/react/components/index.js +7 -2
  137. package/dist/esm/global-account/react/components/ui/Tabs.js +2 -2
  138. package/dist/esm/global-account/react/components/ui/dialog.js +2 -2
  139. package/dist/esm/global-account/react/hooks/index.d.ts +1 -1
  140. package/dist/esm/global-account/react/hooks/index.js +1 -1
  141. package/dist/esm/global-account/react/hooks/useB3BalanceFromAddresses.js +1 -0
  142. package/dist/esm/global-account/react/stores/index.d.ts +1 -0
  143. package/dist/esm/global-account/react/stores/index.js +1 -0
  144. package/dist/esm/global-account/react/stores/useModalStore.d.ts +34 -3
  145. package/dist/esm/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  146. package/dist/esm/global-account/react/stores/useRecentAddressesStore.js +33 -0
  147. package/dist/esm/global-account/react/utils/profileDisplay.d.ts +2 -0
  148. package/dist/esm/global-account/react/utils/profileDisplay.js +2 -2
  149. package/dist/esm/shared/constants/chains/supported.d.ts +2 -2
  150. package/dist/esm/shared/utils/ipfs.js +1 -1
  151. package/dist/styles/index.css +1 -1
  152. package/dist/types/anyspend/react/components/common/OrderHistory.d.ts +1 -1
  153. package/dist/types/global-account/react/components/Deposit/Deposit.d.ts +1 -0
  154. package/dist/types/global-account/react/components/LinkAccount/LinkAccount.d.ts +6 -4
  155. package/dist/types/global-account/react/components/LinkAccount/LinkNewAccount.d.ts +4 -0
  156. package/dist/types/global-account/react/components/ManageAccount/AppsContent.d.ts +6 -0
  157. package/dist/types/global-account/react/components/ManageAccount/BottomNavigation.d.ts +2 -0
  158. package/dist/types/global-account/react/components/ManageAccount/Header.d.ts +3 -0
  159. package/dist/types/global-account/react/components/ManageAccount/HomeActions.d.ts +5 -0
  160. package/dist/types/global-account/react/components/ManageAccount/HomeContent.d.ts +6 -0
  161. package/dist/types/global-account/react/components/ManageAccount/NFTContent.d.ts +2 -0
  162. package/dist/types/global-account/react/components/ManageAccount/ProfileSection.d.ts +2 -0
  163. package/dist/types/global-account/react/components/ManageAccount/SettingsContent.d.ts +7 -0
  164. package/dist/types/global-account/react/components/ManageAccount/SettingsMenuItem.d.ts +9 -0
  165. package/dist/types/global-account/react/components/ManageAccount/SettingsProfileCard.d.ts +2 -0
  166. package/dist/types/global-account/react/components/ManageAccount/TokenContent.d.ts +2 -0
  167. package/dist/types/global-account/react/components/ModalHeader/ModalHeader.d.ts +10 -0
  168. package/dist/types/global-account/react/components/Send/Send.d.ts +5 -0
  169. package/dist/types/global-account/react/components/icons/BellIcon.d.ts +3 -0
  170. package/dist/types/global-account/react/components/icons/ChevronDownIcon.d.ts +2 -0
  171. package/dist/types/global-account/react/components/icons/CopyIcon.d.ts +2 -0
  172. package/dist/types/global-account/react/components/icons/LinkIcon.d.ts +3 -0
  173. package/dist/types/global-account/react/components/icons/LockIcon.d.ts +3 -0
  174. package/dist/types/global-account/react/components/icons/WalletIcon.d.ts +2 -0
  175. package/dist/types/global-account/react/components/index.d.ts +4 -2
  176. package/dist/types/global-account/react/hooks/index.d.ts +1 -1
  177. package/dist/types/global-account/react/stores/index.d.ts +1 -0
  178. package/dist/types/global-account/react/stores/useModalStore.d.ts +34 -3
  179. package/dist/types/global-account/react/stores/useRecentAddressesStore.d.ts +25 -0
  180. package/dist/types/global-account/react/utils/profileDisplay.d.ts +2 -0
  181. package/dist/types/shared/constants/chains/supported.d.ts +2 -2
  182. package/package.json +1 -1
  183. package/src/anyspend/react/components/AnySpend.tsx +225 -167
  184. package/src/anyspend/react/components/AnySpendCustom.tsx +1 -1
  185. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +1 -1
  186. package/src/anyspend/react/components/common/FeeDetailPanel.tsx +1 -1
  187. package/src/anyspend/react/components/common/FiatPaymentMethod.tsx +2 -2
  188. package/src/anyspend/react/components/common/OrderHistory.tsx +8 -13
  189. package/src/anyspend/react/components/common/PanelOnrampPayment.tsx +1 -1
  190. package/src/anyspend/react/components/common/PointsDetailPanel.tsx +1 -1
  191. package/src/anyspend/react/components/common/RecipientSelection.tsx +1 -1
  192. package/src/global-account/react/components/AccountAssets/AccountAssets.tsx +115 -25
  193. package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +303 -126
  194. package/src/global-account/react/components/B3DynamicModal.tsx +28 -6
  195. package/src/global-account/react/components/Deposit/Deposit.tsx +211 -0
  196. package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +332 -433
  197. package/src/global-account/react/components/LinkAccount/LinkNewAccount.tsx +490 -0
  198. package/src/global-account/react/components/ManageAccount/AppsContent.tsx +79 -0
  199. package/src/global-account/react/components/ManageAccount/BalanceContent.tsx +2 -3
  200. package/src/global-account/react/components/ManageAccount/BottomNavigation.tsx +83 -0
  201. package/src/global-account/react/components/ManageAccount/Header.tsx +230 -0
  202. package/src/global-account/react/components/ManageAccount/HomeActions.tsx +118 -0
  203. package/src/global-account/react/components/ManageAccount/HomeContent.tsx +42 -0
  204. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +73 -589
  205. package/src/global-account/react/components/ManageAccount/NFTContent.tsx +24 -0
  206. package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +74 -0
  207. package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +87 -0
  208. package/src/global-account/react/components/ManageAccount/SettingsMenuItem.tsx +31 -0
  209. package/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +74 -0
  210. package/src/global-account/react/components/ManageAccount/TokenContent.tsx +41 -0
  211. package/src/global-account/react/components/ModalHeader/ModalHeader.tsx +50 -0
  212. package/src/global-account/react/components/Send/Send.tsx +585 -0
  213. package/src/global-account/react/components/icons/BellIcon.tsx +15 -0
  214. package/src/global-account/react/components/icons/ChevronDownIcon.tsx +17 -0
  215. package/src/global-account/react/components/icons/CopyIcon.tsx +22 -0
  216. package/src/global-account/react/components/icons/LinkIcon.tsx +15 -0
  217. package/src/global-account/react/components/icons/LockIcon.tsx +15 -0
  218. package/src/global-account/react/components/icons/WalletIcon.tsx +21 -0
  219. package/src/global-account/react/components/index.ts +9 -2
  220. package/src/global-account/react/components/ui/Tabs.tsx +5 -13
  221. package/src/global-account/react/components/ui/dialog.tsx +32 -14
  222. package/src/global-account/react/hooks/index.ts +3 -0
  223. package/src/global-account/react/hooks/useB3BalanceFromAddresses.ts +1 -0
  224. package/src/global-account/react/stores/index.ts +1 -0
  225. package/src/global-account/react/stores/useModalStore.ts +39 -2
  226. package/src/global-account/react/stores/useRecentAddressesStore.ts +55 -0
  227. package/src/global-account/react/utils/profileDisplay.ts +4 -2
  228. package/src/shared/utils/ipfs.ts +1 -1
  229. package/src/styles/index.css +6 -1
@@ -4,12 +4,16 @@ import app from "@b3dotfun/sdk/global-account/app";
4
4
  import { Button, useB3, useProfile } from "@b3dotfun/sdk/global-account/react";
5
5
  import { cn } from "@b3dotfun/sdk/shared/utils/cn";
6
6
  import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
7
+ import { getIpfsUrl } from "@b3dotfun/sdk/shared/utils/ipfs";
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,23 @@ 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 [hoveredProfile, setHoveredProfile] = useState<string | null>(null);
22
31
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
23
32
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
24
33
  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 setB3ModalOpen = useModalStore(state => state.setB3ModalOpen);
40
+ const contentType = useModalStore(state => state.contentType);
41
+ const { setPreference } = useProfileSettings();
28
42
 
29
43
  const account = useActiveAccount();
30
44
  const { data: profile, refetch: refreshProfile } = useProfile({
@@ -32,9 +46,11 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
32
46
  fresh: true,
33
47
  });
34
48
 
35
- // Thirdweb upload function
36
-
37
- const hasAvatar = profile?.avatar;
49
+ const currentAvatar = user?.avatar
50
+ ? getIpfsUrl(user?.avatar)
51
+ : profile?.avatar
52
+ ? getIpfsUrl(profile.avatar)
53
+ : undefined;
38
54
 
39
55
  const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
40
56
  const file = event.target.files?.[0];
@@ -56,10 +72,12 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
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);
63
81
  setSelectedFile(null);
64
82
  if (previewUrl) {
65
83
  URL.revokeObjectURL(previewUrl);
@@ -70,163 +88,322 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
70
88
  }
71
89
  };
72
90
 
73
- const handleUpload = async () => {
74
- if (!selectedFile) {
75
- toast.error("Please select an image first");
91
+ const handleSaveChanges = async () => {
92
+ if (!account?.address) {
93
+ toast.error("No account connected");
76
94
  return;
77
95
  }
78
96
 
79
- setIsUploading(true);
97
+ setIsSaving(true);
80
98
  try {
81
- debug("Starting upload to IPFS", selectedFile);
99
+ // If user uploaded a new file
100
+ if (selectedFile) {
101
+ debug("Starting upload to IPFS", selectedFile);
82
102
 
83
- // Upload to IPFS using Thirdweb
84
- const ipfsUrl = await upload({
85
- client,
86
- files: [selectedFile],
87
- });
103
+ // Upload to IPFS using Thirdweb
104
+ const ipfsUrl = await upload({
105
+ client,
106
+ files: [selectedFile],
107
+ });
108
+
109
+ debug("Upload successful", ipfsUrl);
110
+
111
+ // Save avatar URL using profiles service
112
+ const user = await app.service("users").setAvatar(
113
+ {
114
+ avatar: ipfsUrl,
115
+ },
116
+ // @ts-expect-error - our typed client is expecting context even though it's set elsewhere
117
+ {},
118
+ );
119
+ // update user
120
+ // @ts-expect-error this resolved fine, look into why expect-error needed
121
+ setUser(user);
88
122
 
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);
123
+ toast.success("Looks great! Your avatar has been saved!");
124
+ } else if (selectedAvatar && selectedAvatar !== currentAvatar) {
125
+ // User selected from existing profile avatars
126
+ // Find the profile that matches the selected avatar
127
+ const selectedProfile = profile?.profiles?.find(p => p.avatar === selectedAvatar);
128
+
129
+ if (selectedProfile && selectedProfile.type) {
130
+ debug("Setting profile preference to:", selectedProfile.type);
131
+
132
+ // Set preference for this profile type
133
+ await setPreference(account.address, selectedProfile.type, account.address, async (message: string) => {
134
+ // Sign the message using the active account
135
+ const signature = await account.signMessage({ message });
136
+ return signature;
137
+ });
138
+
139
+ toast.success("Avatar updated successfully!");
140
+ }
141
+ }
103
142
 
104
143
  // Refresh profile to get updated avatar
105
144
  await refreshProfile();
106
145
 
107
- toast.success(
108
- hasAvatar ? "Nice look! Your avatar has been updated!" : "Looks great! Your avatar has been saved!",
109
- );
110
-
111
146
  onSetAvatar?.();
112
-
113
- // Clean up
114
- handleRemoveFile();
115
147
  } catch (error) {
116
- debug("Error uploading avatar:", error);
117
- toast.error("Failed to upload avatar. Please try again.");
148
+ debug("Error saving avatar:", error);
149
+ toast.error("Failed to save avatar. Please try again.");
118
150
  } finally {
119
- setIsUploading(false);
120
151
  setIsSaving(false);
121
152
  }
122
153
  };
123
154
 
124
- const handleFileInputClick = () => {
155
+ const handleCancel = () => {
156
+ if (viewStep === "upload") {
157
+ setViewStep("select");
158
+ handleRemovePreview();
159
+ } else {
160
+ setB3ModalContentType({
161
+ type: "manageAccount",
162
+ chain: (contentType as any)?.chain,
163
+ partnerId: partnerId,
164
+ });
165
+ }
166
+ };
167
+
168
+ const handleProfileAvatarSelect = (avatarUrl: string) => {
169
+ setSelectedAvatar(avatarUrl);
170
+ };
171
+
172
+ const handleUploadImageClick = () => {
173
+ setViewStep("upload");
174
+ };
175
+
176
+ const handleOpenFilePicker = () => {
125
177
  fileInputRef.current?.click();
126
178
  };
127
179
 
180
+ const handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
181
+ e.preventDefault();
182
+ e.stopPropagation();
183
+ setIsDragging(true);
184
+ };
185
+
186
+ const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
187
+ e.preventDefault();
188
+ e.stopPropagation();
189
+ setIsDragging(false);
190
+ };
191
+
192
+ const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
193
+ e.preventDefault();
194
+ e.stopPropagation();
195
+ };
196
+
197
+ const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
198
+ e.preventDefault();
199
+ e.stopPropagation();
200
+ setIsDragging(false);
201
+
202
+ const file = e.dataTransfer.files?.[0];
203
+ if (file) {
204
+ // Validate file type
205
+ if (!file.type.startsWith("image/")) {
206
+ toast.error("Please select an image file");
207
+ return;
208
+ }
209
+
210
+ // Validate file size (max 5MB)
211
+ if (file.size > 5 * 1024 * 1024) {
212
+ toast.error("File size must be less than 5MB");
213
+ return;
214
+ }
215
+
216
+ setSelectedFile(file);
217
+
218
+ // Create preview URL
219
+ const url = URL.createObjectURL(file);
220
+ setPreviewUrl(url);
221
+ setSelectedAvatar(url);
222
+ }
223
+ };
224
+
225
+ const handleLinkMoreAccount = () => {
226
+ setB3ModalContentType({
227
+ type: "linkAccount",
228
+ chain: (contentType as any)?.chain,
229
+ partnerId: partnerId,
230
+ });
231
+ };
232
+
128
233
  const isLoading = isUploading || isSaving;
129
234
 
235
+ // Get profile avatars
236
+ const profileAvatars =
237
+ profile?.profiles
238
+ ?.filter(p => p.avatar)
239
+ .map(p => ({
240
+ type: p.type,
241
+ avatar: getIpfsUrl(p?.avatar || ""),
242
+ name: p.name || p.type,
243
+ })) || [];
244
+
130
245
  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>
246
+ <div className={cn("flex w-full max-w-md flex-col bg-white", className)}>
247
+ {/* Header */}
248
+ {viewStep === "upload" && <ModalHeader title="Upload Image" />}
140
249
 
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" />
168
- ) : (
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>
250
+ {/* Content */}
251
+ <div className="flex flex-col items-center p-6">
252
+ {viewStep === "select" ? (
253
+ <>
254
+ {/* Avatar Preview */}
255
+ <div className="relative mb-6">
256
+ <div className="h-32 w-32 overflow-hidden rounded-full">
257
+ <img
258
+ src={selectedAvatar || currentAvatar || "https://via.placeholder.com/128"}
259
+ alt="Avatar preview"
260
+ className="h-full w-full object-cover"
261
+ />
262
+ </div>
263
+ {selectedAvatar && (
264
+ <button
265
+ onClick={handleRemovePreview}
266
+ 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]"
267
+ >
268
+ <X className="h-4 w-4" />
269
+ </button>
270
+ )}
271
+ </div>
272
+
273
+ {/* Upload Image Button */}
274
+ <button
275
+ onClick={handleUploadImageClick}
276
+ 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]"
277
+ >
278
+ <Upload className="h-4 w-4" />
279
+ Upload image
280
+ </button>
281
+
282
+ {/* Select Profile Image Section */}
283
+ <div className="w-full">
284
+ <h3 className="mb-2 text-base font-semibold text-[#18181b]">Select your profile image</h3>
285
+ <p className="mb-4 text-sm font-semibold text-[#475467]">
286
+ Pick an avatar from your linked profiles, ENS or upload a new one.
287
+ </p>
288
+
289
+ {/* Profile Avatars */}
290
+ <div className="mb-4 flex gap-3">
291
+ {profileAvatars.map((profileAvatar, index) => (
292
+ <div
293
+ key={index}
294
+ className="relative"
295
+ onMouseEnter={() => setHoveredProfile(profileAvatar.type)}
296
+ onMouseLeave={() => setHoveredProfile(null)}
297
+ >
298
+ <button
299
+ onClick={() => handleProfileAvatarSelect(profileAvatar.avatar)}
300
+ className={cn(
301
+ "h-16 w-16 overflow-hidden rounded-full border-2 transition-all",
302
+ selectedAvatar === profileAvatar.avatar
303
+ ? "border-[#3368ef] ring-2 ring-[#3368ef]/20"
304
+ : "border-transparent hover:border-[#e4e4e7]",
305
+ )}
306
+ >
307
+ <img
308
+ src={profileAvatar.avatar}
309
+ alt={`${profileAvatar.type} avatar`}
310
+ className="h-full w-full object-cover"
311
+ />
312
+ </button>
313
+
314
+ {/* Tooltip */}
315
+ {hoveredProfile === profileAvatar.type && (
316
+ <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">
317
+ {profileAvatar.name}
318
+ </div>
319
+ )}
171
320
  </div>
172
- )}
321
+ ))}
173
322
  </div>
323
+
324
+ {/* Link More Account */}
174
325
  <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}
326
+ onClick={handleLinkMoreAccount}
327
+ className="font-inter flex items-center gap-2 text-sm font-semibold text-[#3368ef] hover:underline"
178
328
  >
179
- <X size={16} />
329
+ <svg
330
+ width="16"
331
+ height="16"
332
+ viewBox="0 0 16 16"
333
+ fill="none"
334
+ xmlns="http://www.w3.org/2000/svg"
335
+ className="h-4 w-4"
336
+ >
337
+ <path
338
+ 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"
339
+ fill="currentColor"
340
+ />
341
+ </svg>
342
+ Link more account
180
343
  </button>
181
344
  </div>
182
-
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
188
- </p>
189
- </div>
190
- </div>
345
+ </>
346
+ ) : (
347
+ <>
348
+ {/* Upload View */}
349
+ {!selectedFile ? (
350
+ <div
351
+ onClick={handleOpenFilePicker}
352
+ onDragEnter={handleDragEnter}
353
+ onDragLeave={handleDragLeave}
354
+ onDragOver={handleDragOver}
355
+ onDrop={handleDrop}
356
+ className={cn(
357
+ "mb-6 flex w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-16 transition-colors",
358
+ isDragging
359
+ ? "border-[#3368ef] bg-[#f0f5ff]"
360
+ : "border-[#e4e4e7] hover:border-[#3368ef] hover:bg-[#f0f5ff]",
361
+ )}
362
+ >
363
+ <p className="font-inter mb-1 text-sm">
364
+ <span className="font-semibold text-[#3368ef]">Click to upload</span>
365
+ <span className="text-[#71717a]"> or drag and drop</span>
366
+ </p>
367
+ <p className="text-xs text-[#71717a]">PNG, JPG or GIF (up to 5MB)</p>
368
+ </div>
369
+ ) : (
370
+ <div className="mb-6 w-full">
371
+ <div className="aspect-square w-full overflow-hidden rounded-xl bg-[#f4f4f5]">
372
+ <img src={previewUrl || ""} alt="Preview" className="h-full w-full object-cover" />
373
+ </div>
374
+ </div>
375
+ )}
376
+ </>
191
377
  )}
192
378
 
193
379
  {/* Hidden file input */}
194
380
  <input ref={fileInputRef} type="file" accept="image/*" onChange={handleFileSelect} className="hidden" />
195
381
  </div>
196
382
 
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
- </>
210
- ) : (
211
- <>
212
- <Check className="mr-2 h-4 w-4" />
213
- {hasAvatar ? "Update Avatar" : "Set Avatar"}
214
- </>
215
- )}
216
- </Button>
217
- )}
218
-
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"}
383
+ {/* Footer Buttons */}
384
+ <div className="font-inter flex gap-3 border-t border-[#e4e4e7] p-6 font-semibold">
385
+ <Button
386
+ onClick={handleCancel}
387
+ variant="outline"
388
+ disabled={isLoading}
389
+ className="flex-1 rounded-xl border-[#e4e4e7] text-[#18181b] hover:bg-[#f4f4f5]"
390
+ >
391
+ Cancel
392
+ </Button>
393
+ <Button
394
+ onClick={handleSaveChanges}
395
+ disabled={isLoading || !selectedAvatar}
396
+ className="flex-1 rounded-xl bg-[#3368ef] text-white hover:bg-[#2952cc]"
397
+ >
398
+ {isLoading ? (
399
+ <>
400
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
401
+ Saving...
402
+ </>
403
+ ) : (
404
+ "Save changes"
405
+ )}
222
406
  </Button>
223
- </div>
224
-
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>
230
407
  </div>
231
408
  </div>
232
409
  );
@@ -19,10 +19,13 @@ import { useEffect, useRef } from "react";
19
19
  import { useSetActiveWallet } from "thirdweb/react";
20
20
  import { AvatarEditor } from "./AvatarEditor/AvatarEditor";
21
21
  import { useB3 } from "./B3Provider/useB3";
22
+ import { Deposit } from "./Deposit/Deposit";
22
23
  import { LinkAccount } from "./LinkAccount/LinkAccount";
23
- import { ProfileEditor } from "./ProfileEditor/ProfileEditor";
24
+ import { LinkNewAccount } from "./LinkAccount/LinkNewAccount";
24
25
  import { ManageAccount } from "./ManageAccount/ManageAccount";
26
+ import { ProfileEditor } from "./ProfileEditor/ProfileEditor";
25
27
  import { RequestPermissions } from "./RequestPermissions/RequestPermissions";
28
+ import { Send } from "./Send/Send";
26
29
  import { SignInWithB3Flow } from "./SignInWithB3/SignInWithB3Flow";
27
30
  import { Dialog, DialogContent, DialogDescription, DialogTitle } from "./ui/dialog";
28
31
  import { Drawer, DrawerContent, DrawerDescription, DrawerTitle } from "./ui/drawer";
@@ -30,7 +33,10 @@ import { Drawer, DrawerContent, DrawerDescription, DrawerTitle } from "./ui/draw
30
33
  const debug = debugB3React("B3DynamicModal");
31
34
 
32
35
  export function B3DynamicModal() {
33
- const { isOpen, setB3ModalOpen, contentType, history, navigateBack } = useModalStore();
36
+ const isOpen = useModalStore(state => state.isOpen);
37
+ const setB3ModalOpen = useModalStore(state => state.setB3ModalOpen);
38
+ const contentType = useModalStore(state => state.contentType);
39
+ const navigateBack = useModalStore(state => state.navigateBack);
34
40
  const { theme } = useB3();
35
41
  const isMobile = useIsMobile();
36
42
  const prevIsOpenRef = useRef(isOpen);
@@ -64,7 +70,10 @@ export function B3DynamicModal() {
64
70
  "anySpendSignatureMint",
65
71
  "anySpendBondKit",
66
72
  "linkAccount",
73
+ "linkNewAccount",
67
74
  "avatarEditor",
75
+ "deposit",
76
+ "send",
68
77
  "profileEditor",
69
78
  ];
70
79
 
@@ -83,7 +92,7 @@ export function B3DynamicModal() {
83
92
 
84
93
  // Check if current content type is in freestyle types
85
94
  const isFreestyleType = freestyleTypes.includes(contentType?.type as string);
86
- const hideCloseButton = isFreestyleType;
95
+ const hideCloseButton = true;
87
96
 
88
97
  // Build content class using cn utility
89
98
  // eslint-disable-next-line tailwindcss/no-custom-classname
@@ -121,7 +130,7 @@ export function B3DynamicModal() {
121
130
  case "anySpendFundTournament":
122
131
  return <AnySpendTournament {...contentType} mode="modal" action="fund" />;
123
132
  case "anySpendOrderHistory":
124
- return <OrderHistory onBack={() => {}} mode="modal" />;
133
+ return <OrderHistory {...contentType} mode="modal" />;
125
134
  case "anySpendStakeB3":
126
135
  return <AnySpendStakeB3 {...contentType} mode="modal" />;
127
136
  case "anySpendStakeB3ExactIn":
@@ -138,10 +147,16 @@ export function B3DynamicModal() {
138
147
  return <AnySpendBondKit {...contentType} />;
139
148
  case "linkAccount":
140
149
  return <LinkAccount {...contentType} />;
150
+ case "linkNewAccount":
151
+ return <LinkNewAccount {...contentType} />;
141
152
  case "anySpendDepositHype":
142
153
  return <AnySpendDepositHype {...contentType} mode="modal" />;
143
154
  case "avatarEditor":
144
155
  return <AvatarEditor onSetAvatar={contentType.onSuccess} />;
156
+ case "deposit":
157
+ return <Deposit />;
158
+ case "send":
159
+ return <Send {...contentType} />;
145
160
  case "profileEditor":
146
161
  return <ProfileEditor onSuccess={contentType.onSuccess} />;
147
162
  // Add other modal types here
@@ -162,6 +177,12 @@ export function B3DynamicModal() {
162
177
  contentClass,
163
178
  "rounded-2xl bg-white shadow-xl dark:bg-gray-900",
164
179
  "border border-gray-200 dark:border-gray-800",
180
+ (contentType?.type === "manageAccount" ||
181
+ contentType?.type === "deposit" ||
182
+ contentType?.type === "send" ||
183
+ contentType?.type === "avatarEditor") &&
184
+ "p-0",
185
+ "mx-auto w-full max-w-md sm:max-w-lg", // TODO CHECK THIS
165
186
  // Remove default width classes for avatar editor and profile editor
166
187
  contentType?.type === "avatarEditor" || contentType?.type === "profileEditor"
167
188
  ? "!w-[90vw] !max-w-none" // Use !important to override default styles
@@ -171,8 +192,9 @@ export function B3DynamicModal() {
171
192
  >
172
193
  <ModalTitle className="sr-only hidden">{contentType?.type || "Modal"}</ModalTitle>
173
194
  <ModalDescription className="sr-only hidden">{contentType?.type || "Modal Body"}</ModalDescription>
195
+
174
196
  <div className={cn("no-scrollbar max-h-[90dvh] overflow-auto sm:max-h-[80dvh]")}>
175
- {history.length > 0 && contentType?.showBackButton && (
197
+ {(!hideCloseButton || contentType?.showBackButton) && (
176
198
  <button
177
199
  onClick={navigateBack}
178
200
  className="flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
@@ -193,7 +215,7 @@ export function B3DynamicModal() {
193
215
  strokeLinejoin="round"
194
216
  />
195
217
  </svg>
196
- <span className="text-sm font-medium">Back</span>
218
+ <span className="font-inter text-sm font-semibold">Back</span>
197
219
  </button>
198
220
  )}
199
221
  {renderContent()}