Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add option to hide balance, closes leather-io#5096 #5865

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/app/components/account-total-balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { styled } from 'leather-styles/jsx';
import { SkeletonLoader, shimmerStyles } from '@leather.io/ui';

import { useTotalBalance } from '@app/common/hooks/balance/use-total-balance';
import { PrivateText } from '@app/components/privacy/private-text';

interface AccountTotalBalanceProps {
btcAddress: string;
Expand All @@ -26,7 +27,7 @@ export const AccountTotalBalance = memo(({ btcAddress, stxAddress }: AccountTota
textStyle="label.02"
data-state={isLoadingAdditionalData || isFetching ? 'loading' : undefined}
>
{totalUsdBalance}
<PrivateText>{totalUsdBalance}</PrivateText>
</styled.span>
</SkeletonLoader>
);
Expand Down
11 changes: 8 additions & 3 deletions src/app/components/balance/btc-balance.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { Caption } from '@leather.io/ui';
import { formatMoney } from '@leather.io/utils';

import { BitcoinNativeSegwitAccountLoader } from '../loaders/bitcoin-account-loader';
import { BtcBalanceLoader } from '../loaders/btc-balance-loader';
import { BitcoinNativeSegwitAccountLoader } from '@app/components/loaders/bitcoin-account-loader';
import { BtcBalanceLoader } from '@app/components/loaders/btc-balance-loader';
import { PrivateText } from '@app/components/privacy/private-text';

export function BtcBalance() {
return (
<BitcoinNativeSegwitAccountLoader current>
{signer => (
<BtcBalanceLoader address={signer.address}>
{balance => <Caption>{formatMoney(balance.availableBalance)}</Caption>}
{balance => (
<Caption>
<PrivateText canClickToShow>{formatMoney(balance.availableBalance)}</PrivateText>
</Caption>
)}
</BtcBalanceLoader>
)}
</BitcoinNativeSegwitAccountLoader>
Expand Down
7 changes: 6 additions & 1 deletion src/app/components/balance/stx-balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useStxCryptoAssetBalance } from '@leather.io/query';
import { Caption } from '@leather.io/ui';

import { stacksValue } from '@app/common/stacks-utils';
import { PrivateText } from '@app/components/privacy/private-text';

interface StxBalanceProps {
address: string;
Expand All @@ -21,5 +22,9 @@ export function StxBalance(props: StxBalanceProps) {
[filteredBalanceQuery.data?.unlockedBalance.amount]
);

return <Caption>{stxBalance}</Caption>;
return (
<Caption>
<PrivateText canClickToShow>{stxBalance}</PrivateText>
</Caption>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import { IncreaseFeeButton } from '@app/components/stacks-transaction-item/increase-fee-button';
import { TransactionTitle } from '@app/components/transaction/transaction-title';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useIsPrivateMode } from '@app/store/settings/settings.selectors';

import { TransactionItemLayout } from '../transaction-item/transaction-item.layout';
import { BitcoinTransactionIcon } from './bitcoin-transaction-icon';
Expand All @@ -33,10 +34,11 @@
export function BitcoinTransactionItem({ transaction }: BitcoinTransactionItemProps) {
const { pathname } = useLocation();
const navigate = useNavigate();
const isPrivate = useIsPrivateMode();

const { data: inscriptionData } = useInscriptionByOutput(transaction);

const bitcoinAddress = useCurrentAccountNativeSegwitAddressIndexZero();

Check warning on line 41 in src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx

View workflow job for this annotation

GitHub Actions / lint-eslint

'useCurrentAccountNativeSegwitAddressIndexZero' is deprecated. Use signer.address instead
const { handleOpenBitcoinTxLink: handleOpenTxLink } = useBitcoinExplorerLink();
const caption = useMemo(() => getBitcoinTxCaption(transaction), [transaction]);
const value = useMemo(
Expand Down Expand Up @@ -98,6 +100,7 @@
txStatus={<BitcoinTransactionStatus transaction={transaction} />}
txTitle={<TransactionTitle title={title} />}
txValue={value}
isPrivate={isPrivate}
/>
);
}
16 changes: 11 additions & 5 deletions src/app/components/crypto-asset-item/crypto-asset-item.layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Flex, styled } from 'leather-styles/jsx';
import { Box, Flex } from 'leather-styles/jsx';

import type { Money } from '@leather.io/models';
import {
Expand All @@ -11,6 +11,7 @@ import {
} from '@leather.io/ui';
import { spamFilter } from '@leather.io/utils';

import { PrivateTextLayout } from '@app/components/privacy/private-text.layout';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';

import { parseCryptoAssetBalance } from './crypto-asset-item.layout.utils';
Expand All @@ -25,6 +26,7 @@ interface CryptoAssetItemLayoutProps {
icon: React.ReactNode;
isLoading?: boolean;
isLoadingAdditionalData?: boolean;
isPrivate?: boolean;
onSelectAsset?(symbol: string, contractId?: string): void;
titleLeft: string;
titleRightBulletInfo?: React.ReactNode;
Expand All @@ -39,6 +41,7 @@ export function CryptoAssetItemLayout({
icon,
isLoading = false,
isLoadingAdditionalData = false,
isPrivate = false,
onSelectAsset,
titleLeft,
titleRightBulletInfo,
Expand All @@ -50,17 +53,18 @@ export function CryptoAssetItemLayout({
<SkeletonLoader width="126px" isLoading={isLoading}>
<BasicTooltip
asChild
label={formattedBalance.isAbbreviated ? availableBalanceString : undefined}
label={formattedBalance.isAbbreviated && !isPrivate ? availableBalanceString : undefined}
side="left"
>
<Flex alignItems="center" gap="space.02" textStyle="label.02">
<BulletSeparator>
<styled.span
<PrivateTextLayout
isPrivate={isPrivate}
data-state={isLoadingAdditionalData ? 'loading' : undefined}
className={shimmerStyles}
>
{formattedBalance.value} {balanceSuffix}
</styled.span>
</PrivateTextLayout>
{titleRightBulletInfo}
</BulletSeparator>
</Flex>
Expand All @@ -76,7 +80,9 @@ export function CryptoAssetItemLayout({
data-state={isLoadingAdditionalData ? 'loading' : undefined}
className={shimmerStyles}
>
{availableBalance.amount.toNumber() > 0 ? fiatBalance : null}
<PrivateTextLayout isPrivate={isPrivate}>
{availableBalance.amount.toNumber() > 0 ? fiatBalance : null}
</PrivateTextLayout>
</Caption>
{captionRightBulletInfo}
</BulletSeparator>
Expand Down
17 changes: 17 additions & 0 deletions src/app/components/layout/card/card.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,23 @@ export function CardWithBalanceFooter() {
);
}

export function CardWithPrivateBalanceFooter() {
return (
<Component
footer={
<ButtonRow>
<Button fullWidth onClick={() => null}>
Continue
</Button>
<AvailableBalance balance="$10" isPrivate />
</ButtonRow>
}
>
<Box height="40vh">Card content</Box>
</Component>
);
}

export function CardWithBigHeader() {
return (
<Component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import { Box, Flex, HStack, styled } from 'leather-styles/jsx';

import { InfoCircleIcon } from '@leather.io/ui';

import { PrivateTextLayout } from '@app/components/privacy/private-text.layout';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';

interface AvailableBalanceProps {
balance: string;
balanceTooltipLabel?: string;
isPrivate?: boolean;
}

export function AvailableBalance({
balance,
isPrivate,
balanceTooltipLabel = 'Amount that is immediately available for use after taking into account any pending transactions or holds placed on your account by the protocol.',
}: AvailableBalanceProps) {
return (
Expand All @@ -26,7 +29,7 @@ export function AvailableBalance({
</BasicTooltip>
</HStack>
<styled.span color="ink.text-subdued" mr="space.02" textStyle="caption.01">
{balance}
<PrivateTextLayout isPrivate={isPrivate}>{balance}</PrivateTextLayout>
</styled.span>
</Flex>
);
Expand Down
38 changes: 38 additions & 0 deletions src/app/components/privacy/private-text.layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';

import { type HTMLStyledProps, styled } from 'leather-styles/jsx';

import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';

interface PrivateTextLayoutProps extends HTMLStyledProps<'span'> {
children: React.ReactNode;
isPrivate?: boolean;
onShowValue?(): void;
}

export function PrivateTextLayout({
isPrivate,
onShowValue,
children,
style = {},
...rest
}: PrivateTextLayoutProps) {
const canShowValue = isPrivate && onShowValue;

return (
<BasicTooltip label="Show value" disabled={!canShowValue} asChild>
<styled.span
{...rest}
onClick={canShowValue ? onShowValue : undefined}
cursor={canShowValue ? 'pointer' : undefined}
style={{
...style,
fontFamily: isPrivate ? 'Fira Code, Consolata, monospace' : style?.fontFamily,
letterSpacing: isPrivate ? '0.05em' : style?.letterSpacing,
}}
>
{isPrivate ? '***' : children}
</styled.span>
</BasicTooltip>
);
}
25 changes: 25 additions & 0 deletions src/app/components/privacy/private-text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { type HTMLStyledProps } from 'leather-styles/jsx';

import { PrivateTextLayout } from '@app/components/privacy/private-text.layout';
import { useTogglePrivateMode } from '@app/store/settings/settings.actions';
import { useIsPrivateMode } from '@app/store/settings/settings.selectors';

interface PrivateTextProps extends HTMLStyledProps<'span'> {
children: React.ReactNode;
canClickToShow?: boolean;
}

export function PrivateText({ children, canClickToShow, ...rest }: PrivateTextProps) {
const isPrivateMode = useIsPrivateMode();
const togglePrivateMode = useTogglePrivateMode();

return (
<PrivateTextLayout
{...rest}
isPrivate={isPrivateMode}
onShowValue={canClickToShow ? togglePrivateMode : undefined}
>
{children}
</PrivateTextLayout>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { whenPageMode } from '@app/common/utils';
import { openIndexPageInNewTab } from '@app/common/utils/open-in-new-tab';
import { TransactionTitle } from '@app/components/transaction/transaction-title';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useIsPrivateMode } from '@app/store/settings/settings.selectors';

import { TransactionItemLayout } from '../transaction-item/transaction-item.layout';
import { IncreaseFeeButton } from './increase-fee-button';
Expand All @@ -41,6 +42,7 @@ export function StacksTransactionItem({
}: StacksTransactionItemProps) {
const { handleOpenStacksTxLink } = useStacksExplorerLink();
const currentAccount = useCurrentStacksAccount();
const isPrivate = useIsPrivateMode();

const { pathname } = useLocation();
const navigate = useNavigate();
Expand Down Expand Up @@ -96,6 +98,7 @@ export function StacksTransactionItem({
txStatus={txStatus}
txTitle={<TransactionTitle title={txTitle} />}
txValue={txValue}
isPrivate={isPrivate}
/>
);
}
14 changes: 9 additions & 5 deletions src/app/components/transaction-item/transaction-item.layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { ReactNode } from 'react';

import { HStack, styled } from 'leather-styles/jsx';
import { HStack } from 'leather-styles/jsx';

import { Caption, ItemLayout, Pressable } from '@leather.io/ui';

import { PrivateTextLayout } from '@app/components/privacy/private-text.layout';

interface TransactionItemLayoutProps {
openTxLink(): void;
rightElement?: ReactNode;
Expand All @@ -13,13 +15,14 @@ interface TransactionItemLayoutProps {
txIcon?: ReactNode;
txStatus?: ReactNode;
children?: ReactNode;
isPrivate?: boolean;
}

function TxValue({ txValue }: { txValue: ReactNode }) {
function TxValue({ txValue, isPrivate }: { txValue: ReactNode; isPrivate?: boolean }) {
return (
<styled.span textStyle="label.02" px="space.02">
<PrivateTextLayout isPrivate={isPrivate} textStyle="label.02" px="space.02">
{txValue}
</styled.span>
</PrivateTextLayout>
);
}

Expand All @@ -31,6 +34,7 @@ export function TransactionItemLayout({
txStatus,
txTitle,
txValue,
isPrivate,
}: TransactionItemLayoutProps) {
return (
<Pressable onClick={openTxLink} my="space.02">
Expand All @@ -49,7 +53,7 @@ export function TransactionItemLayout({
{txStatus && txStatus}
</HStack>
}
titleRight={<TxValue txValue={txValue} />}
titleRight={<TxValue txValue={txValue} isPrivate={isPrivate} />}
captionRight={rightElement}
/>
</Pressable>
Expand Down
3 changes: 3 additions & 0 deletions src/app/features/asset-list/asset-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Stx20TokenAssetList } from '@app/features/asset-list/stacks/stx20-token
import { StxCryptoAssetItem } from '@app/features/asset-list/stacks/stx-crypo-asset-item/stx-crypto-asset-item';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useHasLedgerKeys } from '@app/store/ledger/ledger.selectors';
import { useIsPrivateMode } from '@app/store/settings/settings.selectors';

import { ConnectLedgerAssetItemFallback } from './_components/connect-ledger-asset-item-fallback';
import { BtcCryptoAssetItem } from './bitcoin/btc-crypto-asset-item/btc-crypto-asset-item';
Expand All @@ -36,6 +37,7 @@ interface AssetListProps {
export function AssetList({ onSelectAsset, variant = 'read-only' }: AssetListProps) {
const currentAccount = useCurrentStacksAccount();
const isLedger = useHasLedgerKeys();
const isPrivate = useIsPrivateMode();

const isReadOnly = variant === 'read-only';

Expand Down Expand Up @@ -85,6 +87,7 @@ export function AssetList({ onSelectAsset, variant = 'read-only' }: AssetListPro
<StxCryptoAssetItem
balance={balance}
isLoading={isLoading}
isPrivate={isPrivate}
onSelectAsset={onSelectAsset}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { convertAssetBalanceToFiat } from '@app/common/asset-utils';
import { CryptoAssetItemLayout } from '@app/components/crypto-asset-item/crypto-asset-item.layout';
import type { AssetListVariant } from '@app/features/asset-list/asset-list';
import { useCurrentBtcCryptoAssetBalanceNativeSegwit } from '@app/query/bitcoin/balance/btc-balance-native-segwit.hooks';
import { useIsPrivateMode } from '@app/store/settings/settings.selectors';

interface Brc20TokenAssetDetails {
balance: CryptoAssetBalance;
Expand All @@ -30,6 +31,7 @@ function getBrc20TokenFiatBalance(token: Brc20TokenAssetDetails) {

export function Brc20TokenAssetList({ tokens }: Brc20TokenAssetListProps) {
const { isLoading } = useCurrentBtcCryptoAssetBalanceNativeSegwit();
const isPrivate = useIsPrivateMode();

if (!tokens.length) return null;
return (
Expand All @@ -40,6 +42,7 @@ export function Brc20TokenAssetList({ tokens }: Brc20TokenAssetListProps) {
captionLeft={token.info.name.toUpperCase()}
icon={<Brc20AvatarIcon />}
isLoading={isLoading}
isPrivate={isPrivate}
key={token.info.symbol}
titleLeft={token.info.symbol}
fiatBalance={getBrc20TokenFiatBalance(token)}
Expand Down
Loading
Loading