@b3dotfun/sdk 0.0.65-alpha.0 → 0.0.65-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 (28) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +37 -23
  2. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +22 -9
  3. package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +6 -6
  4. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +5 -1
  5. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +15 -9
  6. package/dist/cjs/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.d.ts +7 -5
  7. package/dist/cjs/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.js +13 -9
  8. package/dist/cjs/anyspend/react/hooks/useCryptoPaymentMethodState.d.ts +42 -0
  9. package/dist/cjs/anyspend/react/hooks/useCryptoPaymentMethodState.js +51 -0
  10. package/dist/esm/anyspend/react/components/AnySpend.js +37 -23
  11. package/dist/esm/anyspend/react/components/AnySpendCustom.js +22 -9
  12. package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +6 -6
  13. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +5 -1
  14. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +15 -9
  15. package/dist/esm/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.d.ts +7 -5
  16. package/dist/esm/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.js +13 -9
  17. package/dist/esm/anyspend/react/hooks/useCryptoPaymentMethodState.d.ts +42 -0
  18. package/dist/esm/anyspend/react/hooks/useCryptoPaymentMethodState.js +48 -0
  19. package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +5 -1
  20. package/dist/types/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.d.ts +7 -5
  21. package/dist/types/anyspend/react/hooks/useCryptoPaymentMethodState.d.ts +42 -0
  22. package/package.json +1 -1
  23. package/src/anyspend/react/components/AnySpend.tsx +49 -28
  24. package/src/anyspend/react/components/AnySpendCustom.tsx +28 -15
  25. package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +7 -6
  26. package/src/anyspend/react/hooks/useAnyspendFlow.ts +23 -11
  27. package/src/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.ts +20 -12
  28. package/src/anyspend/react/hooks/useCryptoPaymentMethodState.ts +71 -0
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useCryptoPaymentMethodState = useCryptoPaymentMethodState;
4
+ const react_1 = require("react");
5
+ const CryptoPaymentMethod_1 = require("../components/common/CryptoPaymentMethod");
6
+ /**
7
+ * Custom hook to manage crypto payment method state with dual-state system:
8
+ *
9
+ * - `cryptoPaymentMethod`: Auto-selected based on wallet availability and balance
10
+ * - `selectedCryptoPaymentMethod`: Explicitly selected by user
11
+ * - `effectiveCryptoPaymentMethod`: User selection takes priority over auto-selection
12
+ *
13
+ * This allows automatic payment method suggestions while respecting explicit user choices.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * const {
18
+ * cryptoPaymentMethod,
19
+ * setCryptoPaymentMethod,
20
+ * selectedCryptoPaymentMethod,
21
+ * setSelectedCryptoPaymentMethod,
22
+ * effectiveCryptoPaymentMethod,
23
+ * resetPaymentMethods
24
+ * } = useCryptoPaymentMethodState();
25
+ *
26
+ * // Use effectiveCryptoPaymentMethod for display
27
+ * // Use setSelectedCryptoPaymentMethod when user explicitly selects
28
+ * // Call resetPaymentMethods when switching tabs or going back
29
+ * ```
30
+ */
31
+ function useCryptoPaymentMethodState() {
32
+ // cryptoPaymentMethod: auto-selected based on balance
33
+ const [cryptoPaymentMethod, setCryptoPaymentMethod] = (0, react_1.useState)(CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE);
34
+ // selectedCryptoPaymentMethod: explicitly selected by user (NONE means no explicit selection)
35
+ const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = (0, react_1.useState)(CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE);
36
+ // The effective payment method (user selection takes priority over auto-selection)
37
+ const effectiveCryptoPaymentMethod = selectedCryptoPaymentMethod !== CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE ? selectedCryptoPaymentMethod : cryptoPaymentMethod;
38
+ // Helper function to reset both states
39
+ const resetPaymentMethods = () => {
40
+ setCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE);
41
+ setSelectedCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE);
42
+ };
43
+ return {
44
+ cryptoPaymentMethod,
45
+ setCryptoPaymentMethod,
46
+ selectedCryptoPaymentMethod,
47
+ setSelectedCryptoPaymentMethod,
48
+ effectiveCryptoPaymentMethod,
49
+ resetPaymentMethods,
50
+ };
51
+ }
@@ -14,6 +14,7 @@ import { parseUnits } from "viem";
14
14
  import { base, mainnet } from "viem/chains";
15
15
  import { useAutoSelectCryptoPaymentMethod } from "../hooks/useAutoSelectCryptoPaymentMethod.js";
16
16
  import { useAutoSetActiveWalletFromWagmi } from "../hooks/useAutoSetActiveWalletFromWagmi.js";
17
+ import { useCryptoPaymentMethodState } from "../hooks/useCryptoPaymentMethodState.js";
17
18
  import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper.js";
18
19
  import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod.js";
19
20
  import { CryptoPaySection } from "./common/CryptoPaySection.js";
@@ -77,9 +78,8 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
77
78
  setActivePanel(targetPanel);
78
79
  }, [activePanel]);
79
80
  const [customRecipients, setCustomRecipients] = useState([]);
80
- // Add state for selected payment method
81
- const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = useState(CryptoPaymentMethodType.NONE);
82
- // Add state for selected fiat payment method
81
+ // Payment method state with dual-state system (auto + explicit user selection)
82
+ const { cryptoPaymentMethod, setCryptoPaymentMethod, selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod, effectiveCryptoPaymentMethod, resetPaymentMethods, } = useCryptoPaymentMethodState();
83
83
  const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState(FiatPaymentMethod.NONE);
84
84
  // const [newRecipientAddress, setNewRecipientAddress] = useState("");
85
85
  // const recipientInputRef = useRef<HTMLInputElement>(null);
@@ -331,8 +331,9 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
331
331
  // Auto-select crypto payment method based on available wallets and balance
332
332
  useAutoSelectCryptoPaymentMethod({
333
333
  paymentType: activeTab,
334
+ cryptoPaymentMethod,
335
+ setCryptoPaymentMethod,
334
336
  selectedCryptoPaymentMethod,
335
- setSelectedCryptoPaymentMethod,
336
337
  hasEnoughBalance,
337
338
  isBalanceLoading,
338
339
  });
@@ -453,9 +454,9 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
453
454
  // Add orderId and payment method to URL for persistence
454
455
  const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
455
456
  params.set("orderId", orderId);
456
- if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
457
- console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
458
- params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
457
+ if (effectiveCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
458
+ console.log("Setting cryptoPaymentMethod in URL:", effectiveCryptoPaymentMethod);
459
+ params.set("cryptoPaymentMethod", effectiveCryptoPaymentMethod);
459
460
  }
460
461
  else {
461
462
  console.log("Payment method is NONE, not setting in URL");
@@ -517,18 +518,18 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
517
518
  if (activeTab === "crypto") {
518
519
  // For crypto: check payment method first, then recipient
519
520
  // If no payment method selected, show "Choose payment method"
520
- if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
521
+ if (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
521
522
  return { text: "Choose payment method", disable: false, error: false, loading: false };
522
523
  }
523
524
  // Check recipient after payment method
524
525
  if (!recipientAddress)
525
526
  return { text: "Select recipient", disable: false, error: false, loading: false };
526
527
  // If payment method selected, show appropriate action
527
- if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ||
528
- selectedCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET) {
528
+ if (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ||
529
+ effectiveCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET) {
529
530
  return { text: "Swap", disable: false, error: false, loading: false };
530
531
  }
531
- if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO) {
532
+ if (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO) {
532
533
  return { text: "Continue to payment", disable: false, error: false, loading: false };
533
534
  }
534
535
  }
@@ -542,7 +543,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
542
543
  isCreatingOnrampOrder,
543
544
  anyspendQuote,
544
545
  activeTab,
545
- selectedCryptoPaymentMethod,
546
+ effectiveCryptoPaymentMethod,
546
547
  selectedFiatPaymentMethod,
547
548
  ]);
548
549
  // Handle main button click
@@ -570,7 +571,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
570
571
  if (activeTab === "crypto") {
571
572
  // For crypto: check payment method first, then recipient
572
573
  // If no payment method selected, show payment method selection
573
- if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
574
+ if (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
574
575
  console.log("No payment method selected, showing selection panel");
575
576
  navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward");
576
577
  return;
@@ -582,11 +583,11 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
582
583
  }
583
584
  invariant(recipientAddress, "Recipient address is not found");
584
585
  // If payment method is selected, create order with payment method info
585
- if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ||
586
- selectedCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET ||
587
- selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO) {
588
- console.log("Creating crypto order with payment method:", selectedCryptoPaymentMethod);
589
- await handleCryptoSwap(selectedCryptoPaymentMethod);
586
+ if (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ||
587
+ effectiveCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET ||
588
+ effectiveCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO) {
589
+ console.log("Creating crypto order with payment method:", effectiveCryptoPaymentMethod);
590
+ await handleCryptoSwap(effectiveCryptoPaymentMethod);
590
591
  return;
591
592
  }
592
593
  }
@@ -760,12 +761,21 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
760
761
  };
761
762
  }, [activePanel, navigateBack]);
762
763
  const historyView = (_jsx("div", { className: "mx-auto flex w-[560px] max-w-full flex-col items-center", children: _jsx(OrderHistory, { mode: mode, onBack: navigateBack, onSelectOrder: onSelectOrder }) }));
763
- const orderDetailsView = (_jsx("div", { className: "mx-auto w-[460px] max-w-full", children: _jsx("div", { className: "relative flex flex-col gap-4", children: oat && (_jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onPaymentMethodChange: setSelectedCryptoPaymentMethod, points: oat.data.points || undefined, onBack: () => {
764
+ const orderDetailsView = (_jsx("div", { className: "mx-auto w-[460px] max-w-full", children: _jsx("div", { className: "relative flex flex-col gap-4", children: oat && (_jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onPaymentMethodChange: method => {
765
+ // When user explicitly changes payment method, set it as selected
766
+ setSelectedCryptoPaymentMethod(method);
767
+ }, points: oat.data.points || undefined, onBack: () => {
764
768
  setOrderId(undefined);
765
769
  navigateBack();
766
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE); // Reset payment method when going back
770
+ // Reset payment methods when going back
771
+ resetPaymentMethods();
767
772
  } })) }) }));
768
- const mainView = (_jsxs("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [isBuyMode && (_jsxs("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: [selectedDstToken.metadata?.logoURI && (_jsx("div", { className: "relative", children: _jsx("img", { src: selectedDstToken.metadata.logoURI, alt: selectedDstToken.symbol, className: "border-as-stroke h-12 w-12 rounded-full border-2 shadow-md" }) })), _jsx("div", { children: _jsxs("h1", { className: "text-as-primary text-xl font-bold", children: ["Buy ", selectedDstToken.symbol] }) })] })), _jsx(TabSection, { activeTab: activeTab, setActiveTab: setActiveTab, setSelectedCryptoPaymentMethod: setSelectedCryptoPaymentMethod, setSelectedFiatPaymentMethod: setSelectedFiatPaymentMethod }), _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [activeTab === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward"), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect, onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward") })) : (_jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: _jsx(PanelOnramp, { srcAmountOnRamp: srcAmountOnRamp, setSrcAmountOnRamp: setSrcAmountOnRamp, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: (panelIndex) => {
773
+ const mainView = (_jsxs("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [isBuyMode && (_jsxs("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: [selectedDstToken.metadata?.logoURI && (_jsx("div", { className: "relative", children: _jsx("img", { src: selectedDstToken.metadata.logoURI, alt: selectedDstToken.symbol, className: "border-as-stroke h-12 w-12 rounded-full border-2 shadow-md" }) })), _jsx("div", { children: _jsxs("h1", { className: "text-as-primary text-xl font-bold", children: ["Buy ", selectedDstToken.symbol] }) })] })), _jsx(TabSection, { activeTab: activeTab, setActiveTab: tab => {
774
+ setActiveTab(tab);
775
+ // Reset payment methods when switching tabs
776
+ resetPaymentMethods();
777
+ setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE);
778
+ }, setSelectedCryptoPaymentMethod: setSelectedCryptoPaymentMethod, setSelectedFiatPaymentMethod: setSelectedFiatPaymentMethod }), _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [activeTab === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward"), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect, onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward") })) : (_jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: _jsx(PanelOnramp, { srcAmountOnRamp: srcAmountOnRamp, setSrcAmountOnRamp: setSrcAmountOnRamp, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: (panelIndex) => {
769
779
  // Map panel index to navigation with direction
770
780
  const panelsWithForwardNav = [PanelView.FIAT_PAYMENT_METHOD, PanelView.RECIPIENT_SELECTION];
771
781
  if (panelsWithForwardNav.includes(panelIndex)) {
@@ -796,7 +806,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
796
806
  }, children: _jsx("div", { className: "relative flex items-center justify-center transition-opacity", children: _jsx(ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }), activeTab === "crypto" && (_jsx(CryptoReceiveSection, { isDepositMode: false, isBuyMode: isBuyMode, selectedRecipientAddress: recipientAddress, recipientName: recipientName || undefined, onSelectRecipient: () => navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward"), setRecipientAddress: setRecipientAddress, recipientAddressFromProps: recipientAddressFromProps, globalAddress: globalAddress, dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
797
807
  setIsSrcInputDirty(false);
798
808
  setDstAmount(value);
799
- }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward"), selectedCryptoPaymentMethod: selectedCryptoPaymentMethod }))] }), _jsxs(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: cn("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: [_jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: cn("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: cn(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: _jsxs("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && _jsx(Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }), !hideTransactionHistoryButton && (globalAddress || recipientAddress) ? (_jsxs(Button, { variant: "link", onClick: onClickHistory, className: "text-as-primary/50 hover:text-as-primary flex items-center gap-1 transition-colors", children: [_jsx(HistoryIcon, { className: "h-4 w-4" }), " ", _jsx("span", { className: "pr-4", children: "Transaction History" })] })) : null] })] }));
809
+ }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward"), selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod }))] }), _jsxs(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: cn("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: [_jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: cn("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: cn(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: _jsxs("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && _jsx(Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }), !hideTransactionHistoryButton && (globalAddress || recipientAddress) ? (_jsxs(Button, { variant: "link", onClick: onClickHistory, className: "text-as-primary/50 hover:text-as-primary flex items-center gap-1 transition-colors", children: [_jsx(HistoryIcon, { className: "h-4 w-4" }), " ", _jsx("span", { className: "pr-4", children: "Transaction History" })] })) : null] })] }));
800
810
  const onrampPaymentView = (_jsx(PanelOnrampPayment, { srcAmountOnRamp: srcAmountOnRamp, recipientName: recipientName || undefined, recipientAddress: recipientAddress, isBuyMode: isBuyMode, destinationTokenChainId: destinationTokenChainId, destinationTokenAddress: destinationTokenAddress, selectedDstChainId: selectedDstChainId, selectedDstToken: selectedDstToken, orderType: "swap", anyspendQuote: anyspendQuote, globalAddress: globalAddress, onOrderCreated: orderId => {
801
811
  setOrderId(orderId);
802
812
  navigateToPanel(PanelView.ORDER_DETAILS, "forward");
@@ -816,7 +826,11 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
816
826
  setRecipientAddress(address);
817
827
  navigateBack();
818
828
  } }));
819
- const cryptoPaymentMethodView = (_jsx(CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: globalWallet, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: navigateBack, onSelectPaymentMethod: (method) => {
829
+ const cryptoPaymentMethodView = (_jsx(CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: globalWallet, selectedPaymentMethod: effectiveCryptoPaymentMethod, setSelectedPaymentMethod: method => {
830
+ // When user explicitly selects a payment method, save it
831
+ setSelectedCryptoPaymentMethod(method);
832
+ }, isCreatingOrder: isCreatingOrder, onBack: navigateBack, onSelectPaymentMethod: (method) => {
833
+ // When user explicitly selects a payment method, save it and go back
820
834
  setSelectedCryptoPaymentMethod(method);
821
835
  navigateBack();
822
836
  } }));
@@ -15,6 +15,7 @@ import { toast } from "sonner";
15
15
  import { base } from "viem/chains";
16
16
  import { useFeatureFlags } from "../contexts/FeatureFlagsContext.js";
17
17
  import { useAutoSetActiveWalletFromWagmi } from "../hooks/useAutoSetActiveWalletFromWagmi.js";
18
+ import { useCryptoPaymentMethodState } from "../hooks/useCryptoPaymentMethodState.js";
18
19
  import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper.js";
19
20
  import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod.js";
20
21
  import { FeeBreakDown } from "./common/FeeBreakDown.js";
@@ -115,8 +116,9 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
115
116
  useAutoSetActiveWalletFromWagmi();
116
117
  const [activePanel, setActivePanel] = useState(loadOrder ? PanelView.ORDER_DETAILS : PanelView.CONFIRM_ORDER);
117
118
  const [activeTab, setActiveTab] = useState(activeTabProps);
118
- // Add state for selected payment methods
119
- const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = useState(CryptoPaymentMethodType.NONE);
119
+ // Payment method state with dual-state system (auto + explicit user selection)
120
+ // Note: AnySpendCustom doesn't use auto-selection, only explicit user selection
121
+ const { setSelectedCryptoPaymentMethod, effectiveCryptoPaymentMethod, resetPaymentMethods } = useCryptoPaymentMethodState();
120
122
  const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState(FiatPaymentMethod.NONE);
121
123
  // Get current user's wallet
122
124
  const currentWallet = useAccountWallet();
@@ -365,7 +367,7 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
365
367
  return;
366
368
  }
367
369
  // Check payment method selection for crypto tab
368
- if (activeTab === "crypto" && selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
370
+ if (activeTab === "crypto" && effectiveCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
369
371
  setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD);
370
372
  return;
371
373
  }
@@ -440,9 +442,14 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
440
442
  const historyView = (_jsx("div", { className: cn("mx-auto flex w-full max-w-2xl flex-col items-center p-5", mode === "modal" && "bg-b3-react-background"), children: _jsx(OrderHistory, { mode: mode, onBack: () => {
441
443
  setActivePanel(PanelView.HISTORY);
442
444
  }, onSelectOrder: onSelectOrder }) }));
443
- const orderDetailsView = (_jsxs("div", { className: cn("mx-auto flex w-full flex-col items-center gap-4 p-5", mode === "modal" && "bg-b3-react-background rounded-xl"), children: [oat && (_jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: activeTab === "fiat" ? CryptoPaymentMethodType.NONE : selectedCryptoPaymentMethod, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onPaymentMethodChange: setSelectedCryptoPaymentMethod, onBack: () => {
445
+ const orderDetailsView = (_jsxs("div", { className: cn("mx-auto flex w-full flex-col items-center gap-4 p-5", mode === "modal" && "bg-b3-react-background rounded-xl"), children: [oat && (_jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: activeTab === "fiat" ? CryptoPaymentMethodType.NONE : effectiveCryptoPaymentMethod, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onPaymentMethodChange: method => {
446
+ // When user explicitly changes payment method, set it as selected
447
+ setSelectedCryptoPaymentMethod(method);
448
+ }, onBack: () => {
444
449
  setOrderId(undefined);
445
450
  setActivePanel(PanelView.CONFIRM_ORDER);
451
+ // Reset payment methods when going back
452
+ resetPaymentMethods();
446
453
  // Remove orderId from URL when canceling
447
454
  const params = new URLSearchParams(searchParams.toString());
448
455
  params.delete("orderId");
@@ -462,17 +469,19 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
462
469
  // Confirm order view.
463
470
  const confirmOrderView = (_jsxs("div", { className: "relative mx-auto flex w-full flex-col items-center", children: [header({ anyspendPrice: anyspendQuote, isLoadingAnyspendPrice: isLoadingAnyspendQuote }), _jsxs(Tabs, { value: activeTab, onValueChange: value => setActiveTab(value), className: "bg-b3-react-background max-h-[60dvh] w-full overflow-y-auto p-5", children: [_jsx("div", { className: "w-full", children: _jsxs("div", { className: "bg-as-surface-secondary relative mb-4 grid h-10 grid-cols-2 rounded-xl", children: [_jsx("div", { className: cn("bg-as-brand absolute bottom-0 left-0 top-0 z-0 rounded-xl transition-transform duration-100", "h-full w-1/2", activeTab === "fiat" ? "translate-x-full" : "translate-x-0"), style: { willChange: "transform" } }), _jsx("button", { className: cn("relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100", activeTab === "crypto" ? "text-white" : "text-as-primary/70 hover:bg-as-on-surface-2 bg-transparent"), onClick: () => {
464
471
  setActiveTab("crypto");
465
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE);
472
+ // Reset payment methods when switching tabs
473
+ resetPaymentMethods();
466
474
  setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE);
467
475
  }, children: "Pay with crypto" }), isOnrampSupported ? (_jsx("button", { className: cn("relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100", activeTab === "fiat" ? "text-white" : "text-as-primary/70 hover:bg-as-on-surface-2 bg-transparent"), onClick: () => {
468
476
  setActiveTab("fiat");
469
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE);
477
+ // Reset payment methods when switching tabs
478
+ resetPaymentMethods();
470
479
  setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE);
471
480
  }, children: "Pay with fiat" })) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { className: cn("relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100", "text-as-primary/50 cursor-not-allowed bg-transparent"), disabled: true, children: "Pay with fiat" }) }), _jsx(TooltipContent, { children: _jsx("span", { className: "text-as-primary w-[140px]", children: "Fiat payments are not supported for this amount" }) })] }))] }) }), _jsx(TabsContent, { value: "crypto", children: _jsxs("div", { className: "mt-2 flex flex-col gap-6", children: [_jsxs("div", { className: "border-as-border-secondary bg-as-surface-secondary flex w-full flex-col gap-4 rounded-xl border p-4", children: [_jsxs(motion.div, { initial: false, animate: {
472
481
  opacity: hasMounted ? 1 : 0,
473
482
  y: hasMounted ? 0 : 20,
474
483
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
475
- }, 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" }), _jsx("button", { className: "text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD), children: selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (_jsxs(_Fragment, { children: [connectedAddress ? (_jsx(_Fragment, { children: _jsx("span", { className: "text-as-tertiarry flex items-center gap-1", children: connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "") }) })) : ("Connect wallet"), _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (_jsxs(_Fragment, { children: ["Transfer crypto", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : (_jsxs(_Fragment, { children: ["Select payment method", _jsx(ChevronRight, { className: "h-4 w-4" })] })) })] }), _jsx("div", { className: "divider w-full" }), recipientSection, _jsx("div", { className: "divider w-full" }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs(motion.div, { initial: false, animate: {
484
+ }, 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" }), _jsx("button", { className: "text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors hover:text-blue-700", onClick: () => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD), children: effectiveCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (_jsxs(_Fragment, { children: [connectedAddress ? (_jsx(_Fragment, { children: _jsx("span", { className: "text-as-tertiarry flex items-center gap-1", children: connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "") }) })) : ("Connect wallet"), _jsx(ChevronRight, { className: "h-4 w-4" })] })) : effectiveCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (_jsxs(_Fragment, { children: ["Transfer crypto", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : (_jsxs(_Fragment, { children: ["Select payment method", _jsx(ChevronRight, { className: "h-4 w-4" })] })) })] }), _jsx("div", { className: "divider w-full" }), recipientSection, _jsx("div", { className: "divider w-full" }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs(motion.div, { initial: false, animate: {
476
485
  opacity: hasMounted ? 1 : 0,
477
486
  y: hasMounted ? 0 : 20,
478
487
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
@@ -488,7 +497,7 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
488
497
  opacity: hasMounted ? 1 : 0,
489
498
  y: hasMounted ? 0 : 20,
490
499
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
491
- }, transition: { duration: 0.3, delay: 0.3, ease: "easeInOut" }, className: "flex w-full flex-col gap-2", children: _jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", textColor: "text-white", disabled: isCreatingOrder || isLoadingAnyspendQuote || !anyspendQuote, onClick: () => handleConfirmOrder(), className: "relative w-full", children: isCreatingOrder ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), _jsx("span", { children: "Creating order..." })] })) : isLoadingAnyspendQuote ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), _jsx("span", { children: "Loading quote..." })] })) : !recipientAddress ? ("Select recipient") : selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE ? ("Choose payment method") : anyspendQuote ? (_jsxs(_Fragment, { children: [_jsx("span", { children: "Checkout" }), _jsx(ChevronRightCircle, { className: "absolute right-0 top-1/2 size-6 -translate-y-1/2 opacity-70" })] })) : ("No quote found") }) }) })] }) }), _jsx(TabsContent, { value: "fiat", children: _jsxs("div", { className: "mt-2 flex flex-col gap-6", children: [_jsxs("div", { className: "border-as-border-secondary bg-as-surface-secondary flex w-full flex-col gap-4 rounded-xl border p-4", children: [_jsxs(motion.div, { initial: false, animate: {
500
+ }, transition: { duration: 0.3, delay: 0.3, ease: "easeInOut" }, className: "flex w-full flex-col gap-2", children: _jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", textColor: "text-white", disabled: isCreatingOrder || isLoadingAnyspendQuote || !anyspendQuote, onClick: () => handleConfirmOrder(), className: "relative w-full", children: isCreatingOrder ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), _jsx("span", { children: "Creating order..." })] })) : isLoadingAnyspendQuote ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), _jsx("span", { children: "Loading quote..." })] })) : !recipientAddress ? ("Select recipient") : effectiveCryptoPaymentMethod === CryptoPaymentMethodType.NONE ? ("Choose payment method") : anyspendQuote ? (_jsxs(_Fragment, { children: [_jsx("span", { children: "Checkout" }), _jsx(ChevronRightCircle, { className: "absolute right-0 top-1/2 size-6 -translate-y-1/2 opacity-70" })] })) : ("No quote found") }) }) })] }) }), _jsx(TabsContent, { value: "fiat", children: _jsxs("div", { className: "mt-2 flex flex-col gap-6", children: [_jsxs("div", { className: "border-as-border-secondary bg-as-surface-secondary flex w-full flex-col gap-4 rounded-xl border p-4", children: [_jsxs(motion.div, { initial: false, animate: {
492
501
  opacity: hasMounted ? 1 : 0,
493
502
  y: hasMounted ? 0 : 20,
494
503
  filter: hasMounted ? "blur(0px)" : "blur(10px)",
@@ -515,7 +524,11 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
515
524
  setActivePanel(PanelView.CONFIRM_ORDER);
516
525
  } }) }));
517
526
  // Crypto payment method view
518
- const cryptoPaymentMethodView = (_jsx("div", { className: cn("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: _jsx(CryptoPaymentMethod, { globalAddress: currentWallet?.wallet?.address, globalWallet: currentWallet?.wallet, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(PanelView.CONFIRM_ORDER), onSelectPaymentMethod: (method) => {
527
+ const cryptoPaymentMethodView = (_jsx("div", { className: cn("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: _jsx(CryptoPaymentMethod, { globalAddress: currentWallet?.wallet?.address, globalWallet: currentWallet?.wallet, selectedPaymentMethod: effectiveCryptoPaymentMethod, setSelectedPaymentMethod: method => {
528
+ // When user explicitly selects a payment method, save it
529
+ setSelectedCryptoPaymentMethod(method);
530
+ }, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(PanelView.CONFIRM_ORDER), onSelectPaymentMethod: (method) => {
531
+ // When user explicitly selects a payment method, save it and go back
519
532
  setSelectedCryptoPaymentMethod(method);
520
533
  setActivePanel(PanelView.CONFIRM_ORDER);
521
534
  } }) }));
@@ -30,7 +30,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
30
30
  SYMBOL: destinationToken.symbol ?? "TOKEN",
31
31
  LOGO_URI: destinationToken.metadata?.logoURI ?? "",
32
32
  };
33
- const { activePanel, setActivePanel, orderId, setOrderId, oat, selectedSrcChainId, setSelectedSrcChainId, selectedSrcToken, setSelectedSrcToken, selectedDstToken, selectedDstChainId, srcAmount, setSrcAmount, dstAmount, isSrcInputDirty, setIsSrcInputDirty, selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod, selectedFiatPaymentMethod, setSelectedFiatPaymentMethod, selectedRecipientAddress, setSelectedRecipientAddress, recipientName, globalAddress, hasEnoughBalance, isBalanceLoading, anyspendQuote, isLoadingAnyspendQuote, activeInputAmountInWei, geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support, createOrder, isCreatingOrder, createOnrampOrder, isCreatingOnrampOrder, } = useAnyspendFlow({
33
+ const { activePanel, setActivePanel, orderId, setOrderId, oat, selectedSrcChainId, setSelectedSrcChainId, selectedSrcToken, setSelectedSrcToken, selectedDstToken, selectedDstChainId, srcAmount, setSrcAmount, dstAmount, isSrcInputDirty, setIsSrcInputDirty, selectedCryptoPaymentMethod, effectiveCryptoPaymentMethod, setSelectedCryptoPaymentMethod, selectedFiatPaymentMethod, setSelectedFiatPaymentMethod, selectedRecipientAddress, setSelectedRecipientAddress, recipientName, globalAddress, hasEnoughBalance, isBalanceLoading, anyspendQuote, isLoadingAnyspendQuote, activeInputAmountInWei, geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support, createOrder, isCreatingOrder, createOnrampOrder, isCreatingOnrampOrder, } = useAnyspendFlow({
34
34
  paymentType,
35
35
  recipientAddress,
36
36
  loadOrder,
@@ -83,12 +83,12 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
83
83
  if (!anyspendQuote || !anyspendQuote.success)
84
84
  return { text: "Get quote error", disable: true, error: true, loading: false };
85
85
  if (paymentType === "crypto") {
86
- if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
86
+ if (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
87
87
  return { text: "Choose payment method", disable: false, error: false, loading: false };
88
88
  }
89
89
  if (!hasEnoughBalance &&
90
90
  !isBalanceLoading &&
91
- selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET) {
91
+ effectiveCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET) {
92
92
  return { text: "Insufficient balance", disable: true, error: true, loading: false };
93
93
  }
94
94
  return { text: `Execute ${actionLabel}`, disable: false, error: false, loading: false };
@@ -108,7 +108,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
108
108
  selectedRecipientOrDefault,
109
109
  anyspendQuote,
110
110
  paymentType,
111
- selectedCryptoPaymentMethod,
111
+ effectiveCryptoPaymentMethod,
112
112
  selectedFiatPaymentMethod,
113
113
  hasEnoughBalance,
114
114
  isBalanceLoading,
@@ -137,7 +137,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
137
137
  }
138
138
  };
139
139
  const headerContent = header ? (header({ anyspendPrice: anyspendQuote, isLoadingAnyspendPrice: isLoadingAnyspendQuote })) : (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsxs("div", { children: [_jsx("h1", { className: "text-as-primary text-xl font-bold", children: actionLabel }), _jsx("p", { className: "text-as-secondary text-sm", children: "Pay from any token to execute a custom exact-in transaction." })] }) }));
140
- const mainView = (_jsxs("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [headerContent, _jsx("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [paymentType === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : (_jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: _jsx(PanelOnramp, { srcAmountOnRamp: srcAmount, setSrcAmountOnRamp: setSrcAmount, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: selectedRecipientOrDefault, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, hideDstToken: true, destinationAmount: dstAmount, onDestinationTokenChange: () => { }, onDestinationChainChange: () => { }, fiatPaymentMethodIndex: PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: PanelView.RECIPIENT_SELECTION, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(PanelView.FEE_DETAIL), customUsdInputValues: customUsdInputValues }) })), _jsx("div", { className: cn("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: _jsx(Button, { variant: "ghost", className: cn("swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl"), children: _jsx("div", { className: "relative flex items-center justify-center transition-opacity", children: _jsx(ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && (_jsx(CryptoReceiveSection, { isDepositMode: false, isBuyMode: true, selectedRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, onSelectRecipient: () => setActivePanel(PanelView.RECIPIENT_SELECTION), dstAmount: dstAmount, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
140
+ const mainView = (_jsxs("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [headerContent, _jsx("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [paymentType === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : (_jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: _jsx(PanelOnramp, { srcAmountOnRamp: srcAmount, setSrcAmountOnRamp: setSrcAmount, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: selectedRecipientOrDefault, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, hideDstToken: true, destinationAmount: dstAmount, onDestinationTokenChange: () => { }, onDestinationChainChange: () => { }, fiatPaymentMethodIndex: PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: PanelView.RECIPIENT_SELECTION, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(PanelView.FEE_DETAIL), customUsdInputValues: customUsdInputValues }) })), _jsx("div", { className: cn("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: _jsx(Button, { variant: "ghost", className: cn("swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl"), children: _jsx("div", { className: "relative flex items-center justify-center transition-opacity", children: _jsx(ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && (_jsx(CryptoReceiveSection, { isDepositMode: false, isBuyMode: true, selectedRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, onSelectRecipient: () => setActivePanel(PanelView.RECIPIENT_SELECTION), dstAmount: dstAmount, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
141
141
  setIsSrcInputDirty(false);
142
142
  setSrcAmount(value);
143
143
  }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(PanelView.FEE_DETAIL) }))] }) }), _jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: cn("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: _jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: cn("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: cn(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: _jsxs("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && _jsx(Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }) }), mainFooter ? mainFooter : null] }));
@@ -217,7 +217,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
217
217
  toast.error("Failed to create order: " + err.message);
218
218
  }
219
219
  };
220
- const orderDetailsView = (_jsx("div", { className: "mx-auto w-[460px] max-w-full", children: _jsx("div", { className: "relative flex flex-col gap-4", children: oat && (_jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: paymentType === "fiat" ? CryptoPaymentMethodType.NONE : selectedCryptoPaymentMethod, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onPaymentMethodChange: setSelectedCryptoPaymentMethod, onBack: () => {
220
+ const orderDetailsView = (_jsx("div", { className: "mx-auto w-[460px] max-w-full", children: _jsx("div", { className: "relative flex flex-col gap-4", children: oat && (_jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: paymentType === "fiat" ? CryptoPaymentMethodType.NONE : effectiveCryptoPaymentMethod, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onPaymentMethodChange: setSelectedCryptoPaymentMethod, onBack: () => {
221
221
  setOrderId(undefined);
222
222
  setActivePanel(PanelView.MAIN);
223
223
  }, disableUrlParamManagement: true, points: oat.data.points || undefined })) }) }));
@@ -93,8 +93,12 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
93
93
  setDstAmount: import("react").Dispatch<import("react").SetStateAction<string>>;
94
94
  isSrcInputDirty: boolean;
95
95
  setIsSrcInputDirty: import("react").Dispatch<import("react").SetStateAction<boolean>>;
96
+ cryptoPaymentMethod: CryptoPaymentMethodType;
97
+ setCryptoPaymentMethod: (method: CryptoPaymentMethodType) => void;
96
98
  selectedCryptoPaymentMethod: CryptoPaymentMethodType;
97
- setSelectedCryptoPaymentMethod: import("react").Dispatch<import("react").SetStateAction<CryptoPaymentMethodType>>;
99
+ setSelectedCryptoPaymentMethod: (method: CryptoPaymentMethodType) => void;
100
+ effectiveCryptoPaymentMethod: CryptoPaymentMethodType;
101
+ resetPaymentMethods: () => void;
98
102
  selectedFiatPaymentMethod: FiatPaymentMethod;
99
103
  setSelectedFiatPaymentMethod: import("react").Dispatch<import("react").SetStateAction<FiatPaymentMethod>>;
100
104
  selectedRecipientAddress: string | undefined;
@@ -7,11 +7,12 @@ import { useEffect, useMemo, useState } from "react";
7
7
  import { toast } from "sonner";
8
8
  import { parseUnits } from "viem";
9
9
  import { base, mainnet } from "viem/chains";
10
- import { useAccount } from "wagmi";
11
10
  import { CryptoPaymentMethodType } from "../components/common/CryptoPaymentMethod.js";
12
11
  import { FiatPaymentMethod } from "../components/common/FiatPaymentMethod.js";
13
12
  import { useAutoSelectCryptoPaymentMethod } from "./useAutoSelectCryptoPaymentMethod.js";
14
13
  import { useAutoSetActiveWalletFromWagmi } from "./useAutoSetActiveWalletFromWagmi.js";
14
+ import { useConnectedWalletDisplay } from "./useConnectedWalletDisplay.js";
15
+ import { useCryptoPaymentMethodState } from "./useCryptoPaymentMethodState.js";
15
16
  export var PanelView;
16
17
  (function (PanelView) {
17
18
  PanelView[PanelView["MAIN"] = 0] = "MAIN";
@@ -42,12 +43,12 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
42
43
  const [isSrcInputDirty, setIsSrcInputDirty] = useState(true);
43
44
  // Derive destination chain ID from token or prop (cannot change)
44
45
  const selectedDstChainId = destinationTokenChainId || selectedDstToken.chainId;
45
- // Payment method state
46
- const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = useState(CryptoPaymentMethodType.NONE);
46
+ // Payment method state with dual-state system (auto + explicit user selection)
47
+ const { cryptoPaymentMethod, setCryptoPaymentMethod, selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod, effectiveCryptoPaymentMethod, resetPaymentMethods, } = useCryptoPaymentMethodState();
47
48
  const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState(FiatPaymentMethod.NONE);
48
49
  // Recipient state
49
50
  const { address: globalAddress } = useAccountWallet();
50
- const { address: wagmiAddress } = useAccount();
51
+ const { walletAddress } = useConnectedWalletDisplay(effectiveCryptoPaymentMethod);
51
52
  const [selectedRecipientAddress, setSelectedRecipientAddress] = useState(recipientAddress);
52
53
  const recipientProfile = useProfile({ address: selectedRecipientAddress, fresh: true });
53
54
  const recipientName = recipientProfile.data?.name;
@@ -62,7 +63,7 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
62
63
  // Check token balance for crypto payments
63
64
  const { rawBalance, isLoading: isBalanceLoading } = useTokenBalance({
64
65
  token: selectedSrcToken,
65
- address: wagmiAddress,
66
+ address: walletAddress,
66
67
  });
67
68
  // Check if user has enough balance
68
69
  const hasEnoughBalance = useMemo(() => {
@@ -79,8 +80,9 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
79
80
  // Auto-select crypto payment method based on available wallets and balance
80
81
  useAutoSelectCryptoPaymentMethod({
81
82
  paymentType,
83
+ cryptoPaymentMethod,
84
+ setCryptoPaymentMethod,
82
85
  selectedCryptoPaymentMethod,
83
- setSelectedCryptoPaymentMethod,
84
86
  hasEnoughBalance,
85
87
  isBalanceLoading,
86
88
  });
@@ -180,9 +182,9 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
180
182
  if (!disableUrlParamManagement) {
181
183
  const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
182
184
  params.set("orderId", newOrderId);
183
- if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
184
- console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
185
- params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
185
+ if (effectiveCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
186
+ console.log("Setting cryptoPaymentMethod in URL:", effectiveCryptoPaymentMethod);
187
+ params.set("cryptoPaymentMethod", effectiveCryptoPaymentMethod);
186
188
  }
187
189
  else {
188
190
  console.log("Payment method is NONE, not setting in URL");
@@ -246,8 +248,12 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
246
248
  isSrcInputDirty,
247
249
  setIsSrcInputDirty,
248
250
  // Payment methods
251
+ cryptoPaymentMethod,
252
+ setCryptoPaymentMethod,
249
253
  selectedCryptoPaymentMethod,
250
254
  setSelectedCryptoPaymentMethod,
255
+ effectiveCryptoPaymentMethod,
256
+ resetPaymentMethods,
251
257
  selectedFiatPaymentMethod,
252
258
  setSelectedFiatPaymentMethod,
253
259
  // Recipient
@@ -2,10 +2,12 @@ import { CryptoPaymentMethodType } from "../components/common/CryptoPaymentMetho
2
2
  interface UseAutoSelectCryptoPaymentMethodParams {
3
3
  /** Current payment type (crypto or fiat) */
4
4
  paymentType?: "crypto" | "fiat";
5
- /** Currently selected payment method */
5
+ /** Auto-selected payment method based on balance (not used in hook logic, but part of state management) */
6
+ cryptoPaymentMethod: CryptoPaymentMethodType;
7
+ /** Function to update the auto-selected payment method */
8
+ setCryptoPaymentMethod: (method: CryptoPaymentMethodType) => void;
9
+ /** User explicitly selected payment method (NONE means no explicit selection) */
6
10
  selectedCryptoPaymentMethod: CryptoPaymentMethodType;
7
- /** Function to update the selected payment method */
8
- setSelectedCryptoPaymentMethod: (method: CryptoPaymentMethodType) => void;
9
11
  /** Whether user has enough balance to pay */
10
12
  hasEnoughBalance: boolean;
11
13
  /** Whether balance is still loading */
@@ -16,11 +18,11 @@ interface UseAutoSelectCryptoPaymentMethodParams {
16
18
  * based on available wallets and balance.
17
19
  *
18
20
  * Auto-selection logic:
19
- * - Only auto-selects when payment method is NONE (doesn't override user choices)
21
+ * - Only auto-selects when selectedCryptoPaymentMethod is NONE (user hasn't explicitly chosen)
20
22
  * - If EOA/Wagmi wallet connected + has balance → CONNECT_WALLET
21
23
  * - If EOA/Wagmi wallet connected + insufficient balance → TRANSFER_CRYPTO
22
24
  * - If only Global wallet available → GLOBAL_WALLET
23
25
  * - If no wallets → remains NONE
24
26
  */
25
- export declare function useAutoSelectCryptoPaymentMethod({ paymentType, selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod, hasEnoughBalance, isBalanceLoading, }: UseAutoSelectCryptoPaymentMethodParams): void;
27
+ export declare function useAutoSelectCryptoPaymentMethod({ paymentType, cryptoPaymentMethod: _cryptoPaymentMethod, setCryptoPaymentMethod, selectedCryptoPaymentMethod, hasEnoughBalance, isBalanceLoading, }: UseAutoSelectCryptoPaymentMethodParams): void;
26
28
  export {};
@@ -6,18 +6,22 @@ import { useConnectedWalletDisplay } from "./useConnectedWalletDisplay.js";
6
6
  * based on available wallets and balance.
7
7
  *
8
8
  * Auto-selection logic:
9
- * - Only auto-selects when payment method is NONE (doesn't override user choices)
9
+ * - Only auto-selects when selectedCryptoPaymentMethod is NONE (user hasn't explicitly chosen)
10
10
  * - If EOA/Wagmi wallet connected + has balance → CONNECT_WALLET
11
11
  * - If EOA/Wagmi wallet connected + insufficient balance → TRANSFER_CRYPTO
12
12
  * - If only Global wallet available → GLOBAL_WALLET
13
13
  * - If no wallets → remains NONE
14
14
  */
15
- export function useAutoSelectCryptoPaymentMethod({ paymentType = "crypto", selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod, hasEnoughBalance, isBalanceLoading, }) {
15
+ export function useAutoSelectCryptoPaymentMethod({ paymentType = "crypto", cryptoPaymentMethod: _cryptoPaymentMethod, setCryptoPaymentMethod, selectedCryptoPaymentMethod, hasEnoughBalance, isBalanceLoading, }) {
16
16
  // Get suggested payment method based on available wallets
17
17
  const { suggestedPaymentMethod } = useConnectedWalletDisplay(selectedCryptoPaymentMethod);
18
18
  useEffect(() => {
19
- // Only auto-select when on crypto payment type and payment method is NONE
20
- if (paymentType !== "crypto" || selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
19
+ // Only auto-select when on crypto payment type
20
+ if (paymentType !== "crypto") {
21
+ return;
22
+ }
23
+ // Only auto-switch if user hasn't explicitly selected a payment method
24
+ if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
21
25
  return;
22
26
  }
23
27
  // If we have a suggested payment method (wallet is connected), use it
@@ -26,28 +30,28 @@ export function useAutoSelectCryptoPaymentMethod({ paymentType = "crypto", selec
26
30
  // Otherwise, default to TRANSFER_CRYPTO if balance is insufficient
27
31
  if (!isBalanceLoading) {
28
32
  if (hasEnoughBalance && suggestedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET) {
29
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
33
+ setCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
30
34
  }
31
35
  else if (!hasEnoughBalance && suggestedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET) {
32
36
  // Wallet connected but insufficient balance - suggest transfer
33
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
37
+ setCryptoPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
34
38
  }
35
39
  else {
36
40
  // Use suggested method (e.g., GLOBAL_WALLET)
37
- setSelectedCryptoPaymentMethod(suggestedPaymentMethod);
41
+ setCryptoPaymentMethod(suggestedPaymentMethod);
38
42
  }
39
43
  }
40
44
  else {
41
45
  // Balance still loading, use suggested method
42
- setSelectedCryptoPaymentMethod(suggestedPaymentMethod);
46
+ setCryptoPaymentMethod(suggestedPaymentMethod);
43
47
  }
44
48
  }
45
49
  }, [
46
50
  paymentType,
51
+ setCryptoPaymentMethod,
47
52
  selectedCryptoPaymentMethod,
48
53
  suggestedPaymentMethod,
49
54
  hasEnoughBalance,
50
55
  isBalanceLoading,
51
- setSelectedCryptoPaymentMethod,
52
56
  ]);
53
57
  }