refactor(suite): refactor trading form components

This commit is contained in:
Seibei Iguchi
2026-01-30 14:07:00 +01:00
parent 5eab9826d8
commit 3f1ac0d2e3
15 changed files with 213 additions and 181 deletions

View File

@@ -38,7 +38,9 @@ export const Collapsible = ({
gap,
}}
>
<Container data-testid={dataTest}>{children}</Container>
<Container data-testid={dataTest} aria-expanded={isOpen ?? uncontrolledIsOpen}>
{children}
</Container>
</CollapsibleContext.Provider>
);
};

View File

@@ -1,4 +1,4 @@
import { ReactNode } from 'react';
import { HTMLProps, ReactNode } from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import styled, { CSSProperties } from 'styled-components';
@@ -13,7 +13,7 @@ const Container = styled(motion.div)<{ $overflow?: CSSProperties['overflow'] }>`
overflow: ${({ $overflow = 'hidden' }) => $overflow};
`;
type CollapsibleContentProps = {
type CollapsibleContentProps = Pick<HTMLProps<HTMLDivElement>, 'onClick'> & {
children: ReactNode;
'data-testid'?: string;
onAnimationComplete?: (isOpen: boolean) => void;
@@ -25,6 +25,7 @@ export const CollapsibleContent = ({
onAnimationComplete,
'data-testid': dataTestId,
overflow,
onClick,
}: CollapsibleContentProps) => {
const { isOpen, contentId, gap } = useCollapsible();
@@ -47,6 +48,7 @@ export const CollapsibleContent = ({
aria-expanded={isOpen}
id={contentId}
$overflow={overflow}
onClick={onClick}
>
<Box padding={{ top: gap }}>{children}</Box>
</Container>

View File

@@ -19,8 +19,9 @@ export type CollapsibleFeesProps = {
networkSymbol: NetworkSymbol;
networkType: NetworkType;
rbfForm?: boolean;
isOpen?: boolean;
} & Pick<FeesContextType, 'feeInfo' | 'composedLevels' | 'changeFeeLevel'> &
Omit<CollapsibleFeesHeaderContentProps, 'supportsAdjustableFees' | 'txMaxFee'>;
Omit<CollapsibleFeesHeaderContentProps, 'supportsAdjustableFees' | 'txMaxFee' | 'isOpen'>;
export function CollapsibleFees({
label,
@@ -31,7 +32,7 @@ export function CollapsibleFees({
changeFeeLevel,
rbfForm,
headerTypographyStyle = 'body',
isHeaderRowLayout,
isOpen,
}: CollapsibleFeesProps) {
const selectedFee = useWatch<FormState, 'selectedFee'>({
name: 'selectedFee',
@@ -68,17 +69,17 @@ export function CollapsibleFees({
composedLevels,
}}
>
<Collapsible gap={12}>
<Collapsible gap={12} isOpen={isOpen} data-testid="@wallet/fees/collapsible-fees">
<CollapsibleFeesHeaderContent
label={label}
headerTypographyStyle={headerTypographyStyle}
supportsAdjustableFees={supportsAdjustableFees}
isHeaderRowLayout={isHeaderRowLayout}
txMaxFee={txMaxFee}
isOpen={isOpen}
/>
{supportsAdjustableFees && (
<Collapsible.Content overflow="unset">
<Collapsible.Content overflow="unset" onClick={ev => ev.stopPropagation()}>
<Column gap={16}>
<Column gap={16}>
{!isCustomFee && <StandardFee />}

View File

@@ -4,7 +4,7 @@ import { useTheme } from 'styled-components';
import { Translation, TranslationKey } from '@suite/intl';
import { Icon, Link, Row, Text, Tooltip } from '@trezor/components';
import { TypographyStyle, spacings } from '@trezor/theme';
import { TypographyStyle } from '@trezor/theme';
import { HELP_CENTER_TRANSACTION_FEES_URL } from '@trezor/urls';
import { useFeesContext } from '../context/FeesContext';
@@ -43,7 +43,7 @@ export function CollapsibleFeesHeader({ label, typographyStyle }: CollapsibleFee
}, [networkType]);
return (
<Row flexWrap="wrap" justifyContent="space-between" gap={spacings.sm} minHeight={44}>
<Row flexWrap="wrap" justifyContent="space-between" gap={12} minHeight={44}>
<Tooltip
addon={
networkType === 'ethereum' && (

View File

@@ -1,5 +1,5 @@
import { TranslationKey } from '@suite/intl';
import { Box, Collapsible, Row } from '@trezor/components';
import { Collapsible, Row } from '@trezor/components';
import { TypographyStyle } from '@trezor/theme';
import { ContentFlex } from 'src/support/suite/ContentFlex';
@@ -11,20 +11,24 @@ import { useTransactionMaxFee } from './hooks/useTransactionMaxFee';
export type CollapsibleFeesHeaderContentProps = {
label?: TranslationKey;
headerTypographyStyle?: TypographyStyle;
isHeaderRowLayout?: boolean;
supportsAdjustableFees: boolean;
txMaxFee: ReturnType<typeof useTransactionMaxFee>;
isOpen?: boolean;
};
export const CollapsibleFeesHeaderContent = ({
label,
headerTypographyStyle = 'body',
supportsAdjustableFees,
isHeaderRowLayout,
txMaxFee,
isOpen,
}: CollapsibleFeesHeaderContentProps) => {
const content = (
<ContentFlex justifyContent="space-between" gap={12}>
<ContentFlex
justifyContent="space-between"
gap={12}
data-testid="@wallet/fees/collapsible-fees-toggle"
>
<CollapsibleFeesHeader label={label} typographyStyle={headerTypographyStyle} />
<Row gap={12}>
<MaximumFee typographyStyle={headerTypographyStyle} txMaxFee={txMaxFee} />
@@ -35,20 +39,5 @@ export const CollapsibleFeesHeaderContent = ({
</ContentFlex>
);
return (
<Collapsible.Toggle data-testid="@wallet/fees/collapsible-fees-toggle">
{isHeaderRowLayout ? (
<Box
backgroundColorOnInteraction={
supportsAdjustableFees ? 'backgroundSurfaceElevation2' : undefined
}
padding={{ vertical: 12, horizontal: 16 }}
>
{content}
</Box>
) : (
content
)}
</Collapsible.Toggle>
);
return isOpen !== undefined ? content : <Collapsible.Toggle>{content}</Collapsible.Toggle>;
};

View File

@@ -9,10 +9,15 @@ import { FieldErrorBanner } from './FieldErrorBanner';
export type FeesProps = {
account: Pick<Account, 'symbol' | 'networkType'>;
isHeaderRowLayout?: boolean;
} & Pick<
CollapsibleFeesProps,
'label' | 'rbfForm' | 'feeInfo' | 'changeFeeLevel' | 'composedLevels' | 'headerTypographyStyle'
| 'label'
| 'rbfForm'
| 'feeInfo'
| 'changeFeeLevel'
| 'composedLevels'
| 'headerTypographyStyle'
| 'isOpen'
>;
export const Fees = ({
@@ -23,7 +28,7 @@ export const Fees = ({
label,
rbfForm,
headerTypographyStyle,
isHeaderRowLayout,
isOpen,
}: FeesProps) => {
useFetchFees({ networkSymbol });
@@ -38,7 +43,7 @@ export const Fees = ({
changeFeeLevel={changeFeeLevel}
rbfForm={rbfForm}
headerTypographyStyle={headerTypographyStyle}
isHeaderRowLayout={isHeaderRowLayout}
isOpen={isOpen}
/>
<FieldErrorBanner fieldName="selectedFee" />

View File

@@ -10,10 +10,9 @@ import {
tradingActions,
} from '@suite-common/trading';
import { TokenAddress } from '@suite-common/wallet-types';
import { Card, Column, Divider, Row } from '@trezor/components';
import { Column, Row } from '@trezor/components';
import { hasBitcoinOnlyFirmware } from '@trezor/device-utils/src/firmwareUtils';
import { useCurrentRef } from '@trezor/react-utils';
import { spacings } from '@trezor/theme';
import { useDispatch, useSelector } from 'src/hooks/suite';
import { useTradingFormContext } from 'src/hooks/wallet/trading/form/useTradingCommonForm';
@@ -22,13 +21,15 @@ import { TradingFormInputCountry } from 'src/views/wallet/trading/common/Trading
import { TradingFormInputFiatCrypto } from 'src/views/wallet/trading/common/TradingForm/TradingFormInput/TradingFormInputFiatCrypto/TradingFormInputFiatCrypto';
import { TradingFormInputPaymentMethod } from 'src/views/wallet/trading/common/TradingForm/TradingFormInput/TradingFormInputPaymentMethod';
import { TradingFormCard } from './TradingFormCard';
import { TradingFormFeesDisclamer } from './TradingFormFeeDisclamer';
import { TradingReceiveAddress } from '../TradingSelectedOffer/TradingReceiveAddress/TradingReceiveAddress';
import { TradingFormSection } from './TradingFormSection';
import { TradingSelectedOfferProvider } from '../TradingSelectedOffer/TradingSelectedOfferProvider';
import {
TradingFormInputBuyAsset,
TradingFormInputBuyAssetProps,
} from './TradingFormInput/TradingFormInputBuyAsset/TradingFormInputBuyAsset';
import { TradingReceiveAddress } from '../TradingSelectedOffer/TradingReceiveAddress/TradingReceiveAddress';
export const TradingBuyFormInputs = () => {
const context = useTradingFormContext<TradingBuyType>();
@@ -61,76 +62,56 @@ export const TradingBuyFormInputs = () => {
const buySupportedCryptoIds = useSelector(selectTradingBuySupportedCryptoIds);
return (
<Column gap={spacings.lg}>
<Card paddingType="none">
<Column gap={spacings.lg}>
<Column
gap={spacings.lg}
padding={{
vertical: spacings.md,
horizontal: spacings.lg,
bottom: cryptoSelect.id && !isLoading ? 0 : spacings.md,
}}
>
<Column gap={spacings.xs}>
<TradingFormInputFiatCrypto
cryptoInputName={TRADING_FORM_CRYPTO_INPUT}
fiatInputName={TRADING_FORM_FIAT_INPUT}
cryptoSelectName={TRADING_FORM_CRYPTO_CURRENCY_SELECT}
currencySelectLabel={currencySelect.label}
cryptoCurrencyLabel={cryptoSelect.id}
/>
{amountInCrypto && (
<Row justifyContent="end">
<TradingBalance
balance={cryptoInput}
displaySymbol={cryptoSelect.displaySymbol}
symbol={cryptoSelect.networkSymbol}
tokenAddress={
(cryptoSelect.contractAddress as TokenAddress) ??
undefined
}
showOnlyAmount
amountInCrypto={amountInCrypto}
/>
</Row>
)}
</Column>
<TradingFormInputBuyAsset
inputLabel="TR_TRADING_YOU_BUY"
inputName={TRADING_FORM_CRYPTO_CURRENCY_SELECT}
inputDisabled={hasBitcoinOnlyFirmware(device)}
onAssetSelect={handleCryptoSelect}
includedCryptoIds={buySupportedCryptoIds}
dataTestId="@trading/form/select-crypto-for-buy"
<Column gap={20}>
<TradingFormCard>
<TradingFormSection>
<Column gap={8}>
<TradingFormInputFiatCrypto
cryptoInputName={TRADING_FORM_CRYPTO_INPUT}
fiatInputName={TRADING_FORM_FIAT_INPUT}
cryptoSelectName={TRADING_FORM_CRYPTO_CURRENCY_SELECT}
currencySelectLabel={currencySelect.label}
cryptoCurrencyLabel={cryptoSelect.id}
/>
{amountInCrypto && (
<Row justifyContent="end">
<TradingBalance
balance={cryptoInput}
displaySymbol={cryptoSelect.displaySymbol}
symbol={cryptoSelect.networkSymbol}
tokenAddress={
(cryptoSelect.contractAddress as TokenAddress) ?? undefined
}
showOnlyAmount
amountInCrypto={amountInCrypto}
/>
</Row>
)}
</Column>
{cryptoSelect && !isLoading && <TradingReceiveAddress />}
</Column>
</Card>
<TradingFormInputBuyAsset
inputLabel="TR_TRADING_YOU_BUY"
inputName={TRADING_FORM_CRYPTO_CURRENCY_SELECT}
inputDisabled={hasBitcoinOnlyFirmware(device)}
onAssetSelect={handleCryptoSelect}
includedCryptoIds={buySupportedCryptoIds}
dataTestId="@trading/form/select-crypto-for-buy"
/>
</TradingFormSection>
{cryptoSelect && !isLoading && <TradingReceiveAddress />}
</TradingFormCard>
<Card paddingType="none">
<Column gap={spacings.lg}>
<Column
gap={spacings.lg}
padding={{ vertical: spacings.md, horizontal: spacings.lg }}
>
<TradingFormInputPaymentMethod label="TR_TRADING_PAYMENT_METHOD" />
<TradingFormInputCountry label="TR_TRADING_COUNTRY" />
</Column>
</Column>
<TradingFormCard>
<TradingFormSection>
<TradingFormInputPaymentMethod label="TR_TRADING_PAYMENT_METHOD" />
<TradingFormInputCountry label="TR_TRADING_COUNTRY" />
</TradingFormSection>
<TradingSelectedOfferProvider />
<Divider margin={0} />
<Column
gap={spacings.lg}
padding={{ vertical: spacings.md, horizontal: spacings.lg }}
>
<TradingFormSection>
<TradingFormFeesDisclamer />
</Column>
</Card>
</TradingFormSection>
</TradingFormCard>
</Column>
);
};

View File

@@ -15,31 +15,32 @@ import {
} from '@suite-common/trading';
import { TokenAddress } from '@suite-common/wallet-types';
import { convertAmountSubunitsToUnits } from '@suite-common/wallet-utils';
import { Card, Column, Divider, FractionButton, Row } from '@trezor/components';
import { Column, FractionButton, Row } from '@trezor/components';
import { useCurrentRef } from '@trezor/react-utils';
import { spacings } from '@trezor/theme';
import { Fees } from 'src/components/wallet/Fees/Fees';
import { useDispatch, useSelector } from 'src/hooks/suite';
import { useTradingAssetDecimals } from 'src/hooks/wallet/trading/form/common/useTradingAssetDecimals';
import { useTradingFormContext } from 'src/hooks/wallet/trading/form/useTradingCommonForm';
import { TradingBalance } from 'src/views/wallet/trading/common/TradingBalance';
import { TradingFormInputFiatCrypto } from 'src/views/wallet/trading/common/TradingForm/TradingFormInput/TradingFormInputFiatCrypto/TradingFormInputFiatCrypto';
import { TradingFormCard } from './TradingFormCard';
import { TradingFormFeesDisclamer } from './TradingFormFeeDisclamer';
import { TradingFormFees } from './TradingFormFees';
import { AssetPickerInputBalance } from './TradingFormInput/TradingFormInputAssetPicker';
import {
TradingFormInputBuyAsset,
TradingFormInputBuyAssetProps,
} from './TradingFormInput/TradingFormInputBuyAsset/TradingFormInputBuyAsset';
import { TradingNetworkReserveBanner } from './TradingNetworkReserveBanner';
import { generateFractionButtons } from './tradingFormInputsUtils';
import { TradingReceiveAddress } from '../TradingSelectedOffer/TradingReceiveAddress/TradingReceiveAddress';
import { TradingSelectedOfferProvider } from '../TradingSelectedOffer/TradingSelectedOfferProvider';
import {
TradingFormInputSellAsset,
TradingFormInputSellAssetProps,
} from './TradingFormInput/TradingFormInputSellAsset/TradingFormInputSellAsset';
import { TradingFormSection } from './TradingFormSection';
import { TradingNetworkReserveBanner } from './TradingNetworkReserveBanner';
import { generateFractionButtons } from './tradingFormInputsUtils';
import { TradingReceiveAddress } from '../TradingSelectedOffer/TradingReceiveAddress/TradingReceiveAddress';
import { TradingSelectedOfferProvider } from '../TradingSelectedOffer/TradingSelectedOfferProvider';
export const TradingExchangeFormInputs = () => {
const context = useTradingFormContext<TradingExchangeType>();
@@ -115,8 +116,8 @@ export const TradingExchangeFormInputs = () => {
const exchangeSellSupportedCryptoIds = useSelector(selectTradingExchangeSellCryptoIds);
return (
<Card paddingType="none">
<Column gap={spacings.lg} padding={spacings.lg}>
<TradingFormCard>
<TradingFormSection>
<TradingFormInputSellAsset
inputName={TRADING_FORM_SEND_CRYPTO_CURRENCY_SELECT}
inputLabel="TR_FROM"
@@ -128,7 +129,7 @@ export const TradingExchangeFormInputs = () => {
dataTestId="@trading/form/select-crypto-for-sell"
onAssetSelect={handleSellAssetSelect}
/>
<Column gap={spacings.xs}>
<Column gap={8}>
<TradingFormInputFiatCrypto
cryptoInputName={TRADING_FORM_OUTPUT_AMOUNT}
fiatInputName={TRADING_FORM_OUTPUT_FIAT}
@@ -138,7 +139,7 @@ export const TradingExchangeFormInputs = () => {
/>
{amountInCrypto && (
<Row justifyContent="space-between" alignItems="flex-start">
<Row gap={spacings.xs} data-testid="@trading/form/fraction-buttons">
<Row gap={8} data-testid="@trading/form/fraction-buttons">
{generateFractionButtons(helpers).map(button => (
<FractionButton
key={button.id}
@@ -179,24 +180,19 @@ export const TradingExchangeFormInputs = () => {
onAssetSelect={handleReceiveAssetSelect}
dataTestId="@trading/form/select-crypto-for-buy"
/>
</Column>
</TradingFormSection>
{receiveCryptoSelect && !isLoading && <TradingReceiveAddress />}
<Divider margin={0} />
<Fees
<TradingFormFees
feeInfo={feeInfo}
account={account}
composedLevels={composedLevels}
changeFeeLevel={changeFeeLevel}
isHeaderRowLayout
/>
<TradingSelectedOfferProvider />
<Divider margin={0} />
<Column gap={spacings.lg} padding={{ vertical: spacings.lg, horizontal: spacings.lg }}>
<TradingFormSection>
<TradingFormFeesDisclamer />
</Column>
</Card>
</TradingFormSection>
</TradingFormCard>
);
};

View File

@@ -0,0 +1,7 @@
import { Card, Column } from '@trezor/components';
export const TradingFormCard = ({ children }: { children: React.ReactNode }) => (
<Card paddingType="none">
<Column hasDivider>{children}</Column>
</Card>
);

View File

@@ -0,0 +1,42 @@
import { useState } from 'react';
import { GhostContainer } from '@trezor/components';
import { Fees, FeesProps } from 'src/components/wallet/Fees/Fees';
export type TradingFormFeesProps = Pick<
FeesProps,
'feeInfo' | 'account' | 'composedLevels' | 'changeFeeLevel'
>;
export const TradingFormFees = ({
feeInfo,
account,
composedLevels,
changeFeeLevel,
}: TradingFormFeesProps) => {
const [isOpen, setIsOpen] = useState(false);
return (
<GhostContainer
padding={{ horizontal: 20, vertical: 12 }}
borderRadius={0}
onClick={() => {
setIsOpen(!isOpen);
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
}}
cursor="pointer"
isActive={isOpen}
>
<Fees
feeInfo={feeInfo}
account={account}
composedLevels={composedLevels}
changeFeeLevel={changeFeeLevel}
isOpen={isOpen}
/>
</GhostContainer>
);
};

View File

@@ -0,0 +1,7 @@
import { Column } from '@trezor/components';
export const TradingFormSection = ({ children }: { children: React.ReactNode }) => (
<Column gap={20} padding={20}>
{children}
</Column>
);

View File

@@ -11,11 +11,9 @@ import {
} from '@suite-common/trading';
import { TokenAddress } from '@suite-common/wallet-types';
import { convertAmountSubunitsToUnits } from '@suite-common/wallet-utils';
import { Card, Column, Divider, FractionButton, Row } from '@trezor/components';
import { Column, FractionButton, Row } from '@trezor/components';
import { useCurrentRef } from '@trezor/react-utils';
import { spacings } from '@trezor/theme';
import { Fees } from 'src/components/wallet/Fees/Fees';
import { useSelector } from 'src/hooks/suite';
import { useTradingAssetDecimals } from 'src/hooks/wallet/trading/form/common/useTradingAssetDecimals';
import { useTradingFormContext } from 'src/hooks/wallet/trading/form/useTradingCommonForm';
@@ -24,15 +22,18 @@ import { TradingFormInputCountry } from 'src/views/wallet/trading/common/Trading
import { TradingFormInputFiatCrypto } from 'src/views/wallet/trading/common/TradingForm/TradingFormInput/TradingFormInputFiatCrypto/TradingFormInputFiatCrypto';
import { TradingFormInputPaymentMethod } from 'src/views/wallet/trading/common/TradingForm/TradingFormInput/TradingFormInputPaymentMethod';
import { TradingFormCard } from './TradingFormCard';
import { TradingFormFeesDisclamer } from './TradingFormFeeDisclamer';
import { TradingFormFees } from './TradingFormFees';
import { AssetPickerInputBalance } from './TradingFormInput/TradingFormInputAssetPicker';
import { TradingNetworkReserveBanner } from './TradingNetworkReserveBanner';
import { generateFractionButtons } from './tradingFormInputsUtils';
import { TradingSelectedOfferProvider } from '../TradingSelectedOffer/TradingSelectedOfferProvider';
import {
TradingFormInputSellAsset,
TradingFormInputSellAssetProps,
} from './TradingFormInput/TradingFormInputSellAsset/TradingFormInputSellAsset';
import { TradingFormSection } from './TradingFormSection';
import { TradingNetworkReserveBanner } from './TradingNetworkReserveBanner';
import { generateFractionButtons } from './tradingFormInputsUtils';
import { TradingSelectedOfferProvider } from '../TradingSelectedOffer/TradingSelectedOfferProvider';
export const TradingSellFormInputs = () => {
const context = useTradingFormContext<TradingSellType>();
@@ -78,8 +79,8 @@ export const TradingSellFormInputs = () => {
const sellSupportedCryptoIds = useSelector(selectTradingSellSupportedCryptoIds);
return (
<Card paddingType="none">
<Column gap={spacings.lg} padding={{ vertical: spacings.md, horizontal: spacings.lg }}>
<TradingFormCard>
<TradingFormSection>
<TradingFormInputSellAsset
inputName={TRADING_FORM_SEND_CRYPTO_CURRENCY_SELECT}
inputLabel="TR_TRADING_YOU_SELL"
@@ -90,7 +91,7 @@ export const TradingSellFormInputs = () => {
dataTestId="@trading/form/select-crypto-for-sell"
onAssetSelect={handleSellAssetSelect}
/>
<Column gap={spacings.xs}>
<Column gap={8}>
<TradingFormInputFiatCrypto
cryptoInputName={TRADING_FORM_OUTPUT_AMOUNT}
fiatInputName={TRADING_FORM_OUTPUT_FIAT}
@@ -100,7 +101,7 @@ export const TradingSellFormInputs = () => {
/>
{amountInCrypto && (
<Row justifyContent="space-between" alignItems="flex-start">
<Row gap={spacings.xs} data-testid="@trading/form/fraction-buttons">
<Row gap={8} data-testid="@trading/form/fraction-buttons">
{generateFractionButtons(helpers).map(button => (
<FractionButton key={button.id} {...button} />
))}
@@ -117,32 +118,27 @@ export const TradingSellFormInputs = () => {
</Row>
)}
</Column>
{showReserveBanner && (
<TradingNetworkReserveBanner
symbol={account.symbol}
contractAddress={tokenAddress}
/>
)}
</Column>
<Divider margin={0} />
<Fees
</TradingFormSection>
<TradingFormFees
feeInfo={feeInfo}
account={account}
composedLevels={composedLevels}
changeFeeLevel={changeFeeLevel}
isHeaderRowLayout
/>
<Divider margin={0} />
<Column gap={spacings.lg} padding={{ vertical: spacings.md, horizontal: spacings.lg }}>
<TradingFormSection>
<TradingFormInputPaymentMethod label="TR_TRADING_RECEIVE_METHOD" />
<TradingFormInputCountry label="TR_TRADING_COUNTRY" />
</Column>
</TradingFormSection>
<TradingSelectedOfferProvider />
<Divider margin={0} />
<Column gap={spacings.lg} padding={{ vertical: spacings.md, horizontal: spacings.lg }}>
<TradingFormSection>
<TradingFormFeesDisclamer />
</Column>
</Card>
</TradingFormSection>
</TradingFormCard>
);
};

View File

@@ -1,8 +1,7 @@
import { ReactNode } from 'react';
import { Translation } from '@suite/intl';
import { Box, Column, Divider, Icon, Row, Text } from '@trezor/components';
import { spacings } from '@trezor/theme';
import { Column, GhostContainer, Icon, Row, Text } from '@trezor/components';
import { AccountLabeling, Address } from 'src/components/suite';
@@ -15,7 +14,7 @@ interface TradingReceiveAddressEmptyProps {
}
export const TradingReceiveAddressEmpty = ({ title, text }: TradingReceiveAddressEmptyProps) => (
<Column alignItems="center" gap={spacings.xxs} padding={{ vertical: spacings.md }}>
<Column alignItems="center" gap={4} padding={{ vertical: 16 }}>
<Text typographyStyle="body">{title}</Text>
<Text typographyStyle="hint" variant="tertiary">
{text}
@@ -34,17 +33,18 @@ export const TradingReceiveAddress = () => {
};
return (
<Box cursor="pointer" backgroundColorOnInteraction="backgroundSurfaceElevation2">
<Divider margin={0} />
<GhostContainer
onClick={onReceiveAccountClick}
data-testid="@trading/receive-address-picker"
cursor="pointer"
borderRadius={0}
>
<Row
data-testid="@trading/receive-address-picker"
alignItems="center"
justifyContent="space-between"
onClick={onReceiveAccountClick}
padding={{
vertical: !receiveAddress ? spacings.lg : spacings.sm,
horizontal: spacings.lg,
vertical: selectedAccountOption?.account && receiveAddress ? 12 : 16,
horizontal: 20,
}}
>
<Text typographyStyle="body">
@@ -60,12 +60,17 @@ export const TradingReceiveAddress = () => {
<Column alignItems="flex-end">
{selectedAccountOption?.account && receiveAddress ? (
<>
<AccountLabeling
data-test-id="@trading/selected-receive-account"
account={selectedAccountOption.account}
accountTypeBadgeSize="small"
showAccountTypeBadge
/>
<Text
typographyStyle="body"
as="div"
data-testid="@trading/selected-receive-account"
>
<AccountLabeling
account={selectedAccountOption.account}
accountTypeBadgeSize="small"
showAccountTypeBadge
/>
</Text>
<Address
value={receiveAddress}
typographyStyle="hint"
@@ -78,8 +83,8 @@ export const TradingReceiveAddress = () => {
{receiveAddress ? (
<Address
value={receiveAddress}
typographyStyle="hint"
variant="tertiary"
typographyStyle="body"
variant="default"
isTruncated
/>
) : (
@@ -94,6 +99,6 @@ export const TradingReceiveAddress = () => {
<Icon name="caretRight" size={20} variant="tertiary" />
</Row>
</Row>
</Box>
</GhostContainer>
);
};

View File

@@ -1,8 +1,7 @@
import { ReactNode } from 'react';
import { Translation } from '@suite/intl';
import { Column, Divider, Icon, Row, SkeletonRectangle, Text } from '@trezor/components';
import { spacings } from '@trezor/theme';
import { Column, GhostContainer, Icon, Row, SkeletonRectangle, Text } from '@trezor/components';
import { useTradingFormContext } from 'src/hooks/wallet/trading/form/useTradingCommonForm';
import {
@@ -20,7 +19,7 @@ interface TradingReceiveAddressEmptyProps {
}
export const TradingReceiveAddressEmpty = ({ title, text }: TradingReceiveAddressEmptyProps) => (
<Column alignItems="center" gap={spacings.xxs} padding={{ vertical: spacings.md }}>
<Column alignItems="center" gap={4} padding={{ vertical: 16 }}>
<Text typographyStyle="body">{title}</Text>
<Text typographyStyle="hint" variant="tertiary">
{text}
@@ -49,15 +48,13 @@ export const TradingSelectedOfferProvider = () => {
}
return (
<Column cursor="pointer">
<Divider margin={0} />
<Row
data-testid="@trading/selected-offer-provider"
alignItems="center"
justifyContent="space-between"
onClick={onGoToOffers}
padding={spacings.lg}
>
<GhostContainer
onClick={onGoToOffers}
cursor="pointer"
data-testid="@trading/selected-offer-provider"
borderRadius={0}
>
<Row alignItems="center" justifyContent="space-between" padding={20}>
<Text typographyStyle="body">
<Translation id="TR_TRADING_PROVIDER" />
</Text>
@@ -66,17 +63,17 @@ export const TradingSelectedOfferProvider = () => {
<SkeletonRectangle animate />
) : (
<>
<Column alignItems="flex-end">
<Text typographyStyle="body" as="div">
<TradingUtilsProvider
providers={providers}
exchange={quote.exchange}
/>
</Column>
</Text>
<Icon name="caretRight" size={20} variant="tertiary" />
</>
)}
</Row>
</Row>
</Column>
</GhostContainer>
);
};

View File

@@ -17,6 +17,7 @@ export class FeeSection {
this.page.getByTestId(`@fee-card/${feeType}-fiat-amount`);
readonly rateOnCard = (feeType: FeeTypes) => this.page.getByTestId(`@fee-card/${feeType}-rate`);
readonly collapsibleFeesToggle: Locator;
readonly collapsibleFees: Locator;
readonly maxFeeLoading: Locator;
readonly customInput: Locator;
readonly maxFee: Locator;
@@ -31,6 +32,7 @@ export class FeeSection {
constructor(private readonly page: Page) {
this.collapsibleFeesToggle = this.page.getByTestId('@wallet/fees/collapsible-fees-toggle');
this.collapsibleFees = this.page.getByTestId('@wallet/fees/collapsible-fees');
this.maxFeeLoading = this.page.getByTestId('@trading/quote/maximum-fee-amount-loading');
this.customInput = this.page.getByTestId('feePerUnit');
this.maxFee = this.page.getByTestId('@trading/quote/maximum-fee-amount');
@@ -74,7 +76,7 @@ export class FeeSection {
@step()
async openCollapsibleFees() {
const isExpanded = await this.collapsibleFeesToggle.getAttribute('aria-expanded');
const isExpanded = await this.collapsibleFees.getAttribute('aria-expanded');
if (isExpanded === 'true') {
return;
@@ -93,9 +95,9 @@ export class FeeSection {
);
}
await expect(this.collapsibleFeesToggle).toHaveAttribute('aria-expanded', 'false');
await expect(this.collapsibleFees).toHaveAttribute('aria-expanded', 'false');
await this.collapsibleFeesToggle.click();
await expect(this.collapsibleFeesToggle).toHaveAttribute('aria-expanded', 'true');
await expect(this.collapsibleFees).toHaveAttribute('aria-expanded', 'true');
}
@step()