Merge pull request #648 from 0xProject/feature/website/fill-order

Add shared order support
This commit is contained in:
Brandon Millman
2018-06-01 11:22:25 -07:00
committed by GitHub
4 changed files with 75 additions and 34 deletions

View File

@@ -38,6 +38,7 @@ import {
} from 'ts/types'; } from 'ts/types';
import { configs } from 'ts/utils/configs'; import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants'; import { constants } from 'ts/utils/constants';
import { orderParser } from 'ts/utils/order_parser';
import { Translate } from 'ts/utils/translate'; import { Translate } from 'ts/utils/translate';
import { utils } from 'ts/utils/utils'; import { utils } from 'ts/utils/utils';
@@ -86,7 +87,7 @@ export class LegacyPortal extends React.Component<LegacyPortalProps, LegacyPorta
} }
constructor(props: LegacyPortalProps) { constructor(props: LegacyPortalProps) {
super(props); super(props);
this._sharedOrderIfExists = this._getSharedOrderIfExists(); this._sharedOrderIfExists = orderParser.parse(window.location.search);
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`); const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`);
@@ -362,32 +363,6 @@ export class LegacyPortal extends React.Component<LegacyPortalProps, LegacyPorta
isWethNoticeDialogOpen: false, isWethNoticeDialogOpen: false,
}); });
} }
private _getSharedOrderIfExists(): Order | undefined {
const queryString = window.location.search;
if (queryString.length === 0) {
return undefined;
}
const queryParams = queryString.substring(1).split('&');
const orderQueryParam = _.find(queryParams, queryParam => {
const queryPair = queryParam.split('=');
return queryPair[0] === 'order';
});
if (_.isUndefined(orderQueryParam)) {
return undefined;
}
const orderPair = orderQueryParam.split('=');
if (orderPair.length !== 2) {
return undefined;
}
const order = JSON.parse(decodeURIComponent(orderPair[1]));
const validationResult = validator.validate(order, portalOrderSchema);
if (validationResult.errors.length > 0) {
logUtils.log(`Invalid shared order: ${validationResult.errors}`);
return undefined;
}
return order;
}
private _updateScreenWidth(): void { private _updateScreenWidth(): void {
const newScreenWidth = utils.getScreenWidth(); const newScreenWidth = utils.getScreenWidth();
this.props.dispatcher.updateScreenWidth(newScreenWidth); this.props.dispatcher.updateScreenWidth(newScreenWidth);

View File

@@ -43,9 +43,14 @@ export const defaultMenuItemEntries: MenuItemEntry[] = [
iconName: 'zmdi-circle-o', iconName: 'zmdi-circle-o',
}, },
{ {
to: `${WebsitePaths.Portal}/direct`, to: `${WebsitePaths.Portal}/generate`,
labelText: 'Trade direct', labelText: 'Generate order',
iconName: 'zmdi-swap', iconName: 'zmdi-arrow-right-top',
},
{
to: `${WebsitePaths.Portal}/fill`,
labelText: 'Fill order',
iconName: 'zmdi-arrow-left-bottom',
}, },
]; ];

View File

@@ -10,6 +10,7 @@ import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog
import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog';
import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog';
import { EthWrappers } from 'ts/components/eth_wrappers'; import { EthWrappers } from 'ts/components/eth_wrappers';
import { FillOrder } from 'ts/components/fill_order';
import { AssetPicker } from 'ts/components/generate_order/asset_picker'; import { AssetPicker } from 'ts/components/generate_order/asset_picker';
import { BackButton } from 'ts/components/portal/back_button'; import { BackButton } from 'ts/components/portal/back_button';
import { Loading } from 'ts/components/portal/loading'; import { Loading } from 'ts/components/portal/loading';
@@ -42,6 +43,7 @@ import {
} from 'ts/types'; } from 'ts/types';
import { configs } from 'ts/utils/configs'; import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants'; import { constants } from 'ts/utils/constants';
import { orderParser } from 'ts/utils/order_parser';
import { Translate } from 'ts/utils/translate'; import { Translate } from 'ts/utils/translate';
import { utils } from 'ts/utils/utils'; import { utils } from 'ts/utils/utils';
@@ -116,9 +118,11 @@ const styles: Styles = {
export class Portal extends React.Component<PortalProps, PortalState> { export class Portal extends React.Component<PortalProps, PortalState> {
private _blockchain: Blockchain; private _blockchain: Blockchain;
private _sharedOrderIfExists: Order;
private _throttledScreenWidthUpdate: () => void; private _throttledScreenWidthUpdate: () => void;
constructor(props: PortalProps) { constructor(props: PortalProps) {
super(props); super(props);
this._sharedOrderIfExists = orderParser.parse(window.location.search);
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER);
const hasAcceptedDisclaimer = const hasAcceptedDisclaimer =
@@ -336,9 +340,14 @@ export class Portal extends React.Component<PortalProps, PortalState> {
render: this._renderTradeHistory.bind(this), render: this._renderTradeHistory.bind(this),
}, },
{ {
pathName: `${WebsitePaths.Portal}/direct`, pathName: `${WebsitePaths.Portal}/generate`,
headerText: 'Trade Direct', headerText: 'Generate Order',
render: this._renderTradeDirect.bind(this), render: this._renderGenerateOrderForm.bind(this),
},
{
pathName: `${WebsitePaths.Portal}/fill`,
headerText: 'Fill Order',
render: this._renderFillOrder.bind(this),
}, },
]; ];
return ( return (
@@ -386,7 +395,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
/> />
); );
} }
private _renderTradeDirect(match: any, location: Location, history: History): React.ReactNode { private _renderGenerateOrderForm(): React.ReactNode {
return ( return (
<GenerateOrderForm <GenerateOrderForm
blockchain={this._blockchain} blockchain={this._blockchain}
@@ -395,6 +404,25 @@ export class Portal extends React.Component<PortalProps, PortalState> {
/> />
); );
} }
private _renderFillOrder(): React.ReactNode {
const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache)
? this.props.userSuppliedOrderCache
: this._sharedOrderIfExists;
return (
<FillOrder
blockchain={this._blockchain}
blockchainErr={this.props.blockchainErr}
initialOrder={initialFillOrder}
isOrderInUrl={!_.isUndefined(this._sharedOrderIfExists)}
orderFillAmount={this.props.orderFillAmount}
networkId={this.props.networkId}
userAddress={this.props.userAddress}
tokenByAddress={this.props.tokenByAddress}
dispatcher={this.props.dispatcher}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
/>
);
}
private _renderTokenBalances(): React.ReactNode { private _renderTokenBalances(): React.ReactNode {
const allTokens = _.values(this.props.tokenByAddress); const allTokens = _.values(this.props.tokenByAddress);
const trackedTokens = _.filter(allTokens, t => t.isTracked); const trackedTokens = _.filter(allTokens, t => t.isTracked);

View File

@@ -0,0 +1,33 @@
import { logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
import { validator } from 'ts/schemas/validator';
import { Order } from 'ts/types';
export const orderParser = {
parse(queryString: string): Order | undefined {
if (queryString.length === 0) {
return undefined;
}
const queryParams = queryString.substring(1).split('&');
const orderQueryParam = _.find(queryParams, queryParam => {
const queryPair = queryParam.split('=');
return queryPair[0] === 'order';
});
if (_.isUndefined(orderQueryParam)) {
return undefined;
}
const orderPair = orderQueryParam.split('=');
if (orderPair.length !== 2) {
return undefined;
}
const order = JSON.parse(decodeURIComponent(orderPair[1]));
const validationResult = validator.validate(order, portalOrderSchema);
if (validationResult.errors.length > 0) {
logUtils.log(`Invalid shared order: ${validationResult.errors}`);
return undefined;
}
return order;
},
};