Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
kien-ngo committed Nov 28, 2024
1 parent 07afcee commit 4b66fbd
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 44 deletions.
1 change: 1 addition & 0 deletions packages/thirdweb/src/exports/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ export {
export {
AccountBalance,
type AccountBalanceProps,
type AccountBalanceFormatParams
} from "../react/web/ui/prebuilt/Account/balance.js";
export {
AccountName,
Expand Down
45 changes: 40 additions & 5 deletions packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ import { fadeInAnimation } from "../design-system/animations.js";
import { StyledButton } from "../design-system/elements.js";
import { AccountAddress } from "../prebuilt/Account/address.js";
import { AccountAvatar } from "../prebuilt/Account/avatar.js";
import { AccountBalance } from "../prebuilt/Account/balance.js";
import {
AccountBalance,
type AccountBalanceFormatParams,
} from "../prebuilt/Account/balance.js";
import { AccountBlobbie } from "../prebuilt/Account/blobbie.js";
import { AccountName } from "../prebuilt/Account/name.js";
import { AccountProvider } from "../prebuilt/Account/provider.js";
Expand Down Expand Up @@ -278,12 +281,13 @@ export const ConnectedWalletDetails: React.FC<{
chain={walletChain}
loadingComponent={<Skeleton height={fontSize.xs} width="70px" />}
fallbackComponent={<Skeleton height={fontSize.xs} width="70px" />}
formatFn={formatBalanceOnButton}
formatFn={formatAccountBalanceForButton}

Check warning on line 284 in packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx#L284

Added line #L284 was not covered by tests
tokenAddress={
props.detailsButton?.displayBalanceToken?.[
Number(walletChain?.id)
]
}
showFiatValue="USD"

Check warning on line 290 in packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx#L290

Added line #L290 was not covered by tests
/>
</Text>
</Container>
Expand Down Expand Up @@ -380,11 +384,12 @@ function DetailsModal(props: {
<AccountBalance
fallbackComponent={<Skeleton height="1em" width="100px" />}
loadingComponent={<Skeleton height="1em" width="100px" />}
formatFn={(num: number) => formatNumber(num, 9)}
chain={walletChain}
tokenAddress={
props.displayBalanceToken?.[Number(walletChain?.id)]
}
formatFn={formatAccountBalanceForModal}
showFiatValue="USD"

Check warning on line 392 in packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx#L391-L392

Added lines #L391 - L392 were not covered by tests
/>
</Text>
</Text>
Expand Down Expand Up @@ -1006,8 +1011,38 @@ function DetailsModal(props: {
);
}

function formatBalanceOnButton(num: number) {
return formatNumber(num, num < 1 ? 5 : 4);
/**
* Format the display balance for both crypto and fiat, in the Details button and Modal
* If both crypto balance and fiat balance exist, we have to keep the string very short to avoid UI issues.
* @internal
*/
function formatAccountBalanceForButton(
props: AccountBalanceFormatParams,
): string {
if (props.fiatBalance && props.fiatSymbol) {

Check warning on line 1022 in packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx#L1019-L1022

Added lines #L1019 - L1022 were not covered by tests
// Need to keep them short to avoid UI overflow issues
const formattedTokenBalance = formatNumber(props.tokenBalance, 1);
const formattedFiatBalance = formatNumber(props.fiatBalance, 0);
return `${formattedTokenBalance} ${props.tokenSymbol} (${props.fiatSymbol}${formattedFiatBalance})`;
}
const formattedTokenBalance = formatNumber(
props.tokenBalance,
props.tokenBalance < 1 ? 5 : 4,
);
return `${formattedTokenBalance} ${props.tokenSymbol}`;
}

Check warning on line 1033 in packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx#L1024-L1033

Added lines #L1024 - L1033 were not covered by tests

function formatAccountBalanceForModal(
props: AccountBalanceFormatParams,
): string {
if (props.fiatBalance && props.fiatSymbol) {

Check warning on line 1038 in packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx#L1035-L1038

Added lines #L1035 - L1038 were not covered by tests
// Need to keep them short to avoid UI overflow issues
const formattedTokenBalance = formatNumber(props.tokenBalance, 5);
const formattedFiatBalance = formatNumber(props.fiatBalance, 4);
return `${formattedTokenBalance} ${props.tokenSymbol} (${props.fiatSymbol}${formattedFiatBalance})`;
}
const formattedTokenBalance = formatNumber(props.tokenBalance, 9);
return `${formattedTokenBalance} ${props.tokenSymbol}`;

Check warning on line 1045 in packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx#L1040-L1045

Added lines #L1040 - L1045 were not covered by tests
}

const WalletInfoButton = /* @__PURE__ */ StyledButton((_) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,11 @@
import { describe, expect, it } from "vitest";
import { ANVIL_CHAIN } from "~test/chains.js";
import { render, screen, waitFor } from "~test/react-render.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
import { getWalletBalance } from "../../../../../wallets/utils/getWalletBalance.js";
import { AccountBalance } from "./balance.js";
import { AccountProvider } from "./provider.js";

describe.runIf(process.env.TW_SECRET_KEY)("AccountBalance component", () => {
it("format the balance properly", async () => {
const roundTo1Decimal = (num: number): number => Math.round(num * 10) / 10;
const balance = await getWalletBalance({
chain: ANVIL_CHAIN,
client: TEST_CLIENT,
address: TEST_ACCOUNT_A.address,
});

render(
<AccountProvider address={TEST_ACCOUNT_A.address} client={TEST_CLIENT}>
<AccountBalance chain={ANVIL_CHAIN} formatFn={roundTo1Decimal} />
</AccountProvider>,
);

waitFor(() =>
expect(
screen.getByText(roundTo1Decimal(Number(balance.displayValue)), {
exact: true,
selector: "span",
}),
).toBeInTheDocument(),
);
});

it("should fallback properly if failed to load", () => {
render(
<AccountProvider address={TEST_ACCOUNT_A.address} client={TEST_CLIENT}>
Expand Down
90 changes: 77 additions & 13 deletions packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
import type React from "react";
import type { JSX } from "react";
import type { Chain } from "../../../../../chains/types.js";
import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
import { convertCryptoToFiat } from "../../../../../exports/pay.js";
import { useActiveWalletChain } from "../../../../../react/core/hooks/wallets/useActiveWalletChain.js";
import {
type GetWalletBalanceResult,
getWalletBalance,
} from "../../../../../wallets/utils/getWalletBalance.js";
import { getWalletBalance } from "../../../../../wallets/utils/getWalletBalance.js";
import { useAccountContext } from "./provider.js";

/**
* @internal
*/
export type AccountBalanceFormatParams = {
tokenBalance: number;
tokenSymbol: string;
fiatBalance?: number;
fiatSymbol?: string;
};

/**
* Props for the AccountBalance component
* @component
Expand All @@ -33,7 +42,7 @@ export interface AccountBalanceProps
* use this function to transform the balance display value like round up the number
* Particularly useful to avoid overflowing-UI issues
*/
formatFn?: (num: number) => number;
formatFn?: (props: AccountBalanceFormatParams) => string;
/**
* This component will be shown while the balance of the account is being fetched
* If not passed, the component will return `null`.
Expand Down Expand Up @@ -67,9 +76,11 @@ export interface AccountBalanceProps
* Optional `useQuery` params
*/
queryOptions?: Omit<
UseQueryOptions<GetWalletBalanceResult>,
UseQueryOptions<AccountBalanceFormatParams>,
"queryFn" | "queryKey"
>;

showFiatValue?: "USD";
}

/**
Expand Down Expand Up @@ -149,10 +160,11 @@ export interface AccountBalanceProps
export function AccountBalance({
chain,
tokenAddress,
formatFn,
loadingComponent,
fallbackComponent,
queryOptions,
formatFn,
showFiatValue,
...restProps
}: AccountBalanceProps) {
const { address, client } = useAccountContext();
Expand All @@ -164,20 +176,61 @@ export function AccountBalance({
chainToLoad?.id || -1,
address || "0x0",
{ tokenAddress },
showFiatValue,
] as const,
queryFn: async () => {
queryFn: async (): Promise<AccountBalanceFormatParams> => {
if (!chainToLoad) {
throw new Error("chain is required");
}
if (!client) {
throw new Error("client is required");
}
return getWalletBalance({
const tokenBalanceData = await getWalletBalance({

Check warning on line 188 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L188

Added line #L188 was not covered by tests
chain: chainToLoad,
client,
address,
tokenAddress,
});

if (!tokenBalanceData) {
throw new Error(
`Failed to retrieve ${tokenAddress ? `token: ${tokenAddress}` : "native token"} balance for address: ${address} on chainId:${chainToLoad.id}`,
);
}

Check warning on line 199 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L195-L199

Added lines #L195 - L199 were not covered by tests

if (showFiatValue) {
const fiatData = await convertCryptoToFiat({
fromAmount: Number(tokenBalanceData.displayValue),
fromTokenAddress: tokenAddress || NATIVE_TOKEN_ADDRESS,
to: showFiatValue,
chain: chainToLoad,
client,
}).catch(() => undefined);

Check warning on line 208 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L201-L208

Added lines #L201 - L208 were not covered by tests

// We can never support 100% of token out there, so if something fails to resolve, it's expected
// in that case just return the tokenBalance and symbol
return {
tokenBalance: Number(tokenBalanceData.displayValue),
tokenSymbol: tokenBalanceData.symbol,
fiatBalance: fiatData?.result,
fiatSymbol: fiatData?.result
? new Intl.NumberFormat("en", {
style: "currency",
currency: showFiatValue,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
})
.formatToParts(0)
.find((p) => p.type === "currency")?.value ||
showFiatValue.toUpperCase()
: undefined,
};
}

Check warning on line 228 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L212-L228

Added lines #L212 - L228 were not covered by tests

return {
tokenBalance: Number(tokenBalanceData.displayValue),
tokenSymbol: tokenBalanceData.symbol,
};

Check warning on line 233 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L230-L233

Added lines #L230 - L233 were not covered by tests
},
...queryOptions,
});
Expand All @@ -190,13 +243,24 @@ export function AccountBalance({
return fallbackComponent || null;
}

const displayValue = formatFn
? formatFn(Number(balanceQuery.data.displayValue))
: balanceQuery.data.displayValue;
if (formatFn) {
return <span {...restProps}>{formatFn(balanceQuery.data)}</span>;
}

Check warning on line 248 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L246-L248

Added lines #L246 - L248 were not covered by tests

const { tokenBalance, tokenSymbol, fiatBalance, fiatSymbol } =
balanceQuery.data;

Check warning on line 251 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L250-L251

Added lines #L250 - L251 were not covered by tests

if (fiatBalance && fiatSymbol) {
return (
<span {...restProps}>
{`${tokenBalance} ${tokenSymbol} (${fiatSymbol}${fiatBalance})`}
</span>

Check warning on line 257 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L254-L257

Added lines #L254 - L257 were not covered by tests
);
}

Check warning on line 259 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L259

Added line #L259 was not covered by tests

return (
<span {...restProps}>
{displayValue} {balanceQuery.data.symbol}
{tokenBalance} {tokenSymbol}

Check warning on line 263 in packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/prebuilt/Account/balance.tsx#L263

Added line #L263 was not covered by tests
</span>
);
}

0 comments on commit 4b66fbd

Please sign in to comment.