Skip to content

Commit

Permalink
feat(suite): add new token select into send form
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasklim committed Nov 22, 2024
1 parent f4e57ba commit cf5fb05
Show file tree
Hide file tree
Showing 9 changed files with 564 additions and 278 deletions.
132 changes: 132 additions & 0 deletions packages/suite/src/components/suite/copy/TokenAddressRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { MouseEvent, useState } from 'react';

import styled, { css, useTheme } from 'styled-components';

import { Icon, Link, Text, TextProps } from '@trezor/components';
import { borders, spacingsPx } from '@trezor/theme';

const IconWrapper = styled.div`
display: none;
padding: ${spacingsPx.xxxs};
border-radius: ${borders.radii.xxxs};
margin-left: ${spacingsPx.xxs};
background-color: ${({ theme }) => theme.iconSubdued};
height: 16px;
align-items: center;
justify-content: center;
&:hover {
opacity: 0.7;
}
`;

const onHoverTextOverflowContainerHover = css`
border-radius: ${borders.radii.xxxs};
background-color: ${({ theme }) => theme.backgroundSurfaceElevation2};
outline: ${borders.widths.large} solid ${({ theme }) => theme.backgroundSurfaceElevation2};
z-index: 3;
${IconWrapper} {
display: flex;
}
`;

const TextOverflowContainer = styled.div<{ $shouldAllowCopy?: boolean }>`
position: relative;
display: inline-flex;
align-items: center;
max-width: 100%;
overflow: hidden;
cursor: ${({ $shouldAllowCopy }) => ($shouldAllowCopy ? 'pointer' : 'cursor')};
user-select: none;
${({ $shouldAllowCopy }) =>
$shouldAllowCopy &&
css`
@media (hover: none) {
${onHoverTextOverflowContainerHover}
}
&:hover,
&:focus {
${onHoverTextOverflowContainerHover}
}
`}
`;

interface TokenAddressRowProps {
tokenExplorerUrl?: string;
tokenContractAddress: string | null;
shouldAllowCopy?: boolean;
typographyStyle?: TextProps['typographyStyle'];
variant?: TextProps['variant'];
onCopy: () => void;
}

// This is needed because icon interferes with pointer events of Select
// eslint-disable-next-line local-rules/no-override-ds-component
const IconWithNoPointer = styled(Icon)`
pointer-events: none;
`;

// TODO: this component is little bit copy/paste of IOAddress component, please check it
export const TokenAddressRow = ({
tokenContractAddress,
tokenExplorerUrl,
shouldAllowCopy = true,
typographyStyle = 'label',
variant = 'default',
onCopy,
}: TokenAddressRowProps) => {
const [isClicked, setIsClicked] = useState(false);
const theme = useTheme();

if (!tokenContractAddress) return null;

const copy = (event: MouseEvent) => {
setIsClicked(true);
event.stopPropagation();
onCopy();
};

const shortenedTokenAddress = `${tokenContractAddress.slice(0, 6)}...${tokenContractAddress.slice(-4)}`;

return (
<Text typographyStyle={typographyStyle} variant={variant}>
<TextOverflowContainer
onMouseLeave={() => setIsClicked(false)}
data-testid="@tx-detail/txid-value"
id={tokenContractAddress}
$shouldAllowCopy={shouldAllowCopy}
>
<Text textWrap="nowrap">{shortenedTokenAddress}</Text>
{shouldAllowCopy ? (
<IconWrapper onClick={copy}>
<IconWithNoPointer
name={isClicked ? 'check' : 'copy'}
size={12}
color={theme.iconOnPrimary}
/>
</IconWrapper>
) : null}
{tokenExplorerUrl ? (
<IconWrapper>
<Link
type="label"
variant="nostyle"
href={tokenExplorerUrl}
target="_blank"
onClick={e => e.stopPropagation()}
>
<IconWithNoPointer
name="arrowUpRight"
size={12}
color={theme.iconOnPrimary}
/>
</Link>
</IconWrapper>
) : null}
</TextOverflowContainer>
</Text>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { Account } from '@suite-common/wallet-types';
import { spacingsPx, zIndices, typography } from '@trezor/theme';
import { H2 } from '@trezor/components';
import { CoinLogo } from '@trezor/product-components';
import { isTestnet } from '@suite-common/wallet-utils';

import {
MetadataLabeling,
Expand Down Expand Up @@ -143,12 +142,13 @@ export const AccountDetails = ({ selectedAccount, isBalanceShown }: AccountDetai
<FormattedCryptoAmount value={formattedBalance} symbol={symbol} />
</AmountUnitSwitchWrapper>
</CryptoBalance>
{!isTestnet(symbol) && (
<ForegroundWrapper>
≈&nbsp;
<FiatValue amount={formattedBalance} symbol={symbol} />
</ForegroundWrapper>
)}
<ForegroundWrapper>
<FiatValue
amount={formattedBalance}
symbol={symbol}
showApproximationIndicator
/>
</ForegroundWrapper>
</AccountBalance>
)}
</DetailsContainer>
Expand Down
8 changes: 8 additions & 0 deletions packages/suite/src/support/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@ const messages = defineMessagesWithTypeCheck({
defaultMessage: 'Search by name, symbol, network, or contract address',
id: 'TR_SELECT_NAME_OR_ADDRESS',
},
TR_SEARCH_TOKEN_IN_SEND_FORM_MODAL: {
defaultMessage: 'Search by name, symbol, or contract address',
id: 'TR_SEARCH_TOKEN_IN_SEND_FORM_MODAL',
},
TR_TOKEN_NOT_FOUND: {
defaultMessage: 'No token found',
id: 'TR_TOKEN_NOT_FOUND',
Expand Down Expand Up @@ -9156,6 +9160,10 @@ const messages = defineMessagesWithTypeCheck({
id: 'TR_PASSPHRASE_DESCRIPTION_ITEM3',
defaultMessage: 'No one can recover it, not even Trezor Support',
},
TR_UNRECOGNIZED: {
id: 'TR_UNRECOGNIZED',
defaultMessage: 'Unrecognized',
},
TR_CONNECT_DEVICE_SEND_PROMO_TITLE: {
id: 'TR_CONNECT_DEVICE_SEND_PROMO_TITLE',
defaultMessage: "Your Trezor isn't connected",
Expand Down
4 changes: 2 additions & 2 deletions packages/suite/src/utils/wallet/tokenUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BigNumber } from '@trezor/utils/src/bigNumber';
import { Account, Rate, TokenAddress, RatesByKey } from '@suite-common/wallet-types';
import { TokenInfo } from '@trezor/connect';
import { getFiatRateKey, isTokenMatchesSearch } from '@suite-common/wallet-utils';
import { getFiatRateKey, isNftToken, isTokenMatchesSearch } from '@suite-common/wallet-utils';
import { NetworkSymbol, getNetworkFeatures } from '@suite-common/wallet-config';
import { FiatCurrencyCode } from '@suite-common/suite-config';
import {
Expand Down Expand Up @@ -72,7 +72,7 @@ export const getTokens = (
searchQuery?: string,
) => {
// filter out NFT tokens until we implement them
const tokensWithoutNFTs = tokens.filter(token => !['ERC1155', 'ERC721'].includes(token.type));
const tokensWithoutNFTs = tokens.filter(token => !isNftToken(token));

const hasCoinDefinitions = getNetworkFeatures(symbol).includes('coin-definitions');

Expand Down
41 changes: 10 additions & 31 deletions packages/suite/src/views/wallet/send/Outputs/Amount/Amount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
findToken,
} from '@suite-common/wallet-utils';

import { FiatValue, Translation, NumberInput, HiddenPlaceholder } from 'src/components/suite';
import { FiatValue, Translation, NumberInput } from 'src/components/suite';
import { useSendFormContext } from 'src/hooks/wallet';
import { useBitcoinAmountUnit } from 'src/hooks/wallet/useBitcoinAmountUnit';
import { useTranslation } from 'src/hooks/suite';
Expand All @@ -23,16 +23,14 @@ import {
validateMin,
validateReserveOrBalance,
} from 'src/utils/suite/validation';
import { formatTokenSymbol } from 'src/utils/wallet/tokenUtils';

import { TokenSelect } from './TokenSelect';
import { FiatInput } from './FiatInput';
import { SendMaxSwitch } from './SendMaxSwitch';

type AmountProps = {
interface AmountProps {
output: Partial<Output>;
outputId: number;
};
}
export const Amount = ({ output, outputId }: AmountProps) => {
const { translationString } = useTranslation();
const {
Expand Down Expand Up @@ -83,7 +81,7 @@ export const Amount = ({ output, outputId }: AmountProps) => {
}

const withTokens = hasNetworkFeatures(account, 'tokens');
const symbolToUse = shouldSendInSats ? 'sat' : symbol.toUpperCase();
const displayNetworkSymbol = shouldSendInSats ? 'sat' : symbol.toUpperCase();
const isLowAnonymity = isLowAnonymityWarning(outputError);
const inputState = isLowAnonymity ? 'warning' : getInputState(error);
const bottomText = isLowAnonymity ? undefined : error?.message;
Expand Down Expand Up @@ -129,13 +127,6 @@ export const Amount = ({ output, outputId }: AmountProps) => {
composeTransaction(amountName);
};

const isTokenSelected = !!token;
const tokenBalance = isTokenSelected ? (
<HiddenPlaceholder>
{`${token.balance} ${formatTokenSymbol(token?.symbol || token.contract)}`}
</HiddenPlaceholder>
) : undefined;

const sendMaxSwitch = (
<SendMaxSwitch
isSetMaxActive={isSetMaxActive}
Expand All @@ -158,18 +149,8 @@ export const Amount = ({ output, outputId }: AmountProps) => {
}
labelRight={isSetMaxVisible && (!isWithRate || isBelowLaptop) && sendMaxSwitch}
labelLeft={
<Row gap={spacings.sm} alignItems="baseline">
<Row>
<Translation id="AMOUNT" />
{isTokenSelected && (
<Text variant="tertiary" typographyStyle="label">
(
<Translation
id="TOKEN_BALANCE"
values={{ balance: tokenBalance }}
/>
)
</Text>
)}
</Row>
}
bottomText={bottomText || null}
Expand All @@ -181,13 +162,11 @@ export const Amount = ({ output, outputId }: AmountProps) => {
rules={cryptoAmountRules}
control={control}
innerAddon={
withTokens ? (
<TokenSelect output={output} outputId={outputId} />
) : (
<Text variant="tertiary" typographyStyle="hint">
{symbolToUse}
</Text>
)
<Text variant="tertiary">
{withTokens && token
? token?.symbol?.toUpperCase()
: displayNetworkSymbol}
</Text>
}
/>

Expand Down
Loading

0 comments on commit cf5fb05

Please sign in to comment.