merge master

pull/401/head
slowbackspace 5 years ago
commit 74b466be05

@ -1,17 +1,22 @@
## 1.1.0-beta ## 1.1.0-beta
__added__ __added__
- Ripple support enabled - Ripple support
- responsive sidebar - responsive sidebar
- QR code scanner in send form - QR code scanner in send form
- clear send form button - clear send form button
- backup notification modal
__updated__
- connect v7
- babel v7
- ethereum tokens list
- most of dependencies
__changed__ __changed__
- update dependencies - icons for T1 and TT
- upgrade babel7
- split icons for T1 and TT
- device header styles - device header styles
- input styles - input styles
- split sign and verify title - sign and verify title
__fixed__ __fixed__
- beta disclaimer wrapper position - beta disclaimer wrapper position

@ -1,6 +1,6 @@
{ {
"name": "trezor-wallet", "name": "trezor-wallet",
"version": "1.0.3-beta", "version": "1.1.0-beta",
"author": "TREZOR <info@trezor.io>", "author": "TREZOR <info@trezor.io>",
"description": "", "description": "",
"bin": { "bin": {
@ -78,9 +78,9 @@
"styled-components": "^4.1.3", "styled-components": "^4.1.3",
"styled-normalize": "^8.0.6", "styled-normalize": "^8.0.6",
"trezor-bridge-communicator": "1.0.2", "trezor-bridge-communicator": "1.0.2",
"trezor-connect": "7.0.0-beta.2", "trezor-connect": "7.0.0-beta.3",
"wallet-address-validator": "^0.2.4", "wallet-address-validator": "^0.2.4",
"web3": "1.0.0-beta.38", "web3": "1.0.0-beta.35",
"webpack": "^4.29.3", "webpack": "^4.29.3",
"webpack-build-notifier": "^0.1.30", "webpack-build-notifier": "^0.1.30",
"webpack-bundle-analyzer": "^3.0.3", "webpack-bundle-analyzer": "^3.0.3",

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -205,7 +205,7 @@ const discoverAccount = (device: TrezorDevice, discoveryProcess: Discovery): Asy
} }
// handle outdated firmware error // handle outdated firmware error
if (error.message === UI.FIRMWARE) { if (error.message === UI.FIRMWARE_OLD) {
dispatch({ dispatch({
type: DISCOVERY.FIRMWARE_OUTDATED, type: DISCOVERY.FIRMWARE_OUTDATED,
device, device,

@ -59,6 +59,17 @@ export const onPassphraseSubmit = (passphrase: string): AsyncAction => async (di
}); });
}; };
export const onReceiveConfirmation = (confirmation: any): AsyncAction => async (dispatch: Dispatch): Promise<void> => {
await TrezorConnect.uiResponse({
type: UI.RECEIVE_CONFIRMATION,
payload: confirmation,
});
dispatch({
type: MODAL.CLOSE,
});
};
export const onRememberDevice = (device: TrezorDevice): Action => ({ export const onRememberDevice = (device: TrezorDevice): Action => ({
type: CONNECT.REMEMBER, type: CONNECT.REMEMBER,
device, device,
@ -173,6 +184,7 @@ export const onQrScan = (parsedUri: parsedURI, networkType: string): ThunkAction
export default { export default {
onPinSubmit, onPinSubmit,
onPassphraseSubmit, onPassphraseSubmit,
onReceiveConfirmation,
onRememberDevice, onRememberDevice,
onForgetDevice, onForgetDevice,
onForgetSingleDevice, onForgetSingleDevice,

@ -94,6 +94,10 @@ export const showAddress = (path: Array<number>): AsyncAction => async (dispatch
type: RECEIVE.HIDE_ADDRESS, type: RECEIVE.HIDE_ADDRESS,
}); });
// special case: device no-backup permissions not granted
// $FlowIssue: remove this after trezor-connect@7.0.0 release
if (response.payload.code === 403) return;
dispatch({ dispatch({
type: NOTIFICATION.ADD, type: NOTIFICATION.ADD,
payload: { payload: {

@ -347,6 +347,17 @@ export const gotoFirmwareUpdate = (): ThunkAction => (dispatch: Dispatch, getSta
dispatch(goto(`/device/${devUrl}/firmware-update`)); dispatch(goto(`/device/${devUrl}/firmware-update`));
}; };
/*
* Go to NoBackup page
*/
export const gotoBackup = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
const { selectedDevice } = getState().wallet;
if (!selectedDevice || !selectedDevice.features) return;
const devUrl: string = `${selectedDevice.features.device_id}${selectedDevice.instance ? `:${selectedDevice.instance}` : ''}`;
dispatch(goto(`/device/${devUrl}/backup`));
};
/* /*
* Try to redirect to initial url * Try to redirect to initial url
*/ */

@ -3,6 +3,7 @@ import TrezorConnect, {
DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, BLOCKCHAIN_EVENT, DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, BLOCKCHAIN_EVENT,
} from 'trezor-connect'; } from 'trezor-connect';
import { CONTEXT_NONE } from 'actions/constants/modal'; import { CONTEXT_NONE } from 'actions/constants/modal';
import urlConstants from 'constants/urls';
import * as CONNECT from 'actions/constants/TrezorConnect'; import * as CONNECT from 'actions/constants/TrezorConnect';
import * as NOTIFICATION from 'actions/constants/notification'; import * as NOTIFICATION from 'actions/constants/notification';
import { getDuplicateInstanceNumber } from 'reducers/utils'; import { getDuplicateInstanceNumber } from 'reducers/utils';
@ -120,7 +121,7 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS
if (buildUtils.isDev()) { if (buildUtils.isDev()) {
window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/'; // eslint-disable-line no-underscore-dangle window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/'; // eslint-disable-line no-underscore-dangle
// window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://connect.trezor.io/5/'; // eslint-disable-line no-underscore-dangle // window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://localhost:8088/'; // eslint-disable-line no-underscore-dangle
window.TrezorConnect = TrezorConnect; window.TrezorConnect = TrezorConnect;
} }
@ -131,6 +132,10 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS
popup: false, popup: false,
webusb: true, webusb: true,
pendingTransportEvent: (getState().devices.length < 1), pendingTransportEvent: (getState().devices.length < 1),
manifest: {
email: 'info@trezor.io',
appUrl: urlConstants.NEXT_WALLET,
},
}); });
} catch (error) { } catch (error) {
dispatch({ dispatch({

@ -7,3 +7,4 @@ export const CONTEXT_DEVICE: 'modal_ctx_device' = 'modal_ctx_device';
export const CONTEXT_EXTERNAL_WALLET: 'modal_ctx_external-wallet' = 'modal_ctx_external-wallet'; export const CONTEXT_EXTERNAL_WALLET: 'modal_ctx_external-wallet' = 'modal_ctx_external-wallet';
export const OPEN_SCAN_QR: 'modal__open_scan_qr' = 'modal__open_scan_qr'; export const OPEN_SCAN_QR: 'modal__open_scan_qr' = 'modal__open_scan_qr';
export const CONTEXT_SCAN_QR: 'modal__ctx_scan_qr' = 'modal__ctx_scan_qr'; export const CONTEXT_SCAN_QR: 'modal__ctx_scan_qr' = 'modal__ctx_scan_qr';
export const CONTEXT_CONFIRMATION: 'modal__ctx_confirmation' = 'modal__ctx_confirmation';

@ -28,7 +28,7 @@ const Backdrop = ({
); );
Backdrop.propTypes = { Backdrop.propTypes = {
show: PropTypes.bool.isRequired, show: PropTypes.bool,
className: PropTypes.string, className: PropTypes.string,
animated: PropTypes.bool, animated: PropTypes.bool,
onClick: PropTypes.func, onClick: PropTypes.func,

@ -63,7 +63,7 @@ const Footer = ({ opened, toggle, isLanding }: Props) => (
<Left> <Left>
<Copy>&copy; {getYear(new Date())}</Copy> <Copy>&copy; {getYear(new Date())}</Copy>
<StyledLink href="http://satoshilabs.com" isGreen>SatoshiLabs</StyledLink> <StyledLink href="http://satoshilabs.com" isGreen>SatoshiLabs</StyledLink>
<StyledLink href="./assets/tos.pdf" isGreen> <StyledLink href="https://trezor.io/static/pdf/tos.pdf" isGreen>
<FormattedMessage {...l10nMessages.TR_TERMS} /> <FormattedMessage {...l10nMessages.TR_TERMS} />
</StyledLink> </StyledLink>
<StyledLink onClick={toggle} isGreen>{ opened ? 'Hide Log' : 'Show Log' }</StyledLink> <StyledLink onClick={toggle} isGreen>{ opened ? 'Hide Log' : 'Show Log' }</StyledLink>

@ -0,0 +1,85 @@
/* @flow */
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import icons from 'config/icons';
import { getOldWalletUrl } from 'utils/url';
import colors from 'config/colors';
import { H2 } from 'components/Heading';
import P from 'components/Paragraph';
import Icon from 'components/Icon';
import Button from 'components/Button';
import Link from 'components/Link';
import type { TrezorDevice } from 'flowtype';
import type { Props as BaseProps } from '../../Container';
type Props = {
onReceiveConfirmation: $ElementType<$ElementType<BaseProps, 'modalActions'>, 'onReceiveConfirmation'>;
device: ?TrezorDevice;
}
const Wrapper = styled.div`
max-width: 370px;
padding: 30px 48px;
`;
const StyledLink = styled(Link)`
position: absolute;
right: 15px;
top: 15px;
`;
const BackupButton = styled(Button)`
width: 100%;
margin-bottom: 10px;
`;
const ProceedButton = styled(Button)`
background: transparent;
border-color: ${colors.WARNING_PRIMARY};
color: ${colors.WARNING_PRIMARY};
&:focus,
&:hover,
&:active {
color: ${colors.WHITE};
background: ${colors.WARNING_PRIMARY};
box-shadow: none;
}
`;
const StyledP = styled(P)`
padding-bottom: 20px;
`;
const Row = styled.div`
display: flex;
flex-direction: column;
`;
const Confirmation = (props: Props) => (
<Wrapper>
<StyledLink onClick={() => props.onReceiveConfirmation(false)}>
<Icon size={24} color={colors.TEXT_SECONDARY} icon={icons.CLOSE} />
</StyledLink>
<H2>Your Trezor is not backed up</H2>
<Icon size={48} color={colors.WARNING_PRIMARY} icon={icons.WARNING} />
<StyledP isSmaller>If your device is ever lost or damaged, your funds will be lost. Backup your device first, to protect your coins against such events.</StyledP>
<Row>
<Link href={`${getOldWalletUrl(props.device)}/?backup`}>
<BackupButton onClick={() => props.onReceiveConfirmation(false)}>Create a backup in 3 minutes</BackupButton>
</Link>
<ProceedButton isWhite onClick={() => props.onReceiveConfirmation(true)}>Show address, I will take the risk</ProceedButton>
</Row>
</Wrapper>
);
Confirmation.propTypes = {
onReceiveConfirmation: PropTypes.func.isRequired,
};
export default Confirmation;

@ -2,7 +2,7 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import styled from 'styled-components'; import styled from 'styled-components';
import { getOldWalletUrl } from 'utils/url';
import icons from 'config/icons'; import icons from 'config/icons';
import colors from 'config/colors'; import colors from 'config/colors';
@ -34,11 +34,23 @@ const StyledLink = styled(Link)`
const Wrapper = styled.div` const Wrapper = styled.div`
max-width: 370px; max-width: 370px;
padding: 30px 48px; padding: 30px 0px;
`;
const Content = styled.div`
padding: 0px 48px;
`; `;
const StyledP = styled(P)` const StyledP = styled(P)`
padding: 20px 0px; padding-bottom: 20px;
`;
const Divider = styled.div`
width: 100%;
height: 1px;
background: ${colors.DIVIDER};
margin: 20px 0px;
`; `;
const Row = styled.div` const Row = styled.div`
@ -50,6 +62,24 @@ const Row = styled.div`
} }
`; `;
const BackupButton = styled(Button)`
width: 100%;
`;
const WarnButton = styled(Button)`
background: transparent;
border-color: ${colors.WARNING_PRIMARY};
color: ${colors.WARNING_PRIMARY};
&:focus,
&:hover,
&:active {
color: ${colors.WHITE};
background: ${colors.WARNING_PRIMARY};
box-shadow: none;
}
`;
class ConfirmUnverifiedAddress extends PureComponent<Props> { class ConfirmUnverifiedAddress extends PureComponent<Props> {
componentDidMount(): void { componentDidMount(): void {
this.keyboardHandler = this.keyboardHandler.bind(this); this.keyboardHandler = this.keyboardHandler.bind(this);
@ -100,22 +130,44 @@ class ConfirmUnverifiedAddress extends PureComponent<Props> {
: <FormattedMessage {...l10nMessages.TR_PLEASE_DISABLE_PASSPHRASE} />; : <FormattedMessage {...l10nMessages.TR_PLEASE_DISABLE_PASSPHRASE} />;
} }
const needsBackup = device.features && device.features.needs_backup;
return ( return (
<Wrapper> <Wrapper>
<StyledLink onClick={onCancel}> <Content>
<Icon size={24} color={colors.TEXT_SECONDARY} icon={icons.CLOSE} /> <StyledLink onClick={onCancel}>
</StyledLink> <Icon size={24} color={colors.TEXT_SECONDARY} icon={icons.CLOSE} />
<H2>{ deviceStatus }</H2> </StyledLink>
<StyledP isSmaller> <H2>{ deviceStatus }</H2>
<FormattedMessage <StyledP isSmaller>
{...l10nMessages.TR_TO_PREVENT_PHISHING_ATTACKS_COMMA} <FormattedMessage
values={{ claim }} {...l10nMessages.TR_TO_PREVENT_PHISHING_ATTACKS_COMMA}
/> values={{ claim }}
</StyledP> />
<Row> </StyledP>
<Button onClick={() => (!account ? this.verifyAddress() : 'false')}><FormattedMessage {...l10nMessages.TR_TRY_AGAIN} /></Button> </Content>
<Button isWhite onClick={() => this.showUnverifiedAddress()}><FormattedMessage {...l10nMessages.TR_SHOW_UNVERIFIED_ADDRESS} /></Button> <Content>
</Row> <Row>
<Button onClick={() => (!account ? this.verifyAddress() : 'false')}><FormattedMessage {...l10nMessages.TR_TRY_AGAIN} /></Button>
<WarnButton isWhite onClick={() => this.showUnverifiedAddress()}><FormattedMessage {...l10nMessages.TR_SHOW_UNVERIFIED_ADDRESS} /></WarnButton>
</Row>
</Content>
{needsBackup && <Divider />}
{needsBackup && (
<>
<Content>
<H2>Device {device.label} is not backed up</H2>
<StyledP isSmaller>If your device is ever lost or damaged, your funds will be lost. Backup your device first, to protect your coins against such events.</StyledP>
</Content>
<Content>
<Row>
<Link href={`${getOldWalletUrl(device)}/?backup`}>
<BackupButton>Create a backup in 3 minutes</BackupButton>
</Link>
</Row>
</Content>
</>
)}
</Wrapper> </Wrapper>
); );
} }

@ -19,6 +19,7 @@ import PassphraseType from 'components/modals/passphrase/Type';
import ConfirmSignTx from 'components/modals/confirm/SignTx'; import ConfirmSignTx from 'components/modals/confirm/SignTx';
import ConfirmAction from 'components/modals/confirm/Action'; import ConfirmAction from 'components/modals/confirm/Action';
import ConfirmUnverifiedAddress from 'components/modals/confirm/UnverifiedAddress'; import ConfirmUnverifiedAddress from 'components/modals/confirm/UnverifiedAddress';
import ConfirmNoBackup from 'components/modals/confirm/NoBackup';
import ForgetDevice from 'components/modals/device/Forget'; import ForgetDevice from 'components/modals/device/Forget';
import RememberDevice from 'components/modals/device/Remember'; import RememberDevice from 'components/modals/device/Remember';
import DuplicateDevice from 'components/modals/device/Duplicate'; import DuplicateDevice from 'components/modals/device/Duplicate';
@ -189,6 +190,19 @@ const getQrModal = (props: Props) => {
); );
}; };
const getConfirmationModal = (props: Props) => {
const { modal, modalActions, wallet } = props;
if (modal.context !== MODAL.CONTEXT_CONFIRMATION) return null;
switch (modal.windowType) {
case 'no-backup':
return (<ConfirmNoBackup device={wallet.selectedDevice} onReceiveConfirmation={modalActions.onReceiveConfirmation} />);
default:
return null;
}
};
// modal container component // modal container component
const Modal = (props: Props) => { const Modal = (props: Props) => {
const { modal } = props; const { modal } = props;
@ -205,6 +219,9 @@ const Modal = (props: Props) => {
case MODAL.CONTEXT_SCAN_QR: case MODAL.CONTEXT_SCAN_QR:
component = getQrModal(props); component = getQrModal(props);
break; break;
case MODAL.CONTEXT_CONFIRMATION:
component = getConfirmationModal(props);
break;
default: default:
break; break;
} }

@ -0,0 +1,25 @@
/* @flow */
import * as React from 'react';
import Notification from 'components/Notification';
import type { Props } from '../../index';
export default (props: Props) => {
const { selectedDevice } = props.wallet;
const needsBackup = selectedDevice && selectedDevice.features && selectedDevice.features.needs_backup;
if (!needsBackup) return null;
return (
<Notification
key="no-backup"
type="warning"
title="Your Trezor is not backed up!"
message="If your device is ever lost or damaged, your funds will be lost. Backup your device first, to protect your coins against such events."
actions={
[{
label: 'Create a backup',
callback: props.routerActions.gotoBackup,
}]
}
/>
);
};

@ -13,6 +13,7 @@ import * as RouterActions from 'actions/RouterActions';
import OnlineStatus from './components/OnlineStatus'; import OnlineStatus from './components/OnlineStatus';
import UpdateBridge from './components/UpdateBridge'; import UpdateBridge from './components/UpdateBridge';
import UpdateFirmware from './components/UpdateFirmware'; import UpdateFirmware from './components/UpdateFirmware';
import NoBackup from './components/NoBackup';
export type StateProps = { export type StateProps = {
connect: $ElementType<State, 'connect'>; connect: $ElementType<State, 'connect'>;
@ -36,6 +37,7 @@ const Notifications = (props: Props) => (
<OnlineStatus {...props} /> <OnlineStatus {...props} />
<UpdateBridge {...props} /> <UpdateBridge {...props} />
<UpdateFirmware {...props} /> <UpdateFirmware {...props} />
<NoBackup {...props} />
</React.Fragment> </React.Fragment>
); );

@ -47,6 +47,21 @@ export default (props: Props) => {
)} )}
/>, />,
); );
} else if (location.state.send) {
notifications.push(
<Notification
key="xrp-warning"
type="warning"
title="Do not send to accounts requiring a destination tag!"
message={(
<>
Destination tag is an arbitrary number which serves as a unique identifier of your transaction. Some services may require this to process your transaction. The current firmware version <strong>does not support</strong> destination tags yet.
<br /><br />
If the receiver requires a destination tag, do not use Trezor to send XRP. We are working on adding this feature.
</>
)}
/>,
);
} }
} }

@ -0,0 +1,5 @@
export default {
NEXT_WALLET: 'https://beta-wallet.trezor.io/next',
OLD_WALLET: 'https://wallet.trezor.io',
OLD_WALLET_BETA: 'https://beta-wallet.trezor.io',
};

@ -38,6 +38,7 @@ import type {
Device, Device,
Features, Features,
DeviceStatus, DeviceStatus,
FirmwareRelease,
DeviceFirmwareStatus, DeviceFirmwareStatus,
DeviceMode, DeviceMode,
DeviceMessageType, DeviceMessageType,
@ -55,6 +56,7 @@ export type AcquiredDevice = $Exact<{
+label: string, +label: string,
+features: Features, +features: Features,
+firmware: DeviceFirmwareStatus, +firmware: DeviceFirmwareStatus,
+firmwareRelease: ?FirmwareRelease,
status: DeviceStatus, status: DeviceStatus,
+mode: DeviceMode, +mode: DeviceMode,
state: ?string, state: ?string,

@ -20,7 +20,10 @@ export type State = {
windowType?: string; windowType?: string;
} | { } | {
context: typeof MODAL.CONTEXT_SCAN_QR, context: typeof MODAL.CONTEXT_SCAN_QR,
} } | {
context: typeof MODAL.CONTEXT_CONFIRMATION,
windowType: string;
};
const initialState: State = { const initialState: State = {
context: MODAL.CONTEXT_NONE, context: MODAL.CONTEXT_NONE,
@ -98,6 +101,12 @@ export default function modal(state: State = initialState, action: Action): Stat
context: MODAL.CONTEXT_SCAN_QR, context: MODAL.CONTEXT_SCAN_QR,
}; };
case UI.REQUEST_CONFIRMATION:
return {
context: MODAL.CONTEXT_CONFIRMATION,
windowType: action.payload.view,
};
default: default:
return state; return state;
} }

@ -62,6 +62,11 @@ export const routes: Array<Route> = [
pattern: '/device/:device/firmware-update', pattern: '/device/:device/firmware-update',
fields: ['device', 'firmware-update'], fields: ['device', 'firmware-update'],
}, },
{
name: 'wallet-backup',
pattern: '/device/:device/backup',
fields: ['device', 'backup'],
},
{ {
name: 'wallet-device-settings', name: 'wallet-device-settings',
pattern: '/device/:device/settings', pattern: '/device/:device/settings',

@ -0,0 +1,24 @@
/* @flow */
import urlConstants from 'constants/urls';
import type { TrezorDevice } from 'flowtype';
const getOldWalletUrl = (device: ?TrezorDevice): string => {
if (!device || !device.firmwareRelease) return urlConstants.OLD_WALLET_BETA;
const release = device.firmwareRelease;
const url = release.channel === 'beta' ? urlConstants.OLD_WALLET_BETA : urlConstants.OLD_WALLET;
return url;
};
// TODO: use uri template to build urls
const getOldWalletReleaseUrl = (device: ?TrezorDevice): string => {
if (!device || !device.firmwareRelease) return urlConstants.OLD_WALLET_BETA;
const release = device.firmwareRelease;
const url = getOldWalletUrl(device);
const version = release.version.join('.');
return `${url}?fw=${version}`;
};
export {
getOldWalletUrl,
getOldWalletReleaseUrl,
};

@ -82,16 +82,16 @@ const getFeeInputState = (feeErrors: string, feeWarnings: string): string => {
return state; return state;
}; };
const getDestinationTagInputState = (errors: string, warnings: string): string => { // const getDestinationTagInputState = (errors: string, warnings: string): string => {
let state = ''; // let state = '';
if (warnings && !errors) { // if (warnings && !errors) {
state = 'warning'; // state = 'warning';
} // }
if (errors) { // if (errors) {
state = 'error'; // state = 'error';
} // }
return state; // return state;
}; // };
const Left = styled.div` const Left = styled.div`
display: flex; display: flex;
@ -109,11 +109,11 @@ const AdvancedForm = (props: Props) => {
warnings, warnings,
infos, infos,
fee, fee,
destinationTag, // destinationTag,
} = props.sendForm; } = props.sendForm;
const { const {
onFeeChange, onFeeChange,
onDestinationTagChange, // onDestinationTagChange,
} = props.sendFormActions; } = props.sendFormActions;
return ( return (
@ -150,7 +150,7 @@ const AdvancedForm = (props: Props) => {
/> />
</InputRow> </InputRow>
<InputRow> {/* <InputRow>
<StyledInput <StyledInput
state={getDestinationTagInputState(errors.destinationTag, warnings.destinationTag)} state={getDestinationTagInputState(errors.destinationTag, warnings.destinationTag)}
autoComplete="off" autoComplete="off"
@ -180,7 +180,7 @@ const AdvancedForm = (props: Props) => {
value={destinationTag} value={destinationTag}
onChange={event => onDestinationTagChange(event.target.value)} onChange={event => onDestinationTagChange(event.target.value)}
/> />
</InputRow> </InputRow> */}
<AdvancedSettingsSendButtonWrapper> <AdvancedSettingsSendButtonWrapper>
{ props.children } { props.children }

@ -6,6 +6,7 @@ import styled from 'styled-components';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import colors from 'config/colors'; import colors from 'config/colors';
import ICONS from 'config/icons'; import ICONS from 'config/icons';
import Tooltip from 'components/Tooltip';
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables'; import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
import type { Network, State as ReducersState } from 'flowtype'; import type { Network, State as ReducersState } from 'flowtype';
import l10nMessages from './index.messages'; import l10nMessages from './index.messages';
@ -58,6 +59,7 @@ const FiatValue = styled.div`
margin: 7px 0; margin: 7px 0;
min-height: 25px; min-height: 25px;
color: ${colors.TEXT_PRIMARY}; color: ${colors.TEXT_PRIMARY};
align-items: center;
`; `;
const FiatValueRate = styled.div` const FiatValueRate = styled.div`
@ -88,6 +90,15 @@ const Label = styled.div`
color: ${colors.TEXT_SECONDARY}; color: ${colors.TEXT_SECONDARY};
`; `;
const StyledIcon = styled(Icon)`
cursor: pointer;
margin-top: -5px;
`;
const TooltipWrapper = styled.div`
display: flex;
align-items: center;
`;
class AccountBalance extends PureComponent<Props, State> { class AccountBalance extends PureComponent<Props, State> {
constructor(props: Props) { constructor(props: Props) {
@ -117,6 +128,20 @@ class AccountBalance extends PureComponent<Props, State> {
fiat = accountBalance.times(fiatRateValue).toFixed(2); fiat = accountBalance.times(fiatRateValue).toFixed(2);
} }
const NoRatesTooltip = (
<Tooltip
maxWidth={285}
placement="top"
content="Fiat rates are not currently available."
>
<StyledIcon
icon={ICONS.HELP}
color={colors.TEXT_SECONDARY}
size={26}
/>
</Tooltip>
);
return ( return (
<Wrapper isHidden={this.state.isHidden}> <Wrapper isHidden={this.state.isHidden}>
<HideBalanceIconWrapper <HideBalanceIconWrapper
@ -134,18 +159,20 @@ class AccountBalance extends PureComponent<Props, State> {
<React.Fragment> <React.Fragment>
<BalanceWrapper> <BalanceWrapper>
<Label><FormattedMessage {...l10nMessages.TR_BALANCE} /></Label> <Label><FormattedMessage {...l10nMessages.TR_BALANCE} /></Label>
{fiatRate && ( <TooltipWrapper>
<FiatValue>${fiat}</FiatValue> <FiatValue>{fiatRate ? `$ ${fiat}` : 'N/A'}</FiatValue>
)} {!fiatRate && NoRatesTooltip}
</TooltipWrapper>
<CoinBalance>{this.props.balance} {network.symbol}</CoinBalance> <CoinBalance>{this.props.balance} {network.symbol}</CoinBalance>
</BalanceWrapper> </BalanceWrapper>
{fiatRate && ( <BalanceRateWrapper>
<BalanceRateWrapper> <Label><FormattedMessage {...l10nMessages.TR_RATE} /></Label>
<Label><FormattedMessage {...l10nMessages.TR_RATE} /></Label> <TooltipWrapper>
<FiatValueRate>${fiatRateValue}</FiatValueRate> <FiatValueRate>{fiatRate ? `$ ${fiatRateValue}` : 'N/A'}</FiatValueRate>
<CoinBalance>1.00 {network.symbol}</CoinBalance> {!fiatRate && NoRatesTooltip}
</BalanceRateWrapper> </TooltipWrapper>
)} <CoinBalance>1 {network.symbol}</CoinBalance>
</BalanceRateWrapper>
</React.Fragment> </React.Fragment>
)} )}
</Wrapper> </Wrapper>

@ -6,7 +6,7 @@ import Icon from 'components/Icon';
import colors from 'config/colors'; import colors from 'config/colors';
import ICONS from 'config/icons'; import ICONS from 'config/icons';
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables'; import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
import Tooltip from 'components/Tooltip';
import type { Network, State as ReducersState } from 'flowtype'; import type { Network, State as ReducersState } from 'flowtype';
type Props = { type Props = {
@ -57,6 +57,7 @@ const FiatValue = styled.div`
margin: 7px 0; margin: 7px 0;
min-height: 25px; min-height: 25px;
color: ${colors.TEXT_PRIMARY}; color: ${colors.TEXT_PRIMARY};
align-items: center;
`; `;
const FiatValueRate = styled.div` const FiatValueRate = styled.div`
@ -65,8 +66,8 @@ const FiatValueRate = styled.div`
min-height: 25px; min-height: 25px;
margin: 7px 0; margin: 7px 0;
display: flex; display: flex;
align-items: center;
color: ${colors.TEXT_PRIMARY}; color: ${colors.TEXT_PRIMARY};
align-items: center;
`; `;
const BalanceWrapper = styled.div` const BalanceWrapper = styled.div`
@ -87,6 +88,15 @@ const Label = styled.div`
color: ${colors.TEXT_SECONDARY}; color: ${colors.TEXT_SECONDARY};
`; `;
const StyledIcon = styled(Icon)`
cursor: pointer;
margin-top: -5px;
`;
const TooltipWrapper = styled.div`
display: flex;
align-items: center;
`;
class AccountBalance extends PureComponent<Props, State> { class AccountBalance extends PureComponent<Props, State> {
constructor(props: Props) { constructor(props: Props) {
@ -116,6 +126,20 @@ class AccountBalance extends PureComponent<Props, State> {
fiat = accountBalance.times(fiatRateValue).toFixed(2); fiat = accountBalance.times(fiatRateValue).toFixed(2);
} }
const NoRatesTooltip = (
<Tooltip
maxWidth={285}
placement="top"
content="Fiat rates are not currently available."
>
<StyledIcon
icon={ICONS.HELP}
color={colors.TEXT_SECONDARY}
size={26}
/>
</Tooltip>
);
return ( return (
<Wrapper isHidden={this.state.isHidden}> <Wrapper isHidden={this.state.isHidden}>
<HideBalanceIconWrapper <HideBalanceIconWrapper
@ -133,24 +157,28 @@ class AccountBalance extends PureComponent<Props, State> {
<React.Fragment> <React.Fragment>
<BalanceWrapper> <BalanceWrapper>
<Label>Balance</Label> <Label>Balance</Label>
{fiatRate && ( <TooltipWrapper>
<FiatValue>${fiat}</FiatValue> <FiatValue>{fiatRate ? `$ ${fiat}` : 'N/A'}</FiatValue>
)} {!fiatRate && NoRatesTooltip}
</TooltipWrapper>
<CoinBalance>{this.props.balance} {network.symbol}</CoinBalance> <CoinBalance>{this.props.balance} {network.symbol}</CoinBalance>
</BalanceWrapper> </BalanceWrapper>
{this.props.reserve !== '0' && ( {this.props.reserve !== '0' && (
<BalanceWrapper> <BalanceWrapper>
<Label>Reserve</Label> <Label>Reserve</Label>
<CoinBalance>{this.props.reserve} {network.symbol}</CoinBalance> <FiatValueRate>{this.props.reserve} {network.symbol}</FiatValueRate>
</BalanceWrapper> </BalanceWrapper>
)} )}
{fiatRate && (
<BalanceRateWrapper> <BalanceRateWrapper>
<Label>Rate</Label> <Label>Rate</Label>
<FiatValueRate>${fiatRateValue}</FiatValueRate> <TooltipWrapper>
<CoinBalance>1.00 {network.symbol}</CoinBalance> <FiatValueRate>{fiatRate ? `$ ${fiatRateValue}` : 'N/A'}</FiatValueRate>
</BalanceRateWrapper> {!fiatRate && NoRatesTooltip}
)} </TooltipWrapper>
<CoinBalance>1 {network.symbol}</CoinBalance>
</BalanceRateWrapper>
</React.Fragment> </React.Fragment>
)} )}
</Wrapper> </Wrapper>

@ -1,3 +1,4 @@
/* @flow */
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { H1 } from 'components/Heading'; import { H1 } from 'components/Heading';
@ -7,9 +8,16 @@ import Button from 'components/Button';
import P from 'components/Paragraph'; import P from 'components/Paragraph';
import Link from 'components/Link'; import Link from 'components/Link';
import ICONS from 'config/icons'; import ICONS from 'config/icons';
import { getOldWalletUrl } from 'utils/url';
import Content from 'views/Wallet/components/Content'; import Content from 'views/Wallet/components/Content';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import type { TrezorDevice } from 'flowtype';
type Props = {
device: ?TrezorDevice;
}
const Section = styled.section` const Section = styled.section`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -32,7 +40,7 @@ const StyledH1 = styled(H1)`
text-align: center; text-align: center;
`; `;
const DeviceSettings = () => ( const DeviceSettings = (props: Props) => (
<Content> <Content>
<Section> <Section>
<Row> <Row>
@ -43,7 +51,7 @@ const DeviceSettings = () => (
/> />
<StyledH1>Device settings is under construction</StyledH1> <StyledH1>Device settings is under construction</StyledH1>
<StyledP>Please use Bitcoin wallet interface to change your device settings</StyledP> <StyledP>Please use Bitcoin wallet interface to change your device settings</StyledP>
<Link href="https://beta-wallet.trezor.io/"> <Link href={getOldWalletUrl(props.device)}>
<Button>Take me to the Bitcoin wallet</Button> <Button>Take me to the Bitcoin wallet</Button>
</Link> </Link>
</Row> </Row>

@ -4,6 +4,7 @@ import React from 'react';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { getOldWalletReleaseUrl } from 'utils/url';
import styled from 'styled-components'; import styled from 'styled-components';
import { H1 } from 'components/Heading'; import { H1 } from 'components/Heading';
@ -136,7 +137,7 @@ const FirmwareUpdate = (props: Props) => (
<StyledP> <StyledP>
<FormattedMessage {...l10nMessages.TR_PLEASE_USE_OLD_WALLET} /> <FormattedMessage {...l10nMessages.TR_PLEASE_USE_OLD_WALLET} />
</StyledP> </StyledP>
<Link href="https://beta-wallet.trezor.io"> <Link href={getOldWalletReleaseUrl(props.device)}>
<Button> <Button>
<FormattedMessage {...l10nCommonMessages.TR_TAKE_ME_TO_BITCOIN_WALLET} /> <FormattedMessage {...l10nCommonMessages.TR_TAKE_ME_TO_BITCOIN_WALLET} />
</Button> </Button>

@ -1,14 +1,22 @@
/* @flow */
import styled from 'styled-components'; import styled from 'styled-components';
import { H1 } from 'components/Heading'; import { H1 } from 'components/Heading';
import Button from 'components/Button'; import Button from 'components/Button';
import { getOldWalletUrl } from 'utils/url';
import Paragraph from 'components/Paragraph'; import Paragraph from 'components/Paragraph';
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import l10nCommonMessages from 'views/common.messages'; import l10nCommonMessages from 'views/common.messages';
import type { TrezorDevice } from 'flowtype';
import l10nMessages from './index.messages'; import l10nMessages from './index.messages';
type Props = {
device: ?TrezorDevice;
}
const Wrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -29,12 +37,12 @@ const StyledParagraph = styled(Paragraph)`
text-align: center; text-align: center;
`; `;
const Initialize = () => ( const Initialize = (props: Props) => (
<Wrapper data-test="Page__device__not__initialized"> <Wrapper data-test="Page__device__not__initialized">
<Row> <Row>
<H1><FormattedMessage {...l10nMessages.TR_YOUR_DEVICE_IS_NOT_INITIALIZED} /></H1> <H1><FormattedMessage {...l10nMessages.TR_YOUR_DEVICE_IS_NOT_INITIALIZED} /></H1>
<StyledParagraph><FormattedMessage {...l10nMessages.TR_PLEASE_USE_TO_START_INITIALIZATION} /></StyledParagraph> <StyledParagraph><FormattedMessage {...l10nMessages.TR_PLEASE_USE_TO_START_INITIALIZATION} /></StyledParagraph>
<A href="https://beta-wallet.trezor.io/"> <A href={getOldWalletUrl(props.device)}>
<Button><FormattedMessage {...l10nCommonMessages.TR_TAKE_ME_TO_BITCOIN_WALLET} /></Button> <Button><FormattedMessage {...l10nCommonMessages.TR_TAKE_ME_TO_BITCOIN_WALLET} /></Button>
</A> </A>
</Row> </Row>

@ -0,0 +1,67 @@
/* @flow */
import React from 'react';
import styled from 'styled-components';
import { H1 } from 'components/Heading';
import P from 'components/Paragraph';
import Link from 'components/Link';
import { getOldWalletUrl } from 'utils/url';
import Button from 'components/Button';
import Icon from 'components/Icon';
import { FONT_SIZE } from 'config/variables';
import colors from 'config/colors';
import icons from 'config/icons';
import type { TrezorDevice } from 'flowtype';
type Props = {
device: ?TrezorDevice;
}
const Wrapper = styled.section`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 90px 35px 40px 35px;
`;
const StyledNavLink = styled(Link)`
color: ${colors.TEXT_SECONDARY};
padding-top: 20px;
font-size: ${FONT_SIZE.BASE};
`;
const StyledH1 = styled(H1)`
text-align: center;
`;
const StyledP = styled(P)`
max-width: 550px;
padding-bottom: 15px;
`;
const Message = styled.div`
text-align: center;
padding: 0 0 15px 0;
`;
const FirmwareUpdate = (props: Props) => (
<Wrapper>
<Icon
size={128}
color={colors.WARNING_PRIMARY}
icon={icons.WARNING}
/>
<StyledH1>Your Trezor is not backed up!</StyledH1>
<Message>
<StyledP>If your device is ever lost or damaged, your funds will be lost. Backup your device first, to protect your coins against such events.</StyledP>
<P>Please use Bitcoin wallet interface to create a backup.</P>
</Message>
<Link href={`${getOldWalletUrl(props.device)}?backup=1`}>
<Button>Take me to the Bitcoin wallet</Button>
</Link>
<StyledNavLink to="/">Ill do that later.</StyledNavLink>
</Wrapper>
);
export default FirmwareUpdate;

@ -28,6 +28,7 @@ import WalletDeviceSettings from 'views/Wallet/views/DeviceSettings';
import WalletSettings from 'views/Wallet/views/WalletSettings'; import WalletSettings from 'views/Wallet/views/WalletSettings';
import WalletBootloader from 'views/Wallet/views/Bootloader'; import WalletBootloader from 'views/Wallet/views/Bootloader';
import WalletFirmwareUpdate from 'views/Wallet/views/FirmwareUpdate'; import WalletFirmwareUpdate from 'views/Wallet/views/FirmwareUpdate';
import WalletNoBackup from 'views/Wallet/views/NoBackup';
import WalletInitialize from 'views/Wallet/views/Initialize'; import WalletInitialize from 'views/Wallet/views/Initialize';
import WalletSeedless from 'views/Wallet/views/Seedless'; import WalletSeedless from 'views/Wallet/views/Seedless';
import WalletAcquire from 'views/Wallet/views/Acquire'; import WalletAcquire from 'views/Wallet/views/Acquire';
@ -56,6 +57,7 @@ const App = () => (
<Route exact path={getPattern('wallet-initialize')} component={WalletInitialize} /> <Route exact path={getPattern('wallet-initialize')} component={WalletInitialize} />
<Route exact path={getPattern('wallet-seedless')} component={WalletSeedless} /> <Route exact path={getPattern('wallet-seedless')} component={WalletSeedless} />
<Route exact path={getPattern('wallet-firmware-update')} component={WalletFirmwareUpdate} /> <Route exact path={getPattern('wallet-firmware-update')} component={WalletFirmwareUpdate} />
<Route exact path={getPattern('wallet-backup')} component={WalletNoBackup} />
<Route exact path={getPattern('wallet-device-settings')} component={WalletDeviceSettings} /> <Route exact path={getPattern('wallet-device-settings')} component={WalletDeviceSettings} />
<Route exact path={getPattern('wallet-account-summary')} component={AccountSummary} /> <Route exact path={getPattern('wallet-account-summary')} component={AccountSummary} />
<Route path={getPattern('wallet-account-send')} component={AccountSend} /> <Route path={getPattern('wallet-account-send')} component={AccountSend} />

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save