181 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { ECSignature } from '0x.js';
 | 
						|
import { BigNumber } from '@0xproject/utils';
 | 
						|
import * as _ from 'lodash';
 | 
						|
import Paper from 'material-ui/Paper';
 | 
						|
import TextField from 'material-ui/TextField';
 | 
						|
import * as React from 'react';
 | 
						|
import { CopyIcon } from 'ts/components/ui/copy_icon';
 | 
						|
import { SideToAssetToken, TokenByAddress, WebsitePaths } from 'ts/types';
 | 
						|
import { configs } from 'ts/utils/configs';
 | 
						|
import { constants } from 'ts/utils/constants';
 | 
						|
import { errorReporter } from 'ts/utils/error_reporter';
 | 
						|
import { utils } from 'ts/utils/utils';
 | 
						|
 | 
						|
interface OrderJSONProps {
 | 
						|
    exchangeContractIfExists: string;
 | 
						|
    orderExpiryTimestamp: BigNumber;
 | 
						|
    orderECSignature: ECSignature;
 | 
						|
    orderTakerAddress: string;
 | 
						|
    orderMakerAddress: string;
 | 
						|
    orderSalt: BigNumber;
 | 
						|
    orderMakerFee: BigNumber;
 | 
						|
    orderTakerFee: BigNumber;
 | 
						|
    orderFeeRecipient: string;
 | 
						|
    sideToAssetToken: SideToAssetToken;
 | 
						|
    tokenByAddress: TokenByAddress;
 | 
						|
}
 | 
						|
 | 
						|
interface OrderJSONState {
 | 
						|
    shareLink: string;
 | 
						|
}
 | 
						|
 | 
						|
export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
 | 
						|
    constructor(props: OrderJSONProps) {
 | 
						|
        super(props);
 | 
						|
        this.state = {
 | 
						|
            shareLink: '',
 | 
						|
        };
 | 
						|
        // tslint:disable-next-line:no-floating-promises
 | 
						|
        this._setShareLinkAsync();
 | 
						|
    }
 | 
						|
    public render() {
 | 
						|
        const order = utils.generateOrder(
 | 
						|
            this.props.exchangeContractIfExists,
 | 
						|
            this.props.sideToAssetToken,
 | 
						|
            this.props.orderExpiryTimestamp,
 | 
						|
            this.props.orderTakerAddress,
 | 
						|
            this.props.orderMakerAddress,
 | 
						|
            this.props.orderMakerFee,
 | 
						|
            this.props.orderTakerFee,
 | 
						|
            this.props.orderFeeRecipient,
 | 
						|
            this.props.orderECSignature,
 | 
						|
            this.props.tokenByAddress,
 | 
						|
            this.props.orderSalt,
 | 
						|
        );
 | 
						|
        const orderJSON = JSON.stringify(order);
 | 
						|
        return (
 | 
						|
            <div>
 | 
						|
                <div className="pb2">
 | 
						|
                    You have successfully generated and cryptographically signed an order! The following JSON contains
 | 
						|
                    the order parameters and cryptographic signature that your counterparty will need to execute a trade
 | 
						|
                    with you.
 | 
						|
                </div>
 | 
						|
                <div className="pb2 flex">
 | 
						|
                    <div className="inline-block pl1" style={{ top: 1 }}>
 | 
						|
                        <CopyIcon data={orderJSON} callToAction="Copy" />
 | 
						|
                    </div>
 | 
						|
                </div>
 | 
						|
                <Paper className="center overflow-hidden">
 | 
						|
                    <TextField
 | 
						|
                        id="orderJSON"
 | 
						|
                        style={{ width: 710 }}
 | 
						|
                        value={JSON.stringify(order, null, '\t')}
 | 
						|
                        multiLine={true}
 | 
						|
                        rows={2}
 | 
						|
                        rowsMax={8}
 | 
						|
                        underlineStyle={{ display: 'none' }}
 | 
						|
                    />
 | 
						|
                </Paper>
 | 
						|
                <div className="pt3 pb2 center">
 | 
						|
                    <div>Share your signed order!</div>
 | 
						|
                    <div>
 | 
						|
                        <div className="mx-auto overflow-hidden" style={{ width: 152 }}>
 | 
						|
                            <TextField id={`${this.state.shareLink}-bitly`} value={this.state.shareLink} />
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
                    <div className="mx-auto pt1 flex" style={{ width: 91 }}>
 | 
						|
                        <div>
 | 
						|
                            <i
 | 
						|
                                style={{ cursor: 'pointer', fontSize: 29 }}
 | 
						|
                                onClick={this._shareViaFacebook.bind(this)}
 | 
						|
                                className="zmdi zmdi-facebook-box"
 | 
						|
                            />
 | 
						|
                        </div>
 | 
						|
                        <div className="pl1" style={{ position: 'relative', width: 28 }}>
 | 
						|
                            <i
 | 
						|
                                style={{
 | 
						|
                                    cursor: 'pointer',
 | 
						|
                                    fontSize: 32,
 | 
						|
                                    position: 'absolute',
 | 
						|
                                    top: -2,
 | 
						|
                                    left: 8,
 | 
						|
                                }}
 | 
						|
                                onClick={this._shareViaEmailAsync.bind(this)}
 | 
						|
                                className="zmdi zmdi-email"
 | 
						|
                            />
 | 
						|
                        </div>
 | 
						|
                        <div className="pl1">
 | 
						|
                            <i
 | 
						|
                                style={{ cursor: 'pointer', fontSize: 29 }}
 | 
						|
                                onClick={this._shareViaTwitterAsync.bind(this)}
 | 
						|
                                className="zmdi zmdi-twitter-box"
 | 
						|
                            />
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
                </div>
 | 
						|
            </div>
 | 
						|
        );
 | 
						|
    }
 | 
						|
    private async _shareViaTwitterAsync() {
 | 
						|
        const tweetText = encodeURIComponent(`Fill my order using the 0x protocol: ${this.state.shareLink}`);
 | 
						|
        window.open(`https://twitter.com/intent/tweet?text=${tweetText}`, 'Share your order', 'width=500,height=400');
 | 
						|
    }
 | 
						|
    private async _shareViaFacebook() {
 | 
						|
        (window as any).FB.ui(
 | 
						|
            {
 | 
						|
                display: 'popup',
 | 
						|
                href: this.state.shareLink,
 | 
						|
                method: 'share',
 | 
						|
            },
 | 
						|
            _.noop,
 | 
						|
        );
 | 
						|
    }
 | 
						|
    private async _shareViaEmailAsync() {
 | 
						|
        const encodedSubject = encodeURIComponent("Let's trade using the 0x protocol");
 | 
						|
        const encodedBody = encodeURIComponent(`I generated an order with the 0x protocol.
 | 
						|
You can see and fill it here: ${this.state.shareLink}`);
 | 
						|
        const mailToLink = `mailto:mail@example.org?subject=${encodedSubject}&body=${encodedBody}`;
 | 
						|
        window.open(mailToLink, '_blank');
 | 
						|
    }
 | 
						|
    private async _setShareLinkAsync() {
 | 
						|
        const shareLink = await this._generateShareLinkAsync();
 | 
						|
        this.setState({
 | 
						|
            shareLink,
 | 
						|
        });
 | 
						|
    }
 | 
						|
    private async _generateShareLinkAsync(): Promise<string> {
 | 
						|
        const longUrl = encodeURIComponent(this._getOrderUrl());
 | 
						|
        const bitlyRequestUrl = `${constants.URL_BITLY_API}/v3/shorten?access_token=${
 | 
						|
            configs.BITLY_ACCESS_TOKEN
 | 
						|
        }&longUrl=${longUrl}`;
 | 
						|
        const response = await fetch(bitlyRequestUrl);
 | 
						|
        const responseBody = await response.text();
 | 
						|
        const bodyObj = JSON.parse(responseBody);
 | 
						|
        if (response.status !== 200 || bodyObj.status_code !== 200) {
 | 
						|
            // TODO: Show error message in UI
 | 
						|
            utils.consoleLog(`Unexpected status code: ${response.status} -> ${responseBody}`);
 | 
						|
            await errorReporter.reportAsync(new Error(`Bitly returned non-200: ${JSON.stringify(response)}`));
 | 
						|
            return '';
 | 
						|
        }
 | 
						|
        return bodyObj.data.url;
 | 
						|
    }
 | 
						|
    private _getOrderUrl() {
 | 
						|
        const order = utils.generateOrder(
 | 
						|
            this.props.exchangeContractIfExists,
 | 
						|
            this.props.sideToAssetToken,
 | 
						|
            this.props.orderExpiryTimestamp,
 | 
						|
            this.props.orderTakerAddress,
 | 
						|
            this.props.orderMakerAddress,
 | 
						|
            this.props.orderMakerFee,
 | 
						|
            this.props.orderTakerFee,
 | 
						|
            this.props.orderFeeRecipient,
 | 
						|
            this.props.orderECSignature,
 | 
						|
            this.props.tokenByAddress,
 | 
						|
            this.props.orderSalt,
 | 
						|
        );
 | 
						|
        const orderJSONString = JSON.stringify(order);
 | 
						|
        const orderUrl = `${configs.BASE_URL}${WebsitePaths.Portal}/fill?order=${orderJSONString}`;
 | 
						|
        return orderUrl;
 | 
						|
    }
 | 
						|
}
 |