@b3dotfun/sdk 0.1.69-alpha.25 → 0.1.69-alpha.26

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 (25) hide show
  1. package/dist/cjs/global-account/react/components/ManageAccount/Header.js +2 -3
  2. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +6 -0
  3. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +1 -1
  4. package/dist/cjs/global-account/react/components/SignInWithB3/SignIn.js +3 -3
  5. package/dist/cjs/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
  6. package/dist/cjs/global-account/react/components/UserAvatar/UserAvatar.js +27 -0
  7. package/dist/cjs/global-account/react/components/index.d.ts +1 -0
  8. package/dist/cjs/global-account/react/components/index.js +6 -3
  9. package/dist/esm/global-account/react/components/ManageAccount/Header.js +2 -3
  10. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +7 -1
  11. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +2 -2
  12. package/dist/esm/global-account/react/components/SignInWithB3/SignIn.js +4 -4
  13. package/dist/esm/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
  14. package/dist/esm/global-account/react/components/UserAvatar/UserAvatar.js +21 -0
  15. package/dist/esm/global-account/react/components/index.d.ts +1 -0
  16. package/dist/esm/global-account/react/components/index.js +2 -0
  17. package/dist/types/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
  18. package/dist/types/global-account/react/components/index.d.ts +1 -0
  19. package/package.json +1 -1
  20. package/src/global-account/react/components/ManageAccount/Header.tsx +2 -5
  21. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +13 -0
  22. package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +5 -26
  23. package/src/global-account/react/components/SignInWithB3/SignIn.tsx +4 -4
  24. package/src/global-account/react/components/UserAvatar/UserAvatar.tsx +45 -0
  25. package/src/global-account/react/components/index.ts +3 -0
@@ -39,13 +39,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.Header = Header;
40
40
  const jsx_runtime_1 = require("react/jsx-runtime");
41
41
  const react_1 = require("../../../../global-account/react");
42
- const constants_1 = require("../../../../shared/constants");
43
42
  const AccordionPrimitive = __importStar(require("@radix-ui/react-accordion"));
44
43
  const framer_motion_1 = require("framer-motion");
45
- const boring_avatars_1 = __importDefault(require("boring-avatars"));
46
44
  const lucide_react_1 = require("lucide-react");
47
45
  const react_2 = require("react");
48
46
  const react_3 = require("thirdweb/react");
47
+ const UserAvatar_1 = require("../UserAvatar/UserAvatar");
49
48
  const ChevronDownIcon_1 = require("../icons/ChevronDownIcon");
50
49
  const LinkIcon_1 = __importDefault(require("../icons/LinkIcon"));
51
50
  const SignOutIcon_1 = __importDefault(require("../icons/SignOutIcon"));
@@ -98,7 +97,7 @@ function BetterAuthHeader({ onLogout }) {
98
97
  setLogoutLoading(false);
99
98
  }
100
99
  };
101
- return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-background border-b3-line flex items-center justify-between border-b px-5 py-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "size-10 shrink-0 overflow-hidden rounded-full", children: (0, jsx_runtime_1.jsx)(boring_avatars_1.default, { name: displayName, variant: "beam", size: 40, colors: constants_1.AVATAR_COLORS }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-0.5", children: [user?.username && ((0, jsx_runtime_1.jsx)("p", { className: "text-b3-grey font-neue-montreal-semibold text-left text-sm", children: user.username })), user?.email && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: user.email }), (0, jsx_runtime_1.jsx)(react_1.CopyToClipboard, { text: user.email })] }))] })] }), (0, jsx_runtime_1.jsxs)("button", { className: "border-b3-line hover:bg-b3-line flex items-center justify-center gap-1.5 rounded-xl border border-solid px-3 py-2 transition-colors", onClick: onLogoutEnhanced, disabled: logoutLoading, children: [logoutLoading ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin", size: 16 })) : ((0, jsx_runtime_1.jsx)(SignOutIcon_1.default, { size: 16, className: "text-b3-grey" })), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-grey font-neue-montreal-semibold text-sm", children: "Sign out" })] })] }));
100
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-background border-b3-line flex items-center justify-between border-b px-5 py-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(UserAvatar_1.UserAvatar, { avatarUrl: user?.avatar, name: displayName, size: 40, className: "shrink-0" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-0.5", children: [user?.username && ((0, jsx_runtime_1.jsx)("p", { className: "text-b3-grey font-neue-montreal-semibold text-left text-sm", children: user.username })), user?.email && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: user.email }), (0, jsx_runtime_1.jsx)(react_1.CopyToClipboard, { text: user.email })] }))] })] }), (0, jsx_runtime_1.jsxs)("button", { className: "border-b3-line hover:bg-b3-line flex items-center justify-center gap-1.5 rounded-xl border border-solid px-3 py-2 transition-colors", onClick: onLogoutEnhanced, disabled: logoutLoading, children: [logoutLoading ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin", size: 16 })) : ((0, jsx_runtime_1.jsx)(SignOutIcon_1.default, { size: 16, className: "text-b3-grey" })), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-grey font-neue-montreal-semibold text-sm", children: "Sign out" })] })] }));
102
101
  }
103
102
  function Header({ onLogout }) {
104
103
  const { authStrategy } = (0, react_1.useB3Config)();
@@ -10,9 +10,15 @@ const BottomNavigation_1 = __importDefault(require("./BottomNavigation"));
10
10
  const HomeContent_1 = require("./HomeContent");
11
11
  const SettingsContent_1 = __importDefault(require("./SettingsContent"));
12
12
  function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain, partnerId, showSwap, showDeposit, }) {
13
+ const { authStrategy } = (0, react_1.useB3Config)();
14
+ const isBetterAuth = authStrategy === "better-auth";
13
15
  const contentType = (0, react_1.useModalStore)(state => state.contentType);
14
16
  const { activeTab = "home", setActiveTab } = contentType;
15
17
  const setB3ModalContentType = (0, react_1.useModalStore)(state => state.setB3ModalContentType);
18
+ // Better Auth: single-view layout — no Home/Swap tabs, just settings content
19
+ if (isBetterAuth) {
20
+ return ((0, jsx_runtime_1.jsx)("div", { className: "b3-manage-account flex-1", children: (0, jsx_runtime_1.jsx)(SettingsContent_1.default, { partnerId: partnerId, onLogout: onLogout, chain: chain }) }));
21
+ }
16
22
  return ((0, jsx_runtime_1.jsx)("div", { className: "b3-manage-account flex-1", children: (0, jsx_runtime_1.jsxs)(react_1.TabsPrimitive, { defaultValue: activeTab, onValueChange: value => {
17
23
  const tab = value;
18
24
  if (tab === "swap") {
@@ -52,7 +52,7 @@ const SettingsContent = ({ partnerId, onLogout, chain, }) => {
52
52
  setB3ModalOpen(false);
53
53
  setLogoutLoading(false);
54
54
  };
55
- return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-[470px] flex-col", children: [(0, jsx_runtime_1.jsx)(ModalHeader_1.default, { showBackButton: false, showCloseButton: false, title: "Settings" }), (0, jsx_runtime_1.jsx)("div", { className: "p-5", children: (0, jsx_runtime_1.jsx)("div", { className: "b3-modal-settings-profile-card dark:border-b3-line dark:bg-b3-background flex items-center rounded-xl border border-[#e4e4e7] bg-[#f4f4f5] p-4", children: (0, jsx_runtime_1.jsx)(SettingsProfileCard_1.default, {}) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3 px-5", children: [!isBetterAuth && ((0, jsx_runtime_1.jsx)(SettingsMenuItem_1.default, { icon: (0, jsx_runtime_1.jsx)("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: (0, jsx_runtime_1.jsx)("path", { d: "M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z", fill: "#F4F4F5" }) }), title: "Linked Accounts", subtitle: `${profiles.length} connected account${profiles.length > 1 ? "s" : ""}`, onClick: () => handleNavigate("linkAccount") })), (0, jsx_runtime_1.jsx)(SettingsMenuItem_1.default, { icon: (0, jsx_runtime_1.jsx)("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: (0, jsx_runtime_1.jsx)("path", { d: "M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z", fill: "#F4F4F5" }) }), title: "Notifications", subtitle: "Manage your notifications", onClick: () => handleNavigate("notifications") }), (0, jsx_runtime_1.jsx)(SettingsMenuItem_1.default, { icon: (0, jsx_runtime_1.jsx)("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: (0, jsx_runtime_1.jsx)("path", { d: "M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z", fill: "#F4F4F5" }) }), title: "Stay signed in", subtitle: session_duration_1.SESSION_DURATION_LABELS[sessionDays] ?? `${sessionDays} days`, onClick: () => handleNavigate("sessionDuration") })] }), (0, jsx_runtime_1.jsx)("div", { className: "mt-auto px-5 pb-5", children: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "b3-modal-sign-out-button border-b3-line hover:bg-b3-line bg-b3-background dark:bg-b3-background dark:border-b3-line dark:hover:bg-b3-line/80 flex w-full items-center justify-center gap-1.5 rounded-xl border border-solid p-3 transition-colors", onClick: onLogoutEnhanced, disabled: logoutLoading, style: {
55
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-[470px] flex-col", children: [!isBetterAuth && (0, jsx_runtime_1.jsx)(ModalHeader_1.default, { showBackButton: false, showCloseButton: false, title: "Settings" }), (0, jsx_runtime_1.jsx)("div", { className: "p-5", children: (0, jsx_runtime_1.jsx)("div", { className: "b3-modal-settings-profile-card dark:border-b3-line dark:bg-b3-background flex items-center rounded-xl border border-[#e4e4e7] bg-[#f4f4f5] p-4", children: (0, jsx_runtime_1.jsx)(SettingsProfileCard_1.default, {}) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3 px-5", children: [!isBetterAuth && ((0, jsx_runtime_1.jsx)(SettingsMenuItem_1.default, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Link, { size: 18, className: "text-[#51525c]" }), title: "Linked Accounts", subtitle: `${profiles.length} connected account${profiles.length > 1 ? "s" : ""}`, onClick: () => handleNavigate("linkAccount") })), (0, jsx_runtime_1.jsx)(SettingsMenuItem_1.default, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Bell, { size: 18, className: "text-[#51525c]" }), title: "Notifications", subtitle: "Manage your notifications", onClick: () => handleNavigate("notifications") }), (0, jsx_runtime_1.jsx)(SettingsMenuItem_1.default, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Clock, { size: 18, className: "text-[#51525c]" }), title: "Stay signed in", subtitle: session_duration_1.SESSION_DURATION_LABELS[sessionDays] ?? `${sessionDays} days`, onClick: () => handleNavigate("sessionDuration") })] }), (0, jsx_runtime_1.jsx)("div", { className: "mt-auto px-5 pb-5", children: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "b3-modal-sign-out-button border-b3-line hover:bg-b3-line bg-b3-background dark:bg-b3-background dark:border-b3-line dark:hover:bg-b3-line/80 flex w-full items-center justify-center gap-1.5 rounded-xl border border-solid p-3 transition-colors", onClick: onLogoutEnhanced, disabled: logoutLoading, style: {
56
56
  boxShadow: "inset 0px 0px 0px 1px rgba(10,13,18,0.18), inset 0px -2px 0px 0px rgba(10,13,18,0.05)",
57
57
  }, children: [logoutLoading ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-grey animate-spin", size: 20 })) : ((0, jsx_runtime_1.jsx)(SignOutIcon_1.default, { size: 20, className: "text-b3-grey", color: "currentColor" })), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-grey dark:text-b3-foreground-muted font-neue-montreal-semibold text-base", children: "Sign out" })] }) })] }));
58
58
  };
@@ -10,10 +10,10 @@ const Icon_1 = __importDefault(require("../../../../global-account/react/compone
10
10
  const constants_1 = require("../../../../shared/constants");
11
11
  const utils_1 = require("../../../../shared/utils");
12
12
  const react_2 = require("@headlessui/react");
13
- const boring_avatars_1 = __importDefault(require("boring-avatars"));
14
13
  const react_3 = require("react");
15
14
  const react_4 = require("thirdweb/react");
16
15
  const useUser_1 = require("../../hooks/useUser");
16
+ const UserAvatar_1 = require("../UserAvatar/UserAvatar");
17
17
  const ManageAccountButton_1 = require("../custom/ManageAccountButton");
18
18
  function SignIn(props) {
19
19
  const { className } = props;
@@ -49,11 +49,11 @@ function SignIn(props) {
49
49
  }, [connectedEOAWallet, isActiveEOAWallet, setActiveWallet, automaticallySetFirstEoa]);
50
50
  const isLoggedIn = isBetterAuth ? isAuthenticated : !!globalAddress;
51
51
  // Desktop version - original dropdown menu
52
- return ((0, jsx_runtime_1.jsx)(react_1.StyleRoot, { children: (0, jsx_runtime_1.jsx)(react_2.Menu, { className: `relative flex items-center ${className || ""}`, as: "div", children: isLoggedIn ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_2.MenuButton, { className: "bg-b3-react-background group flex h-10 items-center gap-1 rounded-xl px-3 focus:outline-none", children: [isBetterAuth ? ((0, jsx_runtime_1.jsx)(boring_avatars_1.default, { name: userDisplayName, variant: "beam", size: 24, colors: constants_1.AVATAR_COLORS })) : (!!walletImage && ((0, jsx_runtime_1.jsx)(react_1.IPFSMediaRenderer, { src: walletImage, alt: "Wallet Image", className: "bg-b3-react-primary h-6 w-6 rounded-full object-cover opacity-100" }))), (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary", children: isBetterAuth ? userDisplayName : ensName ? ensName : (0, utils_1.truncateAddress)(globalAddress ?? "") })] }), (0, jsx_runtime_1.jsx)(react_2.Transition, { enter: "duration-200 ease-out", enterFrom: "scale-95 opacity-0", enterTo: "scale-100 opacity-100", leave: "duration-300 ease-out", leaveFrom: "scale-100 opacity-100", leaveTo: "scale-95 opacity-0", children: (0, jsx_runtime_1.jsx)(react_2.MenuItems, { className: "b3-root absolute -right-4 top-full min-w-64 rounded-2xl border focus:outline-none lg:right-0", modal: false,
52
+ return ((0, jsx_runtime_1.jsx)(react_1.StyleRoot, { children: (0, jsx_runtime_1.jsx)(react_2.Menu, { className: `relative flex items-center ${className || ""}`, as: "div", children: isLoggedIn ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_2.MenuButton, { className: "bg-b3-react-background group flex h-10 items-center gap-1 rounded-xl px-3 focus:outline-none", children: [isBetterAuth ? ((0, jsx_runtime_1.jsx)(UserAvatar_1.UserAvatar, { avatarUrl: user?.avatar, name: userDisplayName, size: 24 })) : (!!walletImage && ((0, jsx_runtime_1.jsx)(react_1.IPFSMediaRenderer, { src: walletImage, alt: "Wallet Image", className: "bg-b3-react-primary h-6 w-6 rounded-full object-cover opacity-100" }))), (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary", children: isBetterAuth ? userDisplayName : ensName ? ensName : (0, utils_1.truncateAddress)(globalAddress ?? "") })] }), (0, jsx_runtime_1.jsx)(react_2.Transition, { enter: "duration-200 ease-out", enterFrom: "scale-95 opacity-0", enterTo: "scale-100 opacity-100", leave: "duration-300 ease-out", leaveFrom: "scale-100 opacity-100", leaveTo: "scale-95 opacity-0", children: (0, jsx_runtime_1.jsx)(react_2.MenuItems, { className: "b3-root absolute -right-4 top-full min-w-64 rounded-2xl border focus:outline-none lg:right-0", modal: false,
53
53
  // TODO: Figure out why setting anchor on mobile causes z-index issues where it appears under elements
54
54
  anchor: isMobile ? "top end" : undefined, children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-react-background", children: [isBetterAuth ? (
55
55
  /* Better Auth: show user info instead of wallet switching */
56
- (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3 rounded-xl p-3", children: [(0, jsx_runtime_1.jsx)(boring_avatars_1.default, { name: userDisplayName, variant: "beam", size: 48, colors: constants_1.AVATAR_COLORS }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-0.5", children: [user?.username && (0, jsx_runtime_1.jsx)("div", { className: "text-b3-react-primary font-semibold", children: user.username }), user?.email && (0, jsx_runtime_1.jsx)("div", { className: "text-b3-react-secondary text-sm", children: user.email })] })] })) : connectedEOAWallet ? ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("border-b3-react-subtle bg-b3-react-background flex cursor-pointer items-center justify-between rounded-xl p-3"), onClick: () => handleSetActiveAccount(connectedEOAWallet?.id), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center", children: [(0, jsx_runtime_1.jsx)("img", { className: "bg-b3-react-primary h-16 w-16 rounded-full opacity-100", src: walletImage, alt: connectedEOAWallet?.id }), (0, jsx_runtime_1.jsxs)("div", { className: "ml-4 grow", children: [ensName && (0, jsx_runtime_1.jsx)("div", { children: ensName }), (0, jsx_runtime_1.jsx)("div", { children: (0, utils_1.truncateAddress)(globalAddress ?? "") })] })] }), isActiveEOAWallet && (0, jsx_runtime_1.jsx)(Icon_1.default, { className: "fill-b3-react-primary", name: "check" })] })) : (connectedSmartWallet && ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("mb-2 flex cursor-pointer items-center justify-between rounded-xl p-3", isActiveSmartWallet
56
+ (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3 rounded-xl p-3", children: [(0, jsx_runtime_1.jsx)(UserAvatar_1.UserAvatar, { avatarUrl: user?.avatar, name: userDisplayName, size: 48 }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-0.5", children: [user?.username && (0, jsx_runtime_1.jsx)("div", { className: "text-b3-react-primary font-semibold", children: user.username }), user?.email && (0, jsx_runtime_1.jsx)("div", { className: "text-b3-react-secondary text-sm", children: user.email })] })] })) : connectedEOAWallet ? ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("border-b3-react-subtle bg-b3-react-background flex cursor-pointer items-center justify-between rounded-xl p-3"), onClick: () => handleSetActiveAccount(connectedEOAWallet?.id), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center", children: [(0, jsx_runtime_1.jsx)("img", { className: "bg-b3-react-primary h-16 w-16 rounded-full opacity-100", src: walletImage, alt: connectedEOAWallet?.id }), (0, jsx_runtime_1.jsxs)("div", { className: "ml-4 grow", children: [ensName && (0, jsx_runtime_1.jsx)("div", { children: ensName }), (0, jsx_runtime_1.jsx)("div", { children: (0, utils_1.truncateAddress)(globalAddress ?? "") })] })] }), isActiveEOAWallet && (0, jsx_runtime_1.jsx)(Icon_1.default, { className: "fill-b3-react-primary", name: "check" })] })) : (connectedSmartWallet && ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("mb-2 flex cursor-pointer items-center justify-between rounded-xl p-3", isActiveSmartWallet
57
57
  ? "bg-b3-react-background"
58
58
  : "bg-b3-react-background hover:bg-b3-react-background"), onClick: () => handleSetActiveAccount(connectedSmartWallet?.id), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center", children: [(0, jsx_runtime_1.jsx)("img", { className: "bg-b3-react-primary h-16 w-16 rounded-full opacity-100", src: smartWalletIcon, alt: connectedSmartWallet?.id }), (0, jsx_runtime_1.jsxs)("div", { className: "grow pl-4", children: [ensName && (0, jsx_runtime_1.jsx)("div", { children: ensName }), (0, jsx_runtime_1.jsx)("div", { children: (0, utils_1.truncateAddress)(globalAddress ?? "") }), (0, jsx_runtime_1.jsx)("div", { children: "Smart wallet" })] })] }), isActiveSmartWallet && (0, jsx_runtime_1.jsx)(Icon_1.default, { className: "fill-b3-react-primary", name: "check" })] }))), (0, jsx_runtime_1.jsx)("div", { className: "ml-3", children: (0, jsx_runtime_1.jsx)(ManageAccountButton_1.ManageAccountButton, { ...props, className: "w-[calc(100%-12px)]" }) }), (0, jsx_runtime_1.jsx)("button", { className: "mb-2 w-full space-y-1", onClick: onDisconnect, children: (0, jsx_runtime_1.jsxs)("div", { className: "hover:bg-b3-react-background group flex h-12 items-center rounded-xl px-4 transition-colors", children: [(0, jsx_runtime_1.jsx)(Icon_1.default, { className: "fill-b3-react-primary mr-4 shrink-0 transition-colors", name: "logout" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-react-primary mr-auto transition-colors", children: isBetterAuth ? "Sign out" : "Disconnect" })] }) })] }) }) })] })) : ((0, jsx_runtime_1.jsx)(react_1.SignInWithB3, { closeAfterLogin: true, onLoginSuccess: async (globalAccount) => {
59
59
  console.log("User authenticated with Global Account!", globalAccount);
@@ -0,0 +1,18 @@
1
+ interface UserAvatarProps {
2
+ /** Direct avatar URL (IPFS or HTTP). Resolved and validated internally. */
3
+ avatarUrl?: string | null;
4
+ /** Seed for the generated fallback avatar + alt text. Use email, username, or address. */
5
+ name?: string;
6
+ /** Avatar size in pixels (square). */
7
+ size?: number;
8
+ /** Additional className for the outer container. */
9
+ className?: string;
10
+ }
11
+ /**
12
+ * Renders a user avatar with IPFS support and boring-avatars fallback.
13
+ *
14
+ * - If `avatarUrl` is provided and valid, renders via IPFSMediaRenderer.
15
+ * - On load failure or missing URL, falls back to a deterministic boring-avatars beam.
16
+ */
17
+ export declare function UserAvatar({ avatarUrl, name, size, className }: UserAvatarProps): import("react/jsx-runtime").JSX.Element;
18
+ export {};
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UserAvatar = UserAvatar;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const profileDisplay_1 = require("../../../../global-account/react/utils/profileDisplay");
9
+ const constants_1 = require("../../../../shared/constants");
10
+ const boring_avatars_1 = __importDefault(require("boring-avatars"));
11
+ const react_1 = require("react");
12
+ const IPFSMediaRenderer_1 = require("../IPFSMediaRenderer/IPFSMediaRenderer");
13
+ /**
14
+ * Renders a user avatar with IPFS support and boring-avatars fallback.
15
+ *
16
+ * - If `avatarUrl` is provided and valid, renders via IPFSMediaRenderer.
17
+ * - On load failure or missing URL, falls back to a deterministic boring-avatars beam.
18
+ */
19
+ function UserAvatar({ avatarUrl, name = "user", size = 40, className }) {
20
+ const resolvedSrc = (0, profileDisplay_1.validateImageUrl)(avatarUrl);
21
+ const [imgError, setImgError] = (0, react_1.useState)(false);
22
+ (0, react_1.useEffect)(() => {
23
+ setImgError(false);
24
+ }, [avatarUrl]);
25
+ const handleImgError = (0, react_1.useCallback)(() => setImgError(true), []);
26
+ return ((0, jsx_runtime_1.jsx)("div", { className: className, style: { width: size, height: size, minWidth: size, minHeight: size }, children: resolvedSrc && !imgError ? ((0, jsx_runtime_1.jsx)("div", { onErrorCapture: handleImgError, className: "h-full w-full overflow-hidden rounded-full", children: (0, jsx_runtime_1.jsx)(IPFSMediaRenderer_1.IPFSMediaRenderer, { src: resolvedSrc, alt: name, className: "h-full w-full object-cover" }) })) : ((0, jsx_runtime_1.jsx)(boring_avatars_1.default, { name: name, variant: "beam", size: size, colors: constants_1.AVATAR_COLORS })) }));
27
+ }
@@ -18,6 +18,7 @@ export { SignInWithB3Privy } from "./SignInWithB3/SignInWithB3Privy";
18
18
  export { LoginStepContainer } from "./SignInWithB3/steps/LoginStep";
19
19
  export { getConnectOptionsFromStrategy, isWalletType, type AllowedStrategy } from "./SignInWithB3/utils/signInUtils";
20
20
  export { ManageAccount } from "./ManageAccount/ManageAccount";
21
+ export { UserAvatar } from "./UserAvatar/UserAvatar";
21
22
  export { Deposit } from "./Deposit/Deposit";
22
23
  export { Send } from "./Send/Send";
23
24
  export { IPFSMediaRenderer } from "./IPFSMediaRenderer/IPFSMediaRenderer";
@@ -3,9 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Dialog = exports.CommandShortcut = exports.CommandSeparator = exports.CommandList = exports.CommandItem = exports.CommandInput = exports.CommandGroup = exports.CommandEmpty = exports.CommandDialog = exports.Command = exports.buttonVariants = exports.Button = exports.badgeVariants = exports.Badge = exports.WalletConnectorIcon = exports.StaggeredFadeLoader = exports.CopyToClipboard = exports.ClientOnly = exports.customButtonVariants = exports.CustomButton = exports.SingleUserSearchSelector = exports.SendERC20Button = exports.SendETHButton = exports.MintButton = exports.AccountAssets = exports.RequestPermissionsButton = exports.RequestPermissions = exports.IPFSMediaRenderer = exports.Send = exports.Deposit = exports.ManageAccount = exports.isWalletType = exports.getConnectOptionsFromStrategy = exports.LoginStepContainer = exports.SignInWithB3Privy = exports.SignInWithB3Flow = exports.SignInWithB3 = exports.WalletRow = exports.PermissionItem = exports.AuthButton = exports.BetterAuthVerifyEmail = exports.BetterAuthSignIn = exports.BetterAuthResetPassword = exports.StyleRoot = exports.useB3Config = exports.useB3Account = exports.useB3 = exports.RelayKitProviderWrapper = exports.B3Provider = exports.B3DynamicModal = void 0;
7
- exports.TooltipTrigger = exports.TooltipProvider = exports.TooltipContent = exports.Tooltip = exports.TextShimmer = exports.TextLoop = exports.TabTrigger = exports.TabsTransitionWrapper = exports.TabsList = exports.TabsContent = exports.Tabs = exports.TabTriggerPrimitive = exports.TabsPrimitive = exports.TabsListPrimitive = exports.TabsContentPrimitive = exports.Skeleton = exports.ShinyButton = exports.ScrollBar = exports.ScrollArea = exports.PopoverTrigger = exports.PopoverContent = exports.Popover = exports.Loading = exports.Input = exports.GlareCardRounded = exports.GlareCard = exports.DropdownMenuTrigger = exports.DropdownMenuSeparator = exports.DropdownMenuItem = exports.DropdownMenuContent = exports.DropdownMenu = exports.DrawerTrigger = exports.DrawerTitle = exports.DrawerPortal = exports.DrawerOverlay = exports.DrawerHeader = exports.DrawerFooter = exports.DrawerDescription = exports.DrawerContent = exports.DrawerClose = exports.Drawer = exports.DialogTrigger = exports.DialogTitle = exports.DialogPortal = exports.DialogOverlay = exports.DialogHeader = exports.DialogFooter = exports.DialogDescription = exports.DialogContent = exports.DialogClose = void 0;
8
- exports.WalletImage = exports.useToastContext = exports.ToastProvider = exports.ToastContainer = exports.Toast = exports.toast = exports.AnimatedLottie = exports.TransitionPanel = void 0;
6
+ exports.CommandShortcut = exports.CommandSeparator = exports.CommandList = exports.CommandItem = exports.CommandInput = exports.CommandGroup = exports.CommandEmpty = exports.CommandDialog = exports.Command = exports.buttonVariants = exports.Button = exports.badgeVariants = exports.Badge = exports.WalletConnectorIcon = exports.StaggeredFadeLoader = exports.CopyToClipboard = exports.ClientOnly = exports.customButtonVariants = exports.CustomButton = exports.SingleUserSearchSelector = exports.SendERC20Button = exports.SendETHButton = exports.MintButton = exports.AccountAssets = exports.RequestPermissionsButton = exports.RequestPermissions = exports.IPFSMediaRenderer = exports.Send = exports.Deposit = exports.UserAvatar = exports.ManageAccount = exports.isWalletType = exports.getConnectOptionsFromStrategy = exports.LoginStepContainer = exports.SignInWithB3Privy = exports.SignInWithB3Flow = exports.SignInWithB3 = exports.WalletRow = exports.PermissionItem = exports.AuthButton = exports.BetterAuthVerifyEmail = exports.BetterAuthSignIn = exports.BetterAuthResetPassword = exports.StyleRoot = exports.useB3Config = exports.useB3Account = exports.useB3 = exports.RelayKitProviderWrapper = exports.B3Provider = exports.B3DynamicModal = void 0;
7
+ exports.TooltipProvider = exports.TooltipContent = exports.Tooltip = exports.TextShimmer = exports.TextLoop = exports.TabTrigger = exports.TabsTransitionWrapper = exports.TabsList = exports.TabsContent = exports.Tabs = exports.TabTriggerPrimitive = exports.TabsPrimitive = exports.TabsListPrimitive = exports.TabsContentPrimitive = exports.Skeleton = exports.ShinyButton = exports.ScrollBar = exports.ScrollArea = exports.PopoverTrigger = exports.PopoverContent = exports.Popover = exports.Loading = exports.Input = exports.GlareCardRounded = exports.GlareCard = exports.DropdownMenuTrigger = exports.DropdownMenuSeparator = exports.DropdownMenuItem = exports.DropdownMenuContent = exports.DropdownMenu = exports.DrawerTrigger = exports.DrawerTitle = exports.DrawerPortal = exports.DrawerOverlay = exports.DrawerHeader = exports.DrawerFooter = exports.DrawerDescription = exports.DrawerContent = exports.DrawerClose = exports.Drawer = exports.DialogTrigger = exports.DialogTitle = exports.DialogPortal = exports.DialogOverlay = exports.DialogHeader = exports.DialogFooter = exports.DialogDescription = exports.DialogContent = exports.DialogClose = exports.Dialog = void 0;
8
+ exports.WalletImage = exports.useToastContext = exports.ToastProvider = exports.ToastContainer = exports.Toast = exports.toast = exports.AnimatedLottie = exports.TransitionPanel = exports.TooltipTrigger = void 0;
9
9
  // TODO woj: Barrel file for all components, this might be reason of bundle size issues
10
10
  // Core Components
11
11
  var B3DynamicModal_1 = require("./B3DynamicModal");
@@ -49,6 +49,9 @@ Object.defineProperty(exports, "isWalletType", { enumerable: true, get: function
49
49
  // ManageAccount Components
50
50
  var ManageAccount_1 = require("./ManageAccount/ManageAccount");
51
51
  Object.defineProperty(exports, "ManageAccount", { enumerable: true, get: function () { return ManageAccount_1.ManageAccount; } });
52
+ // UserAvatar
53
+ var UserAvatar_1 = require("./UserAvatar/UserAvatar");
54
+ Object.defineProperty(exports, "UserAvatar", { enumerable: true, get: function () { return UserAvatar_1.UserAvatar; } });
52
55
  // Deposit Components
53
56
  var Deposit_1 = require("./Deposit/Deposit");
54
57
  Object.defineProperty(exports, "Deposit", { enumerable: true, get: function () { return Deposit_1.Deposit; } });
@@ -1,12 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { CopyToClipboard, useAuthentication, useB3Config, useModalStore, } from "../../../../global-account/react/index.js";
3
- import { AVATAR_COLORS } from "../../../../shared/constants/index.js";
4
3
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
5
4
  import { AnimatePresence, motion } from "framer-motion";
6
- import Avatar from "boring-avatars";
7
5
  import { Loader2 } from "lucide-react";
8
6
  import { useState } from "react";
9
7
  import { useActiveWallet, useConnectedWallets, useSetActiveWallet, useWalletImage } from "thirdweb/react";
8
+ import { UserAvatar } from "../UserAvatar/UserAvatar.js";
10
9
  import { ChevronDownIcon } from "../icons/ChevronDownIcon.js";
11
10
  import LinkIcon from "../icons/LinkIcon.js";
12
11
  import SignOutIcon from "../icons/SignOutIcon.js";
@@ -59,7 +58,7 @@ function BetterAuthHeader({ onLogout }) {
59
58
  setLogoutLoading(false);
60
59
  }
61
60
  };
62
- return (_jsxs("div", { className: "bg-b3-background border-b3-line flex items-center justify-between border-b px-5 py-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "size-10 shrink-0 overflow-hidden rounded-full", children: _jsx(Avatar, { name: displayName, variant: "beam", size: 40, colors: AVATAR_COLORS }) }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [user?.username && (_jsx("p", { className: "text-b3-grey font-neue-montreal-semibold text-left text-sm", children: user.username })), user?.email && (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: user.email }), _jsx(CopyToClipboard, { text: user.email })] }))] })] }), _jsxs("button", { className: "border-b3-line hover:bg-b3-line flex items-center justify-center gap-1.5 rounded-xl border border-solid px-3 py-2 transition-colors", onClick: onLogoutEnhanced, disabled: logoutLoading, children: [logoutLoading ? (_jsx(Loader2, { className: "animate-spin", size: 16 })) : (_jsx(SignOutIcon, { size: 16, className: "text-b3-grey" })), _jsx("p", { className: "text-b3-grey font-neue-montreal-semibold text-sm", children: "Sign out" })] })] }));
61
+ return (_jsxs("div", { className: "bg-b3-background border-b3-line flex items-center justify-between border-b px-5 py-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(UserAvatar, { avatarUrl: user?.avatar, name: displayName, size: 40, className: "shrink-0" }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [user?.username && (_jsx("p", { className: "text-b3-grey font-neue-montreal-semibold text-left text-sm", children: user.username })), user?.email && (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: user.email }), _jsx(CopyToClipboard, { text: user.email })] }))] })] }), _jsxs("button", { className: "border-b3-line hover:bg-b3-line flex items-center justify-center gap-1.5 rounded-xl border border-solid px-3 py-2 transition-colors", onClick: onLogoutEnhanced, disabled: logoutLoading, children: [logoutLoading ? (_jsx(Loader2, { className: "animate-spin", size: 16 })) : (_jsx(SignOutIcon, { size: 16, className: "text-b3-grey" })), _jsx("p", { className: "text-b3-grey font-neue-montreal-semibold text-sm", children: "Sign out" })] })] }));
63
62
  }
64
63
  export function Header({ onLogout }) {
65
64
  const { authStrategy } = useB3Config();
@@ -1,12 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { TabsContentPrimitive, TabsPrimitive, useModalStore, } from "../../../../global-account/react/index.js";
2
+ import { TabsContentPrimitive, TabsPrimitive, useB3Config, useModalStore, } from "../../../../global-account/react/index.js";
3
3
  import BottomNavigation from "./BottomNavigation.js";
4
4
  import { HomeContent } from "./HomeContent.js";
5
5
  import SettingsContent from "./SettingsContent.js";
6
6
  export function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain, partnerId, showSwap, showDeposit, }) {
7
+ const { authStrategy } = useB3Config();
8
+ const isBetterAuth = authStrategy === "better-auth";
7
9
  const contentType = useModalStore(state => state.contentType);
8
10
  const { activeTab = "home", setActiveTab } = contentType;
9
11
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
12
+ // Better Auth: single-view layout — no Home/Swap tabs, just settings content
13
+ if (isBetterAuth) {
14
+ return (_jsx("div", { className: "b3-manage-account flex-1", children: _jsx(SettingsContent, { partnerId: partnerId, onLogout: onLogout, chain: chain }) }));
15
+ }
10
16
  return (_jsx("div", { className: "b3-manage-account flex-1", children: _jsxs(TabsPrimitive, { defaultValue: activeTab, onValueChange: value => {
11
17
  const tab = value;
12
18
  if (tab === "swap") {
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useAuthentication, useB3Config, useModalStore } from "../../../../global-account/react/index.js";
3
3
  import { client } from "../../../../shared/utils/thirdweb.js";
4
4
  import { getSessionDurationDays, SESSION_DURATION_LABELS } from "../../../../shared/utils/session-duration.js";
5
- import { Loader2 } from "lucide-react";
5
+ import { Bell, Clock, Link, Loader2 } from "lucide-react";
6
6
  import { useState } from "react";
7
7
  import { useProfiles } from "thirdweb/react";
8
8
  import SignOutIcon from "../icons/SignOutIcon.js";
@@ -47,7 +47,7 @@ const SettingsContent = ({ partnerId, onLogout, chain, }) => {
47
47
  setB3ModalOpen(false);
48
48
  setLogoutLoading(false);
49
49
  };
50
- return (_jsxs("div", { className: "flex h-[470px] flex-col", children: [_jsx(ModalHeader, { showBackButton: false, showCloseButton: false, title: "Settings" }), _jsx("div", { className: "p-5", children: _jsx("div", { className: "b3-modal-settings-profile-card dark:border-b3-line dark:bg-b3-background flex items-center rounded-xl border border-[#e4e4e7] bg-[#f4f4f5] p-4", children: _jsx(SettingsProfileCard, {}) }) }), _jsxs("div", { className: "space-y-3 px-5", children: [!isBetterAuth && (_jsx(SettingsMenuItem, { icon: _jsx("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z", fill: "#F4F4F5" }) }), title: "Linked Accounts", subtitle: `${profiles.length} connected account${profiles.length > 1 ? "s" : ""}`, onClick: () => handleNavigate("linkAccount") })), _jsx(SettingsMenuItem, { icon: _jsx("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z", fill: "#F4F4F5" }) }), title: "Notifications", subtitle: "Manage your notifications", onClick: () => handleNavigate("notifications") }), _jsx(SettingsMenuItem, { icon: _jsx("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z", fill: "#F4F4F5" }) }), title: "Stay signed in", subtitle: SESSION_DURATION_LABELS[sessionDays] ?? `${sessionDays} days`, onClick: () => handleNavigate("sessionDuration") })] }), _jsx("div", { className: "mt-auto px-5 pb-5", children: _jsxs("button", { type: "button", className: "b3-modal-sign-out-button border-b3-line hover:bg-b3-line bg-b3-background dark:bg-b3-background dark:border-b3-line dark:hover:bg-b3-line/80 flex w-full items-center justify-center gap-1.5 rounded-xl border border-solid p-3 transition-colors", onClick: onLogoutEnhanced, disabled: logoutLoading, style: {
50
+ return (_jsxs("div", { className: "flex h-[470px] flex-col", children: [!isBetterAuth && _jsx(ModalHeader, { showBackButton: false, showCloseButton: false, title: "Settings" }), _jsx("div", { className: "p-5", children: _jsx("div", { className: "b3-modal-settings-profile-card dark:border-b3-line dark:bg-b3-background flex items-center rounded-xl border border-[#e4e4e7] bg-[#f4f4f5] p-4", children: _jsx(SettingsProfileCard, {}) }) }), _jsxs("div", { className: "space-y-3 px-5", children: [!isBetterAuth && (_jsx(SettingsMenuItem, { icon: _jsx(Link, { size: 18, className: "text-[#51525c]" }), title: "Linked Accounts", subtitle: `${profiles.length} connected account${profiles.length > 1 ? "s" : ""}`, onClick: () => handleNavigate("linkAccount") })), _jsx(SettingsMenuItem, { icon: _jsx(Bell, { size: 18, className: "text-[#51525c]" }), title: "Notifications", subtitle: "Manage your notifications", onClick: () => handleNavigate("notifications") }), _jsx(SettingsMenuItem, { icon: _jsx(Clock, { size: 18, className: "text-[#51525c]" }), title: "Stay signed in", subtitle: SESSION_DURATION_LABELS[sessionDays] ?? `${sessionDays} days`, onClick: () => handleNavigate("sessionDuration") })] }), _jsx("div", { className: "mt-auto px-5 pb-5", children: _jsxs("button", { type: "button", className: "b3-modal-sign-out-button border-b3-line hover:bg-b3-line bg-b3-background dark:bg-b3-background dark:border-b3-line dark:hover:bg-b3-line/80 flex w-full items-center justify-center gap-1.5 rounded-xl border border-solid p-3 transition-colors", onClick: onLogoutEnhanced, disabled: logoutLoading, style: {
51
51
  boxShadow: "inset 0px 0px 0px 1px rgba(10,13,18,0.18), inset 0px -2px 0px 0px rgba(10,13,18,0.05)",
52
52
  }, children: [logoutLoading ? (_jsx(Loader2, { className: "text-b3-grey animate-spin", size: 20 })) : (_jsx(SignOutIcon, { size: 20, className: "text-b3-grey", color: "currentColor" })), _jsx("p", { className: "text-b3-grey dark:text-b3-foreground-muted font-neue-montreal-semibold text-base", children: "Sign out" })] }) })] }));
53
53
  };
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { IPFSMediaRenderer, SignInWithB3, StyleRoot, useAccountWallet, useAuthStore, useAuthentication, useB3Config, useIsMobile, } from "../../../../global-account/react/index.js";
3
3
  import Icon from "../../../../global-account/react/components/custom/Icon.js";
4
- import { AVATAR_COLORS, ecosystemWalletId } from "../../../../shared/constants/index.js";
4
+ import { ecosystemWalletId } from "../../../../shared/constants/index.js";
5
5
  import { cn, truncateAddress } from "../../../../shared/utils/index.js";
6
6
  import { Menu, MenuButton, MenuItems, Transition } from "@headlessui/react";
7
- import Avatar from "boring-avatars";
8
7
  import { useEffect } from "react";
9
8
  import { useConnectedWallets, useSetActiveWallet, useWalletImage } from "thirdweb/react";
10
9
  import { useUser } from "../../hooks/useUser.js";
10
+ import { UserAvatar } from "../UserAvatar/UserAvatar.js";
11
11
  import { ManageAccountButton } from "../custom/ManageAccountButton.js";
12
12
  export function SignIn(props) {
13
13
  const { className } = props;
@@ -43,11 +43,11 @@ export function SignIn(props) {
43
43
  }, [connectedEOAWallet, isActiveEOAWallet, setActiveWallet, automaticallySetFirstEoa]);
44
44
  const isLoggedIn = isBetterAuth ? isAuthenticated : !!globalAddress;
45
45
  // Desktop version - original dropdown menu
46
- return (_jsx(StyleRoot, { children: _jsx(Menu, { className: `relative flex items-center ${className || ""}`, as: "div", children: isLoggedIn ? (_jsxs(_Fragment, { children: [_jsxs(MenuButton, { className: "bg-b3-react-background group flex h-10 items-center gap-1 rounded-xl px-3 focus:outline-none", children: [isBetterAuth ? (_jsx(Avatar, { name: userDisplayName, variant: "beam", size: 24, colors: AVATAR_COLORS })) : (!!walletImage && (_jsx(IPFSMediaRenderer, { src: walletImage, alt: "Wallet Image", className: "bg-b3-react-primary h-6 w-6 rounded-full object-cover opacity-100" }))), _jsx("div", { className: "text-as-primary", children: isBetterAuth ? userDisplayName : ensName ? ensName : truncateAddress(globalAddress ?? "") })] }), _jsx(Transition, { enter: "duration-200 ease-out", enterFrom: "scale-95 opacity-0", enterTo: "scale-100 opacity-100", leave: "duration-300 ease-out", leaveFrom: "scale-100 opacity-100", leaveTo: "scale-95 opacity-0", children: _jsx(MenuItems, { className: "b3-root absolute -right-4 top-full min-w-64 rounded-2xl border focus:outline-none lg:right-0", modal: false,
46
+ return (_jsx(StyleRoot, { children: _jsx(Menu, { className: `relative flex items-center ${className || ""}`, as: "div", children: isLoggedIn ? (_jsxs(_Fragment, { children: [_jsxs(MenuButton, { className: "bg-b3-react-background group flex h-10 items-center gap-1 rounded-xl px-3 focus:outline-none", children: [isBetterAuth ? (_jsx(UserAvatar, { avatarUrl: user?.avatar, name: userDisplayName, size: 24 })) : (!!walletImage && (_jsx(IPFSMediaRenderer, { src: walletImage, alt: "Wallet Image", className: "bg-b3-react-primary h-6 w-6 rounded-full object-cover opacity-100" }))), _jsx("div", { className: "text-as-primary", children: isBetterAuth ? userDisplayName : ensName ? ensName : truncateAddress(globalAddress ?? "") })] }), _jsx(Transition, { enter: "duration-200 ease-out", enterFrom: "scale-95 opacity-0", enterTo: "scale-100 opacity-100", leave: "duration-300 ease-out", leaveFrom: "scale-100 opacity-100", leaveTo: "scale-95 opacity-0", children: _jsx(MenuItems, { className: "b3-root absolute -right-4 top-full min-w-64 rounded-2xl border focus:outline-none lg:right-0", modal: false,
47
47
  // TODO: Figure out why setting anchor on mobile causes z-index issues where it appears under elements
48
48
  anchor: isMobile ? "top end" : undefined, children: _jsxs("div", { className: "bg-b3-react-background", children: [isBetterAuth ? (
49
49
  /* Better Auth: show user info instead of wallet switching */
50
- _jsxs("div", { className: "flex items-center gap-3 rounded-xl p-3", children: [_jsx(Avatar, { name: userDisplayName, variant: "beam", size: 48, colors: AVATAR_COLORS }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [user?.username && _jsx("div", { className: "text-b3-react-primary font-semibold", children: user.username }), user?.email && _jsx("div", { className: "text-b3-react-secondary text-sm", children: user.email })] })] })) : connectedEOAWallet ? (_jsxs("div", { className: cn("border-b3-react-subtle bg-b3-react-background flex cursor-pointer items-center justify-between rounded-xl p-3"), onClick: () => handleSetActiveAccount(connectedEOAWallet?.id), children: [_jsxs("div", { className: "flex items-center", children: [_jsx("img", { className: "bg-b3-react-primary h-16 w-16 rounded-full opacity-100", src: walletImage, alt: connectedEOAWallet?.id }), _jsxs("div", { className: "ml-4 grow", children: [ensName && _jsx("div", { children: ensName }), _jsx("div", { children: truncateAddress(globalAddress ?? "") })] })] }), isActiveEOAWallet && _jsx(Icon, { className: "fill-b3-react-primary", name: "check" })] })) : (connectedSmartWallet && (_jsxs("div", { className: cn("mb-2 flex cursor-pointer items-center justify-between rounded-xl p-3", isActiveSmartWallet
50
+ _jsxs("div", { className: "flex items-center gap-3 rounded-xl p-3", children: [_jsx(UserAvatar, { avatarUrl: user?.avatar, name: userDisplayName, size: 48 }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [user?.username && _jsx("div", { className: "text-b3-react-primary font-semibold", children: user.username }), user?.email && _jsx("div", { className: "text-b3-react-secondary text-sm", children: user.email })] })] })) : connectedEOAWallet ? (_jsxs("div", { className: cn("border-b3-react-subtle bg-b3-react-background flex cursor-pointer items-center justify-between rounded-xl p-3"), onClick: () => handleSetActiveAccount(connectedEOAWallet?.id), children: [_jsxs("div", { className: "flex items-center", children: [_jsx("img", { className: "bg-b3-react-primary h-16 w-16 rounded-full opacity-100", src: walletImage, alt: connectedEOAWallet?.id }), _jsxs("div", { className: "ml-4 grow", children: [ensName && _jsx("div", { children: ensName }), _jsx("div", { children: truncateAddress(globalAddress ?? "") })] })] }), isActiveEOAWallet && _jsx(Icon, { className: "fill-b3-react-primary", name: "check" })] })) : (connectedSmartWallet && (_jsxs("div", { className: cn("mb-2 flex cursor-pointer items-center justify-between rounded-xl p-3", isActiveSmartWallet
51
51
  ? "bg-b3-react-background"
52
52
  : "bg-b3-react-background hover:bg-b3-react-background"), onClick: () => handleSetActiveAccount(connectedSmartWallet?.id), children: [_jsxs("div", { className: "flex items-center", children: [_jsx("img", { className: "bg-b3-react-primary h-16 w-16 rounded-full opacity-100", src: smartWalletIcon, alt: connectedSmartWallet?.id }), _jsxs("div", { className: "grow pl-4", children: [ensName && _jsx("div", { children: ensName }), _jsx("div", { children: truncateAddress(globalAddress ?? "") }), _jsx("div", { children: "Smart wallet" })] })] }), isActiveSmartWallet && _jsx(Icon, { className: "fill-b3-react-primary", name: "check" })] }))), _jsx("div", { className: "ml-3", children: _jsx(ManageAccountButton, { ...props, className: "w-[calc(100%-12px)]" }) }), _jsx("button", { className: "mb-2 w-full space-y-1", onClick: onDisconnect, children: _jsxs("div", { className: "hover:bg-b3-react-background group flex h-12 items-center rounded-xl px-4 transition-colors", children: [_jsx(Icon, { className: "fill-b3-react-primary mr-4 shrink-0 transition-colors", name: "logout" }), _jsx("div", { className: "text-b3-react-primary mr-auto transition-colors", children: isBetterAuth ? "Sign out" : "Disconnect" })] }) })] }) }) })] })) : (_jsx(SignInWithB3, { closeAfterLogin: true, onLoginSuccess: async (globalAccount) => {
53
53
  console.log("User authenticated with Global Account!", globalAccount);
@@ -0,0 +1,18 @@
1
+ interface UserAvatarProps {
2
+ /** Direct avatar URL (IPFS or HTTP). Resolved and validated internally. */
3
+ avatarUrl?: string | null;
4
+ /** Seed for the generated fallback avatar + alt text. Use email, username, or address. */
5
+ name?: string;
6
+ /** Avatar size in pixels (square). */
7
+ size?: number;
8
+ /** Additional className for the outer container. */
9
+ className?: string;
10
+ }
11
+ /**
12
+ * Renders a user avatar with IPFS support and boring-avatars fallback.
13
+ *
14
+ * - If `avatarUrl` is provided and valid, renders via IPFSMediaRenderer.
15
+ * - On load failure or missing URL, falls back to a deterministic boring-avatars beam.
16
+ */
17
+ export declare function UserAvatar({ avatarUrl, name, size, className }: UserAvatarProps): import("react/jsx-runtime").JSX.Element;
18
+ export {};
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { validateImageUrl } from "../../../../global-account/react/utils/profileDisplay.js";
3
+ import { AVATAR_COLORS } from "../../../../shared/constants/index.js";
4
+ import Avatar from "boring-avatars";
5
+ import { useCallback, useEffect, useState } from "react";
6
+ import { IPFSMediaRenderer } from "../IPFSMediaRenderer/IPFSMediaRenderer.js";
7
+ /**
8
+ * Renders a user avatar with IPFS support and boring-avatars fallback.
9
+ *
10
+ * - If `avatarUrl` is provided and valid, renders via IPFSMediaRenderer.
11
+ * - On load failure or missing URL, falls back to a deterministic boring-avatars beam.
12
+ */
13
+ export function UserAvatar({ avatarUrl, name = "user", size = 40, className }) {
14
+ const resolvedSrc = validateImageUrl(avatarUrl);
15
+ const [imgError, setImgError] = useState(false);
16
+ useEffect(() => {
17
+ setImgError(false);
18
+ }, [avatarUrl]);
19
+ const handleImgError = useCallback(() => setImgError(true), []);
20
+ return (_jsx("div", { className: className, style: { width: size, height: size, minWidth: size, minHeight: size }, children: resolvedSrc && !imgError ? (_jsx("div", { onErrorCapture: handleImgError, className: "h-full w-full overflow-hidden rounded-full", children: _jsx(IPFSMediaRenderer, { src: resolvedSrc, alt: name, className: "h-full w-full object-cover" }) })) : (_jsx(Avatar, { name: name, variant: "beam", size: size, colors: AVATAR_COLORS })) }));
21
+ }
@@ -18,6 +18,7 @@ export { SignInWithB3Privy } from "./SignInWithB3/SignInWithB3Privy";
18
18
  export { LoginStepContainer } from "./SignInWithB3/steps/LoginStep";
19
19
  export { getConnectOptionsFromStrategy, isWalletType, type AllowedStrategy } from "./SignInWithB3/utils/signInUtils";
20
20
  export { ManageAccount } from "./ManageAccount/ManageAccount";
21
+ export { UserAvatar } from "./UserAvatar/UserAvatar";
21
22
  export { Deposit } from "./Deposit/Deposit";
22
23
  export { Send } from "./Send/Send";
23
24
  export { IPFSMediaRenderer } from "./IPFSMediaRenderer/IPFSMediaRenderer";
@@ -21,6 +21,8 @@ export { LoginStepContainer } from "./SignInWithB3/steps/LoginStep.js";
21
21
  export { getConnectOptionsFromStrategy, isWalletType } from "./SignInWithB3/utils/signInUtils.js";
22
22
  // ManageAccount Components
23
23
  export { ManageAccount } from "./ManageAccount/ManageAccount.js";
24
+ // UserAvatar
25
+ export { UserAvatar } from "./UserAvatar/UserAvatar.js";
24
26
  // Deposit Components
25
27
  export { Deposit } from "./Deposit/Deposit.js";
26
28
  // Send Components
@@ -0,0 +1,18 @@
1
+ interface UserAvatarProps {
2
+ /** Direct avatar URL (IPFS or HTTP). Resolved and validated internally. */
3
+ avatarUrl?: string | null;
4
+ /** Seed for the generated fallback avatar + alt text. Use email, username, or address. */
5
+ name?: string;
6
+ /** Avatar size in pixels (square). */
7
+ size?: number;
8
+ /** Additional className for the outer container. */
9
+ className?: string;
10
+ }
11
+ /**
12
+ * Renders a user avatar with IPFS support and boring-avatars fallback.
13
+ *
14
+ * - If `avatarUrl` is provided and valid, renders via IPFSMediaRenderer.
15
+ * - On load failure or missing URL, falls back to a deterministic boring-avatars beam.
16
+ */
17
+ export declare function UserAvatar({ avatarUrl, name, size, className }: UserAvatarProps): import("react/jsx-runtime").JSX.Element;
18
+ export {};
@@ -18,6 +18,7 @@ export { SignInWithB3Privy } from "./SignInWithB3/SignInWithB3Privy";
18
18
  export { LoginStepContainer } from "./SignInWithB3/steps/LoginStep";
19
19
  export { getConnectOptionsFromStrategy, isWalletType, type AllowedStrategy } from "./SignInWithB3/utils/signInUtils";
20
20
  export { ManageAccount } from "./ManageAccount/ManageAccount";
21
+ export { UserAvatar } from "./UserAvatar/UserAvatar";
21
22
  export { Deposit } from "./Deposit/Deposit";
22
23
  export { Send } from "./Send/Send";
23
24
  export { IPFSMediaRenderer } from "./IPFSMediaRenderer/IPFSMediaRenderer";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.1.69-alpha.25",
3
+ "version": "0.1.69-alpha.26",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -5,14 +5,13 @@ import {
5
5
  useB3Config,
6
6
  useModalStore,
7
7
  } from "@b3dotfun/sdk/global-account/react";
8
- import { AVATAR_COLORS } from "@b3dotfun/sdk/shared/constants";
9
8
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
10
9
  import { AnimatePresence, motion } from "framer-motion";
11
- import Avatar from "boring-avatars";
12
10
  import { Loader2 } from "lucide-react";
13
11
  import { useState } from "react";
14
12
  import { useActiveWallet, useConnectedWallets, useSetActiveWallet, useWalletImage } from "thirdweb/react";
15
13
  import { Wallet } from "thirdweb/wallets";
14
+ import { UserAvatar } from "../UserAvatar/UserAvatar";
16
15
  import { ChevronDownIcon } from "../icons/ChevronDownIcon";
17
16
  import LinkIcon from "../icons/LinkIcon";
18
17
  import SignOutIcon from "../icons/SignOutIcon";
@@ -115,9 +114,7 @@ function BetterAuthHeader({ onLogout }: { onLogout?: () => void }) {
115
114
  return (
116
115
  <div className="bg-b3-background border-b3-line flex items-center justify-between border-b px-5 py-3">
117
116
  <div className="flex items-center gap-2">
118
- <div className="size-10 shrink-0 overflow-hidden rounded-full">
119
- <Avatar name={displayName} variant="beam" size={40} colors={AVATAR_COLORS} />
120
- </div>
117
+ <UserAvatar avatarUrl={user?.avatar} name={displayName} size={40} className="shrink-0" />
121
118
  <div className="flex flex-col gap-0.5">
122
119
  {user?.username && (
123
120
  <p className="text-b3-grey font-neue-montreal-semibold text-left text-sm">{user.username}</p>
@@ -2,6 +2,7 @@ import {
2
2
  ManageAccountModalProps,
3
3
  TabsContentPrimitive,
4
4
  TabsPrimitive,
5
+ useB3Config,
5
6
  useModalStore,
6
7
  } from "@b3dotfun/sdk/global-account/react";
7
8
  import { Chain } from "thirdweb";
@@ -74,9 +75,21 @@ export function ManageAccount({
74
75
  showSwap,
75
76
  showDeposit,
76
77
  }: ManageAccountProps) {
78
+ const { authStrategy } = useB3Config();
79
+ const isBetterAuth = authStrategy === "better-auth";
77
80
  const contentType = useModalStore(state => state.contentType);
78
81
  const { activeTab = "home", setActiveTab } = contentType as ManageAccountModalProps;
79
82
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
83
+
84
+ // Better Auth: single-view layout — no Home/Swap tabs, just settings content
85
+ if (isBetterAuth) {
86
+ return (
87
+ <div className="b3-manage-account flex-1">
88
+ <SettingsContent partnerId={partnerId} onLogout={onLogout} chain={chain} />
89
+ </div>
90
+ );
91
+ }
92
+
80
93
  return (
81
94
  <div className="b3-manage-account flex-1">
82
95
  <TabsPrimitive
@@ -1,7 +1,7 @@
1
1
  import { useAuthentication, useB3Config, useModalStore } from "@b3dotfun/sdk/global-account/react";
2
2
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
3
3
  import { getSessionDurationDays, SESSION_DURATION_LABELS } from "@b3dotfun/sdk/shared/utils/session-duration";
4
- import { Loader2 } from "lucide-react";
4
+ import { Bell, Clock, Link, Loader2 } from "lucide-react";
5
5
  import { useState } from "react";
6
6
  import { Chain } from "thirdweb";
7
7
  import { useProfiles } from "thirdweb/react";
@@ -60,7 +60,7 @@ const SettingsContent = ({
60
60
 
61
61
  return (
62
62
  <div className="flex h-[470px] flex-col">
63
- <ModalHeader showBackButton={false} showCloseButton={false} title="Settings" />
63
+ {!isBetterAuth && <ModalHeader showBackButton={false} showCloseButton={false} title="Settings" />}
64
64
 
65
65
  {/* Profile Section */}
66
66
  <div className="p-5">
@@ -73,41 +73,20 @@ const SettingsContent = ({
73
73
  <div className="space-y-3 px-5">
74
74
  {!isBetterAuth && (
75
75
  <SettingsMenuItem
76
- icon={
77
- <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
78
- <path
79
- d="M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z"
80
- fill="#F4F4F5"
81
- />
82
- </svg>
83
- }
76
+ icon={<Link size={18} className="text-[#51525c]" />}
84
77
  title="Linked Accounts"
85
78
  subtitle={`${profiles.length} connected account${profiles.length > 1 ? "s" : ""}`}
86
79
  onClick={() => handleNavigate("linkAccount")}
87
80
  />
88
81
  )}
89
82
  <SettingsMenuItem
90
- icon={
91
- <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
92
- <path
93
- d="M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z"
94
- fill="#F4F4F5"
95
- />
96
- </svg>
97
- }
83
+ icon={<Bell size={18} className="text-[#51525c]" />}
98
84
  title="Notifications"
99
85
  subtitle="Manage your notifications"
100
86
  onClick={() => handleNavigate("notifications")}
101
87
  />
102
88
  <SettingsMenuItem
103
- icon={
104
- <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
105
- <path
106
- d="M0 12C0 5.37258 5.37258 0 12 0H28C34.6274 0 40 5.37258 40 12V28C40 34.6274 34.6274 40 28 40H12C5.37258 40 0 34.6274 0 28V12Z"
107
- fill="#F4F4F5"
108
- />
109
- </svg>
110
- }
89
+ icon={<Clock size={18} className="text-[#51525c]" />}
111
90
  title="Stay signed in"
112
91
  subtitle={SESSION_DURATION_LABELS[sessionDays] ?? `${sessionDays} days`}
113
92
  onClick={() => handleNavigate("sessionDuration")}
@@ -10,13 +10,13 @@ import {
10
10
  useIsMobile,
11
11
  } from "@b3dotfun/sdk/global-account/react";
12
12
  import Icon from "@b3dotfun/sdk/global-account/react/components/custom/Icon";
13
- import { AVATAR_COLORS, ecosystemWalletId } from "@b3dotfun/sdk/shared/constants";
13
+ import { ecosystemWalletId } from "@b3dotfun/sdk/shared/constants";
14
14
  import { cn, truncateAddress } from "@b3dotfun/sdk/shared/utils";
15
15
  import { Menu, MenuButton, MenuItems, Transition } from "@headlessui/react";
16
- import Avatar from "boring-avatars";
17
16
  import { ReactNode, useEffect } from "react";
18
17
  import { useConnectedWallets, useSetActiveWallet, useWalletImage } from "thirdweb/react";
19
18
  import { useUser } from "../../hooks/useUser";
19
+ import { UserAvatar } from "../UserAvatar/UserAvatar";
20
20
  import { ManageAccountButton } from "../custom/ManageAccountButton";
21
21
 
22
22
  type SignInProps = {
@@ -92,7 +92,7 @@ export function SignIn(props: SignInWithB3Props) {
92
92
  <>
93
93
  <MenuButton className="bg-b3-react-background group flex h-10 items-center gap-1 rounded-xl px-3 focus:outline-none">
94
94
  {isBetterAuth ? (
95
- <Avatar name={userDisplayName} variant="beam" size={24} colors={AVATAR_COLORS} />
95
+ <UserAvatar avatarUrl={user?.avatar} name={userDisplayName} size={24} />
96
96
  ) : (
97
97
  !!walletImage && (
98
98
  <IPFSMediaRenderer
@@ -124,7 +124,7 @@ export function SignIn(props: SignInWithB3Props) {
124
124
  {isBetterAuth ? (
125
125
  /* Better Auth: show user info instead of wallet switching */
126
126
  <div className="flex items-center gap-3 rounded-xl p-3">
127
- <Avatar name={userDisplayName} variant="beam" size={48} colors={AVATAR_COLORS} />
127
+ <UserAvatar avatarUrl={user?.avatar} name={userDisplayName} size={48} />
128
128
  <div className="flex flex-col gap-0.5">
129
129
  {user?.username && <div className="text-b3-react-primary font-semibold">{user.username}</div>}
130
130
  {user?.email && <div className="text-b3-react-secondary text-sm">{user.email}</div>}
@@ -0,0 +1,45 @@
1
+ import { validateImageUrl } from "@b3dotfun/sdk/global-account/react/utils/profileDisplay";
2
+ import { AVATAR_COLORS } from "@b3dotfun/sdk/shared/constants";
3
+ import Avatar from "boring-avatars";
4
+ import { useCallback, useEffect, useState } from "react";
5
+ import { IPFSMediaRenderer } from "../IPFSMediaRenderer/IPFSMediaRenderer";
6
+
7
+ interface UserAvatarProps {
8
+ /** Direct avatar URL (IPFS or HTTP). Resolved and validated internally. */
9
+ avatarUrl?: string | null;
10
+ /** Seed for the generated fallback avatar + alt text. Use email, username, or address. */
11
+ name?: string;
12
+ /** Avatar size in pixels (square). */
13
+ size?: number;
14
+ /** Additional className for the outer container. */
15
+ className?: string;
16
+ }
17
+
18
+ /**
19
+ * Renders a user avatar with IPFS support and boring-avatars fallback.
20
+ *
21
+ * - If `avatarUrl` is provided and valid, renders via IPFSMediaRenderer.
22
+ * - On load failure or missing URL, falls back to a deterministic boring-avatars beam.
23
+ */
24
+ export function UserAvatar({ avatarUrl, name = "user", size = 40, className }: UserAvatarProps) {
25
+ const resolvedSrc = validateImageUrl(avatarUrl);
26
+ const [imgError, setImgError] = useState(false);
27
+
28
+ useEffect(() => {
29
+ setImgError(false);
30
+ }, [avatarUrl]);
31
+
32
+ const handleImgError = useCallback(() => setImgError(true), []);
33
+
34
+ return (
35
+ <div className={className} style={{ width: size, height: size, minWidth: size, minHeight: size }}>
36
+ {resolvedSrc && !imgError ? (
37
+ <div onErrorCapture={handleImgError} className="h-full w-full overflow-hidden rounded-full">
38
+ <IPFSMediaRenderer src={resolvedSrc} alt={name} className="h-full w-full object-cover" />
39
+ </div>
40
+ ) : (
41
+ <Avatar name={name} variant="beam" size={size} colors={AVATAR_COLORS} />
42
+ )}
43
+ </div>
44
+ );
45
+ }
@@ -29,6 +29,9 @@ export { getConnectOptionsFromStrategy, isWalletType, type AllowedStrategy } fro
29
29
  // ManageAccount Components
30
30
  export { ManageAccount } from "./ManageAccount/ManageAccount";
31
31
 
32
+ // UserAvatar
33
+ export { UserAvatar } from "./UserAvatar/UserAvatar";
34
+
32
35
  // Deposit Components
33
36
  export { Deposit } from "./Deposit/Deposit";
34
37