Skip to content

Commit 7681650

Browse files
committed
show balance, show not enough balance error
1 parent 8513839 commit 7681650

File tree

2 files changed

+141
-16
lines changed

2 files changed

+141
-16
lines changed

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx

Lines changed: 122 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ import {
3030
import { useWalletBalance } from "../../../../core/hooks/others/useWalletBalance.js";
3131
import { ConnectButton } from "../../ConnectWallet/ConnectButton.js";
3232
import { ArrowUpDownIcon } from "../../ConnectWallet/icons/ArrowUpDownIcon.js";
33+
import { WalletDotIcon } from "../../ConnectWallet/icons/WalletDotIcon.js";
3334
import { PoweredByThirdweb } from "../../ConnectWallet/PoweredByTW.js";
35+
import { formatTokenAmount } from "../../ConnectWallet/screens/formatTokenBalance.js";
3436
import { Container } from "../../components/basic.js";
3537
import { Button } from "../../components/buttons.js";
3638
import { Input } from "../../components/formElements.js";
@@ -351,10 +353,34 @@ function SwapUIBase(
351353
walletAddress: props.activeWalletInfo?.activeAccount.address,
352354
});
353355

356+
const buyTokenBalanceQuery = useTokenBalance({
357+
chainId: buyTokenWithPrices?.chainId,
358+
tokenAddress: buyTokenWithPrices?.address,
359+
client: props.client,
360+
walletAddress: props.activeWalletInfo?.activeAccount.address,
361+
});
362+
363+
const notEnoughBalance = !!(
364+
props.amountSelection.type === "sell" &&
365+
sellTokenBalanceQuery.data?.value &&
366+
sellTokenWithPrices?.decimals &&
367+
props.amountSelection.amount &&
368+
sellTokenBalanceQuery.data.value <
369+
Number(
370+
toUnits(props.amountSelection.amount, sellTokenWithPrices.decimals),
371+
)
372+
);
373+
354374
return (
355375
<Container p="md">
356376
{/* Sell */}
357377
<TokenSection
378+
isConnected={!!props.activeWalletInfo}
379+
notEnoughBalance={notEnoughBalance}
380+
balance={{
381+
data: sellTokenBalanceQuery.data?.value,
382+
isFetching: sellTokenBalanceQuery.isFetching,
383+
}}
358384
amount={{
359385
data: sellTokenAmount,
360386
isFetching: isSellAmountFetching,
@@ -388,6 +414,12 @@ function SwapUIBase(
388414

389415
{/* Buy */}
390416
<TokenSection
417+
isConnected={!!props.activeWalletInfo}
418+
notEnoughBalance={false}
419+
balance={{
420+
data: buyTokenBalanceQuery.data?.value,
421+
isFetching: buyTokenBalanceQuery.isFetching,
422+
}}
391423
amount={{
392424
data: buyTokenAmount,
393425
isFetching: isBuyAmountFetching,
@@ -427,7 +459,11 @@ function SwapUIBase(
427459
/>
428460
) : (
429461
<Button
430-
disabled={!preparedResultQuery.data || preparedResultQuery.isFetching}
462+
disabled={
463+
!preparedResultQuery.data ||
464+
preparedResultQuery.isFetching ||
465+
notEnoughBalance
466+
}
431467
fullWidth
432468
onClick={() => {
433469
if (
@@ -524,6 +560,7 @@ function DecimalInput(props: {
524560

525561
function TokenSection(props: {
526562
label: string;
563+
notEnoughBalance: boolean;
527564
amount: {
528565
data: string;
529566
isFetching: boolean;
@@ -538,6 +575,11 @@ function TokenSection(props: {
538575
currency: SupportedFiatCurrency;
539576
onSelectToken: () => void;
540577
client: ThirdwebClient;
578+
isConnected: boolean;
579+
balance: {
580+
data: bigint | undefined;
581+
isFetching: boolean;
582+
};
541583
}) {
542584
const chainQuery = useBridgeChains(props.client);
543585
const chain = chainQuery.data?.find(
@@ -567,9 +609,10 @@ function TokenSection(props: {
567609
style={{
568610
display: "flex",
569611
alignItems: "center",
570-
minHeight: "60px",
571612
justifyContent: "space-between",
572613
gap: spacing.sm,
614+
paddingBottom: spacing.sm,
615+
paddingTop: spacing.xs,
573616
}}
574617
>
575618
{props.amount.isFetching ? (
@@ -603,27 +646,90 @@ function TokenSection(props: {
603646
)}
604647
</div>
605648

606-
{/* Fiat Value */}
607-
<div style={{ display: "flex", alignItems: "center", gap: "4px" }}>
608-
<Text size="md" color="secondaryText" weight={500}>
609-
{getFiatSymbol(props.currency)}
610-
</Text>
611-
{props.amount.isFetching ? (
612-
<Skeleton height={fontSize.md} width="50px" />
613-
) : (
614-
<Text size="md" color="secondaryText" weight={500}>
615-
{totalFiatValue === undefined
616-
? "0.00"
617-
: totalFiatValue < 0.01
618-
? "~0.00"
619-
: totalFiatValue.toFixed(2)}
649+
<div
650+
style={{
651+
display: "flex",
652+
alignItems: "center",
653+
gap: "4px",
654+
justifyContent: "space-between",
655+
}}
656+
>
657+
{/* Exceeds Balance / Fiat Value */}
658+
{props.notEnoughBalance ? (
659+
<Text size="md" color="danger" weight={500}>
660+
{" "}
661+
Exceeds Balance{" "}
620662
</Text>
663+
) : (
664+
<div
665+
style={{
666+
display: "flex",
667+
alignItems: "center",
668+
gap: "4px",
669+
}}
670+
>
671+
<Text size="md" color="secondaryText" weight={500}>
672+
{getFiatSymbol(props.currency)}
673+
</Text>
674+
{props.amount.isFetching ? (
675+
<Skeleton height={fontSize.md} width="50px" />
676+
) : (
677+
<div>
678+
<DecimalRenderer value={totalFiatValue?.toFixed(5) || "0.00"} />
679+
</div>
680+
)}
681+
</div>
682+
)}
683+
684+
{/* Balance */}
685+
{props.isConnected && (
686+
<div>
687+
{props.balance.isFetching ||
688+
props.balance.data === undefined ||
689+
!props.selectedToken?.data ? (
690+
<Skeleton height={fontSize.md} width="50px" />
691+
) : (
692+
<Text
693+
size="md"
694+
color="secondaryText"
695+
weight={500}
696+
style={{
697+
display: "flex",
698+
alignItems: "center",
699+
gap: spacing.xxs,
700+
}}
701+
>
702+
<WalletDotIcon size={fontSize.sm} />
703+
<DecimalRenderer
704+
value={formatTokenAmount(
705+
props.balance.data,
706+
props.selectedToken.data.decimals,
707+
5,
708+
)}
709+
/>
710+
</Text>
711+
)}
712+
</div>
621713
)}
622714
</div>
623715
</Container>
624716
);
625717
}
626718

719+
function DecimalRenderer(props: { value: string }) {
720+
const [integerPart, fractionPart] = props.value.split(".");
721+
return (
722+
<div style={{ display: "flex", alignItems: "baseline" }}>
723+
<Text size="md" color="secondaryText" weight={500}>
724+
{integerPart}.
725+
</Text>
726+
<Text size="sm" color="secondaryText" weight={500}>
727+
{fractionPart || "00000"}
728+
</Text>
729+
</div>
730+
);
731+
}
732+
627733
function SelectedTokenButton(props: {
628734
selectedToken:
629735
| {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { IconFC } from "./types.js";
2+
3+
export const WalletDotIcon: IconFC = (props) => {
4+
return (
5+
<svg
6+
xmlns="http://www.w3.org/2000/svg"
7+
fill="none"
8+
viewBox="0 0 18 18"
9+
width={props.size}
10+
height={props.size}
11+
role="presentation"
12+
>
13+
<path
14+
fill="currentColor"
15+
d="M15.6 4.6H1.85v-.55l12.1-.968v.968h1.65V2.4c0-1.21-.98-2.059-2.177-1.888L2.378 2.089C1.18 2.26.2 3.39.2 4.6v11a2.2 2.2 0 002.2 2.2h13.2a2.2 2.2 0 002.2-2.2V6.8a2.2 2.2 0 00-2.2-2.2zm-1.65 7.707a1.65 1.65 0 01-.63-3.176 1.65 1.65 0 11.63 3.176z"
16+
></path>
17+
</svg>
18+
);
19+
};

0 commit comments

Comments
 (0)