mirror of
https://github.com/status-im/safe-react.git
synced 2025-02-04 13:54:11 +00:00
WA-232 tokens route
This commit is contained in:
parent
d7193dcc9a
commit
0b5d14c8f2
@ -7,11 +7,11 @@ import GnoSafe from './Safe'
|
|||||||
type Props = SelectorProps
|
type Props = SelectorProps
|
||||||
|
|
||||||
const Layout = ({
|
const Layout = ({
|
||||||
safe, balances, provider, userAddress,
|
safe, tokens, provider, userAddress,
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{ safe
|
{ safe
|
||||||
? <GnoSafe safe={safe} balances={balances} userAddress={userAddress} />
|
? <GnoSafe safe={safe} tokens={tokens} userAddress={userAddress} />
|
||||||
: <NoSafe provider={provider} text="Not found safe" />
|
: <NoSafe provider={provider} text="Not found safe" />
|
||||||
}
|
}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
@ -4,7 +4,7 @@ import * as React from 'react'
|
|||||||
import { Map } from 'immutable'
|
import { Map } from 'immutable'
|
||||||
import styles from '~/components/layout/PageFrame/index.scss'
|
import styles from '~/components/layout/PageFrame/index.scss'
|
||||||
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
|
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
|
||||||
import { makeBalance } from '~/routes/safe/store/model/balance'
|
import { makeToken } from '~/routes/tokens/store/model/token'
|
||||||
import Component from './Layout'
|
import Component from './Layout'
|
||||||
|
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ const FrameDecorator = story => (
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const ethBalance = makeBalance({
|
const ethBalance = makeToken({
|
||||||
address: '0',
|
address: '0',
|
||||||
name: 'Ether',
|
name: 'Ether',
|
||||||
symbol: 'ETH',
|
symbol: 'ETH',
|
||||||
@ -30,7 +30,7 @@ storiesOf('Routes /safe:address', module)
|
|||||||
userAddress="foo"
|
userAddress="foo"
|
||||||
safe={undefined}
|
safe={undefined}
|
||||||
provider="METAMASK"
|
provider="METAMASK"
|
||||||
balances={Map()}
|
tokens={Map()}
|
||||||
fetchBalance={() => {}}
|
fetchBalance={() => {}}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
@ -39,7 +39,7 @@ storiesOf('Routes /safe:address', module)
|
|||||||
userAddress="foo"
|
userAddress="foo"
|
||||||
safe={undefined}
|
safe={undefined}
|
||||||
provider=""
|
provider=""
|
||||||
balances={Map()}
|
tokens={Map()}
|
||||||
fetchBalance={() => {}}
|
fetchBalance={() => {}}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
@ -51,7 +51,7 @@ storiesOf('Routes /safe:address', module)
|
|||||||
userAddress="foo"
|
userAddress="foo"
|
||||||
safe={safe}
|
safe={safe}
|
||||||
provider="METAMASK"
|
provider="METAMASK"
|
||||||
balances={Map().set('ETH', ethBalance)}
|
tokens={Map().set('ETH', ethBalance)}
|
||||||
fetchBalance={() => {}}
|
fetchBalance={() => {}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@ -64,7 +64,7 @@ storiesOf('Routes /safe:address', module)
|
|||||||
userAddress="foo"
|
userAddress="foo"
|
||||||
safe={safe}
|
safe={safe}
|
||||||
provider="METAMASK"
|
provider="METAMASK"
|
||||||
balances={Map().set('ETH', ethBalance)}
|
tokens={Map().set('ETH', ethBalance)}
|
||||||
fetchBalance={() => {}}
|
fetchBalance={() => {}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -17,11 +17,11 @@ import { Map } from 'immutable'
|
|||||||
import Button from '~/components/layout/Button'
|
import Button from '~/components/layout/Button'
|
||||||
import openHoc, { type Open } from '~/components/hoc/OpenHoc'
|
import openHoc, { type Open } from '~/components/hoc/OpenHoc'
|
||||||
import { type WithStyles } from '~/theme/mui'
|
import { type WithStyles } from '~/theme/mui'
|
||||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
type Props = Open & WithStyles & {
|
type Props = Open & WithStyles & {
|
||||||
balances: Map<string, Balance>,
|
tokens: Map<string, Token>,
|
||||||
onMoveFunds: (balance: Balance) => void,
|
onMoveFunds: (token: Token) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
@ -33,9 +33,9 @@ const styles = {
|
|||||||
export const MOVE_FUNDS_BUTTON_TEXT = 'Move'
|
export const MOVE_FUNDS_BUTTON_TEXT = 'Move'
|
||||||
|
|
||||||
const BalanceComponent = openHoc(({
|
const BalanceComponent = openHoc(({
|
||||||
open, toggle, balances, classes, onMoveFunds,
|
open, toggle, tokens, classes, onMoveFunds,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const hasBalances = balances.count() > 0
|
const hasBalances = tokens.count() > 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@ -53,18 +53,18 @@ const BalanceComponent = openHoc(({
|
|||||||
</ListItem>
|
</ListItem>
|
||||||
<Collapse in={open} timeout="auto">
|
<Collapse in={open} timeout="auto">
|
||||||
<List component="div" disablePadding>
|
<List component="div" disablePadding>
|
||||||
{balances.valueSeq().map((balance: Balance) => {
|
{tokens.valueSeq().map((token: Token) => {
|
||||||
const symbol = balance.get('symbol')
|
const symbol = token.get('symbol')
|
||||||
const name = balance.get('name')
|
const name = token.get('name')
|
||||||
const disabled = Number(balance.get('funds')) === 0
|
const disabled = Number(token.get('funds')) === 0
|
||||||
const onMoveFundsClick = () => onMoveFunds(balance)
|
const onMoveFundsClick = () => onMoveFunds(token)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem key={symbol} className={classNames(classes.nested, symbol)}>
|
<ListItem key={symbol} className={classNames(classes.nested, symbol)}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Img src={balance.get('logoUrl')} height={30} alt={name} />
|
<Img src={token.get('logoUrl')} height={30} alt={name} />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={name} secondary={`${balance.get('funds')} ${symbol}`} />
|
<ListItemText primary={name} secondary={`${token.get('funds')} ${symbol}`} />
|
||||||
<Button variant="raised" color="primary" onClick={onMoveFundsClick} disabled={disabled}>
|
<Button variant="raised" color="primary" onClick={onMoveFundsClick} disabled={disabled}>
|
||||||
{MOVE_FUNDS_BUTTON_TEXT}
|
{MOVE_FUNDS_BUTTON_TEXT}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -9,7 +9,7 @@ import Img from '~/components/layout/Img'
|
|||||||
import Paragraph from '~/components/layout/Paragraph'
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
import Row from '~/components/layout/Row'
|
import Row from '~/components/layout/Row'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
import Withdraw from '~/routes/safe/component/Withdraw'
|
import Withdraw from '~/routes/safe/component/Withdraw'
|
||||||
import Transactions from '~/routes/safe/component/Transactions'
|
import Transactions from '~/routes/safe/component/Transactions'
|
||||||
@ -30,7 +30,7 @@ const safeIcon = require('./assets/gnosis_safe.svg')
|
|||||||
|
|
||||||
type SafeProps = {
|
type SafeProps = {
|
||||||
safe: Safe,
|
safe: Safe,
|
||||||
balances: Map<string, Balance>,
|
tokens: Map<string, Token>,
|
||||||
userAddress: string,
|
userAddress: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ const listStyle = {
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
}
|
}
|
||||||
|
|
||||||
const getEthBalanceFrom = (balances: Map<string, Balance>) => {
|
const getEthBalanceFrom = (balances: Map<string, Token>) => {
|
||||||
const ethBalance = balances.get('ETH')
|
const ethBalance = balances.get('ETH')
|
||||||
if (!ethBalance) {
|
if (!ethBalance) {
|
||||||
return 0
|
return 0
|
||||||
@ -93,13 +93,13 @@ class GnoSafe extends React.PureComponent<SafeProps, State> {
|
|||||||
this.setState({ component: <RemoveOwner safeAddress={safe.get('address')} threshold={safe.get('threshold')} safe={safe} name={name} userToRemove={address} /> })
|
this.setState({ component: <RemoveOwner safeAddress={safe.get('address')} threshold={safe.get('threshold')} safe={safe} name={name} userToRemove={address} /> })
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoveTokens = (ercToken: Balance) => {
|
onMoveTokens = (ercToken: Token) => {
|
||||||
const { safe } = this.props
|
const { safe } = this.props
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
component: <SendToken
|
component: <SendToken
|
||||||
safe={safe}
|
safe={safe}
|
||||||
balance={ercToken}
|
token={ercToken}
|
||||||
key={ercToken.get('symbol')}
|
key={ercToken.get('symbol')}
|
||||||
onReset={this.onListTransactions}
|
onReset={this.onListTransactions}
|
||||||
/>,
|
/>,
|
||||||
@ -107,15 +107,15 @@ class GnoSafe extends React.PureComponent<SafeProps, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { safe, balances, userAddress } = this.props
|
const { safe, tokens, userAddress } = this.props
|
||||||
const { component } = this.state
|
const { component } = this.state
|
||||||
const ethBalance = getEthBalanceFrom(balances)
|
const ethBalance = getEthBalanceFrom(tokens)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row grow>
|
<Row grow>
|
||||||
<Col sm={12} top="xs" md={5} margin="xl" overflow>
|
<Col sm={12} top="xs" md={5} margin="xl" overflow>
|
||||||
<List style={listStyle}>
|
<List style={listStyle}>
|
||||||
<BalanceInfo balances={balances} onMoveFunds={this.onMoveTokens} />
|
<BalanceInfo tokens={tokens} onMoveFunds={this.onMoveTokens} />
|
||||||
<Owners
|
<Owners
|
||||||
owners={safe.owners}
|
owners={safe.owners}
|
||||||
onAddOwner={this.onAddOwner}
|
onAddOwner={this.onAddOwner}
|
||||||
|
@ -5,9 +5,9 @@ import { connect } from 'react-redux'
|
|||||||
import Stepper from '~/components/Stepper'
|
import Stepper from '~/components/Stepper'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
import { getStandardTokenContract } from '~/routes/tokens/store/actions/fetchTokens'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
import { createTransaction } from '~/wallets/createTransactions'
|
import { createTransaction } from '~/wallets/createTransactions'
|
||||||
import { getStandardTokenContract } from '~/routes/safe/store/actions/fetchBalances'
|
|
||||||
import { EMPTY_DATA } from '~/wallets/ethTransactions'
|
import { EMPTY_DATA } from '~/wallets/ethTransactions'
|
||||||
import { toNative } from '~/wallets/tokens'
|
import { toNative } from '~/wallets/tokens'
|
||||||
import actions, { type Actions } from './actions'
|
import actions, { type Actions } from './actions'
|
||||||
@ -21,7 +21,7 @@ const getSteps = () => [
|
|||||||
|
|
||||||
type Props = SelectorProps & Actions & {
|
type Props = SelectorProps & Actions & {
|
||||||
safe: Safe,
|
safe: Safe,
|
||||||
balance: Balance,
|
token: Token,
|
||||||
onReset: () => void,
|
onReset: () => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,16 +40,16 @@ const getTransferData = async (tokenAddress: string, to: string, amount: BigNumb
|
|||||||
return myToken.contract.transfer.getData(to, amount)
|
return myToken.contract.transfer.getData(to, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
const processTokenTransfer = async (safe: Safe, balance: Balance, to: string, amount: number, userAddress: string) => {
|
const processTokenTransfer = async (safe: Safe, token: Token, to: string, amount: number, userAddress: string) => {
|
||||||
const symbol = balance.get('symbol')
|
const symbol = token.get('symbol')
|
||||||
const nonce = Date.now()
|
const nonce = Date.now()
|
||||||
const name = `Send ${amount} ${balance.get('symbol')} to ${to}`
|
const name = `Send ${amount} ${token.get('symbol')} to ${to}`
|
||||||
const value = isEther(symbol) ? amount : 0
|
const value = isEther(symbol) ? amount : 0
|
||||||
const tokenAddress = balance.get('address')
|
const tokenAddress = token.get('address')
|
||||||
const destination = isEther(symbol) ? to : tokenAddress
|
const destination = isEther(symbol) ? to : tokenAddress
|
||||||
const data = isEther(symbol)
|
const data = isEther(symbol)
|
||||||
? EMPTY_DATA
|
? EMPTY_DATA
|
||||||
: await getTransferData(tokenAddress, to, await toNative(amount, balance.get('decimals')))
|
: await getTransferData(tokenAddress, to, await toNative(amount, token.get('decimals')))
|
||||||
|
|
||||||
return createTransaction(safe, name, destination, value, nonce, userAddress, data)
|
return createTransaction(safe, name, destination, value, nonce, userAddress, data)
|
||||||
}
|
}
|
||||||
@ -61,12 +61,12 @@ class SendToken extends React.Component<Props, State> {
|
|||||||
|
|
||||||
onTransaction = async (values: Object) => {
|
onTransaction = async (values: Object) => {
|
||||||
try {
|
try {
|
||||||
const { safe, balance, userAddress } = this.props
|
const { safe, token, userAddress } = this.props
|
||||||
|
|
||||||
const amount = values[TKN_VALUE_PARAM]
|
const amount = values[TKN_VALUE_PARAM]
|
||||||
const destination = values[TKN_DESTINATION_PARAM]
|
const destination = values[TKN_DESTINATION_PARAM]
|
||||||
|
|
||||||
await processTokenTransfer(safe, balance, destination, amount, userAddress)
|
await processTokenTransfer(safe, token, destination, amount, userAddress)
|
||||||
await sleep(1500)
|
await sleep(1500)
|
||||||
this.props.fetchTransactions()
|
this.props.fetchTransactions()
|
||||||
this.setState({ done: true })
|
this.setState({ done: true })
|
||||||
@ -84,10 +84,10 @@ class SendToken extends React.Component<Props, State> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { done } = this.state
|
const { done } = this.state
|
||||||
const { balance } = this.props
|
const { token } = this.props
|
||||||
const steps = getSteps()
|
const steps = getSteps()
|
||||||
const finishedButton = <Stepper.FinishButton title={SEE_TXS_BUTTON_TEXT} />
|
const finishedButton = <Stepper.FinishButton title={SEE_TXS_BUTTON_TEXT} />
|
||||||
const symbol = balance.get('symbol')
|
const symbol = token.get('symbol')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@ -98,7 +98,7 @@ class SendToken extends React.Component<Props, State> {
|
|||||||
steps={steps}
|
steps={steps}
|
||||||
onReset={this.onReset}
|
onReset={this.onReset}
|
||||||
>
|
>
|
||||||
<Stepper.Page funds={balance.get('funds')} symbol={symbol}>
|
<Stepper.Page funds={token.get('funds')} symbol={symbol}>
|
||||||
{ SendTokenForm }
|
{ SendTokenForm }
|
||||||
</Stepper.Page>
|
</Stepper.Page>
|
||||||
<Stepper.Page symbol={symbol}>
|
<Stepper.Page symbol={symbol}>
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
|
import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
|
||||||
import { fetchBalances } from '~/routes/safe/store/actions/fetchBalances'
|
import { fetchTokens } from '~/routes/tokens/store/actions/fetchTokens'
|
||||||
|
|
||||||
export type Actions = {
|
export type Actions = {
|
||||||
fetchSafe: typeof fetchSafe,
|
fetchSafe: typeof fetchSafe,
|
||||||
fetchBalances: typeof fetchBalances,
|
fetchTokens: typeof fetchTokens,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
fetchSafe,
|
fetchSafe,
|
||||||
fetchBalances,
|
fetchTokens,
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,12 @@ const TIMEOUT = process.env.NODE_ENV === 'test' ? 1500 : 15000
|
|||||||
class SafeView extends React.PureComponent<Props> {
|
class SafeView extends React.PureComponent<Props> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.intervalId = setInterval(() => {
|
this.intervalId = setInterval(() => {
|
||||||
const { safe, fetchBalances, fetchSafe } = this.props
|
const { safe, fetchTokens, fetchSafe } = this.props
|
||||||
if (!safe) {
|
if (!safe) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const safeAddress = safe.get('address')
|
const safeAddress = safe.get('address')
|
||||||
fetchBalances(safeAddress)
|
fetchTokens(safeAddress)
|
||||||
fetchSafe(safe)
|
fetchSafe(safe)
|
||||||
}, TIMEOUT)
|
}, TIMEOUT)
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ class SafeView extends React.PureComponent<Props> {
|
|||||||
|
|
||||||
if (this.props.safe) {
|
if (this.props.safe) {
|
||||||
const safeAddress = this.props.safe.get('address')
|
const safeAddress = this.props.safe.get('address')
|
||||||
this.props.fetchBalances(safeAddress)
|
this.props.fetchTokens(safeAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,13 +45,13 @@ class SafeView extends React.PureComponent<Props> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
safe, provider, balances, granted, userAddress,
|
safe, provider, tokens, granted, userAddress,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
{ granted
|
{ granted
|
||||||
? <Layout balances={balances} provider={provider} safe={safe} userAddress={userAddress} />
|
? <Layout tokens={tokens} provider={provider} safe={safe} userAddress={userAddress} />
|
||||||
: <NoRights />
|
: <NoRights />
|
||||||
}
|
}
|
||||||
</Page>
|
</Page>
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { List, Map } from 'immutable'
|
import { List, Map } from 'immutable'
|
||||||
import { createSelector, createStructuredSelector, type Selector } from 'reselect'
|
import { createSelector, createStructuredSelector, type Selector } from 'reselect'
|
||||||
import { balanceSelector, safeSelector, type RouterProps, type SafeSelectorProps } from '~/routes/safe/store/selectors'
|
import { safeSelector, type RouterProps, type SafeSelectorProps } from '~/routes/safe/store/selectors'
|
||||||
import { providerNameSelector, userAccountSelector } from '~/wallets/store/selectors/index'
|
import { providerNameSelector, userAccountSelector } from '~/wallets/store/selectors/index'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { type Owner } from '~/routes/safe/store/model/owner'
|
import { type Owner } from '~/routes/safe/store/model/owner'
|
||||||
import { type GlobalState } from '~/store/index'
|
import { type GlobalState } from '~/store/index'
|
||||||
import { sameAddress } from '~/wallets/ethAddresses'
|
import { sameAddress } from '~/wallets/ethAddresses'
|
||||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
import { tokensSelector } from '~/routes/tokens/store/selectors'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
export type SelectorProps = {
|
export type SelectorProps = {
|
||||||
safe: SafeSelectorProps,
|
safe: SafeSelectorProps,
|
||||||
provider: string,
|
provider: string,
|
||||||
balances: Map<string, Balance>,
|
tokens: Map<string, Token>,
|
||||||
userAddress: string,
|
userAddress: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ export const grantedSelector: Selector<GlobalState, RouterProps, boolean> = crea
|
|||||||
export default createStructuredSelector({
|
export default createStructuredSelector({
|
||||||
safe: safeSelector,
|
safe: safeSelector,
|
||||||
provider: providerNameSelector,
|
provider: providerNameSelector,
|
||||||
balances: balanceSelector,
|
tokens: tokensSelector,
|
||||||
granted: grantedSelector,
|
granted: grantedSelector,
|
||||||
userAddress: userAccountSelector,
|
userAddress: userAccountSelector,
|
||||||
})
|
})
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { Map } from 'immutable'
|
|
||||||
import { createAction } from 'redux-actions'
|
|
||||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
|
||||||
|
|
||||||
export const ADD_BALANCES = 'ADD_BALANCES'
|
|
||||||
|
|
||||||
type BalanceProps = {
|
|
||||||
safeAddress: string,
|
|
||||||
balances: Map<string, Balance>,
|
|
||||||
}
|
|
||||||
|
|
||||||
const addBalances = createAction(
|
|
||||||
ADD_BALANCES,
|
|
||||||
(safeAddress: string, balances: Map<string, Balance>): BalanceProps => ({
|
|
||||||
safeAddress,
|
|
||||||
balances,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
export default addBalances
|
|
@ -11,15 +11,23 @@ const buildSafesFrom = async (loadedSafes: Object): Promise<Map<string, Safe>> =
|
|||||||
const safes = Map()
|
const safes = Map()
|
||||||
|
|
||||||
const keys = Object.keys(loadedSafes)
|
const keys = Object.keys(loadedSafes)
|
||||||
const safeRecords = await Promise.all(keys.map((address: string) => buildSafe(loadedSafes[address])))
|
try {
|
||||||
|
const safeRecords = await Promise.all(keys.map((address: string) => buildSafe(loadedSafes[address])))
|
||||||
|
|
||||||
return safes.withMutations(async (map) => {
|
return safes.withMutations(async (map) => {
|
||||||
safeRecords.forEach((safe: Safe) => map.set(safe.get('address'), safe))
|
safeRecords.forEach((safe: Safe) => map.set(safe.get('address'), safe))
|
||||||
})
|
})
|
||||||
|
} catch (err) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
console.log("Error while fetching safes information")
|
||||||
|
|
||||||
|
return Map()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default () => async (dispatch: ReduxDispatch<GlobalState>) => {
|
export default () => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||||
const storedSafes = load(SAFES_KEY)
|
const storedSafes = load(SAFES_KEY)
|
||||||
|
|
||||||
const safes = storedSafes ? await buildSafesFrom(storedSafes) : Map()
|
const safes = storedSafes ? await buildSafesFrom(storedSafes) : Map()
|
||||||
|
|
||||||
return dispatch(updateSafes(safes))
|
return dispatch(updateSafes(safes))
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { Map } from 'immutable'
|
|
||||||
import { handleActions, type ActionType } from 'redux-actions'
|
|
||||||
import addBalances, { ADD_BALANCES } from '~/routes/safe/store/actions/addBalances'
|
|
||||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
|
||||||
|
|
||||||
export const BALANCE_REDUCER_ID = 'balances'
|
|
||||||
|
|
||||||
export type State = Map<string, Map<string, Balance>>
|
|
||||||
|
|
||||||
export default handleActions({
|
|
||||||
[ADD_BALANCES]: (state: State, action: ActionType<typeof addBalances>): State =>
|
|
||||||
state.update(action.payload.safeAddress, (prevSafe: Map<string, Balance>) => {
|
|
||||||
if (!prevSafe) {
|
|
||||||
return action.payload.balances
|
|
||||||
}
|
|
||||||
|
|
||||||
return prevSafe.equals(action.payload.balances) ? prevSafe : action.payload.balances
|
|
||||||
}),
|
|
||||||
}, Map())
|
|
@ -6,11 +6,9 @@ import { type GlobalState } from '~/store/index'
|
|||||||
import { SAFE_PARAM_ADDRESS } from '~/routes/routes'
|
import { SAFE_PARAM_ADDRESS } from '~/routes/routes'
|
||||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
import { safesMapSelector } from '~/routes/safeList/store/selectors'
|
import { safesMapSelector } from '~/routes/safeList/store/selectors'
|
||||||
import { BALANCE_REDUCER_ID } from '~/routes/safe/store/reducer/balances'
|
|
||||||
import { type State as TransactionsState, TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
import { type State as TransactionsState, TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
||||||
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
||||||
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
||||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
|
||||||
|
|
||||||
export type RouterProps = {
|
export type RouterProps = {
|
||||||
match: Match,
|
match: Match,
|
||||||
@ -26,14 +24,12 @@ type TransactionProps = {
|
|||||||
|
|
||||||
const safePropAddressSelector = (state: GlobalState, props: SafeProps) => props.safeAddress
|
const safePropAddressSelector = (state: GlobalState, props: SafeProps) => props.safeAddress
|
||||||
|
|
||||||
const safeParamAddressSelector = (state: GlobalState, props: RouterProps) => props.match.params[SAFE_PARAM_ADDRESS] || ''
|
|
||||||
|
|
||||||
const balancesSelector = (state: GlobalState) => state[BALANCE_REDUCER_ID]
|
|
||||||
|
|
||||||
const transactionsSelector = (state: GlobalState): TransactionsState => state[TRANSACTIONS_REDUCER_ID]
|
const transactionsSelector = (state: GlobalState): TransactionsState => state[TRANSACTIONS_REDUCER_ID]
|
||||||
|
|
||||||
const oneTransactionSelector = (state: GlobalState, props: TransactionProps) => props.transaction
|
const oneTransactionSelector = (state: GlobalState, props: TransactionProps) => props.transaction
|
||||||
|
|
||||||
|
export const safeParamAddressSelector = (state: GlobalState, props: RouterProps) => props.match.params[SAFE_PARAM_ADDRESS] || ''
|
||||||
|
|
||||||
export const safeTransactionsSelector: Selector<GlobalState, SafeProps, List<Transaction>> = createSelector(
|
export const safeTransactionsSelector: Selector<GlobalState, SafeProps, List<Transaction>> = createSelector(
|
||||||
transactionsSelector,
|
transactionsSelector,
|
||||||
safePropAddressSelector,
|
safePropAddressSelector,
|
||||||
@ -82,18 +78,6 @@ export const safeSelector: Selector<GlobalState, RouterProps, SafeSelectorProps>
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
export const balanceSelector: Selector<GlobalState, RouterProps, Map<string, Balance>> = createSelector(
|
|
||||||
balancesSelector,
|
|
||||||
safeParamAddressSelector,
|
|
||||||
(balances: Map<string, Map<string, Balance>>, address: string) => {
|
|
||||||
if (!address) {
|
|
||||||
return Map()
|
|
||||||
}
|
|
||||||
|
|
||||||
return balances.get(address) || Map()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
export default createStructuredSelector({
|
export default createStructuredSelector({
|
||||||
safe: safeSelector,
|
safe: safeSelector,
|
||||||
})
|
})
|
||||||
|
@ -29,7 +29,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
safes: Map(),
|
safes: Map(),
|
||||||
providers: makeProvider(),
|
providers: makeProvider(),
|
||||||
balances: Map(),
|
tokens: Map(),
|
||||||
transactions: Map(),
|
transactions: Map(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
safes: Map(),
|
safes: Map(),
|
||||||
providers: makeProvider(),
|
providers: makeProvider(),
|
||||||
balances: Map(),
|
tokens: Map(),
|
||||||
transactions: Map(),
|
transactions: Map(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
safes: Map(),
|
safes: Map(),
|
||||||
providers: makeProvider(),
|
providers: makeProvider(),
|
||||||
balances: Map(),
|
tokens: Map(),
|
||||||
transactions: Map(),
|
transactions: Map(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: map,
|
[SAFE_REDUCER_ID]: map,
|
||||||
providers: makeProvider(provider),
|
providers: makeProvider(provider),
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: map,
|
[SAFE_REDUCER_ID]: map,
|
||||||
providers: makeProvider(provider),
|
providers: makeProvider(provider),
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: map,
|
[SAFE_REDUCER_ID]: map,
|
||||||
providers: makeProvider(provider),
|
providers: makeProvider(provider),
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ const safeSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: Map(),
|
[SAFE_REDUCER_ID]: Map(),
|
||||||
providers: undefined,
|
providers: undefined,
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
const match: Match = buildMathPropsFrom('fooAddress')
|
const match: Match = buildMathPropsFrom('fooAddress')
|
||||||
@ -38,7 +38,7 @@ const safeSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: map,
|
[SAFE_REDUCER_ID]: map,
|
||||||
providers: undefined,
|
providers: undefined,
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: Map(),
|
[SAFE_REDUCER_ID]: Map(),
|
||||||
providers: makeProvider(),
|
providers: makeProvider(),
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: Map(),
|
transactions: Map(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: Map(),
|
[SAFE_REDUCER_ID]: Map(),
|
||||||
providers: makeProvider(),
|
providers: makeProvider(),
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: Map({ fooAddress: List([transaction]) }),
|
transactions: Map({ fooAddress: List([transaction]) }),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: Map(),
|
[SAFE_REDUCER_ID]: Map(),
|
||||||
providers: makeProvider(),
|
providers: makeProvider(),
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: Map({ fooAddress: List([transaction]) }),
|
transactions: Map({ fooAddress: List([transaction]) }),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ const grantedSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: Map(),
|
[SAFE_REDUCER_ID]: Map(),
|
||||||
providers: makeProvider(),
|
providers: makeProvider(),
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: Map({ fooAddress: List([transaction]) }),
|
transactions: Map({ fooAddress: List([transaction]) }),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ const safesListSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||||
[SAFE_REDUCER_ID]: Map(),
|
[SAFE_REDUCER_ID]: Map(),
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
const emptyList = List([])
|
const emptyList = List([])
|
||||||
@ -42,7 +42,7 @@ const safesListSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||||
[SAFE_REDUCER_ID]: map,
|
[SAFE_REDUCER_ID]: map,
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ const safesListSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||||
[SAFE_REDUCER_ID]: map,
|
[SAFE_REDUCER_ID]: map,
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ const safesListSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: map,
|
[SAFE_REDUCER_ID]: map,
|
||||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ const safesListSelectorTests = () => {
|
|||||||
const reduxStore = {
|
const reduxStore = {
|
||||||
[SAFE_REDUCER_ID]: map,
|
[SAFE_REDUCER_ID]: map,
|
||||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||||
balances: undefined,
|
tokens: undefined,
|
||||||
transactions: undefined,
|
transactions: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
90
src/routes/tokens/component/Layout.jsx
Normal file
90
src/routes/tokens/component/Layout.jsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// @flow
|
||||||
|
import * as MuiList from '@material-ui/core/List'
|
||||||
|
import * as React from 'react'
|
||||||
|
import Block from '~/components/layout/Block'
|
||||||
|
import Col from '~/components/layout/Col'
|
||||||
|
import Bold from '~/components/layout/Bold'
|
||||||
|
import Img from '~/components/layout/Img'
|
||||||
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
|
import Row from '~/components/layout/Row'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
import { type SelectorProps } from '~/routes/tokens/container/selector'
|
||||||
|
import { type Actions } from '~/routes/tokens/container/actions'
|
||||||
|
import TokenComponent from './Token'
|
||||||
|
// import AddToken from '~/routes/tokens/component/AddToken'
|
||||||
|
// import RemoveToken from '~/routes/tokens/component/RemoveToken'
|
||||||
|
|
||||||
|
const safeIcon = require('~/routes/safe/component/Safe/assets/gnosis_safe.svg')
|
||||||
|
|
||||||
|
type TokenProps = SelectorProps & Actions
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
component: React$Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
const listStyle = {
|
||||||
|
width: '100%',
|
||||||
|
}
|
||||||
|
|
||||||
|
class TokenLayout extends React.PureComponent<TokenProps, State> {
|
||||||
|
state = {
|
||||||
|
component: undefined,
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
onAddToken = () => {
|
||||||
|
const { addresses } = this.props
|
||||||
|
this.setState({ component: <AddToken/> })
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemoveToken = () => {
|
||||||
|
this.setState({ component: <RemoveToken /> })
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
onEnableToken = (token: Token) => {
|
||||||
|
const { enableToken, safe } = this.props
|
||||||
|
const safeAddress = safe.get('address')
|
||||||
|
|
||||||
|
enableToken(safeAddress, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
onDisableToken = (token: Token) => {
|
||||||
|
const { disableToken, safe } = this.props
|
||||||
|
const safeAddress = safe.get('address')
|
||||||
|
|
||||||
|
disableToken(safeAddress, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { safe, tokens } = this.props
|
||||||
|
const { component } = this.state
|
||||||
|
const name = safe ? safe.get('name') : ''
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row grow>
|
||||||
|
<Col sm={12} top="xs" md={5} margin="xl" overflow>
|
||||||
|
<MuiList style={listStyle}>
|
||||||
|
{tokens.map((token: Token) => (<TokenComponent
|
||||||
|
token={token}
|
||||||
|
onDisableToken={this.onDisableToken}
|
||||||
|
onEnableToken={this.onEnableToken}
|
||||||
|
/>))}
|
||||||
|
</MuiList>
|
||||||
|
</Col>
|
||||||
|
<Col sm={12} center="xs" md={7} margin="xl" layout="column">
|
||||||
|
<Block margin="xl">
|
||||||
|
<Paragraph size="lg" noMargin align="right">
|
||||||
|
<Bold>{name}</Bold>
|
||||||
|
</Paragraph>
|
||||||
|
</Block>
|
||||||
|
<Row grow>
|
||||||
|
<Col sm={12} center={component ? undefined : 'sm'} middle={component ? undefined : 'sm'} layout="column">
|
||||||
|
{ component || <Img alt="Safe Icon" src={safeIcon} height={330} /> }
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TokenLayout
|
107
src/routes/tokens/component/Token/index.jsx
Normal file
107
src/routes/tokens/component/Token/index.jsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// @flow
|
||||||
|
import * as React from 'react'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
import { withStyles } from '@material-ui/core/styles'
|
||||||
|
import Block from '~/components/layout/Block'
|
||||||
|
import Bold from '~/components/layout/Bold'
|
||||||
|
import Checkbox from '@material-ui/core/Checkbox'
|
||||||
|
import Card from '@material-ui/core/Card'
|
||||||
|
import CardContent from '@material-ui/core/CardContent'
|
||||||
|
import CardMedia from '@material-ui/core/CardMedia'
|
||||||
|
import Typography from '@material-ui/core/Typography'
|
||||||
|
// import Delete from '@material-ui/icons/Delete'
|
||||||
|
// import IconButton from '@material-ui/core/IconButton'
|
||||||
|
import { type WithStyles } from '~/theme/mui'
|
||||||
|
|
||||||
|
type Props = WithStyles & {
|
||||||
|
token: Token,
|
||||||
|
onRemoveToken: (balance: Token)=> void,
|
||||||
|
onEnableToken: (token: Token) => void,
|
||||||
|
onDisableToken: (token: Token) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
checked: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = theme => ({
|
||||||
|
card: {
|
||||||
|
display: 'flex',
|
||||||
|
},
|
||||||
|
details: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flex: '1 0 auto',
|
||||||
|
},
|
||||||
|
cover: {
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
},
|
||||||
|
controls: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingLeft: theme.spacing.unit,
|
||||||
|
paddingBottom: theme.spacing.unit,
|
||||||
|
},
|
||||||
|
playIcon: {
|
||||||
|
height: 38,
|
||||||
|
width: 38,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
class TokenComponent extends React.Component<Props, State> {
|
||||||
|
state = {
|
||||||
|
checked: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// onRemoveClick = () => this.props.onRemoveToken(this.props.token)
|
||||||
|
|
||||||
|
handleChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
|
||||||
|
const { checked } = e.target
|
||||||
|
const callback = checked ? this.props.onDisableToken : this.props.onDisableToken
|
||||||
|
this.setState(() => ({ checked: e.target.checked }), () => callback(this.props.token))
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { classes, token } = this.props
|
||||||
|
const name = token.get('name')
|
||||||
|
const symbol = token.get('symbol')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className={classes.card}>
|
||||||
|
<Block className={classes.details}>
|
||||||
|
<CardContent className={classes.content}>
|
||||||
|
<Typography variant="headline">{name}</Typography>
|
||||||
|
<Typography variant="subheading" color="textSecondary">
|
||||||
|
{symbol}
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
<Block className={classes.controls}>
|
||||||
|
<Bold>
|
||||||
|
{symbol}
|
||||||
|
</Bold>
|
||||||
|
<Checkbox
|
||||||
|
checked={this.state.checked}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
{/*
|
||||||
|
<IconButton aria-label="Delete" onClick={this.onRemoveClick}>
|
||||||
|
<Delete />
|
||||||
|
</IconButton>
|
||||||
|
*/}
|
||||||
|
</Block>
|
||||||
|
</Block>
|
||||||
|
<CardMedia
|
||||||
|
className={classes.cover}
|
||||||
|
image={token.get('logoUrl')}
|
||||||
|
title={name}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withStyles(styles, { withTheme: true })(TokenComponent)
|
13
src/routes/tokens/container/actions.js
Normal file
13
src/routes/tokens/container/actions.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// @flow
|
||||||
|
import enableToken from '~/routes/tokens/store/actions/enableToken'
|
||||||
|
import disableToken from '~/routes/tokens/store/actions/disableToken'
|
||||||
|
|
||||||
|
export type Actions = {
|
||||||
|
enableToken: typeof enableToken,
|
||||||
|
disableToken: typeof disableToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
enableToken,
|
||||||
|
disableToken,
|
||||||
|
}
|
31
src/routes/tokens/container/index.jsx
Normal file
31
src/routes/tokens/container/index.jsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// @flow
|
||||||
|
import * as React from 'react'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import Page from '~/components/layout/Page'
|
||||||
|
import Layout from '~/routes/tokens/component/Layout'
|
||||||
|
import selector, { type SelectorProps } from './selector'
|
||||||
|
import actions, { type Actions } from './actions'
|
||||||
|
|
||||||
|
type Props = Actions & SelectorProps
|
||||||
|
|
||||||
|
class TokensView extends React.PureComponent<Props> {
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
tokens, addresses, safe, disableToken, enableToken,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<Layout
|
||||||
|
tokens={tokens}
|
||||||
|
addresses={addresses}
|
||||||
|
safe={safe}
|
||||||
|
disableToken={disableToken}
|
||||||
|
enableToken={enableToken}
|
||||||
|
/>
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(selector, actions)(TokensView)
|
19
src/routes/tokens/container/selector.js
Normal file
19
src/routes/tokens/container/selector.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// @flow
|
||||||
|
import { List } from 'immutable'
|
||||||
|
import { createStructuredSelector } from 'reselect'
|
||||||
|
import { tokenListSelector, tokenAddressesSelector } from '~/routes/tokens/store/selectors'
|
||||||
|
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||||
|
import { safeSelector } from '~/routes/safe/store/selectors'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
|
export type SelectorProps = {
|
||||||
|
tokens: List<Token>,
|
||||||
|
addresses: List<String>,
|
||||||
|
safe: Safe,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createStructuredSelector({
|
||||||
|
safe: safeSelector,
|
||||||
|
tokens: tokenListSelector,
|
||||||
|
addresses: tokenAddressesSelector,
|
||||||
|
})
|
21
src/routes/tokens/store/actions/addTokens.js
Normal file
21
src/routes/tokens/store/actions/addTokens.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// @flow
|
||||||
|
import { Map } from 'immutable'
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
|
export const ADD_TOKENS = 'ADD_TOKENS'
|
||||||
|
|
||||||
|
type TokenProps = {
|
||||||
|
safeAddress: string,
|
||||||
|
tokens: Map<string, Token>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const addTokens = createAction(
|
||||||
|
ADD_TOKENS,
|
||||||
|
(safeAddress: string, tokens: Map<string, Token>): TokenProps => ({
|
||||||
|
safeAddress,
|
||||||
|
tokens,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
export default addTokens
|
15
src/routes/tokens/store/actions/disableToken.js
Normal file
15
src/routes/tokens/store/actions/disableToken.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// @flow
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
|
export const DISABLE_TOKEN = 'DISABLE_TOKEN'
|
||||||
|
|
||||||
|
const disableToken = createAction(
|
||||||
|
DISABLE_TOKEN,
|
||||||
|
(safeAddress: string, token: Token) => ({
|
||||||
|
safeAddress,
|
||||||
|
symbol: token.get('symbol'),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
export default disableToken
|
15
src/routes/tokens/store/actions/enableToken.js
Normal file
15
src/routes/tokens/store/actions/enableToken.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// @flow
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
|
export const ENABLE_TOKEN = 'ENABLE_TOKEN'
|
||||||
|
|
||||||
|
const enableToken = createAction(
|
||||||
|
ENABLE_TOKEN,
|
||||||
|
(safeAddress: string, token: Token) => ({
|
||||||
|
safeAddress,
|
||||||
|
symbol: token.get('symbol'),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
export default enableToken
|
@ -5,10 +5,10 @@ import type { Dispatch as ReduxDispatch } from 'redux'
|
|||||||
import StandardToken from '@gnosis.pm/util-contracts/build/contracts/StandardToken.json'
|
import StandardToken from '@gnosis.pm/util-contracts/build/contracts/StandardToken.json'
|
||||||
import { getBalanceInEtherOf, getWeb3 } from '~/wallets/getWeb3'
|
import { getBalanceInEtherOf, getWeb3 } from '~/wallets/getWeb3'
|
||||||
import { type GlobalState } from '~/store/index'
|
import { type GlobalState } from '~/store/index'
|
||||||
import { makeBalance, type Balance, type BalanceProps } from '~/routes/safe/store/model/balance'
|
import { makeToken, type Token, type TokenProps } from '~/routes/tokens/store/model/token'
|
||||||
import logo from '~/assets/icons/icon_etherTokens.svg'
|
import logo from '~/assets/icons/icon_etherTokens.svg'
|
||||||
import { ensureOnce } from '~/utils/singleton'
|
import { ensureOnce } from '~/utils/singleton'
|
||||||
import addBalances from './addBalances'
|
import addTokens from './addTokens'
|
||||||
|
|
||||||
|
|
||||||
const createStandardTokenContract = async () => {
|
const createStandardTokenContract = async () => {
|
||||||
@ -29,9 +29,9 @@ export const calculateBalanceOf = async (tokenAddress: string, address: string,
|
|||||||
.catch(() => '0')
|
.catch(() => '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchBalances = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
export const fetchTokens = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||||
const balance = await getBalanceInEtherOf(safeAddress)
|
const balance = await getBalanceInEtherOf(safeAddress)
|
||||||
const ethBalance = makeBalance({
|
const ethBalance = makeToken({
|
||||||
address: '0',
|
address: '0',
|
||||||
name: 'Ether',
|
name: 'Ether',
|
||||||
symbol: 'ETH',
|
symbol: 'ETH',
|
||||||
@ -57,17 +57,17 @@ export const fetchBalances = (safeAddress: string) => async (dispatch: ReduxDisp
|
|||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const balancesRecords = await Promise.all(json.map(async (item: BalanceProps) => {
|
const balancesRecords = await Promise.all(json.map(async (item: TokenProps) => {
|
||||||
const funds = await calculateBalanceOf(item.address, safeAddress, item.decimals)
|
const funds = await calculateBalanceOf(item.address, safeAddress, item.decimals)
|
||||||
return makeBalance({ ...item, funds })
|
return makeToken({ ...item, funds })
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const balances: Map<string, Balance> = Map().withMutations((map) => {
|
const balances: Map<string, Token> = Map().withMutations((map) => {
|
||||||
balancesRecords.forEach(record => map.set(record.get('symbol'), record))
|
balancesRecords.forEach(record => map.set(record.get('symbol'), record))
|
||||||
map.set('ETH', ethBalance)
|
map.set('ETH', ethBalance)
|
||||||
})
|
})
|
||||||
|
|
||||||
return dispatch(addBalances(safeAddress, balances))
|
return dispatch(addTokens(safeAddress, balances))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
console.log("Error fetching token balances...")
|
console.log("Error fetching token balances...")
|
@ -2,22 +2,26 @@
|
|||||||
import { Record } from 'immutable'
|
import { Record } from 'immutable'
|
||||||
import type { RecordFactory, RecordOf } from 'immutable'
|
import type { RecordFactory, RecordOf } from 'immutable'
|
||||||
|
|
||||||
export type BalanceProps = {
|
export type TokenProps = {
|
||||||
address: string,
|
address: string,
|
||||||
name: string,
|
name: string,
|
||||||
symbol: string,
|
symbol: string,
|
||||||
decimals: number,
|
decimals: number,
|
||||||
logoUrl: string,
|
logoUrl: string,
|
||||||
funds: string,
|
funds: string,
|
||||||
|
status: boolean,
|
||||||
|
removable: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeBalance: RecordFactory<BalanceProps> = Record({
|
export const makeToken: RecordFactory<TokenProps> = Record({
|
||||||
address: '',
|
address: '',
|
||||||
name: '',
|
name: '',
|
||||||
symbol: '',
|
symbol: '',
|
||||||
decimals: 0,
|
decimals: 0,
|
||||||
logoUrl: '',
|
logoUrl: '',
|
||||||
funds: '0',
|
funds: '0',
|
||||||
|
status: true,
|
||||||
|
removable: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
export type Balance = RecordOf<BalanceProps>
|
export type Token = RecordOf<TokenProps>
|
26
src/routes/tokens/store/reducer/tokens.js
Normal file
26
src/routes/tokens/store/reducer/tokens.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// @flow
|
||||||
|
import { Map } from 'immutable'
|
||||||
|
import { handleActions, type ActionType } from 'redux-actions'
|
||||||
|
import addTokens, { ADD_TOKENS } from '~/routes/tokens/store/actions/addTokens'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
import disableToken, { DISABLE_TOKEN } from '~/routes/tokens/store/actions/disableToken'
|
||||||
|
import enableToken, { ENABLE_TOKEN } from '~/routes/tokens/store/actions/enableToken'
|
||||||
|
|
||||||
|
export const TOKEN_REDUCER_ID = 'tokens'
|
||||||
|
|
||||||
|
export type State = Map<string, Map<string, Token>>
|
||||||
|
|
||||||
|
export default handleActions({
|
||||||
|
[ADD_TOKENS]: (state: State, action: ActionType<typeof addTokens>): State =>
|
||||||
|
state.update(action.payload.safeAddress, (prevSafe: Map<string, Token>) => {
|
||||||
|
if (!prevSafe) {
|
||||||
|
return action.payload.tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
return prevSafe.equals(action.payload.tokens) ? prevSafe : action.payload.tokens
|
||||||
|
}),
|
||||||
|
[DISABLE_TOKEN]: (state: State, action: ActionType<typeof disableToken>): State =>
|
||||||
|
state.setIn([action.payload.safeAddress, action.payload.symbol, 'status'], false),
|
||||||
|
[ENABLE_TOKEN]: (state: State, action: ActionType<typeof enableToken>): State =>
|
||||||
|
state.setIn([action.payload.safeAddress, action.payload.symbol, 'status'], true),
|
||||||
|
}, Map())
|
36
src/routes/tokens/store/selectors/index.js
Normal file
36
src/routes/tokens/store/selectors/index.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// @flow
|
||||||
|
import { List, Map } from 'immutable'
|
||||||
|
import { createSelector, type Selector } from 'reselect'
|
||||||
|
import { safeParamAddressSelector, type RouterProps } from '~/routes/safe/store/selectors'
|
||||||
|
import { type GlobalState } from '~/store'
|
||||||
|
import { TOKEN_REDUCER_ID } from '~/routes/tokens/store/reducer/tokens'
|
||||||
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
|
||||||
|
const balancesSelector = (state: GlobalState) => state[TOKEN_REDUCER_ID]
|
||||||
|
|
||||||
|
export const tokensSelector: Selector<GlobalState, RouterProps, Map<string, Token>> = createSelector(
|
||||||
|
balancesSelector,
|
||||||
|
safeParamAddressSelector,
|
||||||
|
(balances: Map<string, Map<string, Token>>, address: string) => {
|
||||||
|
if (!address) {
|
||||||
|
return Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
return balances.get(address) || Map()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
export const tokenListSelector = createSelector(
|
||||||
|
tokensSelector,
|
||||||
|
(balances: Map<string, Token>) => balances.toList(),
|
||||||
|
)
|
||||||
|
|
||||||
|
export const tokenAddressesSelector = createSelector(
|
||||||
|
tokenListSelector,
|
||||||
|
(balances: List<Token>) => {
|
||||||
|
const addresses = List().withMutations(list =>
|
||||||
|
balances.map(token => list.push(token.address)))
|
||||||
|
|
||||||
|
return addresses
|
||||||
|
},
|
||||||
|
)
|
@ -5,7 +5,7 @@ import { combineReducers, createStore, applyMiddleware, compose, type Reducer, t
|
|||||||
import thunk from 'redux-thunk'
|
import thunk from 'redux-thunk'
|
||||||
import provider, { PROVIDER_REDUCER_ID, type State as ProviderState } from '~/wallets/store/reducer/provider'
|
import provider, { PROVIDER_REDUCER_ID, type State as ProviderState } from '~/wallets/store/reducer/provider'
|
||||||
import safe, { SAFE_REDUCER_ID, type State as SafeState } from '~/routes/safe/store/reducer/safe'
|
import safe, { SAFE_REDUCER_ID, type State as SafeState } from '~/routes/safe/store/reducer/safe'
|
||||||
import balances, { BALANCE_REDUCER_ID, type State as BalancesState } from '~/routes/safe/store/reducer/balances'
|
import tokens, { TOKEN_REDUCER_ID, type State as TokensState } from '~/routes/tokens/store/reducer/tokens'
|
||||||
import transactions, { type State as TransactionsState, transactionsInitialState, TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
import transactions, { type State as TransactionsState, transactionsInitialState, TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
||||||
|
|
||||||
export const history = createBrowserHistory()
|
export const history = createBrowserHistory()
|
||||||
@ -20,7 +20,7 @@ const finalCreateStore = composeEnhancers(applyMiddleware(
|
|||||||
export type GlobalState = {
|
export type GlobalState = {
|
||||||
providers: ProviderState,
|
providers: ProviderState,
|
||||||
safes: SafeState,
|
safes: SafeState,
|
||||||
balances: BalancesState,
|
tokens: TokensState,
|
||||||
transactions: TransactionsState,
|
transactions: TransactionsState,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ const reducers: Reducer<GlobalState> = combineReducers({
|
|||||||
routing: routerReducer,
|
routing: routerReducer,
|
||||||
[PROVIDER_REDUCER_ID]: provider,
|
[PROVIDER_REDUCER_ID]: provider,
|
||||||
[SAFE_REDUCER_ID]: safe,
|
[SAFE_REDUCER_ID]: safe,
|
||||||
[BALANCE_REDUCER_ID]: balances,
|
[TOKEN_REDUCER_ID]: tokens,
|
||||||
[TRANSACTIONS_REDUCER_ID]: transactions,
|
[TRANSACTIONS_REDUCER_ID]: transactions,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import TestUtils from 'react-dom/test-utils'
|
import TestUtils from 'react-dom/test-utils'
|
||||||
import * as fetchBalancesAction from '~/routes/safe/store/actions/fetchBalances'
|
import * as fetchBalancesAction from '~/routes/tokens/store/actions/fetchTokens'
|
||||||
import { aNewStore } from '~/store'
|
import { aNewStore } from '~/store'
|
||||||
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||||
import { addTknTo, getTokenContract } from '~/test/utils/tokenMovements'
|
import { addTknTo, getTokenContract } from '~/test/utils/tokenMovements'
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { Map } from 'immutable'
|
import { Map } from 'immutable'
|
||||||
import { BALANCE_REDUCER_ID } from '~/routes/safe/store/reducer/balances'
|
import * as fetchTokensAction from '~/routes/tokens/store/actions/fetchTokens'
|
||||||
import * as fetchBalancesAction from '~/routes/safe/store/actions/fetchBalances'
|
|
||||||
import { aNewStore } from '~/store'
|
import { aNewStore } from '~/store'
|
||||||
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
import { type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
import { TOKEN_REDUCER_ID } from '~/routes/tokens/store/reducer/tokens'
|
||||||
import { addEtherTo, addTknTo } from '~/test/utils/tokenMovements'
|
import { addEtherTo, addTknTo } from '~/test/utils/tokenMovements'
|
||||||
import { dispatchTknBalance } from '~/test/utils/transactions/moveTokens.helper'
|
import { dispatchTknBalance } from '~/test/utils/transactions/moveTokens.helper'
|
||||||
|
|
||||||
@ -21,13 +21,13 @@ describe('Safe - redux balance property', () => {
|
|||||||
const tokenList = ['WE', '<3', 'GNO', 'OMG', 'RDN']
|
const tokenList = ['WE', '<3', 'GNO', 'OMG', 'RDN']
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
await store.dispatch(fetchBalancesAction.fetchBalances(address))
|
await store.dispatch(fetchTokensAction.fetchTokens(address))
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
const balances: Map<string, Map<string, Balance>> | typeof undefined = store.getState()[BALANCE_REDUCER_ID]
|
const tokens: Map<string, Map<string, Token>> | typeof undefined = store.getState()[TOKEN_REDUCER_ID]
|
||||||
if (!balances) throw new Error()
|
if (!tokens) throw new Error()
|
||||||
|
|
||||||
const safeBalances: Map<string, Balance> | typeof undefined = balances.get(address)
|
const safeBalances: Map<string, Token> | typeof undefined = tokens.get(address)
|
||||||
if (!safeBalances) throw new Error()
|
if (!safeBalances) throw new Error()
|
||||||
expect(safeBalances.size).toBe(6)
|
expect(safeBalances.size).toBe(6)
|
||||||
|
|
||||||
@ -41,13 +41,13 @@ describe('Safe - redux balance property', () => {
|
|||||||
it('reducer should return 0.03456 ETH as funds to safe with 0.03456 ETH', async () => {
|
it('reducer should return 0.03456 ETH as funds to safe with 0.03456 ETH', async () => {
|
||||||
// WHEN
|
// WHEN
|
||||||
await addEtherTo(address, '0.03456')
|
await addEtherTo(address, '0.03456')
|
||||||
await store.dispatch(fetchBalancesAction.fetchBalances(address))
|
await store.dispatch(fetchTokensAction.fetchTokens(address))
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
const balances: Map<string, Map<string, Balance>> | typeof undefined = store.getState()[BALANCE_REDUCER_ID]
|
const tokens: Map<string, Map<string, Token>> | typeof undefined = store.getState()[TOKEN_REDUCER_ID]
|
||||||
if (!balances) throw new Error()
|
if (!tokens) throw new Error()
|
||||||
|
|
||||||
const safeBalances: Map<string, Balance> | typeof undefined = balances.get(address)
|
const safeBalances: Map<string, Token> | typeof undefined = tokens.get(address)
|
||||||
if (!safeBalances) throw new Error()
|
if (!safeBalances) throw new Error()
|
||||||
expect(safeBalances.size).toBe(6)
|
expect(safeBalances.size).toBe(6)
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ describe('Safe - redux balance property', () => {
|
|||||||
await dispatchTknBalance(store, tokenAddress, address)
|
await dispatchTknBalance(store, tokenAddress, address)
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
const safeBalances = store.getState()[BALANCE_REDUCER_ID].get(address)
|
const safeBalances = store.getState()[TOKEN_REDUCER_ID].get(address)
|
||||||
expect(safeBalances.size).toBe(1)
|
expect(safeBalances.size).toBe(1)
|
||||||
|
|
||||||
const tknBalance = safeBalances.get('TKN')
|
const tknBalance = safeBalances.get('TKN')
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
import { Map } from 'immutable'
|
import { Map } from 'immutable'
|
||||||
import TestUtils from 'react-dom/test-utils'
|
import TestUtils from 'react-dom/test-utils'
|
||||||
import { sleep } from '~/utils/timer'
|
import { sleep } from '~/utils/timer'
|
||||||
import * as fetchBalancesAction from '~/routes/safe/store/actions/fetchBalances'
|
import * as fetchTokensAction from '~/routes/tokens/store/actions/fetchTokens'
|
||||||
import { checkMinedTx, checkPendingTx, EXPAND_BALANCE_INDEX } from '~/test/builder/safe.dom.utils'
|
import { checkMinedTx, checkPendingTx, EXPAND_BALANCE_INDEX } from '~/test/builder/safe.dom.utils'
|
||||||
import { makeBalance, type Balance } from '~/routes/safe/store/model/balance'
|
|
||||||
import addBalances from '~/routes/safe/store/actions/addBalances'
|
|
||||||
import { whenExecuted } from '~/test/utils/logTransactions'
|
import { whenExecuted } from '~/test/utils/logTransactions'
|
||||||
import SendToken from '~/routes/safe/component/SendToken'
|
import SendToken from '~/routes/safe/component/SendToken'
|
||||||
|
import { makeToken, type Token } from '~/routes/tokens/store/model/token'
|
||||||
|
import addTokens from '~/routes/tokens/store/actions/addTokens'
|
||||||
|
|
||||||
export const sendMoveTokensForm = async (
|
export const sendMoveTokensForm = async (
|
||||||
SafeDom: React$Component<any, any>,
|
SafeDom: React$Component<any, any>,
|
||||||
@ -44,9 +44,9 @@ export const sendMoveTokensForm = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const dispatchTknBalance = async (store: Store, tokenAddress: string, address: string) => {
|
export const dispatchTknBalance = async (store: Store, tokenAddress: string, address: string) => {
|
||||||
const fetchBalancesMock = jest.spyOn(fetchBalancesAction, 'fetchBalances')
|
const fetchBalancesMock = jest.spyOn(fetchTokensAction, 'fetchTokens')
|
||||||
const funds = await fetchBalancesAction.calculateBalanceOf(tokenAddress, address, 18)
|
const funds = await fetchTokensAction.calculateBalanceOf(tokenAddress, address, 18)
|
||||||
const balances: Map<string, Balance> = Map().set('TKN', makeBalance({
|
const balances: Map<string, Token> = Map().set('TKN', makeToken({
|
||||||
address: tokenAddress,
|
address: tokenAddress,
|
||||||
name: 'Token',
|
name: 'Token',
|
||||||
symbol: 'TKN',
|
symbol: 'TKN',
|
||||||
@ -54,8 +54,8 @@ export const dispatchTknBalance = async (store: Store, tokenAddress: string, add
|
|||||||
logoUrl: 'https://github.com/TrustWallet/tokens/blob/master/images/0x6810e776880c02933d47db1b9fc05908e5386b96.png?raw=true',
|
logoUrl: 'https://github.com/TrustWallet/tokens/blob/master/images/0x6810e776880c02933d47db1b9fc05908e5386b96.png?raw=true',
|
||||||
funds,
|
funds,
|
||||||
}))
|
}))
|
||||||
fetchBalancesMock.mockImplementation(() => store.dispatch(addBalances(address, balances)))
|
fetchBalancesMock.mockImplementation(() => store.dispatch(addTokens(address, balances)))
|
||||||
await store.dispatch(fetchBalancesAction.fetchBalances(address))
|
await store.dispatch(fetchTokensAction.fetchTokens(address))
|
||||||
fetchBalancesMock.mockRestore()
|
fetchBalancesMock.mockRestore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user