@b3dotfun/sdk 0.0.31-alpha.0 → 0.0.31-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/AnyspendDepositHype.js +2 -2
- package/dist/cjs/anyspend/react/components/common/OrderDetails.d.ts +1 -0
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +7 -3
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +47 -17
- package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +2 -2
- package/dist/esm/anyspend/react/components/common/OrderDetails.d.ts +1 -0
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +7 -3
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +49 -19
- package/dist/types/anyspend/react/components/common/OrderDetails.d.ts +1 -0
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
- package/package.json +1 -1
- package/src/anyspend/react/components/AnyspendDepositHype.tsx +2 -1
- package/src/anyspend/react/components/common/OrderDetails.tsx +6 -2
- package/src/anyspend/react/hooks/useAnyspendFlow.ts +53 -16
|
@@ -57,6 +57,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
|
|
|
57
57
|
sourceTokenAddress,
|
|
58
58
|
sourceTokenChainId,
|
|
59
59
|
slippage: SLIPPAGE_PERCENT,
|
|
60
|
+
disableUrlParamManagement: true,
|
|
60
61
|
});
|
|
61
62
|
// Button state logic
|
|
62
63
|
const btnInfo = (0, react_3.useMemo)(() => {
|
|
@@ -233,8 +234,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
|
|
|
233
234
|
const orderDetailsView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto w-[460px] max-w-full", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex flex-col gap-4", children: oat && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(OrderStatus_1.OrderStatus, { order: oat.data.order, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod }), (0, jsx_runtime_1.jsx)(OrderDetails_1.OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTx: oat.data.relayTx, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: paymentType === "fiat" ? CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE : selectedCryptoPaymentMethod, onBack: () => {
|
|
234
235
|
setOrderId(undefined);
|
|
235
236
|
setActivePanel(useAnyspendFlow_1.PanelView.MAIN);
|
|
236
|
-
|
|
237
|
-
} })] })) }) }));
|
|
237
|
+
}, disableUrlParamManagement: true })] })) }) }));
|
|
238
238
|
// Loading view
|
|
239
239
|
const loadingView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto flex w-full flex-col items-center gap-4 p-5", children: (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary", children: "Loading order details..." }) }));
|
|
240
240
|
// Panel views
|
|
@@ -9,6 +9,7 @@ interface OrderDetailsProps {
|
|
|
9
9
|
refundTxs: components["schemas"]["RefundTx"][] | null;
|
|
10
10
|
cryptoPaymentMethod?: CryptoPaymentMethodType;
|
|
11
11
|
onBack?: () => void;
|
|
12
|
+
disableUrlParamManagement?: boolean;
|
|
12
13
|
}
|
|
13
14
|
export declare const OrderDetails: import("react").NamedExoticComponent<OrderDetailsProps>;
|
|
14
15
|
export declare const OrderDetailsLoadingView: import("react/jsx-runtime").JSX.Element;
|
|
@@ -130,7 +130,7 @@ function roundTokenAmount(amount) {
|
|
|
130
130
|
const roundedDecimalPart = digits.join("");
|
|
131
131
|
return `${wholePart}.${roundedDecimalPart}`;
|
|
132
132
|
}
|
|
133
|
-
exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal", order, depositTxs, relayTx, executeTx, refundTxs, cryptoPaymentMethod, onBack, }) {
|
|
133
|
+
exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal", order, depositTxs, relayTx, executeTx, refundTxs, cryptoPaymentMethod, onBack, disableUrlParamManagement = false, }) {
|
|
134
134
|
const router = (0, hooks_1.useRouter)();
|
|
135
135
|
const searchParams = (0, hooks_1.useSearchParams)();
|
|
136
136
|
// Read crypto payment method from URL parameters
|
|
@@ -196,12 +196,16 @@ exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal",
|
|
|
196
196
|
};
|
|
197
197
|
// When waitingForDeposit is true, we show a message to the user to wait for the deposit to be processed.
|
|
198
198
|
const setWaitingForDeposit = (0, react_5.useCallback)(() => {
|
|
199
|
+
if (disableUrlParamManagement)
|
|
200
|
+
return;
|
|
199
201
|
const params = new URLSearchParams(searchParams.toString());
|
|
200
202
|
params.set("waitingForDeposit", "true");
|
|
201
203
|
router.push(`?${params}`);
|
|
202
|
-
}, [router, searchParams]);
|
|
204
|
+
}, [router, searchParams, disableUrlParamManagement]);
|
|
203
205
|
// Clean up URL parameters before closing modal or navigating back
|
|
204
206
|
const cleanupUrlParams = (0, react_5.useCallback)(() => {
|
|
207
|
+
if (disableUrlParamManagement)
|
|
208
|
+
return;
|
|
205
209
|
const params = new URLSearchParams(searchParams.toString());
|
|
206
210
|
params.delete("waitingForDeposit");
|
|
207
211
|
params.delete("orderId");
|
|
@@ -210,7 +214,7 @@ exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal",
|
|
|
210
214
|
if (params.toString() !== searchParams.toString()) {
|
|
211
215
|
router.push(`?${params}`);
|
|
212
216
|
}
|
|
213
|
-
}, [router, searchParams]);
|
|
217
|
+
}, [router, searchParams, disableUrlParamManagement]);
|
|
214
218
|
// Helper functions that clean up URL params before executing actions
|
|
215
219
|
const handleCloseModal = (0, react_5.useCallback)(() => {
|
|
216
220
|
cleanupUrlParams();
|
|
@@ -19,8 +19,9 @@ interface UseAnyspendFlowProps {
|
|
|
19
19
|
sourceTokenAddress?: string;
|
|
20
20
|
sourceTokenChainId?: number;
|
|
21
21
|
slippage?: number;
|
|
22
|
+
disableUrlParamManagement?: boolean;
|
|
22
23
|
}
|
|
23
|
-
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, }: UseAnyspendFlowProps): {
|
|
24
|
+
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, disableUrlParamManagement, }: UseAnyspendFlowProps): {
|
|
24
25
|
activePanel: PanelView;
|
|
25
26
|
setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
|
|
26
27
|
orderId: string | undefined;
|
|
@@ -75,6 +76,8 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
75
76
|
setSelectedRecipientAddress: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
76
77
|
recipientName: string | null | undefined;
|
|
77
78
|
globalAddress: string | undefined;
|
|
79
|
+
hasEnoughBalance: boolean;
|
|
80
|
+
isBalanceLoading: boolean;
|
|
78
81
|
anyspendQuote: {
|
|
79
82
|
success: boolean;
|
|
80
83
|
message: string;
|
|
@@ -11,6 +11,7 @@ const react_3 = require("react");
|
|
|
11
11
|
const sonner_1 = require("sonner");
|
|
12
12
|
const viem_1 = require("viem");
|
|
13
13
|
const chains_1 = require("viem/chains");
|
|
14
|
+
const wagmi_1 = require("wagmi");
|
|
14
15
|
const CryptoPaymentMethod_1 = require("../components/common/CryptoPaymentMethod");
|
|
15
16
|
const FiatPaymentMethod_1 = require("../components/common/FiatPaymentMethod");
|
|
16
17
|
var PanelView;
|
|
@@ -22,7 +23,7 @@ var PanelView;
|
|
|
22
23
|
PanelView[PanelView["ORDER_DETAILS"] = 4] = "ORDER_DETAILS";
|
|
23
24
|
PanelView[PanelView["LOADING"] = 5] = "LOADING";
|
|
24
25
|
})(PanelView || (exports.PanelView = PanelView = {}));
|
|
25
|
-
function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, }) {
|
|
26
|
+
function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, disableUrlParamManagement = false, }) {
|
|
26
27
|
const searchParams = (0, react_2.useSearchParamsSSR)();
|
|
27
28
|
const router = (0, react_2.useRouter)();
|
|
28
29
|
// Panel and order state
|
|
@@ -42,6 +43,7 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
42
43
|
const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = (0, react_3.useState)(FiatPaymentMethod_1.FiatPaymentMethod.NONE);
|
|
43
44
|
// Recipient state
|
|
44
45
|
const { address: globalAddress } = (0, react_2.useAccountWallet)();
|
|
46
|
+
const { address: wagmiAddress } = (0, wagmi_1.useAccount)();
|
|
45
47
|
const [selectedRecipientAddress, setSelectedRecipientAddress] = (0, react_3.useState)(recipientAddress);
|
|
46
48
|
const recipientProfile = (0, react_2.useProfile)({ address: selectedRecipientAddress, fresh: true });
|
|
47
49
|
const recipientName = recipientProfile.data?.name;
|
|
@@ -51,11 +53,34 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
51
53
|
setSelectedRecipientAddress(globalAddress);
|
|
52
54
|
}
|
|
53
55
|
}, [selectedRecipientAddress, globalAddress]);
|
|
56
|
+
// Check token balance for crypto payments
|
|
57
|
+
const { rawBalance, isLoading: isBalanceLoading } = (0, react_2.useTokenBalance)({
|
|
58
|
+
token: selectedSrcToken,
|
|
59
|
+
address: wagmiAddress,
|
|
60
|
+
});
|
|
61
|
+
// Check if user has enough balance
|
|
62
|
+
const hasEnoughBalance = (0, react_3.useMemo)(() => {
|
|
63
|
+
if (!rawBalance || isBalanceLoading || paymentType !== "crypto")
|
|
64
|
+
return false;
|
|
65
|
+
try {
|
|
66
|
+
const requiredAmount = (0, viem_1.parseUnits)(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
|
|
67
|
+
return rawBalance >= requiredAmount;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}, [rawBalance, srcAmount, selectedSrcToken.decimals, isBalanceLoading, paymentType]);
|
|
73
|
+
// Auto-set crypto payment method based on balance
|
|
54
74
|
(0, react_3.useEffect)(() => {
|
|
55
|
-
if (paymentType === "crypto") {
|
|
56
|
-
|
|
75
|
+
if (paymentType === "crypto" && !isBalanceLoading) {
|
|
76
|
+
if (hasEnoughBalance) {
|
|
77
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.CONNECT_WALLET);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.TRANSFER_CRYPTO);
|
|
81
|
+
}
|
|
57
82
|
}
|
|
58
|
-
}, [paymentType]);
|
|
83
|
+
}, [paymentType, hasEnoughBalance, isBalanceLoading]);
|
|
59
84
|
// Fetch specific token when sourceTokenAddress and sourceTokenChainId are provided
|
|
60
85
|
(0, react_3.useEffect)(() => {
|
|
61
86
|
const fetchSourceToken = async () => {
|
|
@@ -114,14 +139,14 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
114
139
|
}, [anyspendQuote, slippage]);
|
|
115
140
|
// Update useEffect for URL parameter to not override loadOrder
|
|
116
141
|
(0, react_3.useEffect)(() => {
|
|
117
|
-
if (loadOrder)
|
|
118
|
-
return; // Skip if we have a loadOrder
|
|
142
|
+
if (loadOrder || disableUrlParamManagement)
|
|
143
|
+
return; // Skip if we have a loadOrder or URL param management is disabled
|
|
119
144
|
const orderIdParam = searchParams.get("orderId");
|
|
120
145
|
if (orderIdParam) {
|
|
121
146
|
setOrderId(orderIdParam);
|
|
122
147
|
setActivePanel(PanelView.ORDER_DETAILS);
|
|
123
148
|
}
|
|
124
|
-
}, [searchParams, loadOrder]);
|
|
149
|
+
}, [searchParams, loadOrder, disableUrlParamManagement]);
|
|
125
150
|
// Order creation hooks
|
|
126
151
|
const { createOrder, isCreatingOrder } = (0, react_1.useAnyspendCreateOrder)({
|
|
127
152
|
onSuccess: data => {
|
|
@@ -130,17 +155,19 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
130
155
|
setActivePanel(PanelView.ORDER_DETAILS);
|
|
131
156
|
onOrderSuccess?.(newOrderId);
|
|
132
157
|
// Add orderId and payment method to URL for persistence
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
158
|
+
if (!disableUrlParamManagement) {
|
|
159
|
+
const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
|
|
160
|
+
params.set("orderId", newOrderId);
|
|
161
|
+
if (selectedCryptoPaymentMethod !== CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE) {
|
|
162
|
+
console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
|
|
163
|
+
params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.log("Payment method is NONE, not setting in URL");
|
|
167
|
+
}
|
|
168
|
+
console.log("Final URL params:", params.toString());
|
|
169
|
+
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
141
170
|
}
|
|
142
|
-
console.log("Final URL params:", params.toString());
|
|
143
|
-
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
144
171
|
},
|
|
145
172
|
onError: error => {
|
|
146
173
|
console.error(error);
|
|
@@ -196,6 +223,9 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
|
|
|
196
223
|
setSelectedRecipientAddress,
|
|
197
224
|
recipientName,
|
|
198
225
|
globalAddress,
|
|
226
|
+
// Balance check
|
|
227
|
+
hasEnoughBalance,
|
|
228
|
+
isBalanceLoading,
|
|
199
229
|
// Quote data
|
|
200
230
|
anyspendQuote,
|
|
201
231
|
isLoadingAnyspendQuote,
|
|
@@ -50,6 +50,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
|
|
|
50
50
|
sourceTokenAddress,
|
|
51
51
|
sourceTokenChainId,
|
|
52
52
|
slippage: SLIPPAGE_PERCENT,
|
|
53
|
+
disableUrlParamManagement: true,
|
|
53
54
|
});
|
|
54
55
|
// Button state logic
|
|
55
56
|
const btnInfo = useMemo(() => {
|
|
@@ -226,8 +227,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
|
|
|
226
227
|
const orderDetailsView = (_jsx("div", { className: "mx-auto w-[460px] max-w-full", children: _jsx("div", { className: "relative flex flex-col gap-4", children: oat && (_jsxs(_Fragment, { children: [_jsx(OrderStatus, { order: oat.data.order, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod }), _jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTx: oat.data.relayTx, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: paymentType === "fiat" ? CryptoPaymentMethodType.NONE : selectedCryptoPaymentMethod, onBack: () => {
|
|
227
228
|
setOrderId(undefined);
|
|
228
229
|
setActivePanel(PanelView.MAIN);
|
|
229
|
-
|
|
230
|
-
} })] })) }) }));
|
|
230
|
+
}, disableUrlParamManagement: true })] })) }) }));
|
|
231
231
|
// Loading view
|
|
232
232
|
const loadingView = (_jsx("div", { className: "mx-auto flex w-full flex-col items-center gap-4 p-5", children: _jsx("div", { className: "text-as-primary", children: "Loading order details..." }) }));
|
|
233
233
|
// Panel views
|
|
@@ -9,6 +9,7 @@ interface OrderDetailsProps {
|
|
|
9
9
|
refundTxs: components["schemas"]["RefundTx"][] | null;
|
|
10
10
|
cryptoPaymentMethod?: CryptoPaymentMethodType;
|
|
11
11
|
onBack?: () => void;
|
|
12
|
+
disableUrlParamManagement?: boolean;
|
|
12
13
|
}
|
|
13
14
|
export declare const OrderDetails: import("react").NamedExoticComponent<OrderDetailsProps>;
|
|
14
15
|
export declare const OrderDetailsLoadingView: import("react/jsx-runtime").JSX.Element;
|
|
@@ -124,7 +124,7 @@ function roundTokenAmount(amount) {
|
|
|
124
124
|
const roundedDecimalPart = digits.join("");
|
|
125
125
|
return `${wholePart}.${roundedDecimalPart}`;
|
|
126
126
|
}
|
|
127
|
-
export const OrderDetails = memo(function OrderDetails({ mode = "modal", order, depositTxs, relayTx, executeTx, refundTxs, cryptoPaymentMethod, onBack, }) {
|
|
127
|
+
export const OrderDetails = memo(function OrderDetails({ mode = "modal", order, depositTxs, relayTx, executeTx, refundTxs, cryptoPaymentMethod, onBack, disableUrlParamManagement = false, }) {
|
|
128
128
|
const router = useRouter();
|
|
129
129
|
const searchParams = useSearchParams();
|
|
130
130
|
// Read crypto payment method from URL parameters
|
|
@@ -190,12 +190,16 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
|
|
|
190
190
|
};
|
|
191
191
|
// When waitingForDeposit is true, we show a message to the user to wait for the deposit to be processed.
|
|
192
192
|
const setWaitingForDeposit = useCallback(() => {
|
|
193
|
+
if (disableUrlParamManagement)
|
|
194
|
+
return;
|
|
193
195
|
const params = new URLSearchParams(searchParams.toString());
|
|
194
196
|
params.set("waitingForDeposit", "true");
|
|
195
197
|
router.push(`?${params}`);
|
|
196
|
-
}, [router, searchParams]);
|
|
198
|
+
}, [router, searchParams, disableUrlParamManagement]);
|
|
197
199
|
// Clean up URL parameters before closing modal or navigating back
|
|
198
200
|
const cleanupUrlParams = useCallback(() => {
|
|
201
|
+
if (disableUrlParamManagement)
|
|
202
|
+
return;
|
|
199
203
|
const params = new URLSearchParams(searchParams.toString());
|
|
200
204
|
params.delete("waitingForDeposit");
|
|
201
205
|
params.delete("orderId");
|
|
@@ -204,7 +208,7 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
|
|
|
204
208
|
if (params.toString() !== searchParams.toString()) {
|
|
205
209
|
router.push(`?${params}`);
|
|
206
210
|
}
|
|
207
|
-
}, [router, searchParams]);
|
|
211
|
+
}, [router, searchParams, disableUrlParamManagement]);
|
|
208
212
|
// Helper functions that clean up URL params before executing actions
|
|
209
213
|
const handleCloseModal = useCallback(() => {
|
|
210
214
|
cleanupUrlParams();
|
|
@@ -19,8 +19,9 @@ interface UseAnyspendFlowProps {
|
|
|
19
19
|
sourceTokenAddress?: string;
|
|
20
20
|
sourceTokenChainId?: number;
|
|
21
21
|
slippage?: number;
|
|
22
|
+
disableUrlParamManagement?: boolean;
|
|
22
23
|
}
|
|
23
|
-
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, }: UseAnyspendFlowProps): {
|
|
24
|
+
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, disableUrlParamManagement, }: UseAnyspendFlowProps): {
|
|
24
25
|
activePanel: PanelView;
|
|
25
26
|
setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
|
|
26
27
|
orderId: string | undefined;
|
|
@@ -75,6 +76,8 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
75
76
|
setSelectedRecipientAddress: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
76
77
|
recipientName: string | null | undefined;
|
|
77
78
|
globalAddress: string | undefined;
|
|
79
|
+
hasEnoughBalance: boolean;
|
|
80
|
+
isBalanceLoading: boolean;
|
|
78
81
|
anyspendQuote: {
|
|
79
82
|
success: boolean;
|
|
80
83
|
message: string;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { B3_TOKEN, getDefaultToken, USDC_BASE } from "../../../anyspend/index.js";
|
|
2
2
|
import { useAnyspendCreateOnrampOrder, useAnyspendCreateOrder, useAnyspendOrderAndTransactions, useAnyspendQuote, useGeoOnrampOptions, } from "../../../anyspend/react/index.js";
|
|
3
3
|
import { anyspendService } from "../../../anyspend/services/anyspend.js";
|
|
4
|
-
import { useAccountWallet, useProfile, useRouter, useSearchParamsSSR } from "../../../global-account/react/index.js";
|
|
4
|
+
import { useAccountWallet, useProfile, useRouter, useSearchParamsSSR, useTokenBalance, } from "../../../global-account/react/index.js";
|
|
5
5
|
import { formatTokenAmount, formatUnits } from "../../../shared/utils/number.js";
|
|
6
|
-
import { useEffect, useState } from "react";
|
|
6
|
+
import { useEffect, useMemo, useState } from "react";
|
|
7
7
|
import { toast } from "sonner";
|
|
8
8
|
import { parseUnits } from "viem";
|
|
9
9
|
import { base, mainnet } from "viem/chains";
|
|
10
|
+
import { useAccount } from "wagmi";
|
|
10
11
|
import { CryptoPaymentMethodType } from "../components/common/CryptoPaymentMethod.js";
|
|
11
12
|
import { FiatPaymentMethod } from "../components/common/FiatPaymentMethod.js";
|
|
12
13
|
export var PanelView;
|
|
@@ -18,7 +19,7 @@ export var PanelView;
|
|
|
18
19
|
PanelView[PanelView["ORDER_DETAILS"] = 4] = "ORDER_DETAILS";
|
|
19
20
|
PanelView[PanelView["LOADING"] = 5] = "LOADING";
|
|
20
21
|
})(PanelView || (PanelView = {}));
|
|
21
|
-
export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, }) {
|
|
22
|
+
export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, disableUrlParamManagement = false, }) {
|
|
22
23
|
const searchParams = useSearchParamsSSR();
|
|
23
24
|
const router = useRouter();
|
|
24
25
|
// Panel and order state
|
|
@@ -38,6 +39,7 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
38
39
|
const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState(FiatPaymentMethod.NONE);
|
|
39
40
|
// Recipient state
|
|
40
41
|
const { address: globalAddress } = useAccountWallet();
|
|
42
|
+
const { address: wagmiAddress } = useAccount();
|
|
41
43
|
const [selectedRecipientAddress, setSelectedRecipientAddress] = useState(recipientAddress);
|
|
42
44
|
const recipientProfile = useProfile({ address: selectedRecipientAddress, fresh: true });
|
|
43
45
|
const recipientName = recipientProfile.data?.name;
|
|
@@ -47,11 +49,34 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
47
49
|
setSelectedRecipientAddress(globalAddress);
|
|
48
50
|
}
|
|
49
51
|
}, [selectedRecipientAddress, globalAddress]);
|
|
52
|
+
// Check token balance for crypto payments
|
|
53
|
+
const { rawBalance, isLoading: isBalanceLoading } = useTokenBalance({
|
|
54
|
+
token: selectedSrcToken,
|
|
55
|
+
address: wagmiAddress,
|
|
56
|
+
});
|
|
57
|
+
// Check if user has enough balance
|
|
58
|
+
const hasEnoughBalance = useMemo(() => {
|
|
59
|
+
if (!rawBalance || isBalanceLoading || paymentType !== "crypto")
|
|
60
|
+
return false;
|
|
61
|
+
try {
|
|
62
|
+
const requiredAmount = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
|
|
63
|
+
return rawBalance >= requiredAmount;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}, [rawBalance, srcAmount, selectedSrcToken.decimals, isBalanceLoading, paymentType]);
|
|
69
|
+
// Auto-set crypto payment method based on balance
|
|
50
70
|
useEffect(() => {
|
|
51
|
-
if (paymentType === "crypto") {
|
|
52
|
-
|
|
71
|
+
if (paymentType === "crypto" && !isBalanceLoading) {
|
|
72
|
+
if (hasEnoughBalance) {
|
|
73
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
|
|
77
|
+
}
|
|
53
78
|
}
|
|
54
|
-
}, [paymentType]);
|
|
79
|
+
}, [paymentType, hasEnoughBalance, isBalanceLoading]);
|
|
55
80
|
// Fetch specific token when sourceTokenAddress and sourceTokenChainId are provided
|
|
56
81
|
useEffect(() => {
|
|
57
82
|
const fetchSourceToken = async () => {
|
|
@@ -110,14 +135,14 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
110
135
|
}, [anyspendQuote, slippage]);
|
|
111
136
|
// Update useEffect for URL parameter to not override loadOrder
|
|
112
137
|
useEffect(() => {
|
|
113
|
-
if (loadOrder)
|
|
114
|
-
return; // Skip if we have a loadOrder
|
|
138
|
+
if (loadOrder || disableUrlParamManagement)
|
|
139
|
+
return; // Skip if we have a loadOrder or URL param management is disabled
|
|
115
140
|
const orderIdParam = searchParams.get("orderId");
|
|
116
141
|
if (orderIdParam) {
|
|
117
142
|
setOrderId(orderIdParam);
|
|
118
143
|
setActivePanel(PanelView.ORDER_DETAILS);
|
|
119
144
|
}
|
|
120
|
-
}, [searchParams, loadOrder]);
|
|
145
|
+
}, [searchParams, loadOrder, disableUrlParamManagement]);
|
|
121
146
|
// Order creation hooks
|
|
122
147
|
const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
|
|
123
148
|
onSuccess: data => {
|
|
@@ -126,17 +151,19 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
126
151
|
setActivePanel(PanelView.ORDER_DETAILS);
|
|
127
152
|
onOrderSuccess?.(newOrderId);
|
|
128
153
|
// Add orderId and payment method to URL for persistence
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
154
|
+
if (!disableUrlParamManagement) {
|
|
155
|
+
const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
|
|
156
|
+
params.set("orderId", newOrderId);
|
|
157
|
+
if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
|
|
158
|
+
console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
|
|
159
|
+
params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log("Payment method is NONE, not setting in URL");
|
|
163
|
+
}
|
|
164
|
+
console.log("Final URL params:", params.toString());
|
|
165
|
+
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
137
166
|
}
|
|
138
|
-
console.log("Final URL params:", params.toString());
|
|
139
|
-
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
140
167
|
},
|
|
141
168
|
onError: error => {
|
|
142
169
|
console.error(error);
|
|
@@ -192,6 +219,9 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
192
219
|
setSelectedRecipientAddress,
|
|
193
220
|
recipientName,
|
|
194
221
|
globalAddress,
|
|
222
|
+
// Balance check
|
|
223
|
+
hasEnoughBalance,
|
|
224
|
+
isBalanceLoading,
|
|
195
225
|
// Quote data
|
|
196
226
|
anyspendQuote,
|
|
197
227
|
isLoadingAnyspendQuote,
|
|
@@ -9,6 +9,7 @@ interface OrderDetailsProps {
|
|
|
9
9
|
refundTxs: components["schemas"]["RefundTx"][] | null;
|
|
10
10
|
cryptoPaymentMethod?: CryptoPaymentMethodType;
|
|
11
11
|
onBack?: () => void;
|
|
12
|
+
disableUrlParamManagement?: boolean;
|
|
12
13
|
}
|
|
13
14
|
export declare const OrderDetails: import("react").NamedExoticComponent<OrderDetailsProps>;
|
|
14
15
|
export declare const OrderDetailsLoadingView: import("react/jsx-runtime").JSX.Element;
|
|
@@ -19,8 +19,9 @@ interface UseAnyspendFlowProps {
|
|
|
19
19
|
sourceTokenAddress?: string;
|
|
20
20
|
sourceTokenChainId?: number;
|
|
21
21
|
slippage?: number;
|
|
22
|
+
disableUrlParamManagement?: boolean;
|
|
22
23
|
}
|
|
23
|
-
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, }: UseAnyspendFlowProps): {
|
|
24
|
+
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, disableUrlParamManagement, }: UseAnyspendFlowProps): {
|
|
24
25
|
activePanel: PanelView;
|
|
25
26
|
setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
|
|
26
27
|
orderId: string | undefined;
|
|
@@ -75,6 +76,8 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
75
76
|
setSelectedRecipientAddress: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
76
77
|
recipientName: string | null | undefined;
|
|
77
78
|
globalAddress: string | undefined;
|
|
79
|
+
hasEnoughBalance: boolean;
|
|
80
|
+
isBalanceLoading: boolean;
|
|
78
81
|
anyspendQuote: {
|
|
79
82
|
success: boolean;
|
|
80
83
|
message: string;
|
package/package.json
CHANGED
|
@@ -115,6 +115,7 @@ function AnySpendDepositHypeInner({
|
|
|
115
115
|
sourceTokenAddress,
|
|
116
116
|
sourceTokenChainId,
|
|
117
117
|
slippage: SLIPPAGE_PERCENT,
|
|
118
|
+
disableUrlParamManagement: true,
|
|
118
119
|
});
|
|
119
120
|
|
|
120
121
|
// Button state logic
|
|
@@ -434,8 +435,8 @@ function AnySpendDepositHypeInner({
|
|
|
434
435
|
onBack={() => {
|
|
435
436
|
setOrderId(undefined);
|
|
436
437
|
setActivePanel(PanelView.MAIN);
|
|
437
|
-
onSuccess?.();
|
|
438
438
|
}}
|
|
439
|
+
disableUrlParamManagement
|
|
439
440
|
/>
|
|
440
441
|
</>
|
|
441
442
|
)}
|
|
@@ -63,6 +63,7 @@ interface OrderDetailsProps {
|
|
|
63
63
|
refundTxs: components["schemas"]["RefundTx"][] | null;
|
|
64
64
|
cryptoPaymentMethod?: CryptoPaymentMethodType; // Now optional since we read from URL
|
|
65
65
|
onBack?: () => void;
|
|
66
|
+
disableUrlParamManagement?: boolean; // When true, will not modify URL parameters
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
// Add this helper function near the top or just above the component
|
|
@@ -202,6 +203,7 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
202
203
|
refundTxs,
|
|
203
204
|
cryptoPaymentMethod,
|
|
204
205
|
onBack,
|
|
206
|
+
disableUrlParamManagement = false,
|
|
205
207
|
}: OrderDetailsProps) {
|
|
206
208
|
const router = useRouter();
|
|
207
209
|
const searchParams = useSearchParams();
|
|
@@ -284,13 +286,15 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
284
286
|
|
|
285
287
|
// When waitingForDeposit is true, we show a message to the user to wait for the deposit to be processed.
|
|
286
288
|
const setWaitingForDeposit = useCallback(() => {
|
|
289
|
+
if (disableUrlParamManagement) return;
|
|
287
290
|
const params = new URLSearchParams(searchParams.toString());
|
|
288
291
|
params.set("waitingForDeposit", "true");
|
|
289
292
|
router.push(`?${params}`);
|
|
290
|
-
}, [router, searchParams]);
|
|
293
|
+
}, [router, searchParams, disableUrlParamManagement]);
|
|
291
294
|
|
|
292
295
|
// Clean up URL parameters before closing modal or navigating back
|
|
293
296
|
const cleanupUrlParams = useCallback(() => {
|
|
297
|
+
if (disableUrlParamManagement) return;
|
|
294
298
|
const params = new URLSearchParams(searchParams.toString());
|
|
295
299
|
params.delete("waitingForDeposit");
|
|
296
300
|
params.delete("orderId");
|
|
@@ -300,7 +304,7 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
300
304
|
if (params.toString() !== searchParams.toString()) {
|
|
301
305
|
router.push(`?${params}`);
|
|
302
306
|
}
|
|
303
|
-
}, [router, searchParams]);
|
|
307
|
+
}, [router, searchParams, disableUrlParamManagement]);
|
|
304
308
|
|
|
305
309
|
// Helper functions that clean up URL params before executing actions
|
|
306
310
|
const handleCloseModal = useCallback(() => {
|
|
@@ -7,12 +7,19 @@ import {
|
|
|
7
7
|
useGeoOnrampOptions,
|
|
8
8
|
} from "@b3dotfun/sdk/anyspend/react";
|
|
9
9
|
import { anyspendService } from "@b3dotfun/sdk/anyspend/services/anyspend";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
useAccountWallet,
|
|
12
|
+
useProfile,
|
|
13
|
+
useRouter,
|
|
14
|
+
useSearchParamsSSR,
|
|
15
|
+
useTokenBalance,
|
|
16
|
+
} from "@b3dotfun/sdk/global-account/react";
|
|
11
17
|
import { formatTokenAmount, formatUnits } from "@b3dotfun/sdk/shared/utils/number";
|
|
12
|
-
import { useEffect, useState } from "react";
|
|
18
|
+
import { useEffect, useMemo, useState } from "react";
|
|
13
19
|
import { toast } from "sonner";
|
|
14
20
|
import { parseUnits } from "viem";
|
|
15
21
|
import { base, mainnet } from "viem/chains";
|
|
22
|
+
import { useAccount } from "wagmi";
|
|
16
23
|
import { components } from "../../types/api";
|
|
17
24
|
import { CryptoPaymentMethodType } from "../components/common/CryptoPaymentMethod";
|
|
18
25
|
import { FiatPaymentMethod } from "../components/common/FiatPaymentMethod";
|
|
@@ -36,6 +43,7 @@ interface UseAnyspendFlowProps {
|
|
|
36
43
|
sourceTokenAddress?: string;
|
|
37
44
|
sourceTokenChainId?: number;
|
|
38
45
|
slippage?: number;
|
|
46
|
+
disableUrlParamManagement?: boolean;
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
export function useAnyspendFlow({
|
|
@@ -48,6 +56,7 @@ export function useAnyspendFlow({
|
|
|
48
56
|
sourceTokenAddress,
|
|
49
57
|
sourceTokenChainId,
|
|
50
58
|
slippage = 0,
|
|
59
|
+
disableUrlParamManagement = false,
|
|
51
60
|
}: UseAnyspendFlowProps) {
|
|
52
61
|
const searchParams = useSearchParamsSSR();
|
|
53
62
|
const router = useRouter();
|
|
@@ -76,6 +85,7 @@ export function useAnyspendFlow({
|
|
|
76
85
|
|
|
77
86
|
// Recipient state
|
|
78
87
|
const { address: globalAddress } = useAccountWallet();
|
|
88
|
+
const { address: wagmiAddress } = useAccount();
|
|
79
89
|
const [selectedRecipientAddress, setSelectedRecipientAddress] = useState<string | undefined>(recipientAddress);
|
|
80
90
|
const recipientProfile = useProfile({ address: selectedRecipientAddress, fresh: true });
|
|
81
91
|
const recipientName = recipientProfile.data?.name;
|
|
@@ -87,11 +97,33 @@ export function useAnyspendFlow({
|
|
|
87
97
|
}
|
|
88
98
|
}, [selectedRecipientAddress, globalAddress]);
|
|
89
99
|
|
|
100
|
+
// Check token balance for crypto payments
|
|
101
|
+
const { rawBalance, isLoading: isBalanceLoading } = useTokenBalance({
|
|
102
|
+
token: selectedSrcToken,
|
|
103
|
+
address: wagmiAddress,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Check if user has enough balance
|
|
107
|
+
const hasEnoughBalance = useMemo(() => {
|
|
108
|
+
if (!rawBalance || isBalanceLoading || paymentType !== "crypto") return false;
|
|
109
|
+
try {
|
|
110
|
+
const requiredAmount = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
|
|
111
|
+
return rawBalance >= requiredAmount;
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}, [rawBalance, srcAmount, selectedSrcToken.decimals, isBalanceLoading, paymentType]);
|
|
116
|
+
|
|
117
|
+
// Auto-set crypto payment method based on balance
|
|
90
118
|
useEffect(() => {
|
|
91
|
-
if (paymentType === "crypto") {
|
|
92
|
-
|
|
119
|
+
if (paymentType === "crypto" && !isBalanceLoading) {
|
|
120
|
+
if (hasEnoughBalance) {
|
|
121
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
|
|
122
|
+
} else {
|
|
123
|
+
setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
|
|
124
|
+
}
|
|
93
125
|
}
|
|
94
|
-
}, [paymentType]);
|
|
126
|
+
}, [paymentType, hasEnoughBalance, isBalanceLoading]);
|
|
95
127
|
|
|
96
128
|
// Fetch specific token when sourceTokenAddress and sourceTokenChainId are provided
|
|
97
129
|
useEffect(() => {
|
|
@@ -159,14 +191,14 @@ export function useAnyspendFlow({
|
|
|
159
191
|
|
|
160
192
|
// Update useEffect for URL parameter to not override loadOrder
|
|
161
193
|
useEffect(() => {
|
|
162
|
-
if (loadOrder) return; // Skip if we have a loadOrder
|
|
194
|
+
if (loadOrder || disableUrlParamManagement) return; // Skip if we have a loadOrder or URL param management is disabled
|
|
163
195
|
|
|
164
196
|
const orderIdParam = searchParams.get("orderId");
|
|
165
197
|
if (orderIdParam) {
|
|
166
198
|
setOrderId(orderIdParam);
|
|
167
199
|
setActivePanel(PanelView.ORDER_DETAILS);
|
|
168
200
|
}
|
|
169
|
-
}, [searchParams, loadOrder]);
|
|
201
|
+
}, [searchParams, loadOrder, disableUrlParamManagement]);
|
|
170
202
|
|
|
171
203
|
// Order creation hooks
|
|
172
204
|
const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
|
|
@@ -177,16 +209,18 @@ export function useAnyspendFlow({
|
|
|
177
209
|
onOrderSuccess?.(newOrderId);
|
|
178
210
|
|
|
179
211
|
// Add orderId and payment method to URL for persistence
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
212
|
+
if (!disableUrlParamManagement) {
|
|
213
|
+
const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
|
|
214
|
+
params.set("orderId", newOrderId);
|
|
215
|
+
if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
|
|
216
|
+
console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
|
|
217
|
+
params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
|
|
218
|
+
} else {
|
|
219
|
+
console.log("Payment method is NONE, not setting in URL");
|
|
220
|
+
}
|
|
221
|
+
console.log("Final URL params:", params.toString());
|
|
222
|
+
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
187
223
|
}
|
|
188
|
-
console.log("Final URL params:", params.toString());
|
|
189
|
-
router.push(`${window.location.pathname}?${params.toString()}`);
|
|
190
224
|
},
|
|
191
225
|
onError: error => {
|
|
192
226
|
console.error(error);
|
|
@@ -245,6 +279,9 @@ export function useAnyspendFlow({
|
|
|
245
279
|
setSelectedRecipientAddress,
|
|
246
280
|
recipientName,
|
|
247
281
|
globalAddress,
|
|
282
|
+
// Balance check
|
|
283
|
+
hasEnoughBalance,
|
|
284
|
+
isBalanceLoading,
|
|
248
285
|
// Quote data
|
|
249
286
|
anyspendQuote,
|
|
250
287
|
isLoadingAnyspendQuote,
|