aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
blob: 4b99933328c43d9ec5dbbe9532e07bae353616f5 (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
import { AssetBuyer } from '@0x/asset-buyer';
import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import * as React from 'react';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';

import { ERC20AssetAmountInput, ERC20AssetAmountInputProps } from '../components/erc20_asset_amount_input';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
import { ColorOption } from '../style/theme';
import { AffiliateInfo, ERC20Asset, Omit, OrderProcessState, QuoteFetchOrigin } from '../types';
import { buyQuoteUpdater } from '../util/buy_quote_updater';

export interface SelectedERC20AssetAmountInputProps {
    fontColor?: ColorOption;
    startingFontSizePx: number;
    onSelectAssetClick?: (asset?: ERC20Asset) => void;
}

interface ConnectedState {
    assetBuyer: AssetBuyer;
    value?: BigNumber;
    asset?: ERC20Asset;
    isInputDisabled: boolean;
    numberOfAssetsAvailable?: number;
    affiliateInfo?: AffiliateInfo;
    canSelectOtherAsset: boolean;
}

interface ConnectedDispatch {
    updateBuyQuote: (
        assetBuyer: AssetBuyer,
        value?: BigNumber,
        asset?: ERC20Asset,
        affiliateInfo?: AffiliateInfo,
    ) => void;
}

type ConnectedProps = Omit<ERC20AssetAmountInputProps, keyof SelectedERC20AssetAmountInputProps>;

type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps;

const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => {
    const processState = state.buyOrderState.processState;
    const isInputEnabled = processState === OrderProcessState.None || processState === OrderProcessState.Failure;
    const isInputDisabled = !isInputEnabled;
    const selectedAsset =
        !_.isUndefined(state.selectedAsset) && state.selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20
            ? (state.selectedAsset as ERC20Asset)
            : undefined;
    const numberOfAssetsAvailable = _.isUndefined(state.availableAssets) ? undefined : state.availableAssets.length;
    const canSelectOtherAsset =
        numberOfAssetsAvailable && numberOfAssetsAvailable > 1
            ? isInputEnabled || processState === OrderProcessState.Success
            : false;

    const assetBuyer = state.providerState.assetBuyer;
    return {
        assetBuyer,
        value: state.selectedAssetUnitAmount,
        asset: selectedAsset,
        isInputDisabled,
        numberOfAssetsAvailable,
        affiliateInfo: state.affiliateInfo,
        canSelectOtherAsset,
    };
};

const debouncedUpdateBuyQuoteAsync = _.debounce(buyQuoteUpdater.updateBuyQuoteAsync.bind(buyQuoteUpdater), 200, {
    trailing: true,
}) as typeof buyQuoteUpdater.updateBuyQuoteAsync;

const mapDispatchToProps = (
    dispatch: Dispatch<Action>,
    _ownProps: SelectedERC20AssetAmountInputProps,
): ConnectedDispatch => ({
    updateBuyQuote: (assetBuyer, value, asset, affiliateInfo) => {
        // Update the input
        dispatch(actions.updateSelectedAssetAmount(value));
        // invalidate the last buy quote.
        dispatch(actions.updateLatestBuyQuote(undefined));
        // reset our buy state
        dispatch(actions.setBuyOrderStateNone());

        if (!_.isUndefined(value) && value.isGreaterThan(0) && !_.isUndefined(asset)) {
            // even if it's debounced, give them the illusion it's loading
            dispatch(actions.setQuoteRequestStatePending());
            // tslint:disable-next-line:no-floating-promises
            debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, QuoteFetchOrigin.Manual, {
                setPending: true,
                dispatchErrors: true,
                affiliateInfo,
            });
        }
    },
});

const mergeProps = (
    connectedState: ConnectedState,
    connectedDispatch: ConnectedDispatch,
    ownProps: SelectedERC20AssetAmountInputProps,
): FinalProps => {
    return {
        ...ownProps,
        asset: connectedState.asset,
        value: connectedState.value,
        onChange: (value, asset) => {
            connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset, connectedState.affiliateInfo);
        },
        isInputDisabled: connectedState.isInputDisabled,
        numberOfAssetsAvailable: connectedState.numberOfAssetsAvailable,
        canSelectOtherAsset: connectedState.canSelectOtherAsset,
    };
};

export const SelectedERC20AssetAmountInput: React.ComponentClass<SelectedERC20AssetAmountInputProps> = connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
)(ERC20AssetAmountInput);