From 01977f91cdef379c89e8f682b39b554f497df544 Mon Sep 17 00:00:00 2001 From: apanizo Date: Tue, 17 Apr 2018 11:37:01 +0200 Subject: [PATCH 1/3] WA-230 Adding get balance selector using rr match props. Included tests --- src/routes/safe/store/selectors/index.js | 15 +++++ .../safe/store/test/balance.selector.js | 61 +++++++++++++++++++ src/routes/safe/store/test/safe.spec.js | 4 ++ src/store/index.js | 3 +- 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/routes/safe/store/test/balance.selector.js diff --git a/src/routes/safe/store/selectors/index.js b/src/routes/safe/store/selectors/index.js index 4c403eb5..1bcd96f2 100644 --- a/src/routes/safe/store/selectors/index.js +++ b/src/routes/safe/store/selectors/index.js @@ -6,6 +6,7 @@ import { type GlobalState } from '~/store/index' import { SAFE_PARAM_ADDRESS } from '~/routes/routes' import { type Safe } from '~/routes/safe/store/model/safe' import { safesMapSelector } from '~/routes/safeList/store/selectors' +import { BALANCE_REDUCER_ID } from '~/routes/safe/store/reducer/balances' type RouterProps = { match: Match, @@ -13,6 +14,8 @@ type RouterProps = { const safeAddessSelector = (state: GlobalState, props: RouterProps) => props.match.params[SAFE_PARAM_ADDRESS] || '' +const balancesSelector = (state: GlobalState) => state[BALANCE_REDUCER_ID] + export type SafeSelectorProps = Safe | typeof undefined export const safeSelector: Selector = createSelector( @@ -27,6 +30,18 @@ export const safeSelector: Selector }, ) +export const balanceSelector: Selector = createSelector( + balancesSelector, + safeAddessSelector, + (balances: Map, address: string) => { + if (!address) { + return '0' + } + + return balances.get(address) || '0' + }, +) + export default createStructuredSelector({ safe: safeSelector, }) diff --git a/src/routes/safe/store/test/balance.selector.js b/src/routes/safe/store/test/balance.selector.js new file mode 100644 index 00000000..18da3b01 --- /dev/null +++ b/src/routes/safe/store/test/balance.selector.js @@ -0,0 +1,61 @@ +// @flow +import { type Match } from 'react-router-dom' +import addBalance from '~/routes/safe/store/actions/addBalance' +import { aNewStore } from '~/store' +import { balanceSelector } from '../selectors' + +const buildMathPropsFrom = (address): Match => ({ + params: { + address, + }, + isExact: true, + path: '', + url: '', +}) + +const balanceSelectorTests = () => { + describe('Safe Selector[balanceSelector]', () => { + it('should return 0 when safe address is not found', () => { + // GIVEN + const safeAddress = 'foo' + const match = buildMathPropsFrom(safeAddress) + const store = aNewStore() + + // WHEN + const balance = balanceSelector(store.getState(), { match }) + + // THEN + expect(balance).toBe('0') + }) + + it('should return 0 when safe has no funds', async () => { + // GIVEN + const safeAddress = 'foo' + const match = buildMathPropsFrom(safeAddress) + const store = aNewStore() + + // WHEN + await store.dispatch(addBalance('bar', '1')) + const balance = balanceSelector(store.getState(), { match }) + + // THEN + expect(balance).toBe('0') + }) + + it('should return safe funds', async () => { + // GIVEN + const safeAddress = 'foo' + const match = buildMathPropsFrom(safeAddress) + const store = aNewStore() + + // WHEN + await store.dispatch(addBalance(safeAddress, '1')) + const balance = balanceSelector(store.getState(), { match }) + + // THEN + expect(balance).toBe('1') + }) + }) +} + +export default balanceSelectorTests diff --git a/src/routes/safe/store/test/safe.spec.js b/src/routes/safe/store/test/safe.spec.js index df6e0259..ea07c3ee 100644 --- a/src/routes/safe/store/test/safe.spec.js +++ b/src/routes/safe/store/test/safe.spec.js @@ -1,6 +1,7 @@ // @flow import balanceReducerTests from './balance.reducer' import safeReducerTests from './safe.reducer' +import balanceSelectorTests from './balance.selector' import safeSelectorTests from './safe.selector' describe('Safe Test suite', () => { @@ -10,4 +11,7 @@ describe('Safe Test suite', () => { // SAFE SELECTOR safeSelectorTests() + + // BALANCE SELECTOR + balanceSelectorTests() }) diff --git a/src/store/index.js b/src/store/index.js index 7538a26d..882978f1 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -33,4 +33,5 @@ const initialState = { [SAFE_REDUCER_ID]: calculateInitialState() } export const store: Store = createStore(reducers, initialState, finalCreateStore) -export const aNewStore = (): Store => createStore(reducers, initialState, finalCreateStore) +export const aNewStore = (localState?: Object): Store => + createStore(reducers, localState, finalCreateStore) From c866afcf56048eb026a6429ddbee0651a42c9050 Mon Sep 17 00:00:00 2001 From: apanizo Date: Tue, 17 Apr 2018 12:01:29 +0200 Subject: [PATCH 2/3] WA-230 Including in tests decimal eth for testing balances --- src/routes/safe/store/test/balance.reducer.js | 10 +++++----- src/routes/safe/store/test/balance.selector.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/routes/safe/store/test/balance.reducer.js b/src/routes/safe/store/test/balance.reducer.js index f54da801..923fc449 100644 --- a/src/routes/safe/store/test/balance.reducer.js +++ b/src/routes/safe/store/test/balance.reducer.js @@ -6,10 +6,10 @@ import { getWeb3 } from '~/wallets/getWeb3' import { promisify } from '~/utils/promisify' import { aDeployedSafe } from './builder/deployedSafe.builder' -const addOneEtherTo = async (address: string) => { +const addEtherTo = async (address: string, eth: string) => { const web3 = getWeb3() const accounts = await promisify(cb => web3.eth.getAccounts(cb)) - const txData = { from: accounts[0], to: address, value: web3.toWei('1', 'ether') } + const txData = { from: accounts[0], to: address, value: web3.toWei(eth, 'ether') } return promisify(cb => web3.eth.sendTransaction(txData, cb)) } @@ -34,19 +34,19 @@ const balanceReducerTests = () => { expect(balances.get(address)).toBe('0') }) - it('reducer should return 1 ETH as funds to safe with 1 ETH', async () => { + it('reducer should return 1.3456 ETH as funds to safe with 1 ETH', async () => { // GIVEN const safeTx = await aDeployedSafe(store) const address = safeTx.contractAddress // WHEN - await addOneEtherTo(address) + await addEtherTo(address, '1.3456') await store.dispatch(fetchBalance(address)) // THEN const balances = store.getState()[BALANCE_REDUCER_ID] expect(balances).not.toBe(undefined) - expect(balances.get(address)).toBe('1') + expect(balances.get(address)).toBe('1.3456') }) }) } diff --git a/src/routes/safe/store/test/balance.selector.js b/src/routes/safe/store/test/balance.selector.js index 18da3b01..b6b850e4 100644 --- a/src/routes/safe/store/test/balance.selector.js +++ b/src/routes/safe/store/test/balance.selector.js @@ -49,11 +49,11 @@ const balanceSelectorTests = () => { const store = aNewStore() // WHEN - await store.dispatch(addBalance(safeAddress, '1')) + await store.dispatch(addBalance(safeAddress, '1.3456')) const balance = balanceSelector(store.getState(), { match }) // THEN - expect(balance).toBe('1') + expect(balance).toBe('1.3456') }) }) } From 86d3c7c9c4fc4c5b4342570159aebad01f3df355 Mon Sep 17 00:00:00 2001 From: apanizo Date: Tue, 17 Apr 2018 12:42:33 +0200 Subject: [PATCH 3/3] WA-230 Adding to UI safe's balance --- src/components/layout/Paragraph/index.scss | 6 ++--- src/routes/safe/component/Layout.jsx | 4 ++-- src/routes/safe/component/Layout.stories.js | 25 ++++++++++++++++++--- src/routes/safe/component/Safe.jsx | 15 ++++++++++++- src/routes/safe/container/actions.js | 10 +++++++++ src/routes/safe/container/index.jsx | 21 ++++++++++++----- src/routes/safe/container/selector.js | 4 +++- 7 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 src/routes/safe/container/actions.js diff --git a/src/components/layout/Paragraph/index.scss b/src/components/layout/Paragraph/index.scss index ea3a5550..ed0652fd 100644 --- a/src/components/layout/Paragraph/index.scss +++ b/src/components/layout/Paragraph/index.scss @@ -4,15 +4,15 @@ } .soft { - color: #888888; + color: #888888; } .medium { - color: #686868; + color: #686868; } .dark { - color: black; + color: black; } .primary { diff --git a/src/routes/safe/component/Layout.jsx b/src/routes/safe/component/Layout.jsx index 681b227e..e3b7f636 100644 --- a/src/routes/safe/component/Layout.jsx +++ b/src/routes/safe/component/Layout.jsx @@ -6,10 +6,10 @@ import GnoSafe from './Safe' type Props = SelectorProps -const Layout = ({ safe, provider }: Props) => ( +const Layout = ({ safe, balance, provider }: Props) => ( { safe - ? + ? : } diff --git a/src/routes/safe/component/Layout.stories.js b/src/routes/safe/component/Layout.stories.js index 4ba63f70..83cfecea 100644 --- a/src/routes/safe/component/Layout.stories.js +++ b/src/routes/safe/component/Layout.stories.js @@ -14,12 +14,31 @@ const FrameDecorator = story => ( storiesOf('Routes /safe:address', module) .addDecorator(FrameDecorator) - .add('Safe undefined being connected', () => ) - .add('Safe undefined NOT connected', () => ) + .add('Safe undefined being connected', () => ( + {}} + /> + )) + .add('Safe undefined NOT connected', () => ( + {}} + /> + )) .add('Safe with 2 owners', () => { const safe = SafeFactory.twoOwnersSafe return ( - + {}} + /> ) }) diff --git a/src/routes/safe/component/Safe.jsx b/src/routes/safe/component/Safe.jsx index 7c7b4dd9..69b86137 100644 --- a/src/routes/safe/component/Safe.jsx +++ b/src/routes/safe/component/Safe.jsx @@ -10,9 +10,10 @@ import { type Safe } from '~/routes/safe/store/model/safe' type SafeProps = { safe: Safe, + balance: string, } -const GnoSafe = ({ safe }: SafeProps) => ( +const GnoSafe = ({ safe, balance }: SafeProps) => ( @@ -21,6 +22,18 @@ const GnoSafe = ({ safe }: SafeProps) => ( + + + Balance + + + + + + {balance} - ETH + + + Address diff --git a/src/routes/safe/container/actions.js b/src/routes/safe/container/actions.js new file mode 100644 index 00000000..e489176c --- /dev/null +++ b/src/routes/safe/container/actions.js @@ -0,0 +1,10 @@ +// @flow +import fetchBalance from '~/routes/safe/store/actions/fetchBalance' + +export type Actions = { + fetchBalance: typeof fetchBalance, +} + +export default { + fetchBalance, +} diff --git a/src/routes/safe/container/index.jsx b/src/routes/safe/container/index.jsx index 348fd17f..4b60b103 100644 --- a/src/routes/safe/container/index.jsx +++ b/src/routes/safe/container/index.jsx @@ -4,19 +4,30 @@ import { connect } from 'react-redux' import Page from '~/components/layout/Page' import Layout from '~/routes/safe/component/Layout' import selector, { type SelectorProps } from './selector' +import actions, { type Actions } from './actions' -type Props = SelectorProps +class SafeView extends React.PureComponent { + componentDidMount() { + const { safe, fetchBalance } = this.props + if (!safe) { return } + + const safeAddress: string = safe.get('address') + fetchBalance(safeAddress) + } -class SafeView extends React.PureComponent { render() { - const { safe, provider } = this.props + const { safe, provider, balance } = this.props return ( - + ) } } -export default connect(selector)(SafeView) +export default connect(selector, actions)(SafeView) diff --git a/src/routes/safe/container/selector.js b/src/routes/safe/container/selector.js index 86af6918..3ac175f5 100644 --- a/src/routes/safe/container/selector.js +++ b/src/routes/safe/container/selector.js @@ -1,14 +1,16 @@ // @flow import { createStructuredSelector } from 'reselect' -import { safeSelector, type SafeSelectorProps } from '~/routes/safe/store/selectors' +import { balanceSelector, safeSelector, type SafeSelectorProps } from '~/routes/safe/store/selectors' import { providerNameSelector } from '~/wallets/store/selectors/index' export type SelectorProps = { safe: SafeSelectorProps, provider: string, + balance: string, } export default createStructuredSelector({ safe: safeSelector, provider: providerNameSelector, + balance: balanceSelector, })