@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.
- package/dist/cjs/global-account/react/components/ManageAccount/Header.js +2 -3
- package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +6 -0
- package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +1 -1
- package/dist/cjs/global-account/react/components/SignInWithB3/SignIn.js +3 -3
- package/dist/cjs/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
- package/dist/cjs/global-account/react/components/UserAvatar/UserAvatar.js +27 -0
- package/dist/cjs/global-account/react/components/index.d.ts +1 -0
- package/dist/cjs/global-account/react/components/index.js +6 -3
- package/dist/esm/global-account/react/components/ManageAccount/Header.js +2 -3
- package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +7 -1
- package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +2 -2
- package/dist/esm/global-account/react/components/SignInWithB3/SignIn.js +4 -4
- package/dist/esm/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
- package/dist/esm/global-account/react/components/UserAvatar/UserAvatar.js +21 -0
- package/dist/esm/global-account/react/components/index.d.ts +1 -0
- package/dist/esm/global-account/react/components/index.js +2 -0
- package/dist/types/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
- package/dist/types/global-account/react/components/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/global-account/react/components/ManageAccount/Header.tsx +2 -5
- package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +13 -0
- package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +5 -26
- package/src/global-account/react/components/SignInWithB3/SignIn.tsx +4 -4
- package/src/global-account/react/components/UserAvatar/UserAvatar.tsx +45 -0
- 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)(
|
|
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)(
|
|
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)(
|
|
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)(
|
|
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.
|
|
7
|
-
exports.
|
|
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(
|
|
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(
|
|
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 {
|
|
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(
|
|
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(
|
|
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
|
@@ -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
|
-
<
|
|
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 {
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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
|
|