diff --git a/src/components/Table/TableHead.jsx b/src/components/Table/TableHead.jsx index 7a400200..3ca33152 100644 --- a/src/components/Table/TableHead.jsx +++ b/src/components/Table/TableHead.jsx @@ -15,6 +15,7 @@ export type Column = { label: string, custom: boolean, // If content will be rendered by user manually width?: number, + static?: boolean, // If content can't be sorted by values in the column } export const cellWidth = (width: number | typeof undefined) => { @@ -57,7 +58,7 @@ class GnoTableHead extends React.PureComponent { {column.label} diff --git a/src/components/Table/sorting.js b/src/components/Table/sorting.js index bbe345ad..2375f911 100644 --- a/src/components/Table/sorting.js +++ b/src/components/Table/sorting.js @@ -23,7 +23,7 @@ const desc = (a: Object, b: Object, orderBy: string, orderProp: boolean) => { } // eslint-disable-next-line -export const stableSort = (array: Array, cmp: any, fixed: boolean): Array => { +export const stableSort = (array: Array, cmp: any, fixed: boolean): Array => { const fixedElems: Array = fixed ? array.filter((elem: any) => elem.fixed) : [] const data: Array = fixed ? array.filter((elem: any) => !elem[FIXED]) : array const stabilizedThis = data.map((el, index) => [el, index]) diff --git a/src/routes/safe/components/Balances/dataFetcher.js b/src/routes/safe/components/Balances/dataFetcher.js index 1cd13cbf..3a39d9c0 100644 --- a/src/routes/safe/components/Balances/dataFetcher.js +++ b/src/routes/safe/components/Balances/dataFetcher.js @@ -4,6 +4,7 @@ import { type Token } from '~/logic/tokens/store/model/token' import { buildOrderFieldFrom, FIXED, type SortRow } from '~/components/Table/sorting' import { type Column } from '~/components/Table/TableHead' +export const BALANCE_TABLE_IMAGE_ID = 'image' export const BALANCE_TABLE_ASSET_ID = 'asset' export const BALANCE_TABLE_BALANCE_ID = 'balance' export const BALANCE_TABLE_VALUE_ID = 'value' @@ -17,7 +18,8 @@ export type BalanceRow = SortRow export const getBalanceData = (activeTokens: List): List => { const rows = activeTokens.map((token: Token) => ({ - [BALANCE_TABLE_ASSET_ID]: { name: token.name, logoUri: token.logoUri }, + [BALANCE_TABLE_IMAGE_ID]: token.logoUri, + [BALANCE_TABLE_ASSET_ID]: token.name, [BALANCE_TABLE_BALANCE_ID]: `${token.balance} ${token.symbol}`, [buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)]: Number(token.balance), [FIXED]: token.get('symbol') === 'ETH', @@ -27,7 +29,17 @@ export const getBalanceData = (activeTokens: List): List => { } export const generateColumns = () => { - const assetRow: Column = { + const imageColumn: Column = { + id: BALANCE_TABLE_IMAGE_ID, + order: false, + static: true, + label: '', + custom: false, + disablePadding: true, + width: 30, + } + + const assetColumn: Column = { id: BALANCE_TABLE_ASSET_ID, order: false, disablePadding: false, @@ -36,7 +48,7 @@ export const generateColumns = () => { width: 250, } - const balanceRow: Column = { + const balanceColumn: Column = { id: BALANCE_TABLE_BALANCE_ID, align: 'right', order: true, @@ -53,7 +65,7 @@ export const generateColumns = () => { custom: true, } - return List([assetRow, balanceRow, actions]) + return List([imageColumn, assetColumn, balanceColumn, actions]) } export const filterByZero = (data: List, hideZero: boolean): List => data.filter((row: BalanceRow) => (hideZero ? row[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)] !== 0 : true)) diff --git a/src/routes/safe/components/Balances/index.jsx b/src/routes/safe/components/Balances/index.jsx index b18a74c5..ce310f9f 100644 --- a/src/routes/safe/components/Balances/index.jsx +++ b/src/routes/safe/components/Balances/index.jsx @@ -12,14 +12,16 @@ import TableCell from '@material-ui/core/TableCell' import { withStyles } from '@material-ui/core/styles' import Col from '~/components/layout/Col' import Row from '~/components/layout/Row' +import Img from '~/components/layout/Img' +import ButtonLink from '~/components/layout/ButtonLink' import Paragraph from '~/components/layout/Paragraph' import Modal from '~/components/Modal' import { type Column, cellWidth } from '~/components/Table/TableHead' import Table from '~/components/Table' import { - getBalanceData, generateColumns, BALANCE_TABLE_ASSET_ID, type BalanceRow, filterByZero, + getBalanceData, generateColumns, BALANCE_TABLE_IMAGE_ID, BALANCE_TABLE_BALANCE_ID, type BalanceRow, filterByZero, } from './dataFetcher' -import AssetTableCell from './AssetTableCell' +import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils' import Tokens from './Tokens' import SendModal from './SendModal' import Receive from './Receive' @@ -127,9 +129,7 @@ class Balances extends React.Component { Hide zero balances - - Manage Tokens - + Manage Tokens { { {autoColumns.map((column: Column) => ( - {column.id === BALANCE_TABLE_ASSET_ID ? : row[column.id]} + {column.id === BALANCE_TABLE_IMAGE_ID ? Logo : row[column.id]} ))} diff --git a/src/routes/safe/components/Balances/style.js b/src/routes/safe/components/Balances/style.js index 38ca7014..5418fa88 100644 --- a/src/routes/safe/components/Balances/style.js +++ b/src/routes/safe/components/Balances/style.js @@ -25,6 +25,9 @@ export const styles = (theme: Object) => ({ '&:hover $actions': { visibility: 'initial', }, + '&:focus $actions': { + visibility: 'initial', + }, }, actions: { justifyContent: 'flex-end', diff --git a/src/test/tokens.dom.adding.test.js b/src/test/tokens.dom.adding.test.js index 5322d820..84d55895 100644 --- a/src/test/tokens.dom.adding.test.js +++ b/src/test/tokens.dom.adding.test.js @@ -1,5 +1,4 @@ // @flow -import * as TestUtils from 'react-dom/test-utils' import { getWeb3 } from '~/logic/wallets/getWeb3' import { type Match } from 'react-router-dom' import { getFirstTokenContract, getSecondTokenContract } from '~/test/utils/tokenMovements' @@ -7,60 +6,60 @@ import { aNewStore } from '~/store' import { aMinedSafe } from '~/test/builder/safe.redux.builder' import { travelToTokens } from '~/test/builder/safe.dom.utils' import { sleep } from '~/utils/timer' -import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps' +import { buildMatchPropsFrom } from '~/test/utils/buildReactRouterProps' import { tokenListSelector } from '~/logic/tokens/store/selectors' import { testToken } from '~/test/builder/tokens.dom.utils' import * as fetchTokensModule from '~/logic/tokens/store/actions/fetchTokens' import * as enhancedFetchModule from '~/utils/fetch' describe('DOM > Feature > Add new ERC 20 Tokens', () => { - // let web3 - // let accounts - // let firstErc20Token - // let secondErc20Token + let web3 + let accounts + let firstErc20Token + let secondErc20Token - // beforeAll(async () => { - // web3 = getWeb3() - // accounts = await web3.eth.getAccounts() - // firstErc20Token = await getFirstTokenContract(web3, accounts[0]) - // secondErc20Token = await getSecondTokenContract(web3, accounts[0]) + beforeAll(async () => { + web3 = getWeb3() + accounts = await web3.eth.getAccounts() + firstErc20Token = await getFirstTokenContract(web3, accounts[0]) + secondErc20Token = await getSecondTokenContract(web3, accounts[0]) - // // $FlowFixMe - // enhancedFetchModule.enhancedFetch = jest.fn() - // enhancedFetchModule.enhancedFetch.mockImplementation(() => Promise.resolve({ - // results: [ - // { - // address: firstErc20Token.address, - // name: 'First Token Example', - // symbol: 'FTE', - // decimals: 18, - // logoUri: 'https://upload.wikimedia.org/wikipedia/commons/c/c0/Earth_simple_icon.png', - // }, - // ], - // })) - // }) + // $FlowFixMe + enhancedFetchModule.enhancedFetch = jest.fn() + enhancedFetchModule.enhancedFetch.mockImplementation(() => Promise.resolve({ + results: [ + { + address: firstErc20Token.address, + name: 'First Token Example', + symbol: 'FTE', + decimals: 18, + logoUri: 'https://upload.wikimedia.org/wikipedia/commons/c/c0/Earth_simple_icon.png', + }, + ], + })) + }) it('adds a second erc 20 token filling the form', async () => { - // // GIVEN - // const store = aNewStore() - // const safeAddress = await aMinedSafe(store) - // await store.dispatch(fetchTokensModule.fetchTokens(safeAddress)) - // const TokensDom = await travelToTokens(store, safeAddress) - // await sleep(400) - // const tokens = TestUtils.scryRenderedComponentsWithType(TokensDom, TokenComponent) - // expect(tokens.length).toBe(2) - // testToken(tokens[0].props.token, 'FTE', false) - // testToken(tokens[1].props.token, 'ETH', true) - // // WHEN - // await clickOnAddToken(TokensDom) - // await fillAddress(TokensDom, secondErc20Token) - // await fillHumanReadableInfo(TokensDom) - // // THEN - // const match: Match = buildMathPropsFrom(safeAddress) - // const tokenList = tokenListSelector(store.getState(), { match }) - // expect(tokenList.count()).toBe(3) - // testToken(tokenList.get(0), 'FTE', false) - // testToken(tokenList.get(1), 'ETH', true) - // testToken(tokenList.get(2), 'TKN', true) + // GIVEN + const store = aNewStore() + const safeAddress = await aMinedSafe(store) + await store.dispatch(fetchTokensModule.fetchTokens(safeAddress)) + const TokensDom = await travelToTokens(store, safeAddress) + await sleep(400) + const tokens = TestUtils.scryRenderedComponentsWithType(TokensDom, TokenComponent) + expect(tokens.length).toBe(2) + testToken(tokens[0].props.token, 'FTE', false) + testToken(tokens[1].props.token, 'ETH', true) + // WHEN + await clickOnAddToken(TokensDom) + await fillAddress(TokensDom, secondErc20Token) + await fillHumanReadableInfo(TokensDom) + // THEN + const match: Match = buildMathPropsFrom(safeAddress) + const tokenList = tokenListSelector(store.getState(), { match }) + expect(tokenList.count()).toBe(3) + testToken(tokenList.get(0), 'FTE', false) + testToken(tokenList.get(1), 'ETH', true) + testToken(tokenList.get(2), 'TKN', true) }) }) diff --git a/src/test/utils/DOMNavigation/index.js b/src/test/utils/DOMNavigation/index.js new file mode 100644 index 00000000..334e856d --- /dev/null +++ b/src/test/utils/DOMNavigation/index.js @@ -0,0 +1,3 @@ +// @flow + +export * from './tokens' \ No newline at end of file diff --git a/src/test/utils/DOMNavigation/tokens.js b/src/test/utils/DOMNavigation/tokens.js new file mode 100644 index 00000000..ac885a0e --- /dev/null +++ b/src/test/utils/DOMNavigation/tokens.js @@ -0,0 +1,8 @@ +// @flow +import { fireEvent } from '@testing-library/reactß' + +const clickOnManageTokens = (dom) => { + const btn = dom.findByTestId() + + +} \ No newline at end of file