You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-wallet/src/views/Wallet/components/LeftNavigation/index.js

389 lines
13 KiB

/* @flow */
import * as React from 'react';
import PropTypes from 'prop-types';
import colors from 'config/colors';
import { FONT_SIZE } from 'config/variables';
6 years ago
import Icon from 'components/Icon';
import WalletTypeIcon from 'components/images/WalletType';
6 years ago
import icons from 'config/icons';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import styled from 'styled-components';
import DeviceHeader from 'components/DeviceHeader';
// import Link from 'components/Link';
import * as deviceUtils from 'utils/device';
import Tooltip from 'components/Tooltip';
import { FormattedMessage } from 'react-intl';
// import { getPattern } from 'support/routes';
6 years ago
import AccountMenu from './components/AccountMenu';
import CoinMenu from './components/CoinMenu';
import DeviceMenu from './components/DeviceMenu';
5 years ago
import Sidebar from './components/Sidebar';
import type { Props } from './components/common';
// import l10nCommonMessages from 'views/common.messages';
import l10nMessages from './index.messages';
const Header = styled(DeviceHeader)`
border-right: 1px solid ${colors.BACKGROUND};
flex: 0 0 auto;
`;
5 years ago
const WalletTypeIconWrapper = styled.div``;
const Counter = styled.div`
display: flex;
justify-content: center;
align-items: center;
border: 1px solid ${colors.DIVIDER};
border-radius: 50%;
color: ${colors.TEXT_SECONDARY};
width: 24px;
height: 24px;
font-size: ${FONT_SIZE.COUNTER};
margin-right: 8px;
`;
const TransitionGroupWrapper = styled(TransitionGroup)`
width: 640px;
`;
const TransitionContentWrapper = styled.div`
width: 320px;
display: inline-block;
vertical-align: top;
`;
const Footer = styled.div.attrs(props => ({
style: { position: props.position },
}))`
6 years ago
width: 320px;
bottom: 0;
background: ${colors.MAIN};
border-right: 1px solid ${colors.BACKGROUND};
`;
const Body = styled.div`
flex: 1 0 auto;
width: 320px;
min-height: ${props => (props.minHeight ? `${props.minHeight}px` : '0px')};
6 years ago
`;
6 years ago
const Help = styled.div`
display: flex;
align-items: center;
justify-content: center;
6 years ago
text-align: center;
width: 319px;
padding: 8px 0px;
6 years ago
border-top: 1px solid ${colors.BACKGROUND};
6 years ago
`;
const A = styled.a`
color: ${colors.TEXT_SECONDARY};
font-size: ${FONT_SIZE.SMALL};
6 years ago
display: inline-block;
padding: 8px;
height: auto;
&:hover {
background: transparent;
color: ${colors.TEXT_PRIMARY};
}
`;
type TransitionMenuProps = {
5 years ago
animationType: ?string,
children?: React.Node,
};
// TransitionMenu needs to dispatch window.resize event
// in order to StickyContainer be recalculated
const TransitionMenu = (props: TransitionMenuProps): React$Element<TransitionGroup> => (
<TransitionGroupWrapper component="div" className="transition-container">
<CSSTransition
key={props.animationType}
5 years ago
onExit={() => {
window.dispatchEvent(new Event('resize'));
}}
onExited={() => window.dispatchEvent(new Event('resize'))}
in
out
classNames={props.animationType}
appear={false}
timeout={300}
>
5 years ago
<TransitionContentWrapper>{props.children}</TransitionContentWrapper>
</CSSTransition>
</TransitionGroupWrapper>
);
5 years ago
const WalletTooltipMsg = ({
walletType,
isDeviceReady,
}: {
walletType: string,
isDeviceReady: ?boolean,
}): any => {
let secondPart = '';
if (isDeviceReady) {
5 years ago
secondPart =
walletType === 'standard' ? (
<FormattedMessage {...l10nMessages.TR_CLICK_HERE_TO_ACCESS_YOUR_HIDDEN} />
) : (
<FormattedMessage {...l10nMessages.TR_CLICK_HERE_TO_ACCESS_YOUR_STANDARD} />
);
} else {
secondPart = <FormattedMessage {...l10nMessages.TR_TO_ACCESS_OTHER_WALLETS} />;
}
return (
<>
5 years ago
{walletType === 'standard' ? (
<FormattedMessage {...l10nMessages.TR_YOU_ARE_IN_YOUR_STANDARD_WALLET} />
) : (
<FormattedMessage {...l10nMessages.TR_YOU_ARE_IN_YOUR_HIDDEN_WALLET} />
)}{' '}
{secondPart}
</>
);
};
type State = {
5 years ago
animationType: ?string,
clicked: boolean,
bodyMinHeight: number,
};
class LeftNavigation extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.deviceMenuRef = React.createRef();
const { location } = this.props.router;
const hasNetwork = location && location.state && location.state.network;
this.state = {
animationType: hasNetwork ? 'slide-left' : null,
clicked: false,
bodyMinHeight: 0,
};
}
componentDidMount() {
this.recalculateBodyMinHeight();
}
componentWillReceiveProps(nextProps: Props) {
const { selectedDevice } = nextProps.wallet;
const { location } = nextProps.router;
const hasNetwork = location && location.state.network;
5 years ago
const deviceReady =
selectedDevice && selectedDevice.features && selectedDevice.mode === 'normal';
if (hasNetwork) {
this.setState({
animationType: 'slide-left',
});
} else {
this.setState({
animationType: deviceReady ? 'slide-right' : null,
});
}
}
componentDidUpdate() {
this.recalculateBodyMinHeight();
}
shouldRenderAccounts() {
const { selectedDevice } = this.props.wallet;
const { location } = this.props.router;
5 years ago
return (
selectedDevice &&
location &&
location.state &&
location.state.network &&
this.state.animationType === 'slide-left'
);
}
handleOpen() {
this.setState({ clicked: true });
this.props.toggleDeviceDropdown(!this.props.wallet.dropdownOpened);
}
shouldRenderCoins() {
return this.state.animationType !== 'slide-left';
}
recalculateBodyMinHeight() {
if (this.deviceMenuRef.current) {
this.setState({
bodyMinHeight: this.deviceMenuRef.current.getMenuHeight(),
});
}
}
deviceMenuRef: { current: any };
render() {
const { props } = this;
let menu;
if (this.shouldRenderAccounts()) {
menu = (
<TransitionMenu animationType="slide-left">
<AccountMenu {...props} />
</TransitionMenu>
);
} else if (this.shouldRenderCoins()) {
menu = (
<TransitionMenu animationType="slide-right">
<CoinMenu {...props} />
</TransitionMenu>
);
}
const { selectedDevice, dropdownOpened } = props.wallet;
const isDeviceAccessible = deviceUtils.isDeviceAccessible(selectedDevice);
5 years ago
const walletType =
selectedDevice && !selectedDevice.useEmptyPassphrase ? 'hidden' : 'standard';
const showWalletType =
selectedDevice &&
selectedDevice.features &&
selectedDevice.features.passphrase_protection;
const isDeviceReady =
selectedDevice && selectedDevice.connected && selectedDevice.available;
return (
5 years ago
<Sidebar isOpen={props.wallet.showSidebar}>
<Header
isSelected
Integration tests (#311) * Add base test env * Add eslint rules for cypress * Add configs and scripts in package json * Added docker file for bridge and emualator * Bridge install progress * Bridge install next step * Add task for integration tests * Fixed deps * Added baseUrl * Added baseUrl fix * Added npx * Added caching for cypress bin * Added path to binary * Install cypress * Finalized dockerfile * Fixed bridge lib path * Fixed path for binary * Adjust script again * Run all the things properly * Try to run the tests * First POC test * First POC test in gitlab * Fixed flow * Fixed gitlab test url, try docker service * export artifacts * Test only integration tests in CI * Test only integration tests in CI 2 * Test only integration tests in CI 3 * Added tests for initialize device * Try to add docker in only one step * Turn on other integration steps * Correct node version * Ignore cache in flow * Run bridge and emulator in debug link mode * Fix param * Try to run new config in CI * init device in docker * Remove docker image after run * Remove amp * Fix path * Artifacts on fail * Artifacts on fail with volume * Artifacts on fail with volume 2 * Install mkdir * Install mkdir again * test * test 2 * test 3 * test 4 * test 5 * test 6 * test 7 * test 8 * test 9 * test 10 * test 11 * test 12 * test 13 * test 14 * test 15 * test 16 * test 17 * Revert "test 17" This reverts commit f3f6c0d6906cdc470aa11ae728b4b61a6b71a732. * test 18 * test 19 * test 20 * test 21 try chrome * test 22 * test 23 * test 24 * test 25 * test 25 try to install chrome again * test 25 try to install chrome again * Added missing deps * Added debug * Install chromium * Install chromium 2 * turn on chromium * turn off debug * turn on debug * fix folder * turn off debug * Fix init device * Add header dashboard test * Bring things back * clean * clean fix * Build image in CI * Added stage step * Added docker image * Added service * Added tests to docker image * Refactor a bit * Correct registry image * Build wallet again * Add test for dashbaord content * new node version, more tests * Remove unused code * typo * Correct snapshots, moved deps to dev, beta disclaimer prop
5 years ago
testId="Main__page__device__header"
isHoverable={false}
onClickWrapper={() => {
if (isDeviceAccessible || this.props.devices.length > 1) {
this.handleOpen();
}
}}
device={selectedDevice}
disabled={!isDeviceAccessible && this.props.devices.length === 1}
isOpen={this.props.wallet.dropdownOpened}
5 years ago
icon={
<React.Fragment>
{showWalletType && (
<Tooltip
5 years ago
content={
<WalletTooltipMsg
walletType={walletType}
isDeviceReady={isDeviceReady}
/>
}
maxWidth={200}
placement="bottom"
enterDelayMs={0.5}
>
<WalletTypeIconWrapper>
<WalletTypeIcon
5 years ago
onClick={e => {
5 years ago
if (selectedDevice && isDeviceReady) {
this.props.duplicateDevice(selectedDevice);
e.stopPropagation();
}
}}
5 years ago
hoverColor={
isDeviceReady
? colors.TEXT_PRIMARY
: colors.TEXT_SECONDARY
}
type={walletType}
size={25}
color={colors.TEXT_SECONDARY}
/>
</WalletTypeIconWrapper>
</Tooltip>
5 years ago
)}
{this.props.devices.length > 1 && (
<Tooltip
5 years ago
content={
<FormattedMessage {...l10nMessages.TR_NUMBER_OF_DEVICES} />
}
maxWidth={200}
placement="bottom"
enterDelayMs={0.5}
>
<Counter>{this.props.devices.length}</Counter>
</Tooltip>
)}
{/* <Tooltip
content={
<FormattedMessage
{...l10nCommonMessages.TR_APPLICATION_SETTINGS}
/>
}
maxWidth={200}
placement="bottom"
enterDelayMs={0.5}
>
<WalletTypeIconWrapper>
<Link to={getPattern('wallet-settings')}>
<Icon
size={25}
color={colors.TEXT_SECONDARY}
hoverColor={colors.TEXT_PRIMARY}
icon={icons.COG}
/>
</Link>
</WalletTypeIconWrapper>
</Tooltip> */}
<Icon
canAnimate={this.state.clicked === true}
isActive={this.props.wallet.dropdownOpened}
size={25}
color={colors.TEXT_SECONDARY}
icon={icons.ARROW_DOWN}
/>
</React.Fragment>
5 years ago
}
{...this.props}
/>
<Body minHeight={this.state.bodyMinHeight}>
{dropdownOpened && <DeviceMenu ref={this.deviceMenuRef} {...this.props} />}
{isDeviceAccessible && menu}
</Body>
Integration tests (#311) * Add base test env * Add eslint rules for cypress * Add configs and scripts in package json * Added docker file for bridge and emualator * Bridge install progress * Bridge install next step * Add task for integration tests * Fixed deps * Added baseUrl * Added baseUrl fix * Added npx * Added caching for cypress bin * Added path to binary * Install cypress * Finalized dockerfile * Fixed bridge lib path * Fixed path for binary * Adjust script again * Run all the things properly * Try to run the tests * First POC test * First POC test in gitlab * Fixed flow * Fixed gitlab test url, try docker service * export artifacts * Test only integration tests in CI * Test only integration tests in CI 2 * Test only integration tests in CI 3 * Added tests for initialize device * Try to add docker in only one step * Turn on other integration steps * Correct node version * Ignore cache in flow * Run bridge and emulator in debug link mode * Fix param * Try to run new config in CI * init device in docker * Remove docker image after run * Remove amp * Fix path * Artifacts on fail * Artifacts on fail with volume * Artifacts on fail with volume 2 * Install mkdir * Install mkdir again * test * test 2 * test 3 * test 4 * test 5 * test 6 * test 7 * test 8 * test 9 * test 10 * test 11 * test 12 * test 13 * test 14 * test 15 * test 16 * test 17 * Revert "test 17" This reverts commit f3f6c0d6906cdc470aa11ae728b4b61a6b71a732. * test 18 * test 19 * test 20 * test 21 try chrome * test 22 * test 23 * test 24 * test 25 * test 25 try to install chrome again * test 25 try to install chrome again * Added missing deps * Added debug * Install chromium * Install chromium 2 * turn on chromium * turn off debug * turn on debug * fix folder * turn off debug * Fix init device * Add header dashboard test * Bring things back * clean * clean fix * Build image in CI * Added stage step * Added docker image * Added service * Added tests to docker image * Refactor a bit * Correct registry image * Build wallet again * Add test for dashbaord content * new node version, more tests * Remove unused code * typo * Correct snapshots, moved deps to dev, beta disclaimer prop
5 years ago
<Footer data-test="Main__page__footer" key="sticky-footer">
6 years ago
<Help>
<A
href="https://trezor.io/support/"
target="_blank"
rel="noreferrer noopener"
>
5 years ago
<Icon size={26} icon={icons.CHAT} color={colors.TEXT_SECONDARY} />
<FormattedMessage {...l10nMessages.TR_NEED_HELP} />
6 years ago
</A>
</Help>
</Footer>
5 years ago
</Sidebar>
);
}
}
LeftNavigation.propTypes = {
connect: PropTypes.object,
accounts: PropTypes.array,
router: PropTypes.object,
fiat: PropTypes.array,
localStorage: PropTypes.object,
discovery: PropTypes.array,
wallet: PropTypes.object,
devices: PropTypes.array,
pending: PropTypes.array,
toggleDeviceDropdown: PropTypes.func,
addAccount: PropTypes.func,
acquireDevice: PropTypes.func,
forgetDevice: PropTypes.func,
duplicateDevice: PropTypes.func,
gotoDeviceSettings: PropTypes.func,
onSelectDevice: PropTypes.func,
};
export default LeftNavigation;