TxsTable wip
This commit is contained in:
parent
c66c59c326
commit
f126071669
|
@ -38,6 +38,7 @@
|
|||
"axios": "0.19.0",
|
||||
"bignumber.js": "9.0.0",
|
||||
"connected-react-router": "^6.3.1",
|
||||
"date-fns": "^1.30.1",
|
||||
"final-form": "4.14.1",
|
||||
"history": "^4.7.2",
|
||||
"immortal-db": "^1.0.2",
|
||||
|
|
|
@ -100,6 +100,7 @@ class Layout extends React.Component<Props, State> {
|
|||
activeTokens,
|
||||
createTransaction,
|
||||
fetchTransactions,
|
||||
transactions,
|
||||
} = this.props
|
||||
const { tabIndex } = this.state
|
||||
|
||||
|
@ -151,7 +152,9 @@ class Layout extends React.Component<Props, State> {
|
|||
createTransaction={createTransaction}
|
||||
/>
|
||||
)}
|
||||
{tabIndex === 1 && <Transactions fetchTransactions={fetchTransactions} safeAddress={address} />}
|
||||
{tabIndex === 1 && (
|
||||
<Transactions transactions={transactions} fetchTransactions={fetchTransactions} safeAddress={address} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// @flow
|
||||
import { format } from 'date-fns'
|
||||
import { List } from 'immutable'
|
||||
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||
import { buildOrderFieldFrom, FIXED, type SortRow } from '~/components/Table/sorting'
|
||||
import { type SortRow } from '~/components/Table/sorting'
|
||||
import { type Column } from '~/components/Table/TableHead'
|
||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||
|
||||
export const TX_TABLE_NONCE_ID = 'nonce'
|
||||
export const TX_TABLE_TYPE_ID = 'type'
|
||||
|
@ -10,51 +12,76 @@ export const TX_TABLE_DATE_ID = 'date'
|
|||
export const TX_TABLE_AMOUNT_ID = 'amount'
|
||||
export const TX_TABLE_STATUS_ID = 'status'
|
||||
|
||||
type BalanceData = {
|
||||
asset: Object,
|
||||
balance: string,
|
||||
const web3 = getWeb3()
|
||||
const { toBN, fromWei } = web3.utils
|
||||
|
||||
type TxData = {
|
||||
nonce: number,
|
||||
type: string,
|
||||
date: Date,
|
||||
amount: number | string,
|
||||
status: string,
|
||||
}
|
||||
|
||||
export type BalanceRow = SortRow<BalanceData>
|
||||
const formatDate = date => format(date, 'MMM D, YYYY - h:m:s')
|
||||
|
||||
export const getBalanceData = (activeTokens: List<Token>): List<BalanceRow> => {
|
||||
const rows = activeTokens.map((token: Token) => ({
|
||||
[BALANCE_TABLE_ASSET_ID]: { name: token.name, logoUri: token.logoUri },
|
||||
[buildOrderFieldFrom(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',
|
||||
export type BalanceRow = SortRow<TxData>
|
||||
|
||||
export const getTxTableData = (transactions: List<Transaction>): List<BalanceRow> => {
|
||||
const rows = transactions.map((tx: Transaction) => ({
|
||||
[TX_TABLE_NONCE_ID]: tx.nonce,
|
||||
[TX_TABLE_TYPE_ID]: 'Outgoing transfer',
|
||||
[TX_TABLE_DATE_ID]: formatDate(tx.isExecuted ? tx.executionDate : tx.submissionDate),
|
||||
[TX_TABLE_AMOUNT_ID]: Number(tx.value) > 0 ? fromWei(toBN(tx.value), 'ether') : 'n/a',
|
||||
[TX_TABLE_STATUS_ID]: tx.isExecuted ? 'done' : 'peding',
|
||||
}))
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
export const generateColumns = () => {
|
||||
const assetColumn: Column = {
|
||||
id: BALANCE_TABLE_ASSET_ID,
|
||||
order: true,
|
||||
const nonceColumn: Column = {
|
||||
id: TX_TABLE_NONCE_ID,
|
||||
disablePadding: false,
|
||||
label: 'Asset',
|
||||
label: 'Nonce',
|
||||
custom: false,
|
||||
width: 250,
|
||||
order: false,
|
||||
width: 50,
|
||||
}
|
||||
|
||||
const balanceColumn: Column = {
|
||||
id: BALANCE_TABLE_BALANCE_ID,
|
||||
align: 'right',
|
||||
order: true,
|
||||
const typeColumn: Column = {
|
||||
id: TX_TABLE_TYPE_ID,
|
||||
order: false,
|
||||
disablePadding: false,
|
||||
label: 'Balance',
|
||||
label: 'Type',
|
||||
custom: false,
|
||||
width: 150,
|
||||
}
|
||||
|
||||
const valueColumn: Column = {
|
||||
id: TX_TABLE_AMOUNT_ID,
|
||||
order: false,
|
||||
disablePadding: false,
|
||||
label: 'Amount',
|
||||
custom: false,
|
||||
width: 100,
|
||||
}
|
||||
|
||||
const dateColumn: Column = {
|
||||
id: TX_TABLE_DATE_ID,
|
||||
order: false,
|
||||
disablePadding: false,
|
||||
label: 'Date',
|
||||
custom: false,
|
||||
}
|
||||
|
||||
const actions: Column = {
|
||||
id: 'actions',
|
||||
const statusColumn: Column = {
|
||||
id: TX_TABLE_STATUS_ID,
|
||||
order: false,
|
||||
disablePadding: false,
|
||||
label: '',
|
||||
custom: true,
|
||||
}
|
||||
|
||||
return List([assetColumn, balanceColumn, actions])
|
||||
return List([nonceColumn, typeColumn, valueColumn, dateColumn, statusColumn])
|
||||
}
|
||||
|
|
|
@ -6,130 +6,64 @@ import { type Token } from '~/logic/tokens/store/model/token'
|
|||
import CallMade from '@material-ui/icons/CallMade'
|
||||
import CallReceived from '@material-ui/icons/CallReceived'
|
||||
import Button from '@material-ui/core/Button'
|
||||
import Checkbox from '@material-ui/core/Checkbox'
|
||||
import TableRow from '@material-ui/core/TableRow'
|
||||
import TableCell from '@material-ui/core/TableCell'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Col from '~/components/layout/Col'
|
||||
import Block from '~/components/layout/Block'
|
||||
import Row from '~/components/layout/Row'
|
||||
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 { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||
import {
|
||||
getBalanceData, generateColumns, BALANCE_TABLE_ASSET_ID, type BalanceRow, filterByZero,
|
||||
} from './dataFetcher'
|
||||
getTxTableData, generateColumns, TX_TABLE_NONCE_ID, type BalanceRow,
|
||||
} from './columns'
|
||||
import { styles } from './style'
|
||||
|
||||
export const MANAGE_TOKENS_BUTTON_TEST_ID = 'manage-tokens-btn'
|
||||
export const BALANCE_ROW_TEST_ID = 'balance-row'
|
||||
|
||||
type State = {
|
||||
hideZero: boolean,
|
||||
showToken: boolean,
|
||||
showReceive: boolean,
|
||||
sendFunds: Object,
|
||||
|
||||
}
|
||||
|
||||
type Props = {
|
||||
classes: Object,
|
||||
granted: boolean,
|
||||
tokens: List<Token>,
|
||||
activeTokens: List<Token>,
|
||||
safeAddress: string,
|
||||
safeName: string,
|
||||
etherScanLink: string,
|
||||
ethBalance: string,
|
||||
createTransaction: Function,
|
||||
transactions: List<Transaction>,
|
||||
}
|
||||
|
||||
type Action = 'Token' | 'Send' | 'Receive'
|
||||
|
||||
class Balances extends React.Component<Props, State> {
|
||||
state = {
|
||||
hideZero: false,
|
||||
showToken: false,
|
||||
sendFunds: {
|
||||
isOpen: false,
|
||||
selectedToken: undefined,
|
||||
},
|
||||
showReceive: false,
|
||||
}
|
||||
|
||||
onShow = (action: Action) => () => {
|
||||
this.setState(() => ({ [`show${action}`]: true }))
|
||||
}
|
||||
|
||||
onHide = (action: Action) => () => {
|
||||
this.setState(() => ({ [`show${action}`]: false }))
|
||||
}
|
||||
|
||||
showSendFunds = (token: Token) => {
|
||||
this.setState({
|
||||
sendFunds: {
|
||||
isOpen: true,
|
||||
selectedToken: token,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
hideSendFunds = () => {
|
||||
this.setState({
|
||||
sendFunds: {
|
||||
isOpen: false,
|
||||
selectedToken: undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
handleChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
|
||||
const { checked } = e.target
|
||||
|
||||
this.setState(() => ({ hideZero: checked }))
|
||||
}
|
||||
state = {}
|
||||
|
||||
render() {
|
||||
const {
|
||||
hideZero, showToken, showReceive, sendFunds,
|
||||
} = this.state
|
||||
const {
|
||||
classes,
|
||||
granted,
|
||||
tokens,
|
||||
safeAddress,
|
||||
activeTokens,
|
||||
safeName,
|
||||
etherScanLink,
|
||||
ethBalance,
|
||||
createTransaction,
|
||||
transactions,
|
||||
} = this.props
|
||||
|
||||
const columns = generateColumns()
|
||||
const autoColumns = columns.filter(c => !c.custom)
|
||||
const checkboxClasses = {
|
||||
root: classes.root,
|
||||
}
|
||||
|
||||
const filteredData = filterByZero(getBalanceData(activeTokens), hideZero)
|
||||
const filteredData = getTxTableData(transactions)
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Block className={classes.container}>
|
||||
<Table
|
||||
label="Balances"
|
||||
defaultOrderBy={BALANCE_TABLE_ASSET_ID}
|
||||
label="Transactions"
|
||||
defaultOrderBy={TX_TABLE_NONCE_ID}
|
||||
columns={columns}
|
||||
data={filteredData}
|
||||
size={filteredData.size}
|
||||
defaultFixed
|
||||
>
|
||||
{(sortedData: Array<BalanceRow>) => sortedData.map((row: any, index: number) => (
|
||||
<TableRow tabIndex={-1} key={index} className={classes.hide} data-testid={BALANCE_ROW_TEST_ID}>
|
||||
<TableRow tabIndex={-1} key={index} className={classes.row}>
|
||||
{autoColumns.map((column: Column) => (
|
||||
<TableCell key={column.id} style={cellWidth(column.width)} align={column.align} component="td">
|
||||
{column.id === BALANCE_TABLE_ASSET_ID ? <AssetTableCell asset={row[column.id]} /> : row[column.id]}
|
||||
<TableCell key={column.id} className={classes.cell} style={cellWidth(column.width)} align={column.align} component="td">
|
||||
{row[column.id]}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableCell component="td">
|
||||
{/* <TableCell component="td">
|
||||
<Row align="end" className={classes.actions}>
|
||||
{granted && (
|
||||
<Button
|
||||
|
@ -155,12 +89,12 @@ class Balances extends React.Component<Props, State> {
|
|||
Receive
|
||||
</Button>
|
||||
</Row>
|
||||
</TableCell>
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
))
|
||||
}
|
||||
</Table>
|
||||
</React.Fragment>
|
||||
</Block>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// @flow
|
||||
import { xs, sm, md, lg } from '~/theme/variables'
|
||||
|
||||
export const styles = (theme: Object) => ({
|
||||
container: {
|
||||
marginTop: lg,
|
||||
},
|
||||
root: {
|
||||
width: '20px',
|
||||
marginRight: sm,
|
||||
},
|
||||
zero: {
|
||||
letterSpacing: '-0.5px',
|
||||
},
|
||||
message: {
|
||||
margin: `${sm} 0`,
|
||||
},
|
||||
actionIcon: {
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
iconSmall: {
|
||||
fontSize: 16,
|
||||
},
|
||||
cell: {
|
||||
paddingTop: md,
|
||||
paddingBottom: md,
|
||||
},
|
||||
row: {
|
||||
'&:hover': {
|
||||
backgroundColor: '#fff3e2',
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
justifyContent: 'flex-end',
|
||||
visibility: 'hidden',
|
||||
},
|
||||
send: {
|
||||
minWidth: '0px',
|
||||
marginRight: sm,
|
||||
width: '70px',
|
||||
},
|
||||
receive: {
|
||||
minWidth: '0px',
|
||||
width: '95px',
|
||||
},
|
||||
leftIcon: {
|
||||
marginRight: xs,
|
||||
},
|
||||
links: {
|
||||
textDecoration: 'underline',
|
||||
'&:hover': {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
})
|
|
@ -1,12 +1,15 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import { List } from 'immutable'
|
||||
import NoTransactions from '~/routes/safe/components/Transactions/NoTransactions'
|
||||
import NoTransactions from '~/routes/safe/components/TransactionsNew/NoTransactions'
|
||||
import TxsTable from '~/routes/safe/components/TransactionsNew/TxsTable'
|
||||
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||
|
||||
type Props = {
|
||||
safeAddress: string,
|
||||
threshold: number,
|
||||
fetchTransactions: Function
|
||||
fetchTransactions: Function,
|
||||
transactions: List<Transaction>,
|
||||
}
|
||||
|
||||
class Transactions extends React.Component<Props, {}> {
|
||||
|
@ -18,9 +21,11 @@ class Transactions extends React.Component<Props, {}> {
|
|||
|
||||
render() {
|
||||
const { transactions, safeName, threshold } = this.props
|
||||
const hasTransactions = false
|
||||
const hasTransactions = transactions.size > 0
|
||||
|
||||
return <React.Fragment>{hasTransactions ? <div /> : <NoTransactions />}</React.Fragment>
|
||||
return (
|
||||
<React.Fragment>{hasTransactions ? <TxsTable transactions={transactions} /> : <NoTransactions />}</React.Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ class SafeView extends React.Component<Props> {
|
|||
tokens,
|
||||
createTransaction,
|
||||
fetchTransactions,
|
||||
transactions,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -75,6 +76,7 @@ class SafeView extends React.Component<Props> {
|
|||
granted={granted}
|
||||
createTransaction={createTransaction}
|
||||
fetchTransactions={fetchTransactions}
|
||||
transactions={transactions}
|
||||
/>
|
||||
</Page>
|
||||
)
|
||||
|
|
|
@ -13,8 +13,10 @@ import { type Safe } from '~/routes/safe/store/models/safe'
|
|||
import { type Owner } from '~/routes/safe/store/models/owner'
|
||||
import { type GlobalState } from '~/store'
|
||||
import { sameAddress } from '~/logic/wallets/ethAddresses'
|
||||
import { safeTransactionsSelector } from '~/routes/safe/store/selectors/index'
|
||||
import { orderedTokenListSelector, tokensSelector } from '~/logic/tokens/store/selectors'
|
||||
import { type Token } from '~/logic/tokens/store/model/token'
|
||||
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||
import { type TokenBalance } from '~/routes/safe/store/models/tokenBalance'
|
||||
import { safeParamAddressSelector } from '../store/selectors'
|
||||
import { getEthAsToken } from '~/logic/tokens/utils/tokenHelpers'
|
||||
|
@ -27,6 +29,7 @@ export type SelectorProps = {
|
|||
userAddress: string,
|
||||
network: string,
|
||||
safeUrl: string,
|
||||
transactions: List<Transaction>,
|
||||
}
|
||||
|
||||
export const grantedSelector: Selector<GlobalState, RouterProps, boolean> = createSelector(
|
||||
|
@ -95,4 +98,5 @@ export default createStructuredSelector<Object, *>({
|
|||
userAddress: userAccountSelector,
|
||||
network: networkSelector,
|
||||
safeUrl: safeParamAddressSelector,
|
||||
transactions: safeTransactionsSelector,
|
||||
})
|
||||
|
|
|
@ -54,6 +54,8 @@ const buildTransactionFrom = async (safeAddress: string, tx: TxServiceModel, saf
|
|||
recipient: tx.to,
|
||||
data: tx.data ? tx.data : EMPTY_DATA,
|
||||
isExecuted: tx.isExecuted,
|
||||
submissionDate: tx.submissionDate,
|
||||
executionDate: tx.executionDate,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ export type TransactionProps = {
|
|||
recipient: string,
|
||||
data: string,
|
||||
isExecuted: boolean,
|
||||
submissionDate: Date,
|
||||
executionDate: Date,
|
||||
}
|
||||
|
||||
export const makeTransaction: RecordFactory<TransactionProps> = Record({
|
||||
|
@ -21,6 +23,8 @@ export const makeTransaction: RecordFactory<TransactionProps> = Record({
|
|||
recipient: '',
|
||||
data: '',
|
||||
isExecuted: false,
|
||||
submissionDate: '',
|
||||
executionDate: '',
|
||||
})
|
||||
|
||||
export type Transaction = RecordOf<TransactionProps>
|
||||
|
|
|
@ -23,17 +23,15 @@ type TransactionProps = {
|
|||
transaction: Transaction,
|
||||
}
|
||||
|
||||
const safePropAddressSelector = (state: GlobalState, props: SafeProps) => props.safeAddress
|
||||
|
||||
const transactionsSelector = (state: GlobalState): TransactionsState => state[TRANSACTIONS_REDUCER_ID]
|
||||
|
||||
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, RouterProps, List<Transaction>> = createSelector(
|
||||
transactionsSelector,
|
||||
safePropAddressSelector,
|
||||
safeParamAddressSelector,
|
||||
(transactions: TransactionsState, address: string): List<Transaction> => {
|
||||
if (!transactions) {
|
||||
return List([])
|
||||
|
|
|
@ -5713,6 +5713,11 @@ data-urls@^1.0.0:
|
|||
whatwg-mimetype "^2.2.0"
|
||||
whatwg-url "^7.0.0"
|
||||
|
||||
date-fns@^1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
|
||||
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
|
||||
|
||||
date-now@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
||||
|
|
Loading…
Reference in New Issue