Skip to content

Commit

Permalink
feat(widget-v2)/balance loading state (#279)
Browse files Browse the repository at this point in the history
  • Loading branch information
codingki authored Sep 26, 2024
1 parent 643ea4c commit 3b34969
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 82 deletions.
26 changes: 26 additions & 0 deletions packages/widget-v2/src/icons/SpinnerIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { ComponentProps } from "react";

export const SpinnerIcon = (props: ComponentProps<"svg">) => {
return (
<svg
fill="none"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<circle
cx="12"
cy="12"
opacity=".25"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
fill="currentColor"
opacity=".75"
/>
</svg>
);
};
116 changes: 116 additions & 0 deletions packages/widget-v2/src/pages/SwapPage/ConnectedWalletContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { Row } from "@/components/Layout";
import { useAccount } from "@/hooks/useAccount";
import { ConnectedWalletModal } from "@/modals/ConnectedWalletModal/ConnectedWalletModal";
import { useMemo } from "react";
import { useSetMaxAmount } from "./useSetMaxAmount";
import { useSourceBalance } from "./useSourceBalance";
import { useModal } from "@/components/Modal";
import { useAtomValue } from "jotai";
import { sourceAssetAtom } from "@/state/swapPage";
import { GhostButton, GhostButtonProps } from "@/components/Button";
import { useGetAssetDetails } from "@/hooks/useGetAssetDetails";
import styled, { css } from "styled-components";
import { SpinnerIcon } from "@/icons/SpinnerIcon";

export const ConnectedWalletContent = () => {
const sourceAsset = useAtomValue(sourceAssetAtom);
const sourceAccount = useAccount(sourceAsset?.chainID);
const sourceDetails = useGetAssetDetails({
assetDenom: sourceAsset?.denom,
amount: sourceAsset?.amount,
chainId: sourceAsset?.chainID,
});

const { data: sourceBalance, isLoading } = useSourceBalance();
const handleMaxButton = useSetMaxAmount();
const connectedWalletModal = useModal(ConnectedWalletModal);

const formattedBalance = useMemo(() => {
if (sourceBalance === undefined || sourceBalance.error?.message) return "";

const amount = sourceBalance?.amount;
let formattedBalanceAmount = sourceBalance?.formattedAmount;

if (amount === "0") {
formattedBalanceAmount = amount;
}

return `${formattedBalanceAmount} ${sourceDetails?.symbol}`;
}, [sourceBalance, sourceDetails?.symbol]);
if (!sourceAccount) return null;
return (
<Row
gap={6}
style={{
paddingRight: 13,
}}
>
<TransparentButton
onClick={() => {
connectedWalletModal.show();
}}
style={{
padding: "8px 13px",
alignItems: "center",
gap: 8,
}}
>
{sourceAccount && (
<img
style={{ objectFit: "cover" }}
src={sourceAccount?.wallet.logo}
height={16}
width={16}
/>
)}
{isLoading ? (
<div
style={{
marginLeft: "8px",
marginRight: "8px",
position: "relative",
}}
>
<SpinnerIcon
style={{
animation: "spin 1s linear infinite",
position: "absolute",
height: 14,
width: 14,
}}
/>
</div>
) : (
formattedBalance
)}
</TransparentButton>

<TransparentButton
disabled={!sourceBalance || sourceBalance?.amount === "0"}
onClick={handleMaxButton}
style={{
padding: "8px 13px",
alignItems: "center",
}}
>
Max
</TransparentButton>
</Row>
);
};

const TransparentButton = styled(GhostButton).attrs({
as: "button",
}) <GhostButtonProps>`
${({ theme, onClick, secondary, disabled }) =>
onClick &&
!disabled &&
css`
background-color: ${secondary
? theme.secondary.background.normal
: theme.primary.ghostButtonHover};
cursor: pointer;
`};
padding: 10px 13px;
border-radius: 90px;
`;
79 changes: 3 additions & 76 deletions packages/widget-v2/src/pages/SwapPage/SwapPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { AssetChainInput } from "@/components/AssetChainInput";
import { Column, Row } from "@/components/Layout";
import { Column } from "@/components/Layout";
import { MainButton } from "@/components/MainButton";
import { ICONS } from "@/icons";
import {
Expand Down Expand Up @@ -33,17 +33,13 @@ import { useGetAssetDetails } from "@/hooks/useGetAssetDetails";
import { WalletSelectorModal } from "@/modals/WalletSelectorModal/WalletSelectorModal";
import { useAccount } from "@/hooks/useAccount";
import { currentPageAtom, Routes } from "@/state/router";
import { GhostButton, GhostButtonProps } from "@/components/Button";
import { ConnectedWalletModal } from "@/modals/ConnectedWalletModal/ConnectedWalletModal";
import styled, { css } from "styled-components";
import {
useInsufficientSourceBalance,
useSetMaxAmount,
} from "./useSetMaxAmount";
import { useSourceBalance } from "./useSourceBalance";
import { TransactionHistoryModal } from "@/modals/TransactionHistoryModal/TransactionHistoryModal";
import { errorAtom, ErrorType } from "@/state/errorPage";
import { useSyncPendingTransactionHistoryItems } from "./useSyncPendingTransactionHistoryItems";
import { ConnectedWalletContent } from "./ConnectedWalletContent";

export const SwapPage = () => {
useSyncPendingTransactionHistoryItems();
Expand All @@ -67,14 +63,11 @@ export const SwapPage = () => {
const selectWalletmodal = useModal(WalletSelectorModal);
const setCurrentPage = useSetAtom(currentPageAtom);
const setSkipBalancesRequest = useSetAtom(skipBalancesRequestAtom);
const connectedWalletModal = useModal(ConnectedWalletModal);
const historyModal = useModal(TransactionHistoryModal);
const sourceBalance = useSourceBalance();
const insufficientBalance = useInsufficientSourceBalance();
const setSwapExecutionState = useSetAtom(setSwapExecutionStateAtom);
const setError = useSetAtom(errorAtom);

const handleMaxButton = useSetMaxAmount();
const setChainAddresses = useSetAtom(chainAddressesAtom);

const sourceAccount = useAccount(sourceAsset?.chainID);
Expand Down Expand Up @@ -114,18 +107,7 @@ export const SwapPage = () => {
chainId: destinationAsset?.chainID,
});

const formattedBalance = useMemo(() => {
if (sourceBalance === undefined || sourceBalance.error?.message) return "";

const amount = sourceBalance?.amount;
let formattedBalanceAmount = sourceBalance?.formattedAmount;

if (amount === "0") {
formattedBalanceAmount = amount;
}

return `${formattedBalanceAmount} ${sourceDetails?.symbol}`;
}, [sourceBalance, sourceDetails?.symbol]);

const chainsContainingSourceAsset = useMemo(() => {
if (!chains || !assets || !sourceAsset?.symbol) return;
Expand Down Expand Up @@ -317,46 +299,7 @@ export const SwapPage = () => {
onClick: () => historyModal.show()
}}
rightContent={
sourceAccount && (
<Row
gap={6}
style={{
paddingRight: 13,
}}
>
<TransparentButton
onClick={() => {
connectedWalletModal.show();
}}
style={{
padding: "8px 13px",
alignItems: "center",
gap: 8,
}}
>
{sourceAccount && (
<img
style={{ objectFit: "cover" }}
src={sourceAccount?.wallet.logo}
height={16}
width={16}
/>
)}
{formattedBalance}
</TransparentButton>

<TransparentButton
disabled={!sourceBalance || sourceBalance?.amount === "0"}
onClick={handleMaxButton}
style={{
padding: "8px 13px",
alignItems: "center",
}}
>
Max
</TransparentButton>
</Row>
)
<ConnectedWalletContent />
}
/>
<Column align="center">
Expand Down Expand Up @@ -409,19 +352,3 @@ export const SwapPage = () => {
</>
);
};

const TransparentButton = styled(GhostButton).attrs({
as: "button",
}) <GhostButtonProps>`
${({ theme, onClick, secondary, disabled }) =>
onClick &&
!disabled &&
css`
background-color: ${secondary
? theme.secondary.background.normal
: theme.primary.ghostButtonHover};
cursor: pointer;
`};
padding: 10px 13px;
border-radius: 90px;
`;
2 changes: 1 addition & 1 deletion packages/widget-v2/src/pages/SwapPage/useSetMaxAmount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const useGasFeeTokenAmount = () => {
};

export const useMaxAmountTokenMinusFees = () => {
const sourceBalance = useSourceBalance();
const { data: sourceBalance } = useSourceBalance();
const gasFeeTokenAmount = useGasFeeTokenAmount();
const maxTokenAmount = sourceBalance?.amount;

Expand Down
19 changes: 14 additions & 5 deletions packages/widget-v2/src/pages/SwapPage/useSourceBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@ import { useAccount } from "@/hooks/useAccount";
import { skipBalancesAtom } from "@/state/skipClient";
import { sourceAssetAtom } from "@/state/swapPage";
import { useAtom, useAtomValue } from "jotai";
import { useMemo } from "react";

export const useSourceBalance = () => {
const [sourceAsset] = useAtom(sourceAssetAtom);
const sourceAccount = useAccount(sourceAsset?.chainID);
const { data: skipBalances } = useAtomValue(skipBalancesAtom);
const { data: skipBalances, isLoading, refetch } = useAtomValue(skipBalancesAtom);

if (!sourceAsset || !sourceAccount || !skipBalances) return;
const { chainID, denom } = sourceAsset;
if (!denom || !chainID) return;
const data = useMemo(() => {
if (!sourceAsset || !sourceAccount || !skipBalances) return;
const { chainID, denom } = sourceAsset;
if (!denom || !chainID) return;

return skipBalances?.chains?.[chainID]?.denoms?.[denom];
return skipBalances?.chains?.[chainID]?.denoms?.[denom];
}, [sourceAsset, sourceAccount, skipBalances]);

return {
data,
isLoading,
refetch
};
};

0 comments on commit 3b34969

Please sign in to comment.