@b3dotfun/sdk 0.0.16 → 0.0.17-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.d.ts +5 -2
- package/dist/cjs/anyspend/react/components/AnySpend.js +264 -55
- package/dist/cjs/anyspend/react/components/AnySpendCustom.js +25 -29
- package/dist/cjs/anyspend/react/components/common/ConnectWalletPayment.d.ts +15 -0
- package/dist/cjs/anyspend/react/components/common/ConnectWalletPayment.js +49 -0
- package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.d.ts +20 -0
- package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +118 -0
- package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.d.ts +15 -0
- package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.js +71 -0
- package/dist/cjs/anyspend/react/components/common/OrderDetails.d.ts +2 -0
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +41 -60
- package/dist/cjs/anyspend/react/components/common/OrderDetailsCollapsible.d.ts +18 -0
- package/dist/cjs/anyspend/react/components/common/OrderDetailsCollapsible.js +42 -0
- package/dist/cjs/anyspend/react/components/common/OrderStatus.js +28 -5
- package/dist/cjs/anyspend/react/components/common/OrderTokenAmountFiat.d.ts +13 -0
- package/dist/cjs/anyspend/react/components/common/OrderTokenAmountFiat.js +50 -0
- package/dist/cjs/anyspend/react/components/common/OrderTokenAmountNew.d.ts +16 -0
- package/dist/cjs/anyspend/react/components/common/OrderTokenAmountNew.js +63 -0
- package/dist/cjs/anyspend/react/components/common/PanelOnramp.d.ts +11 -1
- package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +53 -15
- package/dist/cjs/anyspend/react/components/common/PanelOnrampPayment.js +1 -12
- package/dist/cjs/anyspend/react/components/common/PaymentStripeWeb2.js +4 -12
- package/dist/cjs/anyspend/react/components/common/StepProgress.d.ts +11 -0
- package/dist/cjs/anyspend/react/components/common/StepProgress.js +22 -0
- package/dist/cjs/anyspend/react/components/common/TransferCryptoDetails.d.ts +16 -0
- package/dist/cjs/anyspend/react/components/common/TransferCryptoDetails.js +73 -0
- package/dist/cjs/anyspend/react/components/index.d.ts +3 -0
- package/dist/cjs/anyspend/react/components/index.js +7 -1
- package/dist/cjs/anyspend/react/components/webview/WebviewOnrampPayment.js +1 -10
- package/dist/cjs/anyspend/utils/format.d.ts +1 -0
- package/dist/cjs/anyspend/utils/format.js +23 -10
- package/dist/cjs/anyspend/utils/number.d.ts +7 -0
- package/dist/cjs/anyspend/utils/number.js +18 -0
- package/dist/esm/anyspend/react/components/AnySpend.d.ts +5 -2
- package/dist/esm/anyspend/react/components/AnySpend.js +266 -57
- package/dist/esm/anyspend/react/components/AnySpendCustom.js +27 -31
- package/dist/esm/anyspend/react/components/common/ConnectWalletPayment.d.ts +15 -0
- package/dist/esm/anyspend/react/components/common/ConnectWalletPayment.js +46 -0
- package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.d.ts +20 -0
- package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +114 -0
- package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.d.ts +15 -0
- package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.js +67 -0
- package/dist/esm/anyspend/react/components/common/OrderDetails.d.ts +2 -0
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +43 -62
- package/dist/esm/anyspend/react/components/common/OrderDetailsCollapsible.d.ts +18 -0
- package/dist/esm/anyspend/react/components/common/OrderDetailsCollapsible.js +36 -0
- package/dist/esm/anyspend/react/components/common/OrderStatus.js +27 -4
- package/dist/esm/anyspend/react/components/common/OrderTokenAmountFiat.d.ts +13 -0
- package/dist/esm/anyspend/react/components/common/OrderTokenAmountFiat.js +47 -0
- package/dist/esm/anyspend/react/components/common/OrderTokenAmountNew.d.ts +16 -0
- package/dist/esm/anyspend/react/components/common/OrderTokenAmountNew.js +60 -0
- package/dist/esm/anyspend/react/components/common/PanelOnramp.d.ts +11 -1
- package/dist/esm/anyspend/react/components/common/PanelOnramp.js +54 -16
- package/dist/esm/anyspend/react/components/common/PanelOnrampPayment.js +1 -12
- package/dist/esm/anyspend/react/components/common/PaymentStripeWeb2.js +7 -15
- package/dist/esm/anyspend/react/components/common/StepProgress.d.ts +11 -0
- package/dist/esm/anyspend/react/components/common/StepProgress.js +19 -0
- package/dist/esm/anyspend/react/components/common/TransferCryptoDetails.d.ts +16 -0
- package/dist/esm/anyspend/react/components/common/TransferCryptoDetails.js +70 -0
- package/dist/esm/anyspend/react/components/index.d.ts +3 -0
- package/dist/esm/anyspend/react/components/index.js +3 -0
- package/dist/esm/anyspend/react/components/webview/WebviewOnrampPayment.js +1 -10
- package/dist/esm/anyspend/utils/format.d.ts +1 -0
- package/dist/esm/anyspend/utils/format.js +23 -10
- package/dist/esm/anyspend/utils/number.d.ts +7 -0
- package/dist/esm/anyspend/utils/number.js +17 -0
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/react/components/AnySpend.d.ts +5 -2
- package/dist/types/anyspend/react/components/common/ConnectWalletPayment.d.ts +15 -0
- package/dist/types/anyspend/react/components/common/CryptoPaymentMethod.d.ts +20 -0
- package/dist/types/anyspend/react/components/common/FiatPaymentMethod.d.ts +15 -0
- package/dist/types/anyspend/react/components/common/OrderDetails.d.ts +2 -0
- package/dist/types/anyspend/react/components/common/OrderDetailsCollapsible.d.ts +18 -0
- package/dist/types/anyspend/react/components/common/OrderTokenAmountFiat.d.ts +13 -0
- package/dist/types/anyspend/react/components/common/OrderTokenAmountNew.d.ts +16 -0
- package/dist/types/anyspend/react/components/common/PanelOnramp.d.ts +11 -1
- package/dist/types/anyspend/react/components/common/StepProgress.d.ts +11 -0
- package/dist/types/anyspend/react/components/common/TransferCryptoDetails.d.ts +16 -0
- package/dist/types/anyspend/react/components/index.d.ts +3 -0
- package/dist/types/anyspend/utils/format.d.ts +1 -0
- package/dist/types/anyspend/utils/number.d.ts +7 -0
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpend.tsx +535 -177
- package/src/anyspend/react/components/AnySpendCustom.tsx +33 -38
- package/src/anyspend/react/components/common/ConnectWalletPayment.tsx +124 -0
- package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +227 -0
- package/src/anyspend/react/components/common/FiatPaymentMethod.tsx +173 -0
- package/src/anyspend/react/components/common/OrderDetails.tsx +123 -250
- package/src/anyspend/react/components/common/OrderDetailsCollapsible.tsx +156 -0
- package/src/anyspend/react/components/common/OrderStatus.tsx +47 -24
- package/src/anyspend/react/components/common/OrderTokenAmountFiat.tsx +147 -0
- package/src/anyspend/react/components/common/OrderTokenAmountNew.tsx +215 -0
- package/src/anyspend/react/components/common/PanelOnramp.tsx +215 -62
- package/src/anyspend/react/components/common/PanelOnrampPayment.tsx +1 -14
- package/src/anyspend/react/components/common/PaymentStripeWeb2.tsx +42 -99
- package/src/anyspend/react/components/common/StepProgress.tsx +104 -0
- package/src/anyspend/react/components/common/TransferCryptoDetails.tsx +261 -0
- package/src/anyspend/react/components/index.ts +3 -0
- package/src/anyspend/react/components/webview/WebviewOnrampPayment.tsx +1 -11
- package/src/anyspend/utils/format.ts +24 -11
- package/src/anyspend/utils/number.ts +18 -0
- package/src/styles/index.css +30 -11
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { getDefaultToken, USDC_BASE } from "@b3dotfun/sdk/anyspend";
|
|
4
4
|
import {
|
|
5
|
+
useAnyspendCreateOnrampOrder,
|
|
5
6
|
useAnyspendCreateOrder,
|
|
6
7
|
useAnyspendOrderAndTransactions,
|
|
7
8
|
useAnyspendQuote,
|
|
9
|
+
useGeoOnrampOptions,
|
|
8
10
|
} from "@b3dotfun/sdk/anyspend/react";
|
|
9
11
|
import {
|
|
10
12
|
Button,
|
|
@@ -22,13 +24,17 @@ import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
|
22
24
|
import { shortenAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
|
|
23
25
|
import { formatDisplayNumber, formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
|
|
24
26
|
import invariant from "invariant";
|
|
25
|
-
import { ArrowDown, ChevronRightCircle, ChevronsUpDown, CircleAlert,
|
|
27
|
+
import { ArrowDown, ChevronLeft, ChevronRightCircle, ChevronsUpDown, CircleAlert, HistoryIcon } from "lucide-react";
|
|
26
28
|
import { motion } from "motion/react";
|
|
27
29
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
28
30
|
import { toast } from "sonner";
|
|
29
31
|
import { parseUnits } from "viem";
|
|
30
32
|
import { b3Sepolia, base, mainnet, sepolia } from "viem/chains";
|
|
33
|
+
import { useAccount } from "wagmi";
|
|
31
34
|
import { components } from "../../types/api";
|
|
35
|
+
import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper";
|
|
36
|
+
import { CryptoPaymentMethod, PaymentMethod } from "./common/CryptoPaymentMethod";
|
|
37
|
+
import { FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaymentMethod";
|
|
32
38
|
import { OrderDetails, OrderDetailsLoadingView } from "./common/OrderDetails";
|
|
33
39
|
import { OrderHistory } from "./common/OrderHistory";
|
|
34
40
|
import { OrderStatus } from "./common/OrderStatus";
|
|
@@ -36,7 +42,6 @@ import { OrderTokenAmount } from "./common/OrderTokenAmount";
|
|
|
36
42
|
import { PanelOnramp } from "./common/PanelOnramp";
|
|
37
43
|
import { PanelOnrampPayment } from "./common/PanelOnrampPayment";
|
|
38
44
|
import { TokenBalance } from "./common/TokenBalance";
|
|
39
|
-
import { EnterRecipientModal } from "./modals/EnterRecipientModal";
|
|
40
45
|
|
|
41
46
|
export interface RecipientOption {
|
|
42
47
|
address: string;
|
|
@@ -51,11 +56,33 @@ export enum PanelView {
|
|
|
51
56
|
ORDER_DETAILS,
|
|
52
57
|
LOADING,
|
|
53
58
|
FIAT_PAYMENT,
|
|
59
|
+
RECIPIENT_SELECTION,
|
|
60
|
+
CRYPTO_PAYMENT_METHOD,
|
|
61
|
+
FIAT_PAYMENT_METHOD,
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
const ANYSPEND_RECIPIENTS_KEY = "anyspend_recipients";
|
|
57
65
|
|
|
58
|
-
export function AnySpend({
|
|
66
|
+
export function AnySpend(props: {
|
|
67
|
+
destinationTokenAddress?: string;
|
|
68
|
+
destinationTokenChainId?: number;
|
|
69
|
+
isMainnet?: boolean;
|
|
70
|
+
mode?: "page" | "modal";
|
|
71
|
+
defaultActiveTab?: "crypto" | "fiat";
|
|
72
|
+
loadOrder?: string;
|
|
73
|
+
hideTransactionHistoryButton?: boolean;
|
|
74
|
+
recipientAddress?: string;
|
|
75
|
+
}) {
|
|
76
|
+
const fingerprintConfig = getFingerprintConfig();
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<AnySpendFingerprintWrapper fingerprint={fingerprintConfig}>
|
|
80
|
+
<AnySpendInner {...props} />
|
|
81
|
+
</AnySpendFingerprintWrapper>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function AnySpendInner({
|
|
59
86
|
destinationTokenAddress,
|
|
60
87
|
destinationTokenChainId,
|
|
61
88
|
isMainnet = true,
|
|
@@ -77,6 +104,9 @@ export function AnySpend({
|
|
|
77
104
|
const searchParams = useSearchParamsSSR();
|
|
78
105
|
const router = useRouter();
|
|
79
106
|
|
|
107
|
+
// Get wagmi account state for wallet connection
|
|
108
|
+
const wagmiAccount = useAccount();
|
|
109
|
+
|
|
80
110
|
// Determine if we're in "buy mode" based on whether destination token props are provided
|
|
81
111
|
const isBuyMode = !!(destinationTokenAddress && destinationTokenChainId);
|
|
82
112
|
|
|
@@ -109,6 +139,10 @@ export function AnySpend({
|
|
|
109
139
|
|
|
110
140
|
const [activePanel, setActivePanel] = useState<PanelView>(loadOrder ? PanelView.ORDER_DETAILS : PanelView.MAIN);
|
|
111
141
|
const [customRecipients, setCustomRecipients] = useState<RecipientOption[]>([]);
|
|
142
|
+
// Add state for selected payment method
|
|
143
|
+
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState<PaymentMethod>(PaymentMethod.NONE);
|
|
144
|
+
// Add state for selected fiat payment method
|
|
145
|
+
const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState<FiatPaymentMethod>(FiatPaymentMethod.NONE);
|
|
112
146
|
// const [newRecipientAddress, setNewRecipientAddress] = useState("");
|
|
113
147
|
// const recipientInputRef = useRef<HTMLInputElement>(null);
|
|
114
148
|
|
|
@@ -588,9 +622,38 @@ export function AnySpend({
|
|
|
588
622
|
// setNewRecipientAddress("");
|
|
589
623
|
setActivePanel(PanelView.ORDER_DETAILS);
|
|
590
624
|
|
|
591
|
-
//
|
|
592
|
-
|
|
625
|
+
// Debug: Check payment method before setting URL
|
|
626
|
+
console.log("Creating order - selectedPaymentMethod:", selectedPaymentMethod);
|
|
627
|
+
|
|
628
|
+
// Add orderId and payment method to URL for persistence
|
|
629
|
+
const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
|
|
630
|
+
params.set("orderId", orderId);
|
|
631
|
+
if (selectedPaymentMethod !== PaymentMethod.NONE) {
|
|
632
|
+
console.log("Setting paymentMethod in URL:", selectedPaymentMethod);
|
|
633
|
+
params.set("paymentMethod", selectedPaymentMethod);
|
|
634
|
+
} else {
|
|
635
|
+
console.log("Payment method is NONE, not setting in URL");
|
|
636
|
+
}
|
|
637
|
+
console.log("Final URL params:", params.toString());
|
|
638
|
+
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
639
|
+
},
|
|
640
|
+
onError: error => {
|
|
641
|
+
console.error(error);
|
|
642
|
+
toast.error("Failed to create order: " + error.message);
|
|
643
|
+
},
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
// Add onramp order creation hook
|
|
647
|
+
const { createOrder: createOnrampOrder, isCreatingOrder: isCreatingOnrampOrder } = useAnyspendCreateOnrampOrder({
|
|
648
|
+
onSuccess: data => {
|
|
649
|
+
const orderId = data.data.id;
|
|
650
|
+
setOrderId(orderId);
|
|
651
|
+
setActivePanel(PanelView.ORDER_DETAILS);
|
|
652
|
+
|
|
653
|
+
// Add orderId and payment method to URL for persistence
|
|
654
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
593
655
|
params.set("orderId", orderId);
|
|
656
|
+
params.set("paymentMethod", "fiat");
|
|
594
657
|
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
595
658
|
},
|
|
596
659
|
onError: error => {
|
|
@@ -599,24 +662,54 @@ export function AnySpend({
|
|
|
599
662
|
},
|
|
600
663
|
});
|
|
601
664
|
|
|
665
|
+
// Get geo-based onramp options for fiat payments
|
|
666
|
+
const { geoData, coinbaseAvailablePaymentMethods, isStripeOnrampSupported, stripeWeb2Support } = useGeoOnrampOptions(
|
|
667
|
+
isMainnet,
|
|
668
|
+
srcAmountOnRamp,
|
|
669
|
+
);
|
|
670
|
+
|
|
602
671
|
// Determine button state and text
|
|
603
672
|
const btnInfo: { text: string; disable: boolean; error: boolean } = useMemo(() => {
|
|
604
673
|
if (activeInputAmountInWei === "0") return { text: "Enter an amount", disable: true, error: false };
|
|
605
674
|
if (isLoadingAnyspendQuote) return { text: "Loading...", disable: true, error: false };
|
|
606
675
|
if (!recipientAddress) return { text: "Select recipient", disable: false, error: false };
|
|
607
|
-
if (isCreatingOrder) return { text: "Creating order...", disable: true, error: false };
|
|
676
|
+
if (isCreatingOrder || isCreatingOnrampOrder) return { text: "Creating order...", disable: true, error: false };
|
|
608
677
|
if (!anyspendQuote || !anyspendQuote.success) return { text: "Get rate error", disable: true, error: true };
|
|
609
|
-
|
|
610
|
-
|
|
678
|
+
|
|
679
|
+
if (activeTab === "crypto") {
|
|
680
|
+
// If no payment method selected, show "Choose payment method"
|
|
681
|
+
if (selectedPaymentMethod === PaymentMethod.NONE) {
|
|
682
|
+
return { text: "Choose payment method", disable: false, error: false };
|
|
683
|
+
}
|
|
684
|
+
// If payment method selected, show appropriate action
|
|
685
|
+
if (selectedPaymentMethod === PaymentMethod.CONNECT_WALLET) {
|
|
686
|
+
return { text: "Swap", disable: false, error: false };
|
|
687
|
+
}
|
|
688
|
+
if (selectedPaymentMethod === PaymentMethod.TRANSFER_CRYPTO) {
|
|
689
|
+
return { text: "Continue to payment", disable: false, error: false };
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (activeTab === "fiat") {
|
|
694
|
+
// If no fiat payment method selected, show "Select payment method"
|
|
695
|
+
if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
|
|
696
|
+
return { text: "Select payment method", disable: false, error: false };
|
|
697
|
+
}
|
|
698
|
+
// If payment method is selected, show "Buy"
|
|
699
|
+
return { text: "Buy", disable: false, error: false };
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return { text: "Buy", disable: false, error: false };
|
|
611
703
|
}, [
|
|
612
704
|
activeInputAmountInWei,
|
|
613
705
|
isLoadingAnyspendQuote,
|
|
614
706
|
recipientAddress,
|
|
615
707
|
isCreatingOrder,
|
|
708
|
+
isCreatingOnrampOrder,
|
|
616
709
|
anyspendQuote,
|
|
617
710
|
activeTab,
|
|
618
|
-
|
|
619
|
-
|
|
711
|
+
selectedPaymentMethod,
|
|
712
|
+
selectedFiatPaymentMethod,
|
|
620
713
|
]);
|
|
621
714
|
|
|
622
715
|
// Handle main button click
|
|
@@ -624,7 +717,7 @@ export function AnySpend({
|
|
|
624
717
|
if (btnInfo.disable) return;
|
|
625
718
|
|
|
626
719
|
if (!recipientAddress) {
|
|
627
|
-
|
|
720
|
+
setActivePanel(PanelView.RECIPIENT_SELECTION);
|
|
628
721
|
return;
|
|
629
722
|
}
|
|
630
723
|
|
|
@@ -633,10 +726,60 @@ export function AnySpend({
|
|
|
633
726
|
invariant(recipientAddress, "Recipient address is not found");
|
|
634
727
|
|
|
635
728
|
if (activeTab === "fiat") {
|
|
636
|
-
|
|
729
|
+
// If no fiat payment method selected, show payment method selection
|
|
730
|
+
if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
|
|
731
|
+
setActivePanel(PanelView.FIAT_PAYMENT_METHOD);
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
// If payment method is selected, create order directly
|
|
735
|
+
await handleFiatOrder(selectedFiatPaymentMethod);
|
|
637
736
|
return;
|
|
638
737
|
}
|
|
639
738
|
|
|
739
|
+
if (activeTab === "crypto") {
|
|
740
|
+
// If no payment method selected, show payment method selection
|
|
741
|
+
if (selectedPaymentMethod === PaymentMethod.NONE) {
|
|
742
|
+
console.log("No payment method selected, showing selection panel");
|
|
743
|
+
setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// If payment method is selected, create order with payment method info
|
|
748
|
+
if (
|
|
749
|
+
selectedPaymentMethod === PaymentMethod.CONNECT_WALLET ||
|
|
750
|
+
selectedPaymentMethod === PaymentMethod.TRANSFER_CRYPTO
|
|
751
|
+
) {
|
|
752
|
+
console.log("Creating crypto order with payment method:", selectedPaymentMethod);
|
|
753
|
+
await handleCryptoSwap(selectedPaymentMethod);
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
} catch (err: any) {
|
|
758
|
+
console.error(err);
|
|
759
|
+
toast.error("Failed to create order: " + err.message);
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
const onClickHistory = () => {
|
|
764
|
+
setOrderId(undefined);
|
|
765
|
+
setActivePanel(PanelView.HISTORY);
|
|
766
|
+
// Remove orderId and paymentMethod from URL when going back to history
|
|
767
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
768
|
+
params.delete("orderId");
|
|
769
|
+
params.delete("paymentMethod");
|
|
770
|
+
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
// Handle crypto swap creation
|
|
774
|
+
const handleCryptoSwap = async (method: PaymentMethod) => {
|
|
775
|
+
try {
|
|
776
|
+
invariant(anyspendQuote, "Relay price is not found");
|
|
777
|
+
invariant(recipientAddress, "Recipient address is not found");
|
|
778
|
+
|
|
779
|
+
// Debug: Check payment method values
|
|
780
|
+
console.log("handleCryptoSwap - method parameter:", method);
|
|
781
|
+
console.log("handleCryptoSwap - selectedPaymentMethod state:", selectedPaymentMethod);
|
|
782
|
+
|
|
640
783
|
const srcAmountBigInt = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
|
|
641
784
|
|
|
642
785
|
createOrder({
|
|
@@ -659,13 +802,74 @@ export function AnySpend({
|
|
|
659
802
|
}
|
|
660
803
|
};
|
|
661
804
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
805
|
+
// Handle fiat onramp order creation
|
|
806
|
+
const handleFiatOrder = async (paymentMethod: FiatPaymentMethod) => {
|
|
807
|
+
try {
|
|
808
|
+
invariant(anyspendQuote, "Relay price is not found");
|
|
809
|
+
invariant(recipientAddress, "Recipient address is not found");
|
|
810
|
+
|
|
811
|
+
if (!srcAmountOnRamp || parseFloat(srcAmountOnRamp) <= 0) {
|
|
812
|
+
toast.error("Please enter a valid amount");
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// Determine vendor and payment method string based on selected payment method
|
|
817
|
+
let vendor: components["schemas"]["OnrampMetadata"]["vendor"];
|
|
818
|
+
let paymentMethodString = "";
|
|
819
|
+
|
|
820
|
+
if (paymentMethod === FiatPaymentMethod.COINBASE_PAY) {
|
|
821
|
+
if (coinbaseAvailablePaymentMethods.length === 0) {
|
|
822
|
+
toast.error("Coinbase Pay not available");
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
vendor = "coinbase";
|
|
826
|
+
paymentMethodString = coinbaseAvailablePaymentMethods[0]?.id || ""; // Use first available payment method ID
|
|
827
|
+
} else if (paymentMethod === FiatPaymentMethod.STRIPE) {
|
|
828
|
+
if (!isStripeOnrampSupported && (!stripeWeb2Support || !stripeWeb2Support.isSupport)) {
|
|
829
|
+
toast.error("Stripe not available");
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
vendor = stripeWeb2Support && stripeWeb2Support.isSupport ? "stripe-web2" : "stripe";
|
|
833
|
+
paymentMethodString = "";
|
|
834
|
+
} else {
|
|
835
|
+
toast.error("Please select a payment method");
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const getDstToken = (): components["schemas"]["Token"] => {
|
|
840
|
+
if (isBuyMode) {
|
|
841
|
+
invariant(destinationTokenAddress, "destinationTokenAddress is required");
|
|
842
|
+
return {
|
|
843
|
+
...selectedDstToken,
|
|
844
|
+
chainId: destinationTokenChainId || selectedDstChainId,
|
|
845
|
+
address: destinationTokenAddress,
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
return selectedDstToken;
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
createOnrampOrder({
|
|
852
|
+
isMainnet,
|
|
853
|
+
recipientAddress,
|
|
854
|
+
orderType: "swap",
|
|
855
|
+
dstChain: getDstToken().chainId,
|
|
856
|
+
dstToken: getDstToken(),
|
|
857
|
+
srcFiatAmount: srcAmountOnRamp,
|
|
858
|
+
onramp: {
|
|
859
|
+
vendor: vendor,
|
|
860
|
+
paymentMethod: paymentMethodString,
|
|
861
|
+
country: geoData?.country || "US",
|
|
862
|
+
ipAddress: geoData?.ip,
|
|
863
|
+
redirectUrl:
|
|
864
|
+
window.location.origin === "https://basement.fun" ? "https://basement.fun/deposit" : window.location.origin,
|
|
865
|
+
},
|
|
866
|
+
expectedDstAmount: anyspendQuote?.data?.currencyOut?.amount?.toString() || "0",
|
|
867
|
+
creatorAddress: globalAddress,
|
|
868
|
+
});
|
|
869
|
+
} catch (err: any) {
|
|
870
|
+
console.error(err);
|
|
871
|
+
toast.error("Failed to create order: " + err.message);
|
|
872
|
+
}
|
|
669
873
|
};
|
|
670
874
|
|
|
671
875
|
// Open a dynamic modal
|
|
@@ -686,9 +890,10 @@ export function AnySpend({
|
|
|
686
890
|
const onSelectOrder = (selectedOrderId: string) => {
|
|
687
891
|
setActivePanel(PanelView.MAIN);
|
|
688
892
|
setOrderId(selectedOrderId);
|
|
689
|
-
// Update URL with the new orderId
|
|
893
|
+
// Update URL with the new orderId and preserve existing parameters
|
|
690
894
|
const params = new URLSearchParams(searchParams.toString());
|
|
691
895
|
params.set("orderId", selectedOrderId);
|
|
896
|
+
// Keep existing paymentMethod if present
|
|
692
897
|
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
693
898
|
};
|
|
694
899
|
|
|
@@ -706,8 +911,6 @@ export function AnySpend({
|
|
|
706
911
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
707
912
|
}, [activePanel]);
|
|
708
913
|
|
|
709
|
-
const [isOpenPasteRecipientAddressModal, setIsOpenPasteRecipientAddressModal] = useState(false);
|
|
710
|
-
|
|
711
914
|
const calculatePriceImpact = (inputUsd?: string | number, outputUsd?: string | number) => {
|
|
712
915
|
if (!inputUsd || !outputUsd) {
|
|
713
916
|
return { percentage: "0.00", isNegative: false };
|
|
@@ -760,11 +963,12 @@ export function AnySpend({
|
|
|
760
963
|
onBack={() => {
|
|
761
964
|
setOrderId(undefined);
|
|
762
965
|
setActivePanel(PanelView.MAIN);
|
|
966
|
+
setSelectedPaymentMethod(PaymentMethod.NONE); // Reset payment method when going back
|
|
763
967
|
}}
|
|
764
968
|
/>
|
|
765
969
|
</>
|
|
766
970
|
)}
|
|
767
|
-
{mode === "page" && <div className="h-12" />}
|
|
971
|
+
{/* {mode === "page" && <div className="h-12" />} */}
|
|
768
972
|
</div>
|
|
769
973
|
</div>
|
|
770
974
|
);
|
|
@@ -790,33 +994,43 @@ export function AnySpend({
|
|
|
790
994
|
)}
|
|
791
995
|
|
|
792
996
|
{/* Tab section */}
|
|
793
|
-
<div className="
|
|
794
|
-
<div
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
997
|
+
<div className="w-full">
|
|
998
|
+
<div className="bg-as-surface-secondary relative mb-4 grid h-10 grid-cols-2 rounded-xl">
|
|
999
|
+
<div
|
|
1000
|
+
className={cn(
|
|
1001
|
+
"bg-as-brand absolute bottom-0 left-0 top-0 z-0 rounded-xl transition-transform duration-100",
|
|
1002
|
+
"h-full w-1/2",
|
|
1003
|
+
activeTab === "fiat" ? "translate-x-full" : "translate-x-0",
|
|
1004
|
+
)}
|
|
1005
|
+
style={{ willChange: "transform" }}
|
|
1006
|
+
/>
|
|
1007
|
+
<button
|
|
1008
|
+
className={cn(
|
|
1009
|
+
"relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100",
|
|
1010
|
+
activeTab === "crypto" ? "text-white" : "text-as-primary/70 hover:bg-as-on-surface-2 bg-transparent",
|
|
1011
|
+
)}
|
|
1012
|
+
onClick={() => {
|
|
1013
|
+
setActiveTab("crypto");
|
|
1014
|
+
setSelectedPaymentMethod(PaymentMethod.NONE); // Reset payment method when switching to crypto
|
|
1015
|
+
setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE); // Reset fiat payment method when switching to crypto
|
|
1016
|
+
}}
|
|
1017
|
+
>
|
|
1018
|
+
Pay with crypto
|
|
1019
|
+
</button>
|
|
1020
|
+
<button
|
|
1021
|
+
className={cn(
|
|
1022
|
+
"relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100",
|
|
1023
|
+
activeTab === "fiat" ? "text-white" : "text-as-primary/70 hover:bg-as-on-surface-2 bg-transparent",
|
|
1024
|
+
)}
|
|
1025
|
+
onClick={() => {
|
|
1026
|
+
setActiveTab("fiat");
|
|
1027
|
+
setSelectedPaymentMethod(PaymentMethod.NONE); // Reset crypto payment method when switching to fiat
|
|
1028
|
+
setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE); // Reset fiat payment method when switching to fiat
|
|
1029
|
+
}}
|
|
1030
|
+
>
|
|
1031
|
+
Pay with Fiat
|
|
1032
|
+
</button>
|
|
1033
|
+
</div>
|
|
820
1034
|
</div>
|
|
821
1035
|
|
|
822
1036
|
{/* {selectedSrcChainId === base.id || selectedDstChainId === base.id || activeTab === "fiat" ? (
|
|
@@ -827,25 +1041,47 @@ export function AnySpend({
|
|
|
827
1041
|
</>
|
|
828
1042
|
) : null} */}
|
|
829
1043
|
|
|
830
|
-
<div className="relative flex max-w-[calc(100vw-32px)] flex-col gap-2">
|
|
1044
|
+
<div className="relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2">
|
|
831
1045
|
{/* Send section */}
|
|
832
1046
|
{activeTab === "crypto" ? (
|
|
833
1047
|
<motion.div
|
|
834
1048
|
initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
|
|
835
1049
|
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
|
836
1050
|
transition={{ duration: 0.3, delay: 0, ease: "easeInOut" }}
|
|
837
|
-
className="bg-as-
|
|
1051
|
+
className="bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6"
|
|
838
1052
|
>
|
|
839
1053
|
<div className="flex items-center justify-between">
|
|
840
|
-
<div className="text-as-primary/50 flex h-7 items-center text-sm">
|
|
841
|
-
<
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
1054
|
+
<div className="text-as-primary/50 flex h-7 items-center text-sm">Pay</div>
|
|
1055
|
+
<button
|
|
1056
|
+
className="text-as-primary/50 hover:text-as-primary/70 flex h-7 items-center gap-1 text-sm transition-colors"
|
|
1057
|
+
onClick={() => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD)}
|
|
1058
|
+
>
|
|
1059
|
+
{selectedPaymentMethod === PaymentMethod.CONNECT_WALLET ? (
|
|
1060
|
+
<>
|
|
1061
|
+
{globalAddress || wagmiAccount.address ? (
|
|
1062
|
+
<>
|
|
1063
|
+
{globalWallet?.meta?.icon && (
|
|
1064
|
+
<img src={globalWallet.meta.icon} alt="Connected Wallet" className="h-4 w-4 rounded-full" />
|
|
1065
|
+
)}
|
|
1066
|
+
<span>{shortenAddress(globalAddress || wagmiAccount.address || "")}</span>
|
|
1067
|
+
</>
|
|
1068
|
+
) : (
|
|
1069
|
+
"Connect wallet"
|
|
1070
|
+
)}
|
|
1071
|
+
<ChevronRightCircle className="h-4 w-4" />
|
|
1072
|
+
</>
|
|
1073
|
+
) : selectedPaymentMethod === PaymentMethod.TRANSFER_CRYPTO ? (
|
|
1074
|
+
<>
|
|
1075
|
+
Transfer crypto
|
|
1076
|
+
<ChevronRightCircle className="h-4 w-4" />
|
|
1077
|
+
</>
|
|
1078
|
+
) : (
|
|
1079
|
+
<>
|
|
1080
|
+
Select payment method
|
|
1081
|
+
<ChevronRightCircle className="h-4 w-4" />
|
|
1082
|
+
</>
|
|
1083
|
+
)}
|
|
1084
|
+
</button>
|
|
849
1085
|
</div>
|
|
850
1086
|
<OrderTokenAmount
|
|
851
1087
|
address={globalAddress}
|
|
@@ -860,8 +1096,18 @@ export function AnySpend({
|
|
|
860
1096
|
token={selectedSrcToken}
|
|
861
1097
|
setToken={setSelectedSrcToken}
|
|
862
1098
|
/>
|
|
863
|
-
<div className="
|
|
864
|
-
|
|
1099
|
+
<div className="flex items-center justify-between">
|
|
1100
|
+
<div className="text-as-primary/50 flex h-5 items-center text-sm">
|
|
1101
|
+
{formatDisplayNumber(anyspendQuote?.data?.currencyIn?.amountUsd, { style: "currency", fallback: "" })}
|
|
1102
|
+
</div>
|
|
1103
|
+
<TokenBalance
|
|
1104
|
+
token={selectedSrcToken}
|
|
1105
|
+
walletAddress={globalAddress}
|
|
1106
|
+
onChangeInput={value => {
|
|
1107
|
+
setIsSrcInputDirty(true);
|
|
1108
|
+
setSrcAmount(value);
|
|
1109
|
+
}}
|
|
1110
|
+
/>
|
|
865
1111
|
</div>
|
|
866
1112
|
</motion.div>
|
|
867
1113
|
) : (
|
|
@@ -870,7 +1116,18 @@ export function AnySpend({
|
|
|
870
1116
|
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
|
871
1117
|
transition={{ duration: 0.3, delay: 0, ease: "easeInOut" }}
|
|
872
1118
|
>
|
|
873
|
-
<PanelOnramp
|
|
1119
|
+
<PanelOnramp
|
|
1120
|
+
srcAmountOnRamp={srcAmountOnRamp}
|
|
1121
|
+
setSrcAmountOnRamp={setSrcAmountOnRamp}
|
|
1122
|
+
selectedPaymentMethod={selectedFiatPaymentMethod}
|
|
1123
|
+
setActivePanel={setActivePanel}
|
|
1124
|
+
_recipientAddress={recipientAddress}
|
|
1125
|
+
destinationToken={selectedDstToken}
|
|
1126
|
+
destinationChainId={selectedDstChainId}
|
|
1127
|
+
destinationAmount={dstAmount}
|
|
1128
|
+
onDestinationTokenChange={setSelectedDstToken}
|
|
1129
|
+
onDestinationChainChange={setSelectedDstChainId}
|
|
1130
|
+
/>
|
|
874
1131
|
</motion.div>
|
|
875
1132
|
)}
|
|
876
1133
|
|
|
@@ -878,8 +1135,9 @@ export function AnySpend({
|
|
|
878
1135
|
<Button
|
|
879
1136
|
variant="ghost"
|
|
880
1137
|
className={cn(
|
|
881
|
-
"
|
|
882
|
-
|
|
1138
|
+
"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",
|
|
1139
|
+
isBuyMode && "top-[calc(50%+56px)] cursor-default",
|
|
1140
|
+
activeTab === "fiat" && "hidden",
|
|
883
1141
|
)}
|
|
884
1142
|
onClick={() => {
|
|
885
1143
|
if (activeTab === "fiat" || isBuyMode) {
|
|
@@ -910,106 +1168,104 @@ export function AnySpend({
|
|
|
910
1168
|
</div>
|
|
911
1169
|
</Button>
|
|
912
1170
|
|
|
913
|
-
{/* Receive section */}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
<div className="
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
"text-as-primary/
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
<
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
<
|
|
944
|
-
|
|
1171
|
+
{/* Receive section - Hidden when fiat tab is active */}
|
|
1172
|
+
{activeTab !== "fiat" && (
|
|
1173
|
+
<motion.div
|
|
1174
|
+
initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
|
|
1175
|
+
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
|
1176
|
+
transition={{ duration: 0.3, delay: 0.1, ease: "easeInOut" }}
|
|
1177
|
+
className="bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6"
|
|
1178
|
+
>
|
|
1179
|
+
<div className="flex w-full items-center justify-between">
|
|
1180
|
+
<div className="text-as-primary/50 flex h-7 items-center text-sm">Receive</div>
|
|
1181
|
+
{recipientAddress ? (
|
|
1182
|
+
<button
|
|
1183
|
+
className={cn("text-as-primary/70 flex h-7 items-center gap-2 rounded-lg px-2")}
|
|
1184
|
+
onClick={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
|
|
1185
|
+
>
|
|
1186
|
+
{globalAddress && recipientAddress === globalAddress && globalWallet?.meta?.icon ? (
|
|
1187
|
+
<img
|
|
1188
|
+
src={globalWallet?.meta?.icon}
|
|
1189
|
+
alt="Current wallet"
|
|
1190
|
+
className="bg-as-primary h-6 w-6 rounded-full"
|
|
1191
|
+
/>
|
|
1192
|
+
) : (
|
|
1193
|
+
<div className="flex h-6 w-6 items-center justify-center rounded-full bg-orange-500 text-xs text-white">
|
|
1194
|
+
🦊
|
|
1195
|
+
</div>
|
|
1196
|
+
)}
|
|
1197
|
+
<div className="text-sm">{recipientName ? recipientName : shortenAddress(recipientAddress)}</div>
|
|
1198
|
+
<ChevronRightCircle className="h-4 w-4" />
|
|
1199
|
+
</button>
|
|
1200
|
+
) : (
|
|
1201
|
+
<button
|
|
1202
|
+
className="text-as-primary/70 flex items-center gap-1 rounded-lg"
|
|
1203
|
+
onClick={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
|
|
1204
|
+
>
|
|
1205
|
+
<div className="text-sm font-medium">Select recipient</div>
|
|
1206
|
+
<ChevronsUpDown className="h-3 w-3" />
|
|
1207
|
+
</button>
|
|
1208
|
+
)}
|
|
1209
|
+
</div>
|
|
1210
|
+
{isBuyMode ? (
|
|
1211
|
+
// Fixed destination token display in buy mode
|
|
1212
|
+
<div className="flex items-center justify-between">
|
|
1213
|
+
<div className="text-as-primary text-2xl font-bold">{dstAmount || "0"}</div>
|
|
1214
|
+
<div className="bg-as-brand/10 border-as-brand/30 flex items-center gap-3 rounded-xl border px-4 py-3">
|
|
1215
|
+
{selectedDstToken.metadata?.logoURI && (
|
|
1216
|
+
<img
|
|
1217
|
+
src={selectedDstToken.metadata.logoURI}
|
|
1218
|
+
alt={selectedDstToken.symbol}
|
|
1219
|
+
className="h-8 w-8 rounded-full"
|
|
1220
|
+
/>
|
|
1221
|
+
)}
|
|
1222
|
+
<span className="text-as-brand text-lg font-bold">{selectedDstToken.symbol}</span>
|
|
1223
|
+
</div>
|
|
1224
|
+
</div>
|
|
945
1225
|
) : (
|
|
946
|
-
<
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1226
|
+
<OrderTokenAmount
|
|
1227
|
+
address={recipientAddress}
|
|
1228
|
+
context="to"
|
|
1229
|
+
inputValue={dstAmount}
|
|
1230
|
+
onChangeInput={value => {
|
|
1231
|
+
setIsSrcInputDirty(false);
|
|
1232
|
+
setDstAmount(value);
|
|
1233
|
+
}}
|
|
1234
|
+
chainId={selectedDstChainId}
|
|
1235
|
+
setChainId={setSelectedDstChainId}
|
|
1236
|
+
token={selectedDstToken}
|
|
1237
|
+
setToken={setSelectedDstToken}
|
|
1238
|
+
/>
|
|
953
1239
|
)}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1240
|
+
<div className="text-as-primary/50 flex h-5 items-center text-sm">
|
|
1241
|
+
{formatDisplayNumber(anyspendQuote?.data?.currencyOut?.amountUsd, { style: "currency", fallback: "" })}
|
|
1242
|
+
{anyspendQuote?.data?.currencyIn?.amountUsd &&
|
|
1243
|
+
anyspendQuote?.data?.currencyOut?.amountUsd &&
|
|
1244
|
+
(() => {
|
|
1245
|
+
const { percentage, isNegative } = calculatePriceImpact(
|
|
1246
|
+
anyspendQuote.data.currencyIn.amountUsd,
|
|
1247
|
+
anyspendQuote.data.currencyOut.amountUsd,
|
|
1248
|
+
);
|
|
1249
|
+
|
|
1250
|
+
// Parse the percentage as a number for comparison
|
|
1251
|
+
const percentageNum = parseFloat(percentage);
|
|
1252
|
+
|
|
1253
|
+
// Don't show if less than 1%
|
|
1254
|
+
if (percentageNum < 1) {
|
|
1255
|
+
return null;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// Using inline style to ensure color displays
|
|
1259
|
+
return (
|
|
1260
|
+
<span className="ml-2" style={{ color: percentageNum >= 10 ? "red" : "#FFD700" }}>
|
|
1261
|
+
({isNegative ? "-" : ""}
|
|
1262
|
+
{percentage}%)
|
|
1263
|
+
</span>
|
|
1264
|
+
);
|
|
1265
|
+
})()}
|
|
969
1266
|
</div>
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
address={recipientAddress}
|
|
973
|
-
context="to"
|
|
974
|
-
inputValue={dstAmount}
|
|
975
|
-
onChangeInput={value => {
|
|
976
|
-
setIsSrcInputDirty(false);
|
|
977
|
-
setDstAmount(value);
|
|
978
|
-
}}
|
|
979
|
-
chainId={selectedDstChainId}
|
|
980
|
-
setChainId={setSelectedDstChainId}
|
|
981
|
-
token={selectedDstToken}
|
|
982
|
-
setToken={setSelectedDstToken}
|
|
983
|
-
/>
|
|
984
|
-
)}
|
|
985
|
-
<div className="text-as-primary/50 flex h-5 items-center text-sm">
|
|
986
|
-
{formatDisplayNumber(anyspendQuote?.data?.currencyOut?.amountUsd, { style: "currency", fallback: "" })}
|
|
987
|
-
{anyspendQuote?.data?.currencyIn?.amountUsd &&
|
|
988
|
-
anyspendQuote?.data?.currencyOut?.amountUsd &&
|
|
989
|
-
(() => {
|
|
990
|
-
const { percentage, isNegative } = calculatePriceImpact(
|
|
991
|
-
anyspendQuote.data.currencyIn.amountUsd,
|
|
992
|
-
anyspendQuote.data.currencyOut.amountUsd,
|
|
993
|
-
);
|
|
994
|
-
|
|
995
|
-
// Parse the percentage as a number for comparison
|
|
996
|
-
const percentageNum = parseFloat(percentage);
|
|
997
|
-
|
|
998
|
-
// Don't show if less than 1%
|
|
999
|
-
if (percentageNum < 1) {
|
|
1000
|
-
return null;
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
// Using inline style to ensure color displays
|
|
1004
|
-
return (
|
|
1005
|
-
<span className="ml-2" style={{ color: percentageNum >= 10 ? "red" : "#FFD700" }}>
|
|
1006
|
-
({isNegative ? "-" : ""}
|
|
1007
|
-
{percentage}%)
|
|
1008
|
-
</span>
|
|
1009
|
-
);
|
|
1010
|
-
})()}
|
|
1011
|
-
</div>
|
|
1012
|
-
</motion.div>
|
|
1267
|
+
</motion.div>
|
|
1268
|
+
)}
|
|
1013
1269
|
</div>
|
|
1014
1270
|
|
|
1015
1271
|
{/* Order details section */}
|
|
@@ -1046,7 +1302,7 @@ export function AnySpend({
|
|
|
1046
1302
|
initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
|
|
1047
1303
|
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
|
1048
1304
|
transition={{ duration: 0.3, delay: 0.2, ease: "easeInOut" }}
|
|
1049
|
-
className="flex w-full max-w-[460px] flex-col gap-2"
|
|
1305
|
+
className="mt-4 flex w-full max-w-[460px] flex-col gap-2 pb-2"
|
|
1050
1306
|
>
|
|
1051
1307
|
<ShinyButton
|
|
1052
1308
|
accentColor={"hsl(var(--as-brand))"}
|
|
@@ -1072,9 +1328,7 @@ export function AnySpend({
|
|
|
1072
1328
|
>
|
|
1073
1329
|
<HistoryIcon className="h-4 w-4" /> <span className="pr-4">Transaction History</span>
|
|
1074
1330
|
</Button>
|
|
1075
|
-
) :
|
|
1076
|
-
<div className="h-2 w-full" />
|
|
1077
|
-
)}
|
|
1331
|
+
) : null}
|
|
1078
1332
|
</motion.div>
|
|
1079
1333
|
</div>
|
|
1080
1334
|
);
|
|
@@ -1096,9 +1350,15 @@ export function AnySpend({
|
|
|
1096
1350
|
onOrderCreated={orderId => {
|
|
1097
1351
|
setOrderId(orderId);
|
|
1098
1352
|
setActivePanel(PanelView.ORDER_DETAILS);
|
|
1099
|
-
// Add orderId to URL for persistence
|
|
1100
|
-
const params = new URLSearchParams();
|
|
1353
|
+
// Add orderId and payment method to URL for persistence
|
|
1354
|
+
const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
|
|
1101
1355
|
params.set("orderId", orderId);
|
|
1356
|
+
// For fiat payments, the payment method is always fiat (but we use the active tab context)
|
|
1357
|
+
if (activeTab === "fiat") {
|
|
1358
|
+
params.set("paymentMethod", "fiat");
|
|
1359
|
+
} else if (selectedPaymentMethod !== PaymentMethod.NONE) {
|
|
1360
|
+
params.set("paymentMethod", selectedPaymentMethod);
|
|
1361
|
+
}
|
|
1102
1362
|
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
1103
1363
|
}}
|
|
1104
1364
|
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
@@ -1107,10 +1367,111 @@ export function AnySpend({
|
|
|
1107
1367
|
/>
|
|
1108
1368
|
);
|
|
1109
1369
|
|
|
1370
|
+
const recipientSelectionView = (
|
|
1371
|
+
<div className="mx-auto w-[460px] max-w-full">
|
|
1372
|
+
<div className="flex flex-col gap-6">
|
|
1373
|
+
{/* Header */}
|
|
1374
|
+
<div className="flex justify-around">
|
|
1375
|
+
<button
|
|
1376
|
+
onClick={() => setActivePanel(PanelView.MAIN)}
|
|
1377
|
+
className="text-as-quaternary hover:text-as-primary flex h-8 w-8 items-center justify-center rounded-lg transition-colors"
|
|
1378
|
+
>
|
|
1379
|
+
<ChevronLeft className="h-6 w-6" />
|
|
1380
|
+
</button>
|
|
1381
|
+
<div className="flex-1 text-center">
|
|
1382
|
+
<h2 className="text-as-primary text-lg font-semibold">Add recipient address or ENS</h2>
|
|
1383
|
+
<p className="text-as-primary/60 text-sm">Swap and send tokens to another address</p>
|
|
1384
|
+
</div>
|
|
1385
|
+
</div>
|
|
1386
|
+
|
|
1387
|
+
{/* Address Input */}
|
|
1388
|
+
<div className="flex flex-col gap-4">
|
|
1389
|
+
<div className="bg-as-surface-secondary border-as-border-secondary flex h-12 w-full overflow-hidden rounded-xl border">
|
|
1390
|
+
<input
|
|
1391
|
+
type="text"
|
|
1392
|
+
placeholder="Enter recipient address"
|
|
1393
|
+
value={recipientAddress || ""}
|
|
1394
|
+
onChange={e => setRecipientAddress(e.target.value)}
|
|
1395
|
+
onKeyDown={e => {
|
|
1396
|
+
if (e.key === "Enter" && recipientAddress) {
|
|
1397
|
+
setActivePanel(PanelView.MAIN);
|
|
1398
|
+
}
|
|
1399
|
+
}}
|
|
1400
|
+
className="text-as-primary placeholder:text-as-primary/50 flex-1 bg-transparent px-4 text-base focus:outline-none"
|
|
1401
|
+
autoFocus
|
|
1402
|
+
/>
|
|
1403
|
+
<div className="border-as-border-secondary border-l">
|
|
1404
|
+
<button
|
|
1405
|
+
onClick={async () => {
|
|
1406
|
+
try {
|
|
1407
|
+
const text = await navigator.clipboard.readText();
|
|
1408
|
+
setRecipientAddress(text);
|
|
1409
|
+
} catch (err) {
|
|
1410
|
+
console.error("Failed to read clipboard:", err);
|
|
1411
|
+
}
|
|
1412
|
+
}}
|
|
1413
|
+
className="text-as-primary/70 hover:text-as-primary hover:bg-as-surface-primary h-full px-4 font-semibold transition-colors"
|
|
1414
|
+
>
|
|
1415
|
+
Paste
|
|
1416
|
+
</button>
|
|
1417
|
+
</div>
|
|
1418
|
+
</div>
|
|
1419
|
+
|
|
1420
|
+
{/* Confirm Button */}
|
|
1421
|
+
<button
|
|
1422
|
+
onClick={() => {
|
|
1423
|
+
if (recipientAddress) {
|
|
1424
|
+
setActivePanel(PanelView.MAIN);
|
|
1425
|
+
}
|
|
1426
|
+
}}
|
|
1427
|
+
disabled={!recipientAddress}
|
|
1428
|
+
className="bg-as-brand hover:bg-as-brand/90 disabled:bg-as-on-surface-2 disabled:text-as-secondary h-12 w-full rounded-xl font-medium text-white transition-colors disabled:cursor-not-allowed"
|
|
1429
|
+
>
|
|
1430
|
+
Confirm recipient address
|
|
1431
|
+
</button>
|
|
1432
|
+
</div>
|
|
1433
|
+
</div>
|
|
1434
|
+
</div>
|
|
1435
|
+
);
|
|
1436
|
+
|
|
1437
|
+
const cryptoPaymentMethodView = (
|
|
1438
|
+
<CryptoPaymentMethod
|
|
1439
|
+
globalAddress={globalAddress}
|
|
1440
|
+
globalWallet={globalWallet}
|
|
1441
|
+
selectedPaymentMethod={selectedPaymentMethod}
|
|
1442
|
+
setSelectedPaymentMethod={setSelectedPaymentMethod}
|
|
1443
|
+
isCreatingOrder={isCreatingOrder}
|
|
1444
|
+
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
1445
|
+
onSelectPaymentMethod={(method: PaymentMethod) => {
|
|
1446
|
+
setSelectedPaymentMethod(method);
|
|
1447
|
+
setActivePanel(PanelView.MAIN);
|
|
1448
|
+
}}
|
|
1449
|
+
/>
|
|
1450
|
+
);
|
|
1451
|
+
|
|
1452
|
+
const fiatPaymentMethodView = (
|
|
1453
|
+
<FiatPaymentMethodComponent
|
|
1454
|
+
selectedPaymentMethod={selectedFiatPaymentMethod}
|
|
1455
|
+
setSelectedPaymentMethod={setSelectedFiatPaymentMethod}
|
|
1456
|
+
onBack={() => setActivePanel(PanelView.MAIN)}
|
|
1457
|
+
onSelectPaymentMethod={(method: FiatPaymentMethod) => {
|
|
1458
|
+
setSelectedFiatPaymentMethod(method);
|
|
1459
|
+
setActivePanel(PanelView.MAIN); // Go back to main panel to show updated pricing
|
|
1460
|
+
}}
|
|
1461
|
+
srcAmountOnRamp={srcAmountOnRamp}
|
|
1462
|
+
isMainnet={isMainnet}
|
|
1463
|
+
/>
|
|
1464
|
+
);
|
|
1465
|
+
|
|
1110
1466
|
// Add tabs to the main component when no order is loaded
|
|
1111
1467
|
return (
|
|
1112
1468
|
<StyleRoot>
|
|
1113
|
-
<div
|
|
1469
|
+
<div
|
|
1470
|
+
className={cn(
|
|
1471
|
+
"mx-auto w-full max-w-[460px]",
|
|
1472
|
+
mode === "page" && "bg-as-surface-primary border-as-border-secondary rounded-2xl border p-6 shadow-xl",
|
|
1473
|
+
)}
|
|
1474
|
+
>
|
|
1114
1475
|
<TransitionPanel
|
|
1115
1476
|
activeIndex={
|
|
1116
1477
|
orderId
|
|
@@ -1121,7 +1482,7 @@ export function AnySpend({
|
|
|
1121
1482
|
? PanelView.MAIN
|
|
1122
1483
|
: activePanel
|
|
1123
1484
|
}
|
|
1124
|
-
className={cn("
|
|
1485
|
+
className={cn("overflow-hidden", {
|
|
1125
1486
|
"mt-0": mode === "modal",
|
|
1126
1487
|
})}
|
|
1127
1488
|
variants={{
|
|
@@ -1137,14 +1498,11 @@ export function AnySpend({
|
|
|
1137
1498
|
<div key="order-details-view">{orderDetailsView}</div>,
|
|
1138
1499
|
<div key="loading-view">{OrderDetailsLoadingView}</div>,
|
|
1139
1500
|
<div key="fiat-payment-view">{onrampPaymentView}</div>,
|
|
1501
|
+
<div key="recipient-selection-view">{recipientSelectionView}</div>,
|
|
1502
|
+
<div key="crypto-payment-method-view">{cryptoPaymentMethodView}</div>,
|
|
1503
|
+
<div key="fiat-payment-method-view">{fiatPaymentMethodView}</div>,
|
|
1140
1504
|
]}
|
|
1141
1505
|
</TransitionPanel>
|
|
1142
|
-
<EnterRecipientModal
|
|
1143
|
-
isOpenPasteRecipientAddress={isOpenPasteRecipientAddressModal}
|
|
1144
|
-
setIsOpenPasteRecipientAddress={setIsOpenPasteRecipientAddressModal}
|
|
1145
|
-
recipientAddress={recipientAddress}
|
|
1146
|
-
setRecipientAddress={setRecipientAddress}
|
|
1147
|
-
/>
|
|
1148
1506
|
</div>
|
|
1149
1507
|
</StyleRoot>
|
|
1150
1508
|
);
|