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

Fix/send form #12020

Merged
merged 3 commits into from
Apr 17, 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
15 changes: 11 additions & 4 deletions packages/components/src/components/form/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
value?: string;
innerRef?: Ref<HTMLInputElement>;
label?: ReactElement | string;
labelHoverAddon?: ReactElement;
labelRight?: ReactElement;
labelHoverRight?: React.ReactNode;
labelLeft?: React.ReactNode;
labelRight?: React.ReactNode;
innerAddon?: ReactElement;
/**
* @description pass `null` if bottom text can be `undefined`
Expand All @@ -103,8 +104,9 @@ const Input = ({
innerRef,
inputState,
label,
labelHoverAddon,
labelLeft,
labelRight,
labelHoverRight,
innerAddon,
innerAddonAlign = 'right',
bottomText,
Expand Down Expand Up @@ -138,7 +140,12 @@ const Input = ({
$hasBottomPadding={hasBottomPadding === true && bottomText === null}
className={className}
>
<TopAddons isHovered={isHovered} hoverAddon={labelHoverAddon} addonRight={labelRight} />
<TopAddons
isHovered={isHovered}
addonLeft={labelLeft}
hoverAddonRight={labelHoverRight}
addonRight={labelRight}
/>

<InputWrapper>
{innerAddon && innerAddonAlign === 'left' && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const Textarea: StoryObj<TextareaProps> = {
type: 'range',
},
},
labelHoverAddon: {
labelHoverRight: {
control: 'text',
},
labelRight: {
Expand Down
10 changes: 7 additions & 3 deletions packages/components/src/components/form/Textarea/Textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const TextareaLabel = styled(Label)`
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
isDisabled?: boolean;
label?: ReactNode;
labelHoverAddon?: ReactNode;
labelHoverRight?: ReactNode;
labelRight?: ReactNode;
innerRef?: Ref<HTMLTextAreaElement>;
/**
Expand All @@ -90,7 +90,7 @@ export const Textarea = ({
className,
value,
maxLength,
labelHoverAddon,
labelHoverRight,
isDisabled,
innerRef,
label,
Expand All @@ -114,7 +114,11 @@ export const Textarea = ({
onMouseLeave={() => setIsHovered(false)}
$hasBottomPadding={hasBottomPadding === true && bottomText === null}
>
<TopAddons isHovered={isHovered} hoverAddon={labelHoverAddon} addonRight={labelRight} />
<TopAddons
isHovered={isHovered}
hoverAddonRight={labelHoverRight}
addonRight={labelRight}
/>

<TextareaWrapper $inputState={inputState} disabled={isDisabled} $elevation={elevation}>
<StyledTextarea
Expand Down
45 changes: 35 additions & 10 deletions packages/components/src/components/form/TopAddons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,67 @@ import React from 'react';
import styled from 'styled-components';
import { spacingsPx } from '@trezor/theme';

const Container = styled.div`
const Container = styled.div<{ hasLeftAddon?: boolean }>`
display: flex;
justify-content: end;
justify-content: ${({ hasLeftAddon }) => (hasLeftAddon ? 'space-between' : 'flex-end')};
align-items: flex-end;
gap: ${spacingsPx.xs};
min-height: 30px;
padding-bottom: 6px;
`;

export const HoverAddon = styled.div<{ $isVisible?: boolean }>`
export const RightAddonWrapper = styled.div`
display: flex;
gap: 6px;
`;

export const RightAddon = styled.div`
display: flex;
align-items: center;
`;

export const HoverAddonRight = styled.div<{ $isVisible?: boolean }>`
opacity: ${({ $isVisible }) => ($isVisible ? 1 : 0)};
transition: opacity 0.1s ease-out;
`;

export const RightAddon = styled.div`
export const LeftAddon = styled.div`
display: flex;
align-items: center;
`;

interface TopAddonsProps {
isHovered?: boolean;
addonLeft?: React.ReactNode;
addonRight?: React.ReactNode;
hoverAddon?: React.ReactNode;
hoverAddonRight?: React.ReactNode;
}

export const TopAddons = ({ isHovered, addonRight, hoverAddon }: TopAddonsProps) => {
const isWithTopLabel = hoverAddon || addonRight;
export const TopAddons = ({
isHovered,
addonLeft,
addonRight,
hoverAddonRight,
}: TopAddonsProps) => {
const isWithTopLabel = addonLeft || addonRight || hoverAddonRight;

const isWithRightLabel = addonRight || hoverAddonRight;

if (!isWithTopLabel) {
return null;
}

return (
<Container>
{hoverAddon && <HoverAddon $isVisible={isHovered}>{hoverAddon}</HoverAddon>}
{addonRight && <RightAddon>{addonRight}</RightAddon>}
<Container hasLeftAddon={!!addonLeft}>
{addonLeft && <LeftAddon>{addonLeft}</LeftAddon>}
{isWithRightLabel && (
<RightAddonWrapper>
{hoverAddonRight && (
<HoverAddonRight $isVisible={isHovered}>{hoverAddonRight}</HoverAddonRight>
)}
{addonRight && <RightAddon>{addonRight}</RightAddon>}
</RightAddonWrapper>
)}
</Container>
);
};
2 changes: 1 addition & 1 deletion packages/components/src/components/form/form.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const All: StoryObj = {
value="Input label with warning"
dataTest="input-warning-label"
bottomText="bottom text"
labelHoverAddon={
labelHoverRight={
<Button variant="tertiary" icon="QR" onClick={() => {}}>
Scan QR code
</Button>
Expand Down
2 changes: 1 addition & 1 deletion packages/suite/src/components/wallet/Fees/Fees.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const FeeInfoRow = styled.div`
justify-content: space-between;
align-items: start;
width: 100%;
min-height: 50px; /* reserve space for fiat/crypto amounts */
min-height: 52px; /* reserve space for fiat/crypto amounts */
`;

const FeeAmount = styled.div`
Expand Down
7 changes: 7 additions & 0 deletions packages/suite/src/utils/wallet/tokenUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,10 @@ export const enhanceTokensWithRates = (

return tokensWithRates;
};

export const formatTokenSymbol = (symbol?: string) => {
const tokenSymbol = symbol?.toUpperCase() || 'N/A';
const isTokenSymbolLong = tokenSymbol.length > 7;

return isTokenSymbolLong ? `${tokenSymbol.slice(0, 7)}...` : tokenSymbol;
};
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ const Container = styled.div`
position: relative;
`;

const Heading = styled.p`
position: absolute;
`;

const Text = styled.span`
display: flex;
align-items: center;
Expand Down Expand Up @@ -228,13 +224,6 @@ export const Address = ({ output, outputId, outputsCount }: AddressProps) => {

return (
<Container>
<Heading>
<Translation
id={outputsCount > 1 ? 'TR_SEND_RECIPIENT_ADDRESS' : 'TR_SEND_ADDRESS_SECTION'}
values={{ index: recipientId }}
/>
</Heading>

<Input
inputState={inputState}
innerAddon={
Expand Down Expand Up @@ -266,11 +255,23 @@ export const Address = ({ output, outputId, outputsCount }: AddressProps) => {
<Translation id="RECIPIENT_ADDRESS" />
</Text>
}
labelHoverAddon={
labelHoverRight={
<Button variant="tertiary" size="tiny" icon="QR" onClick={handleQrClick}>
<Translation id="RECIPIENT_SCAN" />
</Button>
}
labelLeft={
<p>
<Translation
id={
outputsCount > 1
? 'TR_SEND_RECIPIENT_ADDRESS'
: 'TR_SEND_ADDRESS_SECTION'
}
values={{ index: recipientId }}
/>
</p>
}
labelRight={
outputsCount > 1 ? (
<IconButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ const Wrapper = styled.div`
interface FiatProps {
output: Partial<Output>;
outputId: number;
labelHoverRight?: React.ReactNode;
labelRight?: React.ReactNode;
}

export const Fiat = ({ output, outputId }: FiatProps) => {
export const Fiat = ({ output, outputId, labelHoverRight, labelRight }: FiatProps) => {
const {
account,
network,
Expand Down Expand Up @@ -213,6 +215,8 @@ export const Fiat = ({ output, outputId }: FiatProps) => {
return (
<Wrapper>
<NumberInput
labelHoverRight={labelHoverRight}
labelRight={labelRight}
control={control}
inputState={inputState}
onChange={handleChange}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Switch } from '@trezor/components';
import { breakpointMediaQueries } from '@trezor/styles';
import { spacingsPx } from '@trezor/theme';
import { Translation } from 'src/components/suite';
import styled, { css } from 'styled-components';

const StyledSwitch = styled(Switch)<{
$hideOnLargeScreens?: boolean;
$hideOnSmallScreens?: boolean;
}>`
${({ $hideOnLargeScreens }) =>
$hideOnLargeScreens &&
css`
${breakpointMediaQueries.lg} {
display: none;
}
`}
${({ $hideOnSmallScreens }) =>
$hideOnSmallScreens &&
css`
${breakpointMediaQueries.below_lg} {
display: none;
}
`}

${breakpointMediaQueries.below_md} {
gap: ${spacingsPx.xs};
}
`;

interface SendMaxSwitchProps {
hideOnLargeScreens?: boolean;
hideOnSmallScreens?: boolean;
isSetMaxActive: boolean;
dataTest: string;
onChange: () => void;
}

export const SendMaxSwitch = ({
isSetMaxActive,
dataTest,
onChange,
hideOnLargeScreens,
hideOnSmallScreens,
}: SendMaxSwitchProps) => (
<StyledSwitch
$hideOnLargeScreens={hideOnLargeScreens}
$hideOnSmallScreens={hideOnSmallScreens}
labelPosition="left"
isChecked={isSetMaxActive}
dataTest={dataTest}
isSmall
onChange={onChange}
label={<Translation id="AMOUNT_SEND_MAX" />}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import BigNumber from 'bignumber.js';
import { Timestamp, TokenAddress, TokenDefinitions } from '@suite-common/wallet-types';
import { TooltipSymbol, Translation } from 'src/components/suite';
import { NetworkSymbol, getNetworkFeatures } from '@suite-common/wallet-config';
import { enhanceTokensWithRates, sortTokensWithRates } from 'src/utils/wallet/tokenUtils';
import {
enhanceTokensWithRates,
formatTokenSymbol,
sortTokensWithRates,
} from 'src/utils/wallet/tokenUtils';
import { getShortFingerprint } from '@suite-common/wallet-utils';
import { selectLocalCurrency } from 'src/reducers/wallet/settingsReducer';
import { FiatCurrencyCode } from '@suite-common/suite-config';
Expand Down Expand Up @@ -57,21 +61,21 @@ export const buildTokenOptions = (
return;
}

const tokenName = token.symbol || 'N/A';
const tokenSymbol = formatTokenSymbol(token.symbol);

if (
!hasCoinDefinitions ||
isTokenDefinitionKnown(coinDefinitions?.data, symbol, token.contract)
) {
result[0].options.push({
value: token.contract,
label: tokenName.toUpperCase(),
label: tokenSymbol,
fingerprint: token.name,
});
} else {
unknownTokens.push({
value: token.contract,
label: `${tokenName.toUpperCase().slice(0, 7)}…`,
label: tokenSymbol,
fingerprint: token.name,
});
}
Expand Down
Loading
Loading