Skip to content

Commit

Permalink
feat: add option to hide balance, closes #5096
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianocola authored and pete-watters committed Sep 11, 2024
1 parent 36a84dc commit cd9192f
Show file tree
Hide file tree
Showing 19 changed files with 235 additions and 36 deletions.
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
8 changes: 7 additions & 1 deletion src/app/components/balance/btc-balance.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Caption } from '@leather.io/ui';
import { formatMoney } from '@leather.io/utils';

import { PrivateText } from '@app/components/privacy/private-text';

import { BitcoinNativeSegwitAccountLoader } from '../loaders/bitcoin-account-loader';
import { BtcBalanceLoader } from '../loaders/btc-balance-loader';

Expand All @@ -9,7 +11,11 @@ export function BtcBalance() {
<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>
);
}
15 changes: 10 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,8 @@ import {
} from '@leather.io/ui';
import { spamFilter } from '@leather.io/utils';

import { PrivateText } from '@app/components/privacy/private-text';
import { useIsPrivacyMode } from '@app/store/settings/settings.selectors';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';

import { parseCryptoAssetBalance } from './crypto-asset-item.layout.utils';
Expand Down Expand Up @@ -43,24 +45,27 @@ export function CryptoAssetItemLayout({
titleLeft,
titleRightBulletInfo,
}: CryptoAssetItemLayoutProps) {
const isPrivacyMode = useIsPrivacyMode();
const { availableBalanceString, dataTestId, formattedBalance } =
parseCryptoAssetBalance(availableBalance);

const titleRight = (
<SkeletonLoader width="126px" isLoading={isLoading}>
<BasicTooltip
asChild
label={formattedBalance.isAbbreviated ? availableBalanceString : undefined}
label={
formattedBalance.isAbbreviated && !isPrivacyMode ? availableBalanceString : undefined
}
side="left"
>
<Flex alignItems="center" gap="space.02" textStyle="label.02">
<BulletSeparator>
<styled.span
<PrivateText
data-state={isLoadingAdditionalData ? 'loading' : undefined}
className={shimmerStyles}
>
{formattedBalance.value} {balanceSuffix}
</styled.span>
</PrivateText>
{titleRightBulletInfo}
</BulletSeparator>
</Flex>
Expand All @@ -76,7 +81,7 @@ export function CryptoAssetItemLayout({
data-state={isLoadingAdditionalData ? 'loading' : undefined}
className={shimmerStyles}
>
{availableBalance.amount.toNumber() > 0 ? fiatBalance : null}
<PrivateText>{availableBalance.amount.toNumber() > 0 ? fiatBalance : null}</PrivateText>
</Caption>
{captionRightBulletInfo}
</BulletSeparator>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Box, Flex, HStack, styled } from 'leather-styles/jsx';

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

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

interface AvailableBalanceProps {
Expand All @@ -26,7 +27,7 @@ export function AvailableBalance({
</BasicTooltip>
</HStack>
<styled.span color="ink.text-subdued" mr="space.02" textStyle="caption.01">
{balance}
<PrivateText canClickToShow>{balance}</PrivateText>
</styled.span>
</Flex>
);
Expand Down
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 { useTogglePrivacyMode } from '@app/store/settings/settings.actions';
import { useIsPrivacyMode } from '@app/store/settings/settings.selectors';
import { PrivateTextLayout } from '@app/ui/components/privacy/private-text.layout';

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

export function PrivateText({ children, canClickToShow, ...rest }: PrivacyAwareProps) {
const isPrivacyMode = useIsPrivacyMode();
const togglePrivacyMode = useTogglePrivacyMode();

return (
<PrivateTextLayout
{...rest}
isPrivate={isPrivacyMode}
onShowValue={canClickToShow ? togglePrivacyMode : undefined}
>
{children}
</PrivateTextLayout>
);
}
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 { PrivateText } from '@app/components/privacy/private-text';

interface TransactionItemLayoutProps {
openTxLink(): void;
rightElement?: ReactNode;
Expand All @@ -17,9 +19,9 @@ interface TransactionItemLayoutProps {

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from '@leather.io/utils';

import { CryptoAssetItemLayout } from '@app/components/crypto-asset-item/crypto-asset-item.layout';
import { PrivateText } from '@app/components/privacy/private-text';

interface StxCryptoAssetItemProps {
balance: StxCryptoAssetBalance;
Expand All @@ -29,9 +30,15 @@ export function StxCryptoAssetItem({ balance, isLoading, onSelectAsset }: StxCry
baseCurrencyAmountInQuote(availableBalance, marketData)
);
const titleRightBulletInfo = (
<styled.span>{formatMoneyWithoutSymbol(lockedBalance)} locked</styled.span>
<styled.span>
<PrivateText>{formatMoneyWithoutSymbol(lockedBalance)}</PrivateText> locked
</styled.span>
);
const captionRightBulletInfo = (
<Caption>
<PrivateText>{fiatLockedBalance}</PrivateText> locked
</Caption>
);
const captionRightBulletInfo = <Caption>{fiatLockedBalance} locked</Caption>;

return (
<CryptoAssetItemLayout
Expand Down
21 changes: 21 additions & 0 deletions src/app/features/settings/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
ExitIcon,
ExpandIcon,
ExternalLinkIcon,
Eye1ClosedIcon,
Eye1Icon,
Flag,
GlobeTiltedIcon,
KeyIcon,
Expand All @@ -37,6 +39,8 @@ import { SignOut } from '@app/features/settings/sign-out/sign-out-confirm';
import { ThemeSheet } from '@app/features/settings/theme/theme-dialog';
import { useLedgerDeviceTargetId } from '@app/store/ledger/ledger.selectors';
import { useCurrentNetworkId } from '@app/store/networks/networks.selectors';
import { useTogglePrivacyMode } from '@app/store/settings/settings.actions';
import { useIsPrivacyMode } from '@app/store/settings/settings.selectors';

import { openFeedbackSheet } from '../feedback-button/feedback-button';
import { extractDeviceNameFromKnownTargetIds } from '../ledger/utils/generic-ledger-utils';
Expand Down Expand Up @@ -67,6 +71,9 @@ export function Settings({
const { walletType } = useWalletType();
const targetId = useLedgerDeviceTargetId();

const isPrivacyMode = useIsPrivacyMode();
const togglePrivacyMode = useTogglePrivacyMode();

const location = useLocation();

const { isPressed: showAdvancedMenuOptions } = useModifierKey('alt', 120);
Expand Down Expand Up @@ -189,6 +196,20 @@ export function Settings({
</Flex>
</Flag>
</DropdownMenu.Item>

<DropdownMenu.Item
data-testid={SettingsSelectors.TogglePrivacy}
onSelect={() => {
void analytics.track('click_toggle_privacy');
togglePrivacyMode();
}}
>
<Flag img={isPrivacyMode ? <Eye1ClosedIcon /> : <Eye1Icon />}>
<Flex justifyContent="space-between" textStyle="label.02">
Toggle privacy
</Flex>
</Flag>
</DropdownMenu.Item>
</DropdownMenu.Group>
<Divider />
<DropdownMenu.Group>
Expand Down
6 changes: 6 additions & 0 deletions src/app/pages/home/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { ModalBackgroundWrapper } from '@app/routes/components/modal-background-
import { useCurrentAccountIndex } from '@app/store/accounts/account';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useTogglePrivacyMode } from '@app/store/settings/settings.actions';
import { useIsPrivacyMode } from '@app/store/settings/settings.selectors';
import { AccountCard } from '@app/ui/components/account/account.card';

import { AccountActions } from './components/account-actions';
Expand All @@ -30,6 +32,8 @@ export function Home() {
const navigate = useNavigate();
const account = useCurrentStacksAccount();
const currentAccountIndex = useCurrentAccountIndex();
const isPrivacyMode = useIsPrivacyMode();
const togglePrivacyMode = useTogglePrivacyMode();

const { data: name = '', isFetching: isFetchingBnsName } = useAccountDisplayName({
address: account?.address || '',
Expand Down Expand Up @@ -66,6 +70,8 @@ export function Home() {
isFetchingBnsName={isFetchingBnsName}
isLoadingBalance={isLoading}
isLoadingAdditionalData={isLoadingAdditionalData}
isBalancePrivate={isPrivacyMode}
onShowBalance={togglePrivacyMode}
>
<AccountActions />
</AccountCard>
Expand Down
5 changes: 5 additions & 0 deletions src/app/store/settings/settings.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ export function useDismissMessage() {
const dispatch = useDispatch();
return (messageId: string) => dispatch(settingsActions.messageDismissed(messageId));
}

export function useTogglePrivacyMode() {
const dispatch = useDispatch();
return () => dispatch(settingsActions.togglePrivacyMode());
}
6 changes: 6 additions & 0 deletions src/app/store/settings/settings.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,9 @@ const selectDismissedMessageIds = createSelector(
export function useDismissedMessageIds() {
return useSelector(selectDismissedMessageIds);
}

const selectIsPrivacyMode = createSelector(selectSettings, state => state.isPrivacyMode ?? false);

export function useIsPrivacyMode() {
return useSelector(selectIsPrivacyMode);
}
4 changes: 4 additions & 0 deletions src/app/store/settings/settings.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { UserSelectedTheme } from '@app/common/theme-provider';
interface InitialState {
userSelectedTheme: UserSelectedTheme;
dismissedMessages: string[];
isPrivacyMode?: boolean;
}

const initialState: InitialState = {
Expand All @@ -26,5 +27,8 @@ export const settingsSlice = createSlice({
resetMessages(state) {
state.dismissedMessages = [];
},
togglePrivacyMode(state) {
state.isPrivacyMode = !state.isPrivacyMode;
},
},
});
32 changes: 32 additions & 0 deletions src/app/ui/components/account/account.card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { useState } from 'react';

import { TooltipProvider } from '@radix-ui/react-tooltip';
import type { Meta } from '@storybook/react';
import { Flex } from 'leather-styles/jsx';

Expand All @@ -15,6 +18,13 @@ const meta: Meta<typeof Component> = {
component: Component,
tags: ['autodocs'],
title: 'Layout/AccountCard',
decorators: [
Story => (
<TooltipProvider>
<Story />
</TooltipProvider>
),
],
};

export default meta;
Expand Down Expand Up @@ -75,3 +85,25 @@ export function AccountCardBnsNameLoading() {
</Component>
);
}

export function AccountCardPrivateBalance() {
const [isBalanceHidden, setisBalanceHidden] = useState(true);
return (
<Component
name="leather.btc"
balance="$1,000"
toggleSwitchAccount={() => null}
isLoadingBalance={false}
isFetchingBnsName={false}
isBalancePrivate={isBalanceHidden}
onShowBalance={() => setisBalanceHidden(false)}
>
<Flex justify="space-between">
<IconButton icon={<ArrowUpIcon />} label="Send" />
<IconButton icon={<ArrowDownIcon />} label="Receive" />
<IconButton icon={<PlusIcon />} label="Buy" />
<IconButton icon={<ArrowsRepeatLeftRightIcon />} label="Swap" />
</Flex>
</Component>
);
}
Loading

0 comments on commit cd9192f

Please sign in to comment.