aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/components/trade_history/trade_history.tsx
blob: 84c0f70a82927a2bd73f0e30e64cf82c04327fdc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import * as _ from 'lodash';
import Divider from 'material-ui/Divider';
import Paper from 'material-ui/Paper';
import * as React from 'react';
import { TradeHistoryItem } from 'ts/components/trade_history/trade_history_item';
import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage';
import { Fill, TokenByAddress } from 'ts/types';
import { utils } from 'ts/utils/utils';

const FILL_POLLING_INTERVAL = 1000;

interface TradeHistoryProps {
    tokenByAddress: TokenByAddress;
    userAddress: string;
    networkId: number;
    isFullWidth?: boolean;
    shouldHideHeader?: boolean;
    isScrollable?: boolean;
}

interface TradeHistoryState {
    sortedFills: Fill[];
}

export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistoryState> {
    public static defaultProps: Partial<TradeHistoryProps> = {
        isFullWidth: false,
        shouldHideHeader: false,
        isScrollable: true,
    };
    private _fillPollingIntervalId: number;
    public constructor(props: TradeHistoryProps) {
        super(props);
        const sortedFills = this._getSortedFills();
        this.state = {
            sortedFills,
        };
    }
    public componentWillMount(): void {
        this._startPollingForFills();
    }
    public componentWillUnmount(): void {
        this._stopPollingForFills();
    }
    public componentDidMount(): void {
        window.scrollTo(0, 0);
    }
    public render(): React.ReactNode {
        const rootClassName = !this.props.isFullWidth ? 'lg-px4 md-px4 sm-px2' : undefined;
        return (
            <div className={rootClassName}>
                {!this.props.shouldHideHeader && (
                    <div>
                        <h3>Trade history</h3>
                        <Divider />
                    </div>
                )}
                {this.props.isScrollable ? (
                    <div className="pt2" style={{ height: 608, overflow: 'scroll' }}>
                        {this._renderTrades()}
                    </div>
                ) : (
                    this._renderTrades()
                )}
            </div>
        );
    }
    private _renderTrades(): React.ReactNode {
        const numNonCustomFills = this._numFillsWithoutCustomERC20Tokens();
        if (numNonCustomFills === 0) {
            return this._renderEmptyNotice();
        }

        return _.map(this.state.sortedFills, (fill, index) => {
            return (
                <TradeHistoryItem
                    key={`${fill.orderHash}-${fill.filledTakerTokenAmount}-${index}`}
                    fill={fill}
                    tokenByAddress={this.props.tokenByAddress}
                    userAddress={this.props.userAddress}
                    networkId={this.props.networkId}
                />
            );
        });
    }
    private _renderEmptyNotice(): React.ReactNode {
        return (
            <Paper className="mt1 p2 mx-auto center" style={{ width: '80%' }}>
                No filled orders yet.
            </Paper>
        );
    }
    private _numFillsWithoutCustomERC20Tokens(): number {
        let numNonCustomFills = 0;
        const tokens = _.values(this.props.tokenByAddress);
        _.each(this.state.sortedFills, fill => {
            const takerToken = _.find(tokens, token => {
                return token.address === fill.takerToken;
            });
            const makerToken = _.find(tokens, token => {
                return token.address === fill.makerToken;
            });
            // For now we don't show history items for orders using custom ERC20
            // tokens the client does not know how to display.
            // TODO: Try to retrieve the name/symbol of an unknown token in order to display it
            // Be sure to remove similar logic in trade_history_item.tsx
            if (!_.isUndefined(takerToken) && !_.isUndefined(makerToken)) {
                numNonCustomFills += 1;
            }
        });
        return numNonCustomFills;
    }
    private _startPollingForFills(): void {
        this._fillPollingIntervalId = window.setInterval(() => {
            const sortedFills = this._getSortedFills();
            if (!utils.deepEqual(sortedFills, this.state.sortedFills)) {
                this.setState({
                    sortedFills,
                });
            }
        }, FILL_POLLING_INTERVAL);
    }
    private _stopPollingForFills(): void {
        clearInterval(this._fillPollingIntervalId);
    }
    private _getSortedFills(): Fill[] {
        const fillsByHash = tradeHistoryStorage.getUserFillsByHash(this.props.userAddress, this.props.networkId);
        const fills = _.values(fillsByHash);
        const sortedFills = _.sortBy(fills, [(fill: Fill) => fill.blockTimestamp * -1]);
        return sortedFills;
    }
}