@b3dotfun/sdk 0.1.65 → 0.1.66-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 +2 -0
- package/dist/cjs/anyspend/react/components/AnySpend.js +7 -16
- package/dist/cjs/anyspend/react/components/AnySpendCollectorClubPurchase.d.ts +6 -1
- package/dist/cjs/anyspend/react/components/AnySpendCollectorClubPurchase.js +151 -22
- package/dist/cjs/anyspend/react/components/AnySpendCustom.js +4 -50
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.d.ts +2 -0
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +4 -2
- package/dist/cjs/anyspend/react/components/AnySpendDeposit.d.ts +3 -1
- package/dist/cjs/anyspend/react/components/AnySpendDeposit.js +2 -2
- package/dist/cjs/anyspend/react/components/AnySpendWorkflowTrigger.d.ts +31 -0
- package/dist/cjs/anyspend/react/components/AnySpendWorkflowTrigger.js +14 -0
- package/dist/cjs/anyspend/react/components/QRDeposit.js +5 -13
- package/dist/cjs/anyspend/react/components/ccShopAbi.d.ts +113 -0
- package/dist/cjs/anyspend/react/components/ccShopAbi.js +63 -0
- package/dist/cjs/anyspend/react/components/common/CryptoPaySection.d.ts +1 -3
- package/dist/cjs/anyspend/react/components/common/CryptoPaySection.js +3 -3
- package/dist/cjs/anyspend/react/components/common/OrderTokenAmount.d.ts +1 -4
- package/dist/cjs/anyspend/react/components/common/OrderTokenAmount.js +3 -57
- package/dist/cjs/anyspend/react/components/common/PaySection.js +1 -1
- package/dist/cjs/anyspend/react/components/index.d.ts +2 -0
- package/dist/cjs/anyspend/react/components/index.js +3 -1
- 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/useAnyspendCreateOnrampOrder.js +1 -0
- package/dist/cjs/anyspend/react/hooks/useAnyspendCreateOrder.d.ts +1 -0
- package/dist/cjs/anyspend/react/hooks/useAnyspendCreateOrder.js +1 -0
- package/dist/cjs/anyspend/react/hooks/useOnOrderSuccess.d.ts +10 -0
- package/dist/cjs/anyspend/react/hooks/useOnOrderSuccess.js +27 -0
- package/dist/cjs/anyspend/services/anyspend.d.ts +2 -1
- package/dist/cjs/anyspend/services/anyspend.js +2 -1
- package/dist/cjs/anyspend/utils/chain.d.ts +1 -1
- package/dist/cjs/anyspend/utils/chain.js +72 -62
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +4 -0
- package/dist/cjs/global-account/react/hooks/useUserQuery.js +10 -0
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +37 -1
- package/dist/cjs/global-account/react/stores/userStore.js +1 -0
- package/dist/esm/anyspend/react/components/AnySpend.d.ts +2 -0
- package/dist/esm/anyspend/react/components/AnySpend.js +7 -16
- package/dist/esm/anyspend/react/components/AnySpendCollectorClubPurchase.d.ts +6 -1
- package/dist/esm/anyspend/react/components/AnySpendCollectorClubPurchase.js +152 -23
- package/dist/esm/anyspend/react/components/AnySpendCustom.js +4 -17
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.d.ts +2 -0
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +4 -2
- package/dist/esm/anyspend/react/components/AnySpendDeposit.d.ts +3 -1
- package/dist/esm/anyspend/react/components/AnySpendDeposit.js +2 -2
- package/dist/esm/anyspend/react/components/AnySpendWorkflowTrigger.d.ts +31 -0
- package/dist/esm/anyspend/react/components/AnySpendWorkflowTrigger.js +11 -0
- package/dist/esm/anyspend/react/components/QRDeposit.js +6 -14
- package/dist/esm/anyspend/react/components/ccShopAbi.d.ts +113 -0
- package/dist/esm/anyspend/react/components/ccShopAbi.js +60 -0
- package/dist/esm/anyspend/react/components/common/CryptoPaySection.d.ts +1 -3
- package/dist/esm/anyspend/react/components/common/CryptoPaySection.js +3 -3
- package/dist/esm/anyspend/react/components/common/OrderTokenAmount.d.ts +1 -4
- package/dist/esm/anyspend/react/components/common/OrderTokenAmount.js +2 -56
- package/dist/esm/anyspend/react/components/common/PaySection.js +1 -1
- package/dist/esm/anyspend/react/components/index.d.ts +2 -0
- package/dist/esm/anyspend/react/components/index.js +1 -0
- 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/useAnyspendCreateOnrampOrder.js +1 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendCreateOrder.d.ts +1 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendCreateOrder.js +1 -0
- package/dist/esm/anyspend/react/hooks/useOnOrderSuccess.d.ts +10 -0
- package/dist/esm/anyspend/react/hooks/useOnOrderSuccess.js +24 -0
- package/dist/esm/anyspend/services/anyspend.d.ts +2 -1
- package/dist/esm/anyspend/services/anyspend.js +2 -1
- package/dist/esm/anyspend/utils/chain.d.ts +1 -1
- package/dist/esm/anyspend/utils/chain.js +72 -62
- package/dist/esm/global-account/react/components/B3DynamicModal.js +4 -0
- package/dist/esm/global-account/react/hooks/useUserQuery.js +11 -1
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +37 -1
- package/dist/esm/global-account/react/stores/userStore.js +1 -0
- package/dist/types/anyspend/react/components/AnySpend.d.ts +2 -0
- package/dist/types/anyspend/react/components/AnySpendCollectorClubPurchase.d.ts +6 -1
- package/dist/types/anyspend/react/components/AnySpendCustomExactIn.d.ts +2 -0
- package/dist/types/anyspend/react/components/AnySpendDeposit.d.ts +3 -1
- package/dist/types/anyspend/react/components/AnySpendWorkflowTrigger.d.ts +31 -0
- package/dist/types/anyspend/react/components/ccShopAbi.d.ts +113 -0
- package/dist/types/anyspend/react/components/common/CryptoPaySection.d.ts +1 -3
- package/dist/types/anyspend/react/components/common/OrderTokenAmount.d.ts +1 -4
- package/dist/types/anyspend/react/components/index.d.ts +2 -0
- package/dist/types/anyspend/react/hooks/index.d.ts +1 -0
- package/dist/types/anyspend/react/hooks/useAnyspendCreateOrder.d.ts +1 -0
- package/dist/types/anyspend/react/hooks/useOnOrderSuccess.d.ts +10 -0
- package/dist/types/anyspend/services/anyspend.d.ts +2 -1
- package/dist/types/anyspend/utils/chain.d.ts +1 -1
- package/dist/types/global-account/react/stores/useModalStore.d.ts +37 -1
- package/package.json +1 -1
- package/src/anyspend/README.md +14 -0
- package/src/anyspend/docs/checkout-sessions.md +228 -0
- package/src/anyspend/docs/components.md +26 -0
- package/src/anyspend/docs/examples.md +58 -0
- package/src/anyspend/docs/hooks.md +32 -0
- package/src/anyspend/llms.txt +185 -0
- package/src/anyspend/react/components/AnySpend.tsx +9 -17
- package/src/anyspend/react/components/AnySpendCollectorClubPurchase.tsx +206 -22
- package/src/anyspend/react/components/AnySpendCustom.tsx +3 -18
- package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +5 -1
- package/src/anyspend/react/components/AnySpendDeposit.tsx +5 -0
- package/src/anyspend/react/components/AnySpendWorkflowTrigger.tsx +73 -0
- package/src/anyspend/react/components/QRDeposit.tsx +19 -15
- package/src/anyspend/react/components/ccShopAbi.ts +64 -0
- package/src/anyspend/react/components/common/CryptoPaySection.tsx +0 -5
- package/src/anyspend/react/components/common/OrderTokenAmount.tsx +1 -70
- package/src/anyspend/react/components/common/PaySection.tsx +0 -1
- package/src/anyspend/react/components/index.ts +2 -0
- package/src/anyspend/react/hooks/index.ts +1 -0
- package/src/anyspend/react/hooks/useAnyspendCreateOnrampOrder.ts +1 -0
- package/src/anyspend/react/hooks/useAnyspendCreateOrder.ts +2 -0
- package/src/anyspend/react/hooks/useOnOrderSuccess.ts +36 -0
- package/src/anyspend/services/anyspend.ts +3 -0
- package/src/anyspend/utils/chain.ts +81 -65
- package/src/global-account/react/components/B3DynamicModal.tsx +4 -0
- package/src/global-account/react/hooks/useUserQuery.ts +12 -1
- package/src/global-account/react/stores/useModalStore.ts +39 -2
- package/src/global-account/react/stores/userStore.ts +1 -0
|
@@ -392,8 +392,8 @@ function getPaymentUrl(address, amount, currency, chainId, decimals) {
|
|
|
392
392
|
// For EVM chains, follow EIP-681 format
|
|
393
393
|
// Format: ethereum:[address]@[chainId]?value=[amount]&symbol=[symbol]
|
|
394
394
|
const params = new URLSearchParams();
|
|
395
|
-
// Add value for native token transfers
|
|
396
|
-
if (currency === chain.nativeToken.symbol) {
|
|
395
|
+
// Add value for native token transfers (skip if amount not provided, e.g. deposit_first)
|
|
396
|
+
if (currency === chain.nativeToken.symbol && amount !== undefined) {
|
|
397
397
|
params.append("value", amount.toString());
|
|
398
398
|
}
|
|
399
399
|
// Handle token transfers differently from native transfers
|
|
@@ -408,28 +408,31 @@ function getPaymentUrl(address, amount, currency, chainId, decimals) {
|
|
|
408
408
|
}
|
|
409
409
|
// For ERC20 tokens, convert from smallest unit to display units using decimals
|
|
410
410
|
// For example: 2400623 (raw) with 6 decimals becomes "2.400623"
|
|
411
|
-
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
411
|
+
// Skip amount if not provided (e.g. deposit_first orders)
|
|
412
|
+
if (amount !== undefined) {
|
|
413
|
+
let displayAmount;
|
|
414
|
+
if (decimals !== undefined && currency !== chain.nativeToken.symbol) {
|
|
415
|
+
// Convert from smallest unit to display unit for ERC20 tokens
|
|
416
|
+
const divisor = BigInt(10 ** decimals);
|
|
417
|
+
const wholePart = amount / divisor;
|
|
418
|
+
const fractionalPart = amount % divisor;
|
|
419
|
+
if (fractionalPart === BigInt(0)) {
|
|
420
|
+
displayAmount = wholePart.toString();
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
// Format fractional part with leading zeros if needed
|
|
424
|
+
const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
|
|
425
|
+
// Remove trailing zeros
|
|
426
|
+
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
427
|
+
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
428
|
+
}
|
|
419
429
|
}
|
|
420
430
|
else {
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
// Remove trailing zeros
|
|
424
|
-
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
425
|
-
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
431
|
+
// For native tokens or when decimals not provided, use raw amount
|
|
432
|
+
displayAmount = amount.toString();
|
|
426
433
|
}
|
|
434
|
+
tokenParams.append("amount", displayAmount);
|
|
427
435
|
}
|
|
428
|
-
else {
|
|
429
|
-
// For native tokens or when decimals not provided, use raw amount
|
|
430
|
-
displayAmount = amount.toString();
|
|
431
|
-
}
|
|
432
|
-
tokenParams.append("amount", displayAmount);
|
|
433
436
|
tokenParams.append("address", address); // recipient address
|
|
434
437
|
// For Arbitrum and other L2s, try a more explicit format
|
|
435
438
|
if (chainId !== chains_1.mainnet.id) {
|
|
@@ -449,7 +452,9 @@ function getPaymentUrl(address, amount, currency, chainId, decimals) {
|
|
|
449
452
|
// to make sure wallets recognize the correct chain
|
|
450
453
|
const nativeParams = new URLSearchParams();
|
|
451
454
|
nativeParams.append("chainId", chainId.toString());
|
|
452
|
-
|
|
455
|
+
if (amount !== undefined) {
|
|
456
|
+
nativeParams.append("value", amount.toString());
|
|
457
|
+
}
|
|
453
458
|
const url = `ethereum:${address}@${chainId}?${nativeParams.toString()}`;
|
|
454
459
|
return url;
|
|
455
460
|
}
|
|
@@ -468,60 +473,65 @@ function getPaymentUrl(address, amount, currency, chainId, decimals) {
|
|
|
468
473
|
const isNativeSOL = currency === chain.nativeToken.symbol || currency === "SOL" || currency === "11111111111111111111111111111111";
|
|
469
474
|
if (isNativeSOL) {
|
|
470
475
|
// Native SOL transfers - convert from lamports to SOL
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
else {
|
|
486
|
-
// Fallback: assume SOL has 9 decimals
|
|
487
|
-
const divisor = BigInt(1000000000); // 1e9
|
|
488
|
-
const wholePart = amount / divisor;
|
|
489
|
-
const fractionalPart = amount % divisor;
|
|
490
|
-
if (fractionalPart === BigInt(0)) {
|
|
491
|
-
displayAmount = wholePart.toString();
|
|
476
|
+
if (amount !== undefined) {
|
|
477
|
+
let displayAmount;
|
|
478
|
+
if (decimals !== undefined) {
|
|
479
|
+
const divisor = BigInt(10 ** decimals);
|
|
480
|
+
const wholePart = amount / divisor;
|
|
481
|
+
const fractionalPart = amount % divisor;
|
|
482
|
+
if (fractionalPart === BigInt(0)) {
|
|
483
|
+
displayAmount = wholePart.toString();
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
|
|
487
|
+
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
488
|
+
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
489
|
+
}
|
|
492
490
|
}
|
|
493
491
|
else {
|
|
494
|
-
|
|
495
|
-
const
|
|
496
|
-
|
|
492
|
+
// Fallback: assume SOL has 9 decimals
|
|
493
|
+
const divisor = BigInt(1000000000); // 1e9
|
|
494
|
+
const wholePart = amount / divisor;
|
|
495
|
+
const fractionalPart = amount % divisor;
|
|
496
|
+
if (fractionalPart === BigInt(0)) {
|
|
497
|
+
displayAmount = wholePart.toString();
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
const fractionalStr = fractionalPart.toString().padStart(9, "0");
|
|
501
|
+
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
502
|
+
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
503
|
+
}
|
|
497
504
|
}
|
|
505
|
+
// For native SOL, use simple format without spl-token parameter
|
|
506
|
+
params.append("amount", displayAmount);
|
|
498
507
|
}
|
|
499
|
-
// For native SOL, use simple format without spl-token parameter
|
|
500
|
-
params.append("amount", displayAmount);
|
|
501
508
|
}
|
|
502
509
|
else {
|
|
503
510
|
// SPL token transfers
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
+
if (amount !== undefined) {
|
|
512
|
+
let displayAmount;
|
|
513
|
+
if (decimals !== undefined) {
|
|
514
|
+
const divisor = BigInt(10 ** decimals);
|
|
515
|
+
const wholePart = amount / divisor;
|
|
516
|
+
const fractionalPart = amount % divisor;
|
|
517
|
+
if (fractionalPart === BigInt(0)) {
|
|
518
|
+
displayAmount = wholePart.toString();
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
|
|
522
|
+
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
523
|
+
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
524
|
+
}
|
|
511
525
|
}
|
|
512
526
|
else {
|
|
513
|
-
|
|
514
|
-
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
515
|
-
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
527
|
+
displayAmount = amount.toString();
|
|
516
528
|
}
|
|
529
|
+
params.append("amount", displayAmount);
|
|
517
530
|
}
|
|
518
|
-
else {
|
|
519
|
-
displayAmount = amount.toString();
|
|
520
|
-
}
|
|
521
|
-
params.append("amount", displayAmount);
|
|
522
531
|
params.append("spl-token", currency); // token mint address
|
|
523
532
|
}
|
|
524
|
-
const
|
|
533
|
+
const queryString = params.toString();
|
|
534
|
+
const url = queryString ? `solana:${address}?${queryString}` : `solana:${address}`;
|
|
525
535
|
console.log("Solana URL (isNativeSOL:", isNativeSOL, "):", url);
|
|
526
536
|
return url;
|
|
527
537
|
}
|
|
@@ -8,6 +8,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
8
8
|
const react_1 = require("../../../anyspend/react");
|
|
9
9
|
const AnySpendDeposit_1 = require("../../../anyspend/react/components/AnySpendDeposit");
|
|
10
10
|
const AnyspendDepositHype_1 = require("../../../anyspend/react/components/AnyspendDepositHype");
|
|
11
|
+
const AnySpendWorkflowTrigger_1 = require("../../../anyspend/react/components/AnySpendWorkflowTrigger");
|
|
11
12
|
const AnySpendDepositUpside_1 = require("../../../anyspend/react/components/AnySpendDepositUpside");
|
|
12
13
|
const AnySpendStakeUpside_1 = require("../../../anyspend/react/components/AnySpendStakeUpside");
|
|
13
14
|
const AnySpendStakeUpsideExactIn_1 = require("../../../anyspend/react/components/AnySpendStakeUpsideExactIn");
|
|
@@ -58,6 +59,7 @@ function B3DynamicModal() {
|
|
|
58
59
|
"send",
|
|
59
60
|
"notifications",
|
|
60
61
|
"anySpendDeposit",
|
|
62
|
+
"anySpendWorkflowTrigger",
|
|
61
63
|
];
|
|
62
64
|
const freestyleTypes = [
|
|
63
65
|
"anySpendNft",
|
|
@@ -128,6 +130,8 @@ function B3DynamicModal() {
|
|
|
128
130
|
return (0, jsx_runtime_1.jsx)(react_1.AnySpendCollectorClubPurchase, { ...contentType, mode: "modal" });
|
|
129
131
|
case "anySpendDeposit":
|
|
130
132
|
return (0, jsx_runtime_1.jsx)(AnySpendDeposit_1.AnySpendDeposit, { ...contentType, mode: "modal" });
|
|
133
|
+
case "anySpendWorkflowTrigger":
|
|
134
|
+
return (0, jsx_runtime_1.jsx)(AnySpendWorkflowTrigger_1.AnySpendWorkflowTrigger, { ...contentType, mode: "modal" });
|
|
131
135
|
case "avatarEditor":
|
|
132
136
|
return (0, jsx_runtime_1.jsx)(AvatarEditor_1.AvatarEditor, { onSetAvatar: contentType.onSuccess });
|
|
133
137
|
case "deposit":
|
|
@@ -14,6 +14,16 @@ function useUserQuery() {
|
|
|
14
14
|
const user = (0, userStore_1.useUserStore)(state => state.user);
|
|
15
15
|
const setUserStore = (0, userStore_1.useUserStore)(state => state.setUser);
|
|
16
16
|
const clearUserStore = (0, userStore_1.useUserStore)(state => state.clearUser);
|
|
17
|
+
// Manually rehydrate persisted store inside useLayoutEffect to avoid
|
|
18
|
+
// updating AuthenticationProvider state during Hydrate render.
|
|
19
|
+
// useLayoutEffect (not useEffect) ensures rehydration triggers a
|
|
20
|
+
// synchronous re-render before any useEffect callbacks fire, so
|
|
21
|
+
// downstream effects always see the persisted user value.
|
|
22
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
23
|
+
if (!userStore_1.useUserStore.persist.hasHydrated()) {
|
|
24
|
+
userStore_1.useUserStore.persist.rehydrate();
|
|
25
|
+
}
|
|
26
|
+
}, []);
|
|
17
27
|
// Listen for storage events from other tabs/windows
|
|
18
28
|
(0, react_1.useEffect)(() => {
|
|
19
29
|
const handleStorageChange = (e) => {
|
|
@@ -470,11 +470,45 @@ export interface AnySpendCollectorClubPurchaseProps extends BaseModalProps {
|
|
|
470
470
|
forceFiatPayment?: boolean;
|
|
471
471
|
/** Staging environment support */
|
|
472
472
|
isStaging?: boolean;
|
|
473
|
+
/** Optional discount code to apply to the purchase */
|
|
474
|
+
discountCode?: string;
|
|
473
475
|
}
|
|
474
476
|
/**
|
|
475
477
|
* Props for the AnySpend Deposit modal
|
|
476
478
|
* Flexible deposit component with optional chain selection
|
|
477
479
|
*/
|
|
480
|
+
/**
|
|
481
|
+
* Props for the AnySpend Workflow Trigger modal
|
|
482
|
+
* Handles payments that trigger b3os-workflow runs
|
|
483
|
+
*/
|
|
484
|
+
export interface AnySpendWorkflowTriggerModalProps extends BaseModalProps {
|
|
485
|
+
/** Modal type identifier */
|
|
486
|
+
type: "anySpendWorkflowTrigger";
|
|
487
|
+
/** Payment recipient address (hex) */
|
|
488
|
+
recipientAddress: string;
|
|
489
|
+
/** Destination chain ID */
|
|
490
|
+
chainId: number;
|
|
491
|
+
/** Destination token address */
|
|
492
|
+
tokenAddress: string;
|
|
493
|
+
/** Required payment amount in token base units (wei) */
|
|
494
|
+
amount: string;
|
|
495
|
+
/** Workflow ID to trigger */
|
|
496
|
+
workflowId: string;
|
|
497
|
+
/** Organization ID that owns the workflow */
|
|
498
|
+
orgId: string;
|
|
499
|
+
/** Optional callback metadata */
|
|
500
|
+
callbackMetadata?: {
|
|
501
|
+
inputs?: Record<string, unknown>;
|
|
502
|
+
} & Record<string, unknown>;
|
|
503
|
+
/** Callback when payment succeeds */
|
|
504
|
+
onSuccess?: (amount: string) => void;
|
|
505
|
+
/** Callback when modal is closed */
|
|
506
|
+
onClose?: () => void;
|
|
507
|
+
/** Custom action label */
|
|
508
|
+
actionLabel?: string;
|
|
509
|
+
/** Custom class names */
|
|
510
|
+
classes?: AnySpendAllClasses;
|
|
511
|
+
}
|
|
478
512
|
export interface AnySpendDepositModalProps extends BaseModalProps {
|
|
479
513
|
/** Modal type identifier */
|
|
480
514
|
type: "anySpendDeposit";
|
|
@@ -534,11 +568,13 @@ export interface AnySpendDepositModalProps extends BaseModalProps {
|
|
|
534
568
|
classes?: AnySpendAllClasses;
|
|
535
569
|
/** Whether to allow direct transfer without swap */
|
|
536
570
|
allowDirectTransfer?: boolean;
|
|
571
|
+
/** Opaque metadata passed to the order for callbacks (e.g., workflow form data) */
|
|
572
|
+
callbackMetadata?: Record<string, unknown>;
|
|
537
573
|
}
|
|
538
574
|
/**
|
|
539
575
|
* Union type of all possible modal content types
|
|
540
576
|
*/
|
|
541
|
-
export type ModalContentType = SignInWithB3ModalProps | RequestPermissionsModalProps | ManageAccountModalProps | AnySpendModalProps | AnyspendOrderDetailsProps | AnySpendNftProps | AnySpendJoinTournamentProps | AnySpendFundTournamentProps | AnySpendOrderHistoryProps | AnySpendStakeB3Props | AnySpendStakeB3ExactInProps | AnySpendStakeUpsideProps | AnySpendStakeUpsideExactInProps | AnySpendDepositUpsideProps | AnySpendBuySpinProps | AnySpendSignatureMintProps | AnySpendBondKitProps | LinkAccountModalProps | LinkNewAccountModalProps | AnySpendDepositHypeProps | AvatarEditorModalProps | DepositModalProps | SendModalProps | NotificationsModalProps | AnySpendCollectorClubPurchaseProps | AnySpendDepositModalProps;
|
|
577
|
+
export type ModalContentType = SignInWithB3ModalProps | RequestPermissionsModalProps | ManageAccountModalProps | AnySpendModalProps | AnyspendOrderDetailsProps | AnySpendNftProps | AnySpendJoinTournamentProps | AnySpendFundTournamentProps | AnySpendOrderHistoryProps | AnySpendStakeB3Props | AnySpendStakeB3ExactInProps | AnySpendStakeUpsideProps | AnySpendStakeUpsideExactInProps | AnySpendDepositUpsideProps | AnySpendBuySpinProps | AnySpendSignatureMintProps | AnySpendBondKitProps | LinkAccountModalProps | LinkNewAccountModalProps | AnySpendDepositHypeProps | AvatarEditorModalProps | DepositModalProps | SendModalProps | NotificationsModalProps | AnySpendCollectorClubPurchaseProps | AnySpendDepositModalProps | AnySpendWorkflowTriggerModalProps;
|
|
542
578
|
/**
|
|
543
579
|
* State interface for the modal store
|
|
544
580
|
*/
|
|
@@ -53,4 +53,6 @@ export declare function AnySpend(props: {
|
|
|
53
53
|
allowDirectTransfer?: boolean;
|
|
54
54
|
/** Fixed destination token amount (in wei/smallest unit). When provided, user cannot change the amount. */
|
|
55
55
|
destinationTokenAmount?: string;
|
|
56
|
+
/** Opaque metadata passed to the order for callbacks (e.g., workflow form data) */
|
|
57
|
+
callbackMetadata?: Record<string, unknown>;
|
|
56
58
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -18,6 +18,7 @@ import { useAutoSelectCryptoPaymentMethod } from "../hooks/useAutoSelectCryptoPa
|
|
|
18
18
|
import { useConnectedWalletDisplay } from "../hooks/useConnectedWalletDisplay.js";
|
|
19
19
|
import { useCryptoPaymentMethodState } from "../hooks/useCryptoPaymentMethodState.js";
|
|
20
20
|
import { useDirectTransfer } from "../hooks/useDirectTransfer.js";
|
|
21
|
+
import { useOnOrderSuccess } from "../hooks/useOnOrderSuccess.js";
|
|
21
22
|
import { useRecipientAddressState } from "../hooks/useRecipientAddressState.js";
|
|
22
23
|
import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper.js";
|
|
23
24
|
import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod.js";
|
|
@@ -54,7 +55,7 @@ export function AnySpend(props) {
|
|
|
54
55
|
console.log("[mitch] AnySpend rendered with fingerprintConfig:", props, fingerprintConfig);
|
|
55
56
|
return (_jsx(AnySpendFingerprintWrapper, { fingerprint: fingerprintConfig, children: _jsx(AnySpendInner, { ...props }) }));
|
|
56
57
|
}
|
|
57
|
-
function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationTokenChainId, mode = "modal", defaultActiveTab = "crypto", loadOrder, hideTransactionHistoryButton, recipientAddress: recipientAddressFromProps, onTokenSelect, onSuccess, customUsdInputValues, hideHeader, hideBottomNavigation = false, disableUrlParamManagement = false, returnToHomeUrl, customRecipientLabel, returnHomeLabel, classes, allowDirectTransfer = false, destinationTokenAmount, }) {
|
|
58
|
+
function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationTokenChainId, mode = "modal", defaultActiveTab = "crypto", loadOrder, hideTransactionHistoryButton, recipientAddress: recipientAddressFromProps, onTokenSelect, onSuccess, customUsdInputValues, hideHeader, hideBottomNavigation = false, disableUrlParamManagement = false, returnToHomeUrl, customRecipientLabel, returnHomeLabel, classes, allowDirectTransfer = false, destinationTokenAmount, callbackMetadata, }) {
|
|
58
59
|
const searchParams = useSearchParamsSSR();
|
|
59
60
|
const router = useRouter();
|
|
60
61
|
const { partnerId } = useB3Config();
|
|
@@ -65,8 +66,6 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
65
66
|
// Add refs to track URL state
|
|
66
67
|
const initialUrlProcessed = useRef(false);
|
|
67
68
|
const lastUrlUpdate = useRef(null);
|
|
68
|
-
// Track if onSuccess has been called for the current order
|
|
69
|
-
const onSuccessCalled = useRef(false);
|
|
70
69
|
// Track animation direction for TransitionPanel
|
|
71
70
|
const animationDirection = useRef(null);
|
|
72
71
|
// Track previous panel for proper back navigation
|
|
@@ -486,18 +485,8 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
486
485
|
}
|
|
487
486
|
}
|
|
488
487
|
}, [anyspendQuote, isSrcInputDirty, destinationTokenAmount]);
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
console.log("Calling onSuccess");
|
|
492
|
-
const txHash = oat?.data?.executeTx?.txHash;
|
|
493
|
-
onSuccess?.(txHash);
|
|
494
|
-
onSuccessCalled.current = true;
|
|
495
|
-
}
|
|
496
|
-
}, [oat?.data?.order.status, oat?.data?.executeTx?.txHash, onSuccess]);
|
|
497
|
-
// Reset flag when orderId changes
|
|
498
|
-
useEffect(() => {
|
|
499
|
-
onSuccessCalled.current = false;
|
|
500
|
-
}, [orderId]);
|
|
488
|
+
// Call onSuccess when order is executed
|
|
489
|
+
useOnOrderSuccess({ orderData: oat, orderId, onSuccess });
|
|
501
490
|
const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
|
|
502
491
|
onSuccess: data => {
|
|
503
492
|
const orderId = data.data.id;
|
|
@@ -724,6 +713,7 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
724
713
|
srcAmount: srcAmountBigInt.toString(),
|
|
725
714
|
expectedDstAmount: anyspendQuote?.data?.currencyOut?.amount || "0",
|
|
726
715
|
creatorAddress: globalAddress,
|
|
716
|
+
callbackMetadata,
|
|
727
717
|
});
|
|
728
718
|
}
|
|
729
719
|
catch (err) {
|
|
@@ -798,6 +788,7 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
798
788
|
},
|
|
799
789
|
expectedDstAmount: anyspendQuote?.data?.currencyOut?.amount?.toString() || "0",
|
|
800
790
|
creatorAddress: globalAddress,
|
|
791
|
+
callbackMetadata,
|
|
801
792
|
});
|
|
802
793
|
}
|
|
803
794
|
catch (err) {
|
|
@@ -884,7 +875,7 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
884
875
|
// Reset payment methods when switching tabs
|
|
885
876
|
resetPaymentMethods();
|
|
886
877
|
setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE);
|
|
887
|
-
}, setSelectedCryptoPaymentMethod: setSelectedCryptoPaymentMethod, setSelectedFiatPaymentMethod: setSelectedFiatPaymentMethod }), _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [activeTab === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward"), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect, onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward")
|
|
878
|
+
}, setSelectedCryptoPaymentMethod: setSelectedCryptoPaymentMethod, setSelectedFiatPaymentMethod: setSelectedFiatPaymentMethod }), _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [activeTab === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward"), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect, onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward") })) : (_jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: _jsx(PanelOnramp, { srcAmountOnRamp: srcAmountOnRamp, setSrcAmountOnRamp: setSrcAmountOnRamp, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: (panelIndex) => {
|
|
888
879
|
// Map panel index to navigation with direction
|
|
889
880
|
const panelsWithForwardNav = [PanelView.FIAT_PAYMENT_METHOD, PanelView.RECIPIENT_SELECTION];
|
|
890
881
|
if (panelsWithForwardNav.includes(panelIndex)) {
|
|
@@ -69,5 +69,10 @@ export interface AnySpendCollectorClubPurchaseProps {
|
|
|
69
69
|
* Force fiat payment
|
|
70
70
|
*/
|
|
71
71
|
forceFiatPayment?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Optional discount code to apply to the purchase.
|
|
74
|
+
* When provided, validates on-chain and adjusts the price accordingly.
|
|
75
|
+
*/
|
|
76
|
+
discountCode?: string;
|
|
72
77
|
}
|
|
73
|
-
export declare function AnySpendCollectorClubPurchase({ loadOrder, mode, activeTab, packId, packAmount, pricePerPack, paymentToken, recipientAddress, spenderAddress, isStaging, onSuccess, header, showRecipient, vendingMachineId, packType, forceFiatPayment, }: AnySpendCollectorClubPurchaseProps): import("react/jsx-runtime").JSX.Element;
|
|
78
|
+
export declare function AnySpendCollectorClubPurchase({ loadOrder, mode, activeTab, packId, packAmount, pricePerPack, paymentToken, recipientAddress, spenderAddress, isStaging, onSuccess, header, showRecipient, vendingMachineId, packType, forceFiatPayment, discountCode, }: AnySpendCollectorClubPurchaseProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -26,27 +26,22 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
import { USDC_BASE } from "../../../anyspend/constants/index.js";
|
|
29
|
+
import { PUBLIC_BASE_RPC_URL } from "../../../shared/constants/index.js";
|
|
29
30
|
import { formatUnits } from "../../../shared/utils/number.js";
|
|
30
|
-
import { useMemo } from "react";
|
|
31
|
-
import { encodeFunctionData } from "viem";
|
|
31
|
+
import { useEffect, useMemo, useState } from "react";
|
|
32
|
+
import { createPublicClient, encodeFunctionData, http } from "viem";
|
|
33
|
+
import { base } from "viem/chains";
|
|
32
34
|
import { AnySpendCustom } from "./AnySpendCustom.js";
|
|
35
|
+
import { BUY_PACKS_FOR_ABI, BUY_PACKS_FOR_WITH_DISCOUNT_ABI, GET_DISCOUNT_CODE_ABI, IS_DISCOUNT_CODE_VALID_FOR_PACK_ABI, } from "./ccShopAbi.js";
|
|
33
36
|
// Collector Club Shop contract addresses on Base
|
|
34
37
|
const CC_SHOP_ADDRESS = "0x47366E64E4917dd4DdC04Fb9DC507c1dD2b87294";
|
|
35
38
|
const CC_SHOP_ADDRESS_STAGING = "0x8b751143342ac41eB965E55430e3F7Adf6BE01fA";
|
|
36
39
|
const BASE_CHAIN_ID = 8453;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{ internalType: "uint256", name: "amount", type: "uint256" },
|
|
43
|
-
],
|
|
44
|
-
name: "buyPacksFor",
|
|
45
|
-
outputs: [],
|
|
46
|
-
stateMutability: "nonpayable",
|
|
47
|
-
type: "function",
|
|
48
|
-
};
|
|
49
|
-
export function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activeTab = "crypto", packId, packAmount, pricePerPack, paymentToken = USDC_BASE, recipientAddress, spenderAddress, isStaging = false, onSuccess, header, showRecipient = true, vendingMachineId, packType, forceFiatPayment, }) {
|
|
40
|
+
const basePublicClient = createPublicClient({
|
|
41
|
+
chain: base,
|
|
42
|
+
transport: http(PUBLIC_BASE_RPC_URL),
|
|
43
|
+
});
|
|
44
|
+
export function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activeTab = "crypto", packId, packAmount, pricePerPack, paymentToken = USDC_BASE, recipientAddress, spenderAddress, isStaging = false, onSuccess, header, showRecipient = true, vendingMachineId, packType, forceFiatPayment, discountCode, }) {
|
|
50
45
|
const ccShopAddress = isStaging ? CC_SHOP_ADDRESS_STAGING : CC_SHOP_ADDRESS;
|
|
51
46
|
// Calculate total amount needed (pricePerPack * packAmount)
|
|
52
47
|
const totalAmount = useMemo(() => {
|
|
@@ -58,15 +53,130 @@ export function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activ
|
|
|
58
53
|
return "0";
|
|
59
54
|
}
|
|
60
55
|
}, [pricePerPack, packAmount]);
|
|
61
|
-
//
|
|
56
|
+
// Discount code validation state
|
|
57
|
+
const [discountInfo, setDiscountInfo] = useState({
|
|
58
|
+
isValid: false,
|
|
59
|
+
discountAmount: BigInt(0),
|
|
60
|
+
minPurchaseAmount: BigInt(0),
|
|
61
|
+
isLoading: false,
|
|
62
|
+
error: null,
|
|
63
|
+
});
|
|
64
|
+
// Validate discount code on-chain when provided
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!discountCode) {
|
|
67
|
+
setDiscountInfo({
|
|
68
|
+
isValid: false,
|
|
69
|
+
discountAmount: BigInt(0),
|
|
70
|
+
minPurchaseAmount: BigInt(0),
|
|
71
|
+
isLoading: false,
|
|
72
|
+
error: null,
|
|
73
|
+
});
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let cancelled = false;
|
|
77
|
+
const validateDiscount = async () => {
|
|
78
|
+
setDiscountInfo(prev => ({ ...prev, isLoading: true, error: null }));
|
|
79
|
+
try {
|
|
80
|
+
// Validate against specific pack and fetch full details in parallel
|
|
81
|
+
const [validForPack, codeDetails] = await Promise.all([
|
|
82
|
+
basePublicClient.readContract({
|
|
83
|
+
address: ccShopAddress,
|
|
84
|
+
abi: [IS_DISCOUNT_CODE_VALID_FOR_PACK_ABI],
|
|
85
|
+
functionName: "isDiscountCodeValidForPack",
|
|
86
|
+
args: [discountCode, BigInt(packId)],
|
|
87
|
+
}),
|
|
88
|
+
basePublicClient.readContract({
|
|
89
|
+
address: ccShopAddress,
|
|
90
|
+
abi: [GET_DISCOUNT_CODE_ABI],
|
|
91
|
+
functionName: "getDiscountCode",
|
|
92
|
+
args: [discountCode],
|
|
93
|
+
}),
|
|
94
|
+
]);
|
|
95
|
+
if (cancelled)
|
|
96
|
+
return;
|
|
97
|
+
const [isValid, discountAmount] = validForPack;
|
|
98
|
+
const { minPurchaseAmount, packId: restrictedPackId, exists } = codeDetails;
|
|
99
|
+
if (!exists) {
|
|
100
|
+
setDiscountInfo({
|
|
101
|
+
isValid: false,
|
|
102
|
+
discountAmount: BigInt(0),
|
|
103
|
+
minPurchaseAmount: BigInt(0),
|
|
104
|
+
isLoading: false,
|
|
105
|
+
error: "Discount code does not exist",
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (!isValid) {
|
|
110
|
+
// Provide specific error based on code details
|
|
111
|
+
if (restrictedPackId !== BigInt(0) && restrictedPackId !== BigInt(packId)) {
|
|
112
|
+
setDiscountInfo({
|
|
113
|
+
isValid: false,
|
|
114
|
+
discountAmount: BigInt(0),
|
|
115
|
+
minPurchaseAmount: BigInt(0),
|
|
116
|
+
isLoading: false,
|
|
117
|
+
error: "Discount code is not valid for this pack",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
setDiscountInfo({
|
|
122
|
+
isValid: false,
|
|
123
|
+
discountAmount: BigInt(0),
|
|
124
|
+
minPurchaseAmount: BigInt(0),
|
|
125
|
+
isLoading: false,
|
|
126
|
+
error: "Invalid or expired discount code",
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
setDiscountInfo({ isValid: true, discountAmount, minPurchaseAmount, isLoading: false, error: null });
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (cancelled)
|
|
135
|
+
return;
|
|
136
|
+
console.error("Failed to validate discount code", { discountCode, error });
|
|
137
|
+
setDiscountInfo({
|
|
138
|
+
isValid: false,
|
|
139
|
+
discountAmount: BigInt(0),
|
|
140
|
+
minPurchaseAmount: BigInt(0),
|
|
141
|
+
isLoading: false,
|
|
142
|
+
error: "Failed to validate discount code",
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
validateDiscount();
|
|
147
|
+
return () => {
|
|
148
|
+
cancelled = true;
|
|
149
|
+
};
|
|
150
|
+
}, [discountCode, ccShopAddress, packId]);
|
|
151
|
+
// Calculate effective dstAmount after discount
|
|
152
|
+
const effectiveDstAmount = useMemo(() => {
|
|
153
|
+
if (!discountCode || !discountInfo.isValid || discountInfo.discountAmount === BigInt(0)) {
|
|
154
|
+
return totalAmount;
|
|
155
|
+
}
|
|
156
|
+
const total = BigInt(totalAmount);
|
|
157
|
+
const discount = discountInfo.discountAmount;
|
|
158
|
+
if (discount >= total) {
|
|
159
|
+
console.error("Discount exceeds total price", { totalAmount, discountAmount: discount.toString() });
|
|
160
|
+
return "0";
|
|
161
|
+
}
|
|
162
|
+
return (total - discount).toString();
|
|
163
|
+
}, [totalAmount, discountCode, discountInfo.isValid, discountInfo.discountAmount]);
|
|
164
|
+
// Calculate fiat amount (effectiveDstAmount in USD, assuming USDC with 6 decimals)
|
|
62
165
|
const srcFiatAmount = useMemo(() => {
|
|
63
|
-
if (!
|
|
166
|
+
if (!effectiveDstAmount || effectiveDstAmount === "0")
|
|
64
167
|
return "0";
|
|
65
|
-
return formatUnits(
|
|
66
|
-
}, [
|
|
67
|
-
// Encode the
|
|
168
|
+
return formatUnits(effectiveDstAmount, USDC_BASE.decimals);
|
|
169
|
+
}, [effectiveDstAmount]);
|
|
170
|
+
// Encode the contract function call (with or without discount)
|
|
68
171
|
const encodedData = useMemo(() => {
|
|
69
172
|
try {
|
|
173
|
+
if (discountCode && discountInfo.isValid) {
|
|
174
|
+
return encodeFunctionData({
|
|
175
|
+
abi: [BUY_PACKS_FOR_WITH_DISCOUNT_ABI],
|
|
176
|
+
functionName: "buyPacksForWithDiscount",
|
|
177
|
+
args: [recipientAddress, BigInt(packId), BigInt(packAmount), discountCode],
|
|
178
|
+
});
|
|
179
|
+
}
|
|
70
180
|
return encodeFunctionData({
|
|
71
181
|
abi: [BUY_PACKS_FOR_ABI],
|
|
72
182
|
functionName: "buyPacksFor",
|
|
@@ -74,17 +184,36 @@ export function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activ
|
|
|
74
184
|
});
|
|
75
185
|
}
|
|
76
186
|
catch (error) {
|
|
77
|
-
console.error("Failed to encode function data", { recipientAddress, packId, packAmount, error });
|
|
187
|
+
console.error("Failed to encode function data", { recipientAddress, packId, packAmount, discountCode, error });
|
|
78
188
|
return "0x";
|
|
79
189
|
}
|
|
80
|
-
}, [recipientAddress, packId, packAmount]);
|
|
190
|
+
}, [recipientAddress, packId, packAmount, discountCode, discountInfo.isValid]);
|
|
81
191
|
// Default header if not provided
|
|
82
192
|
const defaultHeader = () => (_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: "Buy Collector Club Packs" }), _jsxs("p", { className: "text-as-secondary text-sm", children: ["Purchase ", packAmount, " pack", packAmount !== 1 ? "s" : "", " using any token"] })] }) }));
|
|
83
|
-
|
|
193
|
+
// Don't render AnySpendCustom while discount is being validated (avoids showing wrong price)
|
|
194
|
+
if (discountCode && discountInfo.isLoading) {
|
|
195
|
+
return (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsx("p", { className: "text-as-secondary text-sm", children: "Validating discount code..." }) }));
|
|
196
|
+
}
|
|
197
|
+
if (discountCode && discountInfo.error) {
|
|
198
|
+
return (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsx("p", { className: "text-sm text-red-500", children: discountInfo.error }) }));
|
|
199
|
+
}
|
|
200
|
+
if (discountCode &&
|
|
201
|
+
discountInfo.isValid &&
|
|
202
|
+
discountInfo.minPurchaseAmount > BigInt(0) &&
|
|
203
|
+
BigInt(packAmount) < discountInfo.minPurchaseAmount) {
|
|
204
|
+
return (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsxs("p", { className: "text-sm text-red-500", children: ["Minimum purchase of ", discountInfo.minPurchaseAmount.toString(), " pack", discountInfo.minPurchaseAmount > BigInt(1) ? "s" : "", " required for this discount code"] }) }));
|
|
205
|
+
}
|
|
206
|
+
if (discountCode && discountInfo.isValid && effectiveDstAmount === "0") {
|
|
207
|
+
return (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsx("p", { className: "text-sm text-red-500", children: "Discount exceeds total price" }) }));
|
|
208
|
+
}
|
|
209
|
+
return (_jsx(AnySpendCustom, { loadOrder: loadOrder, mode: mode, activeTab: activeTab, recipientAddress: recipientAddress, spenderAddress: spenderAddress ?? ccShopAddress, orderType: "custom", dstChainId: BASE_CHAIN_ID, dstToken: paymentToken, dstAmount: effectiveDstAmount, contractAddress: ccShopAddress, encodedData: encodedData, metadata: {
|
|
84
210
|
packId,
|
|
85
211
|
packAmount,
|
|
86
212
|
pricePerPack,
|
|
87
213
|
vendingMachineId,
|
|
88
214
|
packType,
|
|
215
|
+
...(discountCode && discountInfo.isValid
|
|
216
|
+
? { discountCode, discountAmount: discountInfo.discountAmount.toString() }
|
|
217
|
+
: {}),
|
|
89
218
|
}, header: header || defaultHeader, onSuccess: onSuccess, showRecipient: showRecipient, srcFiatAmount: srcFiatAmount, forceFiatPayment: forceFiatPayment }));
|
|
90
219
|
}
|