Skip to content

Commit

Permalink
feat(Watch Only): guard against bch as well
Browse files Browse the repository at this point in the history
  • Loading branch information
plondon committed Jun 1, 2018
1 parent 96581e2 commit b251318
Show file tree
Hide file tree
Showing 22 changed files with 288 additions and 28 deletions.
Expand Up @@ -18,12 +18,12 @@ class BchBalance extends React.PureComponent {

componentWillMount () {
if (Remote.NotAsked.is(this.props.data)) {
this.props.actions.fetchData(this.props.context)
this.props.actions.fetchSpendableBalance(this.props.context)
}
}

handleRefresh () {
this.props.actions.fetchData(this.props.context)
this.props.actions.fetchSpendableBalance(this.props.context)
}

render () {
Expand Down
@@ -1,3 +1,3 @@
import { selectors } from 'data'

export const getData = selectors.core.data.bch.getBalance
export const getData = selectors.core.data.bch.getSpendableBalance
@@ -0,0 +1,53 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

import { Remote } from 'blockchain-wallet-v4/src'
import { actions } from 'data'
import { getData } from './selectors'
import Error from './template.error'
import Loading from './template.loading'
import Success from './template.success'

class BchWatchOnlyBalance extends React.PureComponent {
constructor (props) {
super(props)
this.handleRefresh = this.handleRefresh.bind(this)
}

componentWillMount () {
if (Remote.NotAsked.is(this.props.data)) {
this.props.actions.fetchUnspendableBalance(this.props.context)
}
}

handleRefresh () {
this.props.actions.fetchUnspendableBalance(this.props.context)
}

render () {
const { data, large } = this.props

return data.cata({
Success: (value) => <Success balance={value} large={large} />,
Failure: (message) => <Error onRefresh={this.handleRefresh} />,
Loading: () => <Loading />,
NotAsked: () => <Loading />
})
}
}

BchWatchOnlyBalance.propTypes = {
context: PropTypes.string.isRequired
}

const mapStateToProps = (state) => ({
data: getData(state)
})

const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(actions.core.data.bch, dispatch)
})

export default connect(mapStateToProps, mapDispatchToProps)(BchWatchOnlyBalance)
@@ -0,0 +1,3 @@
import { selectors } from 'data'

export const getData = selectors.core.data.bch.getUnspendableBalance
@@ -0,0 +1,22 @@
import React from 'react'
import styled from 'styled-components'
import { FormattedMessage } from 'react-intl'
import { Link } from 'blockchain-info-components'

const Wrapper = styled.div`
display: flex;
box-sizing: border-box;
justify-content: flex-end;
padding-right: 25px;
`
const ErrorLink = styled(Link)`
text-decoration: underline;
`

export default (props) => (
<Wrapper>
<ErrorLink size='12px' weight={300} onClick={() => props.onRefresh()}>
<FormattedMessage id='wallet.menutop.balance.refresh' defaultMessage='Refresh {curr} data' values={{curr: 'Watch Only Bitcoin Cash'}} />
</ErrorLink>
</Wrapper>
)
@@ -0,0 +1,21 @@
import React from 'react'
import styled from 'styled-components'

import { FlatLoader } from 'blockchain-info-components'

const Wrapper = styled.div`
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 5px;
box-sizing: border-box;
`

export default (props) => {
return (
<Wrapper>
<FlatLoader width='50px' height='14px' />
</Wrapper>
)
}
@@ -0,0 +1,46 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import FiatDisplay from 'components/Display/FiatDisplay'
import { LinkContainer } from 'react-router-bootstrap'
import { FormattedMessage } from 'react-intl'
import { Banner, Text } from 'blockchain-info-components'

const Wrapper = styled.div`
display: inline-flex;
flex-direction: row;
align-items: center;
padding-left: 5px;
margin-bottom: 10px;
padding-right: ${props => props.large ? '15px' : '25px'};
> div:last-child {
margin-left: 10px;
> div {
color: ${props => props.theme['gray-3']}
}
}
`

const Success = props => {
const { balance } = props

return (
<LinkContainer to='/bch/transactions'>
<Wrapper>
<Text size='10px' weight={300}>BCH</Text>
<Banner inline type='informational'>
<FiatDisplay coin='BCH' cursor='pointer' size='10px' weight={300}>{balance}</FiatDisplay>
<Text size='10px' weight={300}>
<FormattedMessage id='scenes.wallet.menutop.balance.watchonlybchbalance' defaultMessage='&nbsp;Non-Spendable' />
</Text>
</Banner>
</Wrapper>
</LinkContainer>
)
}

Success.propTypes = {
balance: PropTypes.number.isRequired
}

export default Success
Expand Up @@ -5,8 +5,8 @@ import * as Currency from 'blockchain-wallet-v4/src/exchange/currency'

export const getData = (state) => {
const btcBalanceR = selectors.core.data.bitcoin.getSpendableBalance(state)
const bchBalanceR = selectors.core.data.bch.getSpendableBalance(state)
const ethBalanceR = selectors.core.data.ethereum.getBalance(state)
const bchBalanceR = selectors.core.data.bch.getBalance(state)
const btcBalance = btcBalanceR.getOrElse(0)
const ethBalance = ethBalanceR.getOrElse(0)
const bchBalance = bchBalanceR.getOrElse(0)
Expand Down
Expand Up @@ -12,7 +12,13 @@ class Balance extends React.PureComponent {
render () {
const { data } = this.props
return data.cata({
Success: (value) => <Success btcContext={value.btcSpendableContext} btcUnspendableContext={value.btcUnspendableContext} ethContext={value.ethContext} bchContext={value.bchContext} path={value.path} />,
Success: (value) => <Success
btcContext={value.btcContext}
ethContext={value.ethContext}
bchContext={value.bchContext}
btcUnspendableContext={value.btcUnspendableContext}
bchUnspendableContext={value.bchUnspendableContext}
path={value.path} />,
Failure: (message) => <Error>{message}</Error>,
Loading: () => <Loading />,
NotAsked: () => <Loading />
Expand Down
@@ -1,20 +1,17 @@
import { Remote } from 'blockchain-wallet-v4/src'
import { selectors } from 'data'
import { filter, reject, prop, lift } from 'ramda'
import { lift } from 'ramda'

export const getData = (state) => {
const ethContextR = selectors.core.kvStore.ethereum.getContext(state)
const bchContextR = Remote.of(selectors.core.kvStore.bch.getContext(state))
const btcActiveAccountsR = selectors.core.common.btc.getActiveHDAccounts(state)
const btcActiveAddressesR = selectors.core.common.btc.getActiveAddresses(state)
const btcContextR = Remote.of(selectors.core.wallet.getSpendableContext(state))
const bchContextR = Remote.of(selectors.core.kvStore.bch.getSpendableContext(state))
const btcUnspendableContextR = Remote.of(selectors.core.wallet.getUnspendableContext(state))
const bchUnspendableContextR = Remote.of(selectors.core.kvStore.bch.getUnspendableContext(state))
const path = state.router.location.pathname

const transform = lift((btcActiveAddresses, btcActiveAccounts, ethContext, bchContext) => {
const spendable = (a) => a.priv
const accounts = btcActiveAccounts.map(prop('xpub'))
const btcUnspendableContext = reject(spendable, btcActiveAddresses).map(prop('addr'))
const btcSpendableContext = filter(spendable, btcActiveAddresses).map(prop('addr')).concat(accounts)
return {btcSpendableContext, btcUnspendableContext, ethContext, bchContext, path}
const transform = lift((btcContext, ethContext, bchContext, btcUnspendableContext, bchUnspendableContext) => {
return {btcContext, ethContext, bchContext, btcUnspendableContext, bchUnspendableContext, path}
})
return transform(btcActiveAddressesR, btcActiveAccountsR, ethContextR, bchContextR)
return transform(btcContextR, ethContextR, bchContextR, btcUnspendableContextR, bchUnspendableContextR)
}
Expand Up @@ -6,6 +6,7 @@ import BtcBalance from './BtcBalance'
import EthBalance from './EthBalance'
import BchBalance from './BchBalance'
import BtcWatchOnlyBalance from './BtcWatchOnlyBalance'
import BchWatchOnlyBalance from './BchWatchOnlyBalance'

import { FormattedMessage } from 'react-intl'
import { ComponentDropdown, Separator, Text } from 'blockchain-info-components'
Expand Down Expand Up @@ -64,9 +65,14 @@ const BalanceDropdown = styled.div`
position: relative;
}
`
const SubItems = styled.div`
display: flex;
align-items: flex-end;
flex-direction: column;
`

const Success = props => {
const { btcContext, ethContext, bchContext, btcUnspendableContext, path } = props
const { btcContext, ethContext, bchContext, btcUnspendableContext, bchUnspendableContext, path } = props

const getComponentOrder = () => {
switch (path) {
Expand All @@ -87,10 +93,11 @@ const Success = props => {
}

const getSubBalances = () => {
return btcUnspendableContext.length ? <Fragment>
return btcUnspendableContext.length || bchUnspendableContext.length ? <SubItems>
<Separator margin='0' />
<BtcWatchOnlyBalance context={btcUnspendableContext} />
</Fragment> : null
<BchWatchOnlyBalance context={bchUnspendableContext} />
</SubItems> : null
}

return (
Expand Down
Expand Up @@ -5,8 +5,8 @@ import { Color } from 'blockchain-info-components'

export const getData = (state) => {
const btcBalanceR = selectors.core.data.bitcoin.getSpendableBalance(state)
const bchBalanceR = selectors.core.data.bch.getSpendableBalance(state)
const ethBalanceR = selectors.core.data.ethereum.getBalance(state)
const bchBalanceR = selectors.core.data.bch.getBalance(state)
const btcBalance = btcBalanceR.getOrElse(0)
const ethBalance = ethBalanceR.getOrElse(0)
const bchBalance = bchBalanceR.getOrElse(0)
Expand Down
12 changes: 12 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/bch/actionTypes.js
Expand Up @@ -29,3 +29,15 @@ export const FETCH_BCH_TRANSACTION_HISTORY = '@CORE.FETCH_BCH_TRANSACTION_HISTOR
export const FETCH_BCH_TRANSACTION_HISTORY_LOADING = '@CORE.FETCH_BCH_TRANSACTION_HISTORY_LOADING'
export const FETCH_BCH_TRANSACTION_HISTORY_SUCCESS = '@CORE.FETCH_BCH_TRANSACTION_HISTORY_SUCCESS'
export const FETCH_BCH_TRANSACTION_HISTORY_FAILURE = '@CORE.FETCH_BCH_TRANSACTION_HISTORY_FAILURE'

// FETCH_BCH_TRANSACTION_HISTORY
export const FETCH_BCH_SPENDABLE_BALANCE = '@CORE.FETCH_BCH_SPENDABLE_BALANCE'
export const FETCH_BCH_SPENDABLE_BALANCE_LOADING = '@CORE.FETCH_BCH_SPENDABLE_BALANCE_LOADING'
export const FETCH_BCH_SPENDABLE_BALANCE_SUCCESS = '@CORE.FETCH_BCH_SPENDABLE_BALANCE_SUCCESS'
export const FETCH_BCH_SPENDABLE_BALANCE_FAILURE = '@CORE.FETCH_BCH_SPENDABLE_BALANCE_FAILURE'

// FETCH_BCH_TRANSACTION_HISTORY
export const FETCH_BCH_UNSPENDABLE_BALANCE = '@CORE.FETCH_BCH_UNSPENDABLE_BALANCE'
export const FETCH_BCH_UNSPENDABLE_BALANCE_LOADING = '@CORE.FETCH_BCH_UNSPENDABLE_BALANCE_LOADING'
export const FETCH_BCH_UNSPENDABLE_BALANCE_SUCCESS = '@CORE.FETCH_BCH_UNSPENDABLE_BALANCE_SUCCESS'
export const FETCH_BCH_UNSPENDABLE_BALANCE_FAILURE = '@CORE.FETCH_BCH_UNSPENDABLE_BALANCE_FAILURE'
11 changes: 11 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/bch/actions.js
Expand Up @@ -31,3 +31,14 @@ export const fetchTransactionHistory = (address, start, end) => ({ type: AT.FETC
export const fetchTransactionHistoryLoading = () => ({ type: AT.FETCH_BCH_TRANSACTION_HISTORY_LOADING })
export const fetchTransactionHistorySuccess = (data) => ({ type: AT.FETCH_BCH_TRANSACTION_HISTORY_SUCCESS, payload: data })
export const fetchTransactionHistoryFailure = (error) => ({ type: AT.FETCH_BCH_TRANSACTION_HISTORY_FAILURE, payload: error })

export const fetchSpendableBalance = (context) => ({ type: AT.FETCH_BCH_SPENDABLE_BALANCE, payload: { context } })
export const fetchSpendableBalanceLoading = () => ({ type: AT.FETCH_BCH_SPENDABLE_BALANCE_LOADING })
export const fetchSpendableBalanceSuccess = (data) => ({ type: AT.FETCH_BCH_SPENDABLE_BALANCE_SUCCESS, payload: data })
export const fetchSpendableBalanceFailure = (error) => ({ type: AT.FETCH_BCH_SPENDABLE_BALANCE_FAILURE, payload: error })

// FETCH_BCH_UNSPENDABLE_BALANCE
export const fetchUnspendableBalance = (context) => ({ type: AT.FETCH_BCH_UNSPENDABLE_BALANCE, payload: { context } })
export const fetchUnspendableBalanceLoading = () => ({ type: AT.FETCH_BCH_UNSPENDABLE_BALANCE_LOADING })
export const fetchUnspendableBalanceSuccess = (data) => ({ type: AT.FETCH_BCH_UNSPENDABLE_BALANCE_SUCCESS, payload: data })
export const fetchUnspendableBalanceFailure = (error) => ({ type: AT.FETCH_BCH_UNSPENDABLE_BALANCE_FAILURE, payload: error })
24 changes: 24 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/bch/reducers.js
Expand Up @@ -9,6 +9,8 @@ const INITIAL_STATE = {
latest_block: Remote.NotAsked,
rates: Remote.NotAsked,
transactions: [],
spendable_balance: Remote.NotAsked,
unspendable_balance: Remote.NotAsked,
transaction_history: Remote.NotAsked
}

Expand Down Expand Up @@ -87,6 +89,28 @@ const bchReducer = (state = INITIAL_STATE, action) => {
case AT.FETCH_BCH_TRANSACTION_HISTORY_FAILURE: {
return assoc('transaction_history', Remote.Failure(payload), state)
}
case AT.FETCH_BCH_SPENDABLE_BALANCE_LOADING: {
return assoc('spendable_balance', Remote.Loading, state)
}
case AT.FETCH_BCH_SPENDABLE_BALANCE_SUCCESS: {
const { wallet } = payload
const balance = wallet.final_balance
return assoc('spendable_balance', Remote.Success(balance), state)
}
case AT.FETCH_BCH_SPENDABLE_BALANCE_FAILURE: {
return assoc('spendable_balance', Remote.Failure(payload), state)
}
case AT.FETCH_BCH_UNSPENDABLE_BALANCE_LOADING: {
return assoc('unspendable_balance', Remote.Loading, state)
}
case AT.FETCH_BCH_UNSPENDABLE_BALANCE_SUCCESS: {
const { wallet } = payload
const balance = wallet.final_balance
return assoc('unspendable_balance', Remote.Success(balance), state)
}
case AT.FETCH_BCH_UNSPENDABLE_BALANCE_FAILURE: {
return assoc('unspendable_balance', Remote.Failure(payload), state)
}
default:
return state
}
Expand Down
Expand Up @@ -10,6 +10,8 @@ export default ({ api }) => {
yield takeLatest(AT.FETCH_BCH_RATES, dataBchSagas.fetchRates)
yield takeLatest(AT.FETCH_BCH_FEE, dataBchSagas.fetchFee)
yield fork(dataBchSagas.watchTransactions)
yield takeLatest(AT.FETCH_BCH_SPENDABLE_BALANCE, dataBchSagas.fetchSpendableBalance)
yield takeLatest(AT.FETCH_BCH_UNSPENDABLE_BALANCE, dataBchSagas.fetchUnspendableBalance)
yield takeLatest(AT.FETCH_BCH_TRANSACTION_HISTORY, dataBchSagas.fetchTransactionHistory)
}
}
30 changes: 27 additions & 3 deletions packages/blockchain-wallet-v4/src/redux/data/bch/sagas.js
Expand Up @@ -95,6 +95,28 @@ export default ({ api }) => {
}
}

const fetchSpendableBalance = function * (action) {
try {
const { context } = action.payload
yield put(A.fetchSpendableBalanceLoading())
const data = yield call(api.fetchBchData, context)
yield put(A.fetchSpendableBalanceSuccess(data))
} catch (e) {
yield put(A.fetchSpendableBalanceFailure(e))
}
}

const fetchUnspendableBalance = function * (action) {
try {
const { context } = action.payload
yield put(A.fetchUnspendableBalanceLoading())
const data = yield call(api.fetchBchData, context)
yield put(A.fetchUnspendableBalanceSuccess(data))
} catch (e) {
yield put(A.fetchUnspendableBalanceFailure(e))
}
}

const multiaddrSaga = function * (data) {
const bchData = {
addresses: indexBy(prop('address'), prop('addresses', data)),
Expand All @@ -105,11 +127,13 @@ export default ({ api }) => {
}

return {
fetchFee,
fetchData,
fetchRates,
fetchFee,
fetchUnspent,
watchTransactions,
fetchTransactionHistory,
fetchUnspent
fetchSpendableBalance,
fetchUnspendableBalance,
fetchTransactionHistory
}
}

0 comments on commit b251318

Please sign in to comment.