Skip to content

Commit

Permalink
feat(suite): refactor advanced coin settings modal
Browse files Browse the repository at this point in the history
  • Loading branch information
seibei-iguchi committed Mar 6, 2025
1 parent e690769 commit caf1784
Show file tree
Hide file tree
Showing 12 changed files with 240 additions and 333 deletions.
5 changes: 3 additions & 2 deletions packages/components/src/components/List/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ const ContentWrapper = styled.div`
export type ListItemProps = {
children: React.ReactNode;
bulletComponent?: React.ReactNode;
'data-testid'?: string;
};

export const ListItem = ({ bulletComponent, children }: ListItemProps) => {
export const ListItem = ({ bulletComponent, 'data-testid': dataTestId, children }: ListItemProps) => {
const { bulletGap, bulletAlignment, bulletComponent: listBulletComponent } = useList();

return (
<Item $gap={bulletGap} $bulletAlignment={bulletAlignment}>
<Item $gap={bulletGap} $bulletAlignment={bulletAlignment} data-testid={dataTestId}>
<BulletWrapper>{bulletComponent ?? listBulletComponent}</BulletWrapper>
<ContentWrapper>{children}</ContentWrapper>
</Item>
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/components/NewModal/NewModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const InnerNewModalBase = ({
{hasHeader && (
<Row
padding={{ horizontal: spacings.md, top: spacings.md }}
alignItems="center"
alignItems={description ? 'flex-start' : 'center'}
gap={spacings.md}
as="header"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const allowedTextTextProps = [
'textWrap',
'align',
'ellipsisLineCount',
'case',
] as const satisfies TextPropsKeys[];
type AllowedTextTextProps = Pick<TextPropsCommon, (typeof allowedTextTextProps)[number]>;

Expand Down
30 changes: 27 additions & 3 deletions packages/components/src/components/typography/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import { TransientProps, makePropsTransient } from '../../utils/transientProps';
export const textWraps = ['balance', 'break-word', 'pretty', 'nowrap'];
export type TextWrap = (typeof textWraps)[number];

export const textCase = ['uppercase', 'lowercase', 'titlecase'] as const;
export type TextCase = (typeof textCase)[number];

export type TextProps = {
typographyStyle?: TypographyStyle;
textWrap?: TextWrap;
align?: UIHorizontalAlignment;
ellipsisLineCount?: number;
case?: TextCase;
};

export type TextPropsKeys = keyof TextProps;
Expand All @@ -32,6 +36,7 @@ export const withTextProps = ({
$typographyStyle,
$align,
$ellipsisLineCount = 0,
$case,
}: TransientTextProps) => css`
${$textWrap &&
css`
Expand All @@ -42,23 +47,34 @@ export const withTextProps = ({
${typography[$typographyStyle]}
`
: ''}
${$align &&
${$align &&
css`
text-align: ${$align};
`}
${$ellipsisLineCount > 0 &&
${$ellipsisLineCount > 0 &&
css`
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
`}
${$ellipsisLineCount > 1 &&
${$ellipsisLineCount > 1 &&
css`
white-space: initial;
-webkit-line-clamp: ${$ellipsisLineCount};
display: -webkit-box;
-webkit-box-orient: vertical;
`}
${$case && $case === 'titlecase'
? css`
text-transform: lowercase;
&::first-letter {
text-transform: uppercase;
}
`
: css`
text-transform: ${$case};
`}
`;

const getStorybookType = (key: TextPropsKeys) => {
Expand Down Expand Up @@ -91,6 +107,13 @@ const getStorybookType = (key: TextPropsKeys) => {
min: 0,
},
};
case 'case':
return {
options: [undefined, ...textCase],
control: {
type: 'select',
},
};
default:
return {
control: {
Expand Down Expand Up @@ -120,6 +143,7 @@ export const getTextPropsStory = (allowedTextProps: Array<TextPropsKeys>) => {
...(allowedTextProps.includes('typographyStyle') ? { typographyStyle: undefined } : {}),
...(allowedTextProps.includes('align') ? { align: undefined } : {}),
...(allowedTextProps.includes('ellipsisLineCount') ? { hasEllipsis: undefined } : {}),
...(allowedTextProps.includes('case') ? { case: undefined } : {}),
},
argTypes,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,77 +1,197 @@
import styled from 'styled-components';
import { useState } from 'react';

import { type NetworkSymbol, getNetwork } from '@suite-common/wallet-config';
import { variables } from '@trezor/components';
import { CoinLogo } from '@trezor/product-components';
import {
Button,
Card,
CollapsibleBox,
Column,
DotIndicator,
Input,
List,
NewModal,
Row,
Text,
} from '@trezor/components';
import { spacings } from '@trezor/theme';

import { Modal, Translation } from 'src/components/suite';
import { useSelector } from 'src/hooks/suite';
import { getCoinLabel } from 'src/utils/suite/getCoinLabel';
import { toggleTor } from 'src/actions/suite/suiteActions';
import { Translation } from 'src/components/suite';
import { useBackendsForm, useDefaultUrls } from 'src/hooks/settings/backends';
import { useDispatch, useSelector } from 'src/hooks/suite';
import { selectTorState } from 'src/reducers/suite/suiteReducer';

import { CustomBackends } from './CustomBackends/CustomBackends';
import { BackendTypeSelect } from './CustomBackends/BackendTypeSelect';
import ConnectionInfo from './CustomBackends/ConnectionInfo';
import { TorModal, TorResult } from './CustomBackends/TorModal';

const Section = styled.div`
display: flex;
flex-direction: column;
`;
type AdvancedCoinSettingsModalProps = {
symbol: NetworkSymbol;
onCancel: () => void;
};

const Heading = styled.div`
display: flex;
align-items: center;
line-height: initial;
export const AdvancedCoinSettingsModal = ({ symbol, onCancel }: AdvancedCoinSettingsModalProps) => {
const network = getNetwork(symbol);
const { isTorEnabled } = useSelector(selectTorState);
const blockchain = useSelector(state => state.wallet.blockchain);
const dispatch = useDispatch();
const [torModalOpen, setTorModalOpen] = useState(false);

> * + * {
margin-left: 16px;
}
`;
const {
type,
urls,
input: { error, name, placeholder, register, reset, validate, value },
changeType,
addUrl,
removeUrl,
save,
hasOnlyOnions,
} = useBackendsForm(symbol);

const Header = styled.div`
display: flex;
flex-direction: column;
`;
const onSaveClick = () => {
if (!isTorEnabled && hasOnlyOnions()) {
setTorModalOpen(true);
} else {
save();
onCancel();
}
};

const Subheader = styled.span`
font-size: ${variables.FONT_SIZE.NORMAL};
font-weight: ${variables.FONT_WEIGHT.MEDIUM};
color: ${({ theme }) => theme.legacy.TYPE_LIGHT_GREY};
`;
const onTorResult = async (result: TorResult) => {
switch (result) {
case 'enable-tor':
await dispatch(toggleTor(true));

interface AdvancedCoinSettingsModalProps {
symbol: NetworkSymbol;
onCancel: () => void;
}
setTorModalOpen(false);
save();
onCancel();

export const AdvancedCoinSettingsModal = ({ symbol, onCancel }: AdvancedCoinSettingsModalProps) => {
const blockchain = useSelector(state => state.wallet.blockchain);
const network = getNetwork(symbol);
break;
case 'use-defaults':
changeType('default');
setTorModalOpen(false);

// no default
}
};

const { name, features, testnet: isTestnet } = network;
const hasCustomBackend = !!blockchain[symbol].backends.selected;
const label = getCoinLabel(features, isTestnet, hasCustomBackend);
const { defaultUrls } = useDefaultUrls(symbol);
const { ref: inputRef, ...inputField } = register(name, { validate });
const isEditable = type !== 'default';
const isSubmitButtonDisabled = isEditable && !!error;

return (
<Modal
isCancelable
return torModalOpen ? (
<TorModal onResult={onTorResult} />
) : (
<NewModal
onCancel={onCancel}
heading={
<Heading>
<CoinLogo symbol={symbol} />

<Header>
<span>{name}</span>

{label && (
<Subheader>
<Translation id={label} />
</Subheader>
)}
</Header>
</Heading>
<Text case="titlecase" as="p">
{network.name} <Translation id="TR_BACKENDS" />
</Text>
}
description={
<Translation
id={
network?.networkType === 'cardano'
? 'SETTINGS_ADV_COIN_BLOCKFROST_DESCRIPTION'
: 'SETTINGS_ADV_COIN_BLOCKBOOK_DESCRIPTION'
}
/>
}
size="small"
bottomContent={
<>
<NewModal.Button
onClick={onSaveClick}
isDisabled={isSubmitButtonDisabled}
data-testid="@settings/advance/button/save"
>
<Translation id="TR_CONFIRM" />
</NewModal.Button>
<NewModal.Button onClick={onCancel} variant="tertiary">
<Translation id="TR_CANCEL" />
</NewModal.Button>
</>
}
>
<Section>
<CustomBackends network={network} onCancel={onCancel} />
</Section>
</Modal>
<Column gap={spacings.lg}>
<Card
heading={
<BackendTypeSelect network={network} value={type} onChange={changeType} />
}
>
<Column gap={spacings.xxl}>
{(urls.length || (!isEditable && defaultUrls.length)) && (
<List bulletComponent={<DotIndicator />} gap={spacings.sm}>
{(isEditable ? urls : defaultUrls).map(url => (
<List.Item
data-testid="@settings/advance/url"
key={url}
bulletComponent={
url === blockchain[symbol]?.url ? (
<DotIndicator isActive />
) : undefined
}
>
<Row gap={spacings.sm}>
<Text
variant={
url === blockchain[symbol]?.url
? 'default'
: 'tertiary'
}
>
{url}
</Text>
{isEditable && (
<Button
variant="tertiary"
size="tiny"
icon="trash"
onClick={() => removeUrl(url)}
>
<Translation id="TR_REMOVE" />
</Button>
)}
</Row>
</List.Item>
))}
</List>
)}
{isEditable && (
<Column gap={spacings.sm}>
<Input
data-testid={`@settings/advance/${name}`}
placeholder={placeholder}
inputState={error ? 'error' : undefined}
bottomText={error?.message || null}
innerRef={inputRef}
innerAddon={
<Button
variant="primary"
size="tiny"
icon="plus"
data-testid="@settings/advance/button/add"
onClick={() => {
addUrl(value);
reset();
}}
isDisabled={!!error || value === ''}
>
<Translation id="TR_ADD_NEW_BLOCKBOOK_BACKEND" />
</Button>
}
{...inputField}
/>
</Column>
)}
</Column>
</Card>
<CollapsibleBox heading={<Translation id="SETTINGS_ADV_COIN_CONN_INFO_TITLE" />}>
<ConnectionInfo symbol={symbol} />
</CollapsibleBox>
</Column>
</NewModal>
);
};
Loading

0 comments on commit caf1784

Please sign in to comment.