@layerswap/widget 1.2.1 → 1.2.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/esm/components/Common/CountDownTimer.js +4 -1
- package/dist/esm/components/Common/ImageWithFallback.js +3 -3
- package/dist/esm/components/Common/Sceletons.js +3 -4
- package/dist/esm/components/Input/Amount/MinMax.js +7 -4
- package/dist/esm/components/Input/Amount/ReceiveAmount.js +1 -5
- package/dist/esm/components/Input/Amount/helpers.js +3 -2
- package/dist/esm/components/Input/Amount/index.js +1 -1
- package/dist/esm/components/Input/NumericInput.js +6 -11
- package/dist/esm/components/Menu/index.js +8 -2
- package/dist/esm/components/Pages/Swap/Withdraw/index.js +2 -2
- package/dist/esm/components/Pages/SwapHistory/SwapDetailsComponent.js +2 -16
- package/dist/esm/components/Widget/Index.js +1 -1
- package/dist/esm/context/swap.js +2 -2
- package/dist/esm/hooks/useConnectors.js +1 -8
- package/dist/esm/hooks/useSwapHistoryData.js +96 -3
- package/dist/index.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/components/Buttons/iconButton.d.ts.map +1 -1
- package/dist/types/components/Common/CountDownTimer.d.ts.map +1 -1
- package/dist/types/components/Common/ImageWithFallback.d.ts.map +1 -1
- package/dist/types/components/Common/Sceletons.d.ts.map +1 -1
- package/dist/types/components/Input/Amount/MinMax.d.ts.map +1 -1
- package/dist/types/components/Input/Amount/ReceiveAmount.d.ts.map +1 -1
- package/dist/types/components/Input/Amount/helpers.d.ts +1 -0
- package/dist/types/components/Input/Amount/helpers.d.ts.map +1 -1
- package/dist/types/components/Input/Amount/index.d.ts.map +1 -1
- package/dist/types/components/Input/NumericInput.d.ts +0 -1
- package/dist/types/components/Input/NumericInput.d.ts.map +1 -1
- package/dist/types/components/Menu/index.d.ts.map +1 -1
- package/dist/types/components/Pages/Swap/Withdraw/index.d.ts +4 -1
- package/dist/types/components/Pages/Swap/Withdraw/index.d.ts.map +1 -1
- package/dist/types/components/Pages/SwapHistory/SwapDetailsComponent.d.ts.map +1 -1
- package/dist/types/context/swap.d.ts +3 -2
- package/dist/types/context/swap.d.ts.map +1 -1
- package/dist/types/hooks/useConnectors.d.ts.map +1 -1
- package/dist/types/hooks/useSwapHistoryData.d.ts +1 -1
- package/dist/types/hooks/useSwapHistoryData.d.ts.map +1 -1
- package/dist/types/types/wallet.d.ts +2 -2
- package/dist/types/types/wallet.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -2,13 +2,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
import { SwapStatus } from "../../Models/SwapStatus";
|
|
4
4
|
import { TransactionType } from "../../lib/apiClients/layerSwapApiClient";
|
|
5
|
+
import { useSwapTransactionStore } from "../../stores/swapTransactionStore";
|
|
5
6
|
const CountdownTimer = ({ initialTime, swapDetails, onThresholdChange }) => {
|
|
7
|
+
const { swapTransactions } = useSwapTransactionStore();
|
|
6
8
|
const [elapsedTimer, setElapsedTimer] = useState(0);
|
|
7
9
|
const [thresholdElapsed, setThresholdElapsed] = useState(false);
|
|
8
10
|
const swapInputTransaction = swapDetails?.transactions?.find(t => t.type === TransactionType.Input);
|
|
11
|
+
const storedWalletTransaction = swapTransactions?.[swapDetails?.id];
|
|
9
12
|
useEffect(() => {
|
|
10
13
|
// Start timer immediately when component renders
|
|
11
|
-
const startTime = swapInputTransaction?.timestamp ? new Date(swapInputTransaction.timestamp).getTime() : Date.now();
|
|
14
|
+
const startTime = swapInputTransaction?.timestamp ? new Date(swapInputTransaction.timestamp).getTime() : storedWalletTransaction?.timestamp ? new Date(storedWalletTransaction.timestamp).getTime() : Date.now();
|
|
12
15
|
const timer = setInterval(() => {
|
|
13
16
|
const currentTime = new Date();
|
|
14
17
|
const elapsedTime = currentTime.getTime() - startTime;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { forwardRef, useEffect, useState } from "react";
|
|
3
|
+
import { forwardRef, useCallback, useEffect, useState } from "react";
|
|
4
4
|
import LogoPlaceholder from "../Icons/LogoPlaceholder";
|
|
5
5
|
export const ImageWithFallback = forwardRef(({ src, ...props }, ref) => {
|
|
6
6
|
const [imgSrc, setImgSrc] = useState(src);
|
|
@@ -9,9 +9,9 @@ export const ImageWithFallback = forwardRef(({ src, ...props }, ref) => {
|
|
|
9
9
|
setImgSrc(src);
|
|
10
10
|
setHasError(false);
|
|
11
11
|
}, [src]);
|
|
12
|
-
const handleError = () => {
|
|
12
|
+
const handleError = useCallback(() => {
|
|
13
13
|
setHasError(true);
|
|
14
|
-
};
|
|
14
|
+
}, [setHasError]);
|
|
15
15
|
if (hasError) {
|
|
16
16
|
return _jsx(LogoPlaceholder, { ...props });
|
|
17
17
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { ChevronRight
|
|
3
|
-
import BackgroundField from "./backgroundField";
|
|
2
|
+
import { ChevronRight } from "lucide-react";
|
|
4
3
|
import { classNames } from "../utils/classNames";
|
|
5
4
|
export const SwapHistoryComponentSceleton = () => {
|
|
6
5
|
return _jsx("div", { className: "animate-pulse", children: _jsx("div", { className: " mb-10 ", children: _jsx("div", { className: "-mx-4 mt-10 sm:-mx-6 md:mx-0 md:rounded-lg ", children: _jsxs("table", { className: "min-w-full divide-y divide-secondary-500", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", className: "py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-500 sm:pl-6", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "hidden lg:block", children: _jsx("div", { className: "h-2 w-8 bg-slate-700 rounded-sm col-span-1" }) }) }) }), _jsx("th", { scope: "col", className: "hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-500 lg:table-cell", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-8 bg-slate-700 rounded-sm col-span-1" }) }) }), _jsx("th", { scope: "col", className: "px-3 py-3.5 text-left text-sm font-semibold text-gray-500 ", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-8 bg-slate-700 rounded-sm col-span-1" }) }) }), _jsx("th", { scope: "col", className: "hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-500 lg:table-cell", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-16 bg-slate-700 rounded-sm col-span-1" }) }) }), _jsx("th", { scope: "col", className: "hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-500 lg:table-cell", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-16 bg-slate-700 rounded-sm col-span-1" }) }) }), _jsx("th", { scope: "col", className: "hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-500 lg:table-cell", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-8 bg-slate-700 rounded-sm col-span-1" }) }) }), _jsx("th", { scope: "col", className: "relative py-3.5 pl-3 pr-4 sm:pr-6", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-8 bg-slate-700 rounded-sm col-span-1" }) }) }), _jsx("th", { scope: "col", className: "relative py-3.5 pl-3 pr-4 sm:pr-6" })] }) }), _jsx("tbody", { children: [...Array(5)]?.map((item, index) => (_jsxs("tr", { children: [_jsxs("td", { className: classNames(index === 0 ? '' : 'border-t border-secondary-500', 'relative py-4 pl-4 sm:pl-6 pr-3 text-sm'), children: [_jsx("div", { className: "text-primary-text hidden lg:block", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-16 bg-slate-700 rounded-sm col-span-1" }) }) }), index !== 0 ? _jsx("div", { className: "absolute right-0 left-6 -top-px h-px bg-secondary-500" }) : null] }), _jsx("td", { className: classNames(index === 0 ? '' : 'border-t border-secondary-500', 'hidden px-3 py-3.5 text-sm text-primary-text lg:table-cell'), children: _jsxs("div", { className: "flex space-x-2", children: [_jsx("div", { className: "rounded-full bg-slate-700 h-4 w-4" }), _jsx("div", { className: "grid grid-cols-4 items-center", children: _jsx("div", { className: "h-2 w-16 bg-slate-700 rounded-sm col-span-3" }) })] }) }), _jsx("td", { className: classNames(index === 0 ? '' : 'border-t border-secondary-500', 'px-3 py-3.5 text-sm text-primary-text table-cell'), children: _jsxs("div", { className: "flex space-x-2", children: [_jsx("div", { className: "rounded-full bg-slate-700 h-4 w-4" }), _jsx("div", { className: "grid grid-cols-4 items-center", children: _jsx("div", { className: "h-2 w-16 bg-slate-700 rounded-sm col-span-3" }) })] }) }), _jsx("td", { className: classNames(index === 0 ? '' : 'border-t border-secondary-500', 'hidden px-3 py-3.5 text-sm text-primary-text lg:table-cell'), children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-16 bg-slate-700 rounded-sm col-span-1" }) }) }), _jsx("td", { className: classNames(index === 0 ? '' : 'border-t border-secondary-500', 'relative px-3 py-3.5 text-sm text-primary-text'), children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx("div", { className: "h-2 w-16 bg-slate-700 rounded-sm col-span-1" }) }) }), _jsx("td", { className: classNames(index === 0 ? '' : 'border-t border-secondary-500', 'px-3 py-3.5 text-sm text-primary-text hidden lg:table-cell'), children: _jsxs("div", { className: "flex space-x-2", children: [_jsx("div", { className: "rounded-sm bg-slate-700 h-2 w-2" }), _jsx("div", { className: "grid grid-cols-1 items-center", children: _jsx("div", { className: "h-2 w-16 bg-slate-700 rounded-sm col-span-1" }) })] }) }), _jsx("td", { className: classNames(index === 0 ? '' : 'border-t border-secondary-500', 'px-3 py-3.5 text-sm text-primary-text hidden lg:table-cell'), children: _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx("div", { className: "h-2 w-12 bg-slate-700 rounded-sm col-span-1" }), _jsx("div", { className: "h-2 w-8 bg-slate-700 rounded-sm col-span-1" })] }) }), _jsx("td", { className: classNames(index === 0 ? '' : 'border-t border-secondary-500', 'px-3 py-3.5 text-sm text-primary-text hidden lg:table-cell'), children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx(ChevronRight, { className: "h-5 w-5 text-slate-700" }) }) })] }, index))) })] }) }) }) });
|
|
@@ -15,8 +14,8 @@ export const ExchangesComponentSceleton = () => {
|
|
|
15
14
|
return _jsx(_Fragment, { children: [...Array(12)]?.map((item, index) => _jsx("div", { className: "animate-pulse bg-secondary-700 select-none rounded-lg py-5 px-3", children: _jsxs("div", { className: "flex justify-between space-x-4 md:space-x-16 px-3", children: [_jsxs("div", { className: "flex space-x-2", children: [_jsx("div", { className: "rounded-md bg-slate-700 h-8 w-8" }), _jsx("div", { className: "grid grid-cols-5", children: _jsx("div", { className: "h-2 w-20 bg-slate-700 rounded-sm col-span-3" }) })] }), _jsx("div", { className: "rounded-sm bg-slate-700 h-8 w-20 place-self-end py-3 px-4" })] }) }, index)) });
|
|
16
15
|
};
|
|
17
16
|
export const RewardsComponentSceleton = () => {
|
|
18
|
-
return (_jsxs("div", { className: "space-y-5", children: [_jsxs("div", { className: "space-y-
|
|
17
|
+
return (_jsxs("div", { className: "space-y-5", children: [_jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: "rounded-md w-full bg-gray-500 animate-pulse h-12" }), _jsx("div", { className: "rounded-lg w-full h-[calc(5rem+2px)] bg-gray-500 animate-pulse" })] }), _jsx("div", { className: "rounded-lg bg-secondary-700 animate-pulse h-[calc(5.75rem+2px)] w-full", children: _jsxs("div", { className: "relative w-full p-3", children: [_jsx("div", { className: "flex justify-start", children: _jsx("div", { className: "h-5 w-11 bg-gray-500 animate-pulse rounded-md" }) }), _jsx("div", { className: "flex items-center justify-between w-full mt-1 space-x-2", children: _jsxs("div", { className: "flex flex-col w-full gap-2", children: [_jsx("div", { className: "relative h-4 w-full overflow-hidden rounded-full bg-primary animate-pulse" }), _jsx("div", { className: "h-5 w-11 bg-gray-500 animate-pulse rounded-md" })] }) })] }) })] }));
|
|
19
18
|
};
|
|
20
19
|
export const RewardsComponentLeaderboardSceleton = () => {
|
|
21
|
-
return (_jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "flex justify-start", children: _jsx("div", { className: "rounded-md w-
|
|
20
|
+
return (_jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "flex justify-start", children: _jsx("div", { className: "rounded-md w-25 bg-gray-500 h-5 animate-pulse" }) }), _jsx("div", { className: "rounded-md w-full bg-gray-500 animate-pulse h-10" }), _jsx("div", { className: "animate-pulse rounded-lg bg-gray-500 w-full h-[calc(9.75rem+2px)]" })] }));
|
|
22
21
|
};
|
|
@@ -21,15 +21,18 @@ const MinMax = (props) => {
|
|
|
21
21
|
const gasAmount = gasData?.gas || 0;
|
|
22
22
|
const native_currency = gasData?.token || from?.token;
|
|
23
23
|
const shouldPayGasWithTheToken = (native_currency?.symbol === fromCurrency?.symbol) || !native_currency;
|
|
24
|
+
const fallbackAmount = useMemo(() => {
|
|
25
|
+
return fromCurrency.price_in_usd > 0 ? 0.01 / fromCurrency.price_in_usd : 0.01;
|
|
26
|
+
}, [fromCurrency.price_in_usd]);
|
|
24
27
|
let maxAllowedAmount = useMemo(() => {
|
|
25
|
-
return resolveMaxAllowedAmount({ fromCurrency, limitsMaxAmount, walletBalance, gasAmount, native_currency, depositMethod }) || 0;
|
|
26
|
-
}, [fromCurrency, limitsMinAmount, limitsMaxAmount, walletBalance, gasAmount, native_currency, depositMethod]);
|
|
28
|
+
return resolveMaxAllowedAmount({ fromCurrency, limitsMaxAmount, walletBalance, gasAmount, native_currency, depositMethod, fallbackAmount }) || 0;
|
|
29
|
+
}, [fromCurrency, limitsMinAmount, limitsMaxAmount, walletBalance, gasAmount, native_currency, depositMethod, fallbackAmount]);
|
|
27
30
|
const minAmount = useMemo(() => {
|
|
28
31
|
if (walletBalance && walletBalance.amount !== undefined && limitsMinAmount !== undefined) {
|
|
29
32
|
return Number(walletBalance.amount) < limitsMinAmount ? Number(walletBalance.amount) : limitsMinAmount;
|
|
30
33
|
}
|
|
31
|
-
return limitsMinAmount ||
|
|
32
|
-
}, [walletBalance, limitsMinAmount,
|
|
34
|
+
return limitsMinAmount || fallbackAmount;
|
|
35
|
+
}, [walletBalance, limitsMinAmount, fallbackAmount]);
|
|
33
36
|
const halfOfBalance = (walletBalance?.amount || maxAllowedAmount) ? (walletBalance?.amount || maxAllowedAmount) / 2 : 0;
|
|
34
37
|
const handleSetValue = (value) => {
|
|
35
38
|
mutateBalances();
|
|
@@ -2,13 +2,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import NumberFlow from "@number-flow/react";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { PriceImpact } from "./PriceImpact";
|
|
5
|
-
import { Tooltip, TooltipContent, TooltipTrigger } from "../../../components/shadcn/tooltip";
|
|
6
5
|
export const ReceiveAmount = ({ destination_token, fee, isFeeLoading }) => {
|
|
7
6
|
const receive_amount = fee?.quote.receive_amount;
|
|
8
7
|
const receiveAmountInUsd = receive_amount && destination_token && fee.quote?.destination_token?.price_in_usd ? (receive_amount * fee.quote.destination_token.price_in_usd).toFixed(2) : undefined;
|
|
9
8
|
const quote = fee?.quote;
|
|
10
|
-
|
|
11
|
-
? `${receive_amount} ${destination_token.symbol}`
|
|
12
|
-
: undefined;
|
|
13
|
-
return (_jsx(_Fragment, { children: _jsxs("div", { className: "flex-col w-full flex min-w-0 font-normal border-0 text-[28px] leading-7 text-primary-text relative truncate", children: [_jsx("div", { className: "w-full flex items-center justify-start relative", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("div", { className: clsx("w-full flex items-center py-[3px]", { "animate-pulse-stronger": isFeeLoading }, { "text-secondary-text": !receive_amount }), children: _jsx(NumberFlow, { value: receive_amount || 0, trend: 0, format: { maximumFractionDigits: fee?.quote.destination_token?.decimals || 2 } }) }) }), fullAmountText && (_jsx(TooltipContent, { className: "bg-secondary-300! border-secondary-300! text-primary-text!", children: _jsx("p", { children: fullAmountText }) }))] }) }), _jsxs("div", { className: "flex items-baseline space-x-2 h-5", children: [_jsx("span", { className: "text-base leading-5 font-medium text-secondary-text h-5", children: _jsx(NumberFlow, { className: "p-0", value: Number(receiveAmountInUsd || 0), prefix: "$", format: { maximumFractionDigits: receiveAmountInUsd ? 2 : 0 }, trend: 0 }) }), _jsx(PriceImpact, { className: "h-5 text-base leading-5", quote: quote, refuel: fee?.refuel })] })] }) }));
|
|
9
|
+
return (_jsx(_Fragment, { children: _jsxs("div", { className: "flex-col w-full flex min-w-0 font-normal border-0 text-[28px] leading-7 text-primary-text relative truncate", children: [_jsx("div", { className: "w-full flex items-center justify-start relative", children: _jsx("div", { className: clsx("w-full flex items-center py-[3px] pr-3", { "animate-pulse-stronger": isFeeLoading }, { "text-secondary-text": !receive_amount }), children: _jsx(NumberFlow, { value: receive_amount || 0, trend: 0, format: { maximumFractionDigits: fee?.quote.destination_token?.decimals || 2 } }) }) }), _jsxs("div", { className: "flex items-baseline space-x-2 h-5", children: [_jsx("span", { className: "text-base leading-5 font-medium text-secondary-text h-5", children: _jsx(NumberFlow, { className: "p-0", value: Number(receiveAmountInUsd || 0), prefix: "$", format: { maximumFractionDigits: receiveAmountInUsd ? 2 : 0 }, trend: 0 }) }), _jsx(PriceImpact, { className: "h-5 text-base leading-5", quote: quote, refuel: fee?.refuel })] })] }) }));
|
|
14
10
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export const resolveMaxAllowedAmount = (props) => {
|
|
2
|
-
const { limitsMaxAmount, walletBalance, gasAmount, fromCurrency, native_currency, depositMethod } = props;
|
|
2
|
+
const { limitsMaxAmount, walletBalance, gasAmount, fromCurrency, native_currency, depositMethod, fallbackAmount } = props;
|
|
3
3
|
if (!walletBalance || isNaN(Number(walletBalance.amount)) || depositMethod !== 'wallet')
|
|
4
4
|
return limitsMaxAmount;
|
|
5
5
|
const shouldPayGasWithTheToken = Number(walletBalance.amount) > 0 && (native_currency?.symbol === fromCurrency?.symbol) || !native_currency;
|
|
6
6
|
const payableAmount = Number(walletBalance.amount) - gasAmount;
|
|
7
7
|
if (!shouldPayGasWithTheToken)
|
|
8
8
|
return isNaN(Number(walletBalance.amount)) ? 0 : Number(walletBalance.amount);
|
|
9
|
-
|
|
9
|
+
const res = Number(Number(payableAmount).toFixed(fromCurrency?.decimals));
|
|
10
|
+
return res <= 0 ? fallbackAmount : res;
|
|
10
11
|
};
|
|
@@ -38,7 +38,7 @@ const AmountField = forwardRef(function AmountField({ usdPosition = "bottom", ac
|
|
|
38
38
|
const disabled = Boolean(fromExchange && !toCurrency);
|
|
39
39
|
return (_jsx(_Fragment, { children: _jsxs("div", { className: clsx("flex flex-col bg-secondary-500 space-y-0.5 relative w-full group", className, {
|
|
40
40
|
'focus-within:[&_.usd-suffix]:invisible': usdPosition === "right"
|
|
41
|
-
}), children: [_jsx(NumericInput, { disabled: disabled, placeholder: placeholder, step: isNaN(step) ? 0.01 : step, name: name, ref: amountRef, precision: fromCurrency?.precision, tempValue: actionValue,
|
|
41
|
+
}), children: [_jsx(NumericInput, { disabled: disabled, placeholder: placeholder, step: isNaN(step) ? 0.01 : step, name: name, ref: amountRef, precision: fromCurrency?.precision, tempValue: actionValue, className: "w-full text-[28px] leading-[34px] rounded-xl text-primary-text focus:outline-none focus:border-none focus:ring-0 duration-300 ease-in-out bg-secondary-500! font-normal! group-[.exchange-amount-field]:text-xl group-[.exchange-amount-field]:px-2.5 group-[.exchange-amount-field]:pb-2 group-[.exchange-amount-field]:pr-2 group-[.exchange-amount-field]:bg-secondary-300! px-0 truncate", onChange: e => {
|
|
42
42
|
/^[0-9]*[.,]?[0-9]*$/.test(e.target.value) && handleChange(e);
|
|
43
43
|
} }), _jsx("div", { className: clsx("usd-suffix text-base group-[.exchange-amount-field]:text-sm leading-5 font-medium text-secondary-text pointer-events-none", {
|
|
44
44
|
"absolute bottom-[11px]": usdPosition === "right",
|
|
@@ -3,9 +3,8 @@ import { useField, useFormikContext } from "formik";
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
import { classNames } from '../utils/classNames';
|
|
5
5
|
import { isScientific } from "../utils/RoundDecimals";
|
|
6
|
-
import { Tooltip, TooltipContent, TooltipTrigger } from "../../components/shadcn/tooltip";
|
|
7
6
|
// Use with Formik
|
|
8
|
-
const NumericInput = forwardRef(function NumericInput({ label, disabled, tempValue, placeholder, minLength, maxLength, precision, step, name, className, children, onChange, onFocus, onBlur
|
|
7
|
+
const NumericInput = forwardRef(function NumericInput({ label, disabled, tempValue, placeholder, minLength, maxLength, precision, step, name, className, children, onChange, onFocus, onBlur }, ref) {
|
|
9
8
|
const { handleChange } = useFormikContext();
|
|
10
9
|
const [field] = useField(name);
|
|
11
10
|
const formattedTempValue = Number(tempValue) >= 0 ? isScientific(tempValue)
|
|
@@ -14,16 +13,12 @@ const NumericInput = forwardRef(function NumericInput({ label, disabled, tempVal
|
|
|
14
13
|
: '')
|
|
15
14
|
: tempValue?.toString()
|
|
16
15
|
: '';
|
|
17
|
-
const displayValue = !isNaN(Number(tempValue)) ? formattedTempValue : field.value;
|
|
18
|
-
const fullTooltipText = displayValue && Number(displayValue) > 0
|
|
19
|
-
? `${displayValue}${tokenSymbol ? ` ${tokenSymbol}` : ''}`
|
|
20
|
-
: undefined;
|
|
21
16
|
return _jsxs("div", { children: [label &&
|
|
22
|
-
_jsx("label", { htmlFor: name, className: "block font-semibold text-secondary-text text-sm mb-1.5 w-full", children: label }), _jsxs(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
_jsx("label", { htmlFor: name, className: "block font-semibold text-secondary-text text-sm mb-1.5 w-full", children: label }), _jsxs("div", { className: "flex relative w-full", children: [!isNaN(Number(tempValue)) &&
|
|
18
|
+
_jsx("span", { className: classNames('py-2 flex text-secondary-text/45 items-center h-12 leading-4 bg-secondary-700 min-w-0 rounded-lg font-semibold border-0 ', className), ref: ref, children: _jsx("span", { children: formattedTempValue }) }), isNaN(Number(tempValue)) &&
|
|
19
|
+
_jsx("input", { ...field, inputMode: "decimal", autoComplete: "off", disabled: disabled, placeholder: placeholder, autoCorrect: "off", minLength: minLength, maxLength: maxLength, onInput: (event) => { replaceComma(event); limitDecimalPlaces(event, precision); }, onFocus: onFocus, onBlur: onBlur, type: "text", step: step, name: name, id: name, ref: ref, className: classNames('disabled:cursor-not-allowed h-12 leading-4 border-secondary-500 placeholder:text-secondary-text bg-secondary-700 focus:ring-primary focus:border-primary block min-w-0 rounded-lg font-semibold border-0', className), onChange: onChange ? onChange : e => {
|
|
20
|
+
/^[0-9]*[.,]?[0-9]*$/.test(e.target.value) && handleChange(e);
|
|
21
|
+
} }), _jsx(_Fragment, { children: children })] })] });
|
|
27
22
|
});
|
|
28
23
|
function limitDecimalPlaces(e, count) {
|
|
29
24
|
if (e.target.value.indexOf('.') == -1) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { MenuIcon, ChevronLeft } from "lucide-react";
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
4
|
import IconButton from "../Buttons/iconButton";
|
|
5
5
|
import { FormWizardProvider, useFormWizardaUpdate, useFormWizardState } from "../../context/formWizardProvider";
|
|
6
6
|
import { MenuStep } from "../../Models/Wizard";
|
|
@@ -35,8 +35,14 @@ const Comp = () => {
|
|
|
35
35
|
onMenuNavigationChange(path);
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (isOpen) {
|
|
40
|
+
goToStep(MenuStep.Menu);
|
|
41
|
+
onMenuNavigationChange("/");
|
|
42
|
+
}
|
|
43
|
+
}, [isOpen, onMenuNavigationChange]);
|
|
38
44
|
return _jsx(_Fragment, { children: _jsxs("div", { className: "text-secondary-text cursor-pointer relative", children: [_jsx("div", { className: "sm:-mr-2 mr-0", children: _jsx(IconButton, { className: "inline-flex active:animate-press-down", onClick: () => setIsOpen(true), icon: _jsx(MenuIcon, { strokeWidth: "2" }) }) }), _jsx(Modal, { isOpen: isOpen, setIsOpen: handleModalOpenStateChange, children: _jsx(ModalContent, { className: "pb-4", header: _jsxs("div", { className: "inline-flex items-center w-full", children: [goBack &&
|
|
39
|
-
_jsx("div", { className: "-ml-2", children: _jsx(IconButton, { className: "inline-flex", onClick: goBack, icon: _jsx(ChevronLeft, { strokeWidth: "2" }) }) }), _jsx("h2", { className: "flex-1", children: currentStepName })] }), children: ({ closeModal }) => (_jsx("div", { className: "openpicker h-full", id: "virtualListContainer", children: _jsxs(Wizard, { wizardId: 'menuWizard', children: [_jsx(WizardItem, { StepName: MenuStep.Menu, inModal: true, children: _jsx(MenuList, { goToStep: handleGoToStep }) }), _jsx(WizardItem, { StepName: MenuStep.Transactions, GoBack: goBackToMenuStep, className: "h-full", inModal: true, children: _jsx(HistoryList, { onNewTransferClick: closeModal }) }), _jsx(WizardItem, { StepName: MenuStep.Campaigns, GoBack: goBackToMenuStep, className: "h-full", inModal: true, children: _jsx(CampaignsComponent, { onCampaignSelect: (campaign) => { handleGoToStep(MenuStep.CampaignDetails); setSelectedCampaign(campaign.name); } }) }), _jsx(WizardItem, { StepName: MenuStep.CampaignDetails, GoBack: () => { goToStep(MenuStep.Campaigns, "back"); onMenuNavigationChange("/campaigns"); }, className: "h-full", inModal: true, children: _jsx(CampaignDetailsComponent, { campaignName: selectedCampaign }) })] }) })) }) })] }) });
|
|
45
|
+
_jsx("div", { className: "-ml-2", children: _jsx(IconButton, { className: "inline-flex", onClick: goBack, icon: _jsx(ChevronLeft, { strokeWidth: "2" }) }) }), _jsx("h2", { className: "flex-1", children: currentStepName })] }), children: ({ closeModal }) => (_jsx("div", { className: "openpicker h-full", id: "virtualListContainer", children: _jsxs(Wizard, { wizardId: 'menuWizard', children: [_jsx(WizardItem, { StepName: MenuStep.Menu, inModal: true, children: _jsx(MenuList, { goToStep: handleGoToStep }) }), _jsx(WizardItem, { StepName: MenuStep.Transactions, GoBack: goBackToMenuStep, className: "h-full", inModal: true, children: _jsx(HistoryList, { onNewTransferClick: () => { closeModal(); onMenuNavigationChange("/"); } }) }), _jsx(WizardItem, { StepName: MenuStep.Campaigns, GoBack: goBackToMenuStep, className: "h-full", inModal: true, children: _jsx(CampaignsComponent, { onCampaignSelect: (campaign) => { handleGoToStep(MenuStep.CampaignDetails); setSelectedCampaign(campaign.name); } }) }), _jsx(WizardItem, { StepName: MenuStep.CampaignDetails, GoBack: () => { goToStep(MenuStep.Campaigns, "back"); onMenuNavigationChange("/campaigns"); }, className: "h-full", inModal: true, children: _jsx(CampaignDetailsComponent, { campaignName: selectedCampaign }) })] }) })) }) })] }) });
|
|
40
46
|
};
|
|
41
47
|
const LayerswapMenu = () => {
|
|
42
48
|
return (_jsx(FormWizardProvider, { noToolBar: true, hideMenu: true, initialStep: MenuStep.Menu, children: _jsx(Comp, {}) }));
|
|
@@ -18,6 +18,6 @@ const Comp = () => {
|
|
|
18
18
|
_jsx(NotFound, { swapId: swapId }) }) });
|
|
19
19
|
return (_jsx(SwapDetails, { type: "widget" }));
|
|
20
20
|
};
|
|
21
|
-
export const SwapWithdrawal = () => {
|
|
22
|
-
return (_jsx(SwapDataProvider, { children: _jsx(Comp, {}) }));
|
|
21
|
+
export const SwapWithdrawal = ({ initialSwapData }) => {
|
|
22
|
+
return (_jsx(SwapDataProvider, { initialSwapData: initialSwapData, children: _jsx(Comp, {}) }));
|
|
23
23
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { TransactionType } from '../../../lib/apiClients/layerSwapApiClient';
|
|
4
|
-
import shortenAddress
|
|
4
|
+
import shortenAddress from '../../../components/utils/ShortenAddress';
|
|
5
5
|
import CopyButton from '../../../components/Buttons/copyButton';
|
|
6
6
|
import StatusIcon from './StatusIcons';
|
|
7
7
|
import { ExternalLink } from 'lucide-react';
|
|
@@ -19,7 +19,6 @@ const SwapDetails = ({ swapResponse }) => {
|
|
|
19
19
|
const { swap } = swapResponse;
|
|
20
20
|
const { source_network, destination_network, source_exchange } = swap;
|
|
21
21
|
const initialSettings = useInitialSettings();
|
|
22
|
-
const { hideFrom, account, } = initialSettings;
|
|
23
22
|
const { setSubmitedFormValues, setSwapModalOpen, setSwapId, createSwap } = useSwapDataUpdate();
|
|
24
23
|
const settings = useSettingsState();
|
|
25
24
|
const [isRepeatLoading, setIsRepeatLoading] = useState(false);
|
|
@@ -66,19 +65,6 @@ const SwapDetails = ({ swapResponse }) => {
|
|
|
66
65
|
const swapInputTransaction = swap?.transactions?.find(t => t.type === TransactionType.Input);
|
|
67
66
|
const swapOutputTransaction = swap?.transactions?.find(t => t.type === TransactionType.Output);
|
|
68
67
|
const refundTransaction = swap?.transactions?.find(t => t.type === TransactionType.Refund);
|
|
69
|
-
let sourceAccountAddress = undefined;
|
|
70
|
-
if (hideFrom && account) {
|
|
71
|
-
sourceAccountAddress = account;
|
|
72
|
-
}
|
|
73
|
-
else if (swapInputTransaction?.from) {
|
|
74
|
-
sourceAccountAddress = swapInputTransaction?.from;
|
|
75
|
-
}
|
|
76
|
-
else if (source_network?.name === KnownInternalNames.Exchanges.Coinbase && swap?.exchange_account_connected) {
|
|
77
|
-
sourceAccountAddress = shortenEmail(swap?.exchange_account_name, 10);
|
|
78
|
-
}
|
|
79
|
-
else if (source_exchange) {
|
|
80
|
-
sourceAccountAddress = "Exchange";
|
|
81
|
-
}
|
|
82
68
|
return (_jsxs(_Fragment, { children: [_jsx("section", { className: 'pb-3 space-y-3', children: _jsx("div", { className: 'p-3 bg-secondary-500 rounded-xl', children: _jsxs("div", { className: 'text-sm flex flex-col gap-3', children: [_jsxs("div", { className: "flex justify-between items-center text-sm text-primary-text", children: [_jsx("p", { className: "text-left text-secondary-text", children: "Transaction ID" }), _jsx(CopyButton, { toCopy: swap?.id, iconClassName: 'order-2 ml-1 text-primary-text', children: shortenAddress(swap?.id) })] }), _jsxs("div", { className: "flex justify-between items-baseline", children: [_jsx("span", { className: "text-left text-secondary-text", children: "Date & Time" }), _jsxs("span", { className: 'text-primary-text', children: [(new Date(swap.created_date)).toLocaleString(), " ", _jsx("span", { className: 'text-primary-text-tertiary', children: getDateDifferenceString(new Date(swap.created_date)) })] })] }), _jsxs("div", { className: "flex justify-between p items-baseline", children: [_jsx("span", { className: "text-left text-secondary-text", children: "Status " }), _jsx("span", { className: "text-primary-text", children: _jsx(StatusIcon, { swap: swap }) })] })] }) }) }), _jsx("section", { className: 'pb-2', children: _jsxs("div", { className: 'flex flex-col justify-between w-full h-full gap-3', children: [_jsx("div", { className: 'space-y-3', children: _jsx("div", { className: 'p-3 bg-secondary-500 rounded-xl text-primary-text', children: _jsxs("div", { className: 'text-sm flex flex-col gap-3', children: [_jsxs("div", { className: "flex justify-between items-baseline", children: [_jsx("p", { className: "text-left text-secondary-text", children: "Source transaction" }), swapInputTransaction?.transaction_hash ?
|
|
83
69
|
_jsxs("a", { target: "_blank", href: input_tx_explorer_template?.replace("{0}", swapInputTransaction.transaction_hash), className: 'flex items-center space-x-1', rel: "noopener noreferrer", children: [_jsx("span", { children: shortenAddress(swapInputTransaction.transaction_hash) }), _jsx(ExternalLink, { className: 'h-4' })] })
|
|
84
70
|
:
|
|
@@ -99,6 +85,6 @@ const SwapDetails = ({ swapResponse }) => {
|
|
|
99
85
|
:
|
|
100
86
|
_jsx("span", { children: "-" })] }) })] }) }) }), swap.status === SwapStatus.Completed &&
|
|
101
87
|
_jsx(SecondaryButton, { type: 'button', size: 'xl', onClick: handleRepeatSwap, isLoading: isRepeatLoading, children: _jsx("p", { className: 'text-primary-text', children: isRepeatLoading ? 'Creating Swap...' : 'Repeat Swap' }) }), (swap.status !== SwapStatus.Completed && swap.status !== SwapStatus.Expired && swap.status !== SwapStatus.Failed) &&
|
|
102
|
-
_jsx(SubmitButton, { type: 'button', onClick: handleViewCompleteSwap, children: _jsx("p", { children: swap.status == SwapStatus.LsTransferPending ? "View Swap" : "Complete Swap" }) })] }) })] }));
|
|
88
|
+
_jsx(SubmitButton, { type: 'button', onClick: handleViewCompleteSwap, children: _jsx("p", { children: swap.status == SwapStatus.LsTransferPending || swapInputTransaction ? "View Swap" : "Complete Swap" }) })] }) })] }));
|
|
103
89
|
};
|
|
104
90
|
export default SwapDetails;
|
|
@@ -12,7 +12,7 @@ const Widget = ({ children, hideMenu, goBack, contextualMenu }) => {
|
|
|
12
12
|
const { isEmbedded } = useSettingsState();
|
|
13
13
|
return _jsxs("div", { className: "relative p-px h-full", children: [AppSettings.ThemeData?.enableWideVersion && !isEmbedded &&
|
|
14
14
|
_jsx("div", { className: "invisible sm:visible absolute inset-0 rounded-[25px] bg-linear-to-t from-secondary-800 to-secondary-300 pointer-events-none" }), _jsxs("div", { id: "widget", style: AppSettings.ThemeData?.cardBackgroundStyle, className: clsx("sm:pb-4 rounded-3xl w-full overflow-hidden relative bg-secondary-700 h-full flex flex-col has-expandContainerHeight:min-h-[650px]", {
|
|
15
|
-
"max-sm:has-openpicker:min-h-svh max-sm:min-h-[99.8svh] sm:has-openpicker:min-h-[79svh]": AppSettings.ThemeData?.enableWideVersion,
|
|
15
|
+
"max-sm:has-openpicker:min-h-svh max-sm:min-h-[99.8svh] sm:has-openpicker:min-h-[79svh]!": AppSettings.ThemeData?.enableWideVersion,
|
|
16
16
|
"max-sm:min-h-[99svh]!": isEmbedded,
|
|
17
17
|
"has-openpicker:min-h-[675px]": !AppSettings.ThemeData?.enableWideVersion
|
|
18
18
|
}), children: [AppSettings.ApiVersion === 'testnet' &&
|
package/dist/esm/context/swap.js
CHANGED
|
@@ -30,7 +30,7 @@ export const SwapDataStateContext = createContext({
|
|
|
30
30
|
setSwapError: (value) => { }
|
|
31
31
|
});
|
|
32
32
|
export const SwapDataUpdateContext = createContext(null);
|
|
33
|
-
export function SwapDataProvider({ children }) {
|
|
33
|
+
export function SwapDataProvider({ children, initialSwapData }) {
|
|
34
34
|
const { sourceRoutes, destinationRoutes } = useSettingsState();
|
|
35
35
|
const initialSettings = useInitialSettings();
|
|
36
36
|
const { onSwapCreate } = useCallbacks();
|
|
@@ -67,7 +67,7 @@ export function SwapDataProvider({ children }) {
|
|
|
67
67
|
const layerswapApiClient = new LayerSwapApiClient();
|
|
68
68
|
const swap_details_endpoint = `/swaps/${swapId}?exclude_deposit_actions=true`;
|
|
69
69
|
const [interval, setInterval] = useState(0);
|
|
70
|
-
const { data, mutate, error } = useSWR(swapId ? swap_details_endpoint : null, layerswapApiClient.fetcher, { refreshInterval: interval, dedupingInterval: interval || 1000 });
|
|
70
|
+
const { data, mutate, error } = useSWR(swapId ? swap_details_endpoint : null, layerswapApiClient.fetcher, { refreshInterval: interval, dedupingInterval: interval || 1000, fallbackData: initialSwapData ? { data: initialSwapData } : undefined });
|
|
71
71
|
const swapBasicData = useMemo(() => {
|
|
72
72
|
if (swapId && data?.data) {
|
|
73
73
|
return data?.data?.swap ? {
|
|
@@ -10,7 +10,7 @@ export function useConnectors({ featuredProviders, filteredProviders, searchValu
|
|
|
10
10
|
.filter(g => g.availableHiddenWalletsForConnect && g.availableHiddenWalletsForConnect?.length > 0)
|
|
11
11
|
.map((provider) => provider.availableHiddenWalletsForConnect
|
|
12
12
|
?.filter(v => (searchValue ? v.name.toLowerCase().includes(searchValue.toLowerCase()) : true) &&
|
|
13
|
-
!
|
|
13
|
+
!featuredConnectors.some(c => c.id.toLowerCase() === v.id.toLowerCase()))
|
|
14
14
|
.map((connector) => ({ ...connector, providerName: provider.name, isHidden: true })))
|
|
15
15
|
.flat(), [featuredProviders, searchValue]);
|
|
16
16
|
const initialConnectors = useMemo(() => {
|
|
@@ -25,13 +25,6 @@ export function useConnectors({ featuredProviders, filteredProviders, searchValu
|
|
|
25
25
|
filteredProviders,
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
const featuredWalletsIds = [
|
|
29
|
-
'metamask',
|
|
30
|
-
'argent',
|
|
31
|
-
'rainbow',
|
|
32
|
-
'bitkeep',
|
|
33
|
-
'okx-wallet',
|
|
34
|
-
];
|
|
35
28
|
function removeDuplicatesWithKey(arr, key) {
|
|
36
29
|
const countMap = {};
|
|
37
30
|
const providerMap = {};
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { useSwrSwaps } from './useSwrSwaps';
|
|
3
|
+
import LayerSwapApiClient from '../lib/apiClients/layerSwapApiClient';
|
|
3
4
|
import { SwapStatus } from '../Models/SwapStatus';
|
|
5
|
+
import { useSwapTransactionStore } from '../stores/swapTransactionStore';
|
|
4
6
|
export function useSwapHistoryData(addresses) {
|
|
5
7
|
const [revalidateAll, setRevalidateAll] = useState(false);
|
|
8
|
+
const [localStorageSwaps, setLocalStorageSwaps] = useState([]);
|
|
9
|
+
const [isLoadingLocalSwaps, setIsLoadingLocalSwaps] = useState(false);
|
|
10
|
+
const { swapTransactions } = useSwapTransactionStore();
|
|
11
|
+
const fetchedIdsRef = useRef(new Set());
|
|
6
12
|
const pendingDeposit = useSwrSwaps({
|
|
7
13
|
statuses: ['PendingDeposit'],
|
|
8
14
|
addresses,
|
|
@@ -28,10 +34,97 @@ export function useSwapHistoryData(addresses) {
|
|
|
28
34
|
revalidateAll,
|
|
29
35
|
revalidateFirstPage: true,
|
|
30
36
|
});
|
|
37
|
+
// Stable key for swapTransactions (only include non-completed swaps from the last 30 minutes)
|
|
38
|
+
const storeSwapIds = useMemo(() => {
|
|
39
|
+
const thirtyMinutesAgo = Date.now() - 30 * 60 * 1000;
|
|
40
|
+
return Object.entries(swapTransactions || {})
|
|
41
|
+
.filter(([, tx]) => tx.timestamp >= thirtyMinutesAgo)
|
|
42
|
+
.map(([id]) => id)
|
|
43
|
+
.sort()
|
|
44
|
+
.join(',');
|
|
45
|
+
}, [swapTransactions]);
|
|
46
|
+
// Fetch swaps from store that are not in the backend results
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const fetchLocalStorageSwaps = async () => {
|
|
49
|
+
try {
|
|
50
|
+
const localSwapIds = storeSwapIds ? storeSwapIds.split(',').filter(Boolean) : [];
|
|
51
|
+
if (localSwapIds.length === 0) {
|
|
52
|
+
// Clear fetched IDs when local storage is empty
|
|
53
|
+
fetchedIdsRef.current.clear();
|
|
54
|
+
setLocalStorageSwaps([]);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Get all swap IDs from backend results
|
|
58
|
+
const backendSwapIds = new Set([
|
|
59
|
+
...pendingDeposit.swaps.map(s => s.swap.id),
|
|
60
|
+
...completed.swaps.map(s => s.swap.id)
|
|
61
|
+
]);
|
|
62
|
+
// Clean up fetchedIdsRef - remove IDs that are no longer in local storage
|
|
63
|
+
const localSwapIdSet = new Set(localSwapIds);
|
|
64
|
+
for (const id of Array.from(fetchedIdsRef.current)) {
|
|
65
|
+
if (!localSwapIdSet.has(id)) {
|
|
66
|
+
fetchedIdsRef.current.delete(id);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Find swap IDs that exist in store but not in backend results and not already fetched
|
|
70
|
+
const missingSwapIds = localSwapIds.filter(id => !backendSwapIds.has(id) && !fetchedIdsRef.current.has(id));
|
|
71
|
+
if (missingSwapIds.length === 0) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
setIsLoadingLocalSwaps(true);
|
|
75
|
+
const apiClient = new LayerSwapApiClient();
|
|
76
|
+
// Mark as fetched to prevent re-fetching
|
|
77
|
+
missingSwapIds.forEach(id => fetchedIdsRef.current.add(id));
|
|
78
|
+
// Fetch missing swaps from backend
|
|
79
|
+
const fetchedSwaps = await Promise.all(missingSwapIds.map(async (swapId) => {
|
|
80
|
+
try {
|
|
81
|
+
const response = await apiClient.GetSwapAsync(swapId);
|
|
82
|
+
return response?.data || null;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}));
|
|
88
|
+
setLocalStorageSwaps(prev => {
|
|
89
|
+
const existingIds = new Set(prev.map(s => s.swap.id));
|
|
90
|
+
const newSwaps = fetchedSwaps.filter((s) => s !== null && !existingIds.has(s.swap.id));
|
|
91
|
+
return [...prev, ...newSwaps];
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
console.error('Error fetching localStorage swaps:', error);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
setIsLoadingLocalSwaps(false);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
// Only fetch once backend data is loaded
|
|
102
|
+
if (!pendingDeposit.isLoading && !completed.isLoading) {
|
|
103
|
+
fetchLocalStorageSwaps();
|
|
104
|
+
}
|
|
105
|
+
}, [storeSwapIds, pendingDeposit.isLoading, completed.isLoading, pendingDeposit.swaps, completed.swaps]);
|
|
106
|
+
// Merge localStorage swaps with completed swaps
|
|
107
|
+
const mergedCompleted = useMemo(() => {
|
|
108
|
+
const allCompletedSwaps = [...completed.swaps];
|
|
109
|
+
// Add localStorage swaps that aren't already in the list
|
|
110
|
+
const completedIds = new Set(allCompletedSwaps.map(s => s.swap.id));
|
|
111
|
+
const pendingIds = new Set(pendingDeposit.swaps.map(s => s.swap.id));
|
|
112
|
+
for (const swap of localStorageSwaps) {
|
|
113
|
+
if (!completedIds.has(swap.swap.id) && !pendingIds.has(swap.swap.id)) {
|
|
114
|
+
allCompletedSwaps.push(swap);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Sort by created_date descending
|
|
118
|
+
allCompletedSwaps.sort((a, b) => new Date(b.swap.created_date).getTime() - new Date(a.swap.created_date).getTime());
|
|
119
|
+
return {
|
|
120
|
+
...completed,
|
|
121
|
+
swaps: allCompletedSwaps,
|
|
122
|
+
};
|
|
123
|
+
}, [completed, localStorageSwaps, pendingDeposit.swaps]);
|
|
31
124
|
return {
|
|
32
125
|
pendingDeposit,
|
|
33
|
-
completed,
|
|
34
|
-
isLoadingAny: pendingDeposit.isLoading || completed.isLoading,
|
|
126
|
+
completed: mergedCompleted,
|
|
127
|
+
isLoadingAny: pendingDeposit.isLoading || completed.isLoading || isLoadingLocalSwaps,
|
|
35
128
|
isValidatingAny: pendingDeposit.isValidating || completed.isValidating,
|
|
36
129
|
};
|
|
37
130
|
}
|