136 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { constants as sharedConstants, Styles } from '@0xproject/react-shared';
 | 
						|
import { BigNumber, logUtils } from '@0xproject/utils';
 | 
						|
import * as _ from 'lodash';
 | 
						|
import Toggle from 'material-ui/Toggle';
 | 
						|
import * as React from 'react';
 | 
						|
import { Blockchain } from 'ts/blockchain';
 | 
						|
import { Dispatcher } from 'ts/redux/dispatcher';
 | 
						|
import { colors } from 'ts/style/colors';
 | 
						|
import { BalanceErrs, Token, TokenState } from 'ts/types';
 | 
						|
import { analytics } from 'ts/utils/analytics';
 | 
						|
import { constants } from 'ts/utils/constants';
 | 
						|
import { errorReporter } from 'ts/utils/error_reporter';
 | 
						|
import { utils } from 'ts/utils/utils';
 | 
						|
 | 
						|
const DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS = new BigNumber(2).pow(256).minus(1);
 | 
						|
 | 
						|
interface AllowanceToggleProps {
 | 
						|
    networkId: number;
 | 
						|
    blockchain: Blockchain;
 | 
						|
    dispatcher: Dispatcher;
 | 
						|
    onErrorOccurred: (errType: BalanceErrs) => void;
 | 
						|
    token: Token;
 | 
						|
    tokenState: TokenState;
 | 
						|
    userAddress: string;
 | 
						|
    isDisabled: boolean;
 | 
						|
    refetchTokenStateAsync: () => Promise<void>;
 | 
						|
}
 | 
						|
 | 
						|
interface AllowanceToggleState {
 | 
						|
    isSpinnerVisible: boolean;
 | 
						|
    prevAllowance: BigNumber;
 | 
						|
}
 | 
						|
 | 
						|
const styles: Styles = {
 | 
						|
    baseThumbStyle: {
 | 
						|
        height: 10,
 | 
						|
        width: 10,
 | 
						|
        top: 6,
 | 
						|
        backgroundColor: colors.white,
 | 
						|
        boxShadow: `0px 0px 0px ${colors.allowanceToggleShadow}`,
 | 
						|
    },
 | 
						|
    offThumbStyle: {
 | 
						|
        left: 4,
 | 
						|
    },
 | 
						|
    onThumbStyle: {
 | 
						|
        left: 25,
 | 
						|
    },
 | 
						|
    baseTrackStyle: {
 | 
						|
        width: 25,
 | 
						|
    },
 | 
						|
    offTrackStyle: {
 | 
						|
        backgroundColor: colors.allowanceToggleOffTrack,
 | 
						|
    },
 | 
						|
    onTrackStyle: {
 | 
						|
        backgroundColor: colors.allowanceToggleOnTrack,
 | 
						|
    },
 | 
						|
};
 | 
						|
 | 
						|
export class AllowanceToggle extends React.Component<AllowanceToggleProps, AllowanceToggleState> {
 | 
						|
    constructor(props: AllowanceToggleProps) {
 | 
						|
        super(props);
 | 
						|
        this.state = {
 | 
						|
            isSpinnerVisible: false,
 | 
						|
            prevAllowance: props.tokenState.allowance,
 | 
						|
        };
 | 
						|
    }
 | 
						|
    public componentWillReceiveProps(nextProps: AllowanceToggleProps): void {
 | 
						|
        if (!nextProps.tokenState.allowance.eq(this.state.prevAllowance)) {
 | 
						|
            this.setState({
 | 
						|
                isSpinnerVisible: false,
 | 
						|
                prevAllowance: nextProps.tokenState.allowance,
 | 
						|
            });
 | 
						|
        }
 | 
						|
    }
 | 
						|
    public render(): React.ReactNode {
 | 
						|
        return (
 | 
						|
            <div className="flex">
 | 
						|
                <div>
 | 
						|
                    <Toggle
 | 
						|
                        disabled={this.state.isSpinnerVisible || this.props.isDisabled}
 | 
						|
                        toggled={this._isAllowanceSet()}
 | 
						|
                        onToggle={this._onToggleAllowanceAsync.bind(this)}
 | 
						|
                        thumbStyle={{ ...styles.baseThumbStyle, ...styles.offThumbStyle }}
 | 
						|
                        thumbSwitchedStyle={{ ...styles.baseThumbStyle, ...styles.onThumbStyle }}
 | 
						|
                        trackStyle={{ ...styles.baseTrackStyle, ...styles.offTrackStyle }}
 | 
						|
                        trackSwitchedStyle={{ ...styles.baseTrackStyle, ...styles.onTrackStyle }}
 | 
						|
                    />
 | 
						|
                </div>
 | 
						|
                {this.state.isSpinnerVisible && (
 | 
						|
                    <div className="pl1" style={{ paddingTop: 3 }}>
 | 
						|
                        <i className="zmdi zmdi-spinner zmdi-hc-spin" />
 | 
						|
                    </div>
 | 
						|
                )}
 | 
						|
            </div>
 | 
						|
        );
 | 
						|
    }
 | 
						|
    private async _onToggleAllowanceAsync(): Promise<void> {
 | 
						|
        if (this.props.userAddress === '') {
 | 
						|
            this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        this.setState({
 | 
						|
            isSpinnerVisible: true,
 | 
						|
        });
 | 
						|
 | 
						|
        let newAllowanceAmountInBaseUnits = new BigNumber(0);
 | 
						|
        if (!this._isAllowanceSet()) {
 | 
						|
            newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS;
 | 
						|
        }
 | 
						|
        const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
 | 
						|
        const eventLabel = `${this.props.token.symbol}-${networkName}`;
 | 
						|
        try {
 | 
						|
            await this.props.blockchain.setProxyAllowanceAsync(this.props.token, newAllowanceAmountInBaseUnits);
 | 
						|
            analytics.logEvent('Portal', 'Set Allowance Success', eventLabel, newAllowanceAmountInBaseUnits.toNumber());
 | 
						|
            await this.props.refetchTokenStateAsync();
 | 
						|
        } catch (err) {
 | 
						|
            analytics.logEvent('Portal', 'Set Allowance Failure', eventLabel, newAllowanceAmountInBaseUnits.toNumber());
 | 
						|
            this.setState({
 | 
						|
                isSpinnerVisible: false,
 | 
						|
            });
 | 
						|
            const errMsg = `${err}`;
 | 
						|
            if (utils.didUserDenyWeb3Request(errMsg)) {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
            logUtils.log(`Unexpected error encountered: ${err}`);
 | 
						|
            logUtils.log(err.stack);
 | 
						|
            this.props.onErrorOccurred(BalanceErrs.allowanceSettingFailed);
 | 
						|
            await errorReporter.reportAsync(err);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    private _isAllowanceSet(): boolean {
 | 
						|
        return !this.props.tokenState.allowance.eq(0);
 | 
						|
    }
 | 
						|
}
 |