@b3dotfun/sdk 0.0.26 → 0.0.27-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpendCustom.d.ts +1 -0
  2. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +3 -2
  3. package/dist/cjs/anyspend/react/components/AnySpendNFT.js +2 -2
  4. package/dist/cjs/anyspend/react/components/common/PaymentStripeWeb2.d.ts +2 -1
  5. package/dist/cjs/anyspend/react/components/common/PaymentStripeWeb2.js +3 -3
  6. package/dist/cjs/anyspend/react/components/common/PaymentVendorUI.js +2 -2
  7. package/dist/cjs/anyspend/utils/chain.js +2 -2
  8. package/dist/cjs/global-account/react/components/B3DynamicModal.js +4 -0
  9. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.d.ts +2 -0
  10. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +228 -0
  11. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +56 -3
  12. package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStep.js +1 -1
  13. package/dist/cjs/global-account/react/components/custom/Button.d.ts +1 -1
  14. package/dist/cjs/global-account/react/components/ui/button.d.ts +1 -1
  15. package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +8 -2
  16. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +20 -1
  17. package/dist/cjs/global-account/react/stores/useModalStore.js +3 -0
  18. package/dist/cjs/global-account/react/utils/profileDisplay.d.ts +21 -0
  19. package/dist/cjs/global-account/react/utils/profileDisplay.js +63 -0
  20. package/dist/esm/anyspend/react/components/AnySpendCustom.d.ts +1 -0
  21. package/dist/esm/anyspend/react/components/AnySpendCustom.js +3 -2
  22. package/dist/esm/anyspend/react/components/AnySpendNFT.js +2 -2
  23. package/dist/esm/anyspend/react/components/common/PaymentStripeWeb2.d.ts +2 -1
  24. package/dist/esm/anyspend/react/components/common/PaymentStripeWeb2.js +3 -3
  25. package/dist/esm/anyspend/react/components/common/PaymentVendorUI.js +2 -2
  26. package/dist/esm/anyspend/utils/chain.js +2 -2
  27. package/dist/esm/global-account/react/components/B3DynamicModal.js +4 -0
  28. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.d.ts +2 -0
  29. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +225 -0
  30. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +58 -5
  31. package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStep.js +1 -1
  32. package/dist/esm/global-account/react/components/custom/Button.d.ts +1 -1
  33. package/dist/esm/global-account/react/components/ui/button.d.ts +1 -1
  34. package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +8 -2
  35. package/dist/esm/global-account/react/stores/useModalStore.d.ts +20 -1
  36. package/dist/esm/global-account/react/stores/useModalStore.js +3 -0
  37. package/dist/esm/global-account/react/utils/profileDisplay.d.ts +21 -0
  38. package/dist/esm/global-account/react/utils/profileDisplay.js +60 -0
  39. package/dist/styles/index.css +1 -1
  40. package/dist/types/anyspend/react/components/AnySpendCustom.d.ts +1 -0
  41. package/dist/types/anyspend/react/components/common/PaymentStripeWeb2.d.ts +2 -1
  42. package/dist/types/global-account/react/components/LinkAccount/LinkAccount.d.ts +2 -0
  43. package/dist/types/global-account/react/components/custom/Button.d.ts +1 -1
  44. package/dist/types/global-account/react/components/ui/button.d.ts +1 -1
  45. package/dist/types/global-account/react/stores/useModalStore.d.ts +20 -1
  46. package/dist/types/global-account/react/utils/profileDisplay.d.ts +21 -0
  47. package/package.json +2 -2
  48. package/src/anyspend/react/components/AnySpendCustom.tsx +7 -3
  49. package/src/anyspend/react/components/AnySpendNFT.tsx +2 -1
  50. package/src/anyspend/react/components/common/PaymentStripeWeb2.tsx +5 -28
  51. package/src/anyspend/react/components/common/PaymentVendorUI.tsx +2 -2
  52. package/src/anyspend/utils/chain.ts +2 -2
  53. package/src/global-account/react/components/B3DynamicModal.tsx +4 -0
  54. package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +369 -0
  55. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +187 -5
  56. package/src/global-account/react/components/SignInWithB3/steps/LoginStep.tsx +3 -1
  57. package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +9 -2
  58. package/src/global-account/react/stores/useModalStore.ts +26 -1
  59. package/src/global-account/react/utils/profileDisplay.ts +87 -0
@@ -4,6 +4,7 @@ import React from "react";
4
4
  export declare function AnySpendCustom(props: {
5
5
  loadOrder?: string;
6
6
  mode?: "modal" | "page";
7
+ activeTab?: "crypto" | "fiat";
7
8
  recipientAddress?: string;
8
9
  spenderAddress?: string;
9
10
  orderType: components["schemas"]["Order"]["type"];
@@ -40,6 +40,7 @@ var PanelView;
40
40
  function generateGetRelayQuoteRequest({ orderType, srcChainId, srcToken, dstChainId, dstToken, dstAmount, contractAddress, tokenId, contractType, encodedData, spenderAddress, }) {
41
41
  switch (orderType) {
42
42
  case "mint_nft": {
43
+ (0, invariant_1.default)(contractType, "Contract type is required");
43
44
  return {
44
45
  type: "mint_nft",
45
46
  srcChain: srcChainId,
@@ -98,12 +99,12 @@ function AnySpendCustom(props) {
98
99
  const fingerprintConfig = (0, AnySpendFingerprintWrapper_1.getFingerprintConfig)();
99
100
  return ((0, jsx_runtime_1.jsx)(AnySpendFingerprintWrapper_1.AnySpendFingerprintWrapper, { fingerprint: fingerprintConfig, children: (0, jsx_runtime_1.jsx)(AnySpendCustomInner, { ...props }) }));
100
101
  }
101
- function AnySpendCustomInner({ loadOrder, mode = "modal", recipientAddress: recipientAddressProps, spenderAddress, orderType, dstChainId, dstToken, dstAmount, contractAddress, encodedData, metadata, header, onSuccess, showRecipient = true, }) {
102
+ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabProps = "crypto", recipientAddress: recipientAddressProps, spenderAddress, orderType, dstChainId, dstToken, dstAmount, contractAddress, encodedData, metadata, header, onSuccess, showRecipient = true, }) {
102
103
  const hasMounted = (0, react_2.useHasMounted)();
103
104
  const searchParams = (0, react_2.useSearchParamsSSR)();
104
105
  const router = (0, react_2.useRouter)();
105
106
  const [activePanel, setActivePanel] = (0, react_4.useState)(loadOrder ? PanelView.ORDER_DETAILS : PanelView.CONFIRM_ORDER);
106
- const [activeTab, setActiveTab] = (0, react_4.useState)("crypto");
107
+ const [activeTab, setActiveTab] = (0, react_4.useState)(activeTabProps);
107
108
  // Add state for selected payment methods
108
109
  const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = (0, react_4.useState)(CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE);
109
110
  const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = (0, react_4.useState)(FiatPaymentMethod_1.FiatPaymentMethod.NONE);
@@ -82,11 +82,11 @@ function AnySpendNFT({ loadOrder, mode = "modal", recipientAddress, nftContract,
82
82
  }
83
83
  }
84
84
  fetchContractMetadata();
85
- }, [nftContract.contractAddress, nftContract.chainId, nftContract.imageUrl, nftContract.tokenId]);
85
+ }, [nftContract.contractAddress, nftContract.chainId, nftContract.imageUrl, nftContract.tokenId, isLoadingFallback]);
86
86
  const header = ({ anyspendPrice, isLoadingAnyspendPrice, }) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative size-[200px]", children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 scale-95 bg-black/30 blur-md" }), (0, jsx_runtime_1.jsxs)(react_1.GlareCard, { className: "overflow-hidden", children: [imageUrlWithFallback && ((0, jsx_runtime_1.jsx)("img", { src: imageUrlWithFallback, alt: nftContract.name, className: "size-full object-cover" })), (0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 rounded-xl border border-white/10" })] }), (0, jsx_runtime_1.jsx)(DropdownMenu, { nftContract: nftContract })] }), (0, jsx_runtime_1.jsxs)("div", { className: "from-b3-react-background to-as-on-surface-1 -mb-5 mt-[-100px] w-full rounded-t-lg bg-gradient-to-t", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-[100px] w-full" }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-1 flex w-full flex-col items-center gap-2 p-5", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-sf-rounded text-2xl font-semibold", children: nftContract.name }), (0, jsx_runtime_1.jsx)("div", { className: "flex w-fit items-center gap-1", children: anyspendPrice ? ((0, jsx_runtime_1.jsx)(react_2.AnimatePresence, { mode: "wait", children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("text-as-primary group flex items-center text-3xl font-semibold transition-all", {
87
87
  "opacity-0": isLoadingAnyspendPrice,
88
88
  }), children: (0, number_1.formatDisplayNumber)(anyspendPrice?.data?.currencyIn?.amountUsd, { style: "currency" }) }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "h-[36px] w-full" })) })] })] })] }));
89
- return ((0, jsx_runtime_1.jsx)(AnySpendCustom_1.AnySpendCustom, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, orderType: "mint_nft", dstChainId: nftContract.chainId, dstToken: nftContract.currency, dstAmount: nftContract.price, contractAddress: nftContract.contractAddress, encodedData: "0x", metadata: {
89
+ return ((0, jsx_runtime_1.jsx)(AnySpendCustom_1.AnySpendCustom, { loadOrder: loadOrder, mode: mode, activeTab: "fiat", recipientAddress: recipientAddress, orderType: "mint_nft", dstChainId: nftContract.chainId, dstToken: nftContract.currency, dstAmount: nftContract.price, contractAddress: nftContract.contractAddress, encodedData: "0x", metadata: {
90
90
  type: "mint_nft",
91
91
  nftContract: nftContract,
92
92
  }, header: header, onSuccess: onSuccess }));
@@ -1,7 +1,8 @@
1
1
  import { components } from "../../../../anyspend/types/api";
2
2
  interface PaymentStripeWeb2Props {
3
3
  order: components["schemas"]["Order"];
4
+ stripePaymentIntentId: string;
4
5
  onPaymentSuccess?: (paymentIntent: any) => void;
5
6
  }
6
- export default function PaymentStripeWeb2({ order, onPaymentSuccess }: PaymentStripeWeb2Props): import("react/jsx-runtime").JSX.Element;
7
+ export default function PaymentStripeWeb2({ order, stripePaymentIntentId, onPaymentSuccess }: PaymentStripeWeb2Props): import("react/jsx-runtime").JSX.Element;
7
8
  export {};
@@ -18,10 +18,10 @@ const AnySpendFingerprintWrapper_1 = require("../AnySpendFingerprintWrapper");
18
18
  const HowItWorks_1 = __importDefault(require("./HowItWorks"));
19
19
  const PaymentMethodIcons_1 = __importDefault(require("./PaymentMethodIcons"));
20
20
  const stripePromise = (0, stripe_js_1.loadStripe)(constants_1.STRIPE_CONFIG.publishableKey);
21
- function PaymentStripeWeb2({ order, onPaymentSuccess }) {
21
+ function PaymentStripeWeb2({ order, stripePaymentIntentId, onPaymentSuccess }) {
22
22
  const { theme } = (0, react_2.useB3)();
23
23
  const fingerprintConfig = (0, AnySpendFingerprintWrapper_1.getFingerprintConfig)();
24
- const { clientSecret, isLoadingStripeClientSecret, stripeClientSecretError } = (0, react_1.useStripeClientSecret)(order.stripePaymentIntentId);
24
+ const { clientSecret, isLoadingStripeClientSecret, stripeClientSecretError } = (0, react_1.useStripeClientSecret)(stripePaymentIntentId);
25
25
  if (isLoadingStripeClientSecret) {
26
26
  return (0, jsx_runtime_1.jsx)(StripeLoadingState, {});
27
27
  }
@@ -170,7 +170,7 @@ function StripePaymentForm({ order, clientSecret, onPaymentSuccess, }) {
170
170
  // Validation
171
171
  validation: {
172
172
  phone: {
173
- required: "auto", // or 'always', 'never'
173
+ required: "always", // or 'always', 'never'
174
174
  },
175
175
  },
176
176
  } }))] }), message && ((0, jsx_runtime_1.jsxs)("div", { className: "bg-as-red/10 border-as-red/20 flex w-full items-center gap-3 rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-as-red flex h-6 w-6 shrink-0 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-4 w-4 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }), (0, jsx_runtime_1.jsx)("div", { className: "text-as-red text-sm font-medium", children: message })] })), (0, jsx_runtime_1.jsx)(react_2.ShinyButton, { type: "submit", accentColor: "hsl(var(--as-brand))", disabled: !stripe || !elements || loading, className: "relative w-full py-4 text-lg font-semibold", children: loading ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-5 w-5 animate-spin rounded-full border-2 border-current border-t-transparent" }), (0, jsx_runtime_1.jsx)("span", { className: "text-white", children: "Processing Payment..." })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-white", children: "Complete Payment" }), amount && (0, jsx_runtime_1.jsxs)("span", { className: "text-white/90", children: ["$", Number(amount).toFixed(2)] })] })) })] }), showHowItWorks && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-as-on-surface-1 relative max-h-[80vh] w-full max-w-2xl overflow-y-auto rounded-2xl p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-6 flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-as-primary text-xl font-semibold", children: "How it works" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowHowItWorks(false), className: "text-as-primary/60 hover:text-as-primary transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-6 w-6" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsx)(PaymentMethodIcons_1.default, {}), (0, jsx_runtime_1.jsx)(HowItWorks_1.default, { steps: howItWorksSteps })] })] }) }))] }));
@@ -14,8 +14,8 @@ function PaymentVendorUI({ order, dstTokenSymbol }) {
14
14
  return (0, jsx_runtime_1.jsx)(PaymentOneClick_1.default, { order: order, dstTokenSymbol: dstTokenSymbol });
15
15
  }
16
16
  // Handle Stripe Web2 payment flow
17
- if (vendor === "stripe-web2") {
18
- return (0, jsx_runtime_1.jsx)(PaymentStripeWeb2_1.default, { order: order });
17
+ if (vendor === "stripe-web2" && order.stripePaymentIntentId) {
18
+ return (0, jsx_runtime_1.jsx)(PaymentStripeWeb2_1.default, { order: order, stripePaymentIntentId: order.stripePaymentIntentId });
19
19
  }
20
20
  // Return null for unsupported vendors
21
21
  return null;
@@ -113,7 +113,7 @@ exports.EVM_MAINNET = {
113
113
  name: chains_1.avalanche.name,
114
114
  logoUrl: "https://assets.relay.link/icons/square/43114/light.png",
115
115
  type: chain_1.ChainType.EVM,
116
- nativeRequired: (0, viem_1.parseEther)("0.005"),
116
+ nativeRequired: (0, viem_1.parseEther)("0.01"),
117
117
  canDepositNative: true,
118
118
  defaultToken: (0, token_1.getAvaxToken)(),
119
119
  nativeToken: (0, token_1.getAvaxToken)(),
@@ -127,7 +127,7 @@ exports.EVM_MAINNET = {
127
127
  name: chains_1.bsc.name,
128
128
  logoUrl: "https://avatars.githubusercontent.com/u/45615063?s=280&v=4",
129
129
  type: chain_1.ChainType.EVM,
130
- nativeRequired: (0, viem_1.parseEther)("0.00001"),
130
+ nativeRequired: (0, viem_1.parseEther)("0.000025"),
131
131
  canDepositNative: true,
132
132
  defaultToken: (0, token_1.getBnbToken)(),
133
133
  nativeToken: (0, token_1.getBnbToken)(),
@@ -7,6 +7,7 @@ const react_2 = require("../../../global-account/react");
7
7
  const cn_1 = require("../../../shared/utils/cn");
8
8
  const debug_1 = require("../../../shared/utils/debug");
9
9
  const useB3_1 = require("./B3Provider/useB3");
10
+ const LinkAccount_1 = require("./LinkAccount/LinkAccount");
10
11
  const ManageAccount_1 = require("./ManageAccount/ManageAccount");
11
12
  const RequestPermissions_1 = require("./RequestPermissions/RequestPermissions");
12
13
  const SignInWithB3Flow_1 = require("./SignInWithB3/SignInWithB3Flow");
@@ -31,6 +32,7 @@ function B3DynamicModal() {
31
32
  "signInWithB3",
32
33
  "anySpendSignatureMint",
33
34
  "anySpendBondKit",
35
+ "linkAccount",
34
36
  ];
35
37
  const freestyleTypes = [
36
38
  "anySpendNft",
@@ -82,6 +84,8 @@ function B3DynamicModal() {
82
84
  return (0, jsx_runtime_1.jsx)(react_1.AnyspendSignatureMint, { ...contentType, mode: "modal" });
83
85
  case "anySpendBondKit":
84
86
  return (0, jsx_runtime_1.jsx)(react_1.AnySpendBondKit, { ...contentType });
87
+ case "linkAccount":
88
+ return (0, jsx_runtime_1.jsx)(LinkAccount_1.LinkAccount, { ...contentType });
85
89
  // Add other modal types here
86
90
  default:
87
91
  return null;
@@ -0,0 +1,2 @@
1
+ import { LinkAccountModalProps } from "../../stores/useModalStore";
2
+ export declare function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, chain, partnerId, }: LinkAccountModalProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LinkAccount = LinkAccount;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const thirdweb_1 = require("../../../../shared/utils/thirdweb");
6
+ const lucide_react_1 = require("lucide-react");
7
+ const react_1 = require("react");
8
+ const sonner_1 = require("sonner");
9
+ const react_2 = require("thirdweb/react");
10
+ const wallets_1 = require("thirdweb/wallets");
11
+ const useModalStore_1 = require("../../stores/useModalStore");
12
+ const profileDisplay_1 = require("../../utils/profileDisplay");
13
+ const useB3_1 = require("../B3Provider/useB3");
14
+ const button_1 = require("../ui/button");
15
+ const AUTH_METHODS = [
16
+ { id: "email", label: "Email", enabled: true },
17
+ { id: "phone", label: "Phone", enabled: true },
18
+ { id: "google", label: "Google", enabled: true },
19
+ { id: "x", label: "X (Twitter)", enabled: true },
20
+ { id: "discord", label: "Discord", enabled: true },
21
+ { id: "apple", label: "Apple", enabled: true },
22
+ ];
23
+ function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, chain, partnerId, }) {
24
+ const { isLinking, linkingMethod, setLinkingState, navigateBack, setB3ModalContentType } = (0, useModalStore_1.useModalStore)();
25
+ const [selectedMethod, setSelectedMethod] = (0, react_1.useState)(null);
26
+ const [email, setEmail] = (0, react_1.useState)("");
27
+ const [phone, setPhone] = (0, react_1.useState)("");
28
+ const [otp, setOtp] = (0, react_1.useState)("");
29
+ const [otpSent, setOtpSent] = (0, react_1.useState)(false);
30
+ const [error, setError] = (0, react_1.useState)(null);
31
+ const { data: profilesRaw = [] } = (0, react_2.useProfiles)({ client: thirdweb_1.client });
32
+ // Get connected auth methods
33
+ const connectedAuthMethods = profilesRaw
34
+ .filter((profile) => !["custom_auth_endpoint", "siwe"].includes(profile.type))
35
+ .map((profile) => profile.type);
36
+ // Filter available auth methods
37
+ const availableAuthMethods = AUTH_METHODS.filter(method => !connectedAuthMethods.includes(method.id) && method.enabled);
38
+ const profiles = profilesRaw
39
+ .filter((profile) => !["custom_auth_endpoint", "siwe"].includes(profile.type))
40
+ .map((profile) => ({
41
+ ...(0, profileDisplay_1.getProfileDisplayInfo)(profile),
42
+ originalProfile: profile,
43
+ }));
44
+ const { account } = (0, useB3_1.useB3)();
45
+ const { mutate: linkProfile } = (0, react_2.useLinkProfile)();
46
+ const onSuccess = (0, react_1.useCallback)(async () => {
47
+ await onSuccessCallback?.();
48
+ }, [onSuccessCallback]);
49
+ // Reset linking state when component unmounts
50
+ (0, react_1.useEffect)(() => {
51
+ return () => {
52
+ if (isLinking) {
53
+ setLinkingState(false);
54
+ }
55
+ };
56
+ }, [isLinking, setLinkingState]);
57
+ const mutationOptions = {
58
+ onError: (error) => {
59
+ console.error("Error linking account:", error);
60
+ sonner_1.toast.error(error.message);
61
+ setLinkingState(false);
62
+ onError?.(error);
63
+ },
64
+ };
65
+ const validateInput = () => {
66
+ if (selectedMethod === "email") {
67
+ if (!email) {
68
+ setError("Please enter your email address");
69
+ return false;
70
+ }
71
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
72
+ setError("Please enter a valid email address");
73
+ return false;
74
+ }
75
+ }
76
+ else if (selectedMethod === "phone") {
77
+ if (!phone) {
78
+ setError("Please enter your phone number");
79
+ return false;
80
+ }
81
+ if (!/^\+?[\d\s-]{10,}$/.test(phone)) {
82
+ setError("Please enter a valid phone number");
83
+ return false;
84
+ }
85
+ }
86
+ setError(null);
87
+ return true;
88
+ };
89
+ const handleSendOTP = async () => {
90
+ if (!validateInput())
91
+ return;
92
+ try {
93
+ setLinkingState(true, selectedMethod);
94
+ setError(null);
95
+ if (selectedMethod === "email") {
96
+ await (0, wallets_1.preAuthenticate)({
97
+ client: thirdweb_1.client,
98
+ strategy: "email",
99
+ email,
100
+ });
101
+ }
102
+ else if (selectedMethod === "phone") {
103
+ await (0, wallets_1.preAuthenticate)({
104
+ client: thirdweb_1.client,
105
+ strategy: "phone",
106
+ phoneNumber: phone,
107
+ });
108
+ }
109
+ setOtpSent(true);
110
+ }
111
+ catch (error) {
112
+ console.error("Error sending OTP:", error);
113
+ setError(error instanceof Error ? error.message : "Failed to send OTP");
114
+ onError?.(error);
115
+ setLinkingState(false);
116
+ }
117
+ };
118
+ const handleLinkAccount = async () => {
119
+ if (!otp) {
120
+ setError("Please enter the verification code");
121
+ return;
122
+ }
123
+ try {
124
+ setLinkingState(true, selectedMethod);
125
+ setError(null);
126
+ if (selectedMethod === "email") {
127
+ await linkProfile({
128
+ client: thirdweb_1.client,
129
+ strategy: "email",
130
+ email,
131
+ verificationCode: otp,
132
+ }, mutationOptions);
133
+ }
134
+ else if (selectedMethod === "phone") {
135
+ await linkProfile({
136
+ client: thirdweb_1.client,
137
+ strategy: "phone",
138
+ phoneNumber: phone,
139
+ verificationCode: otp,
140
+ }, mutationOptions);
141
+ }
142
+ onSuccess?.();
143
+ onClose?.();
144
+ }
145
+ catch (error) {
146
+ console.error("Error linking account:", error);
147
+ setError(error instanceof Error ? error.message : "Failed to link account");
148
+ onError?.(error);
149
+ }
150
+ finally {
151
+ setLinkingState(false);
152
+ }
153
+ };
154
+ const handleSocialLink = async (strategy) => {
155
+ try {
156
+ console.log("handleSocialLink", strategy);
157
+ setLinkingState(true, strategy);
158
+ setError(null);
159
+ const result = await linkProfile({
160
+ client: thirdweb_1.client,
161
+ strategy,
162
+ }, mutationOptions);
163
+ console.log("result", result);
164
+ // Don't close the modal yet, wait for auth to complete
165
+ onSuccess?.();
166
+ }
167
+ catch (error) {
168
+ console.error("Error linking with social:", error);
169
+ setError(error instanceof Error ? error.message : "Failed to link social account");
170
+ onError?.(error);
171
+ setLinkingState(false);
172
+ }
173
+ };
174
+ // Add effect to handle social auth completion
175
+ (0, react_1.useEffect)(() => {
176
+ if (isLinking && linkingMethod && !selectedMethod) {
177
+ // This means we're in a social auth flow
178
+ const checkAuthStatus = async () => {
179
+ try {
180
+ // Wait a bit to ensure auth is complete
181
+ await new Promise(resolve => setTimeout(resolve, 1000));
182
+ onClose?.();
183
+ }
184
+ catch (error) {
185
+ console.error("Error checking auth status:", error);
186
+ setLinkingState(false);
187
+ }
188
+ };
189
+ checkAuthStatus();
190
+ }
191
+ }, [isLinking, linkingMethod, selectedMethod, onClose, setLinkingState]);
192
+ const handleBack = (0, react_1.useCallback)(() => {
193
+ if (isLinking)
194
+ return;
195
+ setSelectedMethod(null);
196
+ setEmail("");
197
+ setPhone("");
198
+ setOtp("");
199
+ setOtpSent(false);
200
+ setError(null);
201
+ setLinkingState(false);
202
+ }, [isLinking, setSelectedMethod, setEmail, setPhone, setOtp, setOtpSent, setError, setLinkingState]);
203
+ (0, react_1.useEffect)(() => {
204
+ if (isLinking) {
205
+ setLinkingState(false);
206
+ navigateBack();
207
+ setB3ModalContentType({
208
+ type: "manageAccount",
209
+ activeTab: "settings",
210
+ setActiveTab: () => { },
211
+ chain,
212
+ partnerId,
213
+ });
214
+ }
215
+ // eslint-disable-next-line react-hooks/exhaustive-deps
216
+ }, [profiles.length]);
217
+ if (!account) {
218
+ return (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "Please connect your account first" });
219
+ }
220
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-6 p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-b3-grey font-neue-montreal-semibold text-2xl", children: "Link New Account" }), selectedMethod && ((0, jsx_runtime_1.jsx)(button_1.Button, { variant: "ghost", className: "text-b3-grey hover:text-b3-grey/80", onClick: handleBack, children: "Backs" }))] }), !selectedMethod ? ((0, jsx_runtime_1.jsxs)("div", { className: "grid gap-3", children: [availableAuthMethods.map(method => ((0, jsx_runtime_1.jsx)(button_1.Button, { className: "bg-b3-primary-wash hover:bg-b3-primary-wash/70 text-b3-grey font-neue-montreal-semibold h-16 justify-start px-6 text-lg", onClick: () => {
221
+ if (method.id === "email" || method.id === "phone") {
222
+ setSelectedMethod(method.id);
223
+ }
224
+ else {
225
+ handleSocialLink(method.id);
226
+ }
227
+ }, disabled: linkingMethod === method.id, children: isLinking && linkingMethod === method.id ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : method.label }, method.id))), availableAuthMethods.length === 0 && ((0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "All available authentication methods have been connected" }))] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [selectedMethod === "email" && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Email Address" }), (0, jsx_runtime_1.jsx)("input", { type: "email", placeholder: "Enter your email", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: email, onChange: e => setEmail(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "email") })] })), selectedMethod === "phone" && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Phone Number" }), (0, jsx_runtime_1.jsx)("input", { type: "tel", placeholder: "Enter your phone number", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: phone, onChange: e => setPhone(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "phone") }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Include country code (e.g., +1 for US)" })] })), error && (0, jsx_runtime_1.jsx)("div", { className: "text-b3-negative font-neue-montreal-medium py-2 text-sm", children: error }), otpSent ? ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Verification Code" }), (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Enter verification code", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: otp, onChange: e => setOtp(e.target.value), disabled: isLinking && linkingMethod === selectedMethod })] }), (0, jsx_runtime_1.jsx)(button_1.Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleLinkAccount, disabled: !otp || (isLinking && linkingMethod === selectedMethod), children: isLinking && linkingMethod === selectedMethod ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : "Link Account" })] })) : ((0, jsx_runtime_1.jsx)(button_1.Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleSendOTP, disabled: (!email && !phone) || (isLinking && linkingMethod === selectedMethod), children: isLinking && linkingMethod === selectedMethod ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" })) : ("Send Verification Code") }))] }))] }));
228
+ }
@@ -11,11 +11,13 @@ const SignOutIcon_1 = require("../../../../global-account/react/components/icons
11
11
  const SwapIcon_1 = require("../../../../global-account/react/components/icons/SwapIcon");
12
12
  const utils_1 = require("../../../../shared/utils");
13
13
  const formatNumber_1 = require("../../../../shared/utils/formatNumber");
14
+ const thirdweb_1 = require("../../../../shared/utils/thirdweb");
14
15
  const lucide_react_1 = require("lucide-react");
15
16
  const react_2 = require("react");
16
17
  const react_3 = require("thirdweb/react");
17
18
  const viem_1 = require("viem");
18
19
  const useFirstEOA_1 = __importDefault(require("../../hooks/useFirstEOA"));
20
+ const profileDisplay_1 = require("../../utils/profileDisplay");
19
21
  const AccountAssets_1 = require("../AccountAssets/AccountAssets");
20
22
  function centerTruncate(str, length = 4) {
21
23
  if (str.length <= length * 2)
@@ -23,7 +25,6 @@ function centerTruncate(str, length = 4) {
23
25
  return `${str.slice(0, length)}...${str.slice(-length)}`;
24
26
  }
25
27
  function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain, partnerId, }) {
26
- const [activeTab, setActiveTab] = (0, react_2.useState)("balance");
27
28
  const [revokingSignerId, setRevokingSignerId] = (0, react_2.useState)(null);
28
29
  const account = (0, react_3.useActiveAccount)();
29
30
  const { data: assets, isLoading } = (0, react_1.useAccountAssets)(account?.address);
@@ -40,7 +41,8 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
40
41
  chain,
41
42
  accountAddress: account?.address,
42
43
  });
43
- const { setB3ModalOpen, setB3ModalContentType } = (0, react_1.useModalStore)();
44
+ const { setB3ModalOpen, setB3ModalContentType, contentType } = (0, react_1.useModalStore)();
45
+ const { activeTab = "balance", setActiveTab } = contentType;
44
46
  const { logout } = (0, react_1.useAuthentication)(partnerId);
45
47
  const [logoutLoading, setLogoutLoading] = (0, react_2.useState)(false);
46
48
  console.log("account", account);
@@ -87,5 +89,56 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
87
89
  };
88
90
  const AssetsContent = () => ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-3 gap-4", children: assets?.nftResponse ? ((0, jsx_runtime_1.jsx)(AccountAssets_1.AccountAssets, { nfts: assets.nftResponse, isLoading: isLoading })) : ((0, jsx_runtime_1.jsx)("div", { className: "col-span-3 py-12 text-center text-gray-500", children: "No NFTs found" })) }));
89
91
  const AppsContent = () => ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [signers?.map((signer) => ((0, jsx_runtime_1.jsx)("div", { className: "rounded-xl border border-gray-200 p-4 dark:border-gray-800", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-gray-100 dark:bg-gray-800", children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-gray-600 dark:text-gray-400", children: "App" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "font-medium text-gray-900 dark:text-white", children: signer.partner.name }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-2 space-y-1", children: [(0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-500", children: ["Added ", new Date(signer.createdAt).toLocaleDateString()] }), (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-500", children: ["Expires ", new Date(Number(signer.endTimestamp) * 1000).toLocaleDateString()] }), (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-500", children: ["Max spend: ", (0, formatNumber_1.formatNumber)(Number((0, viem_1.formatUnits)(signer.nativeTokenLimitPerTransaction, 18))), " ETH"] })] })] })] }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "outline", size: "sm", className: "border-red-200 text-red-500 hover:border-red-300 hover:text-red-600", onClick: () => handleRevoke(signer), disabled: revokingSignerId === signer.id, children: revokingSignerId === signer.id ? "Revoking..." : "Revoke" })] }) }, signer.id))), !signers?.length && (0, jsx_runtime_1.jsx)("div", { className: "py-12 text-center text-gray-500", children: "No connected apps" })] }));
90
- return ((0, jsx_runtime_1.jsx)("div", { className: "b3-manage-account bg-b3-background flex flex-col rounded-xl", children: (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: (0, jsx_runtime_1.jsxs)(react_1.TabsPrimitive, { defaultValue: activeTab, onValueChange: setActiveTab, children: [(0, jsx_runtime_1.jsxs)(react_1.TabsListPrimitive, { className: "font-neue-montreal-semibold text-b3-grey flex h-8 w-full items-start justify-start gap-8 border-0 text-xl md:p-4", children: [(0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "balance", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Overview" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "assets", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Mints" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "apps", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Apps" })] }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "balance", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(BalanceContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "assets", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(AssetsContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "apps", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(AppsContent, {}) })] }) }) }));
92
+ const SettingsContent = () => {
93
+ const [unlinkingAccountId, setUnlinkingAccountId] = (0, react_2.useState)(null);
94
+ const { data: profilesRaw = [], isLoading: isLoadingProfiles } = (0, react_3.useProfiles)({ client: thirdweb_1.client });
95
+ const { mutate: unlinkProfile, isPending: isUnlinking } = (0, react_3.useUnlinkProfile)();
96
+ const { setB3ModalOpen, setB3ModalContentType, isLinking } = (0, react_1.useModalStore)();
97
+ const profiles = profilesRaw
98
+ .filter((profile) => !["custom_auth_endpoint", "siwe"].includes(profile.type))
99
+ .map((profile) => ({
100
+ ...(0, profileDisplay_1.getProfileDisplayInfo)(profile),
101
+ originalProfile: profile,
102
+ }));
103
+ const handleUnlink = async (profile) => {
104
+ setUnlinkingAccountId(profile.title);
105
+ try {
106
+ await unlinkProfile({
107
+ client: thirdweb_1.client,
108
+ profileToUnlink: profile.originalProfile,
109
+ });
110
+ }
111
+ catch (error) {
112
+ console.error("Error unlinking account:", error);
113
+ }
114
+ finally {
115
+ setUnlinkingAccountId(null);
116
+ }
117
+ };
118
+ const handleOpenLinkModal = () => {
119
+ setB3ModalOpen(true);
120
+ setB3ModalContentType({
121
+ type: "linkAccount",
122
+ showBackButton: true,
123
+ partnerId,
124
+ chain,
125
+ onSuccess: async () => {
126
+ // Let the LinkAccount component handle modal closing
127
+ },
128
+ onError: () => {
129
+ // Let the LinkAccount component handle errors
130
+ },
131
+ onClose: () => {
132
+ // Let the LinkAccount component handle closing
133
+ },
134
+ });
135
+ };
136
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-8", children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), (0, jsx_runtime_1.jsxs)(react_1.Button, { className: "bg-b3-primary-wash hover:bg-b3-primary-wash/70 flex items-center gap-2 rounded-full px-4 py-2", onClick: handleOpenLinkModal, disabled: isLinking, children: [isLinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.LinkIcon, { size: 16, className: "text-b3-primary-blue" })), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center py-8", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: profiles.map(profile => ((0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? ((0, jsx_runtime_1.jsx)("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : ((0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium bg-b3-primary-wash rounded px-2 py-0.5 text-xs", children: profile.type.toUpperCase() })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "ghost", size: "icon", className: "text-b3-grey hover:text-b3-negative", onClick: () => handleUnlink(profile), disabled: unlinkingAccountId === profile.title || isUnlinking, children: unlinkingAccountId === profile.title || isUnlinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Account Preferences" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line rounded-xl p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Dark Mode" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Switch between light and dark theme" })] }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash h-6 w-12 rounded-full" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), (0, jsx_runtime_1.jsx)("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3-powered apps" })] }), (0, jsx_runtime_1.jsx)("button", { className: "text-b3-grey hover:text-b3-grey/80 hover:bg-b3-line border-b3-line flex size-12 items-center justify-center rounded-full border", onClick: onLogoutEnhanced, children: logoutLoading ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : (0, jsx_runtime_1.jsx)(SignOutIcon_1.SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
137
+ };
138
+ return ((0, jsx_runtime_1.jsx)("div", { className: "b3-manage-account bg-b3-background flex flex-col rounded-xl", children: (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: (0, jsx_runtime_1.jsxs)(react_1.TabsPrimitive, { defaultValue: activeTab, onValueChange: value => {
139
+ const tab = value;
140
+ if (["balance", "assets", "apps", "settings"].includes(tab)) {
141
+ setActiveTab?.(tab);
142
+ }
143
+ }, children: [(0, jsx_runtime_1.jsxs)(react_1.TabsListPrimitive, { className: "font-neue-montreal-semibold text-b3-grey flex h-8 w-full items-start justify-start gap-8 border-0 text-xl md:p-4", children: [(0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "balance", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Overview" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "assets", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Mints" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "apps", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Apps" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "settings", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Settings" })] }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "balance", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(BalanceContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "assets", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(AssetsContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "apps", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(AppsContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "settings", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(SettingsContent, {}) })] }) }) }));
91
144
  }
@@ -17,7 +17,7 @@ function LoginStepContainer({ children, partnerId }) {
17
17
  },
18
18
  }, !!partnerId);
19
19
  const partnerLogo = partner?.data?.[0]?.loginCustomization?.logoUrl;
20
- return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center", children: [partnerLogo && (0, jsx_runtime_1.jsx)("img", { src: partnerLogo, alt: "Partner Logo", className: "mb-6 mt-6 h-12 w-auto object-contain" }), children, (0, jsx_runtime_1.jsxs)("h2", { className: "mt-6 flex items-center gap-2 text-lg font-bold", children: ["Powered by", (0, jsx_runtime_1.jsx)("img", { alt: "B3 Logo", className: "h-5", src: "https://cdn.b3.fun/b3_logo.svg" }), "Connect"] })] }));
20
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center", children: [partnerLogo && ((0, jsx_runtime_1.jsx)("img", { src: partnerLogo, alt: "Partner Logo", className: "partner-logo mb-6 mt-6 h-12 w-auto object-contain" })), children, (0, jsx_runtime_1.jsxs)("h2", { className: "mt-6 flex items-center gap-2 text-lg font-bold", children: ["Powered by", (0, jsx_runtime_1.jsx)("img", { alt: "B3 Logo", className: "h-5", src: "https://cdn.b3.fun/b3_logo.svg" }), "Connect"] })] }));
21
21
  }
22
22
  function LoginStep({ onSuccess, onError, partnerId, chain }) {
23
23
  const wallet = (0, wallets_1.ecosystemWallet)(constants_1.ecosystemWalletId, {
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  declare const buttonVariants: (props?: ({
3
3
  variant?: "link" | "default" | "b3" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
4
- size?: "default" | "icon" | "sm" | "lg" | null | undefined;
4
+ size?: "default" | "sm" | "lg" | "icon" | null | undefined;
5
5
  } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
6
6
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
7
7
  variant?: "default" | "outline";
@@ -2,7 +2,7 @@ import { type VariantProps } from "class-variance-authority";
2
2
  import * as React from "react";
3
3
  declare const buttonVariants: (props?: ({
4
4
  variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
5
- size?: "default" | "icon" | "sm" | "lg" | null | undefined;
5
+ size?: "default" | "sm" | "lg" | "icon" | null | undefined;
6
6
  } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
7
7
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
8
8
  asChild?: boolean;
@@ -40,9 +40,14 @@ function useUnifiedChainSwitchAndExecute() {
40
40
  if (!signer) {
41
41
  throw new Error("No account connected");
42
42
  }
43
+ // Get the target chain configuration instead of using potentially stale walletClient.chain
44
+ const targetChain = supported_1.supportedChains.find(chain => chain.id === targetChainId);
45
+ if (!targetChain) {
46
+ throw new Error(`Chain ${targetChainId} is not supported`);
47
+ }
43
48
  const hash = await walletClient.sendTransaction({
44
49
  account: signer,
45
- chain: walletClient.chain,
50
+ chain: targetChain,
46
51
  to: params.to,
47
52
  data: params.data,
48
53
  value: params.value,
@@ -55,7 +60,7 @@ function useUnifiedChainSwitchAndExecute() {
55
60
  if (onCorrectChain) {
56
61
  return await executeTransaction();
57
62
  }
58
- sonner_1.toast.info(`Switching to ${(0, anyspend_1.getChainName)(targetChainId)}…`);
63
+ const switchingToastId = sonner_1.toast.info(`Switching to ${(0, anyspend_1.getChainName)(targetChainId)}…`);
59
64
  const targetChain = supported_1.supportedChains.find(chain => chain.id === targetChainId);
60
65
  if (!targetChain) {
61
66
  sonner_1.toast.error(`Chain ${targetChainId} is not supported`);
@@ -77,6 +82,7 @@ function useUnifiedChainSwitchAndExecute() {
77
82
  },
78
83
  },
79
84
  });
85
+ sonner_1.toast.dismiss(switchingToastId);
80
86
  return await executeTransaction();
81
87
  }
82
88
  catch (e) {
@@ -78,6 +78,10 @@ export interface ManageAccountModalProps extends BaseModalProps {
78
78
  chain: Chain;
79
79
  /** Partner ID */
80
80
  partnerId: string;
81
+ /** Active Tab */
82
+ activeTab?: "balance" | "assets" | "apps" | "settings";
83
+ /** Function to set the active tab */
84
+ setActiveTab?: (tab: "balance" | "assets" | "apps" | "settings") => void;
81
85
  }
82
86
  /**
83
87
  * Props for the AnySpend modal
@@ -274,10 +278,19 @@ export interface AnySpendBondKitProps extends BaseModalProps {
274
278
  /** Callback function called when purchase is successful */
275
279
  onSuccess?: (txHash?: string) => void;
276
280
  }
281
+ export interface LinkAccountModalProps extends BaseModalProps {
282
+ type: "linkAccount";
283
+ showBackButton?: boolean;
284
+ onSuccess?: () => void;
285
+ onError?: (error: Error) => void;
286
+ onClose?: () => void;
287
+ partnerId: string;
288
+ chain: Chain;
289
+ }
277
290
  /**
278
291
  * Union type of all possible modal content types
279
292
  */
280
- export type ModalContentType = SignInWithB3ModalProps | RequestPermissionsModalProps | ManageAccountModalProps | AnySpendModalProps | AnyspendOrderDetailsProps | AnySpendNftProps | AnySpendJoinTournamentProps | AnySpendFundTournamentProps | TransakProps | AnySpendOrderHistoryProps | AnySpendStakeB3Props | AnySpendBuySpinProps | AnySpendSignatureMintProps | AnySpendBondKitProps;
293
+ export type ModalContentType = SignInWithB3ModalProps | RequestPermissionsModalProps | ManageAccountModalProps | AnySpendModalProps | AnyspendOrderDetailsProps | AnySpendNftProps | AnySpendJoinTournamentProps | AnySpendFundTournamentProps | TransakProps | AnySpendOrderHistoryProps | AnySpendStakeB3Props | AnySpendBuySpinProps | AnySpendSignatureMintProps | AnySpendBondKitProps | LinkAccountModalProps;
281
294
  /**
282
295
  * State interface for the modal store
283
296
  */
@@ -300,6 +313,12 @@ interface ModalState {
300
313
  ecoSystemAccountAddress?: Address;
301
314
  /** Function to set the ecosystem account address */
302
315
  setEcoSystemAccountAddress: (address: Address) => void;
316
+ /** Whether an account linking operation is in progress */
317
+ isLinking: boolean;
318
+ /** The method currently being linked */
319
+ linkingMethod: string | null;
320
+ /** Function to set the linking state */
321
+ setLinkingState: (isLinking: boolean, method?: string | null) => void;
303
322
  }
304
323
  /**
305
324
  * Zustand store for managing modal state
@@ -33,4 +33,7 @@ exports.useModalStore = (0, zustand_1.create)(set => ({
33
33
  clearHistory: () => set({ history: [] }),
34
34
  ecoSystemAccountAddress: undefined,
35
35
  setEcoSystemAccountAddress: (address) => set({ ecoSystemAccountAddress: address }),
36
+ isLinking: false,
37
+ linkingMethod: null,
38
+ setLinkingState: (isLinking, method = null) => set({ isLinking, linkingMethod: isLinking ? method : null }),
36
39
  }));