diff options
Diffstat (limited to 'packages/website/ts/components/portal/portal.tsx')
-rw-r--r-- | packages/website/ts/components/portal/portal.tsx | 245 |
1 files changed, 208 insertions, 37 deletions
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index e572b7911..d9d50c5ab 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -3,20 +3,40 @@ import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import * as React from 'react'; import * as DocumentTitle from 'react-document-title'; +import { Link, Route, RouteComponentProps, 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 { EthWrappers } from 'ts/components/eth_wrappers'; import { AssetPicker } from 'ts/components/generate_order/asset_picker'; +import { BackButton } from 'ts/components/portal/back_button'; +import { Loading } from 'ts/components/portal/loading'; +import { Menu } from 'ts/components/portal/menu'; +import { Section } from 'ts/components/portal/section'; +import { TextHeader } from 'ts/components/portal/text_header'; import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; +import { TokenBalances } from 'ts/components/token_balances'; import { TopBar, TopBarDisplayType } 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 { Wallet } from 'ts/components/wallet/wallet'; +import { GenerateOrderForm } from 'ts/containers/generate_order_form'; import { localStorage } from 'ts/local_storage/local_storage'; import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; +import { FullscreenMessage } from 'ts/pages/fullscreen_message'; import { Dispatcher } from 'ts/redux/dispatcher'; -import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, TokenVisibility } from 'ts/types'; +import { + BlockchainErrs, + HashData, + Order, + ProviderType, + ScreenWidths, + TokenByAddress, + TokenVisibility, + WebsitePaths, +} from 'ts/types'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; @@ -54,6 +74,12 @@ interface PortalState { tokenManagementState: TokenManagementState; } +interface AccountManagementItem { + pathName: string; + headerText: string; + render: () => React.ReactNode; +} + enum TokenManagementState { Add = 'Add', Remove = 'Remove', @@ -62,6 +88,7 @@ enum TokenManagementState { const THROTTLE_TIMEOUT = 100; const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded); +const LEFT_COLUMN_WIDTH = 346; const styles: Styles = { root: { @@ -72,15 +99,15 @@ const styles: Styles = { body: { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, + leftColumn: { + width: LEFT_COLUMN_WIDTH, + height: '100%', + }, scrollContainer: { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, WebkitOverflowScrolling: 'touch', overflow: 'auto', }, - title: { - fontWeight: 'bold', - fontSize: 20, - }, }; export class Portal extends React.Component<PortalProps, PortalState> { @@ -148,8 +175,6 @@ export class Portal extends React.Component<PortalProps, PortalState> { const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( this.props.dispatcher, ); - const allTokens = _.values(this.props.tokenByAddress); - const trackedTokens = _.filter(allTokens, t => t.isTracked); const isAssetPickerDialogOpen = this.state.tokenManagementState !== TokenManagementState.None; const tokenVisibility = this.state.tokenManagementState === TokenManagementState.Add @@ -173,36 +198,17 @@ export class Portal extends React.Component<PortalProps, PortalState> { style={{ backgroundColor: colors.lightestGrey }} /> <div id="portal" style={styles.body}> - <div className="sm-flex flex-center"> - <div className="flex-last px3"> - <div className="py3" style={styles.title}> - Your Account - </div> - <Wallet - userAddress={this.props.userAddress} - networkId={this.props.networkId} - blockchain={this._blockchain} - blockchainIsLoaded={this.props.blockchainIsLoaded} - blockchainErr={this.props.blockchainErr} - dispatcher={this.props.dispatcher} - tokenByAddress={this.props.tokenByAddress} - trackedTokens={trackedTokens} - userEtherBalanceInWei={this.props.userEtherBalanceInWei} - lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} - injectedProviderName={this.props.injectedProviderName} - providerType={this.props.providerType} - onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} - onAddToken={this._onAddToken.bind(this)} - onRemoveToken={this._onRemoveToken.bind(this)} - /> - </div> - <div className="flex-auto px3" style={styles.scrollContainer}> - <div className="py3" style={styles.title}> - Explore 0x Ecosystem - </div> - <RelayerIndex networkId={this.props.networkId} /> - </div> - </div> + <Switch> + <Route + path={`${WebsitePaths.Portal}/:route`} + render={this._renderMenuAndAccountManagement.bind(this)} + /> + <Route + exact={true} + path={`${WebsitePaths.Portal}/`} + render={this._renderWalletAndRelayerIndex.bind(this)} + /> + </Switch> <BlockchainErrDialog blockchain={this._blockchain} blockchainErr={this.props.blockchainErr} @@ -241,6 +247,154 @@ export class Portal extends React.Component<PortalProps, PortalState> { </div> ); } + private _renderWalletAndRelayerIndex(): React.ReactNode { + return <PortalLayout left={this._renderWallet()} right={this._renderRelayerIndexSection()} />; + } + private _renderMenuAndAccountManagement(routeComponentProps: RouteComponentProps<any>): React.ReactNode { + return <PortalLayout left={this._renderMenu(routeComponentProps)} right={this._renderAccountManagement()} />; + } + private _renderMenu(routeComponentProps: RouteComponentProps<any>): React.ReactNode { + return ( + <Section + header={<BackButton to={`${WebsitePaths.Portal}`} labelText="back to Relayers" />} + body={<Menu selectedPath={routeComponentProps.location.pathname} />} + /> + ); + } + private _renderWallet(): React.ReactNode { + const allTokens = _.values(this.props.tokenByAddress); + const trackedTokens = _.filter(allTokens, t => t.isTracked); + return ( + <Section + header={<TextHeader labelText="Your Account" />} + body={ + <Wallet + userAddress={this.props.userAddress} + networkId={this.props.networkId} + blockchain={this._blockchain} + blockchainIsLoaded={this.props.blockchainIsLoaded} + blockchainErr={this.props.blockchainErr} + dispatcher={this.props.dispatcher} + tokenByAddress={this.props.tokenByAddress} + trackedTokens={trackedTokens} + userEtherBalanceInWei={this.props.userEtherBalanceInWei} + lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} + injectedProviderName={this.props.injectedProviderName} + providerType={this.props.providerType} + onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} + onAddToken={this._onAddToken.bind(this)} + onRemoveToken={this._onRemoveToken.bind(this)} + /> + } + /> + ); + } + private _renderAccountManagement(): React.ReactNode { + const accountManagementItems: AccountManagementItem[] = [ + { + pathName: `${WebsitePaths.Portal}/weth`, + headerText: 'Wrapped ETH', + render: this._renderEthWrapper.bind(this), + }, + { + pathName: `${WebsitePaths.Portal}/account`, + headerText: 'Your Account', + render: this._renderTokenBalances.bind(this), + }, + { + pathName: `${WebsitePaths.Portal}/trades`, + headerText: 'Trade History', + render: this._renderTradeHistory.bind(this), + }, + { + pathName: `${WebsitePaths.Portal}/direct`, + headerText: 'Trade Direct', + render: this._renderTradeDirect.bind(this), + }, + ]; + return ( + <Switch> + {_.map(accountManagementItems, item => { + return <Route path={item.pathName} render={this._renderAccountManagementItem.bind(this, item)} />; + })}} + <Route render={this._renderNotFoundMessage.bind(this)} /> + </Switch> + ); + } + private _renderAccountManagementItem(item: AccountManagementItem): React.ReactNode { + return ( + <Section + header={<TextHeader labelText={item.headerText} />} + body={<Loading isLoading={!this.props.blockchainIsLoaded} content={item.render()} />} + /> + ); + } + 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 _renderTradeDirect(match: any, location: Location, history: History): React.ReactNode { + return ( + <GenerateOrderForm + blockchain={this._blockchain} + hashData={this.props.hashData} + dispatcher={this.props.dispatcher} + /> + ); + } + private _renderTokenBalances(): React.ReactNode { + const allTokens = _.values(this.props.tokenByAddress); + const trackedTokens = _.filter(allTokens, t => t.isTracked); + 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 _renderRelayerIndexSection(): React.ReactNode { + return ( + <Section + header={<TextHeader labelText="Explore 0x Relayers" />} + body={<RelayerIndex networkId={this.props.networkId} />} + /> + ); + } + private _renderNotFoundMessage(): React.ReactNode { + return ( + <FullscreenMessage + headerText="404 Not Found" + bodyText="Hm... looks like we couldn't find what you are looking for." + /> + ); + } private _onTokenChosen(tokenAddress: string): void { if (_.isEmpty(tokenAddress)) { this.setState({ @@ -295,3 +449,20 @@ export class Portal extends React.Component<PortalProps, PortalState> { this.props.dispatcher.updateScreenWidth(newScreenWidth); } } + +interface PortalLayoutProps { + left: React.ReactNode; + right: React.ReactNode; +} +const PortalLayout = (props: PortalLayoutProps) => { + return ( + <div className="sm-flex flex-center"> + <div className="flex-last px3"> + <div style={styles.leftColumn}>{props.left}</div> + </div> + <div className="flex-auto px3" style={styles.scrollContainer}> + {props.right} + </div> + </div> + ); +}; // tslint:disable:max-file-line-count |