Merge branch 'v2-prototype' into fix/request-timeout-issue

* v2-prototype:
  Remove legacy portal code
This commit is contained in:
Fabio Berger
2018-07-13 16:12:49 +02:00
6 changed files with 5 additions and 538 deletions

View File

@@ -1,339 +0,0 @@
import { colors } from '@0xproject/react-shared';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import CircularProgress from 'material-ui/CircularProgress';
import Paper from 'material-ui/Paper';
import * as React from 'react';
import * as DocumentTitle from 'react-document-title';
import { Route, Switch } from 'react-router-dom';
import { Blockchain } from 'ts/blockchain';
import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog';
import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog';
import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog';
import { WrappedEthSectionNoticeDialog } from 'ts/components/dialogs/wrapped_eth_section_notice_dialog';
import { EthWrappers } from 'ts/components/eth_wrappers';
import { FillOrder } from 'ts/components/fill_order';
import { Footer } from 'ts/components/footer';
import { LegacyPortalMenu } from 'ts/components/legacy_portal/legacy_portal_menu';
import { TokenBalances } from 'ts/components/token_balances';
import { TopBar } from 'ts/components/top_bar/top_bar';
import { TradeHistory } from 'ts/components/trade_history/trade_history';
import { FlashMessage } from 'ts/components/ui/flash_message';
import { GenerateOrderForm } from 'ts/containers/generate_order_form';
import { localStorage } from 'ts/local_storage/local_storage';
import { Dispatcher } from 'ts/redux/dispatcher';
import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
import { orderParser } from 'ts/utils/order_parser';
import { Translate } from 'ts/utils/translate';
import { utils } from 'ts/utils/utils';
const THROTTLE_TIMEOUT = 100;
export interface LegacyPortalProps {
blockchainErr: BlockchainErrs;
blockchainIsLoaded: boolean;
dispatcher: Dispatcher;
hashData: HashData;
injectedProviderName: string;
networkId: number;
nodeVersion: string;
orderFillAmount: BigNumber;
providerType: ProviderType;
screenWidth: ScreenWidths;
tokenByAddress: TokenByAddress;
userEtherBalanceInWei?: BigNumber;
userAddress: string;
shouldBlockchainErrDialogBeOpen: boolean;
userSuppliedOrderCache: Order;
location: Location;
flashMessage?: string | React.ReactNode;
lastForceTokenStateRefetch: number;
translate: Translate;
}
interface LegacyPortalState {
prevNetworkId: number;
prevNodeVersion: string;
prevUserAddress: string;
prevPathname: string;
isDisclaimerDialogOpen: boolean;
isWethNoticeDialogOpen: boolean;
isLedgerDialogOpen: boolean;
}
export class LegacyPortal extends React.Component<LegacyPortalProps, LegacyPortalState> {
private _blockchain: Blockchain;
private _sharedOrderIfExists: Order;
private _throttledScreenWidthUpdate: () => void;
public static hasAlreadyDismissedWethNotice(): boolean {
const didDismissWethNotice = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE);
const hasAlreadyDismissedWethNotice = !_.isUndefined(didDismissWethNotice) && !_.isEmpty(didDismissWethNotice);
return hasAlreadyDismissedWethNotice;
}
constructor(props: LegacyPortalProps) {
super(props);
this._sharedOrderIfExists = orderParser.parse(window.location.search);
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`);
const hasAlreadyDismissedWethNotice = LegacyPortal.hasAlreadyDismissedWethNotice();
const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER);
const hasAcceptedDisclaimer =
!_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer);
this.state = {
prevNetworkId: this.props.networkId,
prevNodeVersion: this.props.nodeVersion,
prevUserAddress: this.props.userAddress,
prevPathname: this.props.location.pathname,
isDisclaimerDialogOpen: !hasAcceptedDisclaimer,
isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances,
isLedgerDialogOpen: false,
};
}
public componentDidMount(): void {
window.addEventListener('resize', this._throttledScreenWidthUpdate);
window.scrollTo(0, 0);
}
public componentWillMount(): void {
this._blockchain = new Blockchain(this.props.dispatcher);
}
public componentWillUnmount(): void {
this._blockchain.destroy();
window.removeEventListener('resize', this._throttledScreenWidthUpdate);
// We re-set the entire redux state when the portal is unmounted so that when it is re-rendered
// the initialization process always occurs from the same base state. This helps avoid
// initialization inconsistencies (i.e While the portal was unrendered, the user might have
// become disconnected from their backing Ethereum node, changes user accounts, etc...)
this.props.dispatcher.resetState();
}
public componentWillReceiveProps(nextProps: LegacyPortalProps): void {
if (nextProps.networkId !== this.state.prevNetworkId) {
// tslint:disable-next-line:no-floating-promises
this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
this.setState({
prevNetworkId: nextProps.networkId,
});
}
if (nextProps.userAddress !== this.state.prevUserAddress) {
const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress;
// tslint:disable-next-line:no-floating-promises
this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress);
this.setState({
prevUserAddress: nextProps.userAddress,
});
}
if (nextProps.nodeVersion !== this.state.prevNodeVersion) {
// tslint:disable-next-line:no-floating-promises
this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion);
}
if (nextProps.location.pathname !== this.state.prevPathname) {
const isViewingBalances = _.includes(nextProps.location.pathname, `${WebsitePaths.Portal}/balances`);
const hasAlreadyDismissedWethNotice = LegacyPortal.hasAlreadyDismissedWethNotice();
this.setState({
prevPathname: nextProps.location.pathname,
isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances,
});
}
}
public render(): React.ReactNode {
const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind(
this.props.dispatcher,
);
const portalStyle: React.CSSProperties = {
minHeight: '100vh',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
};
const portalMenuContainerStyle: React.CSSProperties = {
overflow: 'hidden',
backgroundColor: colors.darkestGrey,
color: colors.white,
};
return (
<div style={portalStyle}>
<DocumentTitle title="0x Portal DApp" />
<TopBar
userAddress={this.props.userAddress}
networkId={this.props.networkId}
injectedProviderName={this.props.injectedProviderName}
onToggleLedgerDialog={this.onToggleLedgerDialog.bind(this)}
dispatcher={this.props.dispatcher}
providerType={this.props.providerType}
blockchainIsLoaded={this.props.blockchainIsLoaded}
location={this.props.location}
blockchain={this._blockchain}
translate={this.props.translate}
/>
<div id="portal" className="mx-auto max-width-4" style={{ width: '100%' }}>
<Paper className="mb3 mt2">
<div className="mx-auto flex">
<div className="col col-2 pr2 pt1 sm-hide xs-hide" style={portalMenuContainerStyle}>
<LegacyPortalMenu menuItemStyle={{ color: colors.white }} />
</div>
<div className="col col-12 lg-col-10 md-col-10 sm-col sm-col-12">
<div className="py2" style={{ backgroundColor: colors.grey50 }}>
{this.props.blockchainIsLoaded ? (
<Switch>
<Route
path={`${WebsitePaths.Portal}/weth`}
render={this._renderEthWrapper.bind(this)}
/>
<Route
path={`${WebsitePaths.Portal}/fill`}
render={this._renderFillOrder.bind(this)}
/>
<Route
path={`${WebsitePaths.Portal}/balances`}
render={this._renderTokenBalances.bind(this)}
/>
<Route
path={`${WebsitePaths.Portal}/trades`}
render={this._renderTradeHistory.bind(this)}
/>
<Route
path={`${WebsitePaths.Home}`}
render={this._renderGenerateOrderForm.bind(this)}
/>
</Switch>
) : (
<div className="pt4 sm-px2 sm-pt2 sm-m1" style={{ height: 500 }}>
<div
className="relative sm-px2 sm-pt2 sm-m1"
style={{ height: 122, top: '50%', transform: 'translateY(-50%)' }}
>
<div className="center pb2">
<CircularProgress size={40} thickness={5} />
</div>
<div className="center pt2" style={{ paddingBottom: 11 }}>
Loading Portal...
</div>
</div>
</div>
)}
</div>
</div>
</div>
</Paper>
<BlockchainErrDialog
blockchain={this._blockchain}
blockchainErr={this.props.blockchainErr}
isOpen={this.props.shouldBlockchainErrDialogBeOpen}
userAddress={this.props.userAddress}
toggleDialogFn={updateShouldBlockchainErrDialogBeOpen}
networkId={this.props.networkId}
/>
<WrappedEthSectionNoticeDialog
isOpen={this.state.isWethNoticeDialogOpen}
onToggleDialog={this._onWethNoticeAccepted.bind(this)}
/>
<PortalDisclaimerDialog
isOpen={this.state.isDisclaimerDialogOpen}
onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)}
/>
<FlashMessage dispatcher={this.props.dispatcher} flashMessage={this.props.flashMessage} />
<LedgerConfigDialog
providerType={this.props.providerType}
networkId={this.props.networkId}
blockchain={this._blockchain}
dispatcher={this.props.dispatcher}
toggleDialogFn={this.onToggleLedgerDialog.bind(this)}
isOpen={this.state.isLedgerDialogOpen}
/>
</div>
<Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
</div>
);
}
public onToggleLedgerDialog(): void {
this.setState({
isLedgerDialogOpen: !this.state.isLedgerDialogOpen,
});
}
private _renderEthWrapper(): React.ReactNode {
return (
<EthWrappers
networkId={this.props.networkId}
blockchain={this._blockchain}
dispatcher={this.props.dispatcher}
tokenByAddress={this.props.tokenByAddress}
userAddress={this.props.userAddress}
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
/>
);
}
private _renderTradeHistory(): React.ReactNode {
return (
<TradeHistory
tokenByAddress={this.props.tokenByAddress}
userAddress={this.props.userAddress}
networkId={this.props.networkId}
/>
);
}
private _renderTokenBalances(): React.ReactNode {
const trackedTokens = utils.getTrackedTokens(this.props.tokenByAddress);
return (
<TokenBalances
blockchain={this._blockchain}
blockchainErr={this.props.blockchainErr}
blockchainIsLoaded={this.props.blockchainIsLoaded}
dispatcher={this.props.dispatcher}
screenWidth={this.props.screenWidth}
tokenByAddress={this.props.tokenByAddress}
trackedTokens={trackedTokens}
userAddress={this.props.userAddress}
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
networkId={this.props.networkId}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
/>
);
}
private _renderFillOrder(_match: any, _location: Location, _history: History): 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 _renderGenerateOrderForm(_match: any, _location: Location, _history: History): React.ReactNode {
return (
<GenerateOrderForm
blockchain={this._blockchain}
hashData={this.props.hashData}
dispatcher={this.props.dispatcher}
/>
);
}
private _onPortalDisclaimerAccepted(): void {
localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set');
this.setState({
isDisclaimerDialogOpen: false,
});
}
private _onWethNoticeAccepted(): void {
localStorage.setItem(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE, 'set');
this.setState({
isWethNoticeDialogOpen: false,
});
}
private _updateScreenWidth(): void {
const newScreenWidth = utils.getScreenWidth();
this.props.dispatcher.updateScreenWidth(newScreenWidth);
}
}

View File

@@ -1,73 +0,0 @@
import * as _ from 'lodash';
import * as React from 'react';
import { MenuItem } from 'ts/components/ui/menu_item';
import { WebsitePaths } from 'ts/types';
export interface LegacyPortalMenuProps {
menuItemStyle: React.CSSProperties;
onClick?: () => void;
}
interface LegacyPortalMenuState {}
export class LegacyPortalMenu extends React.Component<LegacyPortalMenuProps, LegacyPortalMenuState> {
public static defaultProps: Partial<LegacyPortalMenuProps> = {
onClick: _.noop,
};
public render(): React.ReactNode {
return (
<div>
<MenuItem
style={this.props.menuItemStyle}
className="py2"
to={`${WebsitePaths.Portal}`}
onClick={this.props.onClick.bind(this)}
>
{this._renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')}
</MenuItem>
<MenuItem
style={this.props.menuItemStyle}
className="py2"
to={`${WebsitePaths.Portal}/fill`}
onClick={this.props.onClick.bind(this)}
>
{this._renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')}
</MenuItem>
<MenuItem
style={this.props.menuItemStyle}
className="py2"
to={`${WebsitePaths.Portal}/balances`}
onClick={this.props.onClick.bind(this)}
>
{this._renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')}
</MenuItem>
<MenuItem
style={this.props.menuItemStyle}
className="py2"
to={`${WebsitePaths.Portal}/trades`}
onClick={this.props.onClick.bind(this)}
>
{this._renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')}
</MenuItem>
<MenuItem
style={this.props.menuItemStyle}
className="py2"
to={`${WebsitePaths.Portal}/weth`}
onClick={this.props.onClick.bind(this)}
>
{this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
</MenuItem>
</div>
);
}
private _renderMenuItemWithIcon(title: string, iconName: string): React.ReactNode {
return (
<div className="flex" style={{ fontWeight: 100 }}>
<div className="pr1 pl2">
<i style={{ fontSize: 20 }} className={`zmdi ${iconName}`} />
</div>
<div className="pl1">{title}</div>
</div>
);
}
}

View File

@@ -7,7 +7,6 @@ import MenuItem from 'material-ui/MenuItem';
import * as React from 'react';
import { Link } from 'react-router-dom';
import { Blockchain } from 'ts/blockchain';
import { LegacyPortalMenu } from 'ts/components/legacy_portal/legacy_portal_menu';
import { DrawerMenu } from 'ts/components/portal/drawer_menu';
import { ProviderDisplay } from 'ts/components/top_bar/provider_display';
import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item';
@@ -17,7 +16,6 @@ import { Dispatcher } from 'ts/redux/dispatcher';
import { Deco, Key, ProviderType, WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
import { Translate } from 'ts/utils/translate';
import { utils } from 'ts/utils/utils';
export enum TopBarDisplayType {
Default,
@@ -213,8 +211,6 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
);
const popoverContent = <Menu style={{ color: colors.darkGrey }}>{developerSectionMenuItems}</Menu>;
// TODO : Remove this once we ship portal v2
const shouldShowPortalV2Drawer = this._isViewingPortal() && utils.shouldShowPortalV2();
return (
<div
style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style, ...{ height } }}
@@ -294,11 +290,11 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
</div>
</Container>
{shouldShowPortalV2Drawer ? this._renderPortalV2Drawer() : this._renderDrawer()}
{this._isViewingPortal() ? this._renderPortalDrawer() : this._renderDrawer()}
</div>
);
}
private _renderPortalV2Drawer(): React.ReactNode {
private _renderPortalDrawer(): React.ReactNode {
return (
<Drawer
open={this.state.isDrawerOpen}
@@ -326,7 +322,6 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
onRequestChange={this._onMenuButtonClick.bind(this)}
>
<div className="clearfix">
{this._renderPortalMenu()}
{this._renderDocsMenu()}
{this._renderWiki()}
<div className="pl1 py1 mt3" style={{ backgroundColor: colors.lightGrey }}>
@@ -478,20 +473,6 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
);
}
private _renderPortalMenu(): React.ReactNode {
if (!this._isViewingPortal()) {
return undefined;
}
return (
<div className="lg-hide md-hide">
<div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}>
{this.props.translate.get(Key.PortalDApp, Deco.CapWords)}
</div>
<LegacyPortalMenu menuItemStyle={{ color: 'black' }} onClick={this._onMenuButtonClick.bind(this)} />
</div>
);
}
private _onMenuButtonClick(): void {
this.setState({
isDrawerOpen: !this.state.isDrawerOpen,

View File

@@ -1,92 +0,0 @@
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import * as React from 'react';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import {
LegacyPortal as LegacyPortalComponent,
LegacyPortalProps as LegacyPortalComponentProps,
} from 'ts/components/legacy_portal/legacy_portal';
import { Dispatcher } from 'ts/redux/dispatcher';
import { State } from 'ts/redux/reducer';
import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types';
import { constants } from 'ts/utils/constants';
import { Translate } from 'ts/utils/translate';
interface ConnectedState {
blockchainErr: BlockchainErrs;
blockchainIsLoaded: boolean;
hashData: HashData;
injectedProviderName: string;
networkId: number;
nodeVersion: string;
orderFillAmount: BigNumber;
providerType: ProviderType;
tokenByAddress: TokenByAddress;
lastForceTokenStateRefetch: number;
userEtherBalanceInWei?: BigNumber;
screenWidth: ScreenWidths;
shouldBlockchainErrDialogBeOpen: boolean;
userAddress: string;
userSuppliedOrderCache: Order;
flashMessage?: string | React.ReactNode;
translate: Translate;
}
interface ConnectedDispatch {
dispatcher: Dispatcher;
}
const mapStateToProps = (state: State, _ownProps: LegacyPortalComponentProps): ConnectedState => {
const receiveAssetToken = state.sideToAssetToken[Side.Receive];
const depositAssetToken = state.sideToAssetToken[Side.Deposit];
const receiveAddress = !_.isUndefined(receiveAssetToken.address)
? receiveAssetToken.address
: constants.NULL_ADDRESS;
const depositAddress = !_.isUndefined(depositAssetToken.address)
? depositAssetToken.address
: constants.NULL_ADDRESS;
const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0);
const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0);
const hashData = {
depositAmount,
depositTokenContractAddr: depositAddress,
feeRecipientAddress: constants.NULL_ADDRESS,
makerFee: constants.MAKER_FEE,
orderExpiryTimestamp: state.orderExpiryTimestamp,
orderMakerAddress: state.userAddress,
orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS,
receiveAmount,
receiveTokenContractAddr: receiveAddress,
takerFee: constants.TAKER_FEE,
orderSalt: state.orderSalt,
};
return {
blockchainErr: state.blockchainErr,
blockchainIsLoaded: state.blockchainIsLoaded,
hashData,
injectedProviderName: state.injectedProviderName,
networkId: state.networkId,
nodeVersion: state.nodeVersion,
orderFillAmount: state.orderFillAmount,
providerType: state.providerType,
screenWidth: state.screenWidth,
shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen,
tokenByAddress: state.tokenByAddress,
lastForceTokenStateRefetch: state.lastForceTokenStateRefetch,
userAddress: state.userAddress,
userEtherBalanceInWei: state.userEtherBalanceInWei,
userSuppliedOrderCache: state.userSuppliedOrderCache,
flashMessage: state.flashMessage,
translate: state.translate,
};
};
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
dispatcher: new Dispatcher(dispatch),
});
export const LegacyPortal: React.ComponentClass<LegacyPortalComponentProps> = connect(
mapStateToProps,
mapDispatchToProps,
)(LegacyPortalComponent);

View File

@@ -34,14 +34,9 @@ import 'less/all.less';
// At the same time webpack statically parses for System.import() to determine bundle chunk split points
// so each lazy import needs it's own `System.import()` declaration.
// TODO: Remove this once we ship V2
const LazyPortal = utils.shouldShowPortalV2()
? createLazyComponent('Portal', async () =>
System.import<any>(/* webpackChunkName: "portal" */ 'ts/containers/portal'),
)
: createLazyComponent('LegacyPortal', async () =>
System.import<any>(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'),
);
const LazyPortal = createLazyComponent('Portal', async () =>
System.import<any>(/* webpackChunkName: "portal" */ 'ts/containers/portal'),
);
const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () =>
System.import<any>(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'),
);

View File

@@ -358,11 +358,6 @@ export const utils = {
return providerType === ProviderType.Injected && injectedProviderName !== constants.PROVIDER_NAME_PUBLIC;
},
isDogfood,
shouldShowPortalV2(): boolean {
// return this.isDevelopment() || this.isStaging() || this.isDogfood();
// TODO: Remove this method entirely after launch.
return true;
},
shouldShowJobsPage(): boolean {
return this.isDevelopment() || this.isStaging() || this.isDogfood();
},