Skip to content

Commit

Permalink
feat: ui items, closes #4314 and #4840
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf committed Jan 31, 2024
1 parent b21decb commit 208c557
Show file tree
Hide file tree
Showing 55 changed files with 845 additions and 612 deletions.
108 changes: 56 additions & 52 deletions src/app/components/account/account-list-item-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,82 @@
import { ComponentProps, ReactNode } from 'react';

import { SettingsSelectors } from '@tests/selectors/settings.selectors';
import { Flex, HStack, Stack, StackProps, styled } from 'leather-styles/jsx';
import { HStack } from 'leather-styles/jsx';

import { useViewportMinWidth } from '@app/common/hooks/use-media-query';
import { BulletSeparator } from '@app/ui/components/bullet-separator/bullet-separator';
import { CheckmarkIcon } from '@app/ui/components/icons/checkmark-icon';
import { Item } from '@app/ui/components/items/item';
import { ItemDefaultLayout } from '@app/ui/components/items/item-default.layout';
import { Spinner } from '@app/ui/components/spinner';
import { truncateMiddle } from '@app/ui/utils/truncate-middle';

import { Flag } from '../layout/flag';
import { StacksAccountLoader } from '../loaders/stacks-account-loader';
import { BitcoinNativeSegwitAccountLoader } from './bitcoin-account-loader';

interface AccountListItemLayoutProps extends StackProps {
isLoading: boolean;
isActive: boolean;
interface AccountListItemLayoutProps extends ComponentProps<'div'> {
accountName: ReactNode;
avatar: ReactNode;
balanceLabel: ReactNode;
index: number;
accountName: React.ReactNode;
avatar: React.JSX.Element;
balanceLabel: React.ReactNode;
isLoading: boolean;
isPressable?: boolean;
isSelected: boolean;
onSelectAccount(): void;
}
export function AccountListItemLayout(props: AccountListItemLayoutProps) {
const {
index,
isLoading,
isActive,
accountName,
avatar,
balanceLabel,
index,
isLoading,
isPressable,
isSelected,
onSelectAccount,
children = null,
...rest
} = props;

const isBreakpointSm = useViewportMinWidth('sm');

return (
<Flex
width="100%"
key={`account-${index}`}
<Item.Root
data-testid={SettingsSelectors.SwitchAccountItemIndex.replace('[index]', `${index}`)}
cursor="pointer"
position="relative"
isPressable={isPressable}
key={`account-${index}`}
onClick={onSelectAccount}
{...rest}
>
<Flag align="middle" img={avatar} spacing="space.04" width="100%" mx="space.04">
<Stack gap="space.01">
<HStack alignItems="center" justifyContent="space-between">
<HStack alignItems="center" gap="space.02">
{accountName}
{isActive && <CheckmarkIcon />}
<Item.Content>
<ItemDefaultLayout
isPressable={isPressable}
flagImg={avatar}
contentLeftTop={
<HStack gap="space.01">
<Item.Text>{accountName}</Item.Text>
{isSelected && <CheckmarkIcon />}
</HStack>
{isLoading ? (
}
contentLeftBottom={
<HStack alignItems="center" gap="space.02" whiteSpace="nowrap">
<BulletSeparator>
<StacksAccountLoader index={index}>
{account => (
<Item.Caption textStyle="caption.01">
{truncateMiddle(account.address, isBreakpointSm ? 4 : 3)}
</Item.Caption>
)}
</StacksAccountLoader>
<BitcoinNativeSegwitAccountLoader index={index}>
{signer => (
<Item.Caption textStyle="caption.01">
{truncateMiddle(signer.address, 5)}
</Item.Caption>
)}
</BitcoinNativeSegwitAccountLoader>
</BulletSeparator>
</HStack>
}
contentRightTop={
isLoading ? (
<Spinner
color="accent.text-subdued"
position="absolute"
Expand All @@ -61,31 +85,11 @@ export function AccountListItemLayout(props: AccountListItemLayoutProps) {
top="calc(50% - 8px)"
/>
) : (
balanceLabel
)}
</HStack>
<HStack alignItems="center" gap="space.02" whiteSpace="nowrap">
<BulletSeparator>
<StacksAccountLoader index={index}>
{account => (
<styled.span textStyle="caption.02">
{truncateMiddle(account.address, isBreakpointSm ? 4 : 3)}
</styled.span>
)}
</StacksAccountLoader>

<BitcoinNativeSegwitAccountLoader index={index}>
{signer => (
<styled.span textStyle="caption.02">
{truncateMiddle(signer.address, 5)}
</styled.span>
)}
</BitcoinNativeSegwitAccountLoader>
</BulletSeparator>
</HStack>
</Stack>
</Flag>
{children}
</Flex>
<Item.Text>{balanceLabel}</Item.Text>
)
}
/>
</Item.Content>
</Item.Root>
);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { useMemo } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

import { BoxProps } from 'leather-styles/jsx';

import { BitcoinTx } from '@shared/models/transactions/bitcoin-transaction.model';
import { RouteUrls } from '@shared/route-urls';

Expand All @@ -15,7 +13,6 @@ import {
isBitcoinTxInbound,
} from '@app/common/transactions/bitcoin/utils';
import { openInNewTab } from '@app/common/utils/open-in-new-tab';
import { usePressable } from '@app/components/item-hover';
import { IncreaseFeeButton } from '@app/components/stacks-transaction-item/increase-fee-button';
import { TransactionTitle } from '@app/components/transaction/transaction-title';
import {
Expand All @@ -34,11 +31,10 @@ import { InscriptionIcon } from './bitcoin-transaction-inscription-icon';
import { BitcoinTransactionStatus } from './bitcoin-transaction-status';
import { BitcoinTransactionValue } from './bitcoin-transaction-value';

interface BitcoinTransactionItemProps extends BoxProps {
interface BitcoinTransactionItemProps {
transaction: BitcoinTx;
}
export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransactionItemProps) {
const [component, bind, { isHovered }] = usePressable(true);
export function BitcoinTransactionItem({ transaction }: BitcoinTransactionItemProps) {
const { pathname } = useLocation();
const navigate = useNavigate();

Expand Down Expand Up @@ -92,7 +88,6 @@ export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransact
const increaseFeeButton = (
<IncreaseFeeButton
isEnabled={isEnabled}
isHovered={isHovered}
isSelected={pathname === RouteUrls.IncreaseBtcFee}
onIncreaseFee={onIncreaseFee}
/>
Expand All @@ -101,6 +96,7 @@ export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransact
return (
<TransactionItemLayout
openTxLink={openTxLink}
rightElement={isEnabled ? increaseFeeButton : undefined}
txCaption={txCaption}
txIcon={
<BitcoinTransactionIcon
Expand All @@ -112,11 +108,6 @@ export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransact
txStatus={<BitcoinTransactionStatus transaction={transaction} />}
txTitle={<TransactionTitle title={title} />}
txValue={txValue}
belowCaptionEl={increaseFeeButton}
{...bind}
{...rest}
>
{component}
</TransactionItemLayout>
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { useNavigate } from 'react-router-dom';
import { RouteUrls } from '@shared/route-urls';
import { noop } from '@shared/utils';

import { Brc20TokenAssetItem } from '@app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';

import { Brc20TokenAssetItemLayout } from './components/brc20-token-asset-item.layout';
import { Brc20AssetListLayout } from './components/brc20-token-asset-list.layout';

export function Brc20TokenAssetList(props: { brc20Tokens?: Brc20Token[] }) {
const navigate = useNavigate();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
Expand All @@ -24,13 +26,18 @@ export function Brc20TokenAssetList(props: { brc20Tokens?: Brc20Token[] }) {
}

if (!props.brc20Tokens?.length) return null;
return props.brc20Tokens.map(token => (
<Brc20TokenAssetItem
token={token}
isPressable={hasPositiveBtcBalanceForFees}
onClick={hasPositiveBtcBalanceForFees ? () => navigateToBrc20SendForm(token) : noop}
displayNotEnoughBalance={!hasPositiveBtcBalanceForFees}
key={token.tick}
/>
));

return (
<Brc20AssetListLayout>
{props.brc20Tokens?.map(token => (
<Brc20TokenAssetItemLayout
key={token.tick}
displayNotEnoughBalance={!hasPositiveBtcBalanceForFees}
token={token}
isPressable={hasPositiveBtcBalanceForFees}
onClick={hasPositiveBtcBalanceForFees ? () => navigateToBrc20SendForm(token) : noop}
/>
))}
</Brc20AssetListLayout>
);
}
Original file line number Diff line number Diff line change
@@ -1,69 +1,52 @@
import { BoxProps, Flex, HStack, styled } from 'leather-styles/jsx';

import type { Money } from '@shared/models/money.model';
import { createMoney } from '@shared/models/money.model';

import { formatBalance } from '@app/common/format-balance';
import { AssetCaption } from '@app/components/crypto-assets/components/asset-caption';
import { usePressable } from '@app/components/item-hover';
import { Flag } from '@app/components/layout/flag';
import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
import { Brc20TokenIcon } from '@app/ui/components/icons/brc20-token-icon';
import { Item } from '@app/ui/components/items/item';
import { ItemDefaultLayout } from '@app/ui/components/items/item-default.layout';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';

interface Brc20TokenAssetItemLayoutProps extends BoxProps {
balance: Money;
caption: string;
interface Brc20TokenAssetItemLayoutProps {
token: Brc20Token;
isPressable?: boolean;
onClick?(): void;
title: string;
displayNotEnoughBalance?: boolean;
}
export function Brc20TokenAssetItemLayout({
balance,
caption,
isPressable,
onClick,
title,
displayNotEnoughBalance,
token,
}: Brc20TokenAssetItemLayoutProps) {
const [component, bind] = usePressable(isPressable);

const balance = createMoney(Number(token.overall_balance), token.tick, 0);
const formattedBalance = formatBalance(balance.amount.toString());

return (
<BasicTooltip
asChild
disabled={!displayNotEnoughBalance}
side="top"
label={'Not enough BTC in balance'}
asChild
side="top"
>
<Flex onClick={isPressable ? onClick : undefined} {...bind}>
<Flag align="middle" img={<Brc20TokenIcon />} spacing="space.04" width="100%">
<HStack alignItems="center" justifyContent="space-between" width="100%">
<styled.span
maxWidth="150px"
overflow="hidden"
textAlign="left"
textOverflow="ellipsis"
textStyle="label.01"
whiteSpace="nowrap"
>
{title}
</styled.span>
<BasicTooltip
label={formattedBalance.isAbbreviated ? balance.amount.toString() : undefined}
side="left"
>
<styled.span data-testid={title} textStyle="label.01">
{formattedBalance.value}
</styled.span>
</BasicTooltip>
</HStack>
<HStack alignItems="center" justifyContent="space-between" height="1.25rem" width="100%">
<AssetCaption caption={caption} />
</HStack>
{component}
</Flag>
</Flex>
<Item.Root isPressable={isPressable} onClick={onClick}>
<Item.Content>
<ItemDefaultLayout
isPressable={isPressable}
flagImg={<Brc20TokenIcon />}
contentLeftTop={<Item.Text>{token.tick}</Item.Text>}
contentLeftBottom={<Item.Caption textStyle="caption.01">{'BRC-20'}</Item.Caption>}
contentRightTop={
<BasicTooltip
label={formattedBalance.isAbbreviated ? balance.amount.toString() : undefined}
side="left"
>
<Item.Text data-testid={token.tick}>{formattedBalance.value}</Item.Text>
</BasicTooltip>
}
/>
</Item.Content>
</Item.Root>
</BasicTooltip>
);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors';
import { Stack, StackProps } from 'leather-styles/jsx';

export function Brc20AssetListLayout({ children }: StackProps) {
return (
<Stack data-testid={CryptoAssetSelectors.CryptoAssetList} width="100%">
{children}
</Stack>
);
}
Loading

0 comments on commit 208c557

Please sign in to comment.