2018-12-15 14:36:50 -08:00
|
|
|
// @flow
|
2019-02-04 20:41:45 -08:00
|
|
|
|
2019-02-12 08:51:23 -08:00
|
|
|
import React, { PureComponent, Fragment, type Element } from 'react';
|
|
|
|
import { InfiniteLoader, AutoSizer, List } from 'react-virtualized';
|
|
|
|
import styled from 'styled-components';
|
|
|
|
import dateFns from 'date-fns';
|
2018-12-15 14:36:50 -08:00
|
|
|
|
2019-02-12 08:51:23 -08:00
|
|
|
import { TransactionItemComponent } from '../components/transaction-item';
|
2019-01-05 11:31:19 -08:00
|
|
|
import { TextComponent } from '../components/text';
|
2019-01-07 11:24:42 -08:00
|
|
|
import { EmptyTransactionsComponent } from '../components/empty-transactions';
|
2018-12-15 14:36:50 -08:00
|
|
|
|
2019-02-12 08:51:23 -08:00
|
|
|
import type { MapDispatchToProps, MapStateToProps } from '../containers/transactions';
|
2018-12-15 14:36:50 -08:00
|
|
|
|
2019-02-12 08:51:23 -08:00
|
|
|
type Props = MapDispatchToProps & MapStateToProps;
|
|
|
|
|
|
|
|
const PAGE_SIZE = 15;
|
|
|
|
const ROW_HEIGHT = 60;
|
|
|
|
const ROW_HEIGHT_WITH_HEADER = 88;
|
|
|
|
|
|
|
|
const Day = styled(TextComponent)`
|
|
|
|
text-transform: uppercase;
|
|
|
|
color: ${props => props.theme.colors.transactionsDate};
|
|
|
|
font-size: ${props => `${props.theme.fontSize.regular * 0.9}em`};
|
|
|
|
font-weight: ${props => String(props.theme.fontWeight.bold)};
|
|
|
|
margin-top: 10px;
|
|
|
|
margin-bottom: 5px;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const RoundedTransactionWrapper = styled.div`
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
${props => (props.roundPosition === 'top'
|
|
|
|
? `
|
2019-02-17 19:56:50 -08:00
|
|
|
border-top-left-radius: ${props.theme.boxBorderRadius};
|
|
|
|
border-top-right-radius: ${props.theme.boxBorderRadius};
|
|
|
|
`
|
|
|
|
: `
|
|
|
|
border-bottom-left-radius: ${props.theme.boxBorderRadius};
|
|
|
|
border-bottom-right-radius: ${props.theme.boxBorderRadius};
|
|
|
|
`
|
|
|
|
)}
|
|
|
|
`;
|
|
|
|
|
|
|
|
const ListWrapper = styled.div`
|
|
|
|
margin-top: 10px;
|
2019-02-12 08:51:23 -08:00
|
|
|
`;
|
2018-12-15 14:36:50 -08:00
|
|
|
|
2018-12-18 13:41:27 -08:00
|
|
|
export class TransactionsView extends PureComponent<Props> {
|
2018-12-15 14:36:50 -08:00
|
|
|
componentDidMount() {
|
2019-02-12 08:51:23 -08:00
|
|
|
const { getTransactions, resetTransactionsList } = this.props;
|
2019-02-17 19:56:50 -08:00
|
|
|
|
2019-02-12 08:51:23 -08:00
|
|
|
resetTransactionsList();
|
2019-02-17 19:56:50 -08:00
|
|
|
getTransactions({
|
|
|
|
count: PAGE_SIZE,
|
|
|
|
offset: 0,
|
|
|
|
shieldedTransactionsCount: 0,
|
|
|
|
});
|
2018-12-15 14:36:50 -08:00
|
|
|
}
|
|
|
|
|
2019-02-12 08:51:23 -08:00
|
|
|
isRowLoaded = ({ index }: { index: number }) => {
|
|
|
|
const { hasNextPage, transactions } = this.props;
|
|
|
|
const transactionsSize = transactions.length;
|
|
|
|
|
|
|
|
return !hasNextPage || index < transactionsSize;
|
|
|
|
};
|
|
|
|
|
|
|
|
renderTransactionWrapper = ({
|
|
|
|
index,
|
|
|
|
transactionDate,
|
|
|
|
previousTransactionDate,
|
|
|
|
nextTransactionDate,
|
|
|
|
component,
|
|
|
|
}: {|
|
|
|
|
index: number,
|
|
|
|
transactionDate: Date,
|
|
|
|
previousTransactionDate: ?Date,
|
|
|
|
nextTransactionDate: ?Date,
|
|
|
|
component: Element<*>,
|
|
|
|
|}) => {
|
|
|
|
if (
|
|
|
|
index === 0
|
|
|
|
|| (previousTransactionDate && !dateFns.isSameDay(transactionDate, previousTransactionDate))
|
|
|
|
) {
|
|
|
|
return <RoundedTransactionWrapper roundPosition='top'>{component}</RoundedTransactionWrapper>;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
nextTransactionDate
|
|
|
|
&& (nextTransactionDate && !dateFns.isSameDay(transactionDate, nextTransactionDate))
|
|
|
|
) {
|
|
|
|
return (
|
|
|
|
<RoundedTransactionWrapper roundPosition='bottom'>{component}</RoundedTransactionWrapper>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return component;
|
|
|
|
};
|
|
|
|
|
|
|
|
renderTransactions = ({ index }: { index: number }) => {
|
|
|
|
const { transactions, zecPrice } = this.props;
|
|
|
|
|
|
|
|
const transaction = transactions[index];
|
|
|
|
const previousTransaction = transactions[index - 1];
|
|
|
|
const nextTransaction = transactions[index + 1];
|
|
|
|
|
|
|
|
const transactionItem = this.renderTransactionWrapper({
|
|
|
|
transactionDate: new Date(transaction.date),
|
|
|
|
previousTransactionDate: previousTransaction ? new Date(previousTransaction.date) : null,
|
|
|
|
nextTransactionDate: nextTransaction ? new Date(nextTransaction.date) : null,
|
|
|
|
component: (
|
|
|
|
<TransactionItemComponent
|
|
|
|
address={transaction.address}
|
|
|
|
amount={transaction.amount}
|
2019-02-19 08:06:34 -08:00
|
|
|
fees={transaction.fees}
|
2019-02-12 08:51:23 -08:00
|
|
|
date={transaction.date}
|
|
|
|
transactionId={transaction.transactionId}
|
|
|
|
type={transaction.type}
|
|
|
|
zecPrice={zecPrice}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
index,
|
|
|
|
});
|
|
|
|
if (
|
|
|
|
index === 0
|
|
|
|
|| (previousTransaction
|
|
|
|
&& !dateFns.isSameDay(new Date(previousTransaction.date), new Date(transaction.date)))
|
|
|
|
) {
|
|
|
|
return (
|
|
|
|
<Fragment>
|
|
|
|
<Day value={dateFns.format(new Date(transaction.date), 'MMM DD, YYYY')} />
|
|
|
|
{transactionItem}
|
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return transactionItem;
|
|
|
|
};
|
|
|
|
|
2019-02-17 19:56:50 -08:00
|
|
|
renderRow = (
|
|
|
|
{ index, key, style }: { index: number, key: string, style: Object },
|
|
|
|
) => (
|
2019-02-12 08:51:23 -08:00
|
|
|
<div key={key} style={style}>
|
2019-02-17 19:56:50 -08:00
|
|
|
{this.isRowLoaded({ index })
|
|
|
|
? this.renderTransactions({ index })
|
|
|
|
: 'Loading...'
|
|
|
|
}
|
2019-02-12 08:51:23 -08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
|
|
|
|
getRowHeight = ({ index }: { index: number }) => {
|
|
|
|
const { transactions } = this.props;
|
|
|
|
|
|
|
|
const transaction = transactions[index];
|
|
|
|
|
|
|
|
if (
|
|
|
|
index === 0
|
|
|
|
|| !dateFns.isSameDay(new Date(transactions[index - 1].date), new Date(transaction.date))
|
|
|
|
) {
|
|
|
|
return ROW_HEIGHT_WITH_HEADER;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ROW_HEIGHT;
|
|
|
|
};
|
|
|
|
|
|
|
|
loadNextPage = () => {
|
|
|
|
const { transactions, getTransactions } = this.props;
|
|
|
|
|
|
|
|
const shieldedTransactionsCount = transactions.filter(
|
|
|
|
transaction => transaction.address === '(Shielded)',
|
|
|
|
).length;
|
|
|
|
|
|
|
|
getTransactions({ count: PAGE_SIZE, offset: transactions.length, shieldedTransactionsCount });
|
|
|
|
};
|
|
|
|
|
|
|
|
loadMoreRows = async () => {
|
|
|
|
const { isLoading } = this.props;
|
|
|
|
|
|
|
|
return isLoading ? Promise.resolve([]) : this.loadNextPage();
|
|
|
|
};
|
|
|
|
|
2018-12-15 14:36:50 -08:00
|
|
|
render() {
|
2019-02-12 08:51:23 -08:00
|
|
|
const { error, transactions, hasNextPage } = this.props;
|
|
|
|
|
|
|
|
const transactionsSize = transactions.length;
|
|
|
|
const isRowLoaded = ({ index }) => !hasNextPage || index < transactionsSize;
|
|
|
|
const rowCount = transactionsSize ? transactionsSize + 1 : transactionsSize;
|
2018-12-15 14:36:50 -08:00
|
|
|
|
|
|
|
if (error) {
|
2019-01-05 11:31:19 -08:00
|
|
|
return <TextComponent value={error} />;
|
2018-12-15 14:36:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2019-02-12 08:51:23 -08:00
|
|
|
<InfiniteLoader
|
|
|
|
isRowLoaded={isRowLoaded}
|
|
|
|
loadMoreRows={this.loadMoreRows}
|
|
|
|
rowCount={rowCount}
|
|
|
|
>
|
|
|
|
{({ onRowsRendered, registerChild }) => (
|
|
|
|
<AutoSizer>
|
|
|
|
{({ width, height }) => (
|
2019-02-17 19:56:50 -08:00
|
|
|
<ListWrapper>
|
|
|
|
<List
|
|
|
|
noRowsRenderer={EmptyTransactionsComponent}
|
|
|
|
ref={registerChild}
|
|
|
|
onRowsRendered={onRowsRendered}
|
|
|
|
rowRenderer={this.renderRow}
|
|
|
|
rowHeight={this.getRowHeight}
|
|
|
|
rowCount={transactionsSize}
|
|
|
|
width={width}
|
|
|
|
height={height - 20}
|
|
|
|
/>
|
|
|
|
</ListWrapper>
|
2019-02-12 08:51:23 -08:00
|
|
|
)}
|
|
|
|
</AutoSizer>
|
2019-01-07 11:24:42 -08:00
|
|
|
)}
|
2019-02-12 08:51:23 -08:00
|
|
|
</InfiniteLoader>
|
2018-12-15 14:36:50 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|