1
0
mirror of https://github.com/trezor/trezor-wallet synced 2024-11-28 03:08:30 +00:00

Refactored /wallet/aside folder to new folder structure

This commit is contained in:
Vasek Mlejnsky 2018-08-16 14:56:35 +02:00
parent 0c58820999
commit 71d8712575
17 changed files with 294 additions and 301 deletions

View File

@ -1,77 +0,0 @@
/* @flow */
//import React, { Node } from 'react';
import * as React from 'react';
import { Link, NavLink } from 'react-router-dom';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import type { TrezorDevice } from 'flowtype';
import { DeviceSelect, DeviceDropdown } from './DeviceSelection';
import AccountSelection from './AccountSelection';
import CoinSelection from './CoinSelection';
import StickyContainer from './StickyContainer';
import type { Props } from './index';
type TransitionMenuProps = {
animationType: string;
children?: React.Node;
}
const TransitionMenu = (props: TransitionMenuProps): React$Element<TransitionGroup> => (
<TransitionGroup component="div" className="transition-container">
<CSSTransition
key={props.animationType}
onExit={() => { window.dispatchEvent(new Event('resize')); }}
onExited={() => window.dispatchEvent(new Event('resize'))}
in
out
classNames={props.animationType}
appear={false}
timeout={300}
>
{ props.children }
</CSSTransition>
</TransitionGroup>
);
const Aside = (props: Props): React$Element<typeof StickyContainer | string> => {
const selected: ?TrezorDevice = props.wallet.selectedDevice;
const { location } = props.router;
if (location.pathname === '/' || !selected) return (<aside />);
let menu = <section />;
if (props.deviceDropdownOpened) {
menu = <DeviceDropdown {...props} />;
} else if (location.state.network) {
menu = (
<TransitionMenu animationType="slide-left">
<AccountSelection {...props} />
</TransitionMenu>
);
} else if (selected.features && !selected.features.bootloader_mode && selected.features.initialized) {
menu = (
<TransitionMenu animationType="slide-right">
<CoinSelection {...props} />
</TransitionMenu>
);
}
return (
<StickyContainer location={location.pathname} deviceSelection={props.deviceDropdownOpened}>
<DeviceSelect {...props} />
{ menu }
<div className="sticky-bottom">
<div className="help">
<a href="https://trezor.io/support/" target="_blank" rel="noreferrer noopener">Need help?</a>
</div>
</div>
</StickyContainer>
);
};
export default Aside;

View File

@ -1,16 +0,0 @@
import styled from 'styled-components';
import React from 'react';
const Section = styled.section`
width: 320px;
display: inline-block;
vertical-align: top;
`;
const AsideSection = (props) => (
<Section>
{props.children}
</Section>
);
export default AsideSection;

View File

@ -1,63 +0,0 @@
import colors from 'config/colors';
import { FONT_SIZE, BORDER_WIDTH } from 'config/variables';
import { NavLink } from 'react-router-dom';
import PropTypes from 'prop-types';
import React from 'react';
import styled, { css } from 'styled-components';
import AsideRow from '../AsideRow';
const Wrapper = styled.div`
height: 64px;
font-size: ${FONT_SIZE.SMALL};
color: ${colors.TEXT_PRIMARY};
border-top: 1px solid ${colors.DIVIDER};
span {
font-size: ${FONT_SIZE.SMALLER};
color: ${colors.TEXT_SECONDARY};
}
${props => props.isSelected && css`
border-left: ${BORDER_WIDTH.SELECTED} solid ${colors.GREEN_PRIMARY};
background: ${colors.WHITE};
&:hover {
background-color: ${colors.WHITE};
}
&:last-child {
border-bottom: 1px solid ${colors.DIVIDER};
}
`}
`;
const AsideRowAccount = ({
accountIndex, balance, url, isSelected = false,
}) => (
<NavLink to={url}>
<Wrapper
to={url}
isSelected={isSelected}
>
<AsideRow column>
Account #{accountIndex + 1}
{balance ? (
<span>{balance}</span>
) : (
<span>Loading...</span>
)}
</AsideRow>
</Wrapper>
</NavLink>
);
AsideRowAccount.propTypes = {
accountIndex: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
balance: PropTypes.string,
isSelected: PropTypes.bool,
};
export default AsideRowAccount;

View File

@ -1,49 +0,0 @@
import colors from 'config/colors';
import { FONT_SIZE } from 'config/variables';
import Icon from 'components/common/Icon';
import PropTypes from 'prop-types';
import React from 'react';
import styled from 'styled-components';
import AsideRow from '../AsideRow';
import CoinName from './CoinName';
import { coinProp } from '../../common';
const Wrapper = styled.div`
display: block;
height: 50px;
font-size: ${FONT_SIZE.BASE};
color: ${colors.TEXT_PRIMARY};
&:hover {
background-color: ${colors.GRAY_LIGHT};
}
`;
const AsideRowCoin = ({ coin, icon }) => (
<Wrapper>
<AsideRow>
<CoinName
coinImg={coin.img}
text={coin.name}
/>
{icon && (
<Icon
icon={icon.type}
color={icon.color}
/>
)}
</AsideRow>
</Wrapper>
);
AsideRowCoin.propTypes = {
...coinProp,
icon: PropTypes.shape({
type: PropTypes.string.isRequired,
color: PropTypes.string.isRequired,
}),
};
export default AsideRowCoin;

View File

@ -1,39 +0,0 @@
import styled from 'styled-components';
import React from 'react';
import PropTypes from 'prop-types';
import colors from 'config/colors';
import { ICON_SIZE } from 'config/variables';
const Wrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`;
const Logo = styled.div`
height: ${ICON_SIZE.BASE};
width: ${ICON_SIZE.BASE};
margin-right: 10px;
background-repeat: no-repeat;
background-position: center;
background-size: auto ${ICON_SIZE.BASE};
background-image: url('${props => props.coinImg}');
`;
const CoinName = ({ coinImg, text }) => (
<Wrapper>
<Logo
coinImg={coinImg}
/>
<p>{text}</p>
</Wrapper>
);
CoinName.propTypes = {
coinImg: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
};
export default CoinName

View File

@ -10,7 +10,8 @@ import Header from '../common/Header';
import Footer from '../common/Footer';
import AccountTabs from './account/AccountTabs';
import DeviceSettingsTabs from './pages/DeviceSettingsTabs';
import AsideContainer from './aside';
// import AsideContainer from './aside';
import LeftNavigation from 'views/Device/components/LeftNavigation/Container';
import ModalContainer from '../modal';
import Notifications from '../common/Notification';
import Log from '../common/Log';
@ -29,7 +30,7 @@ const Wallet = (props: WalletContainerProps) => (
<Header />
{/* <div>{ props.wallet.online ? "ONLINE" : "OFFLINE" }</div> */}
<main>
<AsideContainer />
<LeftNavigation />
<article>
<nav>
<Route path="/device/:device/network/:network/account/:account" component={AccountTabs} />

View File

View File

@ -1,18 +1,14 @@
/* @flow */
import React, { Component, PropTypes } from 'react';
import { toggleDeviceDropdown } from 'actions/WalletActions';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import * as TrezorConnectActions from 'actions/TrezorConnectActions';
import { toggleDeviceDropdown } from 'actions/WalletActions';
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
import type { State, Dispatch } from 'flowtype';
import Aside from './Aside';
import LeftNavigation from './LeftNavigation';
type OwnProps = {
@ -41,8 +37,6 @@ type DispatchProps = {
onSelectDevice: typeof TrezorConnectActions.onSelectDevice,
}
export type Props = StateProps & DispatchProps;
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => ({
connect: state.connect,
accounts: state.accounts,
@ -67,7 +61,6 @@ const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps>
onSelectDevice: bindActionCreators(TrezorConnectActions.onSelectDevice, dispatch),
});
// export default connect(mapStateToProps, mapDispatchToProps)(Aside);
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(Aside),
connect(mapStateToProps, mapDispatchToProps)(LeftNavigation),
);

View File

@ -16,16 +16,16 @@ const Wrapper = styled.div`
border-bottom: 1px solid ${colors.DIVIDER};
`;
const AsideDivider = ({ textLeft, textRight }) => (
const Divider = ({ textLeft, textRight }) => (
<Wrapper>
<p>{textLeft}</p>
<p>{textRight}</p>
</Wrapper>
);
AsideDivider.propTypes = {
Divider.propTypes = {
textLeft: PropTypes.string.isRequired,
textRight: PropTypes.string.isRequired,
};
export default AsideDivider;
export default Divider;

View File

@ -0,0 +1,112 @@
/* @flow */
import * as React from 'react';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import styled from 'styled-components';
import type { TrezorDevice } from 'flowtype';
import { DeviceSelect, DeviceDropdown } from './selection/DeviceSelection';
import AccountSelection from './selection/AccountSelection';
import CoinSelection from './selection/CoinSelection';
import StickyContainer from './StickyContainer';
import type { Props } from './index';
type TransitionMenuProps = {
animationType: string;
children?: React.Node;
}
const TransitionGroupWrapper = styled(TransitionGroup)`
width: 640px;
`;
const TransitionContentWrapper = styled.div`
width: 320px;
display: inline-block;
vertical-align: top;
`;
const TransitionMenu = (props: TransitionMenuProps): React$Element<TransitionGroup> => {
return (
<TransitionGroupWrapper component="div" className="transition-container">
<CSSTransition
key={props.animationType}
onExit={() => { window.dispatchEvent(new Event('resize')); }}
onExited={() => window.dispatchEvent(new Event('resize'))}
in
out
classNames={props.animationType}
appear={false}
timeout={300}
>
<TransitionContentWrapper>
{props.children}
</TransitionContentWrapper>
</CSSTransition>
</TransitionGroupWrapper>
);
};
const LeftNavigation = (props: Props): React$Element<typeof StickyContainer | string> => {
const selected: ?TrezorDevice = props.wallet.selectedDevice;
const { location } = props.router;
if (location.pathname === '/' || !selected) return (<aside />);
let menu = <section />;
let shouldRenderDeviceSelection = false;
// let shouldRenderCoins = false;
// let shouldRenderAccounts = false;
let animationType = '';
if (props.deviceDropdownOpened) {
shouldRenderDeviceSelection = true;
// menu = <DeviceDropdown {...props} />;
} else if (location.state.network) {
// shouldRenderAccounts = true;
shouldRenderDeviceSelection = false;
animationType = 'slide-left';
// menu = (
// <TransitionMenu animationType="slide-left">
// <AccountSelection {...props} />
// </TransitionMenu>
// );
} else if (selected.features && !selected.features.bootloader_mode && selected.features.initialized) {
// shouldRenderCoins = true;
shouldRenderDeviceSelection = false;
animationType = 'slide-right';
// menu = (
// <TransitionMenu animationType="slide-right">
// <CoinSelection {...props} />
// </TransitionMenu>
// );
}
return (
<StickyContainer location={location.pathname} deviceSelection={props.deviceDropdownOpened}>
<DeviceSelect {...props} />
{/* { menu } */}
{shouldRenderDeviceSelection ? (
<DeviceDropdown {...props} />
) : (
<TransitionMenu
animationType={animationType}
>
{animationType === 'slide-left' && <AccountSelection key="accounts" {...props} />}
{animationType === 'slide-right' && <CoinSelection key="coins" {...props} />}
</TransitionMenu>
)}
<div className="sticky-bottom">
<div className="help">
<a href="https://trezor.io/support/" target="_blank" rel="noreferrer noopener">Need help?</a>
</div>
</div>
</StickyContainer>
);
};
export default LeftNavigation;

View File

@ -22,14 +22,16 @@ const Wrapper = styled.div`
transition: background-color ${TRANSITION_TIME.BASE}, color ${TRANSITION_TIME.BASE};
`;
const AsideRow = ({ children, column = false }) => (
const Row = ({
children, column = false,
}) => (
<Wrapper
column={column}
>{children}
</Wrapper>
);
AsideRow.propTypes = {
Row.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
@ -37,4 +39,4 @@ AsideRow.propTypes = {
column: PropTypes.bool,
};
export default AsideRow;
export default Row;

View File

@ -141,7 +141,7 @@ export default class StickyContainer extends React.PureComponent<Props> {
className="sticky-container"
ref={node => this.wrapper = node}
>
{ this.props.children }
{this.props.children}
</div>
</aside>
);

View File

@ -10,19 +10,75 @@ import * as stateUtils from 'reducers/utils';
import Loader from 'components/common/LoaderCircle';
import Tooltip from 'rc-tooltip';
import AsideRowAccount from './AsideRowAccount';
import AsideSection from './AsideSection';
import colors from 'config/colors';
import { FONT_SIZE, BORDER_WIDTH } from 'config/variables';
import styled, { css } from 'styled-components';
import Row from '../Row';
import PropTypes from 'prop-types';
//import AsideRowAccount from './row/account/AsideRowAccount';
import type { TrezorDevice, Accounts } from 'flowtype';
import type { Props } from './index';
const RowAccountWrapper = styled.div`
height: 64px;
font-size: ${FONT_SIZE.SMALL};
color: ${colors.TEXT_PRIMARY};
border-top: 1px solid ${colors.DIVIDER};
span {
font-size: ${FONT_SIZE.SMALLER};
color: ${colors.TEXT_SECONDARY};
}
${props => props.isSelected && css`
border-left: ${BORDER_WIDTH.SELECTED} solid ${colors.GREEN_PRIMARY};
background: ${colors.WHITE};
&:hover {
background-color: ${colors.WHITE};
}
&:last-child {
border-bottom: 1px solid ${colors.DIVIDER};
}
`}
`;
const RowAccount = ({
accountIndex, balance, url, isSelected = false,
}) => (
<NavLink to={url}>
<RowAccountWrapper
to={url}
isSelected={isSelected}
>
<Row column>
Account #{accountIndex + 1}
{balance ? (
<span>{balance}</span>
) : (
<span>Loading...</span>
)}
</Row>
</RowAccountWrapper>
</NavLink>
);
RowAccount.propTypes = {
accountIndex: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
balance: PropTypes.string,
isSelected: PropTypes.bool,
};
const AccountSelection = (props: Props): ?React$Element<string> => {
const selected = props.wallet.selectedDevice;
if (!selected) return null;
const { location } = props.router;
const urlParams = location.state;
const accounts = props.accounts;
const { accounts } = props;
const baseUrl: string = urlParams.deviceInstance ? `/device/${urlParams.device}:${urlParams.deviceInstance}` : `/device/${urlParams.device}`;
const { config } = props.localStorage;
@ -53,7 +109,7 @@ const AccountSelection = (props: Props): ?React$Element<string> => {
}
return (
<AsideRowAccount
<RowAccount
accountIndex={account.index}
balance={balance}
url={url}
@ -70,7 +126,7 @@ const AccountSelection = (props: Props): ?React$Element<string> => {
if (selected.connected) {
const url: string = location.pathname.replace(/account+\/([0-9]*)/, 'account/0');
selectedAccounts = (
<AsideRowAccount
<RowAccount
accountIndex={0}
url={url}
/>
@ -110,7 +166,7 @@ const AccountSelection = (props: Props): ?React$Element<string> => {
placement="top"
>
<div className="add-account disabled">
Add account
Add account
</div>
</Tooltip>
);
@ -119,7 +175,7 @@ const AccountSelection = (props: Props): ?React$Element<string> => {
discoveryStatus = (
<div className="discovery-status">
Accounts could not be loaded
<span>{ `Connect ${selected.instanceLabel} device` }</span>
<span>{`Connect ${selected.instanceLabel} device`}</span>
</div>
);
} else {
@ -136,19 +192,19 @@ const AccountSelection = (props: Props): ?React$Element<string> => {
if (selectedCoin) {
backButton = (
<NavLink to={baseUrl} className={`back ${selectedCoin.network}`}>
<span className={selectedCoin.network}>{ selectedCoin.name }</span>
<span className={selectedCoin.network}>{selectedCoin.name}</span>
</NavLink>
);
}
return (
<AsideSection>
{/* { backButton } */}
<React.Fragment>
{backButton}
<div>
{ selectedAccounts }
{selectedAccounts}
</div>
{ discoveryStatus }
</AsideSection>
{discoveryStatus}
</React.Fragment>
);
};

View File

@ -1,17 +1,92 @@
/* @flow */
import coins from 'constants/coins';
import colors from 'config/colors';
import { FONT_SIZE } from 'config/variables';
import Icon from 'components/common/Icon';
import ICONS from 'config/icons';
import { NavLink } from 'react-router-dom';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import styled from 'styled-components';
import { ICON_SIZE } from 'config/variables';
import { coinProp } from '../common';
import Divider from '../Divider';
import Row from '../Row';
import type { TrezorDevice } from 'flowtype';
import AsideDivider from './AsideDivider';
import AsideRowCoin from './row/coin/AsideRowCoin';
import type { Props } from './index';
const CoinNameWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`;
const Logo = styled.div`
height: ${ICON_SIZE.BASE};
width: ${ICON_SIZE.BASE};
margin-right: 10px;
background-repeat: no-repeat;
background-position: center;
background-size: auto ${ICON_SIZE.BASE};
background-image: url('${props => props.coinImg}');
`;
const CoinName = ({
coinImg, text,
}) => (
<CoinNameWrapper>
<Logo
coinImg={coinImg}
/>
<p>{text}</p>
</CoinNameWrapper>
);
CoinName.propTypes = {
coinImg: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
};
const RowCoinWrapper = styled.div`
display: block;
height: 50px;
font-size: ${FONT_SIZE.BASE};
color: ${colors.TEXT_PRIMARY};
&:hover {
background-color: ${colors.GRAY_LIGHT};
}
`;
const RowCoin = ({
coin, icon,
}) => (
<RowCoinWrapper>
<Row>
<CoinName
coinImg={coin.img}
text={coin.name}
/>
{icon && (
<Icon
icon={icon.type}
color={icon.color}
/>
)}
</Row>
</RowCoinWrapper>
);
RowCoin.propTypes = {
...coinProp,
icon: PropTypes.shape({
type: PropTypes.string.isRequired,
color: PropTypes.string.isRequired,
}),
};
class CoinSelection extends Component {
getBaseUrl() {
const { selectedDevice } = this.props.wallet;
@ -44,7 +119,7 @@ class CoinSelection extends Component {
key={item.network}
to={`${this.getBaseUrl()}/network/${item.network}/account/0`}
>
<AsideRowCoin
<RowCoin
coin={{
img: imgUrl,
name: item.name,
@ -53,13 +128,13 @@ class CoinSelection extends Component {
</NavLink>
);
})}
<AsideDivider
<Divider
textLeft="Other coins"
textRight="(You will be redirected)"
/>
{coins.map(coin => (
<a href={coin.url}>
<AsideRowCoin
<RowCoin
coin={{
img: coin.image,
name: coin.coinName,

View File

@ -5,13 +5,11 @@ import React, { Component } from 'react';
import Select from 'react-select';
import TrezorConnect from 'trezor-connect';
import AsideDivider from './AsideDivider';
import AsideDivider from '../Divider';
import type { TrezorDevice } from 'flowtype';
import type { Props } from './index';
import AsideSection from './AsideSection';
export const DeviceSelect = (props: Props) => {
const { devices } = props;
const { transport } = props.connect;
@ -59,10 +57,10 @@ export const DeviceSelect = (props: Props) => {
return (
<div className={css} onClick={!disabled ? handleOpen : null}>
<div className="label-container">
<span className="label">{ selected.instanceLabel }</span>
<span className="status">{ deviceStatus }</span>
<span className="label">{selected.instanceLabel}</span>
<span className="status">{deviceStatus}</span>
</div>
{ deviceCount > 1 ? <div className="counter">{ deviceCount }</div> : null }
{deviceCount > 1 ? <div className="counter">{deviceCount}</div> : null}
<div className="arrow" />
</div>
);
@ -164,11 +162,11 @@ export class DeviceDropdown extends Component<Props> {
const deviceMenuButtons = deviceMenuItems.map((item, index) => (
<div key={item.type} className={item.type} onClick={event => this.onDeviceMenuClick(item, selected)}>{ item.label}</div>
<div key={item.type} className={item.type} onClick={event => this.onDeviceMenuClick(item, selected)}>{item.label}</div>
));
currentDeviceMenu = deviceMenuButtons.length < 1 ? null : (
<div className="device-menu">
{ deviceMenuButtons }
{deviceMenuButtons}
</div>
);
}
@ -199,8 +197,8 @@ export class DeviceDropdown extends Component<Props> {
return (
<div key={index} className={css} onClick={() => this.props.onSelectDevice(dev)}>
<div className="label-container">
<span className="label">{ dev.instanceLabel }</span>
<span className="status">{ deviceStatus }</span>
<span className="label">{dev.instanceLabel}</span>
<span className="status">{deviceStatus}</span>
</div>
<div
className="forget-button"
@ -216,12 +214,12 @@ export class DeviceDropdown extends Component<Props> {
return (
<AsideSection>
{ currentDeviceMenu }
{ deviceList.length > 1 ? <AsideDivider textLeft={'Other devices'}/> : null }
{ deviceList }
{ webUsbButton }
</AsideSection>
<React.Fragment>
{currentDeviceMenu}
{deviceList.length > 1 ? <AsideDivider textLeft={'Other devices'} /> : null}
{deviceList}
{webUsbButton}
</React.Fragment>
);
}
}

View File

@ -34,7 +34,7 @@ const BrowserNotSupported = (props: {}): React$Element<string> => (
export default (props: Props) => {
const web3 = props.web3;
const { web3 } = props;
const { devices } = props;
const { browserState, transport } = props.connect;
const localStorageError = props.localStorage.error;