@swype-org/react-sdk 0.1.1 → 0.1.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/index.cjs +1357 -491
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -5
- package/dist/index.d.ts +77 -5
- package/dist/index.js +1359 -494
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,8 @@ var wagmi = require('wagmi');
|
|
|
6
6
|
var chains = require('wagmi/chains');
|
|
7
7
|
var reactQuery = require('@tanstack/react-query');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
var viem = require('viem');
|
|
10
|
+
var chains$1 = require('viem/chains');
|
|
9
11
|
|
|
10
12
|
var __defProp = Object.defineProperty;
|
|
11
13
|
var __export = (target, all) => {
|
|
@@ -84,13 +86,19 @@ function SwypeProvider({
|
|
|
84
86
|
if (!queryClientRef.current) {
|
|
85
87
|
queryClientRef.current = new reactQuery.QueryClient();
|
|
86
88
|
}
|
|
89
|
+
const [depositAmount, setDepositAmountRaw] = react.useState(null);
|
|
90
|
+
const setDepositAmount = react.useCallback((amount) => {
|
|
91
|
+
setDepositAmountRaw(amount);
|
|
92
|
+
}, []);
|
|
87
93
|
const value = react.useMemo(
|
|
88
94
|
() => ({
|
|
89
95
|
apiBaseUrl,
|
|
90
96
|
theme,
|
|
91
|
-
tokens: getTheme(theme)
|
|
97
|
+
tokens: getTheme(theme),
|
|
98
|
+
depositAmount,
|
|
99
|
+
setDepositAmount
|
|
92
100
|
}),
|
|
93
|
-
[apiBaseUrl, theme]
|
|
101
|
+
[apiBaseUrl, theme, depositAmount, setDepositAmount]
|
|
94
102
|
);
|
|
95
103
|
return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClientRef.current, children: /* @__PURE__ */ jsxRuntime.jsx(wagmi.WagmiProvider, { config: wagmiConfig, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
104
|
reactAuth.PrivyProvider,
|
|
@@ -112,6 +120,20 @@ function useSwypeConfig() {
|
|
|
112
120
|
}
|
|
113
121
|
return ctx;
|
|
114
122
|
}
|
|
123
|
+
function useSwypeDepositAmount() {
|
|
124
|
+
const ctx = react.useContext(SwypeContext);
|
|
125
|
+
if (!ctx) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
"useSwypeDepositAmount must be used within a <SwypeProvider>"
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
/** Current deposit amount, or null if not set */
|
|
132
|
+
amount: ctx.depositAmount,
|
|
133
|
+
/** Set the deposit amount (pass null to clear) */
|
|
134
|
+
setAmount: ctx.setDepositAmount
|
|
135
|
+
};
|
|
136
|
+
}
|
|
115
137
|
|
|
116
138
|
// src/api.ts
|
|
117
139
|
var api_exports = {};
|
|
@@ -123,7 +145,8 @@ __export(api_exports, {
|
|
|
123
145
|
fetchProviders: () => fetchProviders,
|
|
124
146
|
fetchTransfer: () => fetchTransfer,
|
|
125
147
|
reportActionCompletion: () => reportActionCompletion,
|
|
126
|
-
updateUserConfig: () => updateUserConfig
|
|
148
|
+
updateUserConfig: () => updateUserConfig,
|
|
149
|
+
updateUserConfigBySession: () => updateUserConfigBySession
|
|
127
150
|
});
|
|
128
151
|
async function throwApiError(res) {
|
|
129
152
|
const body = await res.json().catch(() => null);
|
|
@@ -208,6 +231,17 @@ async function updateUserConfig(apiBaseUrl, token, config) {
|
|
|
208
231
|
});
|
|
209
232
|
if (!res.ok) await throwApiError(res);
|
|
210
233
|
}
|
|
234
|
+
async function updateUserConfigBySession(apiBaseUrl, sessionId, config) {
|
|
235
|
+
const res = await fetch(
|
|
236
|
+
`${apiBaseUrl}/v1/authorization-sessions/${sessionId}/user-config`,
|
|
237
|
+
{
|
|
238
|
+
method: "PATCH",
|
|
239
|
+
headers: { "Content-Type": "application/json" },
|
|
240
|
+
body: JSON.stringify({ config })
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
if (!res.ok) await throwApiError(res);
|
|
244
|
+
}
|
|
211
245
|
async function reportActionCompletion(apiBaseUrl, actionId, result) {
|
|
212
246
|
const res = await fetch(
|
|
213
247
|
`${apiBaseUrl}/v1/authorization-actions/${actionId}`,
|
|
@@ -220,6 +254,26 @@ async function reportActionCompletion(apiBaseUrl, actionId, result) {
|
|
|
220
254
|
if (!res.ok) await throwApiError(res);
|
|
221
255
|
return await res.json();
|
|
222
256
|
}
|
|
257
|
+
var VIEM_CHAINS = {
|
|
258
|
+
1: chains$1.mainnet,
|
|
259
|
+
8453: chains$1.base,
|
|
260
|
+
42161: chains$1.arbitrum
|
|
261
|
+
};
|
|
262
|
+
var chainClientCache = /* @__PURE__ */ new Map();
|
|
263
|
+
function getPublicClientForChain(numericChainId) {
|
|
264
|
+
const existing = chainClientCache.get(numericChainId);
|
|
265
|
+
if (existing) return existing;
|
|
266
|
+
const viemChain = VIEM_CHAINS[numericChainId];
|
|
267
|
+
if (!viemChain) {
|
|
268
|
+
throw new Error(`Unsupported chain ID: ${numericChainId}`);
|
|
269
|
+
}
|
|
270
|
+
const client = viem.createPublicClient({
|
|
271
|
+
chain: viemChain,
|
|
272
|
+
transport: viem.http()
|
|
273
|
+
});
|
|
274
|
+
chainClientCache.set(numericChainId, client);
|
|
275
|
+
return client;
|
|
276
|
+
}
|
|
223
277
|
function useTransferPolling(intervalMs = 3e3) {
|
|
224
278
|
const { apiBaseUrl } = useSwypeConfig();
|
|
225
279
|
const { getAccessToken } = reactAuth.usePrivy();
|
|
@@ -274,12 +328,30 @@ function useAuthorizationExecutor() {
|
|
|
274
328
|
const { connectAsync, connectors } = wagmi.useConnect();
|
|
275
329
|
const { switchChainAsync } = wagmi.useSwitchChain();
|
|
276
330
|
const { signTypedDataAsync } = wagmi.useSignTypedData();
|
|
277
|
-
const publicClient = wagmi.usePublicClient();
|
|
278
331
|
const { data: walletClient } = wagmi.useWalletClient();
|
|
279
332
|
const [executing, setExecuting] = react.useState(false);
|
|
280
333
|
const [results, setResults] = react.useState([]);
|
|
281
334
|
const [error, setError] = react.useState(null);
|
|
282
335
|
const executingRef = react.useRef(false);
|
|
336
|
+
const [pendingSelectSource, setPendingSelectSource] = react.useState(null);
|
|
337
|
+
const selectSourceResolverRef = react.useRef(null);
|
|
338
|
+
const resolveSelectSource = react.useCallback((selection) => {
|
|
339
|
+
if (selectSourceResolverRef.current) {
|
|
340
|
+
selectSourceResolverRef.current(selection);
|
|
341
|
+
selectSourceResolverRef.current = null;
|
|
342
|
+
setPendingSelectSource(null);
|
|
343
|
+
}
|
|
344
|
+
}, []);
|
|
345
|
+
const [pendingAllowanceSelection, setPendingAllowanceSelection] = react.useState(null);
|
|
346
|
+
const allowanceSelectionResolverRef = react.useRef(null);
|
|
347
|
+
const sessionIdRef = react.useRef(null);
|
|
348
|
+
const resolveAllowanceSelection = react.useCallback((selection) => {
|
|
349
|
+
if (allowanceSelectionResolverRef.current) {
|
|
350
|
+
allowanceSelectionResolverRef.current(selection);
|
|
351
|
+
allowanceSelectionResolverRef.current = null;
|
|
352
|
+
setPendingAllowanceSelection(null);
|
|
353
|
+
}
|
|
354
|
+
}, []);
|
|
283
355
|
const executeOpenProvider = react.useCallback(
|
|
284
356
|
async (action) => {
|
|
285
357
|
try {
|
|
@@ -323,6 +395,49 @@ function useAuthorizationExecutor() {
|
|
|
323
395
|
},
|
|
324
396
|
[isConnected, address, currentChainId, connectors, connectAsync]
|
|
325
397
|
);
|
|
398
|
+
const executeSelectSource = react.useCallback(
|
|
399
|
+
async (action) => {
|
|
400
|
+
try {
|
|
401
|
+
const options = action.metadata?.options;
|
|
402
|
+
const recommended = action.metadata?.recommended;
|
|
403
|
+
if (!options || options.length <= 1) {
|
|
404
|
+
const selection2 = recommended ?? { chainName: "Base", tokenSymbol: "USDC" };
|
|
405
|
+
return {
|
|
406
|
+
actionId: action.id,
|
|
407
|
+
type: action.type,
|
|
408
|
+
status: "success",
|
|
409
|
+
message: `Auto-selected ${selection2.tokenSymbol} on ${selection2.chainName}.`,
|
|
410
|
+
data: {
|
|
411
|
+
selectedChainName: selection2.chainName,
|
|
412
|
+
selectedTokenSymbol: selection2.tokenSymbol
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
const selection = await new Promise((resolve) => {
|
|
417
|
+
selectSourceResolverRef.current = resolve;
|
|
418
|
+
setPendingSelectSource(action);
|
|
419
|
+
});
|
|
420
|
+
return {
|
|
421
|
+
actionId: action.id,
|
|
422
|
+
type: action.type,
|
|
423
|
+
status: "success",
|
|
424
|
+
message: `Selected ${selection.tokenSymbol} on ${selection.chainName}.`,
|
|
425
|
+
data: {
|
|
426
|
+
selectedChainName: selection.chainName,
|
|
427
|
+
selectedTokenSymbol: selection.tokenSymbol
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
} catch (err) {
|
|
431
|
+
return {
|
|
432
|
+
actionId: action.id,
|
|
433
|
+
type: action.type,
|
|
434
|
+
status: "error",
|
|
435
|
+
message: err instanceof Error ? err.message : "Failed to select source"
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
[]
|
|
440
|
+
);
|
|
326
441
|
const executeSwitchChain = react.useCallback(
|
|
327
442
|
async (action) => {
|
|
328
443
|
try {
|
|
@@ -336,8 +451,17 @@ function useAuthorizationExecutor() {
|
|
|
336
451
|
};
|
|
337
452
|
}
|
|
338
453
|
const targetChainIdNum = parseInt(targetChainIdHex, 16);
|
|
339
|
-
await switchChainAsync({ chainId: targetChainIdNum });
|
|
340
454
|
const hexChainId = `0x${targetChainIdNum.toString(16)}`;
|
|
455
|
+
if (currentChainId === targetChainIdNum) {
|
|
456
|
+
return {
|
|
457
|
+
actionId: action.id,
|
|
458
|
+
type: action.type,
|
|
459
|
+
status: "success",
|
|
460
|
+
message: `Already on chain ${hexChainId}. Skipped.`,
|
|
461
|
+
data: { chainId: hexChainId, switched: false }
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
await switchChainAsync({ chainId: targetChainIdNum });
|
|
341
465
|
return {
|
|
342
466
|
actionId: action.id,
|
|
343
467
|
type: action.type,
|
|
@@ -354,13 +478,14 @@ function useAuthorizationExecutor() {
|
|
|
354
478
|
};
|
|
355
479
|
}
|
|
356
480
|
},
|
|
357
|
-
[switchChainAsync]
|
|
481
|
+
[currentChainId, switchChainAsync]
|
|
358
482
|
);
|
|
359
483
|
const executeApprovePermit2 = react.useCallback(
|
|
360
484
|
async (action) => {
|
|
361
485
|
try {
|
|
362
486
|
const tokenAddress = action.metadata?.tokenAddress;
|
|
363
487
|
const permit2Address = action.metadata?.permit2Address;
|
|
488
|
+
const metadataChainId = action.metadata?.chainId;
|
|
364
489
|
if (!tokenAddress || !permit2Address) {
|
|
365
490
|
return {
|
|
366
491
|
actionId: action.id,
|
|
@@ -399,21 +524,26 @@ function useAuthorizationExecutor() {
|
|
|
399
524
|
outputs: [{ name: "", type: "bool" }]
|
|
400
525
|
}
|
|
401
526
|
];
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
527
|
+
const targetChainIdNum = metadataChainId ? parseInt(metadataChainId, 16) : currentChainId;
|
|
528
|
+
const chainClient = targetChainIdNum ? getPublicClientForChain(targetChainIdNum) : void 0;
|
|
529
|
+
if (chainClient) {
|
|
530
|
+
try {
|
|
531
|
+
const currentAllowance = await chainClient.readContract({
|
|
532
|
+
address: tokenAddress,
|
|
533
|
+
abi: ERC20_ABI,
|
|
534
|
+
functionName: "allowance",
|
|
535
|
+
args: [address, permit2Address]
|
|
536
|
+
});
|
|
537
|
+
if (currentAllowance > 0n) {
|
|
538
|
+
return {
|
|
539
|
+
actionId: action.id,
|
|
540
|
+
type: action.type,
|
|
541
|
+
status: "success",
|
|
542
|
+
message: `Permit2 already approved (allowance: ${currentAllowance.toString()}). Skipped.`,
|
|
543
|
+
data: { skipped: true, existingAllowance: currentAllowance.toString() }
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
} catch {
|
|
417
547
|
}
|
|
418
548
|
}
|
|
419
549
|
if (!walletClient) {
|
|
@@ -431,8 +561,8 @@ function useAuthorizationExecutor() {
|
|
|
431
561
|
functionName: "approve",
|
|
432
562
|
args: [permit2Address, MAX_UINT256]
|
|
433
563
|
});
|
|
434
|
-
if (
|
|
435
|
-
await
|
|
564
|
+
if (chainClient) {
|
|
565
|
+
await chainClient.waitForTransactionReceipt({ hash: txHash });
|
|
436
566
|
}
|
|
437
567
|
return {
|
|
438
568
|
actionId: action.id,
|
|
@@ -450,7 +580,7 @@ function useAuthorizationExecutor() {
|
|
|
450
580
|
};
|
|
451
581
|
}
|
|
452
582
|
},
|
|
453
|
-
[address,
|
|
583
|
+
[address, currentChainId, walletClient]
|
|
454
584
|
);
|
|
455
585
|
const executeSignPermit2 = react.useCallback(
|
|
456
586
|
async (action) => {
|
|
@@ -485,34 +615,55 @@ function useAuthorizationExecutor() {
|
|
|
485
615
|
message: "Missing spenderAddress or tokenAddress in action metadata."
|
|
486
616
|
};
|
|
487
617
|
}
|
|
488
|
-
|
|
618
|
+
const permit2ChainId = metadataChainId ? parseInt(metadataChainId, 16) : currentChainId;
|
|
619
|
+
const chainClient = permit2ChainId ? getPublicClientForChain(permit2ChainId) : void 0;
|
|
620
|
+
let onChainNonce;
|
|
621
|
+
if (chainClient && address) {
|
|
489
622
|
try {
|
|
490
|
-
const [existingAmount, existingExpiration] = await
|
|
623
|
+
const [existingAmount, existingExpiration, chainNonce] = await chainClient.readContract({
|
|
491
624
|
address: PERMIT2_ADDRESS,
|
|
492
625
|
abi: PERMIT2_ALLOWANCE_ABI,
|
|
493
626
|
functionName: "allowance",
|
|
494
627
|
args: [address, tokenAddress, spenderAddress]
|
|
495
628
|
});
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
629
|
+
onChainNonce = chainNonce;
|
|
630
|
+
if (metadataAmount) {
|
|
631
|
+
const requiredSmallestUnit = BigInt(metadataAmount);
|
|
632
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
633
|
+
if (existingAmount >= requiredSmallestUnit && existingExpiration > now) {
|
|
634
|
+
return {
|
|
635
|
+
actionId: action.id,
|
|
636
|
+
type: action.type,
|
|
637
|
+
status: "success",
|
|
638
|
+
message: `Permit2 allowance already sufficient (${existingAmount.toString()}). Skipped.`,
|
|
639
|
+
data: { skipped: true, existingAllowance: existingAmount.toString() }
|
|
640
|
+
};
|
|
641
|
+
}
|
|
508
642
|
}
|
|
509
643
|
} catch {
|
|
510
644
|
}
|
|
511
645
|
}
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
646
|
+
const allowanceSelection = await new Promise((resolve) => {
|
|
647
|
+
allowanceSelectionResolverRef.current = resolve;
|
|
648
|
+
setPendingAllowanceSelection(action);
|
|
649
|
+
});
|
|
650
|
+
if (allowanceSelection.topUpAmount > 0 && sessionIdRef.current) {
|
|
651
|
+
try {
|
|
652
|
+
await updateUserConfigBySession(
|
|
653
|
+
apiBaseUrl,
|
|
654
|
+
sessionIdRef.current,
|
|
655
|
+
{ defaultAllowance: allowanceSelection.topUpAmount }
|
|
656
|
+
);
|
|
657
|
+
} catch {
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
const tokenDecimals = Number(action.metadata?.tokenDecimals ?? 6);
|
|
661
|
+
const topUpSmallestUnit = BigInt(
|
|
662
|
+
Math.round(allowanceSelection.topUpAmount * 10 ** tokenDecimals)
|
|
663
|
+
);
|
|
664
|
+
const baseAmount = metadataAmount ? BigInt(metadataAmount) : BigInt(0);
|
|
665
|
+
const permitAmount = baseAmount + topUpSmallestUnit;
|
|
666
|
+
const nonce = onChainNonce ?? Number(action.metadata?.nonce ?? 0);
|
|
516
667
|
const sigDeadline = BigInt(Math.floor(Date.now() / 1e3) + 3600);
|
|
517
668
|
const expiration = Math.floor(Date.now() / 1e3) + 30 * 24 * 60 * 60;
|
|
518
669
|
const signature = await signTypedDataAsync({
|
|
@@ -569,13 +720,15 @@ function useAuthorizationExecutor() {
|
|
|
569
720
|
};
|
|
570
721
|
}
|
|
571
722
|
},
|
|
572
|
-
[address, currentChainId,
|
|
723
|
+
[address, currentChainId, signTypedDataAsync, apiBaseUrl]
|
|
573
724
|
);
|
|
574
725
|
const executeAction = react.useCallback(
|
|
575
726
|
async (action) => {
|
|
576
727
|
switch (action.type) {
|
|
577
728
|
case "OPEN_PROVIDER":
|
|
578
729
|
return executeOpenProvider(action);
|
|
730
|
+
case "SELECT_SOURCE":
|
|
731
|
+
return executeSelectSource(action);
|
|
579
732
|
case "SWITCH_CHAIN":
|
|
580
733
|
return executeSwitchChain(action);
|
|
581
734
|
case "APPROVE_PERMIT_2":
|
|
@@ -591,7 +744,7 @@ function useAuthorizationExecutor() {
|
|
|
591
744
|
};
|
|
592
745
|
}
|
|
593
746
|
},
|
|
594
|
-
[executeOpenProvider, executeSwitchChain, executeApprovePermit2, executeSignPermit2]
|
|
747
|
+
[executeOpenProvider, executeSelectSource, executeSwitchChain, executeApprovePermit2, executeSignPermit2]
|
|
595
748
|
);
|
|
596
749
|
const executeSession = react.useCallback(
|
|
597
750
|
async (transfer) => {
|
|
@@ -603,6 +756,7 @@ function useAuthorizationExecutor() {
|
|
|
603
756
|
return;
|
|
604
757
|
}
|
|
605
758
|
const sessionId = transfer.authorizationSessions[0].id;
|
|
759
|
+
sessionIdRef.current = sessionId;
|
|
606
760
|
setExecuting(true);
|
|
607
761
|
setError(null);
|
|
608
762
|
setResults([]);
|
|
@@ -611,6 +765,19 @@ function useAuthorizationExecutor() {
|
|
|
611
765
|
const allResults = [];
|
|
612
766
|
const completedActionIds = /* @__PURE__ */ new Set();
|
|
613
767
|
let pendingActions = currentSession.actions.filter((a) => a.status === "PENDING").sort((a, b) => a.orderIndex - b.orderIndex);
|
|
768
|
+
const ACTION_POLL_INTERVAL_MS = 500;
|
|
769
|
+
const ACTION_POLL_MAX_RETRIES = 20;
|
|
770
|
+
let actionPollRetries = 0;
|
|
771
|
+
while (pendingActions.length === 0 && currentSession.status !== "AUTHORIZED" && actionPollRetries < ACTION_POLL_MAX_RETRIES) {
|
|
772
|
+
await new Promise((r) => setTimeout(r, ACTION_POLL_INTERVAL_MS));
|
|
773
|
+
currentSession = await fetchAuthorizationSession(apiBaseUrl, sessionId);
|
|
774
|
+
pendingActions = currentSession.actions.filter((a) => a.status === "PENDING").sort((a, b) => a.orderIndex - b.orderIndex);
|
|
775
|
+
actionPollRetries++;
|
|
776
|
+
}
|
|
777
|
+
if (pendingActions.length === 0 && currentSession.status !== "AUTHORIZED") {
|
|
778
|
+
setError("Authorization actions were not created in time. Please try again.");
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
614
781
|
while (pendingActions.length > 0) {
|
|
615
782
|
const action = pendingActions[0];
|
|
616
783
|
if (completedActionIds.has(action.id)) break;
|
|
@@ -670,7 +837,16 @@ function useAuthorizationExecutor() {
|
|
|
670
837
|
},
|
|
671
838
|
[apiBaseUrl, executeAction]
|
|
672
839
|
);
|
|
673
|
-
return {
|
|
840
|
+
return {
|
|
841
|
+
executing,
|
|
842
|
+
results,
|
|
843
|
+
error,
|
|
844
|
+
pendingSelectSource,
|
|
845
|
+
resolveSelectSource,
|
|
846
|
+
pendingAllowanceSelection,
|
|
847
|
+
resolveAllowanceSelection,
|
|
848
|
+
executeSession
|
|
849
|
+
};
|
|
674
850
|
}
|
|
675
851
|
function Spinner({ size = 40, label }) {
|
|
676
852
|
const { tokens } = useSwypeConfig();
|
|
@@ -788,163 +964,232 @@ function ProviderCard({ provider, selected, onClick }) {
|
|
|
788
964
|
}
|
|
789
965
|
);
|
|
790
966
|
}
|
|
791
|
-
function
|
|
967
|
+
function AccountDropdown({
|
|
792
968
|
accounts,
|
|
793
|
-
|
|
794
|
-
onSelect
|
|
969
|
+
selectedAccountId,
|
|
970
|
+
onSelect,
|
|
971
|
+
selectedWalletId,
|
|
972
|
+
onWalletSelect
|
|
795
973
|
}) {
|
|
796
974
|
const { tokens } = useSwypeConfig();
|
|
797
|
-
const [
|
|
798
|
-
const
|
|
799
|
-
|
|
975
|
+
const [open, setOpen] = react.useState(false);
|
|
976
|
+
const containerRef = react.useRef(null);
|
|
977
|
+
const selected = accounts.find((a) => a.id === selectedAccountId);
|
|
978
|
+
const selectedWallet = selected?.wallets.find(
|
|
979
|
+
(w) => w.id === selectedWalletId
|
|
800
980
|
);
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
setExpandedAccountId(accountId);
|
|
807
|
-
}
|
|
808
|
-
};
|
|
809
|
-
const handleWalletClick = (account, wallet) => {
|
|
810
|
-
const isAlreadySelected = selection?.accountId === account.id && selection?.walletId === wallet.id;
|
|
811
|
-
if (isAlreadySelected) {
|
|
812
|
-
onSelect(null);
|
|
813
|
-
} else {
|
|
814
|
-
onSelect({
|
|
815
|
-
accountId: account.id,
|
|
816
|
-
walletId: wallet.id,
|
|
817
|
-
accountName: account.name,
|
|
818
|
-
walletName: wallet.name,
|
|
819
|
-
chainName: wallet.chain.name
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
|
-
const formatBalance = (wallet) => {
|
|
824
|
-
const parts = [];
|
|
825
|
-
for (const src of wallet.sources) {
|
|
826
|
-
if (src.token.status === "ACTIVE") {
|
|
827
|
-
parts.push(
|
|
828
|
-
`${src.balance.available.amount.toFixed(2)} ${src.balance.available.currency} (${src.token.symbol})`
|
|
829
|
-
);
|
|
981
|
+
react.useEffect(() => {
|
|
982
|
+
if (!open) return;
|
|
983
|
+
const handleClick = (e) => {
|
|
984
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
985
|
+
setOpen(false);
|
|
830
986
|
}
|
|
987
|
+
};
|
|
988
|
+
document.addEventListener("mousedown", handleClick);
|
|
989
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
990
|
+
}, [open]);
|
|
991
|
+
if (accounts.length === 0) return null;
|
|
992
|
+
const hasMultipleChoices = accounts.length > 1 || accounts.length === 1 && onWalletSelect && accounts[0].wallets.filter((w) => w.balance.available.amount > 0).length > 1;
|
|
993
|
+
if (!hasMultipleChoices) {
|
|
994
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
995
|
+
"div",
|
|
996
|
+
{
|
|
997
|
+
style: {
|
|
998
|
+
display: "flex",
|
|
999
|
+
alignItems: "center",
|
|
1000
|
+
gap: "6px",
|
|
1001
|
+
fontSize: "0.85rem",
|
|
1002
|
+
color: tokens.textSecondary
|
|
1003
|
+
},
|
|
1004
|
+
children: [
|
|
1005
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: accounts[0].name }),
|
|
1006
|
+
(selectedWallet ?? accounts[0].wallets[0]) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1007
|
+
"span",
|
|
1008
|
+
{
|
|
1009
|
+
style: {
|
|
1010
|
+
fontSize: "0.75rem",
|
|
1011
|
+
color: tokens.textMuted,
|
|
1012
|
+
fontFamily: '"SF Mono", "Fira Code", monospace'
|
|
1013
|
+
},
|
|
1014
|
+
children: selectedWallet ? `${selectedWallet.chain.name} \xB7 ${selectedWallet.name}` : accounts[0].wallets[0]?.name
|
|
1015
|
+
}
|
|
1016
|
+
)
|
|
1017
|
+
]
|
|
1018
|
+
}
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
const getAccountBalance = (account) => {
|
|
1022
|
+
let total = 0;
|
|
1023
|
+
for (const w of account.wallets) {
|
|
1024
|
+
total += w.balance.available.amount;
|
|
831
1025
|
}
|
|
832
|
-
|
|
833
|
-
return `${wallet.balance.available.amount.toFixed(2)} ${wallet.balance.available.currency}`;
|
|
834
|
-
}
|
|
835
|
-
return parts.join(", ") || "No balance";
|
|
1026
|
+
return total > 0 ? `$${total.toFixed(2)}` : "";
|
|
836
1027
|
};
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
1028
|
+
const hasActiveWallet = (account) => account.wallets.some((w) => w.status === "ACTIVE");
|
|
1029
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, style: { position: "relative" }, children: [
|
|
1030
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1031
|
+
"button",
|
|
840
1032
|
{
|
|
1033
|
+
onClick: () => setOpen(!open),
|
|
841
1034
|
style: {
|
|
842
|
-
display: "
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
1035
|
+
display: "flex",
|
|
1036
|
+
alignItems: "center",
|
|
1037
|
+
gap: "6px",
|
|
1038
|
+
background: "transparent",
|
|
1039
|
+
border: "none",
|
|
1040
|
+
cursor: "pointer",
|
|
1041
|
+
padding: "4px 0",
|
|
1042
|
+
color: tokens.textSecondary,
|
|
1043
|
+
fontFamily: "inherit",
|
|
1044
|
+
fontSize: "0.85rem",
|
|
1045
|
+
outline: "none"
|
|
849
1046
|
},
|
|
850
|
-
children:
|
|
1047
|
+
children: [
|
|
1048
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500, color: tokens.text }, children: selected?.name ?? "Select account" }),
|
|
1049
|
+
(selectedWallet ?? selected?.wallets?.[0]) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1050
|
+
"span",
|
|
1051
|
+
{
|
|
1052
|
+
style: {
|
|
1053
|
+
fontSize: "0.75rem",
|
|
1054
|
+
color: tokens.textMuted,
|
|
1055
|
+
fontFamily: '"SF Mono", "Fira Code", monospace'
|
|
1056
|
+
},
|
|
1057
|
+
children: selectedWallet ? `${selectedWallet.chain.name} \xB7 ${selectedWallet.name}` : selected.wallets[0].name
|
|
1058
|
+
}
|
|
1059
|
+
),
|
|
1060
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1061
|
+
"svg",
|
|
1062
|
+
{
|
|
1063
|
+
width: "12",
|
|
1064
|
+
height: "12",
|
|
1065
|
+
viewBox: "0 0 24 24",
|
|
1066
|
+
fill: "none",
|
|
1067
|
+
style: {
|
|
1068
|
+
transform: open ? "rotate(180deg)" : "rotate(0deg)",
|
|
1069
|
+
transition: "transform 0.15s ease",
|
|
1070
|
+
flexShrink: 0
|
|
1071
|
+
},
|
|
1072
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1073
|
+
"path",
|
|
1074
|
+
{
|
|
1075
|
+
d: "M7 10l5 5 5-5",
|
|
1076
|
+
stroke: tokens.textMuted,
|
|
1077
|
+
strokeWidth: "2",
|
|
1078
|
+
strokeLinecap: "round",
|
|
1079
|
+
strokeLinejoin: "round"
|
|
1080
|
+
}
|
|
1081
|
+
)
|
|
1082
|
+
}
|
|
1083
|
+
)
|
|
1084
|
+
]
|
|
851
1085
|
}
|
|
852
1086
|
),
|
|
853
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1087
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1088
|
+
"div",
|
|
1089
|
+
{
|
|
1090
|
+
style: {
|
|
1091
|
+
position: "absolute",
|
|
1092
|
+
top: "100%",
|
|
1093
|
+
left: 0,
|
|
1094
|
+
right: 0,
|
|
1095
|
+
marginTop: "4px",
|
|
1096
|
+
background: tokens.bgCard,
|
|
1097
|
+
border: `1px solid ${tokens.border}`,
|
|
1098
|
+
borderRadius: tokens.radius,
|
|
1099
|
+
boxShadow: tokens.shadowLg,
|
|
1100
|
+
zIndex: 50,
|
|
1101
|
+
overflow: "hidden",
|
|
1102
|
+
minWidth: "220px"
|
|
1103
|
+
},
|
|
1104
|
+
children: accounts.map((account) => {
|
|
1105
|
+
const isAcctSelected = account.id === selectedAccountId;
|
|
1106
|
+
const balance = getAccountBalance(account);
|
|
1107
|
+
const active = hasActiveWallet(account);
|
|
1108
|
+
const walletsWithBalance = account.wallets.filter(
|
|
1109
|
+
(w) => w.balance.available.amount > 0
|
|
1110
|
+
);
|
|
1111
|
+
const showWallets = onWalletSelect && walletsWithBalance.length > 0;
|
|
1112
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
867
1113
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
868
1114
|
"button",
|
|
869
1115
|
{
|
|
870
|
-
onClick: () =>
|
|
1116
|
+
onClick: () => {
|
|
1117
|
+
onSelect(account.id);
|
|
1118
|
+
if (!showWallets) setOpen(false);
|
|
1119
|
+
},
|
|
871
1120
|
style: {
|
|
872
|
-
width: "100%",
|
|
873
1121
|
display: "flex",
|
|
874
1122
|
alignItems: "center",
|
|
875
1123
|
justifyContent: "space-between",
|
|
876
|
-
|
|
877
|
-
|
|
1124
|
+
width: "100%",
|
|
1125
|
+
padding: "10px 14px",
|
|
1126
|
+
background: isAcctSelected && !selectedWalletId ? tokens.accent + "12" : "transparent",
|
|
878
1127
|
border: "none",
|
|
1128
|
+
borderBottom: showWallets ? "none" : `1px solid ${tokens.border}`,
|
|
879
1129
|
cursor: "pointer",
|
|
880
1130
|
color: tokens.text,
|
|
881
1131
|
fontFamily: "inherit",
|
|
882
|
-
fontSize: "0.
|
|
883
|
-
fontWeight: 500,
|
|
1132
|
+
fontSize: "0.85rem",
|
|
884
1133
|
textAlign: "left",
|
|
885
1134
|
outline: "none",
|
|
886
|
-
transition: "background 0.
|
|
1135
|
+
transition: "background 0.1s ease"
|
|
887
1136
|
},
|
|
888
1137
|
children: [
|
|
889
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
890
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1138
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
1139
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
891
1140
|
"div",
|
|
892
1141
|
{
|
|
893
1142
|
style: {
|
|
894
|
-
width: 28,
|
|
895
|
-
height: 28,
|
|
896
|
-
borderRadius: "6px",
|
|
897
|
-
background: tokens.accent + "25",
|
|
898
1143
|
display: "flex",
|
|
899
1144
|
alignItems: "center",
|
|
900
|
-
|
|
901
|
-
fontSize: "0.75rem",
|
|
902
|
-
fontWeight: 700,
|
|
903
|
-
color: tokens.accent,
|
|
904
|
-
flexShrink: 0
|
|
1145
|
+
gap: "6px"
|
|
905
1146
|
},
|
|
906
|
-
children:
|
|
1147
|
+
children: [
|
|
1148
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: account.name }),
|
|
1149
|
+
active && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1150
|
+
"span",
|
|
1151
|
+
{
|
|
1152
|
+
style: {
|
|
1153
|
+
fontSize: "0.6rem",
|
|
1154
|
+
fontWeight: 600,
|
|
1155
|
+
color: tokens.success,
|
|
1156
|
+
background: tokens.successBg,
|
|
1157
|
+
padding: "1px 5px",
|
|
1158
|
+
borderRadius: "3px",
|
|
1159
|
+
textTransform: "uppercase",
|
|
1160
|
+
letterSpacing: "0.03em"
|
|
1161
|
+
},
|
|
1162
|
+
children: "Active"
|
|
1163
|
+
}
|
|
1164
|
+
)
|
|
1165
|
+
]
|
|
907
1166
|
}
|
|
908
1167
|
),
|
|
909
|
-
/* @__PURE__ */ jsxRuntime.
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
activeWallets.length,
|
|
921
|
-
" wallet",
|
|
922
|
-
activeWallets.length !== 1 ? "s" : ""
|
|
923
|
-
]
|
|
924
|
-
}
|
|
925
|
-
)
|
|
926
|
-
] })
|
|
1168
|
+
balance && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1169
|
+
"div",
|
|
1170
|
+
{
|
|
1171
|
+
style: {
|
|
1172
|
+
fontSize: "0.75rem",
|
|
1173
|
+
color: tokens.textMuted,
|
|
1174
|
+
marginTop: "2px"
|
|
1175
|
+
},
|
|
1176
|
+
children: balance
|
|
1177
|
+
}
|
|
1178
|
+
)
|
|
927
1179
|
] }),
|
|
928
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1180
|
+
isAcctSelected && !selectedWalletId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
929
1181
|
"svg",
|
|
930
1182
|
{
|
|
931
1183
|
width: "14",
|
|
932
1184
|
height: "14",
|
|
933
1185
|
viewBox: "0 0 24 24",
|
|
934
1186
|
fill: "none",
|
|
935
|
-
style: {
|
|
936
|
-
transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)",
|
|
937
|
-
transition: "transform 0.2s ease",
|
|
938
|
-
flexShrink: 0
|
|
939
|
-
},
|
|
1187
|
+
style: { flexShrink: 0, marginLeft: "8px" },
|
|
940
1188
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
941
1189
|
"path",
|
|
942
1190
|
{
|
|
943
|
-
d: "
|
|
944
|
-
|
|
945
|
-
strokeWidth: "2",
|
|
946
|
-
strokeLinecap: "round",
|
|
947
|
-
strokeLinejoin: "round"
|
|
1191
|
+
d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
|
|
1192
|
+
fill: tokens.accent
|
|
948
1193
|
}
|
|
949
1194
|
)
|
|
950
1195
|
}
|
|
@@ -952,202 +1197,720 @@ function AccountWalletSelector({
|
|
|
952
1197
|
]
|
|
953
1198
|
}
|
|
954
1199
|
),
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
{
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1200
|
+
showWallets && walletsWithBalance.map((wallet, wIdx) => {
|
|
1201
|
+
const isWalletSelected = isAcctSelected && wallet.id === selectedWalletId;
|
|
1202
|
+
const walletBal = wallet.balance.available.amount > 0 ? `$${wallet.balance.available.amount.toFixed(2)}` : "";
|
|
1203
|
+
const isLastWallet = wIdx === walletsWithBalance.length - 1;
|
|
1204
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1205
|
+
"button",
|
|
1206
|
+
{
|
|
1207
|
+
onClick: () => {
|
|
1208
|
+
onWalletSelect(account.id, wallet.id);
|
|
1209
|
+
setOpen(false);
|
|
1210
|
+
},
|
|
1211
|
+
style: {
|
|
1212
|
+
display: "flex",
|
|
1213
|
+
alignItems: "center",
|
|
1214
|
+
justifyContent: "space-between",
|
|
1215
|
+
width: "100%",
|
|
1216
|
+
padding: "8px 14px 8px 28px",
|
|
1217
|
+
background: isWalletSelected ? tokens.accent + "12" : "transparent",
|
|
1218
|
+
border: "none",
|
|
1219
|
+
borderBottom: isLastWallet ? `1px solid ${tokens.border}` : "none",
|
|
1220
|
+
cursor: "pointer",
|
|
1221
|
+
color: tokens.text,
|
|
1222
|
+
fontFamily: "inherit",
|
|
1223
|
+
fontSize: "0.8rem",
|
|
1224
|
+
textAlign: "left",
|
|
1225
|
+
outline: "none",
|
|
1226
|
+
transition: "background 0.1s ease"
|
|
1227
|
+
},
|
|
1228
|
+
children: [
|
|
1229
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1230
|
+
"div",
|
|
1231
|
+
{
|
|
1232
|
+
style: {
|
|
1233
|
+
display: "flex",
|
|
1234
|
+
alignItems: "center",
|
|
1235
|
+
gap: "6px",
|
|
1236
|
+
minWidth: 0,
|
|
1237
|
+
flex: 1
|
|
1238
|
+
},
|
|
1239
|
+
children: [
|
|
1240
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1241
|
+
"span",
|
|
989
1242
|
{
|
|
990
1243
|
style: {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
gap: "6px"
|
|
1244
|
+
fontWeight: 500,
|
|
1245
|
+
fontSize: "0.8rem"
|
|
994
1246
|
},
|
|
995
|
-
children:
|
|
996
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: wallet.name }),
|
|
997
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
998
|
-
"span",
|
|
999
|
-
{
|
|
1000
|
-
style: {
|
|
1001
|
-
fontSize: "0.7rem",
|
|
1002
|
-
color: tokens.textMuted,
|
|
1003
|
-
background: tokens.bgHover,
|
|
1004
|
-
padding: "1px 6px",
|
|
1005
|
-
borderRadius: "4px"
|
|
1006
|
-
},
|
|
1007
|
-
children: wallet.chain.name
|
|
1008
|
-
}
|
|
1009
|
-
)
|
|
1010
|
-
]
|
|
1247
|
+
children: wallet.chain.name
|
|
1011
1248
|
}
|
|
1012
1249
|
),
|
|
1013
1250
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1014
|
-
"
|
|
1251
|
+
"span",
|
|
1015
1252
|
{
|
|
1016
1253
|
style: {
|
|
1017
|
-
fontSize: "0.
|
|
1018
|
-
color: tokens.
|
|
1019
|
-
|
|
1254
|
+
fontSize: "0.7rem",
|
|
1255
|
+
color: tokens.textMuted,
|
|
1256
|
+
fontFamily: '"SF Mono", "Fira Code", monospace'
|
|
1020
1257
|
},
|
|
1021
|
-
children:
|
|
1258
|
+
children: wallet.name
|
|
1259
|
+
}
|
|
1260
|
+
),
|
|
1261
|
+
walletBal && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1262
|
+
"span",
|
|
1263
|
+
{
|
|
1264
|
+
style: {
|
|
1265
|
+
fontSize: "0.7rem",
|
|
1266
|
+
color: tokens.textMuted,
|
|
1267
|
+
marginLeft: "auto"
|
|
1268
|
+
},
|
|
1269
|
+
children: walletBal
|
|
1022
1270
|
}
|
|
1023
1271
|
)
|
|
1024
|
-
]
|
|
1025
|
-
|
|
1026
|
-
|
|
1272
|
+
]
|
|
1273
|
+
}
|
|
1274
|
+
),
|
|
1275
|
+
isWalletSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1276
|
+
"svg",
|
|
1277
|
+
{
|
|
1278
|
+
width: "12",
|
|
1279
|
+
height: "12",
|
|
1280
|
+
viewBox: "0 0 24 24",
|
|
1281
|
+
fill: "none",
|
|
1282
|
+
style: {
|
|
1283
|
+
flexShrink: 0,
|
|
1284
|
+
marginLeft: "8px"
|
|
1285
|
+
},
|
|
1286
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1287
|
+
"path",
|
|
1027
1288
|
{
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
viewBox: "0 0 24 24",
|
|
1031
|
-
fill: "none",
|
|
1032
|
-
style: { flexShrink: 0, marginLeft: "8px" },
|
|
1033
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1034
|
-
"path",
|
|
1035
|
-
{
|
|
1036
|
-
d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
|
|
1037
|
-
fill: tokens.accent
|
|
1038
|
-
}
|
|
1039
|
-
)
|
|
1289
|
+
d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
|
|
1290
|
+
fill: tokens.accent
|
|
1040
1291
|
}
|
|
1041
1292
|
)
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
)
|
|
1049
|
-
]
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1293
|
+
}
|
|
1294
|
+
)
|
|
1295
|
+
]
|
|
1296
|
+
},
|
|
1297
|
+
wallet.id
|
|
1298
|
+
);
|
|
1299
|
+
})
|
|
1300
|
+
] }, account.id);
|
|
1301
|
+
})
|
|
1302
|
+
}
|
|
1303
|
+
)
|
|
1304
|
+
] });
|
|
1305
|
+
}
|
|
1306
|
+
var ASSETS = ["USDC", "USDT"];
|
|
1307
|
+
function AdvancedSettings({
|
|
1308
|
+
settings,
|
|
1309
|
+
onChange,
|
|
1310
|
+
chains,
|
|
1311
|
+
providers,
|
|
1312
|
+
onConnectNewAccount,
|
|
1313
|
+
connectingNewAccount
|
|
1314
|
+
}) {
|
|
1315
|
+
const { tokens } = useSwypeConfig();
|
|
1316
|
+
const [open, setOpen] = react.useState(false);
|
|
1317
|
+
const [showProviders, setShowProviders] = react.useState(false);
|
|
1318
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "12px" }, children: [
|
|
1319
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1320
|
+
"button",
|
|
1056
1321
|
{
|
|
1322
|
+
onClick: () => setOpen(!open),
|
|
1057
1323
|
style: {
|
|
1058
|
-
marginTop: "8px",
|
|
1059
|
-
fontSize: "0.8rem",
|
|
1060
|
-
color: tokens.accent,
|
|
1061
1324
|
display: "flex",
|
|
1062
1325
|
alignItems: "center",
|
|
1063
|
-
gap: "6px"
|
|
1326
|
+
gap: "6px",
|
|
1327
|
+
background: "transparent",
|
|
1328
|
+
border: "none",
|
|
1329
|
+
cursor: "pointer",
|
|
1330
|
+
padding: "4px 0",
|
|
1331
|
+
color: tokens.textMuted,
|
|
1332
|
+
fontFamily: "inherit",
|
|
1333
|
+
fontSize: "0.8rem",
|
|
1334
|
+
fontWeight: 500,
|
|
1335
|
+
outline: "none",
|
|
1336
|
+
letterSpacing: "0.02em"
|
|
1064
1337
|
},
|
|
1065
1338
|
children: [
|
|
1066
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1067
|
-
"
|
|
1339
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1340
|
+
"svg",
|
|
1068
1341
|
{
|
|
1069
|
-
|
|
1070
|
-
|
|
1342
|
+
width: "10",
|
|
1343
|
+
height: "10",
|
|
1344
|
+
viewBox: "0 0 24 24",
|
|
1345
|
+
fill: "none",
|
|
1346
|
+
style: {
|
|
1347
|
+
transform: open ? "rotate(180deg)" : "rotate(0deg)",
|
|
1348
|
+
transition: "transform 0.15s ease"
|
|
1349
|
+
},
|
|
1350
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1351
|
+
"path",
|
|
1352
|
+
{
|
|
1353
|
+
d: "M7 10l5 5 5-5",
|
|
1354
|
+
stroke: tokens.textMuted,
|
|
1355
|
+
strokeWidth: "2.5",
|
|
1356
|
+
strokeLinecap: "round",
|
|
1357
|
+
strokeLinejoin: "round"
|
|
1358
|
+
}
|
|
1359
|
+
)
|
|
1071
1360
|
}
|
|
1072
|
-
)
|
|
1073
|
-
"
|
|
1074
|
-
selection.walletName,
|
|
1075
|
-
" on ",
|
|
1076
|
-
selection.chainName
|
|
1361
|
+
),
|
|
1362
|
+
"Advanced options"
|
|
1077
1363
|
]
|
|
1078
1364
|
}
|
|
1079
|
-
)
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1365
|
+
),
|
|
1366
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1367
|
+
"div",
|
|
1368
|
+
{
|
|
1369
|
+
style: {
|
|
1370
|
+
marginTop: "10px",
|
|
1371
|
+
padding: "14px",
|
|
1372
|
+
background: tokens.bgInput,
|
|
1373
|
+
borderRadius: tokens.radius,
|
|
1374
|
+
border: `1px solid ${tokens.border}`
|
|
1375
|
+
},
|
|
1376
|
+
children: [
|
|
1377
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "14px" }, children: [
|
|
1378
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1379
|
+
"label",
|
|
1380
|
+
{
|
|
1381
|
+
style: {
|
|
1382
|
+
display: "block",
|
|
1383
|
+
fontSize: "0.7rem",
|
|
1384
|
+
fontWeight: 600,
|
|
1385
|
+
color: tokens.textMuted,
|
|
1386
|
+
textTransform: "uppercase",
|
|
1387
|
+
letterSpacing: "0.05em",
|
|
1388
|
+
marginBottom: "6px"
|
|
1389
|
+
},
|
|
1390
|
+
children: "Asset"
|
|
1391
|
+
}
|
|
1392
|
+
),
|
|
1393
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: "6px" }, children: ASSETS.map((asset) => {
|
|
1394
|
+
const isSelected = settings.asset === asset;
|
|
1395
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1396
|
+
"button",
|
|
1397
|
+
{
|
|
1398
|
+
onClick: () => onChange({
|
|
1399
|
+
...settings,
|
|
1400
|
+
asset: isSelected ? null : asset
|
|
1401
|
+
}),
|
|
1402
|
+
style: {
|
|
1403
|
+
padding: "6px 14px",
|
|
1404
|
+
fontSize: "0.8rem",
|
|
1405
|
+
fontWeight: 600,
|
|
1406
|
+
fontFamily: "inherit",
|
|
1407
|
+
borderRadius: "6px",
|
|
1408
|
+
border: `1.5px solid ${isSelected ? tokens.accent : tokens.border}`,
|
|
1409
|
+
background: isSelected ? tokens.accent + "18" : "transparent",
|
|
1410
|
+
color: isSelected ? tokens.accent : tokens.text,
|
|
1411
|
+
cursor: "pointer",
|
|
1412
|
+
outline: "none",
|
|
1413
|
+
transition: "all 0.12s ease"
|
|
1414
|
+
},
|
|
1415
|
+
children: asset
|
|
1416
|
+
},
|
|
1417
|
+
asset
|
|
1418
|
+
);
|
|
1419
|
+
}) })
|
|
1420
|
+
] }),
|
|
1421
|
+
chains.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "14px" }, children: [
|
|
1422
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1423
|
+
"label",
|
|
1424
|
+
{
|
|
1425
|
+
style: {
|
|
1426
|
+
display: "block",
|
|
1427
|
+
fontSize: "0.7rem",
|
|
1428
|
+
fontWeight: 600,
|
|
1429
|
+
color: tokens.textMuted,
|
|
1430
|
+
textTransform: "uppercase",
|
|
1431
|
+
letterSpacing: "0.05em",
|
|
1432
|
+
marginBottom: "6px"
|
|
1433
|
+
},
|
|
1434
|
+
children: "Chain"
|
|
1435
|
+
}
|
|
1436
|
+
),
|
|
1437
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: chains.map((chain) => {
|
|
1438
|
+
const isSelected = settings.chain === chain.name;
|
|
1439
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1440
|
+
"button",
|
|
1441
|
+
{
|
|
1442
|
+
onClick: () => onChange({
|
|
1443
|
+
...settings,
|
|
1444
|
+
chain: isSelected ? null : chain.name
|
|
1445
|
+
}),
|
|
1446
|
+
style: {
|
|
1447
|
+
padding: "6px 14px",
|
|
1448
|
+
fontSize: "0.8rem",
|
|
1449
|
+
fontWeight: 600,
|
|
1450
|
+
fontFamily: "inherit",
|
|
1451
|
+
borderRadius: "6px",
|
|
1452
|
+
border: `1.5px solid ${isSelected ? tokens.accent : tokens.border}`,
|
|
1453
|
+
background: isSelected ? tokens.accent + "18" : "transparent",
|
|
1454
|
+
color: isSelected ? tokens.accent : tokens.text,
|
|
1455
|
+
cursor: "pointer",
|
|
1456
|
+
outline: "none",
|
|
1457
|
+
transition: "all 0.12s ease"
|
|
1458
|
+
},
|
|
1459
|
+
children: chain.name
|
|
1460
|
+
},
|
|
1461
|
+
chain.id
|
|
1462
|
+
);
|
|
1463
|
+
}) })
|
|
1464
|
+
] }),
|
|
1465
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: !showProviders ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1466
|
+
"button",
|
|
1467
|
+
{
|
|
1468
|
+
onClick: () => setShowProviders(true),
|
|
1469
|
+
disabled: connectingNewAccount,
|
|
1470
|
+
style: {
|
|
1471
|
+
display: "flex",
|
|
1472
|
+
alignItems: "center",
|
|
1473
|
+
gap: "6px",
|
|
1474
|
+
background: "transparent",
|
|
1475
|
+
border: `1px dashed ${tokens.border}`,
|
|
1476
|
+
borderRadius: tokens.radius,
|
|
1477
|
+
padding: "10px 14px",
|
|
1478
|
+
width: "100%",
|
|
1479
|
+
cursor: connectingNewAccount ? "not-allowed" : "pointer",
|
|
1480
|
+
color: tokens.textSecondary,
|
|
1481
|
+
fontFamily: "inherit",
|
|
1482
|
+
fontSize: "0.825rem",
|
|
1483
|
+
fontWeight: 500,
|
|
1484
|
+
outline: "none",
|
|
1485
|
+
opacity: connectingNewAccount ? 0.5 : 1,
|
|
1486
|
+
transition: "opacity 0.1s ease"
|
|
1487
|
+
},
|
|
1488
|
+
children: [
|
|
1489
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1490
|
+
"svg",
|
|
1491
|
+
{
|
|
1492
|
+
width: "14",
|
|
1493
|
+
height: "14",
|
|
1494
|
+
viewBox: "0 0 24 24",
|
|
1495
|
+
fill: "none",
|
|
1496
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1497
|
+
"path",
|
|
1498
|
+
{
|
|
1499
|
+
d: "M12 5v14M5 12h14",
|
|
1500
|
+
stroke: tokens.textMuted,
|
|
1501
|
+
strokeWidth: "2",
|
|
1502
|
+
strokeLinecap: "round"
|
|
1503
|
+
}
|
|
1504
|
+
)
|
|
1505
|
+
}
|
|
1506
|
+
),
|
|
1507
|
+
"Connect new account"
|
|
1508
|
+
]
|
|
1509
|
+
}
|
|
1510
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1511
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1512
|
+
"div",
|
|
1513
|
+
{
|
|
1514
|
+
style: {
|
|
1515
|
+
display: "flex",
|
|
1516
|
+
alignItems: "center",
|
|
1517
|
+
justifyContent: "space-between",
|
|
1518
|
+
marginBottom: "8px"
|
|
1519
|
+
},
|
|
1520
|
+
children: [
|
|
1521
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1522
|
+
"label",
|
|
1523
|
+
{
|
|
1524
|
+
style: {
|
|
1525
|
+
fontSize: "0.7rem",
|
|
1526
|
+
fontWeight: 600,
|
|
1527
|
+
color: tokens.textMuted,
|
|
1528
|
+
textTransform: "uppercase",
|
|
1529
|
+
letterSpacing: "0.05em"
|
|
1530
|
+
},
|
|
1531
|
+
children: "Select provider"
|
|
1532
|
+
}
|
|
1533
|
+
),
|
|
1534
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1535
|
+
"button",
|
|
1536
|
+
{
|
|
1537
|
+
onClick: () => setShowProviders(false),
|
|
1538
|
+
style: {
|
|
1539
|
+
background: "transparent",
|
|
1540
|
+
border: "none",
|
|
1541
|
+
cursor: "pointer",
|
|
1542
|
+
color: tokens.textMuted,
|
|
1543
|
+
fontSize: "0.75rem",
|
|
1544
|
+
fontFamily: "inherit",
|
|
1545
|
+
outline: "none",
|
|
1546
|
+
padding: "2px 4px"
|
|
1547
|
+
},
|
|
1548
|
+
children: "Cancel"
|
|
1549
|
+
}
|
|
1550
|
+
)
|
|
1551
|
+
]
|
|
1552
|
+
}
|
|
1553
|
+
),
|
|
1554
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1555
|
+
"div",
|
|
1556
|
+
{
|
|
1557
|
+
style: {
|
|
1558
|
+
display: "flex",
|
|
1559
|
+
flexDirection: "column",
|
|
1560
|
+
gap: "6px"
|
|
1561
|
+
},
|
|
1562
|
+
children: providers.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1563
|
+
ProviderCard,
|
|
1564
|
+
{
|
|
1565
|
+
provider: p,
|
|
1566
|
+
selected: false,
|
|
1567
|
+
onClick: () => {
|
|
1568
|
+
onConnectNewAccount(p.id);
|
|
1569
|
+
setShowProviders(false);
|
|
1570
|
+
}
|
|
1571
|
+
},
|
|
1572
|
+
p.id
|
|
1573
|
+
))
|
|
1574
|
+
}
|
|
1575
|
+
)
|
|
1576
|
+
] }) })
|
|
1577
|
+
]
|
|
1578
|
+
}
|
|
1579
|
+
)
|
|
1580
|
+
] });
|
|
1581
|
+
}
|
|
1582
|
+
var TOP_UP_OPTIONS = [0, 25, 50, 100, 500];
|
|
1583
|
+
function AllowanceSelector({ action, onSelect }) {
|
|
1584
|
+
const { tokens } = useSwypeConfig();
|
|
1585
|
+
const metadataAmount = action.metadata?.amount;
|
|
1586
|
+
const tokenDecimals = Number(action.metadata?.tokenDecimals ?? 6);
|
|
1587
|
+
const currency = action.metadata?.currency ?? "USD";
|
|
1588
|
+
const transferAmountRaw = metadataAmount ? Number(BigInt(metadataAmount)) / 10 ** tokenDecimals : 0;
|
|
1589
|
+
const [selectedTopUp, setSelectedTopUp] = react.useState(0);
|
|
1590
|
+
const totalAllowance = transferAmountRaw + selectedTopUp;
|
|
1591
|
+
const formatAmount = (amount) => `$${amount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
1592
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1593
|
+
"div",
|
|
1594
|
+
{
|
|
1595
|
+
style: {
|
|
1596
|
+
padding: "4px 0",
|
|
1597
|
+
textAlign: "left"
|
|
1598
|
+
},
|
|
1599
|
+
children: [
|
|
1600
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1601
|
+
"h3",
|
|
1602
|
+
{
|
|
1603
|
+
style: {
|
|
1604
|
+
fontSize: "1rem",
|
|
1605
|
+
fontWeight: 600,
|
|
1606
|
+
color: tokens.text,
|
|
1607
|
+
margin: "0 0 6px 0",
|
|
1608
|
+
textAlign: "center"
|
|
1609
|
+
},
|
|
1610
|
+
children: "Set spending limit"
|
|
1611
|
+
}
|
|
1612
|
+
),
|
|
1613
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1614
|
+
"p",
|
|
1615
|
+
{
|
|
1616
|
+
style: {
|
|
1617
|
+
fontSize: "0.8rem",
|
|
1618
|
+
color: tokens.textMuted,
|
|
1619
|
+
margin: "0 0 16px 0",
|
|
1620
|
+
lineHeight: 1.5,
|
|
1621
|
+
textAlign: "center"
|
|
1622
|
+
},
|
|
1623
|
+
children: "Pre-authorize a higher amount so future payments go through instantly without wallet prompts."
|
|
1624
|
+
}
|
|
1625
|
+
),
|
|
1626
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1627
|
+
"div",
|
|
1628
|
+
{
|
|
1629
|
+
style: {
|
|
1630
|
+
display: "flex",
|
|
1631
|
+
justifyContent: "space-between",
|
|
1632
|
+
alignItems: "center",
|
|
1633
|
+
padding: "10px 14px",
|
|
1634
|
+
background: tokens.bgInput,
|
|
1635
|
+
borderRadius: tokens.radius,
|
|
1636
|
+
marginBottom: "12px",
|
|
1637
|
+
fontSize: "0.825rem"
|
|
1638
|
+
},
|
|
1639
|
+
children: [
|
|
1640
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: tokens.textSecondary }, children: "This payment" }),
|
|
1641
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: tokens.text }, children: [
|
|
1642
|
+
formatAmount(transferAmountRaw),
|
|
1643
|
+
" ",
|
|
1644
|
+
currency
|
|
1645
|
+
] })
|
|
1646
|
+
]
|
|
1647
|
+
}
|
|
1648
|
+
),
|
|
1649
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1650
|
+
"div",
|
|
1651
|
+
{
|
|
1652
|
+
style: {
|
|
1653
|
+
display: "flex",
|
|
1654
|
+
flexDirection: "column",
|
|
1655
|
+
gap: "6px",
|
|
1656
|
+
marginBottom: "16px"
|
|
1657
|
+
},
|
|
1658
|
+
children: TOP_UP_OPTIONS.map((topUp) => {
|
|
1659
|
+
const isSelected = selectedTopUp === topUp;
|
|
1660
|
+
const total = transferAmountRaw + topUp;
|
|
1661
|
+
const label = topUp === 0 ? "Just this payment" : `+${formatAmount(topUp)} for future payments`;
|
|
1662
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1663
|
+
"button",
|
|
1664
|
+
{
|
|
1665
|
+
onClick: () => setSelectedTopUp(topUp),
|
|
1666
|
+
style: {
|
|
1667
|
+
display: "flex",
|
|
1668
|
+
alignItems: "center",
|
|
1669
|
+
justifyContent: "space-between",
|
|
1670
|
+
width: "100%",
|
|
1671
|
+
padding: "12px 14px",
|
|
1672
|
+
background: isSelected ? tokens.accent + "14" : "transparent",
|
|
1673
|
+
border: `1.5px solid ${isSelected ? tokens.accent : tokens.border}`,
|
|
1674
|
+
borderRadius: tokens.radius,
|
|
1675
|
+
cursor: "pointer",
|
|
1676
|
+
color: tokens.text,
|
|
1677
|
+
fontFamily: "inherit",
|
|
1678
|
+
fontSize: "0.825rem",
|
|
1679
|
+
textAlign: "left",
|
|
1680
|
+
outline: "none",
|
|
1681
|
+
transition: "all 0.12s ease"
|
|
1682
|
+
},
|
|
1683
|
+
children: [
|
|
1684
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
1685
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1686
|
+
"div",
|
|
1687
|
+
{
|
|
1688
|
+
style: {
|
|
1689
|
+
width: 16,
|
|
1690
|
+
height: 16,
|
|
1691
|
+
borderRadius: "50%",
|
|
1692
|
+
border: `2px solid ${isSelected ? tokens.accent : tokens.border}`,
|
|
1693
|
+
display: "flex",
|
|
1694
|
+
alignItems: "center",
|
|
1695
|
+
justifyContent: "center",
|
|
1696
|
+
flexShrink: 0
|
|
1697
|
+
},
|
|
1698
|
+
children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1699
|
+
"div",
|
|
1700
|
+
{
|
|
1701
|
+
style: {
|
|
1702
|
+
width: 8,
|
|
1703
|
+
height: 8,
|
|
1704
|
+
borderRadius: "50%",
|
|
1705
|
+
background: tokens.accent
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
)
|
|
1709
|
+
}
|
|
1710
|
+
),
|
|
1711
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: isSelected ? 600 : 400 }, children: label })
|
|
1712
|
+
] }),
|
|
1713
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1714
|
+
"span",
|
|
1715
|
+
{
|
|
1716
|
+
style: {
|
|
1717
|
+
fontWeight: 600,
|
|
1718
|
+
color: isSelected ? tokens.accent : tokens.textMuted,
|
|
1719
|
+
fontSize: "0.8rem",
|
|
1720
|
+
flexShrink: 0,
|
|
1721
|
+
marginLeft: "8px"
|
|
1722
|
+
},
|
|
1723
|
+
children: formatAmount(total)
|
|
1724
|
+
}
|
|
1725
|
+
)
|
|
1726
|
+
]
|
|
1727
|
+
},
|
|
1728
|
+
topUp
|
|
1729
|
+
);
|
|
1730
|
+
})
|
|
1731
|
+
}
|
|
1732
|
+
),
|
|
1733
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1734
|
+
"div",
|
|
1735
|
+
{
|
|
1736
|
+
style: {
|
|
1737
|
+
display: "flex",
|
|
1738
|
+
justifyContent: "space-between",
|
|
1739
|
+
alignItems: "center",
|
|
1740
|
+
padding: "10px 14px",
|
|
1741
|
+
background: tokens.bgInput,
|
|
1742
|
+
borderRadius: tokens.radius,
|
|
1743
|
+
marginBottom: "14px",
|
|
1744
|
+
fontSize: "0.825rem"
|
|
1745
|
+
},
|
|
1746
|
+
children: [
|
|
1747
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: tokens.textSecondary }, children: "Total authorization" }),
|
|
1748
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 700, color: tokens.text, fontSize: "0.9rem" }, children: [
|
|
1749
|
+
formatAmount(totalAllowance),
|
|
1750
|
+
" ",
|
|
1751
|
+
currency
|
|
1752
|
+
] })
|
|
1753
|
+
]
|
|
1754
|
+
}
|
|
1755
|
+
),
|
|
1756
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1757
|
+
"button",
|
|
1758
|
+
{
|
|
1759
|
+
onClick: () => onSelect({ topUpAmount: selectedTopUp }),
|
|
1760
|
+
style: {
|
|
1761
|
+
width: "100%",
|
|
1762
|
+
padding: "14px",
|
|
1763
|
+
background: tokens.accent,
|
|
1764
|
+
color: tokens.accentText,
|
|
1765
|
+
border: "none",
|
|
1766
|
+
borderRadius: tokens.radius,
|
|
1767
|
+
fontSize: "1rem",
|
|
1768
|
+
fontWeight: 600,
|
|
1769
|
+
cursor: "pointer",
|
|
1770
|
+
transition: "background 0.15s ease",
|
|
1771
|
+
fontFamily: "inherit"
|
|
1772
|
+
},
|
|
1773
|
+
children: "Authorize & Sign"
|
|
1774
|
+
}
|
|
1775
|
+
)
|
|
1776
|
+
]
|
|
1777
|
+
}
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
function isMobile() {
|
|
1781
|
+
if (typeof navigator === "undefined") return false;
|
|
1782
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
1783
|
+
navigator.userAgent
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
function computeSmartDefaults(accts, transferAmount) {
|
|
1787
|
+
if (accts.length === 0) return null;
|
|
1788
|
+
for (const acct of accts) {
|
|
1789
|
+
for (const wallet of acct.wallets) {
|
|
1790
|
+
if (wallet.status === "ACTIVE" && wallet.lastAuthorizedToken) {
|
|
1791
|
+
const matchingSource = wallet.sources.find(
|
|
1792
|
+
(s) => s.token.symbol === wallet.lastAuthorizedToken.symbol
|
|
1793
|
+
);
|
|
1794
|
+
if (matchingSource && matchingSource.balance.available.amount >= transferAmount) {
|
|
1795
|
+
return { accountId: acct.id, walletId: wallet.id };
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
let bestAccount = null;
|
|
1801
|
+
let bestWallet = null;
|
|
1802
|
+
let bestBalance = -1;
|
|
1803
|
+
for (const acct of accts) {
|
|
1804
|
+
for (const wallet of acct.wallets) {
|
|
1805
|
+
const walletBal = wallet.balance.available.amount;
|
|
1806
|
+
if (walletBal > bestBalance) {
|
|
1807
|
+
bestBalance = walletBal;
|
|
1808
|
+
bestAccount = acct;
|
|
1809
|
+
bestWallet = wallet;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
if (bestAccount) {
|
|
1814
|
+
return {
|
|
1815
|
+
accountId: bestAccount.id,
|
|
1816
|
+
walletId: bestWallet?.id ?? null
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
return { accountId: accts[0].id, walletId: null };
|
|
1820
|
+
}
|
|
1821
|
+
function SwypePayment({
|
|
1822
|
+
destination,
|
|
1823
|
+
onComplete,
|
|
1824
|
+
onError
|
|
1825
|
+
}) {
|
|
1826
|
+
const { apiBaseUrl, tokens, depositAmount } = useSwypeConfig();
|
|
1827
|
+
const { ready, authenticated, login, getAccessToken } = reactAuth.usePrivy();
|
|
1828
|
+
const [step, setStep] = react.useState("login");
|
|
1829
|
+
const [error, setError] = react.useState(null);
|
|
1830
|
+
const [providers, setProviders] = react.useState([]);
|
|
1831
|
+
const [accounts, setAccounts] = react.useState([]);
|
|
1832
|
+
const [chains, setChains] = react.useState([]);
|
|
1833
|
+
const [loadingData, setLoadingData] = react.useState(false);
|
|
1834
|
+
const [selectedAccountId, setSelectedAccountId] = react.useState(null);
|
|
1835
|
+
const [selectedWalletId, setSelectedWalletId] = react.useState(null);
|
|
1836
|
+
const [selectedProviderId, setSelectedProviderId] = react.useState(null);
|
|
1837
|
+
const [connectingNewAccount, setConnectingNewAccount] = react.useState(false);
|
|
1838
|
+
const [amount, setAmount] = react.useState(
|
|
1839
|
+
depositAmount != null ? depositAmount.toString() : ""
|
|
1840
|
+
);
|
|
1841
|
+
const [advancedSettings, setAdvancedSettings] = react.useState({
|
|
1842
|
+
asset: null,
|
|
1843
|
+
chain: null
|
|
1844
|
+
});
|
|
1845
|
+
const [transfer, setTransfer] = react.useState(null);
|
|
1846
|
+
const [creatingTransfer, setCreatingTransfer] = react.useState(false);
|
|
1847
|
+
const [mobileFlow, setMobileFlow] = react.useState(false);
|
|
1848
|
+
const pollingTransferIdRef = react.useRef(null);
|
|
1849
|
+
const authExecutor = useAuthorizationExecutor();
|
|
1111
1850
|
const polling = useTransferPolling();
|
|
1112
|
-
const sourceType =
|
|
1113
|
-
const sourceId =
|
|
1851
|
+
const sourceType = connectingNewAccount ? "providerId" : selectedWalletId ? "walletId" : selectedAccountId ? "accountId" : "providerId";
|
|
1852
|
+
const sourceId = connectingNewAccount ? selectedProviderId ?? "" : selectedWalletId ? selectedWalletId : selectedAccountId ? selectedAccountId : selectedProviderId ?? "";
|
|
1853
|
+
react.useEffect(() => {
|
|
1854
|
+
if (depositAmount != null) {
|
|
1855
|
+
setAmount(depositAmount.toString());
|
|
1856
|
+
}
|
|
1857
|
+
}, [depositAmount]);
|
|
1114
1858
|
react.useEffect(() => {
|
|
1115
1859
|
if (ready && authenticated && step === "login") {
|
|
1116
|
-
|
|
1860
|
+
if (depositAmount != null && depositAmount > 0) {
|
|
1861
|
+
setStep("ready");
|
|
1862
|
+
} else {
|
|
1863
|
+
setStep("enter-amount");
|
|
1864
|
+
}
|
|
1117
1865
|
}
|
|
1118
|
-
}, [ready, authenticated, step]);
|
|
1866
|
+
}, [ready, authenticated, step, depositAmount]);
|
|
1867
|
+
const loadingDataRef = react.useRef(false);
|
|
1119
1868
|
react.useEffect(() => {
|
|
1120
|
-
if (
|
|
1121
|
-
if (
|
|
1869
|
+
if (!authenticated) return;
|
|
1870
|
+
if (accounts.length > 0 || loadingDataRef.current) return;
|
|
1122
1871
|
let cancelled = false;
|
|
1872
|
+
loadingDataRef.current = true;
|
|
1123
1873
|
const load = async () => {
|
|
1124
1874
|
setLoadingData(true);
|
|
1125
1875
|
setError(null);
|
|
1126
1876
|
try {
|
|
1127
1877
|
const token = await getAccessToken();
|
|
1128
1878
|
if (!token) throw new Error("Not authenticated");
|
|
1129
|
-
const [prov, accts] = await Promise.all([
|
|
1879
|
+
const [prov, accts, chn] = await Promise.all([
|
|
1130
1880
|
fetchProviders(apiBaseUrl, token),
|
|
1131
|
-
fetchAccounts(apiBaseUrl, token)
|
|
1881
|
+
fetchAccounts(apiBaseUrl, token),
|
|
1882
|
+
fetchChains(apiBaseUrl, token)
|
|
1132
1883
|
]);
|
|
1133
1884
|
if (cancelled) return;
|
|
1134
1885
|
setProviders(prov);
|
|
1135
1886
|
setAccounts(accts);
|
|
1136
|
-
|
|
1887
|
+
setChains(chn);
|
|
1888
|
+
const parsedAmt = depositAmount != null ? depositAmount : 0;
|
|
1889
|
+
const defaults = computeSmartDefaults(accts, parsedAmt);
|
|
1890
|
+
if (defaults) {
|
|
1891
|
+
setSelectedAccountId(defaults.accountId);
|
|
1892
|
+
setSelectedWalletId(defaults.walletId);
|
|
1893
|
+
} else if (prov.length > 0) {
|
|
1894
|
+
setSelectedProviderId(prov[0].id);
|
|
1895
|
+
}
|
|
1137
1896
|
} catch (err) {
|
|
1138
1897
|
if (!cancelled) {
|
|
1139
1898
|
const msg = err instanceof Error ? err.message : "Failed to load data";
|
|
1140
1899
|
setError(msg);
|
|
1141
1900
|
}
|
|
1142
1901
|
} finally {
|
|
1143
|
-
if (!cancelled)
|
|
1902
|
+
if (!cancelled) {
|
|
1903
|
+
setLoadingData(false);
|
|
1904
|
+
loadingDataRef.current = false;
|
|
1905
|
+
}
|
|
1144
1906
|
}
|
|
1145
1907
|
};
|
|
1146
1908
|
load();
|
|
1147
1909
|
return () => {
|
|
1148
1910
|
cancelled = true;
|
|
1911
|
+
loadingDataRef.current = false;
|
|
1149
1912
|
};
|
|
1150
|
-
}, [
|
|
1913
|
+
}, [authenticated, accounts.length, apiBaseUrl, getAccessToken]);
|
|
1151
1914
|
react.useEffect(() => {
|
|
1152
1915
|
if (!polling.transfer) return;
|
|
1153
1916
|
if (polling.transfer.status === "COMPLETED") {
|
|
@@ -1174,6 +1937,61 @@ function SwypePayment({
|
|
|
1174
1937
|
document.removeEventListener("visibilitychange", handleVisibility);
|
|
1175
1938
|
};
|
|
1176
1939
|
}, [mobileFlow, polling]);
|
|
1940
|
+
react.useEffect(() => {
|
|
1941
|
+
if (!authExecutor.pendingSelectSource) return;
|
|
1942
|
+
const action = authExecutor.pendingSelectSource;
|
|
1943
|
+
const hasAdvancedOverride = advancedSettings.asset !== null || advancedSettings.chain !== null;
|
|
1944
|
+
if (hasAdvancedOverride) {
|
|
1945
|
+
const options = action.metadata?.options ?? [];
|
|
1946
|
+
const recommended = action.metadata?.recommended;
|
|
1947
|
+
const match = options.find(
|
|
1948
|
+
(opt) => (advancedSettings.chain === null || opt.chainName === advancedSettings.chain) && (advancedSettings.asset === null || opt.tokenSymbol === advancedSettings.asset)
|
|
1949
|
+
);
|
|
1950
|
+
if (match) {
|
|
1951
|
+
authExecutor.resolveSelectSource({
|
|
1952
|
+
chainName: match.chainName,
|
|
1953
|
+
tokenSymbol: match.tokenSymbol
|
|
1954
|
+
});
|
|
1955
|
+
} else if (recommended) {
|
|
1956
|
+
authExecutor.resolveSelectSource({
|
|
1957
|
+
chainName: recommended.chainName,
|
|
1958
|
+
tokenSymbol: recommended.tokenSymbol
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
} else {
|
|
1962
|
+
const options = action.metadata?.options ?? [];
|
|
1963
|
+
const recommended = action.metadata?.recommended;
|
|
1964
|
+
const selWallet = selectedWalletId ? accounts.find((a) => a.id === selectedAccountId)?.wallets.find((w) => w.id === selectedWalletId) : null;
|
|
1965
|
+
if (selWallet) {
|
|
1966
|
+
const walletMatch = options.find(
|
|
1967
|
+
(opt) => opt.chainName === selWallet.chain.name
|
|
1968
|
+
);
|
|
1969
|
+
if (walletMatch) {
|
|
1970
|
+
authExecutor.resolveSelectSource({
|
|
1971
|
+
chainName: walletMatch.chainName,
|
|
1972
|
+
tokenSymbol: walletMatch.tokenSymbol
|
|
1973
|
+
});
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
if (recommended) {
|
|
1978
|
+
authExecutor.resolveSelectSource({
|
|
1979
|
+
chainName: recommended.chainName,
|
|
1980
|
+
tokenSymbol: recommended.tokenSymbol
|
|
1981
|
+
});
|
|
1982
|
+
} else if (options.length > 0) {
|
|
1983
|
+
authExecutor.resolveSelectSource({
|
|
1984
|
+
chainName: options[0].chainName,
|
|
1985
|
+
tokenSymbol: options[0].tokenSymbol
|
|
1986
|
+
});
|
|
1987
|
+
} else {
|
|
1988
|
+
authExecutor.resolveSelectSource({
|
|
1989
|
+
chainName: "Base",
|
|
1990
|
+
tokenSymbol: "USDC"
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
}, [authExecutor, authExecutor.pendingSelectSource, advancedSettings, selectedWalletId, selectedAccountId, accounts]);
|
|
1177
1995
|
const handlePay = react.useCallback(async () => {
|
|
1178
1996
|
const parsedAmount = parseFloat(amount);
|
|
1179
1997
|
if (isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
@@ -1181,7 +1999,7 @@ function SwypePayment({
|
|
|
1181
1999
|
return;
|
|
1182
2000
|
}
|
|
1183
2001
|
if (!sourceId) {
|
|
1184
|
-
setError("
|
|
2002
|
+
setError("No account or provider selected.");
|
|
1185
2003
|
return;
|
|
1186
2004
|
}
|
|
1187
2005
|
setStep("processing");
|
|
@@ -1191,12 +2009,6 @@ function SwypePayment({
|
|
|
1191
2009
|
try {
|
|
1192
2010
|
const token = await getAccessToken();
|
|
1193
2011
|
if (!token) throw new Error("Not authenticated");
|
|
1194
|
-
const parsedTopUp = parseFloat(topUpBalance);
|
|
1195
|
-
if (!isNaN(parsedTopUp) && parsedTopUp > 0) {
|
|
1196
|
-
await updateUserConfig(apiBaseUrl, token, {
|
|
1197
|
-
defaultAllowance: parsedTopUp
|
|
1198
|
-
});
|
|
1199
|
-
}
|
|
1200
2012
|
const t = await createTransfer(apiBaseUrl, token, {
|
|
1201
2013
|
sourceType,
|
|
1202
2014
|
sourceId,
|
|
@@ -1220,7 +2032,7 @@ function SwypePayment({
|
|
|
1220
2032
|
const msg = err instanceof Error ? err.message : "Transfer creation failed";
|
|
1221
2033
|
setError(msg);
|
|
1222
2034
|
onError?.(msg);
|
|
1223
|
-
setStep("
|
|
2035
|
+
setStep("ready");
|
|
1224
2036
|
} finally {
|
|
1225
2037
|
setCreatingTransfer(false);
|
|
1226
2038
|
}
|
|
@@ -1233,19 +2045,24 @@ function SwypePayment({
|
|
|
1233
2045
|
getAccessToken,
|
|
1234
2046
|
authExecutor,
|
|
1235
2047
|
polling,
|
|
1236
|
-
onError
|
|
1237
|
-
topUpBalance
|
|
2048
|
+
onError
|
|
1238
2049
|
]);
|
|
1239
2050
|
const handleNewPayment = () => {
|
|
1240
|
-
setStep("
|
|
2051
|
+
setStep("ready");
|
|
1241
2052
|
setTransfer(null);
|
|
1242
2053
|
setError(null);
|
|
1243
|
-
setAmount(
|
|
1244
|
-
setTopUpBalance("");
|
|
2054
|
+
setAmount(depositAmount != null ? depositAmount.toString() : "");
|
|
1245
2055
|
setMobileFlow(false);
|
|
1246
2056
|
pollingTransferIdRef.current = null;
|
|
1247
|
-
|
|
1248
|
-
|
|
2057
|
+
setConnectingNewAccount(false);
|
|
2058
|
+
setSelectedWalletId(null);
|
|
2059
|
+
setAdvancedSettings({ asset: null, chain: null });
|
|
2060
|
+
if (accounts.length > 0) setSelectedAccountId(accounts[0].id);
|
|
2061
|
+
};
|
|
2062
|
+
const handleConnectNewAccount = (providerId) => {
|
|
2063
|
+
setSelectedProviderId(providerId);
|
|
2064
|
+
setSelectedAccountId(null);
|
|
2065
|
+
setConnectingNewAccount(true);
|
|
1249
2066
|
};
|
|
1250
2067
|
const cardStyle = {
|
|
1251
2068
|
background: tokens.bgCard,
|
|
@@ -1283,15 +2100,10 @@ function SwypePayment({
|
|
|
1283
2100
|
opacity: 0.5,
|
|
1284
2101
|
cursor: "not-allowed"
|
|
1285
2102
|
};
|
|
1286
|
-
|
|
2103
|
+
({
|
|
1287
2104
|
...btnPrimary,
|
|
1288
|
-
background: "transparent",
|
|
1289
2105
|
color: tokens.textSecondary,
|
|
1290
|
-
border: `1px solid ${tokens.border}
|
|
1291
|
-
width: "auto",
|
|
1292
|
-
flex: "0 0 auto",
|
|
1293
|
-
padding: "14px 20px"
|
|
1294
|
-
};
|
|
2106
|
+
border: `1px solid ${tokens.border}`});
|
|
1295
2107
|
const errorStyle = {
|
|
1296
2108
|
background: tokens.errorBg,
|
|
1297
2109
|
border: `1px solid ${tokens.error}`,
|
|
@@ -1382,62 +2194,20 @@ function SwypePayment({
|
|
|
1382
2194
|
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnPrimary, onClick: login, children: "Connect to Swype" })
|
|
1383
2195
|
] }) });
|
|
1384
2196
|
}
|
|
1385
|
-
if (step === "select-source") {
|
|
1386
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
1387
|
-
stepBadge("Select payment source"),
|
|
1388
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle, children: "Choose a provider" }),
|
|
1389
|
-
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorStyle, children: error }),
|
|
1390
|
-
loadingData ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "24px 0", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { label: "Loading providers..." }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1391
|
-
accounts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1392
|
-
AccountWalletSelector,
|
|
1393
|
-
{
|
|
1394
|
-
accounts,
|
|
1395
|
-
selection: walletSelection,
|
|
1396
|
-
onSelect: (sel) => {
|
|
1397
|
-
setWalletSelection(sel);
|
|
1398
|
-
if (sel) setSelectedProviderId(null);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
) }),
|
|
1402
|
-
!walletSelection && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1403
|
-
"div",
|
|
1404
|
-
{
|
|
1405
|
-
style: {
|
|
1406
|
-
display: "flex",
|
|
1407
|
-
flexDirection: "column",
|
|
1408
|
-
gap: "8px",
|
|
1409
|
-
marginBottom: "20px"
|
|
1410
|
-
},
|
|
1411
|
-
children: providers.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1412
|
-
ProviderCard,
|
|
1413
|
-
{
|
|
1414
|
-
provider: p,
|
|
1415
|
-
selected: selectedProviderId === p.id,
|
|
1416
|
-
onClick: () => {
|
|
1417
|
-
setSelectedProviderId(p.id);
|
|
1418
|
-
setWalletSelection(null);
|
|
1419
|
-
}
|
|
1420
|
-
},
|
|
1421
|
-
p.id
|
|
1422
|
-
))
|
|
1423
|
-
}
|
|
1424
|
-
),
|
|
1425
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1426
|
-
"button",
|
|
1427
|
-
{
|
|
1428
|
-
style: sourceId ? btnPrimary : btnDisabled,
|
|
1429
|
-
disabled: !sourceId,
|
|
1430
|
-
onClick: () => {
|
|
1431
|
-
setError(null);
|
|
1432
|
-
setStep("enter-amount");
|
|
1433
|
-
},
|
|
1434
|
-
children: "Continue"
|
|
1435
|
-
}
|
|
1436
|
-
)
|
|
1437
|
-
] })
|
|
1438
|
-
] });
|
|
1439
|
-
}
|
|
1440
2197
|
if (step === "enter-amount") {
|
|
2198
|
+
const parsedAmount = parseFloat(amount);
|
|
2199
|
+
const canContinue = !isNaN(parsedAmount) && parsedAmount > 0;
|
|
2200
|
+
let maxSourceBalance = null;
|
|
2201
|
+
for (const acct of accounts) {
|
|
2202
|
+
for (const wallet of acct.wallets) {
|
|
2203
|
+
for (const source of wallet.sources) {
|
|
2204
|
+
const bal = source.balance.available.amount;
|
|
2205
|
+
if (maxSourceBalance === null || bal > maxSourceBalance) {
|
|
2206
|
+
maxSourceBalance = bal;
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
1441
2211
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
1442
2212
|
stepBadge("Enter amount"),
|
|
1443
2213
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle, children: "How much?" }),
|
|
@@ -1453,7 +2223,7 @@ function SwypePayment({
|
|
|
1453
2223
|
border: `1px solid ${tokens.border}`,
|
|
1454
2224
|
borderRadius: tokens.radius,
|
|
1455
2225
|
padding: "4px 14px 4px 4px",
|
|
1456
|
-
marginBottom: "
|
|
2226
|
+
marginBottom: "8px"
|
|
1457
2227
|
},
|
|
1458
2228
|
children: [
|
|
1459
2229
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1477,6 +2247,7 @@ function SwypePayment({
|
|
|
1477
2247
|
step: "0.01",
|
|
1478
2248
|
value: amount,
|
|
1479
2249
|
onChange: (e) => setAmount(e.target.value),
|
|
2250
|
+
placeholder: "0.00",
|
|
1480
2251
|
style: {
|
|
1481
2252
|
flex: 1,
|
|
1482
2253
|
background: "transparent",
|
|
@@ -1508,154 +2279,248 @@ function SwypePayment({
|
|
|
1508
2279
|
]
|
|
1509
2280
|
}
|
|
1510
2281
|
),
|
|
1511
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2282
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1512
2283
|
"div",
|
|
1513
2284
|
{
|
|
1514
2285
|
style: {
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
border: `1px solid ${tokens.border}`,
|
|
1520
|
-
borderRadius: tokens.radius,
|
|
1521
|
-
padding: "4px 14px 4px 4px",
|
|
1522
|
-
marginBottom: "20px"
|
|
2286
|
+
fontSize: "0.8rem",
|
|
2287
|
+
color: tokens.textMuted,
|
|
2288
|
+
marginBottom: "20px",
|
|
2289
|
+
paddingLeft: "2px"
|
|
1523
2290
|
},
|
|
1524
|
-
children: [
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
color: tokens.textMuted,
|
|
1532
|
-
paddingLeft: "10px",
|
|
1533
|
-
userSelect: "none"
|
|
1534
|
-
},
|
|
1535
|
-
children: "$"
|
|
1536
|
-
}
|
|
1537
|
-
),
|
|
1538
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1539
|
-
"input",
|
|
1540
|
-
{
|
|
1541
|
-
type: "number",
|
|
1542
|
-
min: "0",
|
|
1543
|
-
step: "1",
|
|
1544
|
-
placeholder: "Top up balance (optional)",
|
|
1545
|
-
value: topUpBalance,
|
|
1546
|
-
onChange: (e) => setTopUpBalance(e.target.value),
|
|
1547
|
-
style: {
|
|
1548
|
-
flex: 1,
|
|
1549
|
-
background: "transparent",
|
|
1550
|
-
border: "none",
|
|
1551
|
-
outline: "none",
|
|
1552
|
-
color: tokens.text,
|
|
1553
|
-
fontSize: "1rem",
|
|
1554
|
-
fontWeight: 600,
|
|
1555
|
-
fontFamily: "inherit",
|
|
1556
|
-
padding: "10px 0"
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1559
|
-
),
|
|
1560
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1561
|
-
"span",
|
|
1562
|
-
{
|
|
1563
|
-
style: {
|
|
1564
|
-
fontSize: "0.75rem",
|
|
1565
|
-
fontWeight: 600,
|
|
1566
|
-
color: tokens.textMuted,
|
|
1567
|
-
background: tokens.bgHover,
|
|
1568
|
-
padding: "4px 10px",
|
|
1569
|
-
borderRadius: "6px",
|
|
1570
|
-
whiteSpace: "nowrap"
|
|
1571
|
-
},
|
|
1572
|
-
children: "USD"
|
|
1573
|
-
}
|
|
1574
|
-
)
|
|
1575
|
-
]
|
|
2291
|
+
children: loadingData ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading balance..." }) : maxSourceBalance !== null && maxSourceBalance > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2292
|
+
"Available: ",
|
|
2293
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: tokens.textSecondary }, children: [
|
|
2294
|
+
"$",
|
|
2295
|
+
maxSourceBalance.toFixed(2)
|
|
2296
|
+
] })
|
|
2297
|
+
] }) : null
|
|
1576
2298
|
}
|
|
1577
2299
|
),
|
|
1578
2300
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1579
|
-
"
|
|
2301
|
+
"button",
|
|
1580
2302
|
{
|
|
1581
|
-
style:
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
2303
|
+
style: canContinue ? btnPrimary : btnDisabled,
|
|
2304
|
+
disabled: !canContinue,
|
|
2305
|
+
onClick: () => {
|
|
2306
|
+
setError(null);
|
|
2307
|
+
setStep("ready");
|
|
1586
2308
|
},
|
|
1587
|
-
children: "
|
|
2309
|
+
children: "Continue"
|
|
1588
2310
|
}
|
|
1589
|
-
)
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
2311
|
+
)
|
|
2312
|
+
] });
|
|
2313
|
+
}
|
|
2314
|
+
if (step === "ready") {
|
|
2315
|
+
const parsedAmount = parseFloat(amount);
|
|
2316
|
+
const canPay = !isNaN(parsedAmount) && parsedAmount > 0 && !!sourceId && !loadingData;
|
|
2317
|
+
const noAccounts = !loadingData && accounts.length === 0;
|
|
2318
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
2319
|
+
stepBadge("Review & pay"),
|
|
2320
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorStyle, children: error }),
|
|
2321
|
+
loadingData ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "24px 0", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { label: "Loading..." }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2322
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2323
|
+
"div",
|
|
2324
|
+
{
|
|
2325
|
+
style: {
|
|
2326
|
+
textAlign: "center",
|
|
2327
|
+
marginBottom: "20px"
|
|
2328
|
+
},
|
|
2329
|
+
children: [
|
|
1605
2330
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1606
|
-
"
|
|
2331
|
+
"div",
|
|
1607
2332
|
{
|
|
1608
2333
|
style: {
|
|
1609
|
-
|
|
1610
|
-
|
|
2334
|
+
fontSize: "2rem",
|
|
2335
|
+
fontWeight: 700,
|
|
2336
|
+
color: tokens.text,
|
|
2337
|
+
lineHeight: 1.2
|
|
1611
2338
|
},
|
|
1612
2339
|
children: [
|
|
1613
|
-
|
|
1614
|
-
"
|
|
1615
|
-
destination.address.slice(-4)
|
|
2340
|
+
"$",
|
|
2341
|
+
parsedAmount > 0 ? parsedAmount.toFixed(2) : "0.00"
|
|
1616
2342
|
]
|
|
1617
2343
|
}
|
|
2344
|
+
),
|
|
2345
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2346
|
+
"button",
|
|
2347
|
+
{
|
|
2348
|
+
onClick: () => setStep("enter-amount"),
|
|
2349
|
+
style: {
|
|
2350
|
+
background: "transparent",
|
|
2351
|
+
border: "none",
|
|
2352
|
+
cursor: "pointer",
|
|
2353
|
+
color: tokens.textMuted,
|
|
2354
|
+
fontSize: "0.75rem",
|
|
2355
|
+
fontFamily: "inherit",
|
|
2356
|
+
outline: "none",
|
|
2357
|
+
padding: "4px 8px",
|
|
2358
|
+
marginTop: "4px"
|
|
2359
|
+
},
|
|
2360
|
+
children: "Change amount"
|
|
2361
|
+
}
|
|
1618
2362
|
)
|
|
1619
|
-
]
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
1625
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Source" }),
|
|
1626
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600 }, children: walletSelection ? `${walletSelection.walletName} (${walletSelection.chainName})` : providers.find((p) => p.id === selectedProviderId)?.name ?? "Provider" })
|
|
1627
|
-
] })
|
|
1628
|
-
]
|
|
1629
|
-
}
|
|
1630
|
-
),
|
|
1631
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "10px" }, children: [
|
|
1632
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1633
|
-
"button",
|
|
2363
|
+
]
|
|
2364
|
+
}
|
|
2365
|
+
),
|
|
2366
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2367
|
+
"div",
|
|
1634
2368
|
{
|
|
1635
|
-
style:
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
2369
|
+
style: {
|
|
2370
|
+
fontSize: "0.825rem",
|
|
2371
|
+
color: tokens.textSecondary,
|
|
2372
|
+
marginBottom: "16px",
|
|
2373
|
+
padding: "12px 14px",
|
|
2374
|
+
background: tokens.bgInput,
|
|
2375
|
+
borderRadius: tokens.radius,
|
|
2376
|
+
lineHeight: 1.7
|
|
1639
2377
|
},
|
|
1640
|
-
children:
|
|
2378
|
+
children: [
|
|
2379
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2380
|
+
"div",
|
|
2381
|
+
{
|
|
2382
|
+
style: { display: "flex", justifyContent: "space-between" },
|
|
2383
|
+
children: [
|
|
2384
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "To" }),
|
|
2385
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2386
|
+
"span",
|
|
2387
|
+
{
|
|
2388
|
+
style: {
|
|
2389
|
+
fontFamily: '"SF Mono", "Fira Code", monospace',
|
|
2390
|
+
fontSize: "0.8rem"
|
|
2391
|
+
},
|
|
2392
|
+
children: [
|
|
2393
|
+
destination.address.slice(0, 6),
|
|
2394
|
+
"...",
|
|
2395
|
+
destination.address.slice(-4)
|
|
2396
|
+
]
|
|
2397
|
+
}
|
|
2398
|
+
)
|
|
2399
|
+
]
|
|
2400
|
+
}
|
|
2401
|
+
),
|
|
2402
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2403
|
+
"div",
|
|
2404
|
+
{
|
|
2405
|
+
style: { display: "flex", justifyContent: "space-between" },
|
|
2406
|
+
children: [
|
|
2407
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Token" }),
|
|
2408
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600 }, children: destination.token.symbol })
|
|
2409
|
+
]
|
|
2410
|
+
}
|
|
2411
|
+
),
|
|
2412
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2413
|
+
"div",
|
|
2414
|
+
{
|
|
2415
|
+
style: {
|
|
2416
|
+
display: "flex",
|
|
2417
|
+
justifyContent: "space-between",
|
|
2418
|
+
alignItems: "center"
|
|
2419
|
+
},
|
|
2420
|
+
children: [
|
|
2421
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "From" }),
|
|
2422
|
+
noAccounts ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500, color: tokens.textMuted }, children: "New account" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2423
|
+
AccountDropdown,
|
|
2424
|
+
{
|
|
2425
|
+
accounts,
|
|
2426
|
+
selectedAccountId,
|
|
2427
|
+
selectedWalletId,
|
|
2428
|
+
onSelect: (id) => {
|
|
2429
|
+
setSelectedAccountId(id);
|
|
2430
|
+
setSelectedWalletId(null);
|
|
2431
|
+
setConnectingNewAccount(false);
|
|
2432
|
+
setSelectedProviderId(null);
|
|
2433
|
+
},
|
|
2434
|
+
onWalletSelect: (accountId, walletId) => {
|
|
2435
|
+
setSelectedAccountId(accountId);
|
|
2436
|
+
setSelectedWalletId(walletId);
|
|
2437
|
+
setConnectingNewAccount(false);
|
|
2438
|
+
setSelectedProviderId(null);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
)
|
|
2442
|
+
]
|
|
2443
|
+
}
|
|
2444
|
+
)
|
|
2445
|
+
]
|
|
1641
2446
|
}
|
|
1642
2447
|
),
|
|
2448
|
+
noAccounts && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "16px" }, children: [
|
|
2449
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2450
|
+
"label",
|
|
2451
|
+
{
|
|
2452
|
+
style: {
|
|
2453
|
+
display: "block",
|
|
2454
|
+
fontSize: "0.8rem",
|
|
2455
|
+
color: tokens.textMuted,
|
|
2456
|
+
marginBottom: "8px",
|
|
2457
|
+
fontWeight: 500,
|
|
2458
|
+
textTransform: "uppercase",
|
|
2459
|
+
letterSpacing: "0.05em"
|
|
2460
|
+
},
|
|
2461
|
+
children: "Connect a wallet"
|
|
2462
|
+
}
|
|
2463
|
+
),
|
|
2464
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2465
|
+
"div",
|
|
2466
|
+
{
|
|
2467
|
+
style: {
|
|
2468
|
+
display: "flex",
|
|
2469
|
+
flexDirection: "column",
|
|
2470
|
+
gap: "8px"
|
|
2471
|
+
},
|
|
2472
|
+
children: providers.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2473
|
+
ProviderCard,
|
|
2474
|
+
{
|
|
2475
|
+
provider: p,
|
|
2476
|
+
selected: selectedProviderId === p.id,
|
|
2477
|
+
onClick: () => {
|
|
2478
|
+
setSelectedProviderId(p.id);
|
|
2479
|
+
setSelectedAccountId(null);
|
|
2480
|
+
setConnectingNewAccount(false);
|
|
2481
|
+
}
|
|
2482
|
+
},
|
|
2483
|
+
p.id
|
|
2484
|
+
))
|
|
2485
|
+
}
|
|
2486
|
+
)
|
|
2487
|
+
] }),
|
|
1643
2488
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1644
2489
|
"button",
|
|
1645
2490
|
{
|
|
1646
|
-
style:
|
|
1647
|
-
disabled: !
|
|
2491
|
+
style: canPay ? btnPrimary : btnDisabled,
|
|
2492
|
+
disabled: !canPay,
|
|
1648
2493
|
onClick: handlePay,
|
|
1649
2494
|
children: [
|
|
1650
2495
|
"Pay $",
|
|
1651
|
-
|
|
2496
|
+
parsedAmount > 0 ? parsedAmount.toFixed(2) : "0.00"
|
|
1652
2497
|
]
|
|
1653
2498
|
}
|
|
2499
|
+
),
|
|
2500
|
+
!noAccounts && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2501
|
+
AdvancedSettings,
|
|
2502
|
+
{
|
|
2503
|
+
settings: advancedSettings,
|
|
2504
|
+
onChange: setAdvancedSettings,
|
|
2505
|
+
chains,
|
|
2506
|
+
providers,
|
|
2507
|
+
onConnectNewAccount: handleConnectNewAccount,
|
|
2508
|
+
connectingNewAccount
|
|
2509
|
+
}
|
|
1654
2510
|
)
|
|
1655
2511
|
] })
|
|
1656
2512
|
] });
|
|
1657
2513
|
}
|
|
1658
2514
|
if (step === "processing") {
|
|
2515
|
+
if (authExecutor.pendingAllowanceSelection) {
|
|
2516
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2517
|
+
AllowanceSelector,
|
|
2518
|
+
{
|
|
2519
|
+
action: authExecutor.pendingAllowanceSelection,
|
|
2520
|
+
onSelect: authExecutor.resolveAllowanceSelection
|
|
2521
|
+
}
|
|
2522
|
+
) });
|
|
2523
|
+
}
|
|
1659
2524
|
const statusLabel = creatingTransfer ? "Creating transfer..." : mobileFlow ? "Waiting for authorization..." : authExecutor.executing ? "Authorizing..." : polling.isPolling ? "Processing payment..." : "Please wait...";
|
|
1660
2525
|
const statusDescription = creatingTransfer ? "Setting up your transfer..." : mobileFlow ? "Complete the authorization in your wallet app, then return here." : authExecutor.executing ? "Complete the wallet prompts to authorize this payment." : polling.isPolling ? "Your payment is being processed. This usually takes a few moments." : "Hang tight...";
|
|
1661
2526
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "16px 0" }, children: [
|
|
@@ -1840,6 +2705,7 @@ exports.lightTheme = lightTheme;
|
|
|
1840
2705
|
exports.swypeApi = api_exports;
|
|
1841
2706
|
exports.useAuthorizationExecutor = useAuthorizationExecutor;
|
|
1842
2707
|
exports.useSwypeConfig = useSwypeConfig;
|
|
2708
|
+
exports.useSwypeDepositAmount = useSwypeDepositAmount;
|
|
1843
2709
|
exports.useTransferPolling = useTransferPolling;
|
|
1844
2710
|
//# sourceMappingURL=index.cjs.map
|
|
1845
2711
|
//# sourceMappingURL=index.cjs.map
|