From 8f55a04931bd0533295c6a139ab4b910c0c70bca Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 17:34:19 +0100 Subject: [PATCH 01/33] add list of supported fiat currencies --- src/config/app.js | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/config/app.js diff --git a/src/config/app.js b/src/config/app.js new file mode 100644 index 00000000..c9778da3 --- /dev/null +++ b/src/config/app.js @@ -0,0 +1,48 @@ +export const FIAT_CURRENCIES = [ + 'usd', + 'aed', + 'ars', + 'aud', + 'bdt', + 'bhd', + 'bmd', + 'brl', + 'cad', + 'chf', + 'clp', + 'cny', + 'czk', + 'dkk', + 'eur', + 'gbp', + 'hkd', + 'huf', + 'idr', + 'ils', + 'inr', + 'jpy', + 'krw', + 'kwd', + 'lkr', + 'mmk', + 'mxn', + 'myr', + 'nok', + 'nzd', + 'php', + 'pkr', + 'pln', + 'rub', + 'sar', + 'sek', + 'sgd', + 'thb', + 'try', + 'twd', + 'vef', + 'vnd', + 'zar', + 'xdr', + 'xag', + 'xau', +]; From c9d7fc8ea9afd68f183e323028f6801e4156bb00 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 17:45:35 +0100 Subject: [PATCH 02/33] add redux support for setting local currency --- src/actions/LocalStorageActions.js | 14 ++++++++++++++ src/actions/WalletActions.js | 9 +++++++++ src/actions/constants/wallet.js | 1 + src/reducers/WalletReducer.js | 8 ++++++++ src/services/LocalStorageService.js | 4 ++++ 5 files changed, 36 insertions(+) diff --git a/src/actions/LocalStorageActions.js b/src/actions/LocalStorageActions.js index 6355c962..ad959790 100644 --- a/src/actions/LocalStorageActions.js +++ b/src/actions/LocalStorageActions.js @@ -57,6 +57,7 @@ const KEY_TOKENS: string = `${STORAGE_PATH}tokens`; const KEY_PENDING: string = `${STORAGE_PATH}pending`; const KEY_BETA_MODAL: string = '/betaModalPrivacy'; // this key needs to be compatible with "parent" (old) wallet const KEY_LANGUAGE: string = `${STORAGE_PATH}language`; +const KEY_LOCAL_CURRENCY: string = `${STORAGE_PATH}localCurrency`; // https://github.com/STRML/react-localstorage/blob/master/react-localstorage.js // or @@ -276,6 +277,11 @@ const loadStorageData = (): ThunkAction => (dispatch: Dispatch): void => { } else { dispatch(WalletActions.fetchLocale(l10nUtils.getInitialLocale())); } + + const localCurrency: ?string = storageUtils.get(TYPE, KEY_LOCAL_CURRENCY); + if (localCurrency) { + dispatch(WalletActions.setLocalCurrency(JSON.parse(localCurrency))); + } }; export const loadData = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { @@ -296,3 +302,11 @@ export const setLanguage = (): ThunkAction => (dispatch: Dispatch, getState: Get const { language } = getState().wallet; storageUtils.set(TYPE, KEY_LANGUAGE, JSON.stringify(language)); }; + +export const setLocalCurrency = (): ThunkAction => ( + dispatch: Dispatch, + getState: GetState +): void => { + const { localCurrency } = getState().wallet; + storageUtils.set(TYPE, KEY_LOCAL_CURRENCY, JSON.stringify(localCurrency)); +}; diff --git a/src/actions/WalletActions.js b/src/actions/WalletActions.js index 063f548e..14045e29 100644 --- a/src/actions/WalletActions.js +++ b/src/actions/WalletActions.js @@ -58,6 +58,10 @@ export type WalletAction = type: typeof WALLET.SET_LANGUAGE, locale: string, messages: { [string]: string }, + } + | { + type: typeof WALLET.SET_LOCAL_CURRENCY, + localCurrency: string, }; export const init = (): ThunkAction => (dispatch: Dispatch): void => { @@ -96,6 +100,11 @@ export const fetchLocale = (locale: string): ThunkAction => (dispatch: Dispatch) }); }; +export const setLocalCurrency = (localCurrency: string): WalletAction => ({ + type: WALLET.SET_LOCAL_CURRENCY, + localCurrency: localCurrency.toLowerCase(), +}); + // This method will be called after each DEVICE.CONNECT action // if connected device has different "passphrase_protection" settings than saved instances // all saved instances will be removed immediately inside DevicesReducer diff --git a/src/actions/constants/wallet.js b/src/actions/constants/wallet.js index d1d8bb0a..0ccff06d 100644 --- a/src/actions/constants/wallet.js +++ b/src/actions/constants/wallet.js @@ -17,3 +17,4 @@ export const CLEAR_UNAVAILABLE_DEVICE_DATA: 'wallet__clear_unavailable_device_da export const TOGGLE_SIDEBAR: 'wallet__toggle_sidebar' = 'wallet__toggle_sidebar'; export const SET_LANGUAGE: 'wallet__set_language' = 'wallet__set_language'; +export const SET_LOCAL_CURRENCY: 'wallet__set_local_currency' = 'wallet__set_local_currency'; diff --git a/src/reducers/WalletReducer.js b/src/reducers/WalletReducer.js index 7f2e9a22..aa92c230 100644 --- a/src/reducers/WalletReducer.js +++ b/src/reducers/WalletReducer.js @@ -13,6 +13,7 @@ type State = { ready: boolean, online: boolean, language: string, + localCurrency: string, messages: { [string]: string }, dropdownOpened: boolean, showBetaDisclaimer: boolean, @@ -28,6 +29,7 @@ const initialState: State = { ready: false, online: navigator.onLine, language: 'en', + localCurrency: 'usd', messages: {}, dropdownOpened: false, firstLocationChange: true, @@ -129,6 +131,12 @@ export default function wallet(state: State = initialState, action: Action): Sta messages: action.messages ? action.messages : state.messages, }; + case WALLET.SET_LOCAL_CURRENCY: + return { + ...state, + localCurrency: action.localCurrency, + }; + default: return state; } diff --git a/src/services/LocalStorageService.js b/src/services/LocalStorageService.js index 5a258ada..4f79cbe5 100644 --- a/src/services/LocalStorageService.js +++ b/src/services/LocalStorageService.js @@ -25,6 +25,10 @@ const LocalStorageService: Middleware = (api: MiddlewareAPI) => (next: Middlewar case WALLET.SET_LANGUAGE: api.dispatch(LocalStorageActions.setLanguage()); break; + + case WALLET.SET_LOCAL_CURRENCY: + api.dispatch(LocalStorageActions.setLocalCurrency()); + break; // first time saving case CONNECT.REMEMBER: api.dispatch(LocalStorageActions.save()); From f08e4683b1a055f8d48a25da602243f9cd513f79 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 17:52:21 +0100 Subject: [PATCH 03/33] add wallet settings page --- .../TopNavigationWalletSettings/index.js | 56 ++++++++ src/views/Wallet/index.js | 10 +- .../Wallet/views/WalletSettings/index.js | 120 ++++++++++++++---- .../views/WalletSettings/index.messages.js | 16 +++ src/views/common.messages.js | 8 ++ 5 files changed, 184 insertions(+), 26 deletions(-) create mode 100644 src/views/Wallet/components/TopNavigationWalletSettings/index.js create mode 100644 src/views/Wallet/views/WalletSettings/index.messages.js diff --git a/src/views/Wallet/components/TopNavigationWalletSettings/index.js b/src/views/Wallet/components/TopNavigationWalletSettings/index.js new file mode 100644 index 00000000..6d25a34b --- /dev/null +++ b/src/views/Wallet/components/TopNavigationWalletSettings/index.js @@ -0,0 +1,56 @@ +import styled from 'styled-components'; +import React from 'react'; +import { FONT_SIZE, FONT_WEIGHT } from 'config/variables'; +import { getPattern } from 'support/routes'; + +import { NavLink } from 'react-router-dom'; + +import colors from 'config/colors'; + +import { FormattedMessage } from 'react-intl'; +import l10nCommonMessages from 'views/common.messages'; + +const Wrapper = styled.div` + position: relative; + display: flex; + height: 100%; + flex: 1; + align-items: center; + padding: 0px 30px 0 35px; + overflow-y: hidden; + overflow-x: auto; +`; + +const StyledNavLink = styled(NavLink)` + font-weight: ${FONT_WEIGHT.MEDIUM}; + font-size: ${FONT_SIZE.TOP_MENU}; + color: ${colors.TEXT_SECONDARY}; + margin: 0px 4px; + padding: 20px 10px; + white-space: nowrap; + + &.active, + &:hover { + transition: all 0.3s ease-in-out; + color: ${colors.TEXT_PRIMARY}; + } + + &:first-child { + margin-left: 0px; + } + + &:last-child { + margin-right: 0px; + } +`; + +// TODO: make universal TopNavigation component +const TopNavigationWalletSettings = () => ( + + + + + +); + +export default TopNavigationWalletSettings; diff --git a/src/views/Wallet/index.js b/src/views/Wallet/index.js index 36ef5cc0..00a40178 100644 --- a/src/views/Wallet/index.js +++ b/src/views/Wallet/index.js @@ -5,6 +5,7 @@ import colors from 'config/colors'; import styled, { css } from 'styled-components'; import { connect } from 'react-redux'; import { Route, withRouter } from 'react-router-dom'; +import { getPattern } from 'support/routes'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; import type { State } from 'flowtype'; @@ -27,6 +28,7 @@ import Backdrop from 'components/Backdrop'; import LeftNavigation from './components/LeftNavigation/Container'; import TopNavigationAccount from './components/TopNavigationAccount'; import TopNavigationDeviceSettings from './components/TopNavigationDeviceSettings'; +import TopNavigationWalletSettings from './components/TopNavigationWalletSettings'; type StateProps = { wallet: $ElementType, @@ -132,13 +134,17 @@ const Wallet = (props: Props) => ( + diff --git a/src/views/Wallet/views/WalletSettings/index.js b/src/views/Wallet/views/WalletSettings/index.js index ba094339..c8e76aeb 100644 --- a/src/views/Wallet/views/WalletSettings/index.js +++ b/src/views/Wallet/views/WalletSettings/index.js @@ -1,47 +1,119 @@ +/* @flow */ import styled from 'styled-components'; import React from 'react'; import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { FormattedMessage, injectIntl } from 'react-intl'; -import colors from 'config/colors'; -import icons from 'config/icons'; +import * as WalletActions from 'actions/WalletActions'; +import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; +import type { State, Dispatch } from 'flowtype'; -import Content from 'views/Wallet/components/Content'; -import { H1 } from 'components/Heading'; -import Icon from 'components/Icon'; import Link from 'components/Link'; +import Content from 'views/Wallet/components/Content'; +import { Select } from 'components/Select'; import Button from 'components/Button'; -const Section = styled.section` +import colors from 'config/colors'; +import { FIAT_CURRENCIES } from 'config/app'; +import { FONT_SIZE } from 'config/variables'; +import l10nCommonMessages from 'views/common.messages'; +import l10nMessages from './index.messages'; + +const CurrencySelect = styled(Select)` + min-width: 77px; + /* max-width: 200px; */ +`; + +const CurrencyLabel = styled.div` + color: ${colors.TEXT_SECONDARY}; + padding-bottom: 10px; +`; + +const Section = styled.div` + margin-bottom: 20px; +`; + +const Actions = styled.div` display: flex; - flex-direction: column; `; -const Row = styled.div` +const Buttons = styled.div` display: flex; - flex-direction: column; - align-items: center; - padding: 50px 0; + justify-content: flex-end; `; -const StyledH1 = styled(H1)` - text-align: center; +const Info = styled.div` + flex: 1; + color: ${colors.TEXT_SECONDARY}; + font-size: ${FONT_SIZE.SMALL}; + align-self: center; `; -const WalletSettings = () => ( +const buildCurrencyOption = currency => { + return { value: currency, label: currency.toUpperCase() }; +}; + +const WalletSettings = (props: Props) => (
- - - Wallet settings is under construction + + + + props.setLocalCurrency(option.value)} + value={buildCurrencyOption(props.wallet.localCurrency)} + options={FIAT_CURRENCIES.map(c => buildCurrencyOption(c))} + /> +
+ + + + + - + - - + +
); -export default connect( - null, - null -)(WalletSettings); +type OwnProps = {}; + +type StateProps = { + wallet: $ElementType, + fiat: $ElementType, + localStorage: $ElementType, +}; + +type DispatchProps = { + setLocalCurrency: typeof WalletActions.setLocalCurrency, +}; + +export type Props = StateProps & DispatchProps; + +const mapStateToProps: MapStateToProps = ( + state: State +): StateProps => ({ + wallet: state.wallet, + fiat: state.fiat, + localStorage: state.localStorage, +}); + +const mapDispatchToProps: MapDispatchToProps = ( + dispatch: Dispatch +): DispatchProps => ({ + setLocalCurrency: bindActionCreators(WalletActions.setLocalCurrency, dispatch), +}); + +export default injectIntl( + connect( + mapStateToProps, + mapDispatchToProps + )(WalletSettings) +); diff --git a/src/views/Wallet/views/WalletSettings/index.messages.js b/src/views/Wallet/views/WalletSettings/index.messages.js new file mode 100644 index 00000000..abcc4d99 --- /dev/null +++ b/src/views/Wallet/views/WalletSettings/index.messages.js @@ -0,0 +1,16 @@ +/* @flow */ +import { defineMessages } from 'react-intl'; +import type { Messages } from 'flowtype/npm/react-intl'; + +const definedMessages: Messages = defineMessages({ + TR_LOCAL_CURRENCY: { + id: 'TR_LOCAL_CURRENCY', + defaultMessage: 'Local currency', + }, + TR_THE_CHANGES_ARE_SAVED: { + id: 'TR_THE_CHANGES_ARE_SAVED', + defaultMessage: 'The changes are saved automatically as they are made', + }, +}); + +export default definedMessages; diff --git a/src/views/common.messages.js b/src/views/common.messages.js index bb578fb9..f4ee59ba 100644 --- a/src/views/common.messages.js +++ b/src/views/common.messages.js @@ -7,6 +7,10 @@ const definedMessages: Messages = defineMessages({ id: 'TR_DEVICE_SETTINGS', defaultMessage: 'Device settings', }, + TR_APPLICATION_SETTINGS: { + id: 'TR_APPLICATION_SETTINGS', + defaultMessage: 'Application settings', + }, TR_ACCOUNT_HASH: { id: 'TR_ACCOUNT_HASH', defaultMessage: 'Account #{number}', @@ -62,6 +66,10 @@ const definedMessages: Messages = defineMessages({ id: 'TR_FORGET_DEVICE', defaultMessage: 'Forget device', }, + TR_CLOSE: { + id: 'TR_CLOSE', + defaultMessage: 'Close', + }, }); export default definedMessages; From 4616ebeadcd444113aa6027846dd14b6d7054d61 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 17:53:28 +0100 Subject: [PATCH 04/33] add utils for converting to/from fiat --- src/utils/fiatConverter.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/utils/fiatConverter.js diff --git a/src/utils/fiatConverter.js b/src/utils/fiatConverter.js new file mode 100644 index 00000000..3bd74a04 --- /dev/null +++ b/src/utils/fiatConverter.js @@ -0,0 +1,18 @@ +const toFiatCurrency = (amount, fiatCurrency, rates) => { + // calculate amount in local currency + const rate = rates[fiatCurrency]; + + let localAmount = parseFloat(amount) * rate; + localAmount = Number.isNaN(localAmount) ? '' : localAmount.toFixed(2); + return localAmount; +}; + +const fromFiatCurrency = (localAmount, fiatCurrency, rates, decimals) => { + const rate = rates[fiatCurrency]; + + let amount = parseFloat(localAmount) / rate; + amount = Number.isNaN(amount) ? '' : amount.toFixed(decimals); + return amount; +}; + +export { toFiatCurrency, fromFiatCurrency }; From d269f31af9ab6ec8a2269d6669bd8b1b3b1449e3 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 17:56:56 +0100 Subject: [PATCH 05/33] return rates for all currencies supported by goingecko --- src/reducers/FiatRateReducer.js | 8 +++++--- src/services/CoingeckoService.js | 10 ++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/reducers/FiatRateReducer.js b/src/reducers/FiatRateReducer.js index fbccf087..dfd94760 100644 --- a/src/reducers/FiatRateReducer.js +++ b/src/reducers/FiatRateReducer.js @@ -7,7 +7,7 @@ import type { FiatRateAction } from 'services/CoingeckoService'; export type Fiat = { +network: string, - value: string, + rates: { [string]: number }, }; export const initialState: Array = []; @@ -15,12 +15,14 @@ export const initialState: Array = []; const update = (state: Array, action: FiatRateAction): Array => { const affected = state.find(f => f.network === action.network); const otherRates = state.filter(d => d !== affected); - const { network, rate } = action; + const { network, rates } = action; + + Object.keys(rates).map(k => rates[k].toFixed(2)); return otherRates.concat([ { network, - value: rate.toFixed(2), + rates, }, ]); }; diff --git a/src/services/CoingeckoService.js b/src/services/CoingeckoService.js index c5e6d216..f39bd0a7 100644 --- a/src/services/CoingeckoService.js +++ b/src/services/CoingeckoService.js @@ -19,9 +19,15 @@ export const RATE_UPDATE: 'rate__update' = 'rate__update'; export type FiatRateAction = { type: typeof RATE_UPDATE, network: string, - rate: number, + rates: { [string]: number }, }; +// const getSupportedCurrencies = async () => { +// const url = 'https://api.coingecko.com/api/v3/simple/supported_vs_currencies'; +// const res = await httpRequest(url, 'json'); +// return res; +// }; + const loadRateAction = (): AsyncAction => async ( dispatch: Dispatch, getState: GetState @@ -41,7 +47,7 @@ const loadRateAction = (): AsyncAction => async ( dispatch({ type: RATE_UPDATE, network: response.symbol, - rate: response.market_data.current_price.usd, + rates: response.market_data.current_price, }); } }); From e54c1befb22b9375ed8153a0a017a677739797f2 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 17:57:30 +0100 Subject: [PATCH 06/33] show balance in local currency --- .../Account/Summary/components/Balance/index.js | 13 +++++++++---- .../Wallet/views/Account/Summary/ethereum/index.js | 7 ++++++- .../Summary/ripple/components/Balance/index.js | 13 +++++++++---- .../Wallet/views/Account/Summary/ripple/index.js | 1 + 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/views/Wallet/views/Account/Summary/components/Balance/index.js b/src/views/Wallet/views/Account/Summary/components/Balance/index.js index fc1e9233..4a3514bf 100644 --- a/src/views/Wallet/views/Account/Summary/components/Balance/index.js +++ b/src/views/Wallet/views/Account/Summary/components/Balance/index.js @@ -15,6 +15,7 @@ type Props = { network: Network, balance: string, fiat: $ElementType, + localCurrency: string, }; type State = { @@ -59,6 +60,7 @@ const FiatValue = styled.div` min-height: 25px; color: ${colors.TEXT_PRIMARY}; align-items: center; + text-transform: uppercase; `; const FiatValueRate = styled.div` @@ -69,6 +71,7 @@ const FiatValueRate = styled.div` display: flex; align-items: center; color: ${colors.TEXT_PRIMARY}; + text-transform: uppercase; `; const BalanceWrapper = styled.div` @@ -116,14 +119,14 @@ class AccountBalance extends PureComponent { } render() { - const { network } = this.props; + const { network, localCurrency } = this.props; const fiatRate = this.props.fiat.find(f => f.network === network.shortcut); let accountBalance = ''; let fiatRateValue = ''; let fiat = ''; if (fiatRate) { accountBalance = new BigNumber(this.props.balance); - fiatRateValue = new BigNumber(fiatRate.value).toFixed(2); + fiatRateValue = new BigNumber(fiatRate.rates[localCurrency]).toFixed(2); fiat = accountBalance.times(fiatRateValue).toFixed(2); } @@ -155,7 +158,9 @@ class AccountBalance extends PureComponent { - {fiatRate ? `$ ${fiat}` : 'N/A'} + + {fiatRate ? `${fiat} ${localCurrency}` : 'N/A'} + {!fiatRate && NoRatesTooltip} @@ -168,7 +173,7 @@ class AccountBalance extends PureComponent { - {fiatRate ? `$ ${fiatRateValue}` : 'N/A'} + {fiatRate ? `${fiatRateValue} ${localCurrency}` : 'N/A'} {!fiatRate && NoRatesTooltip} diff --git a/src/views/Wallet/views/Account/Summary/ethereum/index.js b/src/views/Wallet/views/Account/Summary/ethereum/index.js index 758c6bba..b4cbc08b 100644 --- a/src/views/Wallet/views/Account/Summary/ethereum/index.js +++ b/src/views/Wallet/views/Account/Summary/ethereum/index.js @@ -100,7 +100,12 @@ const AccountSummary = (props: Props) => { /> - +

diff --git a/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js b/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js index 5c1d9744..1a21ac0f 100644 --- a/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js +++ b/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js @@ -14,6 +14,7 @@ type Props = { balance: string, reserve: string, fiat: $ElementType, + localCurrency: string, }; type State = { @@ -58,6 +59,7 @@ const FiatValue = styled.div` min-height: 25px; color: ${colors.TEXT_PRIMARY}; align-items: center; + text-transform: uppercase; `; const FiatValueRate = styled.div` @@ -68,6 +70,7 @@ const FiatValueRate = styled.div` display: flex; color: ${colors.TEXT_PRIMARY}; align-items: center; + text-transform: uppercase; `; const BalanceWrapper = styled.div` @@ -115,14 +118,14 @@ class AccountBalance extends PureComponent { } render() { - const { network } = this.props; + const { network, localCurrency } = this.props; const fiatRate = this.props.fiat.find(f => f.network === network.shortcut); let accountBalance = ''; let fiatRateValue = ''; let fiat = ''; if (fiatRate) { accountBalance = new BigNumber(this.props.balance); - fiatRateValue = new BigNumber(fiatRate.value).toFixed(2); + fiatRateValue = new BigNumber(fiatRate.rates[localCurrency]).toFixed(2); fiat = accountBalance.times(fiatRateValue).toFixed(2); } @@ -152,7 +155,9 @@ class AccountBalance extends PureComponent { - {fiatRate ? `$ ${fiat}` : 'N/A'} + + {fiatRate ? `${fiat} ${localCurrency}` : 'N/A'} + {!fiatRate && NoRatesTooltip} @@ -172,7 +177,7 @@ class AccountBalance extends PureComponent { - {fiatRate ? `$ ${fiatRateValue}` : 'N/A'} + {fiatRate ? `${fiatRateValue} ${localCurrency}` : 'N/A'} {!fiatRate && NoRatesTooltip} diff --git a/src/views/Wallet/views/Account/Summary/ripple/index.js b/src/views/Wallet/views/Account/Summary/ripple/index.js index 4f014c97..7ff6b32b 100644 --- a/src/views/Wallet/views/Account/Summary/ripple/index.js +++ b/src/views/Wallet/views/Account/Summary/ripple/index.js @@ -85,6 +85,7 @@ const AccountSummary = (props: Props) => { balance={balance} reserve={reserve} fiat={props.fiat} + localCurrency={props.wallet.localCurrency} /> {TMP_SHOW_HISTORY && ( From f6dc375dd0a3b79085c79ef20220a7a59b71c859 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 18:37:19 +0100 Subject: [PATCH 07/33] use BigNumber --- src/utils/fiatConverter.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/utils/fiatConverter.js b/src/utils/fiatConverter.js index 3bd74a04..6d546ece 100644 --- a/src/utils/fiatConverter.js +++ b/src/utils/fiatConverter.js @@ -1,17 +1,19 @@ +import BigNumber from 'bignumber.js'; + const toFiatCurrency = (amount, fiatCurrency, rates) => { // calculate amount in local currency const rate = rates[fiatCurrency]; - let localAmount = parseFloat(amount) * rate; - localAmount = Number.isNaN(localAmount) ? '' : localAmount.toFixed(2); + let localAmount = BigNumber(amount).times(rate); + localAmount = localAmount.isNaN() ? '' : localAmount.toFixed(2); return localAmount; }; const fromFiatCurrency = (localAmount, fiatCurrency, rates, decimals) => { const rate = rates[fiatCurrency]; - let amount = parseFloat(localAmount) / rate; - amount = Number.isNaN(amount) ? '' : amount.toFixed(decimals); + let amount = BigNumber(localAmount).div(rate); + amount = amount.isNaN() ? '' : amount.toFixed(decimals); return amount; }; From 1b3a363fd69b8fd65d3f3d2752a78e70f6e4616c Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 18:39:27 +0100 Subject: [PATCH 08/33] show value in local currency in the left menu --- .../LeftNavigation/components/AccountMenu/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index 3df1c5ed..c576e61e 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -9,6 +9,7 @@ import * as stateUtils from 'reducers/utils'; import Tooltip from 'components/Tooltip'; import ICONS from 'config/icons'; import { FormattedMessage } from 'react-intl'; +import { toFiatCurrency } from 'utils/fiatConverter'; import { NavLink } from 'react-router-dom'; import { findDeviceAccounts } from 'reducers/AccountsReducer'; @@ -104,8 +105,6 @@ const AccountMenu = (props: Props) => { if (!selected || !network) return null; - const fiatRate = props.fiat.find(f => f.network === network.shortcut); - const deviceAccounts: Accounts = findDeviceAccounts(accounts, selected, location.state.network); const selectedAccounts = deviceAccounts.map((account, i) => { @@ -121,10 +120,13 @@ const AccountMenu = (props: Props) => { .toString(10); balance = `${availableBalance} ${network.symbol}`; - if (fiatRate) { - const accountBalance = new BigNumber(availableBalance); - const fiat = accountBalance.times(fiatRate.value).toFixed(2); - balance = `${availableBalance} ${network.symbol} / $${fiat}`; + const fiatRates = props.fiat.find(f => f.network === network.shortcut); + if (fiatRates) { + const { localCurrency } = props.wallet; + const fiat = toFiatCurrency(availableBalance, localCurrency, fiatRates.rates); + balance = `${availableBalance} ${ + network.symbol + } / ${localCurrency.toUpperCase()} ${fiat}`; } } From a44a0b608a02ec1deb9b5c6c31cb07d182ad2d71 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Mon, 11 Mar 2019 18:43:41 +0100 Subject: [PATCH 09/33] add currency switcher to eth send form --- src/actions/ethereum/SendFormActions.js | 75 +++++++++++++++- .../ethereum/SendFormValidationActions.js | 9 ++ src/reducers/SendFormEthereumReducer.js | 4 + .../views/Account/Send/ethereum/index.js | 85 ++++++++++++++++++- 4 files changed, 169 insertions(+), 4 deletions(-) diff --git a/src/actions/ethereum/SendFormActions.js b/src/actions/ethereum/SendFormActions.js index e48a13d0..652ea3fb 100644 --- a/src/actions/ethereum/SendFormActions.js +++ b/src/actions/ethereum/SendFormActions.js @@ -10,6 +10,7 @@ import * as WEB3 from 'actions/constants/web3'; import { initialState } from 'reducers/SendFormEthereumReducer'; import * as reducerUtils from 'reducers/utils'; import * as ethUtils from 'utils/ethUtils'; +import { toFiatCurrency, fromFiatCurrency } from 'utils/fiatConverter'; import type { Dispatch, @@ -150,6 +151,9 @@ export const init = (): AsyncAction => async ( initialState.selectedFeeLevel ); + // initial local currency is set according to wallet settings + const { localCurrency } = getState().wallet; + dispatch({ type: SEND.INIT, networkType: 'ethereum', @@ -158,6 +162,7 @@ export const init = (): AsyncAction => async ( networkName: network.shortcut, networkSymbol: network.symbol, currency: network.symbol, + localCurrency, feeLevels, selectedFeeLevel, recommendedGasPrice: gasPrice.toString(), @@ -241,7 +246,7 @@ export const onAddressChange = (address: string): ThunkAction => ( /* * Called from UI on "amount" field change */ -export const onAmountChange = (amount: string): ThunkAction => ( +export const onAmountChange = (amount: string, shouldUpdateLocalAmount = true): ThunkAction => ( dispatch: Dispatch, getState: GetState ): void => { @@ -257,6 +262,72 @@ export const onAmountChange = (amount: string): ThunkAction => ( amount, }, }); + + if (shouldUpdateLocalAmount) { + const { localCurrency } = getState().sendFormEthereum; + const fiatRates = getState().fiat.find(f => f.network === state.networkName); + const localAmount = toFiatCurrency(amount, localCurrency, fiatRates.rates); + dispatch(onLocalAmountChange(localAmount, false)); + } +}; + +/* + * Called from UI on "localAmount" field change + */ +export const onLocalAmountChange = ( + localAmount: string, + shouldUpdateAmount = true +): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state = getState().sendFormEthereum; + const { localCurrency } = getState().sendFormEthereum; + const fiatRates = getState().fiat.find(f => f.network === state.networkName); + const { network } = getState().selectedAccount; + + // updates localAmount + dispatch({ + type: SEND.CHANGE, + networkType: 'ethereum', + state: { + ...state, + untouched: false, + touched: { ...state.touched, localAmount: true }, + setMax: false, + localAmount, + }, + }); + + // updates amount + if (shouldUpdateAmount) { + if (!network) return; + // converts amount in local currency to crypto currency that will be sent + const amount = fromFiatCurrency( + localAmount, + localCurrency, + fiatRates.rates, + network.decimals + ); + dispatch(onAmountChange(amount, false)); + } +}; + +/* + * Called from UI on "localCurrency" selection change + */ +export const onLocalCurrencyChange = (localCurrency: { + value: string, + label: string, +}): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state = getState().sendFormEthereum; + dispatch({ + type: SEND.CHANGE, + networkType: 'ethereum', + state: { + ...state, + localCurrency: localCurrency.value, + }, + }); + // Recalculates amount with new currency rates + dispatch(onLocalAmountChange(state.localAmount)); }; /* @@ -756,7 +827,9 @@ export default { toggleAdvanced, onAddressChange, onAmountChange, + onLocalAmountChange, onCurrencyChange, + onLocalCurrencyChange, onSetMax, onFeeLevelChange, updateFeeLevels, diff --git a/src/actions/ethereum/SendFormValidationActions.js b/src/actions/ethereum/SendFormValidationActions.js index 4ff4a5f6..2be80b2e 100644 --- a/src/actions/ethereum/SendFormValidationActions.js +++ b/src/actions/ethereum/SendFormValidationActions.js @@ -4,6 +4,7 @@ import BigNumber from 'bignumber.js'; import EthereumjsUtil from 'ethereumjs-util'; import EthereumjsUnits from 'ethereumjs-units'; import { findDevice, getPendingAmount, findToken } from 'reducers/utils'; +import { toFiatCurrency } from 'utils/fiatConverter'; import * as SEND from 'actions/constants/send'; import * as ethUtils from 'utils/ethUtils'; @@ -130,6 +131,14 @@ export const recalculateTotalAmount = ($state: State): PayloadAction => ( } else { const b = new BigNumber(account.balance).minus(pendingAmount); state.amount = calculateMaxAmount(b, state.gasPrice, state.gasLimit); + + // calculate amount in local currency + const { localCurrency } = getState().sendFormEthereum; + const fiatRates = getState().fiat.find(f => f.network === state.networkName); + const localAmount = toFiatCurrency(state.amount, localCurrency, fiatRates.rates); + if (localAmount) { + state.localAmount = localAmount; + } } } diff --git a/src/reducers/SendFormEthereumReducer.js b/src/reducers/SendFormEthereumReducer.js index d2db7401..23234658 100644 --- a/src/reducers/SendFormEthereumReducer.js +++ b/src/reducers/SendFormEthereumReducer.js @@ -17,11 +17,13 @@ export type State = { currency: string, // form fields + localCurrency: string, advanced: boolean, untouched: boolean, // set to true when user made any changes in form touched: { [k: string]: boolean }, address: string, amount: string, + localAmount: string, setMax: boolean, feeLevels: Array, selectedFeeLevel: FeeLevel, @@ -45,6 +47,7 @@ export const initialState: State = { networkName: '', networkSymbol: '', currency: '', + localCurrency: '', advanced: false, untouched: true, @@ -52,6 +55,7 @@ export const initialState: State = { address: '', //address: '0x574BbB36871bA6b78E27f4B4dCFb76eA0091880B', amount: '', + localAmount: '', setMax: false, feeLevels: [], selectedFeeLevel: { diff --git a/src/views/Wallet/views/Account/Send/ethereum/index.js b/src/views/Wallet/views/Account/Send/ethereum/index.js index 161801c0..9b344739 100644 --- a/src/views/Wallet/views/Account/Send/ethereum/index.js +++ b/src/views/Wallet/views/Account/Send/ethereum/index.js @@ -9,7 +9,8 @@ import Input from 'components/inputs/Input'; import Icon from 'components/Icon'; import Link from 'components/Link'; import ICONS from 'config/icons'; -import { FONT_SIZE, FONT_WEIGHT, TRANSITION } from 'config/variables'; +import { FONT_SIZE, FONT_WEIGHT, TRANSITION, SCREEN_SIZE } from 'config/variables'; +import { FIAT_CURRENCIES } from 'config/app'; import colors from 'config/colors'; import Title from 'views/Wallet/components/Title'; import P from 'components/Paragraph'; @@ -43,6 +44,44 @@ const InputRow = styled.div` padding-bottom: 28px; `; +const LocalAmountWrapper = styled.div` + display: flex; + align-self: flex-start; + margin-top: 26px; + + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + flex: 1 0 100%; + justify-content: flex-end; + margin-top: 0px; + padding-top: 28px; + } +`; + +const AmountRow = styled(InputRow)` + display: flex; + align-items: flex-end; + padding-bottom: 28px; + + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + flex-wrap: wrap; + } +`; + +const LocalAmountInput = styled(Input)` + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + flex: 1 1 100%; + } +`; + +const LocalCurrencySelect = styled(Select)` + min-width: 77px; + height: 40px; + + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + flex: 1 1 0; + } +`; + const SetMaxAmountButton = styled(Button)` height: 40px; padding: 0 10px; @@ -187,6 +226,16 @@ const QrButton = styled(Button)` padding: 0 10px; `; +const EqualsSign = styled.div` + align-self: center; + padding: 0 10px; + font-size: ${FONT_SIZE.BIGGER}; + + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + display: none; + } +`; + // render helpers const getAddressInputState = ( address: string, @@ -230,6 +279,10 @@ const getTokensSelectData = ( return tokensSelectData; }; +const buildCurrencyOption = currency => { + return { value: currency, label: currency.toUpperCase() }; +}; + // stateless component const AccountSend = (props: Props) => { const device = props.wallet.selectedDevice; @@ -237,9 +290,11 @@ const AccountSend = (props: Props) => { const { address, amount, + localAmount, setMax, networkSymbol, currency, + localCurrency, feeLevels, selectedFeeLevel, gasPriceNeedsUpdate, @@ -255,8 +310,10 @@ const AccountSend = (props: Props) => { toggleAdvanced, onAddressChange, onAmountChange, + onLocalAmountChange, onSetMax, onCurrencyChange, + onLocalCurrencyChange, onFeeLevelChange, updateFeeLevels, onSend, @@ -337,7 +394,7 @@ const AccountSend = (props: Props) => { ]} /> - + { />, ]} /> - + + = + onLocalAmountChange(event.target.value)} + sideAddons={[ + onLocalCurrencyChange(option)} + value={buildCurrencyOption(localCurrency)} + options={FIAT_CURRENCIES.map(c => buildCurrencyOption(c))} + />, + ]} + /> + + From f35492ae6ce9096e0dab7fae35b368290d3a09a7 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 11:37:04 +0100 Subject: [PATCH 10/33] react intl suppor for account balance --- .../Summary/components/Balance/index.js | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/views/Wallet/views/Account/Summary/components/Balance/index.js b/src/views/Wallet/views/Account/Summary/components/Balance/index.js index 4a3514bf..d830616b 100644 --- a/src/views/Wallet/views/Account/Summary/components/Balance/index.js +++ b/src/views/Wallet/views/Account/Summary/components/Balance/index.js @@ -1,12 +1,13 @@ /* @flow */ import React, { PureComponent } from 'react'; -import { FormattedMessage } from 'react-intl'; +import { FormattedMessage, FormattedNumber } from 'react-intl'; import BigNumber from 'bignumber.js'; import styled from 'styled-components'; import Icon from 'components/Icon'; import colors from 'config/colors'; import ICONS from 'config/icons'; import Tooltip from 'components/Tooltip'; +import { toFiatCurrency } from 'utils/fiatConverter'; import { FONT_SIZE, FONT_WEIGHT } from 'config/variables'; import type { Network, State as ReducersState } from 'flowtype'; import l10nMessages from './index.messages'; @@ -121,13 +122,11 @@ class AccountBalance extends PureComponent { render() { const { network, localCurrency } = this.props; const fiatRate = this.props.fiat.find(f => f.network === network.shortcut); - let accountBalance = ''; let fiatRateValue = ''; let fiat = ''; if (fiatRate) { - accountBalance = new BigNumber(this.props.balance); fiatRateValue = new BigNumber(fiatRate.rates[localCurrency]).toFixed(2); - fiat = accountBalance.times(fiatRateValue).toFixed(2); + fiat = toFiatCurrency(this.props.balance, localCurrency, fiatRate.rates); } const NoRatesTooltip = ( @@ -159,7 +158,17 @@ class AccountBalance extends PureComponent { - {fiatRate ? `${fiat} ${localCurrency}` : 'N/A'} + {fiatRate ? ( + + ) : ( + 'N/A' + )} {!fiatRate && NoRatesTooltip} @@ -173,7 +182,17 @@ class AccountBalance extends PureComponent { - {fiatRate ? `${fiatRateValue} ${localCurrency}` : 'N/A'} + {fiatRate ? ( + + ) : ( + 'N/A' + )} {!fiatRate && NoRatesTooltip} From 3e4e671277944019477eaa6bd570b6fd05903a69 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 11:47:14 +0100 Subject: [PATCH 11/33] react intl support for balance in account menu --- .../components/AccountMenu/index.js | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index c576e61e..9d4dac40 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -8,7 +8,7 @@ import styled, { css } from 'styled-components'; import * as stateUtils from 'reducers/utils'; import Tooltip from 'components/Tooltip'; import ICONS from 'config/icons'; -import { FormattedMessage } from 'react-intl'; +import { FormattedMessage, FormattedNumber } from 'react-intl'; import { toFiatCurrency } from 'utils/fiatConverter'; import { NavLink } from 'react-router-dom'; @@ -112,6 +112,9 @@ const AccountMenu = (props: Props) => { const url: string = location.pathname.replace(/account+\/([0-9]*)/, `account/${i}`); let balance: ?string = null; + const fiatRates = props.fiat.find(f => f.network === network.shortcut); + const { localCurrency } = props.wallet; + let fiat = ''; if (account.balance !== '') { const pending = stateUtils.getAccountPendingTx(props.pending, account); const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol); @@ -120,13 +123,9 @@ const AccountMenu = (props: Props) => { .toString(10); balance = `${availableBalance} ${network.symbol}`; - const fiatRates = props.fiat.find(f => f.network === network.shortcut); if (fiatRates) { - const { localCurrency } = props.wallet; - const fiat = toFiatCurrency(availableBalance, localCurrency, fiatRates.rates); - balance = `${availableBalance} ${ - network.symbol - } / ${localCurrency.toUpperCase()} ${fiat}`; + fiat = toFiatCurrency(availableBalance, localCurrency, fiatRates.rates); + balance = `${availableBalance} ${network.symbol} / `; } } @@ -142,7 +141,20 @@ const AccountMenu = (props: Props) => { {...l10nCommonMessages.TR_ACCOUNT_HASH} values={{ number: account.index + 1 }} /> - {balance && {balance}} + {balance && ( + + {balance} + {fiatRates && ( + + )} + + )} {!balance && ( From a0d9383621b9627ae57c2b0bb15eae2d583e3dc8 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 12:22:59 +0100 Subject: [PATCH 12/33] move LANGUAGE variable to config/app.js --- .../Header/components/LanguagePicker/index.js | 3 ++- src/config/app.js | 20 +++++++++++++++++++ src/config/variables.js | 20 ------------------- src/utils/l10n.js | 2 +- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/components/Header/components/LanguagePicker/index.js b/src/components/Header/components/LanguagePicker/index.js index adf84626..8947373c 100644 --- a/src/components/Header/components/LanguagePicker/index.js +++ b/src/components/Header/components/LanguagePicker/index.js @@ -3,7 +3,8 @@ import * as React from 'react'; import styled from 'styled-components'; import colors from 'config/colors'; import ReactSelect from 'react-select'; -import { LANGUAGE, SCREEN_SIZE } from 'config/variables'; +import { SCREEN_SIZE } from 'config/variables'; +import { LANGUAGE } from 'config/app'; import type { Props } from './Container'; diff --git a/src/config/app.js b/src/config/app.js index c9778da3..b533b8f4 100644 --- a/src/config/app.js +++ b/src/config/app.js @@ -1,3 +1,23 @@ +export const LANGUAGE = [ + { code: 'en', name: 'English', en: 'English' }, + { code: 'bn', name: 'Bengali', en: 'Bengali' }, + { code: 'cs', name: 'Česky', en: 'Czech' }, + { code: 'de', name: 'Deutsch', en: 'German' }, + { code: 'el', name: 'Ελληνικά', en: 'Greek' }, + { code: 'es', name: 'Español', en: 'Spanish' }, + { code: 'fr', name: 'Français', en: 'French' }, + { code: 'id', name: 'Bahasa Indonesia', en: 'Indonesian' }, + { code: 'it', name: 'Italiano', en: 'Italian' }, + { code: 'ja', name: '日本語', en: 'Japanese' }, + { code: 'nl', name: 'Nederlands', en: 'Dutch' }, + { code: 'pl', name: 'Polski', en: 'Polish' }, + { code: 'pt', name: 'Português', en: 'Portuguese' }, + { code: 'ru', name: 'Русский', en: 'Russian' }, + { code: 'uk', name: 'Український', en: 'Ukrainian' }, + { code: 'zh', name: '中文(简体)', en: 'Chinese Simplified' }, + { code: 'zh_TW', name: '中文(台灣)', en: 'Chinese Traditional' }, +]; + export const FIAT_CURRENCIES = [ 'usd', 'aed', diff --git a/src/config/variables.js b/src/config/variables.js index b657e62d..3a681bf4 100644 --- a/src/config/variables.js +++ b/src/config/variables.js @@ -81,23 +81,3 @@ export const LINE_HEIGHT = { BASE: '1.8', TREZOR_ACTION: '37px', }; - -export const LANGUAGE = [ - { code: 'en', name: 'English', en: 'English' }, - { code: 'bn', name: 'Bengali', en: 'Bengali' }, - { code: 'cs', name: 'Česky', en: 'Czech' }, - { code: 'de', name: 'Deutsch', en: 'German' }, - { code: 'el', name: 'Ελληνικά', en: 'Greek' }, - { code: 'es', name: 'Español', en: 'Spanish' }, - { code: 'fr', name: 'Français', en: 'French' }, - { code: 'id', name: 'Bahasa Indonesia', en: 'Indonesian' }, - { code: 'it', name: 'Italiano', en: 'Italian' }, - { code: 'ja', name: '日本語', en: 'Japanese' }, - { code: 'nl', name: 'Nederlands', en: 'Dutch' }, - { code: 'pl', name: 'Polski', en: 'Polish' }, - { code: 'pt', name: 'Português', en: 'Portuguese' }, - { code: 'ru', name: 'Русский', en: 'Russian' }, - { code: 'uk', name: 'Український', en: 'Ukrainian' }, - { code: 'zh', name: '中文(简体)', en: 'Chinese Simplified' }, - { code: 'zh_TW', name: '中文(台灣)', en: 'Chinese Traditional' }, -]; diff --git a/src/utils/l10n.js b/src/utils/l10n.js index 8ced69f6..11170d0f 100644 --- a/src/utils/l10n.js +++ b/src/utils/l10n.js @@ -1,4 +1,4 @@ -import { LANGUAGE } from 'config/variables'; +import { LANGUAGE } from 'config/app'; export const getInitialLocale = (defaultLocale = 'en') => { const browserLocale = navigator.language.split('-')[0]; From b722b8d86ac33c7c809e8270e7bb44c78a4ba6c6 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 12:55:21 +0100 Subject: [PATCH 13/33] handle missing rates in util function --- src/actions/ethereum/SendFormActions.js | 19 ++++++---------- .../ethereum/SendFormValidationActions.js | 2 +- src/utils/fiatConverter.js | 22 +++++++++++++++---- .../components/AccountMenu/index.js | 2 +- .../Summary/components/Balance/index.js | 16 +++++++------- .../ripple/components/Balance/index.js | 14 ++++++------ 6 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/actions/ethereum/SendFormActions.js b/src/actions/ethereum/SendFormActions.js index 652ea3fb..c3fe2119 100644 --- a/src/actions/ethereum/SendFormActions.js +++ b/src/actions/ethereum/SendFormActions.js @@ -246,10 +246,10 @@ export const onAddressChange = (address: string): ThunkAction => ( /* * Called from UI on "amount" field change */ -export const onAmountChange = (amount: string, shouldUpdateLocalAmount = true): ThunkAction => ( - dispatch: Dispatch, - getState: GetState -): void => { +export const onAmountChange = ( + amount: string, + shouldUpdateLocalAmount: boolean = true +): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { const state = getState().sendFormEthereum; dispatch({ type: SEND.CHANGE, @@ -266,7 +266,7 @@ export const onAmountChange = (amount: string, shouldUpdateLocalAmount = true): if (shouldUpdateLocalAmount) { const { localCurrency } = getState().sendFormEthereum; const fiatRates = getState().fiat.find(f => f.network === state.networkName); - const localAmount = toFiatCurrency(amount, localCurrency, fiatRates.rates); + const localAmount = toFiatCurrency(amount, localCurrency, fiatRates); dispatch(onLocalAmountChange(localAmount, false)); } }; @@ -276,7 +276,7 @@ export const onAmountChange = (amount: string, shouldUpdateLocalAmount = true): */ export const onLocalAmountChange = ( localAmount: string, - shouldUpdateAmount = true + shouldUpdateAmount: boolean = true ): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { const state = getState().sendFormEthereum; const { localCurrency } = getState().sendFormEthereum; @@ -300,12 +300,7 @@ export const onLocalAmountChange = ( if (shouldUpdateAmount) { if (!network) return; // converts amount in local currency to crypto currency that will be sent - const amount = fromFiatCurrency( - localAmount, - localCurrency, - fiatRates.rates, - network.decimals - ); + const amount = fromFiatCurrency(localAmount, localCurrency, fiatRates, network.decimals); dispatch(onAmountChange(amount, false)); } }; diff --git a/src/actions/ethereum/SendFormValidationActions.js b/src/actions/ethereum/SendFormValidationActions.js index 2be80b2e..6c22a7a1 100644 --- a/src/actions/ethereum/SendFormValidationActions.js +++ b/src/actions/ethereum/SendFormValidationActions.js @@ -135,7 +135,7 @@ export const recalculateTotalAmount = ($state: State): PayloadAction => ( // calculate amount in local currency const { localCurrency } = getState().sendFormEthereum; const fiatRates = getState().fiat.find(f => f.network === state.networkName); - const localAmount = toFiatCurrency(state.amount, localCurrency, fiatRates.rates); + const localAmount = toFiatCurrency(state.amount, localCurrency, fiatRates); if (localAmount) { state.localAmount = localAmount; } diff --git a/src/utils/fiatConverter.js b/src/utils/fiatConverter.js index 6d546ece..756a086d 100644 --- a/src/utils/fiatConverter.js +++ b/src/utils/fiatConverter.js @@ -1,16 +1,30 @@ import BigNumber from 'bignumber.js'; -const toFiatCurrency = (amount, fiatCurrency, rates) => { +const toFiatCurrency = (amount, fiatCurrency, networkRates) => { // calculate amount in local currency - const rate = rates[fiatCurrency]; + if (!networkRates || !networkRates.rates) { + return ''; + } + + const rate = networkRates.rates[fiatCurrency]; + if (!rate) { + return ''; + } let localAmount = BigNumber(amount).times(rate); localAmount = localAmount.isNaN() ? '' : localAmount.toFixed(2); return localAmount; }; -const fromFiatCurrency = (localAmount, fiatCurrency, rates, decimals) => { - const rate = rates[fiatCurrency]; +const fromFiatCurrency = (localAmount, fiatCurrency, networkRates, decimals) => { + if (!networkRates || !networkRates.rates) { + return ''; + } + + const rate = networkRates.rates[fiatCurrency]; + if (!rate) { + return ''; + } let amount = BigNumber(localAmount).div(rate); amount = amount.isNaN() ? '' : amount.toFixed(decimals); diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index 9d4dac40..4ebb7cb7 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -124,7 +124,7 @@ const AccountMenu = (props: Props) => { balance = `${availableBalance} ${network.symbol}`; if (fiatRates) { - fiat = toFiatCurrency(availableBalance, localCurrency, fiatRates.rates); + fiat = toFiatCurrency(availableBalance, localCurrency, fiatRates); balance = `${availableBalance} ${network.symbol} / `; } } diff --git a/src/views/Wallet/views/Account/Summary/components/Balance/index.js b/src/views/Wallet/views/Account/Summary/components/Balance/index.js index d830616b..86268a57 100644 --- a/src/views/Wallet/views/Account/Summary/components/Balance/index.js +++ b/src/views/Wallet/views/Account/Summary/components/Balance/index.js @@ -121,12 +121,12 @@ class AccountBalance extends PureComponent { render() { const { network, localCurrency } = this.props; - const fiatRate = this.props.fiat.find(f => f.network === network.shortcut); + const fiatRates = this.props.fiat.find(f => f.network === network.shortcut); let fiatRateValue = ''; let fiat = ''; - if (fiatRate) { - fiatRateValue = new BigNumber(fiatRate.rates[localCurrency]).toFixed(2); - fiat = toFiatCurrency(this.props.balance, localCurrency, fiatRate.rates); + if (fiatRates) { + fiatRateValue = new BigNumber(fiatRates.rates[localCurrency]).toFixed(2); + fiat = toFiatCurrency(this.props.balance, localCurrency, fiatRates); } const NoRatesTooltip = ( @@ -158,7 +158,7 @@ class AccountBalance extends PureComponent { - {fiatRate ? ( + {fiatRates ? ( { 'N/A' )} - {!fiatRate && NoRatesTooltip} + {!fiatRates && NoRatesTooltip} {this.props.balance} {network.symbol} @@ -182,7 +182,7 @@ class AccountBalance extends PureComponent { - {fiatRate ? ( + {fiatRates ? ( { 'N/A' )} - {!fiatRate && NoRatesTooltip} + {!fiatRates && NoRatesTooltip} 1 {network.symbol} diff --git a/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js b/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js index 1a21ac0f..3f999aa8 100644 --- a/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js +++ b/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js @@ -119,13 +119,13 @@ class AccountBalance extends PureComponent { render() { const { network, localCurrency } = this.props; - const fiatRate = this.props.fiat.find(f => f.network === network.shortcut); + const fiatRates = this.props.fiat.find(f => f.network === network.shortcut); let accountBalance = ''; let fiatRateValue = ''; let fiat = ''; - if (fiatRate) { + if (fiatRates) { accountBalance = new BigNumber(this.props.balance); - fiatRateValue = new BigNumber(fiatRate.rates[localCurrency]).toFixed(2); + fiatRateValue = new BigNumber(fiatRates.rates[localCurrency]).toFixed(2); fiat = accountBalance.times(fiatRateValue).toFixed(2); } @@ -156,9 +156,9 @@ class AccountBalance extends PureComponent { - {fiatRate ? `${fiat} ${localCurrency}` : 'N/A'} + {fiatRates ? `${fiat} ${localCurrency}` : 'N/A'} - {!fiatRate && NoRatesTooltip} + {!fiatRates && NoRatesTooltip} {this.props.balance} {network.symbol} @@ -177,9 +177,9 @@ class AccountBalance extends PureComponent { - {fiatRate ? `${fiatRateValue} ${localCurrency}` : 'N/A'} + {fiatRates ? `${fiatRateValue} ${localCurrency}` : 'N/A'} - {!fiatRate && NoRatesTooltip} + {!fiatRates && NoRatesTooltip} 1 {network.symbol} From 93bea9d1955ce250768021671647ea3c4a0c146b Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 13:55:13 +0100 Subject: [PATCH 14/33] convert comma to dot as a decimal separator --- src/utils/fiatConverter.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/utils/fiatConverter.js b/src/utils/fiatConverter.js index 756a086d..2119444c 100644 --- a/src/utils/fiatConverter.js +++ b/src/utils/fiatConverter.js @@ -2,7 +2,7 @@ import BigNumber from 'bignumber.js'; const toFiatCurrency = (amount, fiatCurrency, networkRates) => { // calculate amount in local currency - if (!networkRates || !networkRates.rates) { + if (!networkRates || !networkRates.rates || !amount) { return ''; } @@ -11,13 +11,15 @@ const toFiatCurrency = (amount, fiatCurrency, networkRates) => { return ''; } - let localAmount = BigNumber(amount).times(rate); + const formattedAmount = amount.replace(',', '.'); + + let localAmount = BigNumber(formattedAmount).times(rate); localAmount = localAmount.isNaN() ? '' : localAmount.toFixed(2); return localAmount; }; const fromFiatCurrency = (localAmount, fiatCurrency, networkRates, decimals) => { - if (!networkRates || !networkRates.rates) { + if (!networkRates || !networkRates.rates || !localAmount) { return ''; } @@ -26,7 +28,9 @@ const fromFiatCurrency = (localAmount, fiatCurrency, networkRates, decimals) => return ''; } - let amount = BigNumber(localAmount).div(rate); + const formattedLocalAmount = localAmount.replace(',', '.'); + + let amount = BigNumber(formattedLocalAmount).div(rate); amount = amount.isNaN() ? '' : amount.toFixed(decimals); return amount; }; From 40f61002b692159219ba8bf41b6c217a5c30576c Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 16:03:14 +0100 Subject: [PATCH 15/33] add currency switcher to ripple send tab --- src/actions/ripple/SendFormActions.js | 80 +++++++++++++++++- .../ripple/SendFormValidationActions.js | 7 ++ src/reducers/SendFormRippleReducer.js | 4 + .../Wallet/views/Account/Send/ripple/index.js | 84 ++++++++++++++++++- 4 files changed, 168 insertions(+), 7 deletions(-) diff --git a/src/actions/ripple/SendFormActions.js b/src/actions/ripple/SendFormActions.js index ffe9d54c..f7efceaa 100644 --- a/src/actions/ripple/SendFormActions.js +++ b/src/actions/ripple/SendFormActions.js @@ -6,6 +6,7 @@ import * as BLOCKCHAIN from 'actions/constants/blockchain'; import { initialState } from 'reducers/SendFormRippleReducer'; import * as reducerUtils from 'reducers/utils'; import { fromDecimalAmount } from 'utils/formatUtils'; +import { toFiatCurrency, fromFiatCurrency } from 'utils/fiatConverter'; import type { Dispatch, @@ -109,6 +110,9 @@ export const init = (): AsyncAction => async ( initialState.selectedFeeLevel ); + // initial local currency is set according to wallet settings + const { localCurrency } = getState().wallet; + dispatch({ type: SEND.INIT, networkType: 'ripple', @@ -116,6 +120,7 @@ export const init = (): AsyncAction => async ( ...initialState, networkName: network.shortcut, networkSymbol: network.symbol, + localCurrency, feeLevels, selectedFeeLevel, fee: network.fee.defaultFee, @@ -154,6 +159,9 @@ export const onClear = (): AsyncAction => async ( initialState.selectedFeeLevel ); + // initial local currency is set according to wallet settings + const { localCurrency } = getState().wallet; + dispatch({ type: SEND.CLEAR, networkType: 'ripple', @@ -161,6 +169,7 @@ export const onClear = (): AsyncAction => async ( ...initialState, networkName: network.shortcut, networkSymbol: network.symbol, + localCurrency, feeLevels, selectedFeeLevel, fee: network.fee.defaultFee, @@ -193,10 +202,10 @@ export const onAddressChange = (address: string): ThunkAction => ( /* * Called from UI on "amount" field change */ -export const onAmountChange = (amount: string): ThunkAction => ( - dispatch: Dispatch, - getState: GetState -): void => { +export const onAmountChange = ( + amount: string, + shouldUpdateLocalAmount: boolean = true +): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { const state = getState().sendFormRipple; dispatch({ type: SEND.CHANGE, @@ -209,6 +218,67 @@ export const onAmountChange = (amount: string): ThunkAction => ( amount, }, }); + + if (shouldUpdateLocalAmount) { + const { localCurrency } = getState().sendFormRipple; + const fiatRates = getState().fiat.find(f => f.network === state.networkName); + const localAmount = toFiatCurrency(amount, localCurrency, fiatRates); + dispatch(onLocalAmountChange(localAmount, false)); + } +}; + +/* + * Called from UI on "localAmount" field change + */ +export const onLocalAmountChange = ( + localAmount: string, + shouldUpdateAmount: boolean = true +): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state = getState().sendFormRipple; + const { localCurrency } = getState().sendFormRipple; + const fiatRates = getState().fiat.find(f => f.network === state.networkName); + const { network } = getState().selectedAccount; + + // updates localAmount + dispatch({ + type: SEND.CHANGE, + networkType: 'ripple', + state: { + ...state, + untouched: false, + touched: { ...state.touched, localAmount: true }, + setMax: false, + localAmount, + }, + }); + + // updates amount + if (shouldUpdateAmount) { + if (!network) return; + // converts amount in local currency to crypto currency that will be sent + const amount = fromFiatCurrency(localAmount, localCurrency, fiatRates, network.decimals); + dispatch(onAmountChange(amount, false)); + } +}; + +/* + * Called from UI on "localCurrency" selection change + */ +export const onLocalCurrencyChange = (localCurrency: { + value: string, + label: string, +}): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + const state = getState().sendFormRipple; + dispatch({ + type: SEND.CHANGE, + networkType: 'ripple', + state: { + ...state, + localCurrency: localCurrency.value, + }, + }); + // Recalculates amount with new currency rates + dispatch(onLocalAmountChange(state.localAmount)); }; /* @@ -434,6 +504,8 @@ export default { toggleAdvanced, onAddressChange, onAmountChange, + onLocalAmountChange, + onLocalCurrencyChange, onSetMax, onFeeLevelChange, updateFeeLevels, diff --git a/src/actions/ripple/SendFormValidationActions.js b/src/actions/ripple/SendFormValidationActions.js index 4b2055ff..b8a8911a 100644 --- a/src/actions/ripple/SendFormValidationActions.js +++ b/src/actions/ripple/SendFormValidationActions.js @@ -4,6 +4,7 @@ import BigNumber from 'bignumber.js'; import * as SEND from 'actions/constants/send'; import { findDevice, getPendingAmount } from 'reducers/utils'; import { toDecimalAmount } from 'utils/formatUtils'; +import { toFiatCurrency } from 'utils/fiatConverter'; import type { Dispatch, @@ -103,6 +104,12 @@ const recalculateTotalAmount = ($state: State): PayloadAction => ( .minus(account.reserve) .minus(pendingAmount); state.amount = calculateMaxAmount(availableBalance, fee); + + // calculate amount in local currency + const { localCurrency } = getState().sendFormRipple; + const fiatRates = getState().fiat.find(f => f.network === state.networkName); + const localAmount = toFiatCurrency(state.amount, localCurrency, fiatRates); + state.localAmount = localAmount; } state.total = calculateTotal(state.amount, fee); diff --git a/src/reducers/SendFormRippleReducer.js b/src/reducers/SendFormRippleReducer.js index b800218f..9b38445a 100644 --- a/src/reducers/SendFormRippleReducer.js +++ b/src/reducers/SendFormRippleReducer.js @@ -16,11 +16,13 @@ export type State = { +networkSymbol: string, // form fields + localCurrency: string, advanced: boolean, untouched: boolean, // set to true when user made any changes in form touched: { [k: string]: boolean }, address: string, amount: string, + localAmount: string, minAmount: string, setMax: boolean, feeLevels: Array, @@ -41,12 +43,14 @@ export type State = { export const initialState: State = { networkName: '', networkSymbol: '', + localCurrency: '', advanced: false, untouched: true, touched: {}, address: '', amount: '', + localAmount: '', minAmount: '0', setMax: false, feeLevels: [], diff --git a/src/views/Wallet/views/Account/Send/ripple/index.js b/src/views/Wallet/views/Account/Send/ripple/index.js index 761747f0..922c1b3e 100644 --- a/src/views/Wallet/views/Account/Send/ripple/index.js +++ b/src/views/Wallet/views/Account/Send/ripple/index.js @@ -9,7 +9,8 @@ import Input from 'components/inputs/Input'; import Icon from 'components/Icon'; import Link from 'components/Link'; import ICONS from 'config/icons'; -import { FONT_SIZE, FONT_WEIGHT, TRANSITION } from 'config/variables'; +import { FONT_SIZE, FONT_WEIGHT, TRANSITION, SCREEN_SIZE } from 'config/variables'; +import { FIAT_CURRENCIES } from 'config/app'; import colors from 'config/colors'; import Title from 'views/Wallet/components/Title'; import P from 'components/Paragraph'; @@ -185,6 +186,53 @@ const QrButton = styled(Button)` padding: 0 10px; `; +const LocalAmountWrapper = styled.div` + display: flex; + align-self: flex-start; + margin-top: 26px; + + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + flex: 1 0 100%; + justify-content: flex-end; + margin-top: 0px; + padding-top: 28px; + } +`; + +const AmountRow = styled(InputRow)` + display: flex; + align-items: flex-end; + padding-bottom: 28px; + + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + flex-wrap: wrap; + } +`; + +const LocalAmountInput = styled(Input)` + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + flex: 1 1 100%; + } +`; + +const LocalCurrencySelect = styled(Select)` + min-width: 77px; + height: 40px; + + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + flex: 1 1 0; + } +`; + +const EqualsSign = styled.div` + align-self: center; + padding: 0 10px; + font-size: ${FONT_SIZE.BIGGER}; + + @media screen and (max-width: ${SCREEN_SIZE.MD}) { + display: none; + } +`; // render helpers const getAddressInputState = ( address: string, @@ -215,6 +263,10 @@ const getAmountInputState = (amountErrors: string, amountWarnings: string): stri return state; }; +const buildCurrencyOption = currency => { + return { value: currency, label: currency.toUpperCase() }; +}; + // stateless component const AccountSend = (props: Props) => { const device = props.wallet.selectedDevice; @@ -222,6 +274,8 @@ const AccountSend = (props: Props) => { const { address, amount, + localAmount, + localCurrency, setMax, feeLevels, selectedFeeLevel, @@ -238,6 +292,8 @@ const AccountSend = (props: Props) => { toggleAdvanced, onAddressChange, onAmountChange, + onLocalAmountChange, + onLocalCurrencyChange, onSetMax, onFeeLevelChange, updateFeeLevels, @@ -307,7 +363,7 @@ const AccountSend = (props: Props) => { ]} /> - + { />, ]} /> - + + = + onLocalAmountChange(event.target.value)} + sideAddons={[ + onLocalCurrencyChange(option)} + value={buildCurrencyOption(localCurrency)} + options={FIAT_CURRENCIES.map(c => buildCurrencyOption(c))} + />, + ]} + /> + + From c745ec37b70884839655d2d8fc6ed1ff6fd1d9a8 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 16:16:02 +0100 Subject: [PATCH 16/33] update fiat instead of crypto amount on fiat select --- src/actions/ethereum/SendFormActions.js | 4 ++-- src/actions/ripple/SendFormActions.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/actions/ethereum/SendFormActions.js b/src/actions/ethereum/SendFormActions.js index c3fe2119..8743ff18 100644 --- a/src/actions/ethereum/SendFormActions.js +++ b/src/actions/ethereum/SendFormActions.js @@ -321,8 +321,8 @@ export const onLocalCurrencyChange = (localCurrency: { localCurrency: localCurrency.value, }, }); - // Recalculates amount with new currency rates - dispatch(onLocalAmountChange(state.localAmount)); + // Recalculates local amount with new currency rates + dispatch(onAmountChange(state.amount, true)); }; /* diff --git a/src/actions/ripple/SendFormActions.js b/src/actions/ripple/SendFormActions.js index f7efceaa..14dd94af 100644 --- a/src/actions/ripple/SendFormActions.js +++ b/src/actions/ripple/SendFormActions.js @@ -277,8 +277,8 @@ export const onLocalCurrencyChange = (localCurrency: { localCurrency: localCurrency.value, }, }); - // Recalculates amount with new currency rates - dispatch(onLocalAmountChange(state.localAmount)); + // Recalculates local amount with new currency rates + dispatch(onAmountChange(state.amount, true)); }; /* From bec12cbaf87b37d7b7e50177765ebb001745faa7 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 17:37:36 +0100 Subject: [PATCH 17/33] fix wallet border-radius --- src/views/Wallet/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/views/Wallet/index.js b/src/views/Wallet/index.js index 00a40178..f601fce2 100644 --- a/src/views/Wallet/index.js +++ b/src/views/Wallet/index.js @@ -78,6 +78,7 @@ const MainContent = styled.article` flex-direction: column; overflow: auto; border-top-right-radius: 4px; + border-top-left-radius: 4px; @media screen and (max-width: ${SCREEN_SIZE.SM}) { ${props => @@ -91,6 +92,7 @@ const MainContent = styled.article` @media screen and (max-width: 1170px) { border-top-right-radius: 0px; + border-top-left-radius: 0px; } `; From 716cab44f7492ad19e740a97914db02994556c8a Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 17:37:56 +0100 Subject: [PATCH 18/33] comment settings in device header --- .../Wallet/components/LeftNavigation/index.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/views/Wallet/components/LeftNavigation/index.js b/src/views/Wallet/components/LeftNavigation/index.js index b2c9cdca..e5e6bc4d 100644 --- a/src/views/Wallet/components/LeftNavigation/index.js +++ b/src/views/Wallet/components/LeftNavigation/index.js @@ -10,16 +10,19 @@ import icons from 'config/icons'; import { TransitionGroup, CSSTransition } from 'react-transition-group'; import styled from 'styled-components'; import DeviceHeader from 'components/DeviceHeader'; +// import Link from 'components/Link'; import * as deviceUtils from 'utils/device'; import Tooltip from 'components/Tooltip'; import { FormattedMessage } from 'react-intl'; +// import { getPattern } from 'support/routes'; import AccountMenu from './components/AccountMenu'; import CoinMenu from './components/CoinMenu'; import DeviceMenu from './components/DeviceMenu'; import Sidebar from './components/Sidebar'; import type { Props } from './components/common'; +// import l10nCommonMessages from 'views/common.messages'; import l10nMessages from './index.messages'; const Header = styled(DeviceHeader)` @@ -310,6 +313,27 @@ class LeftNavigation extends React.PureComponent { {this.props.devices.length} )} + {/* + } + maxWidth={200} + placement="bottom" + enterDelayMs={0.5} + > + + + + + + */} Date: Tue, 12 Mar 2019 17:38:17 +0100 Subject: [PATCH 19/33] add settings to the device menu --- .../DeviceMenu/components/MenuItems/index.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js index 2e9dafaa..31f75749 100644 --- a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js @@ -2,8 +2,10 @@ import React, { PureComponent } from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; import Icon from 'components/Icon'; +import Link from 'components/Link'; import DeviceIcon from 'components/images/DeviceIcon'; import { FormattedMessage } from 'react-intl'; +import { getPattern } from 'support/routes'; import icons from 'config/icons'; import colors from 'config/colors'; @@ -29,6 +31,12 @@ const Item = styled.div` } `; +const Divider = styled.div` + width: 100%; + height: 1px; + background: ${colors.DIVIDER}; +`; + const Label = styled.div` padding-left: 15px; `; @@ -99,6 +107,16 @@ class MenuItems extends PureComponent { + + + + + + + + ); } From d0bb9cbbacc192e850f65770fdf9a1739973e9f3 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 18:13:38 +0100 Subject: [PATCH 20/33] separate presentational from container component --- .../Wallet/views/WalletSettings/Container.js | 44 ++++++++++++++++++ .../Wallet/views/WalletSettings/index.js | 45 ++----------------- src/views/index.js | 2 +- 3 files changed, 49 insertions(+), 42 deletions(-) create mode 100644 src/views/Wallet/views/WalletSettings/Container.js diff --git a/src/views/Wallet/views/WalletSettings/Container.js b/src/views/Wallet/views/WalletSettings/Container.js new file mode 100644 index 00000000..24e5c4d0 --- /dev/null +++ b/src/views/Wallet/views/WalletSettings/Container.js @@ -0,0 +1,44 @@ +/* @flow */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { injectIntl } from 'react-intl'; + +import * as WalletActions from 'actions/WalletActions'; +import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; +import type { State, Dispatch } from 'flowtype'; +import WalletSettings from './index'; + +type OwnProps = {}; + +type StateProps = { + wallet: $ElementType, + fiat: $ElementType, + localStorage: $ElementType, +}; + +type DispatchProps = { + setLocalCurrency: typeof WalletActions.setLocalCurrency, +}; + +export type Props = StateProps & DispatchProps; + +const mapStateToProps: MapStateToProps = ( + state: State +): StateProps => ({ + wallet: state.wallet, + fiat: state.fiat, + localStorage: state.localStorage, +}); + +const mapDispatchToProps: MapDispatchToProps = ( + dispatch: Dispatch +): DispatchProps => ({ + setLocalCurrency: bindActionCreators(WalletActions.setLocalCurrency, dispatch), +}); + +export default injectIntl( + connect( + mapStateToProps, + mapDispatchToProps + )(WalletSettings) +); diff --git a/src/views/Wallet/views/WalletSettings/index.js b/src/views/Wallet/views/WalletSettings/index.js index c8e76aeb..91ddd07b 100644 --- a/src/views/Wallet/views/WalletSettings/index.js +++ b/src/views/Wallet/views/WalletSettings/index.js @@ -1,13 +1,7 @@ /* @flow */ import styled from 'styled-components'; import React from 'react'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { FormattedMessage, injectIntl } from 'react-intl'; - -import * as WalletActions from 'actions/WalletActions'; -import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; -import type { State, Dispatch } from 'flowtype'; +import { FormattedMessage } from 'react-intl'; import Link from 'components/Link'; import Content from 'views/Wallet/components/Content'; @@ -19,6 +13,7 @@ import { FIAT_CURRENCIES } from 'config/app'; import { FONT_SIZE } from 'config/variables'; import l10nCommonMessages from 'views/common.messages'; import l10nMessages from './index.messages'; +import type { Props } from './Container'; const CurrencySelect = styled(Select)` min-width: 77px; @@ -56,6 +51,7 @@ const buildCurrencyOption = currency => { const WalletSettings = (props: Props) => ( + {console.log(props)}
@@ -83,37 +79,4 @@ const WalletSettings = (props: Props) => ( ); -type OwnProps = {}; - -type StateProps = { - wallet: $ElementType, - fiat: $ElementType, - localStorage: $ElementType, -}; - -type DispatchProps = { - setLocalCurrency: typeof WalletActions.setLocalCurrency, -}; - -export type Props = StateProps & DispatchProps; - -const mapStateToProps: MapStateToProps = ( - state: State -): StateProps => ({ - wallet: state.wallet, - fiat: state.fiat, - localStorage: state.localStorage, -}); - -const mapDispatchToProps: MapDispatchToProps = ( - dispatch: Dispatch -): DispatchProps => ({ - setLocalCurrency: bindActionCreators(WalletActions.setLocalCurrency, dispatch), -}); - -export default injectIntl( - connect( - mapStateToProps, - mapDispatchToProps - )(WalletSettings) -); +export default WalletSettings; diff --git a/src/views/index.js b/src/views/index.js index ffd741c9..fa73d779 100644 --- a/src/views/index.js +++ b/src/views/index.js @@ -25,7 +25,7 @@ import AccountSignVerify from 'views/Wallet/views/Account/SignVerify/Container'; import WalletDashboard from 'views/Wallet/views/Dashboard'; import WalletDeviceSettings from 'views/Wallet/views/DeviceSettings'; -import WalletSettings from 'views/Wallet/views/WalletSettings'; +import WalletSettings from 'views/Wallet/views/WalletSettings/Container'; import WalletBootloader from 'views/Wallet/views/Bootloader'; import WalletFirmwareUpdate from 'views/Wallet/views/FirmwareUpdate'; import WalletNoBackup from 'views/Wallet/views/NoBackup'; From c96992a3f73ccbefef7970aa1967e516237db83f Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 12 Mar 2019 18:34:32 +0100 Subject: [PATCH 21/33] searchable currency select with dropDownIndicator enabled --- src/components/Select/index.js | 9 ++++++--- src/views/Wallet/views/Account/Send/ethereum/index.js | 2 +- src/views/Wallet/views/Account/Summary/ethereum/index.js | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/Select/index.js b/src/components/Select/index.js index 7aa4ad66..4db074a0 100644 --- a/src/components/Select/index.js +++ b/src/components/Select/index.js @@ -4,12 +4,15 @@ import ReactSelect from 'react-select'; import ReactAsyncSelect from 'react-select/lib/Async'; import colors from 'config/colors'; -const styles = isSearchable => ({ +const styles = (isSearchable, withDropdownIndicator = true) => ({ singleValue: base => ({ ...base, maxWidth: 'calc(100% - 10px)', // 8px padding + 2px maring-left width: '100%', color: colors.TEXT_SECONDARY, + '&:hover': { + cursor: 'text', + }, }), control: (base, { isDisabled, isFocused }) => ({ ...base, @@ -20,7 +23,7 @@ const styles = isSearchable => ({ boxShadow: isFocused ? `0 0px 6px 0 ${colors.INPUT_FOCUSED_SHADOW}` : 'none', background: isDisabled ? colors.LANDING : colors.WHITE, '&:hover': { - cursor: isSearchable ? 'text' : 'pointer', + cursor: 'pointer', }, }), indicatorSeparator: () => ({ @@ -28,7 +31,7 @@ const styles = isSearchable => ({ }), dropdownIndicator: (base, { isDisabled }) => ({ ...base, - display: isSearchable || isDisabled ? 'none' : 'block', + display: !withDropdownIndicator || isDisabled ? 'none' : 'block', color: colors.TEXT_SECONDARY, path: '', '&:hover': { diff --git a/src/views/Wallet/views/Account/Send/ethereum/index.js b/src/views/Wallet/views/Account/Send/ethereum/index.js index 9b344739..96f1f66c 100644 --- a/src/views/Wallet/views/Account/Send/ethereum/index.js +++ b/src/views/Wallet/views/Account/Send/ethereum/index.js @@ -455,7 +455,7 @@ const AccountSend = (props: Props) => { sideAddons={[ onLocalCurrencyChange(option)} value={buildCurrencyOption(localCurrency)} diff --git a/src/views/Wallet/views/Account/Summary/ethereum/index.js b/src/views/Wallet/views/Account/Summary/ethereum/index.js index b4cbc08b..bc0a2e3f 100644 --- a/src/views/Wallet/views/Account/Summary/ethereum/index.js +++ b/src/views/Wallet/views/Account/Summary/ethereum/index.js @@ -121,6 +121,7 @@ const AccountSummary = (props: Props) => { Date: Tue, 12 Mar 2019 22:40:36 +0100 Subject: [PATCH 22/33] fix intl msg --- src/views/Wallet/views/Account/Send/ethereum/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/Wallet/views/Account/Send/ethereum/index.js b/src/views/Wallet/views/Account/Send/ethereum/index.js index 96f1f66c..e6eec27e 100644 --- a/src/views/Wallet/views/Account/Send/ethereum/index.js +++ b/src/views/Wallet/views/Account/Send/ethereum/index.js @@ -409,7 +409,7 @@ const AccountSend = (props: Props) => { {isCurrentCurrencyToken && selectedToken && ( Date: Wed, 13 Mar 2019 14:11:51 +0100 Subject: [PATCH 23/33] add erc tokens conversion to fiat --- src/actions/ethereum/SendFormActions.js | 8 +++- src/services/CoingeckoService.js | 56 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/actions/ethereum/SendFormActions.js b/src/actions/ethereum/SendFormActions.js index 8743ff18..417513b7 100644 --- a/src/actions/ethereum/SendFormActions.js +++ b/src/actions/ethereum/SendFormActions.js @@ -251,6 +251,7 @@ export const onAmountChange = ( shouldUpdateLocalAmount: boolean = true ): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { const state = getState().sendFormEthereum; + dispatch({ type: SEND.CHANGE, networkType: 'ethereum', @@ -265,7 +266,7 @@ export const onAmountChange = ( if (shouldUpdateLocalAmount) { const { localCurrency } = getState().sendFormEthereum; - const fiatRates = getState().fiat.find(f => f.network === state.networkName); + const fiatRates = getState().fiat.find(f => f.network === state.currency.toLowerCase()); const localAmount = toFiatCurrency(amount, localCurrency, fiatRates); dispatch(onLocalAmountChange(localAmount, false)); } @@ -280,7 +281,6 @@ export const onLocalAmountChange = ( ): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { const state = getState().sendFormEthereum; const { localCurrency } = getState().sendFormEthereum; - const fiatRates = getState().fiat.find(f => f.network === state.networkName); const { network } = getState().selectedAccount; // updates localAmount @@ -300,6 +300,7 @@ export const onLocalAmountChange = ( if (shouldUpdateAmount) { if (!network) return; // converts amount in local currency to crypto currency that will be sent + const fiatRates = getState().fiat.find(f => f.network === state.currency.toLowerCase()); const amount = fromFiatCurrency(localAmount, localCurrency, fiatRates, network.decimals); dispatch(onAmountChange(amount, false)); } @@ -364,6 +365,9 @@ export const onCurrencyChange = (currency: { value: string, label: string }): Th gasLimit, }, }); + + // Recalculates local amount with new currency rates + dispatch(onAmountChange(state.amount, true)); }; /* diff --git a/src/services/CoingeckoService.js b/src/services/CoingeckoService.js index f39bd0a7..5bdd1097 100644 --- a/src/services/CoingeckoService.js +++ b/src/services/CoingeckoService.js @@ -3,6 +3,8 @@ import { httpRequest } from 'utils/networkUtils'; import { resolveAfter } from 'utils/promiseUtils'; import { READY } from 'actions/constants/localStorage'; +import * as TOKEN from 'actions/constants/token'; +import type { Token } from 'reducers/TokensReducer'; import type { Middleware, @@ -14,8 +16,15 @@ import type { GetState, } from 'flowtype'; +const BASE_URL = 'https://api.coingecko.com/'; + export const RATE_UPDATE: 'rate__update' = 'rate__update'; +export type NetworkRate = { + network: string, + rates: { [string]: number }, +}; + export type FiatRateAction = { type: typeof RATE_UPDATE, network: string, @@ -58,6 +67,49 @@ const loadRateAction = (): AsyncAction => async ( await resolveAfter(50000); }; +const fetchCoinRate = async (id: string): Promise => { + const url = new URL(`/api/v3/coins/${id}`, BASE_URL); + url.searchParams.set('tickers', 'false'); + url.searchParams.set('market_data', 'true'); + url.searchParams.set('community_data', 'false'); + url.searchParams.set('developer_data', 'false'); + url.searchParams.set('sparkline', 'false'); + + const response = await fetch(url.toString()); + const rates = await response.json(); + return rates; +}; + +const fetchCoinList = async (): Promise => { + const url = new URL('/api/v3/coins/list', BASE_URL); + + const response = await fetch(url.toString()); + const tokens = await response.json(); + return tokens; +}; + +const loadTokenRateAction = (token: Token): AsyncAction => async ( + dispatch: Dispatch +): Promise => { + const { symbol } = token; + try { + const tokens = await fetchCoinList(); + const tokenData = tokens.find(t => t.symbol === symbol.toLowerCase()); + if (!tokenData) return; + + const res = await fetchCoinRate(tokenData.id); + if (res) { + dispatch({ + type: RATE_UPDATE, + network: res.symbol, + rates: res.market_data.current_price, + }); + } + } catch (err) { + console.log(err); + } +}; + /** * Middleware */ @@ -70,6 +122,10 @@ const CoingeckoService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDi api.dispatch(loadRateAction()); } + if (action.type === TOKEN.ADD) { + api.dispatch(loadTokenRateAction(action.payload)); + } + return action; }; From f0c8c0e100439028faef9873e9b209130c9e1c40 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Wed, 13 Mar 2019 14:34:21 +0100 Subject: [PATCH 24/33] same input state for local amount as for amount --- src/views/Wallet/views/Account/Send/ethereum/index.js | 2 +- src/views/Wallet/views/Account/Send/ripple/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/Wallet/views/Account/Send/ethereum/index.js b/src/views/Wallet/views/Account/Send/ethereum/index.js index e6eec27e..842cb4ac 100644 --- a/src/views/Wallet/views/Account/Send/ethereum/index.js +++ b/src/views/Wallet/views/Account/Send/ethereum/index.js @@ -445,7 +445,7 @@ const AccountSend = (props: Props) => { = { = Date: Wed, 13 Mar 2019 14:34:49 +0100 Subject: [PATCH 25/33] fix clear button --- src/actions/ethereum/SendFormActions.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/actions/ethereum/SendFormActions.js b/src/actions/ethereum/SendFormActions.js index 417513b7..ad1c3f0e 100644 --- a/src/actions/ethereum/SendFormActions.js +++ b/src/actions/ethereum/SendFormActions.js @@ -205,6 +205,9 @@ export const onClear = (): AsyncAction => async ( initialState.selectedFeeLevel ); + // initial local currency is set according to wallet settings + const { localCurrency } = getState().wallet; + dispatch({ type: SEND.CLEAR, networkType: 'ethereum', @@ -213,6 +216,7 @@ export const onClear = (): AsyncAction => async ( networkName: network.shortcut, networkSymbol: network.symbol, currency: network.symbol, + localCurrency, feeLevels, selectedFeeLevel, recommendedGasPrice: gasPrice.toString(), From f0f9a9c7857520acd701ca759efddd96baefac82 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Wed, 13 Mar 2019 15:03:47 +0100 Subject: [PATCH 26/33] fix select cursor --- src/components/Select/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Select/index.js b/src/components/Select/index.js index 4db074a0..4c493b83 100644 --- a/src/components/Select/index.js +++ b/src/components/Select/index.js @@ -11,7 +11,7 @@ const styles = (isSearchable, withDropdownIndicator = true) => ({ width: '100%', color: colors.TEXT_SECONDARY, '&:hover': { - cursor: 'text', + cursor: isSearchable ? 'text' : 'pointer', }, }), control: (base, { isDisabled, isFocused }) => ({ From 6ebf14f6aa31517227b58166bdf66c1d1aa6e225 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Wed, 13 Mar 2019 15:09:55 +0100 Subject: [PATCH 27/33] remove device menu divider after app settings --- .../components/DeviceMenu/components/MenuItems/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js index 31f75749..7bd10306 100644 --- a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js @@ -116,7 +116,6 @@ class MenuItems extends PureComponent { - ); } From 56209f1dc9aa8b010f942488573bef79a273f891 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Wed, 13 Mar 2019 17:01:24 +0100 Subject: [PATCH 28/33] add unit tests for fiatConverter --- src/utils/__tests__/fiatConverter.js | 114 +++++++++++++++++++++++++++ src/utils/fiatConverter.js | 10 ++- 2 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 src/utils/__tests__/fiatConverter.js diff --git a/src/utils/__tests__/fiatConverter.js b/src/utils/__tests__/fiatConverter.js new file mode 100644 index 00000000..19d9cb0e --- /dev/null +++ b/src/utils/__tests__/fiatConverter.js @@ -0,0 +1,114 @@ +import BigNumber from 'bignumber.js'; +import * as utils from '../fiatConverter'; + +describe('fiatConverter utils: toFiatCurrency', () => { + const ratesETH = { + network: 'eth', + rates: { + czk: 3007.1079886708517, + eos: 36.852136278995445, + eur: 117.13118845579191, + gbp: 100.43721437661289, + }, + }; + + it('to existing fiat currency', () => { + expect(utils.toFiatCurrency('1', 'czk', ratesETH)).toBe('3007.11'); + expect(utils.toFiatCurrency('0', 'czk', ratesETH)).toBe('0.00'); + expect(utils.toFiatCurrency('1.00000000000', 'czk', ratesETH)).toBe('3007.11'); + expect(utils.toFiatCurrency('0.12345678910111213', 'eur', ratesETH)).toBe('14.46'); + }); + + it('to missing fiat currency', () => { + expect(utils.toFiatCurrency('1', 'usd', ratesETH)).toBe(''); + expect(utils.toFiatCurrency('0', 'usd', ratesETH)).toBe(''); + expect(utils.toFiatCurrency('1.00000000000', 'usd', ratesETH)).toBe(''); + expect(utils.toFiatCurrency('0.12345678910111213', 'usd', ratesETH)).toBe(''); + }); + + it('non-numeric amount to fiat currency', () => { + expect(utils.toFiatCurrency(undefined, 'czk', ratesETH)).toBe(''); + expect(utils.toFiatCurrency(null, 'czk', ratesETH)).toBe(''); + expect(utils.toFiatCurrency('12133.3131.3141.4', 'czk', ratesETH)).toBe(''); + expect(utils.toFiatCurrency(BigNumber('nanbla'), 'czk', ratesETH)).toBe(''); + }); + + it('with null/undefined/empty rates', () => { + expect(utils.toFiatCurrency('1', 'czk', {})).toBe(''); + expect(utils.toFiatCurrency('1', 'czk', null)).toBe(''); + expect(utils.toFiatCurrency('1', 'czk', undefined)).toBe(''); + }); + + it('with null/undefined/empty currency', () => { + expect(utils.toFiatCurrency('1', {}, ratesETH)).toBe(''); + expect(utils.toFiatCurrency('1', null, ratesETH)).toBe(''); + expect(utils.toFiatCurrency('1', undefined, ratesETH)).toBe(''); + }); +}); + +describe('fiatConverter utils: fromFiatCurrency', () => { + const ratesETH = { + network: 'eth', + rates: { + czk: 3007.1079886708517, + eos: 36.852136278995445, + eur: 117.13118845579191, + gbp: 100.43721437661289, + }, + }; + const decimals = 18; + + it('from existing fiat currency', () => { + expect(utils.fromFiatCurrency('3007.1079886708517', 'czk', ratesETH, decimals)).toBe( + '1.000000000000000000' + ); + expect(utils.fromFiatCurrency('0', 'czk', ratesETH, decimals)).toBe('0.000000000000000000'); + expect(utils.fromFiatCurrency('3007.1079886708517', 'czk', ratesETH, decimals)).toBe( + '1.000000000000000000' + ); + expect(utils.fromFiatCurrency('117.13118845579191', 'eur', ratesETH, decimals)).toBe( + '1.000000000000000000' + ); + }); + + it('from missing fiat currency', () => { + expect(utils.fromFiatCurrency('1', 'usd', ratesETH, decimals)).toBe(''); + expect(utils.fromFiatCurrency('0', 'usd', ratesETH, decimals)).toBe(''); + expect(utils.fromFiatCurrency('1.00000000000', 'usd', ratesETH, decimals)).toBe(''); + expect(utils.fromFiatCurrency('0.12345678910111213', 'usd', ratesETH, decimals)).toBe(''); + }); + + it('non-numeric amount to fiat currency', () => { + expect(utils.fromFiatCurrency(undefined, 'czk', ratesETH, decimals)).toBe(''); + expect(utils.fromFiatCurrency(null, 'czk', ratesETH, decimals)).toBe(''); + expect(utils.fromFiatCurrency('12133.3131.3141.4', 'czk', ratesETH, decimals)).toBe(''); + expect(utils.fromFiatCurrency(BigNumber('nanbla'), 'czk', ratesETH, decimals)).toBe(''); + }); + + it('with null/undefined/empty rates', () => { + expect(utils.fromFiatCurrency('1', 'czk', {}, decimals)).toBe(''); + expect(utils.fromFiatCurrency('1', 'czk', null, decimals)).toBe(''); + expect(utils.fromFiatCurrency('1', 'czk', undefined, decimals)).toBe(''); + }); + + it('with null/undefined/empty currency', () => { + expect(utils.fromFiatCurrency('1', {}, ratesETH, decimals)).toBe(''); + expect(utils.fromFiatCurrency('1', null, ratesETH, decimals)).toBe(''); + expect(utils.fromFiatCurrency('1', undefined, ratesETH, decimals)).toBe(''); + }); + + it('different decimals', () => { + expect(utils.fromFiatCurrency('3007.1079886708517', 'czk', ratesETH, 1)).toBe('1.0'); + expect(utils.fromFiatCurrency('0', 'czk', ratesETH, 0)).toBe('0'); + expect(utils.fromFiatCurrency('3007.1079886708517', 'czk', ratesETH, 5)).toBe('1.00000'); + }); + + it('from fiat currency with comma decimal separator', () => { + expect(utils.fromFiatCurrency('3007,1079886708517', 'czk', ratesETH, decimals)).toBe( + '1.000000000000000000' + ); + expect(utils.fromFiatCurrency('117,13118845579191', 'eur', ratesETH, decimals)).toBe( + '1.000000000000000000' + ); + }); +}); diff --git a/src/utils/fiatConverter.js b/src/utils/fiatConverter.js index 2119444c..b92f8900 100644 --- a/src/utils/fiatConverter.js +++ b/src/utils/fiatConverter.js @@ -11,7 +11,10 @@ const toFiatCurrency = (amount, fiatCurrency, networkRates) => { return ''; } - const formattedAmount = amount.replace(',', '.'); + let formattedAmount = amount; + if (typeof amount === 'string') { + formattedAmount = amount.replace(',', '.'); + } let localAmount = BigNumber(formattedAmount).times(rate); localAmount = localAmount.isNaN() ? '' : localAmount.toFixed(2); @@ -28,7 +31,10 @@ const fromFiatCurrency = (localAmount, fiatCurrency, networkRates, decimals) => return ''; } - const formattedLocalAmount = localAmount.replace(',', '.'); + let formattedLocalAmount = localAmount; + if (typeof localAmount === 'string') { + formattedLocalAmount = localAmount.replace(',', '.'); + } let amount = BigNumber(formattedLocalAmount).div(rate); amount = amount.isNaN() ? '' : amount.toFixed(decimals); From 7a6a3d974ee46df951efd3513dda29b9dd400f92 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Wed, 13 Mar 2019 17:19:57 +0100 Subject: [PATCH 29/33] remove all caps, react-intl now handles the format --- .../Wallet/views/Account/Summary/components/Balance/index.js | 2 -- .../views/Account/Summary/ripple/components/Balance/index.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/views/Wallet/views/Account/Summary/components/Balance/index.js b/src/views/Wallet/views/Account/Summary/components/Balance/index.js index 86268a57..f20a4d7a 100644 --- a/src/views/Wallet/views/Account/Summary/components/Balance/index.js +++ b/src/views/Wallet/views/Account/Summary/components/Balance/index.js @@ -61,7 +61,6 @@ const FiatValue = styled.div` min-height: 25px; color: ${colors.TEXT_PRIMARY}; align-items: center; - text-transform: uppercase; `; const FiatValueRate = styled.div` @@ -72,7 +71,6 @@ const FiatValueRate = styled.div` display: flex; align-items: center; color: ${colors.TEXT_PRIMARY}; - text-transform: uppercase; `; const BalanceWrapper = styled.div` diff --git a/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js b/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js index 3f999aa8..967b9f83 100644 --- a/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js +++ b/src/views/Wallet/views/Account/Summary/ripple/components/Balance/index.js @@ -59,7 +59,6 @@ const FiatValue = styled.div` min-height: 25px; color: ${colors.TEXT_PRIMARY}; align-items: center; - text-transform: uppercase; `; const FiatValueRate = styled.div` @@ -70,7 +69,6 @@ const FiatValueRate = styled.div` display: flex; color: ${colors.TEXT_PRIMARY}; align-items: center; - text-transform: uppercase; `; const BalanceWrapper = styled.div` From ff9f072119e76132c540d9588e5759be1637e2ac Mon Sep 17 00:00:00 2001 From: Vladimir Volek Date: Thu, 14 Mar 2019 13:26:58 +0100 Subject: [PATCH 30/33] test format adjusted --- src/utils/__tests__/cryptoUriParser.js | 18 ------------------ ...{fiatConverter.js => fiatConverter.test.js} | 0 2 files changed, 18 deletions(-) delete mode 100644 src/utils/__tests__/cryptoUriParser.js rename src/utils/__tests__/{fiatConverter.js => fiatConverter.test.js} (100%) diff --git a/src/utils/__tests__/cryptoUriParser.js b/src/utils/__tests__/cryptoUriParser.js deleted file mode 100644 index 1dde9ad6..00000000 --- a/src/utils/__tests__/cryptoUriParser.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as utils from '../cryptoUriParser'; - -describe('crypto uri parser', () => { - it('parseUri', () => { - expect(utils.parseUri('http://www.trezor.io')).toEqual({ address: '//www.trezor.io' }); // TODO: Error in function - expect(utils.parseUri('www.trezor.io')).toEqual({ address: 'www.trezor.io' }); - expect(utils.parseUri('www.trezor.io/TT')).toEqual({ address: 'www.trezor.io/TT' }); - expect(utils.parseUri('www.trezor.io/TT?param1=aha')).toEqual({ - address: 'www.trezor.io/TT', - param1: 'aha', - }); - expect(utils.parseUri('www.trezor.io/TT?param1=aha¶m2=hah')).toEqual({ - address: 'www.trezor.io/TT', - param1: 'aha', - param2: 'hah', - }); - }); -}); diff --git a/src/utils/__tests__/fiatConverter.js b/src/utils/__tests__/fiatConverter.test.js similarity index 100% rename from src/utils/__tests__/fiatConverter.js rename to src/utils/__tests__/fiatConverter.test.js From 1a07af9413f535469d432c9a5c04a25b7bc120a6 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Thu, 14 Mar 2019 15:51:31 +0100 Subject: [PATCH 31/33] fix fiatRates for tokens on set max btn --- src/actions/ethereum/SendFormValidationActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/ethereum/SendFormValidationActions.js b/src/actions/ethereum/SendFormValidationActions.js index 6c22a7a1..6a5d1cc5 100644 --- a/src/actions/ethereum/SendFormValidationActions.js +++ b/src/actions/ethereum/SendFormValidationActions.js @@ -134,7 +134,7 @@ export const recalculateTotalAmount = ($state: State): PayloadAction => ( // calculate amount in local currency const { localCurrency } = getState().sendFormEthereum; - const fiatRates = getState().fiat.find(f => f.network === state.networkName); + const fiatRates = getState().fiat.find(f => f.network === state.currency.toLowerCase()); const localAmount = toFiatCurrency(state.amount, localCurrency, fiatRates); if (localAmount) { state.localAmount = localAmount; From 628d424438aa104311e854db503939f11fd0ced3 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Thu, 14 Mar 2019 16:35:50 +0100 Subject: [PATCH 32/33] fix recalculating local amount for tokens on set max btn --- src/actions/ethereum/SendFormValidationActions.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/actions/ethereum/SendFormValidationActions.js b/src/actions/ethereum/SendFormValidationActions.js index 6a5d1cc5..c3f9a4d0 100644 --- a/src/actions/ethereum/SendFormValidationActions.js +++ b/src/actions/ethereum/SendFormValidationActions.js @@ -131,15 +131,12 @@ export const recalculateTotalAmount = ($state: State): PayloadAction => ( } else { const b = new BigNumber(account.balance).minus(pendingAmount); state.amount = calculateMaxAmount(b, state.gasPrice, state.gasLimit); - - // calculate amount in local currency - const { localCurrency } = getState().sendFormEthereum; - const fiatRates = getState().fiat.find(f => f.network === state.currency.toLowerCase()); - const localAmount = toFiatCurrency(state.amount, localCurrency, fiatRates); - if (localAmount) { - state.localAmount = localAmount; - } } + // calculate amount in local currency + const { localCurrency } = getState().sendFormEthereum; + const fiatRates = getState().fiat.find(f => f.network === state.currency.toLowerCase()); + const localAmount = toFiatCurrency(state.amount, localCurrency, fiatRates); + state.localAmount = localAmount; } state.total = calculateTotal(isToken ? '0' : state.amount, state.gasPrice, state.gasLimit); From 9f2a3f641613ad675004afe102d247d2a43c2013 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Thu, 14 Mar 2019 17:05:50 +0100 Subject: [PATCH 33/33] remove console.log --- src/views/Wallet/views/WalletSettings/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/Wallet/views/WalletSettings/index.js b/src/views/Wallet/views/WalletSettings/index.js index 91ddd07b..56fc65eb 100644 --- a/src/views/Wallet/views/WalletSettings/index.js +++ b/src/views/Wallet/views/WalletSettings/index.js @@ -51,7 +51,6 @@ const buildCurrencyOption = currency => { const WalletSettings = (props: Props) => ( - {console.log(props)}