diff --git a/src/bridge/BridgeSyncContext.js b/src/bridge/BridgeSyncContext.js index 7a4228c8..de1a5aa9 100644 --- a/src/bridge/BridgeSyncContext.js +++ b/src/bridge/BridgeSyncContext.js @@ -16,7 +16,7 @@ import { setAccountSyncState } from 'actions/bridgeSync' import { bridgeSyncSelector, syncStateLocalSelector } from 'reducers/bridgeSync' import type { BridgeSyncState } from 'reducers/bridgeSync' import { accountsSelector, isUpToDateSelector } from 'reducers/accounts' -import { currenciesStatusSelector, getIsCurrencyDown } from 'reducers/currenciesStatus' +import { currenciesStatusSelector, currencyDownStatusLocal } from 'reducers/currenciesStatus' import { SYNC_MAX_CONCURRENT, SYNC_TIMEOUT } from 'config/constants' import type { CurrencyStatus } from 'reducers/currenciesStatus' import { getBridgeForCurrency } from '.' @@ -77,7 +77,7 @@ class Provider extends Component { return } - if (getIsCurrencyDown(this.props.currenciesStatus, account.currency)) { + if (currencyDownStatusLocal(this.props.currenciesStatus, account.currency)) { next() return } diff --git a/src/components/CurrencyDownStatusAlert.js b/src/components/CurrencyDownStatusAlert.js new file mode 100644 index 00000000..e39a5ff7 --- /dev/null +++ b/src/components/CurrencyDownStatusAlert.js @@ -0,0 +1,69 @@ +// @flow + +import React, { PureComponent } from 'react' +import { translate } from 'react-i18next' +import styled from 'styled-components' +import { connect } from 'react-redux' +import { createStructuredSelector } from 'reselect' +import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types' + +import type { CurrencyStatus } from 'reducers/currenciesStatus' +import { currencyDownStatus } from 'reducers/currenciesStatus' +import { openURL } from 'helpers/linking' +import Box from 'components/base/Box' +import IconTriangleWarning from 'icons/TriangleWarning' +import IconExternalLink from 'icons/ExternalLink' + +type Props = { + t: *, + status: ?CurrencyStatus, +} + +const CurrencyDownBox = styled(Box).attrs({ + horizontal: true, + align: 'center', + color: 'white', + borderRadius: 1, + fontSize: 1, + px: 4, + py: 2, + mb: 4, +})` + background-color: ${p => p.theme.colors.alertRed}; +` + +const Link = styled.span` + margin-left: 5px; + margin-right: 5px; + text-decoration: underline; + cursor: pointer; +` + +class CurrencyDownStatusAlert extends PureComponent { + onClick = () => { + const { status } = this.props + if (status) openURL(status.link) + } + + render() { + const { status, t } = this.props + if (!status) return null + return ( + + + + + + {status.message} + {t('common.learnMore')} + + + + ) + } +} +export default connect( + createStructuredSelector({ + status: currencyDownStatus, + }), +)(translate()(CurrencyDownStatusAlert)) diff --git a/src/components/modals/AddAccounts/steps/01-step-choose-currency.js b/src/components/modals/AddAccounts/steps/01-step-choose-currency.js index c3e8952f..5282ef47 100644 --- a/src/components/modals/AddAccounts/steps/01-step-choose-currency.js +++ b/src/components/modals/AddAccounts/steps/01-step-choose-currency.js @@ -5,12 +5,18 @@ import React, { Fragment } from 'react' import TrackPage from 'analytics/TrackPage' import SelectCurrency from 'components/SelectCurrency' import Button from 'components/base/Button' +import CurrencyDownStatusAlert from 'components/CurrencyDownStatusAlert' import CurrencyBadge from 'components/base/CurrencyBadge' import type { StepProps } from '../index' function StepChooseCurrency({ currency, setCurrency }: StepProps) { - return + return ( + + {currency ? : null} + + + ) } export function StepChooseCurrencyFooter({ transitionTo, currency, t }: StepProps) { diff --git a/src/components/modals/Receive/steps/01-step-account.js b/src/components/modals/Receive/steps/01-step-account.js index b293ba36..ae3b70a3 100644 --- a/src/components/modals/Receive/steps/01-step-account.js +++ b/src/components/modals/Receive/steps/01-step-account.js @@ -7,6 +7,7 @@ import Box from 'components/base/Box' import Label from 'components/base/Label' import Button from 'components/base/Button' import SelectAccount from 'components/SelectAccount' +import CurrencyDownStatusAlert from 'components/CurrencyDownStatusAlert' import type { StepProps } from '../index' @@ -14,6 +15,8 @@ export default function StepAccount({ t, account, onChangeAccount }: StepProps) return ( + {account ? : null} + diff --git a/src/components/modals/Receive/steps/02-step-connect-device.js b/src/components/modals/Receive/steps/02-step-connect-device.js index 700574f9..f0bed7c8 100644 --- a/src/components/modals/Receive/steps/02-step-connect-device.js +++ b/src/components/modals/Receive/steps/02-step-connect-device.js @@ -1,21 +1,25 @@ // @flow -import React from 'react' +import React, { Fragment } from 'react' import Box from 'components/base/Box' import Button from 'components/base/Button' import EnsureDeviceApp from 'components/EnsureDeviceApp' +import CurrencyDownStatusAlert from 'components/CurrencyDownStatusAlert' import TrackPage from 'analytics/TrackPage' import type { StepProps } from '../index' export default function StepConnectDevice({ account, onChangeAppOpened }: StepProps) { return ( - onChangeAppOpened(true)} - /> + + {account ? : null} + onChangeAppOpened(true)} + /> + ) } diff --git a/src/components/modals/Send/steps/01-step-amount.js b/src/components/modals/Send/steps/01-step-amount.js index e04e9d18..dddbb3e3 100644 --- a/src/components/modals/Send/steps/01-step-amount.js +++ b/src/components/modals/Send/steps/01-step-amount.js @@ -13,6 +13,7 @@ import Text from 'components/base/Text' import CounterValue from 'components/CounterValue' import Spinner from 'components/base/Spinner' import TrackPage from 'analytics/TrackPage' +import CurrencyDownStatusAlert from 'components/CurrencyDownStatusAlert' import RecipientField from '../fields/RecipientField' import AmountField from '../fields/AmountField' @@ -38,6 +39,8 @@ export default ({ return ( + {account ? : null} + diff --git a/src/reducers/accounts.js b/src/reducers/accounts.js index 1d5d202d..2f490445 100644 --- a/src/reducers/accounts.js +++ b/src/reducers/accounts.js @@ -6,7 +6,7 @@ import accountModel from 'helpers/accountModel' import logger from 'logger' import type { Account, AccountRaw } from '@ledgerhq/live-common/lib/types' import { OUTDATED_CONSIDERED_DELAY, DEBUG_SYNC } from 'config/constants' -import { currenciesStatusSelector, getIsCurrencyDown } from './currenciesStatus' +import { currenciesStatusSelector, currencyDownStatusLocal } from './currenciesStatus' export type AccountsState = Account[] const state: AccountsState = [] @@ -65,7 +65,7 @@ export const activeAccountsSelector = createSelector( accountsSelector, currenciesStatusSelector, (accounts, currenciesStatus) => - accounts.filter(a => !getIsCurrencyDown(currenciesStatus, a.currency)), + accounts.filter(a => !currencyDownStatusLocal(currenciesStatus, a.currency)), ) export const isUpToDateSelector = createSelector(activeAccountsSelector, accounts => diff --git a/src/reducers/currenciesStatus.js b/src/reducers/currenciesStatus.js index 8c1ec8a4..3d48f264 100644 --- a/src/reducers/currenciesStatus.js +++ b/src/reducers/currenciesStatus.js @@ -1,7 +1,8 @@ // @flow import { handleActions, createAction } from 'redux-actions' -import type { Currency } from '@ledgerhq/live-common/lib/types' +import { createSelector } from 'reselect' +import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types' import network from 'api/network' import { urls } from 'config/urls' @@ -11,7 +12,6 @@ import type { State } from './index' export type CurrencyStatus = { id: string, // the currency id - status: 'KO' | 'OK', message: string, link: string, nonce: number, @@ -47,11 +47,17 @@ export const fetchCurrenciesStatus = () => async (dispatch: *) => { export const currenciesStatusSelector = (state: State) => state.currenciesStatus -// It's not a *real* selector, but it's better than having this logic inside component -export const getIsCurrencyDown = (currenciesStatus: CurrenciesStatusState, currency: Currency) => { - const item = currenciesStatus.find(c => c.id === currency.id) - return !!item && item.status === 'KO' -} +// if there is a status, it means that currency is disrupted, the status is returned. +export const currencyDownStatusLocal = ( + currenciesStatus: CurrenciesStatusState, + currency: CryptoCurrency, +): ?CurrencyStatus => currenciesStatus.find(c => c.id === currency.id) + +export const currencyDownStatus = createSelector( + currenciesStatusSelector, + (_, { currency }) => currency, + currencyDownStatusLocal, +) // Exporting reducer