@b3dotfun/sdk 0.0.67 → 0.0.68-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/anyspend/react/components/AnySpend.js +38 -26
- package/dist/cjs/anyspend/react/components/AnySpendCustom.js +10 -6
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +1 -1
- package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +0 -7
- package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -7
- package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +3 -13
- package/dist/cjs/anyspend/react/hooks/index.d.ts +1 -0
- package/dist/cjs/anyspend/react/hooks/index.js +1 -0
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +1 -1
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +12 -12
- package/dist/cjs/anyspend/react/hooks/useConnectedWalletDisplay.js +2 -1
- package/dist/cjs/anyspend/react/hooks/useRecipientAddressState.d.ts +52 -0
- package/dist/cjs/anyspend/react/hooks/useRecipientAddressState.js +52 -0
- package/dist/esm/anyspend/react/components/AnySpend.js +38 -26
- package/dist/esm/anyspend/react/components/AnySpendCustom.js +10 -6
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +1 -1
- package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +1 -8
- package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -7
- package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +3 -13
- package/dist/esm/anyspend/react/hooks/index.d.ts +1 -0
- package/dist/esm/anyspend/react/hooks/index.js +1 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +1 -1
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +12 -12
- package/dist/esm/anyspend/react/hooks/useConnectedWalletDisplay.js +2 -1
- package/dist/esm/anyspend/react/hooks/useRecipientAddressState.d.ts +52 -0
- package/dist/esm/anyspend/react/hooks/useRecipientAddressState.js +49 -0
- package/dist/types/anyspend/react/components/common/CryptoReceiveSection.d.ts +2 -7
- package/dist/types/anyspend/react/hooks/index.d.ts +1 -0
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +1 -1
- package/dist/types/anyspend/react/hooks/useRecipientAddressState.d.ts +52 -0
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpend.tsx +43 -31
- package/src/anyspend/react/components/AnySpendCustom.tsx +10 -7
- package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +1 -1
- package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +1 -8
- package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +5 -27
- package/src/anyspend/react/hooks/index.ts +1 -0
- package/src/anyspend/react/hooks/useAnyspendFlow.ts +13 -12
- package/src/anyspend/react/hooks/useConnectedWalletDisplay.ts +4 -1
- package/src/anyspend/react/hooks/useRecipientAddressState.ts +78 -0
|
@@ -14,7 +14,9 @@ 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 { useConnectedWalletDisplay } from "../hooks/useConnectedWalletDisplay.js";
|
|
17
18
|
import { useCryptoPaymentMethodState } from "../hooks/useCryptoPaymentMethodState.js";
|
|
19
|
+
import { useRecipientAddressState } from "../hooks/useRecipientAddressState.js";
|
|
18
20
|
import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper.js";
|
|
19
21
|
import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod.js";
|
|
20
22
|
import { CryptoPaySection } from "./common/CryptoPaySection.js";
|
|
@@ -304,13 +306,22 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
304
306
|
// : isAddress(newRecipientAddress) || (resolvedAddress && isAddress(resolvedAddress)),
|
|
305
307
|
// [selectedDstChainId, newRecipientAddress, resolvedAddress]
|
|
306
308
|
// );
|
|
307
|
-
// State for recipient selection
|
|
308
|
-
const [recipientAddress, setRecipientAddress] = useState();
|
|
309
309
|
const { address: globalAddress, wallet: globalWallet, connectedEOAWallet } = useAccountWallet();
|
|
310
|
-
const recipientProfile = useProfile({ address: recipientAddress, fresh: true });
|
|
311
|
-
const recipientName = recipientProfile.data?.name;
|
|
312
310
|
// Auto-set active wallet from wagmi
|
|
313
311
|
useAutoSetActiveWalletFromWagmi();
|
|
312
|
+
// Get wallet address based on selected payment method
|
|
313
|
+
const { walletAddress } = useConnectedWalletDisplay(effectiveCryptoPaymentMethod);
|
|
314
|
+
// Recipient address state with dual-state system (auto + explicit user selection)
|
|
315
|
+
// The hook automatically manages priority: props > user selection > wallet/global
|
|
316
|
+
const { setSelectedRecipientAddress, effectiveRecipientAddress,
|
|
317
|
+
// resetRecipientAddress, // Not used yet, but available for future use
|
|
318
|
+
} = useRecipientAddressState({
|
|
319
|
+
recipientAddressFromProps,
|
|
320
|
+
walletAddress,
|
|
321
|
+
globalAddress,
|
|
322
|
+
});
|
|
323
|
+
const recipientProfile = useProfile({ address: effectiveRecipientAddress, fresh: true });
|
|
324
|
+
const recipientName = recipientProfile.data?.name;
|
|
314
325
|
// Check token balance for crypto payments
|
|
315
326
|
const { rawBalance, isLoading: isBalanceLoading } = useTokenBalanceDirect({
|
|
316
327
|
token: selectedSrcToken,
|
|
@@ -368,7 +379,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
368
379
|
type: "swap",
|
|
369
380
|
tradeType: isSrcInputDirty ? "EXACT_INPUT" : "EXACT_OUTPUT",
|
|
370
381
|
amount: activeInputAmountInWei,
|
|
371
|
-
recipientAddress,
|
|
382
|
+
recipientAddress: effectiveRecipientAddress,
|
|
372
383
|
}
|
|
373
384
|
: {
|
|
374
385
|
srcChain: base.id,
|
|
@@ -378,7 +389,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
378
389
|
type: "swap",
|
|
379
390
|
tradeType: "EXACT_INPUT",
|
|
380
391
|
amount: srcAmountOnrampInWei,
|
|
381
|
-
recipientAddress,
|
|
392
|
+
recipientAddress: effectiveRecipientAddress,
|
|
382
393
|
onrampVendor: getOnrampVendor(selectedFiatPaymentMethod),
|
|
383
394
|
});
|
|
384
395
|
// Load custom recipients from local storage on mount
|
|
@@ -394,8 +405,8 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
394
405
|
// Add custom recipients based on local storage
|
|
395
406
|
setCustomRecipients(parsedRecipients);
|
|
396
407
|
// If no wallet is connected and no recipient is selected, select the first recipient
|
|
397
|
-
if (!globalAddress && !
|
|
398
|
-
|
|
408
|
+
if (!globalAddress && !effectiveRecipientAddress && parsedRecipients.length > 0) {
|
|
409
|
+
setSelectedRecipientAddress(parsedRecipients[0].address);
|
|
399
410
|
}
|
|
400
411
|
}
|
|
401
412
|
}
|
|
@@ -403,7 +414,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
403
414
|
console.error("Error loading recipients from local storage:", err);
|
|
404
415
|
}
|
|
405
416
|
// Only run this effect once on mount
|
|
406
|
-
}, [globalAddress,
|
|
417
|
+
}, [globalAddress, effectiveRecipientAddress, customRecipients.length, setSelectedRecipientAddress]);
|
|
407
418
|
// Update dependent amount when relay price changes
|
|
408
419
|
useEffect(() => {
|
|
409
420
|
if (anyspendQuote?.data &&
|
|
@@ -506,7 +517,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
506
517
|
return { text: "No quote found", disable: true, error: false, loading: false };
|
|
507
518
|
if (activeTab === "fiat") {
|
|
508
519
|
// For fiat: check recipient first, then payment method
|
|
509
|
-
if (!
|
|
520
|
+
if (!effectiveRecipientAddress)
|
|
510
521
|
return { text: "Select recipient", disable: false, error: false, loading: false };
|
|
511
522
|
// If no fiat payment method selected, show "Select payment method"
|
|
512
523
|
if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
|
|
@@ -522,7 +533,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
522
533
|
return { text: "Choose payment method", disable: false, error: false, loading: false };
|
|
523
534
|
}
|
|
524
535
|
// Check recipient after payment method
|
|
525
|
-
if (!
|
|
536
|
+
if (!effectiveRecipientAddress)
|
|
526
537
|
return { text: "Select recipient", disable: false, error: false, loading: false };
|
|
527
538
|
// If payment method selected, show appropriate action
|
|
528
539
|
if (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ||
|
|
@@ -538,7 +549,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
538
549
|
activeInputAmountInWei,
|
|
539
550
|
isSameChainSameToken,
|
|
540
551
|
isLoadingAnyspendQuote,
|
|
541
|
-
|
|
552
|
+
effectiveRecipientAddress,
|
|
542
553
|
isCreatingOrder,
|
|
543
554
|
isCreatingOnrampOrder,
|
|
544
555
|
anyspendQuote,
|
|
@@ -554,11 +565,11 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
554
565
|
invariant(anyspendQuote, "Relay price is not found");
|
|
555
566
|
if (activeTab === "fiat") {
|
|
556
567
|
// For fiat: check recipient first
|
|
557
|
-
if (!
|
|
568
|
+
if (!effectiveRecipientAddress) {
|
|
558
569
|
navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward");
|
|
559
570
|
return;
|
|
560
571
|
}
|
|
561
|
-
invariant(
|
|
572
|
+
invariant(effectiveRecipientAddress, "Recipient address is not found");
|
|
562
573
|
// If no fiat payment method selected, show payment method selection
|
|
563
574
|
if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
|
|
564
575
|
navigateToPanel(PanelView.FIAT_PAYMENT_METHOD, "forward");
|
|
@@ -577,11 +588,11 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
577
588
|
return;
|
|
578
589
|
}
|
|
579
590
|
// Check recipient after payment method
|
|
580
|
-
if (!
|
|
591
|
+
if (!effectiveRecipientAddress) {
|
|
581
592
|
navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward");
|
|
582
593
|
return;
|
|
583
594
|
}
|
|
584
|
-
invariant(
|
|
595
|
+
invariant(effectiveRecipientAddress, "Recipient address is not found");
|
|
585
596
|
// If payment method is selected, create order with payment method info
|
|
586
597
|
if (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ||
|
|
587
598
|
effectiveCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET ||
|
|
@@ -610,13 +621,13 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
610
621
|
const handleCryptoSwap = async (method) => {
|
|
611
622
|
try {
|
|
612
623
|
invariant(anyspendQuote, "Relay price is not found");
|
|
613
|
-
invariant(
|
|
624
|
+
invariant(effectiveRecipientAddress, "Recipient address is not found");
|
|
614
625
|
// Debug: Check payment method values
|
|
615
626
|
console.log("handleCryptoSwap - method parameter:", method);
|
|
616
627
|
console.log("handleCryptoSwap - selectedCryptoPaymentMethod state:", selectedCryptoPaymentMethod);
|
|
617
628
|
const srcAmountBigInt = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
|
|
618
629
|
createOrder({
|
|
619
|
-
recipientAddress,
|
|
630
|
+
recipientAddress: effectiveRecipientAddress,
|
|
620
631
|
orderType: "swap",
|
|
621
632
|
srcChain: selectedSrcChainId,
|
|
622
633
|
dstChain: isBuyMode ? destinationTokenChainId : selectedDstChainId,
|
|
@@ -638,7 +649,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
638
649
|
const handleFiatOrder = async (paymentMethod) => {
|
|
639
650
|
try {
|
|
640
651
|
invariant(anyspendQuote, "Relay price is not found");
|
|
641
|
-
invariant(
|
|
652
|
+
invariant(effectiveRecipientAddress, "Recipient address is not found");
|
|
642
653
|
if (!srcAmountOnRamp || parseFloat(srcAmountOnRamp) <= 0) {
|
|
643
654
|
toast.error("Please enter a valid amount");
|
|
644
655
|
return;
|
|
@@ -678,7 +689,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
678
689
|
return selectedDstToken;
|
|
679
690
|
};
|
|
680
691
|
createOnrampOrder({
|
|
681
|
-
recipientAddress,
|
|
692
|
+
recipientAddress: effectiveRecipientAddress,
|
|
682
693
|
orderType: "swap",
|
|
683
694
|
dstChain: getDstToken().chainId,
|
|
684
695
|
dstToken: getDstToken(),
|
|
@@ -784,7 +795,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
784
795
|
else {
|
|
785
796
|
setActivePanel(panelIndex);
|
|
786
797
|
}
|
|
787
|
-
}, _recipientAddress:
|
|
798
|
+
}, _recipientAddress: effectiveRecipientAddress, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, destinationAmount: dstAmount, onDestinationTokenChange: setSelectedDstToken, onDestinationChainChange: setSelectedDstChainId, fiatPaymentMethodIndex: PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: PanelView.RECIPIENT_SELECTION, hideDstToken: isBuyMode, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward"), customUsdInputValues: customUsdInputValues }) })), _jsx(Button, { variant: "ghost", className: cn("border-as-stroke bg-as-surface-primary absolute left-1/2 top-1/2 z-10 h-10 w-10 -translate-x-1/2 -translate-y-1/2 rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", isBuyMode && "top-[calc(50%+56px)] cursor-default", activeTab === "fiat" && "hidden"), onClick: () => {
|
|
788
799
|
if (activeTab === "fiat" || isBuyMode) {
|
|
789
800
|
return;
|
|
790
801
|
}
|
|
@@ -803,11 +814,11 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
803
814
|
const tempDstAmount = dstAmount;
|
|
804
815
|
setSrcAmount(tempDstAmount);
|
|
805
816
|
setDstAmount(tempSrcAmount);
|
|
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,
|
|
817
|
+
}, 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, effectiveRecipientAddress: effectiveRecipientAddress, recipientName: recipientName || undefined, onSelectRecipient: () => navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward"), dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
|
|
807
818
|
setIsSrcInputDirty(false);
|
|
808
819
|
setDstAmount(value);
|
|
809
|
-
}, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward")
|
|
810
|
-
const onrampPaymentView = (_jsx(PanelOnrampPayment, { srcAmountOnRamp: srcAmountOnRamp, recipientName: recipientName || undefined, recipientAddress:
|
|
820
|
+
}, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward") }))] }), _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 || effectiveRecipientAddress) ? (_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] })] }));
|
|
821
|
+
const onrampPaymentView = (_jsx(PanelOnrampPayment, { srcAmountOnRamp: srcAmountOnRamp, recipientName: recipientName || undefined, recipientAddress: effectiveRecipientAddress, isBuyMode: isBuyMode, destinationTokenChainId: destinationTokenChainId, destinationTokenAddress: destinationTokenAddress, selectedDstChainId: selectedDstChainId, selectedDstToken: selectedDstToken, orderType: "swap", anyspendQuote: anyspendQuote, globalAddress: globalAddress, onOrderCreated: orderId => {
|
|
811
822
|
setOrderId(orderId);
|
|
812
823
|
navigateToPanel(PanelView.ORDER_DETAILS, "forward");
|
|
813
824
|
// Add orderId and payment method to URL for persistence
|
|
@@ -822,8 +833,9 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
|
|
|
822
833
|
}
|
|
823
834
|
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
824
835
|
}, onBack: navigateBack, recipientEnsName: globalWallet?.ensName, recipientImageUrl: globalWallet?.meta?.icon }));
|
|
825
|
-
const recipientSelectionView = (_jsx(RecipientSelection, { initialValue:
|
|
826
|
-
|
|
836
|
+
const recipientSelectionView = (_jsx(RecipientSelection, { initialValue: effectiveRecipientAddress || "", onBack: navigateBack, onConfirm: address => {
|
|
837
|
+
// User manually selected a recipient
|
|
838
|
+
setSelectedRecipientAddress(address);
|
|
827
839
|
navigateBack();
|
|
828
840
|
} }));
|
|
829
841
|
const cryptoPaymentMethodView = (_jsx(CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: globalWallet, selectedPaymentMethod: effectiveCryptoPaymentMethod, setSelectedPaymentMethod: method => {
|
|
@@ -16,6 +16,7 @@ import { base } from "viem/chains";
|
|
|
16
16
|
import { useFeatureFlags } from "../contexts/FeatureFlagsContext.js";
|
|
17
17
|
import { useAutoSetActiveWalletFromWagmi } from "../hooks/useAutoSetActiveWalletFromWagmi.js";
|
|
18
18
|
import { useCryptoPaymentMethodState } from "../hooks/useCryptoPaymentMethodState.js";
|
|
19
|
+
import { useRecipientAddressState } from "../hooks/useRecipientAddressState.js";
|
|
19
20
|
import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper.js";
|
|
20
21
|
import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod.js";
|
|
21
22
|
import { FeeBreakDown } from "./common/FeeBreakDown.js";
|
|
@@ -122,10 +123,12 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
|
|
|
122
123
|
const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState(FiatPaymentMethod.NONE);
|
|
123
124
|
// Get current user's wallet
|
|
124
125
|
const currentWallet = useAccountWallet();
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
// Recipient address state with dual-state system (auto + explicit user selection)
|
|
127
|
+
// The hook automatically manages priority: props > user selection > global address
|
|
128
|
+
const { setSelectedRecipientAddress, effectiveRecipientAddress: recipientAddress } = useRecipientAddressState({
|
|
129
|
+
recipientAddressFromProps: recipientAddressProps,
|
|
130
|
+
globalAddress: currentWallet.address,
|
|
131
|
+
});
|
|
129
132
|
const [orderId, setOrderId] = useState(loadOrder);
|
|
130
133
|
// Track if onSuccess has been called for the current order
|
|
131
134
|
const onSuccessCalled = React.useRef(false);
|
|
@@ -519,8 +522,9 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
|
|
|
519
522
|
}
|
|
520
523
|
}, 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") : selectedFiatPaymentMethod === FiatPaymentMethod.NONE ? ("Select payment method") : anyspendQuote ? (_jsxs(_Fragment, { children: [_jsx("span", { children: "Buy" }), _jsx(ChevronRightCircle, { className: "absolute right-0 top-1/2 size-6 -translate-y-1/2 opacity-70" })] })) : ("No quote found") }) }) })] }) })] })] }));
|
|
521
524
|
// Recipient selection view
|
|
522
|
-
const recipientSelectionView = (_jsx("div", { className: cn("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: _jsx(RecipientSelection, { initialValue:
|
|
523
|
-
|
|
525
|
+
const recipientSelectionView = (_jsx("div", { className: cn("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: _jsx(RecipientSelection, { initialValue: recipientAddress || "", title: "Add recipient address or ENS", description: "Send tokens to another address", onBack: () => setActivePanel(PanelView.CONFIRM_ORDER), onConfirm: address => {
|
|
526
|
+
// User manually selected a recipient
|
|
527
|
+
setSelectedRecipientAddress(address);
|
|
524
528
|
setActivePanel(PanelView.CONFIRM_ORDER);
|
|
525
529
|
} }) }));
|
|
526
530
|
// Crypto payment method view
|
|
@@ -168,7 +168,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
168
168
|
}
|
|
169
169
|
};
|
|
170
170
|
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." })] }) }));
|
|
171
|
-
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,
|
|
171
|
+
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, effectiveRecipientAddress: 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 => {
|
|
172
172
|
setIsSrcInputDirty(false);
|
|
173
173
|
setSrcAmount(value);
|
|
174
174
|
}, 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] }));
|
|
@@ -4,7 +4,7 @@ import { useAccountWallet } from "../../../../global-account/react/index.js";
|
|
|
4
4
|
import { cn } from "../../../../shared/utils/cn.js";
|
|
5
5
|
import { shortenAddress } from "../../../../shared/utils/formatAddress.js";
|
|
6
6
|
import { client } from "../../../../shared/utils/thirdweb.js";
|
|
7
|
-
import { WalletCoinbase, WalletMetamask,
|
|
7
|
+
import { WalletCoinbase, WalletMetamask, WalletRainbow, WalletWalletConnect } from "@web3icons/react";
|
|
8
8
|
import { ChevronLeft, ChevronRightCircle, Wallet, X, ZapIcon } from "lucide-react";
|
|
9
9
|
import { useState } from "react";
|
|
10
10
|
import { createPortal } from "react-dom";
|
|
@@ -94,13 +94,6 @@ export function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentM
|
|
|
94
94
|
description: "Connect using WalletConnect protocol",
|
|
95
95
|
connector: availableConnectors.find(c => c.name === "WalletConnect"),
|
|
96
96
|
},
|
|
97
|
-
{
|
|
98
|
-
id: "phantom",
|
|
99
|
-
name: "Phantom",
|
|
100
|
-
icon: _jsx(WalletPhantom, { size: 48 }),
|
|
101
|
-
description: "Connect using Phantom wallet",
|
|
102
|
-
connector: availableConnectors.find(c => c.name === "Phantom"),
|
|
103
|
-
},
|
|
104
97
|
].filter(wallet => wallet.connector); // Only show wallets that have available connectors
|
|
105
98
|
// Reset modal state when closing
|
|
106
99
|
const handleCloseModal = () => {
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { components } from "../../../types/api";
|
|
2
|
-
import { CryptoPaymentMethodType } from "./CryptoPaymentMethod";
|
|
3
2
|
interface CryptoReceiveSectionProps {
|
|
4
3
|
isDepositMode?: boolean;
|
|
5
4
|
isBuyMode?: boolean;
|
|
6
|
-
|
|
5
|
+
effectiveRecipientAddress?: string;
|
|
7
6
|
recipientName?: string;
|
|
8
7
|
onSelectRecipient: () => void;
|
|
9
|
-
setRecipientAddress?: (address: string | undefined) => void;
|
|
10
|
-
recipientAddressFromProps?: string;
|
|
11
|
-
globalAddress?: string;
|
|
12
8
|
dstAmount: string;
|
|
13
9
|
dstToken: components["schemas"]["Token"];
|
|
14
10
|
selectedDstChainId?: number;
|
|
@@ -21,7 +17,6 @@ interface CryptoReceiveSectionProps {
|
|
|
21
17
|
dstTokenLogoURI?: string;
|
|
22
18
|
onShowPointsDetail?: () => void;
|
|
23
19
|
onShowFeeDetail?: () => void;
|
|
24
|
-
selectedCryptoPaymentMethod?: CryptoPaymentMethodType;
|
|
25
20
|
}
|
|
26
|
-
export declare function CryptoReceiveSection({ isDepositMode, isBuyMode,
|
|
21
|
+
export declare function CryptoReceiveSection({ isDepositMode, isBuyMode, effectiveRecipientAddress, recipientName, onSelectRecipient, dstAmount, dstToken, selectedDstChainId, setSelectedDstChainId, setSelectedDstToken, isSrcInputDirty, onChangeDstAmount, anyspendQuote, dstTokenSymbol, dstTokenLogoURI, onShowPointsDetail, onShowFeeDetail, }: CryptoReceiveSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
27
22
|
export {};
|
|
@@ -5,26 +5,16 @@ import { shortenAddress } from "../../../../shared/utils/formatAddress.js";
|
|
|
5
5
|
import { formatDisplayNumber } from "../../../../shared/utils/number.js";
|
|
6
6
|
import { ChevronRight, Info } from "lucide-react";
|
|
7
7
|
import { motion } from "motion/react";
|
|
8
|
-
import { useEffect } from "react";
|
|
9
8
|
import { useFeatureFlags } from "../../contexts/FeatureFlagsContext.js";
|
|
10
|
-
import { useConnectedWalletDisplay } from "../../hooks/useConnectedWalletDisplay.js";
|
|
11
9
|
import { OrderTokenAmount } from "./OrderTokenAmount.js";
|
|
12
10
|
import { PointsBadge } from "./PointsBadge.js";
|
|
13
|
-
export function CryptoReceiveSection({ isDepositMode = false, isBuyMode = false,
|
|
11
|
+
export function CryptoReceiveSection({ isDepositMode = false, isBuyMode = false, effectiveRecipientAddress, recipientName, onSelectRecipient, dstAmount, dstToken, selectedDstChainId, setSelectedDstChainId, setSelectedDstToken, isSrcInputDirty, onChangeDstAmount, anyspendQuote, dstTokenSymbol, dstTokenLogoURI, onShowPointsDetail, onShowFeeDetail, }) {
|
|
14
12
|
const featureFlags = useFeatureFlags();
|
|
15
|
-
|
|
16
|
-
const { walletAddress } = useConnectedWalletDisplay(selectedCryptoPaymentMethod);
|
|
17
|
-
// Set default recipient address when wallet changes
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
if (setRecipientAddress) {
|
|
20
|
-
setRecipientAddress(recipientAddressFromProps || walletAddress || globalAddress);
|
|
21
|
-
}
|
|
22
|
-
}, [recipientAddressFromProps, walletAddress, globalAddress, setRecipientAddress]);
|
|
23
|
-
return (_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.1, ease: "easeInOut" }, className: "receive-section bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6", children: [_jsxs("div", { className: "flex w-full items-center justify-between", children: [_jsxs("div", { className: "text-as-primary/50 flex h-7 items-center gap-1.5 text-sm", children: [isDepositMode ? "Deposit" : "Receive", isSrcInputDirty && anyspendQuote?.data?.fee && onShowFeeDetail && (_jsx("button", { onClick: onShowFeeDetail, className: "text-as-primary/40 hover:text-as-primary/60 transition-colors", children: _jsx(Info, { className: "h-4 w-4" }) }))] }), selectedRecipientAddress ? (_jsx("button", { className: cn("text-as-tertiarry flex h-7 items-center gap-2 rounded-lg"), onClick: onSelectRecipient, children: _jsxs(_Fragment, { children: [_jsx("span", { className: "text-as-tertiarry flex items-center gap-1 text-sm", children: recipientName ? formatUsername(recipientName) : shortenAddress(selectedRecipientAddress || "") }), _jsx(ChevronRight, { className: "h-4 w-4" })] }) })) : (_jsx("button", { className: "text-as-primary/70 flex items-center gap-1 rounded-lg", onClick: onSelectRecipient, children: _jsx("div", { className: "text-sm font-medium", children: "Select recipient" }) }))] }), isBuyMode || isDepositMode ? (
|
|
13
|
+
return (_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.1, ease: "easeInOut" }, className: "receive-section bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6", children: [_jsxs("div", { className: "flex w-full items-center justify-between", children: [_jsxs("div", { className: "text-as-primary/50 flex h-7 items-center gap-1.5 text-sm", children: [isDepositMode ? "Deposit" : "Receive", isSrcInputDirty && anyspendQuote?.data?.fee && onShowFeeDetail && (_jsx("button", { onClick: onShowFeeDetail, className: "text-as-primary/40 hover:text-as-primary/60 transition-colors", children: _jsx(Info, { className: "h-4 w-4" }) }))] }), effectiveRecipientAddress ? (_jsx("button", { className: cn("text-as-tertiarry flex h-7 items-center gap-2 rounded-lg"), onClick: onSelectRecipient, children: _jsxs(_Fragment, { children: [_jsx("span", { className: "text-as-tertiarry flex items-center gap-1 text-sm", children: recipientName ? formatUsername(recipientName) : shortenAddress(effectiveRecipientAddress || "") }), _jsx(ChevronRight, { className: "h-4 w-4" })] }) })) : (_jsx("button", { className: "text-as-primary/70 flex items-center gap-1 rounded-lg", onClick: onSelectRecipient, children: _jsx("div", { className: "text-sm font-medium", children: "Select recipient" }) }))] }), isBuyMode || isDepositMode ? (
|
|
24
14
|
// Fixed destination token display for buy mode and deposit mode
|
|
25
15
|
_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-as-primary text-2xl font-bold", children: dstAmount || "0" }), _jsxs("div", { className: "bg-as-brand/10 border-as-brand/30 flex items-center gap-3 rounded-xl border px-4 py-3", children: [(dstTokenLogoURI || dstToken.metadata?.logoURI) && (_jsx("img", { src: dstTokenLogoURI || dstToken.metadata?.logoURI, alt: dstTokenSymbol || dstToken.symbol, className: "h-8 w-8 rounded-full" })), _jsx("span", { className: "text-as-brand text-lg font-bold", children: dstTokenSymbol || dstToken.symbol })] })] })) : (
|
|
26
16
|
// Token selection for regular swap mode
|
|
27
|
-
_jsx(OrderTokenAmount, { address:
|
|
17
|
+
_jsx(OrderTokenAmount, { address: effectiveRecipientAddress, context: "to", inputValue: dstAmount, onChangeInput: onChangeDstAmount || (() => { }), chainId: selectedDstChainId || dstToken.chainId, setChainId: setSelectedDstChainId || (() => { }), token: dstToken, setToken: setSelectedDstToken || (() => { }) })), _jsxs("div", { className: "text-as-primary/50 flex h-5 items-center justify-start gap-2 text-sm", children: [_jsxs("div", { className: "flex items-center gap-2", children: [formatDisplayNumber(anyspendQuote?.data?.currencyOut?.amountUsd, {
|
|
28
18
|
style: "currency",
|
|
29
19
|
fallback: "",
|
|
30
20
|
}), anyspendQuote?.data?.currencyIn?.amountUsd &&
|
|
@@ -8,6 +8,7 @@ export * from "./useCoinbaseOnrampOptions";
|
|
|
8
8
|
export * from "./useConnectedUserProfile";
|
|
9
9
|
export * from "./useGeoOnrampOptions";
|
|
10
10
|
export * from "./useGetGeo";
|
|
11
|
+
export * from "./useRecipientAddressState";
|
|
11
12
|
export * from "./useSigMint";
|
|
12
13
|
export * from "./useStripeClientSecret";
|
|
13
14
|
export * from "./useStripeSupport";
|
|
@@ -8,6 +8,7 @@ export * from "./useCoinbaseOnrampOptions.js";
|
|
|
8
8
|
export * from "./useConnectedUserProfile.js";
|
|
9
9
|
export * from "./useGeoOnrampOptions.js";
|
|
10
10
|
export * from "./useGetGeo.js";
|
|
11
|
+
export * from "./useRecipientAddressState.js";
|
|
11
12
|
export * from "./useSigMint.js";
|
|
12
13
|
export * from "./useStripeClientSecret.js";
|
|
13
14
|
export * from "./useStripeSupport.js";
|
|
@@ -102,7 +102,7 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
102
102
|
selectedFiatPaymentMethod: FiatPaymentMethod;
|
|
103
103
|
setSelectedFiatPaymentMethod: import("react").Dispatch<import("react").SetStateAction<FiatPaymentMethod>>;
|
|
104
104
|
selectedRecipientAddress: string | undefined;
|
|
105
|
-
setSelectedRecipientAddress:
|
|
105
|
+
setSelectedRecipientAddress: (address: string | undefined) => void;
|
|
106
106
|
recipientName: string | null | undefined;
|
|
107
107
|
globalAddress: string | undefined;
|
|
108
108
|
hasEnoughBalance: boolean;
|
|
@@ -13,6 +13,7 @@ import { useAutoSelectCryptoPaymentMethod } from "./useAutoSelectCryptoPaymentMe
|
|
|
13
13
|
import { useAutoSetActiveWalletFromWagmi } from "./useAutoSetActiveWalletFromWagmi.js";
|
|
14
14
|
import { useConnectedWalletDisplay } from "./useConnectedWalletDisplay.js";
|
|
15
15
|
import { useCryptoPaymentMethodState } from "./useCryptoPaymentMethodState.js";
|
|
16
|
+
import { useRecipientAddressState } from "./useRecipientAddressState.js";
|
|
16
17
|
export var PanelView;
|
|
17
18
|
(function (PanelView) {
|
|
18
19
|
PanelView[PanelView["MAIN"] = 0] = "MAIN";
|
|
@@ -46,20 +47,19 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
46
47
|
// Payment method state with dual-state system (auto + explicit user selection)
|
|
47
48
|
const { cryptoPaymentMethod, setCryptoPaymentMethod, selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod, effectiveCryptoPaymentMethod, resetPaymentMethods, } = useCryptoPaymentMethodState();
|
|
48
49
|
const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState(FiatPaymentMethod.NONE);
|
|
49
|
-
// Recipient state
|
|
50
|
+
// Recipient state with dual-state system (auto + explicit user selection)
|
|
50
51
|
const { address: globalAddress } = useAccountWallet();
|
|
51
52
|
const { walletAddress } = useConnectedWalletDisplay(effectiveCryptoPaymentMethod);
|
|
52
|
-
const [selectedRecipientAddress, setSelectedRecipientAddress] = useState(recipientAddress);
|
|
53
|
-
const recipientProfile = useProfile({ address: selectedRecipientAddress, fresh: true });
|
|
54
|
-
const recipientName = recipientProfile.data?.name;
|
|
55
53
|
// Auto-set active wallet from wagmi
|
|
56
54
|
useAutoSetActiveWalletFromWagmi();
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
55
|
+
// Recipient address state - hook automatically manages priority: props > user selection > wallet/global
|
|
56
|
+
const { setSelectedRecipientAddress, effectiveRecipientAddress } = useRecipientAddressState({
|
|
57
|
+
recipientAddressFromProps: recipientAddress,
|
|
58
|
+
walletAddress,
|
|
59
|
+
globalAddress,
|
|
60
|
+
});
|
|
61
|
+
const recipientProfile = useProfile({ address: effectiveRecipientAddress, fresh: true });
|
|
62
|
+
const recipientName = recipientProfile.data?.name;
|
|
63
63
|
// Check token balance for crypto payments
|
|
64
64
|
const { rawBalance, isLoading: isBalanceLoading } = useTokenBalance({
|
|
65
65
|
token: selectedSrcToken,
|
|
@@ -142,7 +142,7 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
142
142
|
dstTokenAddress: selectedDstToken.address,
|
|
143
143
|
type: orderType,
|
|
144
144
|
amount: activeInputAmountInWei,
|
|
145
|
-
recipientAddress:
|
|
145
|
+
recipientAddress: effectiveRecipientAddress,
|
|
146
146
|
onrampVendor: paymentType === "fiat" ? getOnrampVendor(selectedFiatPaymentMethod) : undefined,
|
|
147
147
|
});
|
|
148
148
|
// Get geo options for fiat
|
|
@@ -257,7 +257,7 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
257
257
|
selectedFiatPaymentMethod,
|
|
258
258
|
setSelectedFiatPaymentMethod,
|
|
259
259
|
// Recipient
|
|
260
|
-
selectedRecipientAddress,
|
|
260
|
+
selectedRecipientAddress: effectiveRecipientAddress,
|
|
261
261
|
setSelectedRecipientAddress,
|
|
262
262
|
recipientName,
|
|
263
263
|
globalAddress,
|
|
@@ -8,6 +8,7 @@ import { CryptoPaymentMethodType } from "../components/common/CryptoPaymentMetho
|
|
|
8
8
|
export function useConnectedWalletDisplay(selectedCryptoPaymentMethod) {
|
|
9
9
|
const { connectedEOAWallet, connectedSmartWallet } = useAccountWallet();
|
|
10
10
|
const { address: wagmiAddress, isConnected: wagmiWalletIsConnected } = useAccount();
|
|
11
|
+
const globalWalletAddress = connectedSmartWallet?.getAccount()?.address;
|
|
11
12
|
// Helper function to check if two addresses are the same
|
|
12
13
|
const isSameAddress = (addr1, addr2) => {
|
|
13
14
|
if (!addr1 || !addr2)
|
|
@@ -16,7 +17,7 @@ export function useConnectedWalletDisplay(selectedCryptoPaymentMethod) {
|
|
|
16
17
|
};
|
|
17
18
|
// Check if connectedEOAWallet and wagmi wallet represent the same wallet
|
|
18
19
|
const connectedEOAAddress = connectedEOAWallet?.getAccount()?.address;
|
|
19
|
-
const isWalletDuplicated = isSameAddress(connectedEOAAddress, wagmiAddress);
|
|
20
|
+
const isWalletDuplicated = isSameAddress(connectedEOAAddress, wagmiAddress) || isSameAddress(globalWalletAddress, wagmiAddress);
|
|
20
21
|
// Determine which wallet to show (prefer connectedEOAWallet if both exist and are the same)
|
|
21
22
|
const shouldShowConnectedEOA = !!connectedEOAWallet;
|
|
22
23
|
const shouldShowWagmiWallet = wagmiWalletIsConnected && (!isWalletDuplicated || !connectedEOAWallet);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
interface UseRecipientAddressStateProps {
|
|
2
|
+
/** Fixed recipient address from props (highest priority) */
|
|
3
|
+
recipientAddressFromProps?: string;
|
|
4
|
+
/** Connected wallet address from payment method */
|
|
5
|
+
walletAddress?: string;
|
|
6
|
+
/** Global account address */
|
|
7
|
+
globalAddress?: string;
|
|
8
|
+
}
|
|
9
|
+
interface UseRecipientAddressStateResult {
|
|
10
|
+
/** User explicitly selected recipient address (undefined means no explicit selection) */
|
|
11
|
+
selectedRecipientAddress: string | undefined;
|
|
12
|
+
/** Function to update the user-selected recipient address */
|
|
13
|
+
setSelectedRecipientAddress: (address: string | undefined) => void;
|
|
14
|
+
/** Effective recipient address (follows priority: props > user selection > wallet/global) */
|
|
15
|
+
effectiveRecipientAddress: string | undefined;
|
|
16
|
+
/** Reset recipient address state */
|
|
17
|
+
resetRecipientAddress: () => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Custom hook to manage recipient address state with automatic priority handling:
|
|
21
|
+
*
|
|
22
|
+
* **Priority System:**
|
|
23
|
+
* 1. `recipientAddressFromProps` - Fixed recipient from component props (highest priority)
|
|
24
|
+
* 2. `selectedRecipientAddress` - User's explicit manual selection
|
|
25
|
+
* 3. `walletAddress` or `globalAddress` - Auto-selected fallback
|
|
26
|
+
*
|
|
27
|
+
* **Key Features:**
|
|
28
|
+
* - Automatically manages recipient address based on priority
|
|
29
|
+
* - Preserves user's manual selections
|
|
30
|
+
* - Updates automatically when wallet/global address changes (if no manual selection)
|
|
31
|
+
* - Derived value approach - no useEffect needed, no stale state bugs
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* const {
|
|
36
|
+
* selectedRecipientAddress,
|
|
37
|
+
* setSelectedRecipientAddress,
|
|
38
|
+
* effectiveRecipientAddress,
|
|
39
|
+
* resetRecipientAddress
|
|
40
|
+
* } = useRecipientAddressState({
|
|
41
|
+
* recipientAddressFromProps,
|
|
42
|
+
* walletAddress,
|
|
43
|
+
* globalAddress,
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* // Use effectiveRecipientAddress for display and operations
|
|
47
|
+
* // Use setSelectedRecipientAddress when user explicitly selects
|
|
48
|
+
* // Call resetRecipientAddress when switching tabs or going back
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function useRecipientAddressState({ recipientAddressFromProps, walletAddress, globalAddress, }?: UseRecipientAddressStateProps): UseRecipientAddressStateResult;
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Custom hook to manage recipient address state with automatic priority handling:
|
|
4
|
+
*
|
|
5
|
+
* **Priority System:**
|
|
6
|
+
* 1. `recipientAddressFromProps` - Fixed recipient from component props (highest priority)
|
|
7
|
+
* 2. `selectedRecipientAddress` - User's explicit manual selection
|
|
8
|
+
* 3. `walletAddress` or `globalAddress` - Auto-selected fallback
|
|
9
|
+
*
|
|
10
|
+
* **Key Features:**
|
|
11
|
+
* - Automatically manages recipient address based on priority
|
|
12
|
+
* - Preserves user's manual selections
|
|
13
|
+
* - Updates automatically when wallet/global address changes (if no manual selection)
|
|
14
|
+
* - Derived value approach - no useEffect needed, no stale state bugs
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* const {
|
|
19
|
+
* selectedRecipientAddress,
|
|
20
|
+
* setSelectedRecipientAddress,
|
|
21
|
+
* effectiveRecipientAddress,
|
|
22
|
+
* resetRecipientAddress
|
|
23
|
+
* } = useRecipientAddressState({
|
|
24
|
+
* recipientAddressFromProps,
|
|
25
|
+
* walletAddress,
|
|
26
|
+
* globalAddress,
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Use effectiveRecipientAddress for display and operations
|
|
30
|
+
* // Use setSelectedRecipientAddress when user explicitly selects
|
|
31
|
+
* // Call resetRecipientAddress when switching tabs or going back
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function useRecipientAddressState({ recipientAddressFromProps, walletAddress, globalAddress, } = {}) {
|
|
35
|
+
// selectedRecipientAddress: explicitly selected by user (undefined means no explicit selection)
|
|
36
|
+
const [selectedRecipientAddress, setSelectedRecipientAddress] = useState(undefined);
|
|
37
|
+
// The effective recipient address, derived on each render, respecting priority.
|
|
38
|
+
const effectiveRecipientAddress = recipientAddressFromProps || selectedRecipientAddress || walletAddress || globalAddress;
|
|
39
|
+
// Helper function to reset user's manual selection.
|
|
40
|
+
const resetRecipientAddress = () => {
|
|
41
|
+
setSelectedRecipientAddress(undefined);
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
selectedRecipientAddress,
|
|
45
|
+
setSelectedRecipientAddress,
|
|
46
|
+
effectiveRecipientAddress,
|
|
47
|
+
resetRecipientAddress,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { components } from "../../../types/api";
|
|
2
|
-
import { CryptoPaymentMethodType } from "./CryptoPaymentMethod";
|
|
3
2
|
interface CryptoReceiveSectionProps {
|
|
4
3
|
isDepositMode?: boolean;
|
|
5
4
|
isBuyMode?: boolean;
|
|
6
|
-
|
|
5
|
+
effectiveRecipientAddress?: string;
|
|
7
6
|
recipientName?: string;
|
|
8
7
|
onSelectRecipient: () => void;
|
|
9
|
-
setRecipientAddress?: (address: string | undefined) => void;
|
|
10
|
-
recipientAddressFromProps?: string;
|
|
11
|
-
globalAddress?: string;
|
|
12
8
|
dstAmount: string;
|
|
13
9
|
dstToken: components["schemas"]["Token"];
|
|
14
10
|
selectedDstChainId?: number;
|
|
@@ -21,7 +17,6 @@ interface CryptoReceiveSectionProps {
|
|
|
21
17
|
dstTokenLogoURI?: string;
|
|
22
18
|
onShowPointsDetail?: () => void;
|
|
23
19
|
onShowFeeDetail?: () => void;
|
|
24
|
-
selectedCryptoPaymentMethod?: CryptoPaymentMethodType;
|
|
25
20
|
}
|
|
26
|
-
export declare function CryptoReceiveSection({ isDepositMode, isBuyMode,
|
|
21
|
+
export declare function CryptoReceiveSection({ isDepositMode, isBuyMode, effectiveRecipientAddress, recipientName, onSelectRecipient, dstAmount, dstToken, selectedDstChainId, setSelectedDstChainId, setSelectedDstToken, isSrcInputDirty, onChangeDstAmount, anyspendQuote, dstTokenSymbol, dstTokenLogoURI, onShowPointsDetail, onShowFeeDetail, }: CryptoReceiveSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
27
22
|
export {};
|
|
@@ -8,6 +8,7 @@ export * from "./useCoinbaseOnrampOptions";
|
|
|
8
8
|
export * from "./useConnectedUserProfile";
|
|
9
9
|
export * from "./useGeoOnrampOptions";
|
|
10
10
|
export * from "./useGetGeo";
|
|
11
|
+
export * from "./useRecipientAddressState";
|
|
11
12
|
export * from "./useSigMint";
|
|
12
13
|
export * from "./useStripeClientSecret";
|
|
13
14
|
export * from "./useStripeSupport";
|
|
@@ -102,7 +102,7 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
102
102
|
selectedFiatPaymentMethod: FiatPaymentMethod;
|
|
103
103
|
setSelectedFiatPaymentMethod: import("react").Dispatch<import("react").SetStateAction<FiatPaymentMethod>>;
|
|
104
104
|
selectedRecipientAddress: string | undefined;
|
|
105
|
-
setSelectedRecipientAddress:
|
|
105
|
+
setSelectedRecipientAddress: (address: string | undefined) => void;
|
|
106
106
|
recipientName: string | null | undefined;
|
|
107
107
|
globalAddress: string | undefined;
|
|
108
108
|
hasEnoughBalance: boolean;
|