@b3dotfun/sdk 0.0.31-alpha.0 → 0.0.31-alpha.2
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/cjs/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/cjs/global-account/react/components/B3Provider/types.d.ts +4 -5
- package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +53 -1
- package/dist/cjs/global-account/react/hooks/useSiwe.js +5 -5
- 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/esm/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/esm/global-account/react/components/B3Provider/types.d.ts +4 -5
- package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +54 -5
- package/dist/esm/global-account/react/hooks/useSiwe.js +5 -5
- package/dist/types/anyspend/react/components/common/OrderDetails.d.ts +1 -0
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
- package/dist/types/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/types/global-account/react/components/B3Provider/types.d.ts +4 -5
- package/package.json +2 -2
- 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
- package/src/global-account/react/components/B3Provider/B3Provider.native.tsx +2 -2
- package/src/global-account/react/components/B3Provider/B3Provider.tsx +2 -2
- package/src/global-account/react/components/B3Provider/types.ts +4 -5
- package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +147 -3
- package/src/global-account/react/hooks/useSiwe.tsx +5 -5
|
@@ -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,
|
|
@@ -72,7 +72,7 @@ export declare const useSigMintCollection: ({ address, chainId }: FindByAddressP
|
|
|
72
72
|
description?: string | undefined;
|
|
73
73
|
createdAt?: string | undefined;
|
|
74
74
|
updatedAt?: string | undefined;
|
|
75
|
-
status?: "
|
|
75
|
+
status?: "ACTIVE" | "DRAFT" | "INACTIVE" | undefined;
|
|
76
76
|
metadata?: {} | undefined;
|
|
77
77
|
logoURI?: string | undefined;
|
|
78
78
|
creator?: string | undefined;
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { User } from "../../../../global-account/types/b3-api.types";
|
|
3
|
-
import { Wallet } from "thirdweb/wallets";
|
|
1
|
+
import { Users } from "@b3dotfun/b3-api";
|
|
4
2
|
import { PermissionsConfig } from "../../../../global-account/types/permissions";
|
|
3
|
+
import { Account, Wallet } from "thirdweb/wallets";
|
|
5
4
|
/**
|
|
6
5
|
* Context type for B3Provider
|
|
7
6
|
*/
|
|
8
7
|
export interface B3ContextType {
|
|
9
8
|
account?: Account;
|
|
10
9
|
automaticallySetFirstEoa: boolean;
|
|
11
|
-
user?:
|
|
10
|
+
user?: Users;
|
|
12
11
|
setWallet: (wallet: Wallet) => void;
|
|
13
12
|
wallet?: Wallet;
|
|
14
|
-
setUser: (user?:
|
|
13
|
+
setUser: (user?: Users) => void;
|
|
15
14
|
initialized: boolean;
|
|
16
15
|
ready: boolean;
|
|
17
16
|
environment?: "development" | "production";
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.ManageAccount = ManageAccount;
|
|
4
7
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const app_1 = __importDefault(require("../../../../global-account/app"));
|
|
5
9
|
const react_1 = require("../../../../global-account/react");
|
|
6
10
|
const SignOutIcon_1 = require("../../../../global-account/react/components/icons/SignOutIcon");
|
|
7
11
|
const formatNumber_1 = require("../../../../shared/utils/formatNumber");
|
|
8
12
|
const thirdweb_1 = require("../../../../shared/utils/thirdweb");
|
|
9
13
|
const lucide_react_1 = require("lucide-react");
|
|
10
14
|
const react_2 = require("react");
|
|
15
|
+
const sonner_1 = require("sonner");
|
|
11
16
|
const react_3 = require("thirdweb/react");
|
|
12
17
|
const viem_1 = require("viem");
|
|
13
18
|
const profileDisplay_1 = require("../../utils/profileDisplay");
|
|
@@ -55,6 +60,45 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
|
|
|
55
60
|
const { data: profilesRaw = [], isLoading: isLoadingProfiles } = (0, react_3.useProfiles)({ client: thirdweb_1.client });
|
|
56
61
|
const { mutate: unlinkProfile, isPending: isUnlinking } = (0, react_3.useUnlinkProfile)();
|
|
57
62
|
const { setB3ModalOpen, setB3ModalContentType, isLinking } = (0, react_1.useModalStore)();
|
|
63
|
+
const { user, setUser } = (0, react_1.useB3)();
|
|
64
|
+
const [isUpdatingCode, setIsUpdatingCode] = (0, react_2.useState)(false);
|
|
65
|
+
const [newReferralCode, setNewReferralCode] = (0, react_2.useState)("");
|
|
66
|
+
const [isEditingCode, setIsEditingCode] = (0, react_2.useState)(false);
|
|
67
|
+
const referallCodeRef = (0, react_2.useRef)(null);
|
|
68
|
+
const { data: referrals, isLoading: isLoadingReferrals } = (0, react_1.useQueryB3)("referrals", "find", { query: { referrerId: user?.userId } }, !!user?.userId);
|
|
69
|
+
// Fetch referred users
|
|
70
|
+
const currentReferralCode = user?.referralCode || user?.userId || "";
|
|
71
|
+
const handleCopyCode = async () => {
|
|
72
|
+
try {
|
|
73
|
+
await navigator.clipboard.writeText(currentReferralCode);
|
|
74
|
+
sonner_1.toast.success("Referral code copied to clipboard!");
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
sonner_1.toast.error("Failed to copy referral code");
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const handleUpdateReferralCode = async () => {
|
|
81
|
+
if (!newReferralCode)
|
|
82
|
+
return;
|
|
83
|
+
setIsUpdatingCode(true);
|
|
84
|
+
try {
|
|
85
|
+
// @ts-expect-error - setReferralCode is not typed for some reason
|
|
86
|
+
const newUser = await app_1.default.service("users").setReferralCode({
|
|
87
|
+
userId: user?.userId,
|
|
88
|
+
referralCode: newReferralCode,
|
|
89
|
+
});
|
|
90
|
+
setUser(newUser);
|
|
91
|
+
sonner_1.toast.success("Referral code updated successfully!");
|
|
92
|
+
setIsEditingCode(false);
|
|
93
|
+
setNewReferralCode("");
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
sonner_1.toast.error("Failed to update referral code");
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
setIsUpdatingCode(false);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
58
102
|
const profiles = profilesRaw
|
|
59
103
|
.filter((profile) => !["custom_auth_endpoint", "siwe"].includes(profile.type))
|
|
60
104
|
.map((profile) => ({
|
|
@@ -91,7 +135,15 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
|
|
|
91
135
|
},
|
|
92
136
|
});
|
|
93
137
|
};
|
|
94
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-8", children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), (0, jsx_runtime_1.jsxs)(react_1.Button, { className: "bg-b3-primary-wash hover:bg-b3-primary-wash/70 flex items-center gap-2 rounded-full px-4 py-2", onClick: handleOpenLinkModal, disabled: isLinking, children: [isLinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.LinkIcon, { size: 16, className: "text-b3-primary-blue" })), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center py-8", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: profiles.map(profile => ((0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? ((0, jsx_runtime_1.jsx)("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : ((0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium bg-b3-primary-wash rounded px-2 py-0.5 text-xs", children: profile.type.toUpperCase() })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "ghost", size: "icon", className: "text-b3-grey hover:text-b3-negative", onClick: () => handleUnlink(profile), disabled: unlinkingAccountId === profile.title || isUnlinking, children: unlinkingAccountId === profile.title || isUnlinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "
|
|
138
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-8", children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), (0, jsx_runtime_1.jsxs)(react_1.Button, { className: "bg-b3-primary-wash hover:bg-b3-primary-wash/70 flex items-center gap-2 rounded-full px-4 py-2", onClick: handleOpenLinkModal, disabled: isLinking, children: [isLinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.LinkIcon, { size: 16, className: "text-b3-primary-blue" })), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center py-8", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: profiles.map(profile => ((0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? ((0, jsx_runtime_1.jsx)("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : ((0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium bg-b3-primary-wash rounded px-2 py-0.5 text-xs", children: profile.type.toUpperCase() })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "ghost", size: "icon", className: "text-b3-grey hover:text-b3-negative", onClick: () => handleUnlink(profile), disabled: unlinkingAccountId === profile.title || isUnlinking, children: unlinkingAccountId === profile.title || isUnlinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Referrals" }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line rounded-xl p-4", children: [isEditingCode && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Your Referral Code" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Share this code with friends to earn rewards" })] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [!isEditingCode && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Your Referral Code" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Share this code with friends to earn rewards" })] })), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: isEditingCode ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("input", { type: "text", value: newReferralCode, onChange: e => setNewReferralCode(e.target.value), className: "rounded-lg border border-gray-200 bg-white px-3 py-1.5 text-sm", placeholder: "Enter new code", ref: referallCodeRef }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", onClick: handleUpdateReferralCode, disabled: isUpdatingCode || !newReferralCode, children: isUpdatingCode ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin" }) : "Save" }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", variant: "ghost", onClick: () => {
|
|
139
|
+
setIsEditingCode(false);
|
|
140
|
+
setNewReferralCode("");
|
|
141
|
+
}, children: "Cancel" })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "rounded-lg border border-gray-200 bg-white px-3 py-1.5 text-sm", children: currentReferralCode }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "icon", variant: "ghost", onClick: handleCopyCode, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { className: "h-4 w-4" }) }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "icon", variant: "ghost", onClick: () => {
|
|
142
|
+
setIsEditingCode(true);
|
|
143
|
+
setTimeout(() => {
|
|
144
|
+
referallCodeRef.current?.focus();
|
|
145
|
+
}, 100);
|
|
146
|
+
}, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { className: "h-4 w-4" }) })] })) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line rounded-xl p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold mb-4", children: "Referred Users" }), isLoadingReferrals ? ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center py-4", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-6 w-6 animate-spin text-gray-400" }) })) : referrals?.data?.length ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: referrals.data.map((referral) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between rounded-lg bg-white p-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-sm font-medium", children: referral.referreeId }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm text-gray-500", children: new Date(referral.createdAt).toLocaleDateString() })] }, String(referral._id)))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "py-4 text-center text-gray-500", children: "No referred users yet" }))] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Account Preferences" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line rounded-xl p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Dark Mode" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Switch between light and dark theme" })] }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash h-6 w-12 rounded-full" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), (0, jsx_runtime_1.jsx)("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3 apps" })] }), (0, jsx_runtime_1.jsx)("button", { className: "text-b3-grey hover:text-b3-grey/80 hover:bg-b3-line border-b3-line flex size-12 items-center justify-center rounded-full border", onClick: onLogoutEnhanced, children: logoutLoading ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : (0, jsx_runtime_1.jsx)(SignOutIcon_1.SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
|
|
95
147
|
};
|
|
96
148
|
return ((0, jsx_runtime_1.jsx)("div", { className: "b3-manage-account bg-b3-background flex flex-col rounded-xl", children: (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: (0, jsx_runtime_1.jsxs)(react_1.TabsPrimitive, { defaultValue: activeTab, onValueChange: value => {
|
|
97
149
|
const tab = value;
|
|
@@ -9,11 +9,11 @@ const debug_1 = __importDefault(require("../../../shared/utils/debug"));
|
|
|
9
9
|
const react_1 = require("react");
|
|
10
10
|
const useSearchParamsSSR_1 = require("./useSearchParamsSSR");
|
|
11
11
|
function useSiwe() {
|
|
12
|
-
const
|
|
12
|
+
const referralCode = (0, useSearchParamsSSR_1.useSearchParam)("referralCode");
|
|
13
13
|
const authenticate = (0, react_1.useCallback)(async (account, partnerId) => {
|
|
14
14
|
if (!account || !account.signMessage)
|
|
15
15
|
throw new Error("Account not found");
|
|
16
|
-
console.log("@@useAuthenticate:
|
|
16
|
+
console.log("@@useAuthenticate:referralCode", referralCode);
|
|
17
17
|
// generate challenge
|
|
18
18
|
const challenge = await app_1.default.service("global-accounts-challenge").create({
|
|
19
19
|
address: account.address,
|
|
@@ -31,13 +31,13 @@ function useSiwe() {
|
|
|
31
31
|
signature,
|
|
32
32
|
serverSignature: challenge.serverSignature,
|
|
33
33
|
nonce: challenge.nonce,
|
|
34
|
-
// http://localhost:5173/?
|
|
35
|
-
|
|
34
|
+
// http://localhost:5173/?referralCode=GIO2
|
|
35
|
+
referralCode,
|
|
36
36
|
partnerId: partnerId,
|
|
37
37
|
});
|
|
38
38
|
(0, debug_1.default)("@@useAuthenticate:response", response);
|
|
39
39
|
return response;
|
|
40
|
-
}, [
|
|
40
|
+
}, [referralCode]);
|
|
41
41
|
return {
|
|
42
42
|
authenticate,
|
|
43
43
|
};
|
|
@@ -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,
|
|
@@ -72,7 +72,7 @@ export declare const useSigMintCollection: ({ address, chainId }: FindByAddressP
|
|
|
72
72
|
description?: string | undefined;
|
|
73
73
|
createdAt?: string | undefined;
|
|
74
74
|
updatedAt?: string | undefined;
|
|
75
|
-
status?: "
|
|
75
|
+
status?: "ACTIVE" | "DRAFT" | "INACTIVE" | undefined;
|
|
76
76
|
metadata?: {} | undefined;
|
|
77
77
|
logoURI?: string | undefined;
|
|
78
78
|
creator?: string | undefined;
|