@b3dotfun/sdk 0.0.79 → 0.0.80-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/anyspend/react/components/AnySpend.js +23 -10
- package/dist/cjs/anyspend/react/components/AnySpendCollectorClubPurchase.js +9 -2
- package/dist/cjs/anyspend/react/components/AnySpendCustom.d.ts +2 -0
- package/dist/cjs/anyspend/react/components/AnySpendCustom.js +75 -19
- package/dist/cjs/anyspend/react/components/AnySpendNFT.js +6 -9
- package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +1 -3
- package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.d.ts +6 -1
- package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.js +40 -13
- package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +13 -7
- package/dist/cjs/anyspend/react/components/common/PanelOnrampPayment.js +5 -3
- package/dist/cjs/anyspend/react/hooks/useGeoOnrampOptions.d.ts +2 -8
- package/dist/cjs/anyspend/react/hooks/useGeoOnrampOptions.js +4 -2
- package/dist/cjs/anyspend/react/hooks/useStripeSupport.d.ts +1 -0
- package/dist/cjs/anyspend/react/hooks/useStripeSupport.js +1 -0
- package/dist/cjs/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +5 -3
- package/dist/cjs/shared/utils/ipfs.d.ts +3 -3
- package/dist/cjs/shared/utils/ipfs.js +8 -8
- package/dist/esm/anyspend/react/components/AnySpend.js +23 -10
- package/dist/esm/anyspend/react/components/AnySpendCollectorClubPurchase.js +9 -2
- package/dist/esm/anyspend/react/components/AnySpendCustom.d.ts +2 -0
- package/dist/esm/anyspend/react/components/AnySpendCustom.js +76 -20
- package/dist/esm/anyspend/react/components/AnySpendNFT.js +7 -10
- package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +1 -3
- package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.d.ts +6 -1
- package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.js +39 -12
- package/dist/esm/anyspend/react/components/common/PanelOnramp.js +14 -8
- package/dist/esm/anyspend/react/components/common/PanelOnrampPayment.js +5 -3
- package/dist/esm/anyspend/react/hooks/useGeoOnrampOptions.d.ts +2 -8
- package/dist/esm/anyspend/react/hooks/useGeoOnrampOptions.js +4 -2
- package/dist/esm/anyspend/react/hooks/useStripeSupport.d.ts +1 -0
- package/dist/esm/anyspend/react/hooks/useStripeSupport.js +1 -0
- package/dist/esm/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +5 -3
- package/dist/esm/shared/utils/ipfs.d.ts +3 -3
- package/dist/esm/shared/utils/ipfs.js +8 -8
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/react/components/AnySpendCustom.d.ts +2 -0
- package/dist/types/anyspend/react/components/common/FiatPaymentMethod.d.ts +6 -1
- package/dist/types/anyspend/react/hooks/useGeoOnrampOptions.d.ts +2 -8
- package/dist/types/anyspend/react/hooks/useStripeSupport.d.ts +1 -0
- package/dist/types/shared/utils/ipfs.d.ts +3 -3
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpend.tsx +24 -10
- package/src/anyspend/react/components/AnySpendCollectorClubPurchase.tsx +9 -1
- package/src/anyspend/react/components/AnySpendCustom.tsx +113 -59
- package/src/anyspend/react/components/AnySpendNFT.tsx +49 -48
- package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +1 -4
- package/src/anyspend/react/components/common/FiatPaymentMethod.tsx +53 -21
- package/src/anyspend/react/components/common/PanelOnramp.tsx +36 -40
- package/src/anyspend/react/components/common/PanelOnrampPayment.tsx +53 -16
- package/src/anyspend/react/hooks/useGeoOnrampOptions.ts +5 -2
- package/src/anyspend/react/hooks/useStripeSupport.ts +1 -0
- package/src/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.tsx +5 -7
- package/src/shared/utils/ipfs.ts +8 -8
|
@@ -510,7 +510,8 @@ function AnySpendInner({
|
|
|
510
510
|
});
|
|
511
511
|
|
|
512
512
|
// Get geo-based onramp options for fiat payments
|
|
513
|
-
const { geoData, coinbaseAvailablePaymentMethods, stripeWeb2Support } =
|
|
513
|
+
const { geoData, coinbaseAvailablePaymentMethods, stripeOnrampSupport, stripeWeb2Support } =
|
|
514
|
+
useGeoOnrampOptions(srcAmountOnRamp);
|
|
514
515
|
|
|
515
516
|
// Helper function to map payment method to onramp vendor
|
|
516
517
|
const getOnrampVendor = (paymentMethod: FiatPaymentMethod): "coinbase" | "stripe" | "stripe-web2" | undefined => {
|
|
@@ -518,11 +519,11 @@ function AnySpendInner({
|
|
|
518
519
|
case FiatPaymentMethod.COINBASE_PAY:
|
|
519
520
|
return "coinbase";
|
|
520
521
|
case FiatPaymentMethod.STRIPE:
|
|
521
|
-
//
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
return undefined;
|
|
522
|
+
// Stripe redirect flow (one-click URL)
|
|
523
|
+
return stripeOnrampSupport ? "stripe" : undefined;
|
|
524
|
+
case FiatPaymentMethod.STRIPE_WEB2:
|
|
525
|
+
// Stripe embedded payment form
|
|
526
|
+
return stripeWeb2Support?.isSupport ? "stripe-web2" : undefined;
|
|
526
527
|
default:
|
|
527
528
|
return undefined;
|
|
528
529
|
}
|
|
@@ -683,7 +684,10 @@ function AnySpendInner({
|
|
|
683
684
|
|
|
684
685
|
// Determine button state and text
|
|
685
686
|
const btnInfo: { text: string; disable: boolean; error: boolean; loading: boolean } = useMemo(() => {
|
|
686
|
-
|
|
687
|
+
// For fiat tab, check srcAmountOnRamp; for crypto tab, check activeInputAmountInWei
|
|
688
|
+
const hasAmount =
|
|
689
|
+
activeTab === "fiat" ? srcAmountOnRamp && parseFloat(srcAmountOnRamp) > 0 : activeInputAmountInWei !== "0";
|
|
690
|
+
if (!hasAmount) return { text: "Enter an amount", disable: true, error: false, loading: false };
|
|
687
691
|
if (isSameChainSameToken)
|
|
688
692
|
return { text: "Select a different token or chain", disable: true, error: false, loading: false };
|
|
689
693
|
if (isLoadingAnyspendQuote) return { text: "Loading quote...", disable: true, error: false, loading: true };
|
|
@@ -739,6 +743,7 @@ function AnySpendInner({
|
|
|
739
743
|
activeTab,
|
|
740
744
|
effectiveCryptoPaymentMethod,
|
|
741
745
|
selectedFiatPaymentMethod,
|
|
746
|
+
srcAmountOnRamp,
|
|
742
747
|
]);
|
|
743
748
|
|
|
744
749
|
// Handle main button click
|
|
@@ -870,11 +875,20 @@ function AnySpendInner({
|
|
|
870
875
|
vendor = "coinbase";
|
|
871
876
|
paymentMethodString = coinbaseAvailablePaymentMethods[0]?.id || ""; // Use first available payment method ID
|
|
872
877
|
} else if (paymentMethod === FiatPaymentMethod.STRIPE) {
|
|
873
|
-
|
|
874
|
-
|
|
878
|
+
// Stripe redirect flow (one-click URL)
|
|
879
|
+
if (!stripeOnrampSupport) {
|
|
880
|
+
toast.error("Credit/Debit Card not available");
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
vendor = "stripe";
|
|
884
|
+
paymentMethodString = "";
|
|
885
|
+
} else if (paymentMethod === FiatPaymentMethod.STRIPE_WEB2) {
|
|
886
|
+
// Stripe embedded payment form
|
|
887
|
+
if (!stripeWeb2Support.isSupport) {
|
|
888
|
+
toast.error("Pay with Card not available");
|
|
875
889
|
return;
|
|
876
890
|
}
|
|
877
|
-
vendor =
|
|
891
|
+
vendor = "stripe-web2";
|
|
878
892
|
paymentMethodString = "";
|
|
879
893
|
} else {
|
|
880
894
|
toast.error("Please select a payment method");
|
|
@@ -27,12 +27,13 @@
|
|
|
27
27
|
import { USDC_BASE } from "@b3dotfun/sdk/anyspend/constants";
|
|
28
28
|
import { components } from "@b3dotfun/sdk/anyspend/types/api";
|
|
29
29
|
import { GetQuoteResponse } from "@b3dotfun/sdk/anyspend/types/api_req_res";
|
|
30
|
+
import { formatUnits } from "@b3dotfun/sdk/shared/utils/number";
|
|
30
31
|
import React, { useMemo } from "react";
|
|
31
32
|
import { encodeFunctionData } from "viem";
|
|
32
33
|
import { AnySpendCustom } from "./AnySpendCustom";
|
|
33
34
|
|
|
34
35
|
// Collector Club Shop contract on Base
|
|
35
|
-
const CC_SHOP_ADDRESS = "
|
|
36
|
+
const CC_SHOP_ADDRESS = "0x23887D10c81118A9a2E3Af59C423e2f4ee4Cc7Cf";
|
|
36
37
|
const BASE_CHAIN_ID = 8453;
|
|
37
38
|
|
|
38
39
|
// ABI for buyPacksFor function only
|
|
@@ -136,6 +137,12 @@ export function AnySpendCollectorClubPurchase({
|
|
|
136
137
|
}
|
|
137
138
|
}, [pricePerPack, packAmount]);
|
|
138
139
|
|
|
140
|
+
// Calculate fiat amount (totalAmount in USD, assuming USDC with 6 decimals)
|
|
141
|
+
const srcFiatAmount = useMemo(() => {
|
|
142
|
+
if (!totalAmount || totalAmount === "0") return "0";
|
|
143
|
+
return formatUnits(totalAmount, USDC_BASE.decimals);
|
|
144
|
+
}, [totalAmount]);
|
|
145
|
+
|
|
139
146
|
// Encode the buyPacksFor function call
|
|
140
147
|
const encodedData = useMemo(() => {
|
|
141
148
|
try {
|
|
@@ -185,6 +192,7 @@ export function AnySpendCollectorClubPurchase({
|
|
|
185
192
|
header={header || defaultHeader}
|
|
186
193
|
onSuccess={onSuccess}
|
|
187
194
|
showRecipient={showRecipient}
|
|
195
|
+
srcFiatAmount={srcFiatAmount}
|
|
188
196
|
/>
|
|
189
197
|
);
|
|
190
198
|
}
|
|
@@ -44,14 +44,13 @@ import { motion } from "motion/react";
|
|
|
44
44
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
45
45
|
|
|
46
46
|
import { base } from "viem/chains";
|
|
47
|
-
import { useFeatureFlags } from "../contexts/FeatureFlagsContext";
|
|
48
47
|
import { useAutoSetActiveWalletFromWagmi } from "../hooks/useAutoSetActiveWalletFromWagmi";
|
|
49
48
|
import { useCryptoPaymentMethodState } from "../hooks/useCryptoPaymentMethodState";
|
|
50
49
|
import { useRecipientAddressState } from "../hooks/useRecipientAddressState";
|
|
51
50
|
import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper";
|
|
52
51
|
import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod";
|
|
53
52
|
import { FeeBreakDown } from "./common/FeeBreakDown";
|
|
54
|
-
import { FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaymentMethod";
|
|
53
|
+
import { FIAT_PAYMENT_METHOD_DISPLAY, FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaymentMethod";
|
|
55
54
|
import { OrderDetails } from "./common/OrderDetails";
|
|
56
55
|
import { OrderHistory } from "./common/OrderHistory";
|
|
57
56
|
import { OrderToken } from "./common/OrderToken";
|
|
@@ -188,6 +187,8 @@ export function AnySpendCustom(props: {
|
|
|
188
187
|
onSuccess?: (txHash?: string) => void;
|
|
189
188
|
showRecipient?: boolean;
|
|
190
189
|
onShowPointsDetail?: () => void;
|
|
190
|
+
/** Fiat amount in USD for fiat payments */
|
|
191
|
+
srcFiatAmount?: string;
|
|
191
192
|
}) {
|
|
192
193
|
const fingerprintConfig = getFingerprintConfig();
|
|
193
194
|
|
|
@@ -215,6 +216,7 @@ function AnySpendCustomInner({
|
|
|
215
216
|
onSuccess,
|
|
216
217
|
showRecipient = true,
|
|
217
218
|
onShowPointsDetail,
|
|
219
|
+
srcFiatAmount: srcFiatAmountProps,
|
|
218
220
|
}: {
|
|
219
221
|
loadOrder?: string;
|
|
220
222
|
mode?: "modal" | "page";
|
|
@@ -238,9 +240,9 @@ function AnySpendCustomInner({
|
|
|
238
240
|
onSuccess?: (txHash?: string) => void;
|
|
239
241
|
showRecipient?: boolean;
|
|
240
242
|
onShowPointsDetail?: () => void;
|
|
243
|
+
srcFiatAmount?: string;
|
|
241
244
|
}) {
|
|
242
245
|
const hasMounted = useHasMounted();
|
|
243
|
-
const featureFlags = useFeatureFlags();
|
|
244
246
|
|
|
245
247
|
const searchParams = useSearchParamsSSR();
|
|
246
248
|
const router = useRouter();
|
|
@@ -353,7 +355,12 @@ function AnySpendCustomInner({
|
|
|
353
355
|
contractType: orderType === "mint_nft" ? metadata?.nftContract?.type : undefined,
|
|
354
356
|
encodedData: encodedData,
|
|
355
357
|
spenderAddress: spenderAddress,
|
|
356
|
-
onrampVendor:
|
|
358
|
+
onrampVendor:
|
|
359
|
+
selectedFiatPaymentMethod === FiatPaymentMethod.STRIPE
|
|
360
|
+
? "stripe"
|
|
361
|
+
: selectedFiatPaymentMethod === FiatPaymentMethod.STRIPE_WEB2
|
|
362
|
+
? "stripe-web2"
|
|
363
|
+
: undefined,
|
|
357
364
|
});
|
|
358
365
|
}, [
|
|
359
366
|
activeTab,
|
|
@@ -402,14 +409,31 @@ function AnySpendCustomInner({
|
|
|
402
409
|
}
|
|
403
410
|
}, [activeTab, anyspendQuote?.data]);
|
|
404
411
|
const formattedSrcAmount = srcAmount ? formatTokenAmount(srcAmount, srcToken.decimals, 6, false) : null;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
412
|
+
// Calculate fiat amount for geo check (regardless of activeTab) to determine tab availability
|
|
413
|
+
const srcFiatAmountForGeoCheck = useMemo(() => {
|
|
414
|
+
// Use prop if provided
|
|
415
|
+
if (srcFiatAmountProps) {
|
|
416
|
+
return srcFiatAmountProps;
|
|
417
|
+
}
|
|
418
|
+
// Fallback to dstAmount if destination token is USDC
|
|
419
|
+
if (dstAmount && dstToken.address.toLowerCase() === USDC_BASE.address.toLowerCase()) {
|
|
420
|
+
return formatUnits(dstAmount, USDC_BASE.decimals);
|
|
421
|
+
}
|
|
422
|
+
// Use srcAmount if available (from quote)
|
|
423
|
+
if (srcAmount) {
|
|
424
|
+
return formatUnits(srcAmount.toString(), USDC_BASE.decimals);
|
|
425
|
+
}
|
|
426
|
+
return "0";
|
|
427
|
+
}, [srcAmount, srcFiatAmountProps, dstAmount, dstToken.address]);
|
|
409
428
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
429
|
+
const srcFiatAmount = useMemo(() => {
|
|
430
|
+
if (activeTab !== "fiat") return "0";
|
|
431
|
+
return srcFiatAmountForGeoCheck;
|
|
432
|
+
}, [activeTab, srcFiatAmountForGeoCheck]);
|
|
433
|
+
|
|
434
|
+
// Get geo data and onramp options (use srcFiatAmountForGeoCheck to check availability regardless of activeTab)
|
|
435
|
+
const { geoData, isOnrampSupported, coinbaseAvailablePaymentMethods, stripeOnrampSupport, stripeWeb2Support } =
|
|
436
|
+
useGeoOnrampOptions(srcFiatAmountForGeoCheck);
|
|
413
437
|
|
|
414
438
|
useEffect(() => {
|
|
415
439
|
if (oat?.data?.order.status === "executed" && !onSuccessCalled.current) {
|
|
@@ -521,9 +545,14 @@ function AnySpendCustomInner({
|
|
|
521
545
|
// Get the current geo data from the hook
|
|
522
546
|
const currentGeoData = geoData;
|
|
523
547
|
|
|
548
|
+
// Use total amount from quote (includes fees) for onramp, fallback to srcFiatAmount
|
|
549
|
+
const onrampAmount = anyspendQuote?.data?.currencyIn?.amountUsd
|
|
550
|
+
? anyspendQuote.data.currencyIn.amountUsd.toString()
|
|
551
|
+
: srcFiatAmount;
|
|
552
|
+
|
|
524
553
|
void createOnrampOrder({
|
|
525
554
|
...createOrderParams,
|
|
526
|
-
srcFiatAmount:
|
|
555
|
+
srcFiatAmount: onrampAmount,
|
|
527
556
|
onramp: {
|
|
528
557
|
vendor: onramp.vendor,
|
|
529
558
|
paymentMethod: onramp.paymentMethod,
|
|
@@ -601,12 +630,21 @@ function AnySpendCustomInner({
|
|
|
601
630
|
}
|
|
602
631
|
vendor = "coinbase";
|
|
603
632
|
paymentMethodString = coinbaseAvailablePaymentMethods[0]?.id || "";
|
|
604
|
-
} else if (paymentMethod === FiatPaymentMethod.
|
|
633
|
+
} else if (paymentMethod === FiatPaymentMethod.STRIPE_WEB2) {
|
|
634
|
+
// Stripe Web2 embedded payment
|
|
605
635
|
if (!stripeWeb2Support || !stripeWeb2Support.isSupport) {
|
|
606
|
-
toast.error("Stripe not available");
|
|
636
|
+
toast.error("Stripe embedded payment not available");
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
vendor = "stripe-web2";
|
|
640
|
+
paymentMethodString = "";
|
|
641
|
+
} else if (paymentMethod === FiatPaymentMethod.STRIPE) {
|
|
642
|
+
// Stripe redirect (one-click buy URL)
|
|
643
|
+
if (!stripeOnrampSupport) {
|
|
644
|
+
toast.error("Stripe redirect payment not available");
|
|
607
645
|
return;
|
|
608
646
|
}
|
|
609
|
-
vendor =
|
|
647
|
+
vendor = "stripe";
|
|
610
648
|
paymentMethodString = "";
|
|
611
649
|
} else {
|
|
612
650
|
toast.error("Please select a payment method");
|
|
@@ -803,7 +841,7 @@ function AnySpendCustomInner({
|
|
|
803
841
|
|
|
804
842
|
// Render points badge if conditions are met
|
|
805
843
|
const renderPointsBadge = () => {
|
|
806
|
-
if (
|
|
844
|
+
if (anyspendQuote?.data?.pointsAmount && anyspendQuote.data.pointsAmount > 0) {
|
|
807
845
|
return (
|
|
808
846
|
<PointsBadge
|
|
809
847
|
pointsAmount={anyspendQuote.data.pointsAmount}
|
|
@@ -1094,32 +1132,28 @@ function AnySpendCustomInner({
|
|
|
1094
1132
|
className="text-as-tertiarry flex flex-wrap items-center justify-end gap-2 text-sm transition-colors hover:text-blue-700"
|
|
1095
1133
|
onClick={() => setActivePanel(PanelView.FIAT_PAYMENT_METHOD)}
|
|
1096
1134
|
>
|
|
1097
|
-
{
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
<span className="whitespace-nowrap">Select payment method</span>
|
|
1120
|
-
<ChevronRight className="h-4 w-4 shrink-0" />
|
|
1121
|
-
</>
|
|
1122
|
-
)}
|
|
1135
|
+
{(() => {
|
|
1136
|
+
const config = FIAT_PAYMENT_METHOD_DISPLAY[selectedFiatPaymentMethod];
|
|
1137
|
+
if (config) {
|
|
1138
|
+
return (
|
|
1139
|
+
<>
|
|
1140
|
+
<div className="flex items-center gap-2 whitespace-nowrap">
|
|
1141
|
+
<div className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-600">
|
|
1142
|
+
<span className="text-xs font-bold text-white">{config.icon}</span>
|
|
1143
|
+
</div>
|
|
1144
|
+
{config.label}
|
|
1145
|
+
</div>
|
|
1146
|
+
<ChevronRight className="h-4 w-4 shrink-0" />
|
|
1147
|
+
</>
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
return (
|
|
1151
|
+
<>
|
|
1152
|
+
<span className="whitespace-nowrap">Select payment method</span>
|
|
1153
|
+
<ChevronRight className="h-4 w-4 shrink-0" />
|
|
1154
|
+
</>
|
|
1155
|
+
);
|
|
1156
|
+
})()}
|
|
1123
1157
|
</button>
|
|
1124
1158
|
</motion.div>
|
|
1125
1159
|
|
|
@@ -1162,20 +1196,32 @@ function AnySpendCustomInner({
|
|
|
1162
1196
|
<div className="flex flex-col items-end gap-0.5">
|
|
1163
1197
|
<div className="flex flex-wrap items-center justify-end gap-2">
|
|
1164
1198
|
{renderPointsBadge()}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1199
|
+
{isLoadingAnyspendQuote ? (
|
|
1200
|
+
<div className="bg-as-surface-secondary h-7 w-16 animate-pulse rounded" />
|
|
1201
|
+
) : (
|
|
1202
|
+
<span className="text-as-primary whitespace-nowrap text-xl font-semibold">
|
|
1203
|
+
{anyspendQuote?.data?.currencyIn?.amountUsd ? (
|
|
1204
|
+
`$${Number(anyspendQuote.data.currencyIn.amountUsd).toFixed(2)}`
|
|
1205
|
+
) : (
|
|
1206
|
+
<>
|
|
1207
|
+
${parseFloat(srcFiatAmount || "0").toFixed(2)}
|
|
1208
|
+
<span className="text-as-tertiarry text-base">+</span>
|
|
1209
|
+
</>
|
|
1210
|
+
)}
|
|
1211
|
+
</span>
|
|
1212
|
+
)}
|
|
1168
1213
|
</div>
|
|
1169
|
-
{
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
{(
|
|
1214
|
+
{(() => {
|
|
1215
|
+
if (anyspendQuote?.data?.fee?.type === "stripeweb2_fee" && anyspendQuote.data.fee.originalAmount) {
|
|
1216
|
+
const fee =
|
|
1173
1217
|
(Number(anyspendQuote.data.fee.originalAmount) - Number(anyspendQuote.data.fee.finalAmount)) /
|
|
1174
|
-
1e6
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1218
|
+
1e6;
|
|
1219
|
+
if (fee > 0) {
|
|
1220
|
+
return <span className="text-as-secondary text-xs">incl. ${fee.toFixed(2)} fee</span>;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
return null;
|
|
1224
|
+
})()}
|
|
1179
1225
|
</div>
|
|
1180
1226
|
</motion.div>
|
|
1181
1227
|
</div>
|
|
@@ -1273,17 +1319,25 @@ function AnySpendCustomInner({
|
|
|
1273
1319
|
</div>
|
|
1274
1320
|
);
|
|
1275
1321
|
|
|
1322
|
+
// Stable callback for fiat payment method selection
|
|
1323
|
+
const handleFiatPaymentMethodSelect = useCallback((method: FiatPaymentMethod) => {
|
|
1324
|
+
setSelectedFiatPaymentMethod(method);
|
|
1325
|
+
setActivePanel(PanelView.CONFIRM_ORDER);
|
|
1326
|
+
}, []);
|
|
1327
|
+
|
|
1328
|
+
// Stable callback for navigating back to confirm order
|
|
1329
|
+
const handleBackToConfirmOrder = useCallback(() => {
|
|
1330
|
+
setActivePanel(PanelView.CONFIRM_ORDER);
|
|
1331
|
+
}, []);
|
|
1332
|
+
|
|
1276
1333
|
// Fiat payment method view
|
|
1277
1334
|
const fiatPaymentMethodView = (
|
|
1278
1335
|
<div className={cn("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4")}>
|
|
1279
1336
|
<FiatPaymentMethodComponent
|
|
1280
1337
|
selectedPaymentMethod={selectedFiatPaymentMethod}
|
|
1281
1338
|
setSelectedPaymentMethod={setSelectedFiatPaymentMethod}
|
|
1282
|
-
onBack={
|
|
1283
|
-
onSelectPaymentMethod={
|
|
1284
|
-
setSelectedFiatPaymentMethod(method);
|
|
1285
|
-
setActivePanel(PanelView.CONFIRM_ORDER);
|
|
1286
|
-
}}
|
|
1339
|
+
onBack={handleBackToConfirmOrder}
|
|
1340
|
+
onSelectPaymentMethod={handleFiatPaymentMethodSelect}
|
|
1287
1341
|
srcAmountOnRamp={srcFiatAmount}
|
|
1288
1342
|
/>
|
|
1289
1343
|
</div>
|
|
@@ -7,7 +7,7 @@ import { getIpfsUrl } from "@b3dotfun/sdk/shared/utils/ipfs";
|
|
|
7
7
|
import { formatDisplayNumber, formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
|
|
8
8
|
import { MoreVertical } from "lucide-react";
|
|
9
9
|
import { AnimatePresence } from "motion/react";
|
|
10
|
-
import { useEffect, useState } from "react";
|
|
10
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
11
|
import { b3 } from "viem/chains";
|
|
12
12
|
import { GetQuoteResponse } from "../../types/api_req_res";
|
|
13
13
|
import { AnySpendCustom } from "./AnySpendCustom";
|
|
@@ -46,19 +46,19 @@ export function AnySpendNFT({
|
|
|
46
46
|
onShowPointsDetail?: () => void;
|
|
47
47
|
}) {
|
|
48
48
|
const [imageUrlWithFallback, setFallbackImageUrl] = useState<string | null>(nftContract.imageUrl);
|
|
49
|
-
const
|
|
49
|
+
const hasFetchedRef = useRef(false);
|
|
50
50
|
|
|
51
51
|
// Fetch contract metadata when imageUrl is empty
|
|
52
52
|
useEffect(() => {
|
|
53
53
|
async function fetchContractMetadata() {
|
|
54
54
|
// fetch image Uri if not provided
|
|
55
|
-
if (nftContract.imageUrl ||
|
|
55
|
+
if (nftContract.imageUrl || hasFetchedRef.current) {
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
setIsLoadingFallback(true);
|
|
59
|
+
hasFetchedRef.current = true;
|
|
61
60
|
|
|
61
|
+
try {
|
|
62
62
|
// Use the chainIdToPublicClient utility function
|
|
63
63
|
const publicClient = chainIdToPublicClient(nftContract.chainId);
|
|
64
64
|
|
|
@@ -96,56 +96,57 @@ export function AnySpendNFT({
|
|
|
96
96
|
}
|
|
97
97
|
} catch (error) {
|
|
98
98
|
console.error("Error fetching contract metadata:", error);
|
|
99
|
-
} finally {
|
|
100
|
-
setIsLoadingFallback(false);
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
fetchContractMetadata();
|
|
105
|
-
}, [nftContract.contractAddress, nftContract.chainId, nftContract.imageUrl, nftContract.tokenId
|
|
106
|
-
|
|
107
|
-
const header = (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
<div className="
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<div className="absolute inset-0 rounded-xl border border-white/10"></div>
|
|
122
|
-
</GlareCard>
|
|
123
|
-
|
|
124
|
-
<DropdownMenu nftContract={nftContract} />
|
|
125
|
-
</div>
|
|
126
|
-
<div className="from-b3-react-background to-as-on-surface-1 -mb-5 mt-[-100px] w-full rounded-t-lg bg-gradient-to-t">
|
|
127
|
-
<div className="h-[100px] w-full" />
|
|
128
|
-
<div className="mb-1 flex w-full flex-col items-center gap-2 p-5">
|
|
129
|
-
<span className="font-sf-rounded text-2xl font-semibold">{nftContract.name}</span>
|
|
130
|
-
|
|
131
|
-
<div className="flex w-fit items-center gap-1">
|
|
132
|
-
{anyspendPrice ? (
|
|
133
|
-
<AnimatePresence mode="wait">
|
|
134
|
-
<div
|
|
135
|
-
className={cn("text-as-primary group flex items-center text-3xl font-semibold transition-all", {
|
|
136
|
-
"opacity-0": isLoadingAnyspendPrice,
|
|
137
|
-
})}
|
|
138
|
-
>
|
|
139
|
-
{formatDisplayNumber(anyspendPrice?.data?.currencyIn?.amountUsd, { style: "currency" })}
|
|
140
|
-
</div>
|
|
141
|
-
</AnimatePresence>
|
|
142
|
-
) : (
|
|
143
|
-
<div className="h-[36px] w-full" />
|
|
103
|
+
}, [nftContract.contractAddress, nftContract.chainId, nftContract.imageUrl, nftContract.tokenId]);
|
|
104
|
+
|
|
105
|
+
const header = useCallback(
|
|
106
|
+
({
|
|
107
|
+
anyspendPrice,
|
|
108
|
+
isLoadingAnyspendPrice,
|
|
109
|
+
}: {
|
|
110
|
+
anyspendPrice: GetQuoteResponse | undefined;
|
|
111
|
+
isLoadingAnyspendPrice: boolean;
|
|
112
|
+
}) => (
|
|
113
|
+
<>
|
|
114
|
+
<div className="relative size-[200px]">
|
|
115
|
+
<div className="absolute inset-0 scale-95 bg-black/30 blur-md"></div>
|
|
116
|
+
<GlareCard className="overflow-hidden">
|
|
117
|
+
{imageUrlWithFallback && (
|
|
118
|
+
<img src={imageUrlWithFallback} alt={nftContract.name} className="size-full object-cover" />
|
|
144
119
|
)}
|
|
120
|
+
<div className="absolute inset-0 rounded-xl border border-white/10"></div>
|
|
121
|
+
</GlareCard>
|
|
122
|
+
|
|
123
|
+
<DropdownMenu nftContract={nftContract} />
|
|
124
|
+
</div>
|
|
125
|
+
<div className="from-b3-react-background to-as-on-surface-1 -mb-5 mt-[-100px] w-full rounded-t-lg bg-gradient-to-t">
|
|
126
|
+
<div className="h-[100px] w-full" />
|
|
127
|
+
<div className="mb-1 flex w-full flex-col items-center gap-2 p-5">
|
|
128
|
+
<span className="font-sf-rounded text-2xl font-semibold">{nftContract.name}</span>
|
|
129
|
+
|
|
130
|
+
<div className="flex w-fit items-center gap-1">
|
|
131
|
+
{anyspendPrice ? (
|
|
132
|
+
<AnimatePresence mode="wait">
|
|
133
|
+
<div
|
|
134
|
+
className={cn("text-as-primary group flex items-center text-3xl font-semibold transition-all", {
|
|
135
|
+
"opacity-0": isLoadingAnyspendPrice,
|
|
136
|
+
})}
|
|
137
|
+
>
|
|
138
|
+
{formatDisplayNumber(anyspendPrice?.data?.currencyIn?.amountUsd, { style: "currency" })}
|
|
139
|
+
</div>
|
|
140
|
+
</AnimatePresence>
|
|
141
|
+
) : (
|
|
142
|
+
<div className="h-[36px] w-full" />
|
|
143
|
+
)}
|
|
144
|
+
</div>
|
|
145
145
|
</div>
|
|
146
146
|
</div>
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
</>
|
|
148
|
+
),
|
|
149
|
+
[imageUrlWithFallback, nftContract],
|
|
149
150
|
);
|
|
150
151
|
|
|
151
152
|
return (
|
|
@@ -5,7 +5,6 @@ import { formatDisplayNumber } from "@b3dotfun/sdk/shared/utils/number";
|
|
|
5
5
|
import { ChevronRight, Info } from "lucide-react";
|
|
6
6
|
import { motion } from "motion/react";
|
|
7
7
|
import { components } from "../../../types/api";
|
|
8
|
-
import { useFeatureFlags } from "../../contexts/FeatureFlagsContext";
|
|
9
8
|
import { OrderTokenAmount } from "./OrderTokenAmount";
|
|
10
9
|
import { PointsBadge } from "./PointsBadge";
|
|
11
10
|
|
|
@@ -55,8 +54,6 @@ export function CryptoReceiveSection({
|
|
|
55
54
|
onShowPointsDetail,
|
|
56
55
|
onShowFeeDetail,
|
|
57
56
|
}: CryptoReceiveSectionProps) {
|
|
58
|
-
const featureFlags = useFeatureFlags();
|
|
59
|
-
|
|
60
57
|
return (
|
|
61
58
|
<motion.div
|
|
62
59
|
initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
|
|
@@ -184,7 +181,7 @@ export function CryptoReceiveSection({
|
|
|
184
181
|
);
|
|
185
182
|
})()}
|
|
186
183
|
</div>
|
|
187
|
-
{
|
|
184
|
+
{anyspendQuote?.data?.pointsAmount > 0 && (
|
|
188
185
|
<PointsBadge
|
|
189
186
|
pointsAmount={anyspendQuote.data.pointsAmount}
|
|
190
187
|
pointsMultiplier={anyspendQuote.data.pointsMultiplier}
|