@b3dotfun/sdk 0.0.80 → 0.0.81-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 (25) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +23 -10
  2. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +22 -6
  3. package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.d.ts +4 -0
  4. package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.js +14 -7
  5. package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +7 -1
  6. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -1
  7. package/dist/cjs/global-account/react/hooks/useUserQuery.d.ts +2 -2
  8. package/dist/cjs/global-account/react/hooks/useUserQuery.js +76 -55
  9. package/dist/esm/anyspend/react/components/AnySpend.js +23 -10
  10. package/dist/esm/anyspend/react/components/AnySpendCustom.js +23 -7
  11. package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.d.ts +4 -0
  12. package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.js +13 -6
  13. package/dist/esm/anyspend/react/components/common/PanelOnramp.js +8 -2
  14. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -1
  15. package/dist/esm/global-account/react/hooks/useUserQuery.d.ts +2 -2
  16. package/dist/esm/global-account/react/hooks/useUserQuery.js +76 -55
  17. package/dist/types/anyspend/react/components/common/FiatPaymentMethod.d.ts +4 -0
  18. package/dist/types/global-account/react/hooks/useUserQuery.d.ts +2 -2
  19. package/package.json +1 -1
  20. package/src/anyspend/react/components/AnySpend.tsx +24 -10
  21. package/src/anyspend/react/components/AnySpendCustom.tsx +42 -33
  22. package/src/anyspend/react/components/common/FiatPaymentMethod.tsx +14 -6
  23. package/src/anyspend/react/components/common/PanelOnramp.tsx +23 -27
  24. package/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx +1 -1
  25. package/src/global-account/react/hooks/useUserQuery.ts +82 -54
@@ -362,18 +362,18 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
362
362
  isBalanceLoading,
363
363
  });
364
364
  // Get geo-based onramp options for fiat payments
365
- const { geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support } = (0, react_1.useGeoOnrampOptions)(srcAmountOnRamp);
365
+ const { geoData, coinbaseAvailablePaymentMethods, stripeOnrampSupport, stripeWeb2Support } = (0, react_1.useGeoOnrampOptions)(srcAmountOnRamp);
366
366
  // Helper function to map payment method to onramp vendor
367
367
  const getOnrampVendor = (paymentMethod) => {
368
368
  switch (paymentMethod) {
369
369
  case FiatPaymentMethod_1.FiatPaymentMethod.COINBASE_PAY:
370
370
  return "coinbase";
371
371
  case FiatPaymentMethod_1.FiatPaymentMethod.STRIPE:
372
- // Determine if it's stripe onramp or stripe-web2 based on support
373
- if (stripeWeb2Support?.isSupport) {
374
- return "stripe-web2";
375
- }
376
- return undefined;
372
+ // Stripe redirect flow (one-click URL)
373
+ return stripeOnrampSupport ? "stripe" : undefined;
374
+ case FiatPaymentMethod_1.FiatPaymentMethod.STRIPE_WEB2:
375
+ // Stripe embedded payment form
376
+ return stripeWeb2Support?.isSupport ? "stripe-web2" : undefined;
377
377
  default:
378
378
  return undefined;
379
379
  }
@@ -518,7 +518,9 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
518
518
  }, [activeTab, selectedSrcChainId, selectedDstChainId, selectedSrcToken.address, selectedDstToken.address]);
519
519
  // Determine button state and text
520
520
  const btnInfo = (0, react_4.useMemo)(() => {
521
- if (activeInputAmountInWei === "0")
521
+ // For fiat tab, check srcAmountOnRamp; for crypto tab, check activeInputAmountInWei
522
+ const hasAmount = activeTab === "fiat" ? srcAmountOnRamp && parseFloat(srcAmountOnRamp) > 0 : activeInputAmountInWei !== "0";
523
+ if (!hasAmount)
522
524
  return { text: "Enter an amount", disable: true, error: false, loading: false };
523
525
  if (isSameChainSameToken)
524
526
  return { text: "Select a different token or chain", disable: true, error: false, loading: false };
@@ -569,6 +571,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
569
571
  activeTab,
570
572
  effectiveCryptoPaymentMethod,
571
573
  selectedFiatPaymentMethod,
574
+ srcAmountOnRamp,
572
575
  ]);
573
576
  // Handle main button click
574
577
  const onMainButtonClick = async () => {
@@ -683,11 +686,21 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
683
686
  paymentMethodString = coinbaseAvailablePaymentMethods[0]?.id || ""; // Use first available payment method ID
684
687
  }
685
688
  else if (paymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.STRIPE) {
686
- if (!stripeWeb2Support || !stripeWeb2Support.isSupport) {
687
- react_2.toast.error("Stripe not available");
689
+ // Stripe redirect flow (one-click URL)
690
+ if (!stripeOnrampSupport) {
691
+ react_2.toast.error("Credit/Debit Card not available");
692
+ return;
693
+ }
694
+ vendor = "stripe";
695
+ paymentMethodString = "";
696
+ }
697
+ else if (paymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.STRIPE_WEB2) {
698
+ // Stripe embedded payment form
699
+ if (!stripeWeb2Support.isSupport) {
700
+ react_2.toast.error("Pay with Card not available");
688
701
  return;
689
702
  }
690
- vendor = stripeWeb2Support && stripeWeb2Support.isSupport ? "stripe-web2" : "stripe";
703
+ vendor = "stripe-web2";
691
704
  paymentMethodString = "";
692
705
  }
693
706
  else {
@@ -236,7 +236,11 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
236
236
  contractType: orderType === "mint_nft" ? metadata?.nftContract?.type : undefined,
237
237
  encodedData: encodedData,
238
238
  spenderAddress: spenderAddress,
239
- onrampVendor: selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.STRIPE ? "stripe-web2" : undefined,
239
+ onrampVendor: selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.STRIPE
240
+ ? "stripe"
241
+ : selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.STRIPE_WEB2
242
+ ? "stripe-web2"
243
+ : undefined,
240
244
  });
241
245
  }, [
242
246
  activeTab,
@@ -578,7 +582,13 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
578
582
  opacity: hasMounted ? 1 : 0,
579
583
  y: hasMounted ? 0 : 20,
580
584
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
581
- }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, className: "relative flex w-full items-center justify-between", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-tertiarry flex h-7 items-center text-sm", children: "Pay with" }), (0, jsx_runtime_1.jsx)("button", { className: "text-as-tertiarry flex flex-wrap items-center justify-end gap-2 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(PanelView.FIAT_PAYMENT_METHOD), children: selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.COINBASE_PAY ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 whitespace-nowrap", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-600", children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-bold text-white", children: "C" }) }), "Coinbase Pay"] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4 shrink-0" })] })) : selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.STRIPE ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 whitespace-nowrap", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-600", children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-bold text-white", children: "S" }) }), "Credit/Debit Card"] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4 shrink-0" })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "whitespace-nowrap", children: "Select payment method" }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4 shrink-0" })] })) })] }), (0, jsx_runtime_1.jsx)("div", { className: "divider w-full" }), recipientSection, (0, jsx_runtime_1.jsx)("div", { className: "divider w-full" }), (0, jsx_runtime_1.jsxs)(react_4.motion.div, { initial: false, animate: {
585
+ }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, className: "relative flex w-full items-center justify-between", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-tertiarry flex h-7 items-center text-sm", children: "Pay with" }), (0, jsx_runtime_1.jsx)("button", { className: "text-as-tertiarry flex flex-wrap items-center justify-end gap-2 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(PanelView.FIAT_PAYMENT_METHOD), children: (() => {
586
+ const config = FiatPaymentMethod_1.FIAT_PAYMENT_METHOD_DISPLAY[selectedFiatPaymentMethod];
587
+ if (config) {
588
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 whitespace-nowrap", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-600", children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-bold text-white", children: config.icon }) }), config.label] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4 shrink-0" })] }));
589
+ }
590
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "whitespace-nowrap", children: "Select payment method" }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4 shrink-0" })] }));
591
+ })() })] }), (0, jsx_runtime_1.jsx)("div", { className: "divider w-full" }), recipientSection, (0, jsx_runtime_1.jsx)("div", { className: "divider w-full" }), (0, jsx_runtime_1.jsxs)(react_4.motion.div, { initial: false, animate: {
582
592
  opacity: hasMounted ? 1 : 0,
583
593
  y: hasMounted ? 0 : 20,
584
594
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
@@ -618,11 +628,17 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
618
628
  setSelectedCryptoPaymentMethod(method);
619
629
  setActivePanel(PanelView.CONFIRM_ORDER);
620
630
  } }) }));
631
+ // Stable callback for fiat payment method selection
632
+ const handleFiatPaymentMethodSelect = (0, react_5.useCallback)((method) => {
633
+ setSelectedFiatPaymentMethod(method);
634
+ setActivePanel(PanelView.CONFIRM_ORDER);
635
+ }, []);
636
+ // Stable callback for navigating back to confirm order
637
+ const handleBackToConfirmOrder = (0, react_5.useCallback)(() => {
638
+ setActivePanel(PanelView.CONFIRM_ORDER);
639
+ }, []);
621
640
  // Fiat payment method view
622
- const fiatPaymentMethodView = ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: (0, jsx_runtime_1.jsx)(FiatPaymentMethod_1.FiatPaymentMethodComponent, { selectedPaymentMethod: selectedFiatPaymentMethod, setSelectedPaymentMethod: setSelectedFiatPaymentMethod, onBack: () => setActivePanel(PanelView.CONFIRM_ORDER), onSelectPaymentMethod: (method) => {
623
- setSelectedFiatPaymentMethod(method);
624
- setActivePanel(PanelView.CONFIRM_ORDER);
625
- }, srcAmountOnRamp: srcFiatAmount }) }));
641
+ const fiatPaymentMethodView = ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: (0, jsx_runtime_1.jsx)(FiatPaymentMethod_1.FiatPaymentMethodComponent, { selectedPaymentMethod: selectedFiatPaymentMethod, setSelectedPaymentMethod: setSelectedFiatPaymentMethod, onBack: handleBackToConfirmOrder, onSelectPaymentMethod: handleFiatPaymentMethodSelect, srcAmountOnRamp: srcFiatAmount }) }));
626
642
  // Points detail view
627
643
  const pointsDetailView = ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: (0, jsx_runtime_1.jsx)(PointsDetailPanel_1.PointsDetailPanel, { pointsAmount: anyspendQuote?.data?.pointsAmount || 0, onBack: () => setActivePanel(PanelView.CONFIRM_ORDER) }) }));
628
644
  // Return the TransitionPanel with all views
@@ -4,6 +4,10 @@ export declare enum FiatPaymentMethod {
4
4
  STRIPE = "stripe",// Stripe redirect (one-click buy URL)
5
5
  STRIPE_WEB2 = "stripe_web2"
6
6
  }
7
+ export declare const FIAT_PAYMENT_METHOD_DISPLAY: Record<FiatPaymentMethod, {
8
+ icon: string;
9
+ label: string;
10
+ } | null>;
7
11
  interface FiatPaymentMethodProps {
8
12
  selectedPaymentMethod: FiatPaymentMethod;
9
13
  setSelectedPaymentMethod: (method: FiatPaymentMethod) => void;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  "use client";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.FiatPaymentMethod = void 0;
4
+ exports.FIAT_PAYMENT_METHOD_DISPLAY = exports.FiatPaymentMethod = void 0;
5
5
  exports.FiatPaymentMethodComponent = FiatPaymentMethodComponent;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("../../../../anyspend/react");
@@ -14,6 +14,13 @@ var FiatPaymentMethod;
14
14
  FiatPaymentMethod["STRIPE"] = "stripe";
15
15
  FiatPaymentMethod["STRIPE_WEB2"] = "stripe_web2";
16
16
  })(FiatPaymentMethod || (exports.FiatPaymentMethod = FiatPaymentMethod = {}));
17
+ // Shared display config for fiat payment methods
18
+ exports.FIAT_PAYMENT_METHOD_DISPLAY = {
19
+ [FiatPaymentMethod.COINBASE_PAY]: { icon: "C", label: "Coinbase Pay" },
20
+ [FiatPaymentMethod.STRIPE]: { icon: "S", label: "Pay via Stripe" },
21
+ [FiatPaymentMethod.STRIPE_WEB2]: { icon: "S", label: "Pay with Card" },
22
+ [FiatPaymentMethod.NONE]: null,
23
+ };
17
24
  function FiatPaymentMethodComponent({ selectedPaymentMethod, setSelectedPaymentMethod, onBack, onSelectPaymentMethod, srcAmountOnRamp, }) {
18
25
  // Load geo-based onramp options like in PanelOnramp
19
26
  const { coinbaseAvailablePaymentMethods, stripeOnrampSupport, stripeWeb2Support, isLoading: isLoadingGeoOnramp, } = (0, react_1.useGeoOnrampOptions)(srcAmountOnRamp);
@@ -50,25 +57,25 @@ function FiatPaymentMethodComponent({ selectedPaymentMethod, setSelectedPaymentM
50
57
  available: true,
51
58
  });
52
59
  }
53
- // Add Stripe redirect (one-click) if available - primary option
60
+ // Add Stripe redirect (one-click) if available - redirects to Stripe checkout
54
61
  if (stripeOnrampSupport) {
55
62
  const stripeFee = getFeeFromApi(FiatPaymentMethod.STRIPE_WEB2); // Use same fee estimate
56
63
  availablePaymentMethods.push({
57
64
  id: FiatPaymentMethod.STRIPE,
58
- name: "Credit/Debit Card",
59
- description: "Pay via Stripe checkout",
65
+ name: "Pay via Stripe",
66
+ description: "Redirects to Stripe checkout",
60
67
  badge: stripeFee ? `$${Number(stripeFee).toFixed(2)} fee` : undefined,
61
68
  badgeColor: "bg-gray-100 text-gray-800",
62
69
  available: true,
63
70
  });
64
71
  }
65
- // Add Stripe Web2 (embedded) if available - secondary option
72
+ // Add Stripe Web2 (embedded) if available - embedded card form
66
73
  if (stripeWeb2Support && stripeWeb2Support.isSupport) {
67
74
  const stripeFee = getFeeFromApi(FiatPaymentMethod.STRIPE_WEB2);
68
75
  availablePaymentMethods.push({
69
76
  id: FiatPaymentMethod.STRIPE_WEB2,
70
- name: "Quick Pay",
71
- description: "Credit or debit card",
77
+ name: "Pay with Card",
78
+ description: "Fast checkout",
72
79
  badge: stripeFee ? `$${Number(stripeFee).toFixed(2)} fee` : undefined,
73
80
  badgeColor: "bg-gray-100 text-gray-800",
74
81
  available: true,
@@ -78,7 +78,13 @@ function PanelOnramp({ srcAmountOnRamp, setSrcAmountOnRamp, selectedPaymentMetho
78
78
  const handleQuickAmount = (value) => {
79
79
  setSrcAmountOnRamp(value);
80
80
  };
81
- return ((0, jsx_runtime_1.jsxs)("div", { className: "panel-onramp bg-as-surface-primary flex w-full flex-col", children: [(0, jsx_runtime_1.jsxs)("div", { className: "border-as-border-secondary bg-as-surface-secondary relative flex w-full flex-col rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex h-7 w-full items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-tertiarry flex items-center text-sm font-bold", children: "Pay" }), (0, jsx_runtime_1.jsx)("button", { className: "text-as-tertiarry flex h-7 items-center gap-1 text-sm", onClick: () => setActivePanel(fiatPaymentMethodIndex), children: selectedPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.COINBASE_PAY ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-blue-600", children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-bold text-white", children: "C" }) }), "Coinbase Pay"] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4" })] })) : selectedPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.STRIPE ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-blue-600", children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-bold text-white", children: "S" }) }), "Stripe"] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4" })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Select payment method", (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4" })] })) })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center pb-2 pt-8", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-tertiarry text-2xl font-bold", children: "$" }), (0, jsx_runtime_1.jsx)(react_2.Input, { ref: amountInputRef, type: "text", value: srcAmountOnRamp, onChange: handleAmountChange, placeholder: "5", className: "text-as-primary placeholder:text-as-primary/50 h-auto border-0 bg-transparent p-0 px-1 pt-1 text-4xl font-bold focus-visible:ring-0 focus-visible:ring-offset-0", style: {
81
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "panel-onramp bg-as-surface-primary flex w-full flex-col", children: [(0, jsx_runtime_1.jsxs)("div", { className: "border-as-border-secondary bg-as-surface-secondary relative flex w-full flex-col rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex h-7 w-full items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-tertiarry flex items-center text-sm font-bold", children: "Pay" }), (0, jsx_runtime_1.jsx)("button", { className: "text-as-tertiarry flex h-7 items-center gap-1 text-sm", onClick: () => setActivePanel(fiatPaymentMethodIndex), children: (() => {
82
+ const config = selectedPaymentMethod ? FiatPaymentMethod_1.FIAT_PAYMENT_METHOD_DISPLAY[selectedPaymentMethod] : null;
83
+ if (config) {
84
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-blue-600", children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-bold text-white", children: config.icon }) }), config.label] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4" })] }));
85
+ }
86
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Select payment method", (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4" })] }));
87
+ })() })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center pb-2 pt-8", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-tertiarry text-2xl font-bold", children: "$" }), (0, jsx_runtime_1.jsx)(react_2.Input, { ref: amountInputRef, type: "text", value: srcAmountOnRamp, onChange: handleAmountChange, placeholder: "5", className: "text-as-primary placeholder:text-as-primary/50 h-auto border-0 bg-transparent p-0 px-1 pt-1 text-4xl font-bold focus-visible:ring-0 focus-visible:ring-offset-0", style: {
82
88
  width: `${Math.max(ONE_CHAR_WIDTH, srcAmountOnRamp.length * ONE_CHAR_WIDTH)}px`,
83
89
  } })] }) }), (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("mx-auto mb-6 flex justify-center gap-2", hideDstToken && "mb-0"), children: customUsdInputValues
84
90
  .filter(v => !isNaN(Number(v)))
@@ -165,7 +165,7 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
165
165
  isOpen,
166
166
  source,
167
167
  });
168
- if (isConnected && isAuthenticated) {
168
+ if (isConnected && isAuthenticated && user) {
169
169
  // Mark that login just completed BEFORE opening manage account or closing modal
170
170
  // This allows Turnkey modal to show (if enableTurnkey is true)
171
171
  if (closeAfterLogin) {
@@ -2,7 +2,7 @@ import { Users } from "@b3dotfun/b3-api";
2
2
  /**
3
3
  * NOTE: THIS IS ONLY MEANT FOR INTERNAL USE, from useOnConnect
4
4
  *
5
- * Custom hook to manage user state with react-query
5
+ * Custom hook to manage user state with Zustand
6
6
  * This allows for invalidation and refetching of user data
7
7
  */
8
8
  export declare function useUserQuery(): {
@@ -59,7 +59,7 @@ export declare function useUserQuery(): {
59
59
  };
60
60
  } | undefined;
61
61
  setUser: (newUser?: Users) => void;
62
- refetchUser: () => Promise<void>;
62
+ refetchUser: () => Promise<any>;
63
63
  clearUser: () => void;
64
64
  queryKey: string[];
65
65
  };
@@ -2,79 +2,100 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useUserQuery = useUserQuery;
4
4
  const debug_1 = require("../../../shared/utils/debug");
5
- const react_query_1 = require("@tanstack/react-query");
5
+ const react_1 = require("react");
6
+ const zustand_1 = require("zustand");
7
+ const middleware_1 = require("zustand/middleware");
6
8
  const debug = (0, debug_1.debugB3React)("useUserQuery");
7
9
  const USER_QUERY_KEY = ["b3-user"];
8
10
  /**
9
- * Retrieves the user from localStorage
11
+ * Zustand store for managing user state
12
+ * Persists user data to localStorage
10
13
  */
11
- function getUserFromStorage() {
12
- if (typeof window === "undefined") {
13
- return null;
14
- }
15
- try {
16
- const storedUser = localStorage.getItem("b3-user");
17
- return storedUser ? JSON.parse(storedUser) : null;
18
- }
19
- catch (error) {
20
- console.warn("Failed to restore user from localStorage:", error);
21
- return null;
22
- }
23
- }
24
- /**
25
- * Saves user to localStorage
26
- */
27
- function saveUserToStorage(user) {
28
- if (typeof window === "undefined") {
29
- return;
30
- }
31
- if (user) {
32
- localStorage.setItem("b3-user", JSON.stringify(user));
33
- }
34
- else {
35
- localStorage.removeItem("b3-user");
36
- }
37
- }
14
+ const useUserStore = (0, zustand_1.create)()((0, middleware_1.persist)(set => ({
15
+ user: null,
16
+ setUser: (newUser) => {
17
+ const userToSave = newUser ?? null;
18
+ set({ user: userToSave });
19
+ debug("User updated", userToSave);
20
+ },
21
+ clearUser: () => {
22
+ set({ user: null });
23
+ debug("User cleared");
24
+ },
25
+ }), {
26
+ name: "b3-user",
27
+ onRehydrateStorage: () => (_, error) => {
28
+ if (error) {
29
+ console.warn("Failed to rehydrate user store:", error);
30
+ }
31
+ },
32
+ }));
38
33
  /**
39
34
  * NOTE: THIS IS ONLY MEANT FOR INTERNAL USE, from useOnConnect
40
35
  *
41
- * Custom hook to manage user state with react-query
36
+ * Custom hook to manage user state with Zustand
42
37
  * This allows for invalidation and refetching of user data
43
38
  */
44
39
  function useUserQuery() {
45
- const queryClient = (0, react_query_1.useQueryClient)();
46
- // Query to get user data (primarily from cache/localStorage)
47
- const { data: user } = (0, react_query_1.useQuery)({
48
- queryKey: USER_QUERY_KEY,
49
- queryFn: getUserFromStorage,
50
- staleTime: Infinity, // User data doesn't go stale automatically
51
- gcTime: Infinity, // Keep in cache indefinitely
52
- initialData: getUserFromStorage,
53
- });
54
- // Mutation to update user
55
- const setUserMutation = (0, react_query_1.useMutation)({
56
- mutationFn: async (newUser) => {
57
- const userToSave = newUser ?? null;
58
- saveUserToStorage(userToSave);
59
- return userToSave;
60
- },
61
- onSuccess: data => {
62
- queryClient.setQueryData(USER_QUERY_KEY, data);
63
- debug("User updated", data);
64
- },
65
- });
40
+ const user = useUserStore(state => state.user);
41
+ const setUserStore = useUserStore(state => state.setUser);
42
+ const clearUserStore = useUserStore(state => state.clearUser);
43
+ // Listen for storage events from other tabs/windows
44
+ (0, react_1.useEffect)(() => {
45
+ const handleStorageChange = (e) => {
46
+ if (e.key === "b3-user") {
47
+ // Sync with changes from other tabs/windows
48
+ const stored = e.newValue;
49
+ if (stored) {
50
+ try {
51
+ const parsed = JSON.parse(stored);
52
+ // Zustand persist format: { state: { user: ... }, version: ... }
53
+ const userData = parsed?.state?.user ?? parsed?.user ?? null;
54
+ useUserStore.setState({ user: userData });
55
+ }
56
+ catch (error) {
57
+ console.warn("Failed to parse user from storage event:", error);
58
+ }
59
+ }
60
+ else {
61
+ useUserStore.setState({ user: null });
62
+ }
63
+ }
64
+ };
65
+ window.addEventListener("storage", handleStorageChange);
66
+ return () => {
67
+ window.removeEventListener("storage", handleStorageChange);
68
+ };
69
+ }, []);
66
70
  // Helper function to set user (maintains backward compatibility)
67
71
  const setUser = (newUser) => {
68
- setUserMutation.mutate(newUser);
72
+ setUserStore(newUser);
69
73
  };
70
74
  // Helper function to invalidate and refetch user
71
75
  const refetchUser = async () => {
72
- await queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
73
- return queryClient.refetchQueries({ queryKey: USER_QUERY_KEY });
76
+ // Re-read from localStorage and update store
77
+ // Zustand persist stores data as { state: { user: ... }, version: ... }
78
+ const stored = localStorage.getItem("b3-user");
79
+ if (stored) {
80
+ try {
81
+ const parsed = JSON.parse(stored);
82
+ // Zustand persist format: { state: { user: ... }, version: ... }
83
+ const userData = parsed?.state?.user ?? parsed?.user ?? null;
84
+ useUserStore.setState({ user: userData });
85
+ return userData ?? undefined;
86
+ }
87
+ catch (error) {
88
+ console.warn("Failed to refetch user from localStorage:", error);
89
+ // Fallback to current store state
90
+ return useUserStore.getState().user ?? undefined;
91
+ }
92
+ }
93
+ useUserStore.setState({ user: null });
94
+ return undefined;
74
95
  };
75
96
  // Helper function to clear user
76
97
  const clearUser = () => {
77
- setUser(undefined);
98
+ clearUserStore();
78
99
  };
79
100
  return {
80
101
  user: user ?? undefined,
@@ -355,18 +355,18 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
355
355
  isBalanceLoading,
356
356
  });
357
357
  // Get geo-based onramp options for fiat payments
358
- const { geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support } = useGeoOnrampOptions(srcAmountOnRamp);
358
+ const { geoData, coinbaseAvailablePaymentMethods, stripeOnrampSupport, stripeWeb2Support } = useGeoOnrampOptions(srcAmountOnRamp);
359
359
  // Helper function to map payment method to onramp vendor
360
360
  const getOnrampVendor = (paymentMethod) => {
361
361
  switch (paymentMethod) {
362
362
  case FiatPaymentMethod.COINBASE_PAY:
363
363
  return "coinbase";
364
364
  case FiatPaymentMethod.STRIPE:
365
- // Determine if it's stripe onramp or stripe-web2 based on support
366
- if (stripeWeb2Support?.isSupport) {
367
- return "stripe-web2";
368
- }
369
- return undefined;
365
+ // Stripe redirect flow (one-click URL)
366
+ return stripeOnrampSupport ? "stripe" : undefined;
367
+ case FiatPaymentMethod.STRIPE_WEB2:
368
+ // Stripe embedded payment form
369
+ return stripeWeb2Support?.isSupport ? "stripe-web2" : undefined;
370
370
  default:
371
371
  return undefined;
372
372
  }
@@ -511,7 +511,9 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
511
511
  }, [activeTab, selectedSrcChainId, selectedDstChainId, selectedSrcToken.address, selectedDstToken.address]);
512
512
  // Determine button state and text
513
513
  const btnInfo = useMemo(() => {
514
- if (activeInputAmountInWei === "0")
514
+ // For fiat tab, check srcAmountOnRamp; for crypto tab, check activeInputAmountInWei
515
+ const hasAmount = activeTab === "fiat" ? srcAmountOnRamp && parseFloat(srcAmountOnRamp) > 0 : activeInputAmountInWei !== "0";
516
+ if (!hasAmount)
515
517
  return { text: "Enter an amount", disable: true, error: false, loading: false };
516
518
  if (isSameChainSameToken)
517
519
  return { text: "Select a different token or chain", disable: true, error: false, loading: false };
@@ -562,6 +564,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
562
564
  activeTab,
563
565
  effectiveCryptoPaymentMethod,
564
566
  selectedFiatPaymentMethod,
567
+ srcAmountOnRamp,
565
568
  ]);
566
569
  // Handle main button click
567
570
  const onMainButtonClick = async () => {
@@ -676,11 +679,21 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
676
679
  paymentMethodString = coinbaseAvailablePaymentMethods[0]?.id || ""; // Use first available payment method ID
677
680
  }
678
681
  else if (paymentMethod === FiatPaymentMethod.STRIPE) {
679
- if (!stripeWeb2Support || !stripeWeb2Support.isSupport) {
680
- toast.error("Stripe not available");
682
+ // Stripe redirect flow (one-click URL)
683
+ if (!stripeOnrampSupport) {
684
+ toast.error("Credit/Debit Card not available");
685
+ return;
686
+ }
687
+ vendor = "stripe";
688
+ paymentMethodString = "";
689
+ }
690
+ else if (paymentMethod === FiatPaymentMethod.STRIPE_WEB2) {
691
+ // Stripe embedded payment form
692
+ if (!stripeWeb2Support.isSupport) {
693
+ toast.error("Pay with Card not available");
681
694
  return;
682
695
  }
683
- vendor = stripeWeb2Support && stripeWeb2Support.isSupport ? "stripe-web2" : "stripe";
696
+ vendor = "stripe-web2";
684
697
  paymentMethodString = "";
685
698
  }
686
699
  else {
@@ -19,7 +19,7 @@ import { useRecipientAddressState } from "../hooks/useRecipientAddressState.js";
19
19
  import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper.js";
20
20
  import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod.js";
21
21
  import { FeeBreakDown } from "./common/FeeBreakDown.js";
22
- import { FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaymentMethod.js";
22
+ import { FIAT_PAYMENT_METHOD_DISPLAY, FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaymentMethod.js";
23
23
  import { OrderDetails } from "./common/OrderDetails.js";
24
24
  import { OrderHistory } from "./common/OrderHistory.js";
25
25
  import { OrderToken } from "./common/OrderToken.js";
@@ -197,7 +197,11 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
197
197
  contractType: orderType === "mint_nft" ? metadata?.nftContract?.type : undefined,
198
198
  encodedData: encodedData,
199
199
  spenderAddress: spenderAddress,
200
- onrampVendor: selectedFiatPaymentMethod === FiatPaymentMethod.STRIPE ? "stripe-web2" : undefined,
200
+ onrampVendor: selectedFiatPaymentMethod === FiatPaymentMethod.STRIPE
201
+ ? "stripe"
202
+ : selectedFiatPaymentMethod === FiatPaymentMethod.STRIPE_WEB2
203
+ ? "stripe-web2"
204
+ : undefined,
201
205
  });
202
206
  }, [
203
207
  activeTab,
@@ -539,7 +543,13 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
539
543
  opacity: hasMounted ? 1 : 0,
540
544
  y: hasMounted ? 0 : 20,
541
545
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
542
- }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, className: "relative flex w-full items-center justify-between", children: [_jsx("div", { className: "text-as-tertiarry flex h-7 items-center text-sm", children: "Pay with" }), _jsx("button", { className: "text-as-tertiarry flex flex-wrap items-center justify-end gap-2 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(PanelView.FIAT_PAYMENT_METHOD), children: selectedFiatPaymentMethod === FiatPaymentMethod.COINBASE_PAY ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2 whitespace-nowrap", children: [_jsx("div", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-600", children: _jsx("span", { className: "text-xs font-bold text-white", children: "C" }) }), "Coinbase Pay"] }), _jsx(ChevronRight, { className: "h-4 w-4 shrink-0" })] })) : selectedFiatPaymentMethod === FiatPaymentMethod.STRIPE ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2 whitespace-nowrap", children: [_jsx("div", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-600", children: _jsx("span", { className: "text-xs font-bold text-white", children: "S" }) }), "Credit/Debit Card"] }), _jsx(ChevronRight, { className: "h-4 w-4 shrink-0" })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "whitespace-nowrap", children: "Select payment method" }), _jsx(ChevronRight, { className: "h-4 w-4 shrink-0" })] })) })] }), _jsx("div", { className: "divider w-full" }), recipientSection, _jsx("div", { className: "divider w-full" }), _jsxs(motion.div, { initial: false, animate: {
546
+ }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, className: "relative flex w-full items-center justify-between", children: [_jsx("div", { className: "text-as-tertiarry flex h-7 items-center text-sm", children: "Pay with" }), _jsx("button", { className: "text-as-tertiarry flex flex-wrap items-center justify-end gap-2 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(PanelView.FIAT_PAYMENT_METHOD), children: (() => {
547
+ const config = FIAT_PAYMENT_METHOD_DISPLAY[selectedFiatPaymentMethod];
548
+ if (config) {
549
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2 whitespace-nowrap", children: [_jsx("div", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-600", children: _jsx("span", { className: "text-xs font-bold text-white", children: config.icon }) }), config.label] }), _jsx(ChevronRight, { className: "h-4 w-4 shrink-0" })] }));
550
+ }
551
+ return (_jsxs(_Fragment, { children: [_jsx("span", { className: "whitespace-nowrap", children: "Select payment method" }), _jsx(ChevronRight, { className: "h-4 w-4 shrink-0" })] }));
552
+ })() })] }), _jsx("div", { className: "divider w-full" }), recipientSection, _jsx("div", { className: "divider w-full" }), _jsxs(motion.div, { initial: false, animate: {
543
553
  opacity: hasMounted ? 1 : 0,
544
554
  y: hasMounted ? 0 : 20,
545
555
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
@@ -579,11 +589,17 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
579
589
  setSelectedCryptoPaymentMethod(method);
580
590
  setActivePanel(PanelView.CONFIRM_ORDER);
581
591
  } }) }));
592
+ // Stable callback for fiat payment method selection
593
+ const handleFiatPaymentMethodSelect = useCallback((method) => {
594
+ setSelectedFiatPaymentMethod(method);
595
+ setActivePanel(PanelView.CONFIRM_ORDER);
596
+ }, []);
597
+ // Stable callback for navigating back to confirm order
598
+ const handleBackToConfirmOrder = useCallback(() => {
599
+ setActivePanel(PanelView.CONFIRM_ORDER);
600
+ }, []);
582
601
  // Fiat payment method view
583
- const fiatPaymentMethodView = (_jsx("div", { className: cn("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: _jsx(FiatPaymentMethodComponent, { selectedPaymentMethod: selectedFiatPaymentMethod, setSelectedPaymentMethod: setSelectedFiatPaymentMethod, onBack: () => setActivePanel(PanelView.CONFIRM_ORDER), onSelectPaymentMethod: (method) => {
584
- setSelectedFiatPaymentMethod(method);
585
- setActivePanel(PanelView.CONFIRM_ORDER);
586
- }, srcAmountOnRamp: srcFiatAmount }) }));
602
+ const fiatPaymentMethodView = (_jsx("div", { className: cn("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: _jsx(FiatPaymentMethodComponent, { selectedPaymentMethod: selectedFiatPaymentMethod, setSelectedPaymentMethod: setSelectedFiatPaymentMethod, onBack: handleBackToConfirmOrder, onSelectPaymentMethod: handleFiatPaymentMethodSelect, srcAmountOnRamp: srcFiatAmount }) }));
587
603
  // Points detail view
588
604
  const pointsDetailView = (_jsx("div", { className: cn("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: _jsx(PointsDetailPanel, { pointsAmount: anyspendQuote?.data?.pointsAmount || 0, onBack: () => setActivePanel(PanelView.CONFIRM_ORDER) }) }));
589
605
  // Return the TransitionPanel with all views
@@ -4,6 +4,10 @@ export declare enum FiatPaymentMethod {
4
4
  STRIPE = "stripe",// Stripe redirect (one-click buy URL)
5
5
  STRIPE_WEB2 = "stripe_web2"
6
6
  }
7
+ export declare const FIAT_PAYMENT_METHOD_DISPLAY: Record<FiatPaymentMethod, {
8
+ icon: string;
9
+ label: string;
10
+ } | null>;
7
11
  interface FiatPaymentMethodProps {
8
12
  selectedPaymentMethod: FiatPaymentMethod;
9
13
  setSelectedPaymentMethod: (method: FiatPaymentMethod) => void;
@@ -10,6 +10,13 @@ export var FiatPaymentMethod;
10
10
  FiatPaymentMethod["STRIPE"] = "stripe";
11
11
  FiatPaymentMethod["STRIPE_WEB2"] = "stripe_web2";
12
12
  })(FiatPaymentMethod || (FiatPaymentMethod = {}));
13
+ // Shared display config for fiat payment methods
14
+ export const FIAT_PAYMENT_METHOD_DISPLAY = {
15
+ [FiatPaymentMethod.COINBASE_PAY]: { icon: "C", label: "Coinbase Pay" },
16
+ [FiatPaymentMethod.STRIPE]: { icon: "S", label: "Pay via Stripe" },
17
+ [FiatPaymentMethod.STRIPE_WEB2]: { icon: "S", label: "Pay with Card" },
18
+ [FiatPaymentMethod.NONE]: null,
19
+ };
13
20
  export function FiatPaymentMethodComponent({ selectedPaymentMethod, setSelectedPaymentMethod, onBack, onSelectPaymentMethod, srcAmountOnRamp, }) {
14
21
  // Load geo-based onramp options like in PanelOnramp
15
22
  const { coinbaseAvailablePaymentMethods, stripeOnrampSupport, stripeWeb2Support, isLoading: isLoadingGeoOnramp, } = useGeoOnrampOptions(srcAmountOnRamp);
@@ -46,25 +53,25 @@ export function FiatPaymentMethodComponent({ selectedPaymentMethod, setSelectedP
46
53
  available: true,
47
54
  });
48
55
  }
49
- // Add Stripe redirect (one-click) if available - primary option
56
+ // Add Stripe redirect (one-click) if available - redirects to Stripe checkout
50
57
  if (stripeOnrampSupport) {
51
58
  const stripeFee = getFeeFromApi(FiatPaymentMethod.STRIPE_WEB2); // Use same fee estimate
52
59
  availablePaymentMethods.push({
53
60
  id: FiatPaymentMethod.STRIPE,
54
- name: "Credit/Debit Card",
55
- description: "Pay via Stripe checkout",
61
+ name: "Pay via Stripe",
62
+ description: "Redirects to Stripe checkout",
56
63
  badge: stripeFee ? `$${Number(stripeFee).toFixed(2)} fee` : undefined,
57
64
  badgeColor: "bg-gray-100 text-gray-800",
58
65
  available: true,
59
66
  });
60
67
  }
61
- // Add Stripe Web2 (embedded) if available - secondary option
68
+ // Add Stripe Web2 (embedded) if available - embedded card form
62
69
  if (stripeWeb2Support && stripeWeb2Support.isSupport) {
63
70
  const stripeFee = getFeeFromApi(FiatPaymentMethod.STRIPE_WEB2);
64
71
  availablePaymentMethods.push({
65
72
  id: FiatPaymentMethod.STRIPE_WEB2,
66
- name: "Quick Pay",
67
- description: "Credit or debit card",
73
+ name: "Pay with Card",
74
+ description: "Fast checkout",
68
75
  badge: stripeFee ? `$${Number(stripeFee).toFixed(2)} fee` : undefined,
69
76
  badgeColor: "bg-gray-100 text-gray-800",
70
77
  available: true,