mirror of
https://github.com/trezor/trezor-wallet
synced 2024-12-01 04:38:15 +00:00
Merge pull request #179 from trezor/fix/landing-refactoring
Fix/landing refactoring
This commit is contained in:
commit
44619c0a95
@ -51,12 +51,7 @@ class Link extends PureComponent {
|
|||||||
let LinkComponent;
|
let LinkComponent;
|
||||||
if (shouldRenderRouterLink) {
|
if (shouldRenderRouterLink) {
|
||||||
LinkComponent = (
|
LinkComponent = (
|
||||||
<StyledNavLink
|
<StyledNavLink {...this.props}>{this.props.children}</StyledNavLink>);
|
||||||
isGreen={this.props.isGreen}
|
|
||||||
isGray={this.props.isGray}
|
|
||||||
to={this.props.to}
|
|
||||||
>{this.props.children}
|
|
||||||
</StyledNavLink>);
|
|
||||||
} else {
|
} else {
|
||||||
LinkComponent = (
|
LinkComponent = (
|
||||||
<A
|
<A
|
||||||
@ -81,6 +76,7 @@ Link.propTypes = {
|
|||||||
PropTypes.string,
|
PropTypes.string,
|
||||||
PropTypes.object,
|
PropTypes.object,
|
||||||
PropTypes.array,
|
PropTypes.array,
|
||||||
|
PropTypes.node,
|
||||||
]).isRequired,
|
]).isRequired,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
href: PropTypes.string,
|
href: PropTypes.string,
|
||||||
@ -91,9 +87,4 @@ Link.propTypes = {
|
|||||||
isGray: PropTypes.bool,
|
isGray: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
Link.defaultProps = {
|
|
||||||
isGreen: false,
|
|
||||||
isGray: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Link;
|
export default Link;
|
||||||
|
@ -23,7 +23,7 @@ export const routes: Array<Route> = [
|
|||||||
fields: ['import'],
|
fields: ['import'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'wallet-setting',
|
name: 'wallet-settings',
|
||||||
pattern: '/settings',
|
pattern: '/settings',
|
||||||
fields: ['settings'],
|
fields: ['settings'],
|
||||||
},
|
},
|
||||||
|
@ -5,15 +5,62 @@ import styled, { keyframes } from 'styled-components';
|
|||||||
import TrezorConnect from 'trezor-connect';
|
import TrezorConnect from 'trezor-connect';
|
||||||
import P from 'components/Paragraph';
|
import P from 'components/Paragraph';
|
||||||
import Button from 'components/Button';
|
import Button from 'components/Button';
|
||||||
|
import { H2 } from 'components/Heading';
|
||||||
import { PULSATE } from 'config/animations';
|
import { PULSATE } from 'config/animations';
|
||||||
import colors from 'config/colors';
|
import colors from 'config/colors';
|
||||||
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
||||||
|
import CaseImage from 'images/case.png';
|
||||||
|
import Link from 'components/Link';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
deviceLabel: string,
|
deviceLabel: string,
|
||||||
showWebUsb: boolean,
|
showWebUsb: boolean,
|
||||||
showDisconnect: boolean,
|
showDisconnect: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Title = styled.div`
|
||||||
|
margin-top: 60px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 36px 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ConnectTrezorWrapper = styled.div`
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
animation: ${PULSATE} 1.3s ease-out infinite;
|
||||||
|
color: ${colors.GREEN_PRIMARY};
|
||||||
|
font-size: ${FONT_SIZE.BASE};
|
||||||
|
font-weight: ${FONT_WEIGHT.BASE};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Image = styled.img`
|
||||||
|
width: 777px;
|
||||||
|
min-height: 500px;
|
||||||
|
margin: auto;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center 0px;
|
||||||
|
background-size: contain;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Footer = styled.div`
|
||||||
|
margin-bottom: 32px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const FooterText = styled.span`
|
||||||
|
margin-right: 4px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledLink = styled(Link)`
|
||||||
|
font-size: ${FONT_SIZE.BASE};
|
||||||
|
`;
|
||||||
|
|
||||||
class ConnectDevice extends PureComponent<Props> {
|
class ConnectDevice extends PureComponent<Props> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (this.props.showWebUsb) {
|
if (this.props.showWebUsb) {
|
||||||
@ -57,25 +104,14 @@ class ConnectDevice extends PureComponent<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const Wrapper = styled.div`
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
align-items: center;
|
|
||||||
width: 400px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 36px 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ConnectTrezorWrapper = styled.div`
|
|
||||||
position: relative;
|
|
||||||
top: 1px;
|
|
||||||
animation: ${PULSATE} 1.3s ease-out infinite;
|
|
||||||
color: ${colors.GREEN_PRIMARY};
|
|
||||||
font-size: ${FONT_SIZE.BASE};
|
|
||||||
font-weight: ${FONT_WEIGHT.BASE};
|
|
||||||
`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div>
|
||||||
|
<Title>
|
||||||
|
<H2 claim>The private bank in your hands.</H2>
|
||||||
|
<P>TREZOR Wallet is an easy-to-use interface for your TREZOR.</P>
|
||||||
|
<P>TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.</P>
|
||||||
|
</Title>
|
||||||
|
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<ConnectTrezorWrapper>
|
<ConnectTrezorWrapper>
|
||||||
{this.props.showDisconnect && `Unplug "${this.props.deviceLabel}" device`}
|
{this.props.showDisconnect && `Unplug "${this.props.deviceLabel}" device`}
|
||||||
@ -95,6 +131,32 @@ class ConnectDevice extends PureComponent<Props> {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
|
|
||||||
|
<Image src={CaseImage} />
|
||||||
|
|
||||||
|
<Footer>
|
||||||
|
{this.props.showWebUsb && (
|
||||||
|
<P>
|
||||||
|
<FooterText>Device not recognized?</FooterText>
|
||||||
|
<StyledLink
|
||||||
|
to="/bridge"
|
||||||
|
isGreen
|
||||||
|
>Try installing the TREZOR Bridge.
|
||||||
|
</StyledLink>
|
||||||
|
</P>
|
||||||
|
)}
|
||||||
|
<P>
|
||||||
|
<FooterText>
|
||||||
|
Don't have TREZOR?
|
||||||
|
</FooterText>
|
||||||
|
<StyledLink
|
||||||
|
href="https://trezor.io/"
|
||||||
|
isGreen
|
||||||
|
>Get one
|
||||||
|
</StyledLink>
|
||||||
|
</P>
|
||||||
|
</Footer>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ const Wrapper = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const InitializationError = (props: { error: ?string }) => (
|
const InitializationError = (props: { error: string }) => (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Notification
|
<Notification
|
||||||
title="Initialization error"
|
title="Initialization error"
|
||||||
message={props.error || ''}
|
message={props.error}
|
||||||
type="error"
|
type="error"
|
||||||
cancelable={false}
|
cancelable={false}
|
||||||
/>
|
/>
|
||||||
|
73
src/views/Landing/components/LandingWrapper/index.js
Normal file
73
src/views/Landing/components/LandingWrapper/index.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/* @flow */
|
||||||
|
import * as React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import Header from 'components/Header';
|
||||||
|
import Footer from 'components/Footer';
|
||||||
|
import Log from 'components/Log';
|
||||||
|
import Loader from 'components/Loader';
|
||||||
|
import ContextNotifications from 'components/notifications/Context';
|
||||||
|
import colors from 'config/colors';
|
||||||
|
|
||||||
|
import InitializationError from '../InitializationError';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
loading?: boolean;
|
||||||
|
error?: ?string;
|
||||||
|
children?: React.Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
min-height: 100%;
|
||||||
|
min-width: 720px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
background: ${colors.LANDING};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LandingContent = styled.div`
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LandingLoader = styled(Loader)`
|
||||||
|
margin: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LandingWrapper = (props: Props) => (
|
||||||
|
<Wrapper>
|
||||||
|
{props.loading && <LandingLoader text="Loading" size={100} />}
|
||||||
|
{!props.loading && (
|
||||||
|
<React.Fragment>
|
||||||
|
<Header />
|
||||||
|
<ContextNotifications />
|
||||||
|
{props.error && <InitializationError error={props.error} />}
|
||||||
|
<Log />
|
||||||
|
{!props.error && (
|
||||||
|
<LandingContent>
|
||||||
|
{ props.children }
|
||||||
|
</LandingContent>
|
||||||
|
)}
|
||||||
|
<Footer />
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
|
||||||
|
LandingWrapper.propTypes = {
|
||||||
|
loading: PropTypes.bool,
|
||||||
|
error: PropTypes.string,
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
LandingWrapper.defaultProps = {
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LandingWrapper;
|
@ -1,158 +0,0 @@
|
|||||||
/* @flow */
|
|
||||||
import React from 'react';
|
|
||||||
import CaseImage from 'images/case.png';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import Header from 'components/Header';
|
|
||||||
import Footer from 'components/Footer';
|
|
||||||
import Log from 'components/Log';
|
|
||||||
import Link from 'components/Link';
|
|
||||||
import Loader from 'components/Loader';
|
|
||||||
import Notification from 'components/Notification';
|
|
||||||
import ContextNotifications from 'components/notifications/Context';
|
|
||||||
import colors from 'config/colors';
|
|
||||||
import P from 'components/Paragraph';
|
|
||||||
import { H2 } from 'components/Heading';
|
|
||||||
import { isWebUSB } from 'utils/device';
|
|
||||||
import { FONT_SIZE } from 'config/variables';
|
|
||||||
|
|
||||||
import InitializationError from './components/InitializationError';
|
|
||||||
import BrowserNotSupported from './components/BrowserNotSupported';
|
|
||||||
import ConnectDevice from './components/ConnectDevice';
|
|
||||||
import InstallBridge from './components/InstallBridge';
|
|
||||||
|
|
||||||
import type { Props } from './Container';
|
|
||||||
|
|
||||||
const LandingWrapper = styled.div`
|
|
||||||
min-height: 100%;
|
|
||||||
min-width: 720px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
background: ${colors.LANDING};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const LandingContent = styled.div`
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const LandingImage = styled.img`
|
|
||||||
width: 777px;
|
|
||||||
min-height: 500px;
|
|
||||||
margin: auto;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center 0px;
|
|
||||||
background-size: contain;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TitleWrapper = styled.div`
|
|
||||||
margin-top: 60px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const LandingFooterWrapper = styled.div`
|
|
||||||
margin-bottom: 32px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const LandingFooterTextWrapper = styled.span`
|
|
||||||
margin-right: 4px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const LandingLoader = styled(Loader)`
|
|
||||||
margin: auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledLink = styled(Link)`
|
|
||||||
font-size: ${FONT_SIZE.BASE};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default (props: Props) => {
|
|
||||||
const { devices } = props;
|
|
||||||
const { browserState, transport } = props.connect;
|
|
||||||
const localStorageError = props.localStorage.error;
|
|
||||||
const connectError = props.connect.error;
|
|
||||||
|
|
||||||
const bridgeRoute: boolean = props.router.location.state.hasOwnProperty('bridge');
|
|
||||||
const deviceLabel = props.wallet.disconnectRequest ? props.wallet.disconnectRequest.label : '';
|
|
||||||
|
|
||||||
const shouldShowInitializationError = connectError && !props.connect.initialized;
|
|
||||||
const shouldShowInstallBridge = props.connect.initialized && (connectError || bridgeRoute);
|
|
||||||
const shouldShowConnectDevice = props.wallet.ready && devices.length < 1;
|
|
||||||
const shouldShowDisconnectDevice = !!props.wallet.disconnectRequest;
|
|
||||||
const shouldShowUnsupportedBrowser = browserState.supported === false;
|
|
||||||
|
|
||||||
const isLoading = !shouldShowInitializationError && !shouldShowInstallBridge && !shouldShowConnectDevice && !shouldShowUnsupportedBrowser && !localStorageError;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LandingWrapper>
|
|
||||||
{isLoading && <LandingLoader text="Loading" size={100} />}
|
|
||||||
{!isLoading && (
|
|
||||||
<React.Fragment>
|
|
||||||
<Header />
|
|
||||||
{localStorageError && (
|
|
||||||
<Notification
|
|
||||||
title="Initialization error"
|
|
||||||
message="Config files are missing"
|
|
||||||
type="error"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<ContextNotifications />
|
|
||||||
{shouldShowInitializationError && <InitializationError error={connectError} />}
|
|
||||||
<Log />
|
|
||||||
<LandingContent>
|
|
||||||
{shouldShowUnsupportedBrowser && <BrowserNotSupported />}
|
|
||||||
{shouldShowInstallBridge && <InstallBridge selectFirstAvailableDevice={props.selectFirstAvailableDevice} transport={transport} />}
|
|
||||||
|
|
||||||
{!shouldShowInstallBridge && (shouldShowConnectDevice || shouldShowDisconnectDevice) && (
|
|
||||||
<div>
|
|
||||||
<TitleWrapper>
|
|
||||||
<H2 claim>The private bank in your hands.</H2>
|
|
||||||
<P>TREZOR Wallet is an easy-to-use interface for your TREZOR.</P>
|
|
||||||
<P>TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.</P>
|
|
||||||
</TitleWrapper>
|
|
||||||
|
|
||||||
<ConnectDevice
|
|
||||||
deviceLabel={deviceLabel}
|
|
||||||
showWebUsb={isWebUSB(transport)}
|
|
||||||
showDisconnect={shouldShowDisconnectDevice}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<LandingImage src={CaseImage} />
|
|
||||||
|
|
||||||
{shouldShowConnectDevice && (
|
|
||||||
<LandingFooterWrapper>
|
|
||||||
{isWebUSB(transport) && (
|
|
||||||
<P>
|
|
||||||
<LandingFooterTextWrapper>Device not recognized?</LandingFooterTextWrapper>
|
|
||||||
<StyledLink
|
|
||||||
to="/bridge"
|
|
||||||
isGreen
|
|
||||||
>Try installing the TREZOR Bridge.
|
|
||||||
</StyledLink>
|
|
||||||
</P>
|
|
||||||
)}
|
|
||||||
<P>
|
|
||||||
<LandingFooterTextWrapper>
|
|
||||||
Don't have TREZOR?
|
|
||||||
</LandingFooterTextWrapper>
|
|
||||||
<StyledLink
|
|
||||||
href="https://trezor.io/"
|
|
||||||
isGreen
|
|
||||||
>Get one
|
|
||||||
</StyledLink>
|
|
||||||
</P>
|
|
||||||
</LandingFooterWrapper>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</LandingContent>
|
|
||||||
|
|
||||||
<Footer />
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</LandingWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,21 +1,16 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
|
import * as React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import * as RouterActions from 'actions/RouterActions';
|
import * as RouterActions from 'actions/RouterActions';
|
||||||
|
|
||||||
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
import type { State, Dispatch } from 'flowtype';
|
import type { State, Dispatch } from 'flowtype';
|
||||||
import LandingPage from './index';
|
import ImportView from './index';
|
||||||
|
|
||||||
|
|
||||||
export type StateProps = {
|
export type StateProps = {
|
||||||
localStorage: $ElementType<State, 'localStorage'>,
|
transport: $ElementType<$ElementType<State, 'connect'>, 'transport'>,
|
||||||
modal: $ElementType<State, 'modal'>,
|
children?: React.Node,
|
||||||
wallet: $ElementType<State, 'wallet'>,
|
|
||||||
connect: $ElementType<State, 'connect'>,
|
|
||||||
router: $ElementType<State, 'router'>,
|
|
||||||
wallet: $ElementType<State, 'wallet'>,
|
|
||||||
devices: $ElementType<State, 'devices'>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DispatchProps = {
|
type DispatchProps = {
|
||||||
@ -29,16 +24,11 @@ type OwnProps = {
|
|||||||
export type Props = StateProps & DispatchProps;
|
export type Props = StateProps & DispatchProps;
|
||||||
|
|
||||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
||||||
localStorage: state.localStorage,
|
transport: state.connect.transport,
|
||||||
modal: state.modal,
|
|
||||||
wallet: state.wallet,
|
|
||||||
connect: state.connect,
|
|
||||||
router: state.router,
|
|
||||||
devices: state.devices,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => ({
|
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => ({
|
||||||
selectFirstAvailableDevice: bindActionCreators(RouterActions.selectFirstAvailableDevice, dispatch),
|
selectFirstAvailableDevice: bindActionCreators(RouterActions.selectFirstAvailableDevice, dispatch),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(LandingPage);
|
export default connect(mapStateToProps, mapDispatchToProps)(ImportView);
|
40
src/views/Landing/views/Import/index.js
Normal file
40
src/views/Landing/views/Import/index.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/* @flow */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import colors from 'config/colors';
|
||||||
|
import icons from 'config/icons';
|
||||||
|
|
||||||
|
import { H2 } from 'components/Heading';
|
||||||
|
import Icon from 'components/Icon';
|
||||||
|
import Link from 'components/Link';
|
||||||
|
import Button from 'components/Button';
|
||||||
|
import LandingWrapper from 'views/Landing/components/LandingWrapper';
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
min-width: 720px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Import = () => (
|
||||||
|
<LandingWrapper>
|
||||||
|
<Wrapper>
|
||||||
|
<Icon
|
||||||
|
size={60}
|
||||||
|
color={colors.WARNING_PRIMARY}
|
||||||
|
icon={icons.WARNING}
|
||||||
|
/>
|
||||||
|
<H2>Import tool is under construction</H2>
|
||||||
|
<Link to="/">
|
||||||
|
<Button>Take me back</Button>
|
||||||
|
</Link>
|
||||||
|
</Wrapper>
|
||||||
|
</LandingWrapper>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Import;
|
34
src/views/Landing/views/InstallBridge/Container.js
Normal file
34
src/views/Landing/views/InstallBridge/Container.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* @flow */
|
||||||
|
import * as React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import * as RouterActions from 'actions/RouterActions';
|
||||||
|
|
||||||
|
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
|
import type { State, Dispatch } from 'flowtype';
|
||||||
|
import InstallBridge from './index';
|
||||||
|
|
||||||
|
export type StateProps = {
|
||||||
|
transport: $ElementType<$ElementType<State, 'connect'>, 'transport'>,
|
||||||
|
children?: React.Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DispatchProps = {
|
||||||
|
selectFirstAvailableDevice: typeof RouterActions.selectFirstAvailableDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Props = StateProps & DispatchProps;
|
||||||
|
|
||||||
|
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
||||||
|
transport: state.connect.transport,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => ({
|
||||||
|
selectFirstAvailableDevice: bindActionCreators(RouterActions.selectFirstAvailableDevice, dispatch),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(InstallBridge);
|
@ -8,10 +8,10 @@ import { Select } from 'components/Select';
|
|||||||
import Link from 'components/Link';
|
import Link from 'components/Link';
|
||||||
import { H1 } from 'components/Heading';
|
import { H1 } from 'components/Heading';
|
||||||
import Button from 'components/Button';
|
import Button from 'components/Button';
|
||||||
import Loader from 'components/Loader';
|
|
||||||
import P from 'components/Paragraph';
|
import P from 'components/Paragraph';
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
import ICONS from 'config/icons';
|
import ICONS from 'config/icons';
|
||||||
|
import LandingWrapper from 'views/Landing/components/LandingWrapper';
|
||||||
import * as RouterActions from 'actions/RouterActions';
|
import * as RouterActions from 'actions/RouterActions';
|
||||||
|
|
||||||
import type { State as TrezorConnectState } from 'reducers/TrezorConnectReducer';
|
import type { State as TrezorConnectState } from 'reducers/TrezorConnectReducer';
|
||||||
@ -148,9 +148,10 @@ class InstallBridge extends PureComponent<Props, State> {
|
|||||||
render() {
|
render() {
|
||||||
const { target } = this.state;
|
const { target } = this.state;
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return <Loader text="Loading" size={100} />;
|
return <LandingWrapper />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
<LandingWrapper loading={!target}>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Top>
|
<Top>
|
||||||
<TitleHeader>TREZOR Bridge<Version>{this.state.currentVersion}</Version></TitleHeader>
|
<TitleHeader>TREZOR Bridge<Version>{this.state.currentVersion}</Version></TitleHeader>
|
||||||
@ -206,6 +207,7 @@ class InstallBridge extends PureComponent<Props, State> {
|
|||||||
)}
|
)}
|
||||||
</Bottom>
|
</Bottom>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
|
</LandingWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
34
src/views/Landing/views/Root/Container.js
Normal file
34
src/views/Landing/views/Root/Container.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* @flow */
|
||||||
|
import * as React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import type { MapStateToProps } from 'react-redux';
|
||||||
|
import type { State } from 'flowtype';
|
||||||
|
import RootView from './index';
|
||||||
|
|
||||||
|
export type StateProps = {
|
||||||
|
localStorage: $ElementType<State, 'localStorage'>,
|
||||||
|
modal: $ElementType<State, 'modal'>,
|
||||||
|
wallet: $ElementType<State, 'wallet'>,
|
||||||
|
connect: $ElementType<State, 'connect'>,
|
||||||
|
router: $ElementType<State, 'router'>,
|
||||||
|
wallet: $ElementType<State, 'wallet'>,
|
||||||
|
devices: $ElementType<State, 'devices'>,
|
||||||
|
children?: React.Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DispatchProps = {};
|
||||||
|
type OwnProps = {};
|
||||||
|
|
||||||
|
export type Props = StateProps & DispatchProps;
|
||||||
|
|
||||||
|
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
||||||
|
localStorage: state.localStorage,
|
||||||
|
modal: state.modal,
|
||||||
|
wallet: state.wallet,
|
||||||
|
connect: state.connect,
|
||||||
|
router: state.router,
|
||||||
|
devices: state.devices,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(RootView);
|
45
src/views/Landing/views/Root/index.js
Normal file
45
src/views/Landing/views/Root/index.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/* @flow */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { isWebUSB } from 'utils/device';
|
||||||
|
|
||||||
|
import LandingWrapper from 'views/Landing/components/LandingWrapper';
|
||||||
|
import BrowserNotSupported from 'views/Landing/components/BrowserNotSupported';
|
||||||
|
import ConnectDevice from 'views/Landing/components/ConnectDevice';
|
||||||
|
import InstallBridge from 'views/Landing/views/InstallBridge/Container';
|
||||||
|
|
||||||
|
import type { Props } from './Container';
|
||||||
|
|
||||||
|
const Root = (props: Props) => {
|
||||||
|
const { initialized, browserState, transport } = props.connect;
|
||||||
|
const { disconnectRequest } = props.wallet;
|
||||||
|
const localStorageError = props.localStorage.error;
|
||||||
|
const connectError = props.connect.error;
|
||||||
|
|
||||||
|
const error = !initialized ? (localStorageError || connectError) : null;
|
||||||
|
const shouldShowUnsupportedBrowser = browserState.supported === false;
|
||||||
|
const shouldShowInstallBridge = initialized && connectError;
|
||||||
|
const shouldShowConnectDevice = props.wallet.ready && props.devices.length < 1;
|
||||||
|
const shouldShowDisconnectDevice = !!disconnectRequest;
|
||||||
|
const isLoading = !error && !shouldShowUnsupportedBrowser && !shouldShowConnectDevice && !shouldShowUnsupportedBrowser;
|
||||||
|
|
||||||
|
const deviceLabel = disconnectRequest ? disconnectRequest.label : '';
|
||||||
|
// corner case: display InstallBridge view on "/" route
|
||||||
|
// it has it's own Container and props
|
||||||
|
if (shouldShowInstallBridge) return <InstallBridge />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LandingWrapper loading={isLoading} error={error}>
|
||||||
|
{shouldShowUnsupportedBrowser && <BrowserNotSupported />}
|
||||||
|
{(shouldShowConnectDevice || shouldShowDisconnectDevice) && (
|
||||||
|
<ConnectDevice
|
||||||
|
deviceLabel={deviceLabel}
|
||||||
|
showWebUsb={isWebUSB(transport)}
|
||||||
|
showDisconnect={shouldShowDisconnectDevice}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</LandingWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Root;
|
@ -1,15 +1,46 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import Content from 'views/Wallet/components/Content';
|
|
||||||
|
|
||||||
const Wrapper = styled.div``;
|
import colors from 'config/colors';
|
||||||
|
import icons from 'config/icons';
|
||||||
|
|
||||||
|
import Content from 'views/Wallet/components/Content';
|
||||||
|
import { H2 } from 'components/Heading';
|
||||||
|
import Icon from 'components/Icon';
|
||||||
|
import Link from 'components/Link';
|
||||||
|
import Button from 'components/Button';
|
||||||
|
|
||||||
|
const Section = styled.section`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Row = styled.div`
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
const WalletSettings = () => (
|
const WalletSettings = () => (
|
||||||
<Content>
|
<Content>
|
||||||
<Wrapper>
|
<Section>
|
||||||
Wallet settings
|
<Row>
|
||||||
</Wrapper>
|
<Icon
|
||||||
|
size={60}
|
||||||
|
color={colors.WARNING_PRIMARY}
|
||||||
|
icon={icons.WARNING}
|
||||||
|
/>
|
||||||
|
<H2>Wallet settings is under construction</H2>
|
||||||
|
<Link to="/">
|
||||||
|
<Button>Take me back</Button>
|
||||||
|
</Link>
|
||||||
|
</Row>
|
||||||
|
</Section>
|
||||||
</Content>
|
</Content>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -7,7 +7,11 @@ import { ConnectedRouter } from 'react-router-redux';
|
|||||||
// general
|
// general
|
||||||
import ErrorBoundary from 'support/ErrorBoundary';
|
import ErrorBoundary from 'support/ErrorBoundary';
|
||||||
import { getPattern } from 'support/routes';
|
import { getPattern } from 'support/routes';
|
||||||
import LandingContainer from 'views/Landing/Container';
|
|
||||||
|
// landing views
|
||||||
|
import RootView from 'views/Landing/views/Root/Container';
|
||||||
|
import InstallBridge from 'views/Landing/views/InstallBridge/Container';
|
||||||
|
import ImportView from 'views/Landing/views/Import/Container';
|
||||||
|
|
||||||
// wallet views
|
// wallet views
|
||||||
import WalletContainer from 'views/Wallet';
|
import WalletContainer from 'views/Wallet';
|
||||||
@ -31,13 +35,13 @@ const App = () => (
|
|||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<ConnectedRouter history={history}>
|
<ConnectedRouter history={history}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path={getPattern('landing-home')} component={LandingContainer} />
|
<Route exact path={getPattern('landing-home')} component={RootView} />
|
||||||
<Route exact path={getPattern('landing-bridge')} component={LandingContainer} />
|
<Route exact path={getPattern('landing-bridge')} component={InstallBridge} />
|
||||||
<Route exact path={getPattern('landing-import')} component={LandingContainer} />
|
<Route exact path={getPattern('landing-import')} component={ImportView} />
|
||||||
<Route>
|
<Route>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<WalletContainer>
|
<WalletContainer>
|
||||||
<Route exact path={getPattern('wallet-setting')} component={WalletSettings} />
|
<Route exact path={getPattern('wallet-settings')} component={WalletSettings} />
|
||||||
<Route exact path={getPattern('wallet-dashboard')} component={WalletDashboard} />
|
<Route exact path={getPattern('wallet-dashboard')} component={WalletDashboard} />
|
||||||
<Route exact path={getPattern('wallet-acquire')} component={WalletAcquire} />
|
<Route exact path={getPattern('wallet-acquire')} component={WalletAcquire} />
|
||||||
<Route exact path={getPattern('wallet-unreadable')} component={WalletUnreadableDevice} />
|
<Route exact path={getPattern('wallet-unreadable')} component={WalletUnreadableDevice} />
|
||||||
|
Loading…
Reference in New Issue
Block a user