mirror of
https://github.com/trezor/trezor-wallet
synced 2025-01-30 01:41:01 +00:00
refactored PendingTransactions
This commit is contained in:
parent
24524d7445
commit
7f517041b1
104
src/components/Transaction/index.js
Normal file
104
src/components/Transaction/index.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/* @flow */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import colors from 'config/colors';
|
||||||
|
import Link from 'components/Link';
|
||||||
|
|
||||||
|
import type { Transaction, Network } from 'flowtype';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
tx: Transaction,
|
||||||
|
network: Network,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
border-bottom: 1px solid ${colors.DIVIDER};
|
||||||
|
padding: 14px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Addresses = styled.div`
|
||||||
|
flex: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Address = styled.div`
|
||||||
|
word-break: break-all;
|
||||||
|
padding: 2px 0px;
|
||||||
|
&:first-child {
|
||||||
|
padding-top: 0px;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Date = styled(Link)`
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
padding-right: 8px;
|
||||||
|
border-bottom: 0px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Value = styled.div`
|
||||||
|
padding-left: 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: right;
|
||||||
|
color: ${colors.GREEN_SECONDARY};
|
||||||
|
|
||||||
|
&.send {
|
||||||
|
color: ${colors.ERROR_PRIMARY};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Amount = styled.div`
|
||||||
|
border: 1px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Fee = styled.div`
|
||||||
|
border: 1px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TransactionItem = ({
|
||||||
|
tx,
|
||||||
|
network,
|
||||||
|
}: Props) => {
|
||||||
|
const url = `${network.explorer.tx}${tx.hash}`;
|
||||||
|
const date = typeof tx.timestamp === 'string' && tx.confirmations > 0 ? tx.timestamp : undefined; // TODO: format date
|
||||||
|
const addresses = (tx.type === 'send' ? tx.outputs : tx.inputs).reduce((arr, item) => arr.concat(item.addresses), []);
|
||||||
|
|
||||||
|
const currency = tx.currency || tx.network;
|
||||||
|
const isToken = currency !== tx.network;
|
||||||
|
const amount = isToken ? `${tx.amount} ${currency}` : `${tx.total} ${network.symbol}`;
|
||||||
|
const fee = isToken && tx.type === 'send' ? `${tx.fee} ${network.symbol}` : undefined;
|
||||||
|
const operation = tx.type === 'send' ? '-' : '+';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{ date && (<Date href={url} isGray>{ date }</Date>)}
|
||||||
|
<Addresses>
|
||||||
|
{ addresses.map(addr => (<Address key={addr}>{addr}</Address>)) }
|
||||||
|
{ tx.confirmations <= 0 && (
|
||||||
|
<Date href={url} isGray>Transaction hash: {tx.hash}</Date>
|
||||||
|
)}
|
||||||
|
</Addresses>
|
||||||
|
<Value className={tx.type}>
|
||||||
|
<Amount>{operation}{amount}</Amount>
|
||||||
|
{ fee && (<Fee>{operation}{fee}</Fee>) }
|
||||||
|
</Value>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionItem.propTypes = {
|
||||||
|
tx: PropTypes.object.isRequired,
|
||||||
|
network: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TransactionItem;
|
@ -1,19 +1,17 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
import React, { PureComponent } from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import colors from 'config/colors';
|
import colors from 'config/colors';
|
||||||
import ColorHash from 'color-hash';
|
|
||||||
import { H2 } from 'components/Heading';
|
import { H2 } from 'components/Heading';
|
||||||
import Link from 'components/Link';
|
import Transaction from 'components/Transaction';
|
||||||
import ScaleText from 'react-scale-text';
|
|
||||||
|
|
||||||
import type { Network } from 'reducers/LocalStorageReducer';
|
import type { Network } from 'reducers/LocalStorageReducer';
|
||||||
import type { Token } from 'reducers/TokensReducer';
|
|
||||||
import type { BaseProps } from '../../index';
|
import type { BaseProps } from '../../index';
|
||||||
|
import testData from './test.data';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
pending: $PropertyType<$ElementType<BaseProps, 'selectedAccount'>, 'pending'>,
|
pending: $PropertyType<$ElementType<BaseProps, 'selectedAccount'>, 'pending'>,
|
||||||
tokens: $PropertyType<$ElementType<BaseProps, 'selectedAccount'>, 'tokens'>,
|
|
||||||
network: Network
|
network: Network
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,153 +20,18 @@ const Wrapper = styled.div`
|
|||||||
border-top: 1px solid ${colors.DIVIDER};
|
border-top: 1px solid ${colors.DIVIDER};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledLink = styled(Link)`
|
const PendingTransactions = (props: Props) => {
|
||||||
text-decoration: none;
|
// const pending = props.pending.filter(tx => !tx.rejected).concat(testData);
|
||||||
`;
|
const pending = props.pending.filter(tx => !tx.rejected);
|
||||||
|
|
||||||
const TransactionWrapper = styled.div`
|
return (
|
||||||
border-bottom: 1px solid ${colors.DIVIDER};
|
<Wrapper>
|
||||||
padding: 14px 0;
|
<H2>Pending transactions</H2>
|
||||||
display: flex;
|
{pending.map(tx => (
|
||||||
flex-direction: row;
|
<Transaction key={tx.hash} network={props.network} tx={tx} />
|
||||||
align-items: center;
|
))}
|
||||||
|
</Wrapper>
|
||||||
&:last-child {
|
);
|
||||||
border-bottom: 0px;
|
};
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TransactionIcon = styled.div`
|
|
||||||
padding: 6px;
|
|
||||||
margin-right: 10px;
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
border-radius: 50%;
|
|
||||||
line-height: 25px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
user-select: none;
|
|
||||||
text-align: center;
|
|
||||||
color: ${props => props.textColor};
|
|
||||||
background: ${props => props.background};
|
|
||||||
border-color: ${props => props.borderColor};
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: ${props => props.color};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const P = styled.p``;
|
|
||||||
|
|
||||||
const TransactionName = styled.div`
|
|
||||||
flex: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TransactionAmount = styled.div`
|
|
||||||
color: colors.TEXT_SECONDARY;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class PendingTransactions extends PureComponent<Props> {
|
|
||||||
getPendingTransactions() {
|
|
||||||
return this.props.pending.filter(tx => !tx.rejected);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionIconColors(tx: any) {
|
|
||||||
let iconColors = {
|
|
||||||
textColor: '#fff',
|
|
||||||
background: '#000',
|
|
||||||
borderColor: '#000',
|
|
||||||
};
|
|
||||||
const bgColorFactory = new ColorHash({ lightness: 0.7 });
|
|
||||||
const textColorFactory = new ColorHash();
|
|
||||||
|
|
||||||
const isSmartContractTx = tx.currency !== this.props.network.symbol;
|
|
||||||
|
|
||||||
if (isSmartContractTx) {
|
|
||||||
const token: ?Token = this.findTransactionToken(tx.currency);
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
iconColors = {
|
|
||||||
textColor: '#ffffff',
|
|
||||||
background: '#000000',
|
|
||||||
borderColor: '#000000',
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const bgColor: string = bgColorFactory.hex(token.name);
|
|
||||||
iconColors = {
|
|
||||||
textColor: textColorFactory.hex(token.name),
|
|
||||||
background: bgColor,
|
|
||||||
borderColor: bgColor,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
iconColors = {
|
|
||||||
textColor: textColorFactory.hex(tx.network),
|
|
||||||
background: bgColorFactory.hex(tx.network),
|
|
||||||
borderColor: bgColorFactory.hex(tx.network),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return iconColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionSymbol(tx: any) {
|
|
||||||
let { symbol } = this.props.network;
|
|
||||||
const isSmartContractTx = tx.currency !== this.props.network.symbol;
|
|
||||||
if (isSmartContractTx) {
|
|
||||||
const token: ?Token = this.findTransactionToken(tx.currency);
|
|
||||||
symbol = token ? token.symbol.toUpperCase() : 'Unknown';
|
|
||||||
}
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionName(tx: any) {
|
|
||||||
let { name } = this.props.network;
|
|
||||||
const isSmartContractTx = tx.currency !== this.props.network.symbol;
|
|
||||||
if (isSmartContractTx) {
|
|
||||||
const token: ?Token = this.findTransactionToken(tx.currency);
|
|
||||||
name = token ? token.symbol.toUpperCase() : 'Unknown';
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
findTransactionToken(transactionCurrency: string) {
|
|
||||||
return this.props.tokens.find(t => t.symbol === transactionCurrency);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Wrapper>
|
|
||||||
<H2>Pending transactions</H2>
|
|
||||||
{this.getPendingTransactions().map(tx => (
|
|
||||||
<TransactionWrapper
|
|
||||||
key={tx.hash}
|
|
||||||
>
|
|
||||||
<TransactionIcon
|
|
||||||
textColor={() => this.getTransactionIconColors(tx).textColor}
|
|
||||||
background={() => this.getTransactionIconColors(tx).background}
|
|
||||||
borderColor={() => this.getTransactionIconColors(tx).borderColor}
|
|
||||||
>
|
|
||||||
<ScaleText widthOnly>
|
|
||||||
<P>{this.getTransactionSymbol(tx)}</P>
|
|
||||||
</ScaleText>
|
|
||||||
</TransactionIcon>
|
|
||||||
|
|
||||||
<TransactionName>
|
|
||||||
<StyledLink
|
|
||||||
href={`${this.props.network.explorer.tx}${tx.hash}`}
|
|
||||||
isGray
|
|
||||||
>
|
|
||||||
{this.getTransactionName(tx)}
|
|
||||||
</StyledLink>
|
|
||||||
</TransactionName>
|
|
||||||
|
|
||||||
<TransactionAmount>
|
|
||||||
{tx.currency !== this.props.network.symbol ? tx.amount : tx.total} {this.getTransactionSymbol(tx)}
|
|
||||||
</TransactionAmount>
|
|
||||||
</TransactionWrapper>
|
|
||||||
))}
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PendingTransactions;
|
export default PendingTransactions;
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
type: 'recv',
|
||||||
|
timestamp: '16:20',
|
||||||
|
address: 'a',
|
||||||
|
deviceState: 'a',
|
||||||
|
status: 'pending',
|
||||||
|
confirmations: 0,
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
addresses: ['in1'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addresses: ['in2'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{
|
||||||
|
addresses: ['out1', 'out2'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sequence: 1,
|
||||||
|
hash: '1234',
|
||||||
|
network: 'eth',
|
||||||
|
currency: 'eth',
|
||||||
|
amount: '0.001',
|
||||||
|
total: '0.001001',
|
||||||
|
fee: '0.000001',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
type: 'send',
|
||||||
|
address: 'a',
|
||||||
|
deviceState: 'a',
|
||||||
|
confirmations: 0,
|
||||||
|
status: 'pending',
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
addresses: ['in1', 'in2'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{
|
||||||
|
addresses: ['out1'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sequence: 1,
|
||||||
|
hash: '12345',
|
||||||
|
network: 'eth',
|
||||||
|
currency: 'T01',
|
||||||
|
amount: '0.001',
|
||||||
|
total: '0.001001',
|
||||||
|
fee: '0.000001',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
address: '0x73d0385F4d8E00C5e6504C6030F47BF6212736A8',
|
||||||
|
amount: '1',
|
||||||
|
confirmations: 0,
|
||||||
|
currency: 'T01',
|
||||||
|
deviceState: '4058d01c7c964787b7d06f0f32ce229088e123a042bf95aad658f1b1b99c73fc',
|
||||||
|
fee: '0.0002',
|
||||||
|
hash: '0xbf6ac83bdf29abacbca91cd4100ddd5cd8de16e72911ea7d1daec17ccbfc6099',
|
||||||
|
inputs: [{
|
||||||
|
addresses: ['0x73d0385F4d8E00C5e6504C6030F47BF6212736A8'],
|
||||||
|
}],
|
||||||
|
network: 'trop',
|
||||||
|
outputs: [{
|
||||||
|
addresses: ['0xFA01a39f8Abaeb660c3137f14A310d0b414b2A15'],
|
||||||
|
}],
|
||||||
|
sequence: 249,
|
||||||
|
status: 'pending',
|
||||||
|
timestamp: '',
|
||||||
|
total: '0.0002',
|
||||||
|
type: 'send',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
address: '0x73d0385F4d8E00C5e6504C6030F47BF6212736A8',
|
||||||
|
amount: '1',
|
||||||
|
confirmations: 0,
|
||||||
|
currency: 'trop',
|
||||||
|
deviceState: '4058d01c7c964787b7d06f0f32ce229088e123a042bf95aad658f1b1b99c73fc',
|
||||||
|
fee: '0.0002',
|
||||||
|
hash: '0xbf6ac83bdf29abacbca91cd4100ddd5cd8de16e72911ea7d1daec17ccbfc6099',
|
||||||
|
inputs: [{
|
||||||
|
addresses: ['0x73d0385F4d8E00C5e6504C6030F47BF6212736A8'],
|
||||||
|
}],
|
||||||
|
network: 'trop',
|
||||||
|
outputs: [{
|
||||||
|
addresses: ['0xFA01a39f8Abaeb660c3137f14A310d0b414b2A15'],
|
||||||
|
}],
|
||||||
|
sequence: 249,
|
||||||
|
status: 'pending',
|
||||||
|
timestamp: '',
|
||||||
|
total: '0.0002',
|
||||||
|
type: 'send',
|
||||||
|
},
|
||||||
|
];
|
Loading…
Reference in New Issue
Block a user