1
0
mirror of https://github.com/trezor/trezor-wallet synced 2024-12-24 16:08:11 +00:00

Merge branch 'master' into fonts-refactoring

This commit is contained in:
slowbackspace 2018-12-18 14:43:12 +01:00
commit 859b1ca6db
21 changed files with 315 additions and 164 deletions

View File

@ -1,10 +1,15 @@
## feature/ripple ## 1.1.2-beta
__added__
- Stellar and Cardano external wallets
# new feature/ripple
__changed__ __changed__
- Split code to coin specific components. actions and reducers - Split code to coin specific components. actions and reducers
- Use TrezorConnect to communicate with trezor-blockchain-link - Use TrezorConnect to communicate with trezor-blockchain-link
__added__ __added__
- Ripple support - Ripple support
## 1.0.2-beta ## 1.0.2-beta
__changed__ __changed__

View File

@ -51,7 +51,7 @@
"rc-tooltip": "^3.7.0", "rc-tooltip": "^3.7.0",
"react": "^16.6.3", "react": "^16.6.3",
"react-dom": "^16.6.3", "react-dom": "^16.6.3",
"react-hot-loader": "^4.3.4", "react-hot-loader": "^4.6.2",
"react-json-view": "^1.19.1", "react-json-view": "^1.19.1",
"react-qr-svg": "^2.1.0", "react-qr-svg": "^2.1.0",
"react-redux": "^5.0.7", "react-redux": "^5.0.7",

View File

@ -8,6 +8,7 @@ import * as TOKEN from 'actions/constants/token';
import * as PENDING from 'actions/constants/pendingTx'; import * as PENDING from 'actions/constants/pendingTx';
import * as reducerUtils from 'reducers/utils'; import * as reducerUtils from 'reducers/utils';
import { initialState } from 'reducers/SelectedAccountReducer';
import type { import type {
PayloadAction, PayloadAction,
@ -17,7 +18,12 @@ import type {
State, State,
} from 'flowtype'; } from 'flowtype';
type SelectedAccountState = $ElementType<State, 'selectedAccount'>; import type {
State as SelectedAccountState,
Loader,
Notification,
ExceptionPage,
} from 'reducers/SelectedAccountReducer';
export type SelectedAccountAction = { export type SelectedAccountAction = {
type: typeof ACCOUNT.DISPOSE, type: typeof ACCOUNT.DISPOSE,
@ -26,18 +32,39 @@ export type SelectedAccountAction = {
payload: SelectedAccountState, payload: SelectedAccountState,
}; };
type AccountStatus = {
type: ?string; // notification type
title: ?string; // notification title
message?: ?string; // notification message
shouldRender: boolean; // should render account page
}
export const dispose = (): Action => ({ export const dispose = (): Action => ({
type: ACCOUNT.DISPOSE, type: ACCOUNT.DISPOSE,
}); });
const getAccountLoader = (state: State, selectedAccount: SelectedAccountState): ?AccountStatus => { // display exception page instead of component body
const getExceptionPage = (state: State, selectedAccount: SelectedAccountState): ?ExceptionPage => {
const device = state.wallet.selectedDevice;
const { discovery, network } = selectedAccount;
if (!device || !device.features || !network || !discovery) return null;
if (discovery.fwOutdated) {
// those values are not used because in this case views/Wallet/views/FirmwareUpdate component will be displayed and it already has text content
return {
type: 'fwOutdated',
title: 'not-used',
message: 'not-used',
shortcut: 'not-used',
};
}
if (discovery.fwNotSupported) {
return {
type: 'fwNotSupported',
title: `${network.name} is not supported with Trezor ${device.features.model}`,
message: 'Find more information on Trezor Wiki.',
shortcut: network.shortcut,
};
}
return null;
};
// display loader instead of component body
const getAccountLoader = (state: State, selectedAccount: SelectedAccountState): ?Loader => {
const device = state.wallet.selectedDevice; const device = state.wallet.selectedDevice;
const { const {
account, account,
@ -49,16 +76,14 @@ const getAccountLoader = (state: State, selectedAccount: SelectedAccountState):
return { return {
type: 'progress', type: 'progress',
title: 'Loading device...', title: 'Loading device...',
shouldRender: false,
}; };
} }
// corner case: accountState didn't finish loading state after LOCATION_CHANGE action // corner case: SelectedAccountState didn't change after LOCATION_CHANGE action
if (!network) { if (!network) {
return { return {
type: 'progress', type: 'progress',
title: 'Loading account state...', title: 'Loading account',
shouldRender: false,
}; };
} }
@ -66,24 +91,6 @@ const getAccountLoader = (state: State, selectedAccount: SelectedAccountState):
if (account) return null; if (account) return null;
// account not found (yet). checking why... // account not found (yet). checking why...
if (discovery && discovery.fwOutdated) {
return {
type: 'info',
title: `Device ${device.instanceLabel} firmware is outdated`,
message: 'TODO: update firmware explanation',
shouldRender: false,
};
}
if (discovery && discovery.fwNotSupported) {
return {
type: 'info',
title: `Device ${device.instanceLabel} is not supported`,
message: 'TODO: model T1 not supported explanation',
shouldRender: false,
};
}
if (!discovery || (discovery.waitingForDevice || discovery.interrupted)) { if (!discovery || (discovery.waitingForDevice || discovery.interrupted)) {
if (device.connected) { if (device.connected) {
// case 1: device is connected but discovery not started yet (probably waiting for auth) // case 1: device is connected but discovery not started yet (probably waiting for auth)
@ -91,7 +98,6 @@ const getAccountLoader = (state: State, selectedAccount: SelectedAccountState):
return { return {
type: 'progress', type: 'progress',
title: 'Authenticating device...', title: 'Authenticating device...',
shouldRender: false,
}; };
} }
// case 2: device is unavailable (created with different passphrase settings) account cannot be accessed // case 2: device is unavailable (created with different passphrase settings) account cannot be accessed
@ -100,7 +106,6 @@ const getAccountLoader = (state: State, selectedAccount: SelectedAccountState):
type: 'info', type: 'info',
title: `Device ${device.instanceLabel} is unavailable`, title: `Device ${device.instanceLabel} is unavailable`,
message: 'Change passphrase settings to use this device', message: 'Change passphrase settings to use this device',
shouldRender: false,
}; };
} }
@ -109,7 +114,6 @@ const getAccountLoader = (state: State, selectedAccount: SelectedAccountState):
type: 'info', type: 'info',
title: `Device ${device.instanceLabel} is disconnected`, title: `Device ${device.instanceLabel} is disconnected`,
message: 'Connect device to load accounts', message: 'Connect device to load accounts',
shouldRender: false,
}; };
} }
@ -118,7 +122,6 @@ const getAccountLoader = (state: State, selectedAccount: SelectedAccountState):
return { return {
type: 'info', type: 'info',
title: 'Account does not exist', title: 'Account does not exist',
shouldRender: false,
}; };
} }
@ -126,11 +129,11 @@ const getAccountLoader = (state: State, selectedAccount: SelectedAccountState):
return { return {
type: 'progress', type: 'progress',
title: 'Loading account', title: 'Loading account',
shouldRender: false,
}; };
}; };
const getAccountNotification = (state: State, selectedAccount: SelectedAccountState): ?AccountStatus => { // display notification above the component, with or without component body
const getAccountNotification = (state: State, selectedAccount: SelectedAccountState): ?(Notification & { shouldRender: boolean }) => {
const device = state.wallet.selectedDevice; const device = state.wallet.selectedDevice;
const { account, network, discovery } = selectedAccount; const { account, network, discovery } = selectedAccount;
if (!device || !network) return null; if (!device || !network) return null;
@ -198,16 +201,6 @@ export const observe = (prevState: State, action: Action): PayloadAction<boolean
// ignore not listed actions // ignore not listed actions
if (actions.indexOf(action.type) < 0) return false; if (actions.indexOf(action.type) < 0) return false;
const state: State = getState(); const state: State = getState();
const notification = {
type: null,
message: null,
title: null,
};
const loader = {
type: null,
message: null,
title: null,
};
const { location } = state.router; const { location } = state.router;
// displayed route is not an account route // displayed route is not an account route
@ -222,25 +215,29 @@ export const observe = (prevState: State, action: Action): PayloadAction<boolean
// prepare new state for "selectedAccount" reducer // prepare new state for "selectedAccount" reducer
const newState: SelectedAccountState = { const newState: SelectedAccountState = {
...initialState,
location: state.router.location.pathname, location: state.router.location.pathname,
account, account,
network, network,
discovery, discovery,
tokens, tokens,
pending, pending,
notification,
loader,
shouldRender: false,
}; };
// get "selectedAccount" status from newState // get "selectedAccount" status from newState
const statusNotification = getAccountNotification(state, newState); const exceptionPage = getExceptionPage(state, newState);
const statusLoader = getAccountLoader(state, newState); const loader = getAccountLoader(state, newState);
const shouldRender = (statusNotification && statusLoader) ? (statusNotification.shouldRender || statusLoader.shouldRender) : true; const notification = getAccountNotification(state, newState);
if (exceptionPage) {
newState.exceptionPage = exceptionPage;
} else {
newState.loader = loader;
newState.notification = notification;
}
newState.shouldRender = !(loader || exceptionPage || (notification && !notification.shouldRender));
newState.notification = statusNotification || notification;
newState.shouldRender = shouldRender;
newState.loader = statusLoader || loader;
// check if newState is different than previous state // check if newState is different than previous state
const stateChanged = reducerUtils.observeChanges(prevState.selectedAccount, newState, { const stateChanged = reducerUtils.observeChanges(prevState.selectedAccount, newState, {
account: ['balance', 'nonce'], account: ['balance', 'nonce'],

View File

@ -101,6 +101,7 @@ const DeviceHeader = ({
isAccessible = true, isAccessible = true,
disabled = false, disabled = false,
isSelected = false, isSelected = false,
className,
}) => { }) => {
const status = getStatus(device); const status = getStatus(device);
return ( return (
@ -109,6 +110,7 @@ const DeviceHeader = ({
isOpen={isOpen} isOpen={isOpen}
isHoverable={isHoverable} isHoverable={isHoverable}
disabled={disabled} disabled={disabled}
className={className}
> >
<ClickWrapper <ClickWrapper
disabled={disabled} disabled={disabled}
@ -139,6 +141,7 @@ DeviceHeader.propTypes = {
isOpen: PropTypes.bool, isOpen: PropTypes.bool,
isSelected: PropTypes.bool, isSelected: PropTypes.bool,
onClickWrapper: PropTypes.func.isRequired, onClickWrapper: PropTypes.func.isRequired,
className: PropTypes.string,
}; };
export default DeviceHeader; export default DeviceHeader;

View File

@ -28,13 +28,23 @@ class CoinLogo extends PureComponent {
} }
render() { render() {
const { network } = this.props; const { network, className, standalone } = this.props;
const logo = (
<Logo
className={className}
hasLongIcon={this.hasLongIcon(network)}
src={require(`./images/${network}.png`)} // eslint-disable-line
/>
);
if (standalone) {
return logo;
}
return ( return (
<Wrapper> <Wrapper className={className}>
<Logo {logo}
hasLongIcon={this.hasLongIcon(network)}
src={require(`./images/${network}.png`)} // eslint-disable-line
/>
</Wrapper> </Wrapper>
); );
} }
@ -42,6 +52,8 @@ class CoinLogo extends PureComponent {
CoinLogo.propTypes = { CoinLogo.propTypes = {
network: PropTypes.string, network: PropTypes.string,
className: PropTypes.string,
standalone: PropTypes.bool,
}; };
export default CoinLogo; export default CoinLogo;

View File

@ -7,34 +7,32 @@ import type { Props } from '../../index';
// There could be only one account notification // There could be only one account notification
export default (props: Props) => { export default (props: Props) => {
const { network, notification } = props.selectedAccount; const { network, notification } = props.selectedAccount;
if (network && notification.type && notification.title) { if (!network || !notification) return null;
if (notification.type === 'backend') {
// special case: backend is down if (notification.type === 'backend') {
// TODO: this is a different component with "auto resolve" button // special case: backend is down
return ( // TODO: this is a different component with "auto resolve" button
<Notification
type="error"
title={notification.title}
message={notification.message}
actions={
[{
label: 'Connect',
callback: async () => {
await props.blockchainReconnect(network.shortcut);
},
}]
}
/>
);
}
return ( return (
<Notification <Notification
type={notification.type} type="error"
title={notification.title} title={notification.title}
message={notification.message} message={notification.message}
actions={
[{
label: 'Connect',
callback: async () => {
await props.blockchainReconnect(network.shortcut);
},
}]
}
/> />
); );
} }
return (
return null; <Notification
type={notification.type}
title={notification.title}
message={notification.message}
/>
);
}; };

View File

@ -10,23 +10,35 @@ import type {
Discovery, Discovery,
} from 'flowtype'; } from 'flowtype';
export type Loader = {
type: string,
title: string,
message?: string,
}
export type Notification = {
type: string,
title: string,
message?: string,
}
export type ExceptionPage = {
type: ?string,
title: ?string,
message: ?string,
shortcut: string,
}
export type State = { export type State = {
location: string; location: string,
account: ?Account; account: ?Account,
network: ?Network; network: ?Network,
tokens: Array<Token>, tokens: Array<Token>,
pending: Array<PendingTx>, pending: Array<PendingTx>,
discovery: ?Discovery, discovery: ?Discovery,
notification: { loader: ?Loader,
type: ?string, notification: ?Notification,
title: ?string, exceptionPage: ?ExceptionPage,
message: ?string,
},
loader: {
type: ?string,
title: ?string,
message: ?string,
},
shouldRender: boolean, shouldRender: boolean,
}; };
@ -37,16 +49,9 @@ export const initialState: State = {
tokens: [], tokens: [],
pending: [], pending: [],
discovery: null, discovery: null,
notification: { loader: null,
type: null, notification: null,
title: null, exceptionPage: null,
message: null,
},
loader: {
type: null,
title: null,
message: null,
},
shouldRender: false, shouldRender: false,
}; };

View File

@ -47,9 +47,11 @@ if (buildUtils.isDev()) {
collapsed: true, collapsed: true,
}); });
if (window && typeof window.devToolsExtension === 'function') { /* eslint-disable no-underscore-dangle */
enhancers.push(window.devToolsExtension()); if (window && typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ === 'function') {
enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__());
} }
/* eslint-enable */
composedEnhancers = compose( composedEnhancers = compose(
applyMiddleware(logger, ...middlewares, ...services), applyMiddleware(logger, ...middlewares, ...services),

View File

@ -0,0 +1,73 @@
/* @flow */
import React from 'react';
import styled from 'styled-components';
import colors from 'config/colors';
import { FONT_SIZE } from 'config/variables';
import { H2 } from 'components/Heading';
import Button from 'components/Button';
import Link from 'components/Link';
import CoinLogo from 'components/images/CoinLogo';
const getInfoUrl = (networkShortcut: ?string) => {
const urls = {
default: 'https://wiki.trezor.io',
xrp: 'https://wiki.trezor.io/Ripple_(XRP)',
};
return networkShortcut ? urls[networkShortcut] : urls.default;
};
type Props = {
networkShortcut: ?string,
title: ?string,
message: ?string,
}
const Wrapper = styled.div`
display: flex;
background: ${colors.WHITE};
flex-direction: column;
flex: 1;
`;
const CoinLogoWrapper = styled.div`
margin: 10px 0;
`;
const StyledCoinLogo = styled(CoinLogo)`
width: 32px;
`;
const StyledLink = styled(Link)`
padding-top: 24px;
`;
const Row = styled.div`
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
const Message = styled.div`
font-size: ${FONT_SIZE.SMALL};
color: ${colors.TEXT_SECONDARY};
text-align: center;
`;
const FirmwareUnsupported = (props: Props) => (
<Wrapper>
<Row>
{props.networkShortcut && <CoinLogoWrapper><StyledCoinLogo standalone network={props.networkShortcut} /></CoinLogoWrapper>}
<H2>{props.title}</H2>
<Message>{props.message}</Message>
<StyledLink href={getInfoUrl(props.networkShortcut)}>
<Button>Find out more info</Button>
</StyledLink>
</Row>
</Wrapper>
);
export default FirmwareUnsupported;

View File

@ -1,10 +1,24 @@
import React from 'react'; /* @flow */
import * as React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import styled from 'styled-components'; import styled from 'styled-components';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import { FONT_SIZE } from 'config/variables'; import { FONT_SIZE } from 'config/variables';
import colors from 'config/colors'; import colors from 'config/colors';
import type { State } from 'flowtype';
import FirmwareUpdate from 'views/Wallet/views/FirmwareUpdate';
import FirmwareUnsupported from './components/FirmwareUnsupported';
type Props = {
children?: React.Node,
isLoading?: boolean,
loader?: $ElementType<$ElementType<State, 'selectedAccount'>, 'loader'>,
exceptionPage?: $ElementType<$ElementType<State, 'selectedAccount'>, 'exceptionPage'>,
}
const Wrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;
flex: 1; flex: 1;
@ -36,22 +50,33 @@ const Row = styled.div`
flex-direction: row; flex-direction: row;
`; `;
const getExceptionPage = (exceptionPage) => {
const { title, message, shortcut } = exceptionPage;
switch (exceptionPage.type) {
case 'fwOutdated':
return <FirmwareUpdate />;
case 'fwNotSupported':
return <FirmwareUnsupported title={title} message={message} networkShortcut={shortcut} />;
default: return null;
}
};
const Content = ({ const Content = ({
children, children,
title,
message,
type,
isLoading = false, isLoading = false,
}) => ( loader,
exceptionPage,
}: Props) => (
<Wrapper> <Wrapper>
{(!isLoading) && children} {(!isLoading) && children}
{isLoading && (type === 'progress' || type === 'info') && ( {isLoading && exceptionPage && getExceptionPage(exceptionPage)}
{isLoading && loader && (
<Loading> <Loading>
<Row> <Row>
{type === 'progress' && <Loader size={30} />} {loader.type === 'progress' && <Loader size={30} />}
<Text>{title || 'Initializing accounts'}</Text> <Text>{loader.title || 'Initializing accounts'}</Text>
</Row> </Row>
{message && <Message>{message}</Message>} {loader.message && <Message>{loader.message}</Message>}
</Loading> </Loading>
)} )}
</Wrapper> </Wrapper>
@ -60,9 +85,8 @@ const Content = ({
Content.propTypes = { Content.propTypes = {
children: PropTypes.oneOfType([PropTypes.element, PropTypes.array]), children: PropTypes.oneOfType([PropTypes.element, PropTypes.array]),
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
title: PropTypes.string, loader: PropTypes.object,
message: PropTypes.string, exceptionPage: PropTypes.object,
type: PropTypes.string,
}; };
export default Content; export default Content;

View File

@ -19,8 +19,10 @@ type State = {
footerFixed: boolean, footerFixed: boolean,
} }
const AsideWrapper = styled.aside` const AsideWrapper = styled.aside.attrs(props => ({
min-height: ${props => props.minHeight}px; style: { minHeight: props.minHeight },
}))`
position: relative; position: relative;
top: 0px; top: 0px;
width: 320px; width: 320px;
@ -30,10 +32,13 @@ const AsideWrapper = styled.aside`
border-right: 1px solid ${colors.DIVIDER}; border-right: 1px solid ${colors.DIVIDER};
`; `;
const StickyContainerWrapper = styled.div` const StickyContainerWrapper = styled.div.attrs(props => ({
top: ${props => props.top}px; style: {
left: ${props => props.left}px; top: props.top,
padding-bottom: ${props => props.paddingBottom}px; left: props.left,
paddingBottom: props.paddingBottom,
},
}))`
position: fixed; position: fixed;
border-right: 1px solid ${colors.DIVIDER}; border-right: 1px solid ${colors.DIVIDER};
width: 320px; width: 320px;

View File

@ -45,8 +45,9 @@ const TransitionContentWrapper = styled.div`
vertical-align: top; vertical-align: top;
`; `;
const Footer = styled.div` const Footer = styled.div.attrs(props => ({
position: ${props => props.position}; style: { position: props.position },
}))`
width: 320px; width: 320px;
bottom: 0; bottom: 0;
background: ${colors.MAIN}; background: ${colors.MAIN};

View File

@ -96,10 +96,12 @@ const AccountReceive = (props: Props) => {
account, account,
discovery, discovery,
shouldRender, shouldRender,
loader,
} = props.selectedAccount; } = props.selectedAccount;
const { type, title, message } = loader;
if (!device || !account || !discovery || !shouldRender) return <Content type={type} title={title} message={message} isLoading />; if (!device || !account || !discovery || !shouldRender) {
const { loader, exceptionPage } = props.selectedAccount;
return <Content loader={loader} exceptionPage={exceptionPage} isLoading />;
}
const { const {
addressVerified, addressVerified,

View File

@ -96,10 +96,12 @@ const AccountReceive = (props: Props) => {
account, account,
discovery, discovery,
shouldRender, shouldRender,
loader,
} = props.selectedAccount; } = props.selectedAccount;
const { type, title, message } = loader;
if (!device || !account || !discovery || !shouldRender) return <Content type={type} title={title} message={message} isLoading />; if (!device || !account || !discovery || !shouldRender) {
const { loader, exceptionPage } = props.selectedAccount;
return <Content loader={loader} exceptionPage={exceptionPage} isLoading />;
}
const { const {
addressVerified, addressVerified,

View File

@ -184,7 +184,6 @@ const AccountSend = (props: Props) => {
discovery, discovery,
tokens, tokens,
shouldRender, shouldRender,
loader,
} = props.selectedAccount; } = props.selectedAccount;
const { const {
address, address,
@ -213,8 +212,11 @@ const AccountSend = (props: Props) => {
updateFeeLevels, updateFeeLevels,
onSend, onSend,
} = props.sendFormActions; } = props.sendFormActions;
const { type, title, message } = loader;
if (!device || !account || !discovery || !network || !shouldRender) return <Content type={type} title={title} message={message} isLoading />; if (!device || !account || !discovery || !network || !shouldRender) {
const { loader, exceptionPage } = props.selectedAccount;
return <Content loader={loader} exceptionPage={exceptionPage} isLoading />;
}
const isCurrentCurrencyToken = networkSymbol !== currency; const isCurrentCurrencyToken = networkSymbol !== currency;

View File

@ -122,7 +122,6 @@ const AccountSend = (props: Props) => {
network, network,
discovery, discovery,
shouldRender, shouldRender,
loader,
} = props.selectedAccount; } = props.selectedAccount;
const { const {
address, address,
@ -142,8 +141,11 @@ const AccountSend = (props: Props) => {
onSetMax, onSetMax,
onSend, onSend,
} = props.sendFormActions; } = props.sendFormActions;
const { type, title, message } = loader;
if (!device || !account || !discovery || !network || !shouldRender) return <Content type={type} title={title} message={message} isLoading />; if (!device || !account || !discovery || !network || !shouldRender) {
const { loader, exceptionPage } = props.selectedAccount;
return <Content loader={loader} exceptionPage={exceptionPage} isLoading />;
}
let isSendButtonDisabled: boolean = Object.keys(errors).length > 0 || total === '0' || amount.length === 0 || address.length === 0 || sending; let isSendButtonDisabled: boolean = Object.keys(errors).length > 0 || total === '0' || amount.length === 0 || address.length === 0 || sending;
let sendButtonText: string = ` ${total} ${network.symbol}`; let sendButtonText: string = ` ${total} ${network.symbol}`;

View File

@ -57,10 +57,14 @@ class SignVerify extends Component <Props> {
render() { render() {
const device = this.props.wallet.selectedDevice; const device = this.props.wallet.selectedDevice;
const { const {
account, discovery, shouldRender, notification, account, discovery, shouldRender,
} = this.props.selectedAccount; } = this.props.selectedAccount;
const { type, title, message } = notification;
if (!device || !account || !discovery || !shouldRender) return <Content type={type} title={title} message={message} isLoading />; if (!device || !account || !discovery || !shouldRender) {
const { loader, exceptionPage } = this.props.selectedAccount;
return <Content loader={loader} exceptionPage={exceptionPage} isLoading />;
}
const { const {
signVerifyActions, signVerifyActions,
signVerify: { signVerify: {

View File

@ -76,13 +76,13 @@ const AccountSummary = (props: Props) => {
network, network,
tokens, tokens,
pending, pending,
loader,
shouldRender, shouldRender,
} = props.selectedAccount; } = props.selectedAccount;
const { type, title, message } = loader; if (!device || !account || !network || !shouldRender) {
const { loader, exceptionPage } = props.selectedAccount;
if (!device || !account || !network || !shouldRender) return <Content type={type} title={title} message={message} isLoading />; return <Content loader={loader} exceptionPage={exceptionPage} isLoading />;
}
const explorerLink: string = `${network.explorer.address}${account.address}`; const explorerLink: string = `${network.explorer.address}${account.address}`;
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol); const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol);

View File

@ -66,13 +66,13 @@ const AccountSummary = (props: Props) => {
account, account,
network, network,
pending, pending,
loader,
shouldRender, shouldRender,
} = props.selectedAccount; } = props.selectedAccount;
const { type, title, message } = loader; if (!device || !account || !network || !shouldRender) {
const { loader, exceptionPage } = props.selectedAccount;
if (!device || !account || !network || !shouldRender) return <Content type={type} title={title} message={message} isLoading />; return <Content loader={loader} exceptionPage={exceptionPage} isLoading />;
}
const explorerLink: string = `${network.explorer.address}${account.address}`; const explorerLink: string = `${network.explorer.address}${account.address}`;
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol); const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol);

View File

@ -9,16 +9,14 @@ import DashboardImg from 'images/dashboard.png';
const Wrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1;
`; `;
const Row = styled.div` const Row = styled.div`
flex: 1; flex: 1;
display: flex; display: flex;
padding: 0px 48px; padding: 100px 48px;
flex-direction: column; flex-direction: column;
justify-content: center;
align-items: center; align-items: center;
`; `;

View File

@ -7249,6 +7249,19 @@ lodash.keys@^3.1.2:
lodash.isarguments "^3.0.0" lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0" lodash.isarray "^3.0.0"
<<<<<<< HEAD
=======
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
lodash.merge@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
>>>>>>> master
lodash.sortby@^4.7.0: lodash.sortby@^4.7.0:
version "4.7.0" version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
@ -9283,17 +9296,20 @@ react-dom@^16.6.3:
prop-types "^15.6.2" prop-types "^15.6.2"
scheduler "^0.11.2" scheduler "^0.11.2"
react-hot-loader@^4.3.4: react-hot-loader@^4.6.2:
version "4.3.4" version "4.6.2"
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.3.4.tgz#4f9bdd55bb20d77a6ae8931fa1c187e5f0ce6279" resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.6.2.tgz#9844b76a7bf4b6fdd45dd91f7e757ddf3aad5289"
integrity sha512-LlKjtHq+RhDq9xm6crXojbkzrEvli5F4/RaeJ//XtDWrwwsAHDjEqKfZZiPCxv7gWV2cxE3YE8TXeE9BDzLqOA== integrity sha512-9XxH/t9jblu4vUDgxHcMLwvm4aOhaoxazzTP9vwjTVzOgU987T4rDYA85XrlmbDan9WkD+h/iVHOK8F8UnQsDg==
dependencies: dependencies:
fast-levenshtein "^2.0.6" fast-levenshtein "^2.0.6"
global "^4.3.0" global "^4.3.0"
hoist-non-react-statics "^2.5.0" hoist-non-react-statics "^2.5.0"
loader-utils "^1.1.0"
lodash.merge "^4.6.1"
prop-types "^15.6.1" prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4" react-lifecycles-compat "^3.0.4"
shallowequal "^1.0.2" shallowequal "^1.0.2"
source-map "^0.7.3"
react-input-autosize@^2.2.1: react-input-autosize@^2.2.1:
version "2.2.1" version "2.2.1"
@ -10606,7 +10622,7 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@^0.7.2: source-map@^0.7.2, source-map@^0.7.3:
version "0.7.3" version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==