aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/website/ts/components/legacy_portal/legacy_portal.tsx2
-rw-r--r--packages/website/ts/components/portal/back_button.tsx41
-rw-r--r--packages/website/ts/components/portal/loading.tsx21
-rw-r--r--packages/website/ts/components/portal/menu.tsx88
-rw-r--r--packages/website/ts/components/portal/portal.tsx245
-rw-r--r--packages/website/ts/components/portal/section.tsx15
-rw-r--r--packages/website/ts/components/portal/text_header.tsx21
-rw-r--r--packages/website/ts/components/relayer_index/relayer_index.tsx20
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx90
-rw-r--r--packages/website/ts/pages/fullscreen_message.tsx30
-rw-r--r--packages/website/ts/pages/not_found.tsx43
11 files changed, 502 insertions, 114 deletions
diff --git a/packages/website/ts/components/legacy_portal/legacy_portal.tsx b/packages/website/ts/components/legacy_portal/legacy_portal.tsx
index 002b258fb..a5ea95629 100644
--- a/packages/website/ts/components/legacy_portal/legacy_portal.tsx
+++ b/packages/website/ts/components/legacy_portal/legacy_portal.tsx
@@ -217,7 +217,7 @@ export class LegacyPortal extends React.Component<LegacyPortalProps, LegacyPorta
/>
<Route
path={`${WebsitePaths.Portal}/trades`}
- component={this._renderTradeHistory.bind(this)}
+ render={this._renderTradeHistory.bind(this)}
/>
<Route
path={`${WebsitePaths.Home}`}
diff --git a/packages/website/ts/components/portal/back_button.tsx b/packages/website/ts/components/portal/back_button.tsx
new file mode 100644
index 000000000..68934f88e
--- /dev/null
+++ b/packages/website/ts/components/portal/back_button.tsx
@@ -0,0 +1,41 @@
+import { colors, Styles } from '@0xproject/react-shared';
+import * as React from 'react';
+import { Link } from 'react-router-dom';
+
+export interface BackButtonProps {
+ to: string;
+ labelText: string;
+}
+
+const BACK_BUTTON_HEIGHT = 28;
+
+const styles: Styles = {
+ backButton: {
+ height: BACK_BUTTON_HEIGHT,
+ paddingTop: 10,
+ backgroundColor: colors.white,
+ borderRadius: BACK_BUTTON_HEIGHT,
+ boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`,
+ },
+ backButtonIcon: {
+ color: colors.mediumBlue,
+ fontSize: 20,
+ },
+};
+
+export const BackButton = (props: BackButtonProps) => {
+ return (
+ <div style={{ height: 65, paddingTop: 25 }}>
+ <Link to={props.to} style={{ textDecoration: 'none' }}>
+ <div className="flex right" style={styles.backButton}>
+ <div style={{ marginLeft: 12 }}>
+ <i style={styles.backButtonIcon} className={`zmdi zmdi-arrow-left`} />
+ </div>
+ <div style={{ marginLeft: 12, marginRight: 12 }}>
+ <div style={{ fontSize: 16, color: colors.lightGrey }}>{props.labelText}</div>
+ </div>
+ </div>
+ </Link>
+ </div>
+ );
+};
diff --git a/packages/website/ts/components/portal/loading.tsx b/packages/website/ts/components/portal/loading.tsx
new file mode 100644
index 000000000..d804dd1b8
--- /dev/null
+++ b/packages/website/ts/components/portal/loading.tsx
@@ -0,0 +1,21 @@
+import CircularProgress from 'material-ui/CircularProgress';
+import * as React from 'react';
+
+const CIRCULAR_PROGRESS_SIZE = 40;
+const CIRCULAR_PROGRESS_THICKNESS = 5;
+
+export interface LoadingProps {
+ isLoading: boolean;
+ content: React.ReactNode;
+}
+export const Loading = (props: LoadingProps) => {
+ if (props.isLoading) {
+ return (
+ <div className="center">
+ <CircularProgress size={CIRCULAR_PROGRESS_SIZE} thickness={CIRCULAR_PROGRESS_THICKNESS} />
+ </div>
+ );
+ } else {
+ return <div>{props.content}</div>;
+ }
+};
diff --git a/packages/website/ts/components/portal/menu.tsx b/packages/website/ts/components/portal/menu.tsx
new file mode 100644
index 000000000..9014d8d42
--- /dev/null
+++ b/packages/website/ts/components/portal/menu.tsx
@@ -0,0 +1,88 @@
+import { colors, Styles } from '@0xproject/react-shared';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { MenuItem } from 'ts/components/ui/menu_item';
+import { Environments, WebsitePaths } from 'ts/types';
+import { configs } from 'ts/utils/configs';
+
+export interface MenuProps {
+ selectedPath?: string;
+}
+
+interface MenuItemEntry {
+ to: string;
+ labelText: string;
+ iconName: string;
+}
+
+const menuItemEntries: MenuItemEntry[] = [
+ {
+ to: `${WebsitePaths.Portal}/account`,
+ labelText: 'Account overview',
+ iconName: 'zmdi-balance-wallet',
+ },
+ {
+ to: `${WebsitePaths.Portal}/trades`,
+ labelText: 'Trade history',
+ iconName: 'zmdi-format-list-bulleted',
+ },
+ {
+ to: `${WebsitePaths.Portal}/weth`,
+ labelText: 'Wrapped ETH',
+ iconName: 'zmdi-circle-o',
+ },
+ {
+ to: `${WebsitePaths.Portal}/direct`,
+ labelText: 'Trade direct',
+ iconName: 'zmdi-swap',
+ },
+];
+
+const DEFAULT_LABEL_COLOR = colors.darkerGrey;
+const DEFAULT_ICON_COLOR = colors.darkerGrey;
+const SELECTED_ICON_COLOR = colors.yellow900;
+
+const LEFT_PADDING = 185;
+
+export const Menu: React.StatelessComponent<MenuProps> = (props: MenuProps) => {
+ return (
+ <div style={{ paddingLeft: LEFT_PADDING }}>
+ {_.map(menuItemEntries, entry => {
+ const selected = entry.to === props.selectedPath;
+ return (
+ <MenuItem key={entry.to} className="py2" to={entry.to}>
+ <MenuItemLabel title={entry.labelText} iconName={entry.iconName} selected={selected} />
+ </MenuItem>
+ );
+ })}
+ </div>
+ );
+};
+
+interface MenuItemLabelProps {
+ title: string;
+ iconName: string;
+ selected: boolean;
+}
+const MenuItemLabel: React.StatelessComponent<MenuItemLabelProps> = (props: MenuItemLabelProps) => {
+ const styles: Styles = {
+ iconStyle: {
+ color: props.selected ? SELECTED_ICON_COLOR : DEFAULT_ICON_COLOR,
+ fontSize: 20,
+ },
+ textStyle: {
+ color: DEFAULT_LABEL_COLOR,
+ fontWeight: props.selected ? 'bold' : 'normal',
+ },
+ };
+ return (
+ <div className="flex">
+ <div className="pr1">
+ <i style={styles.iconStyle} className={`zmdi ${props.iconName}`} />
+ </div>
+ <div className="pl1" style={styles.textStyle}>
+ {props.title}
+ </div>
+ </div>
+ );
+};
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
diff --git a/packages/website/ts/components/portal/section.tsx b/packages/website/ts/components/portal/section.tsx
new file mode 100644
index 000000000..9b172aae0
--- /dev/null
+++ b/packages/website/ts/components/portal/section.tsx
@@ -0,0 +1,15 @@
+import { Styles } from '@0xproject/react-shared';
+import * as React from 'react';
+
+export interface SectionProps {
+ header: React.ReactNode;
+ body: React.ReactNode;
+}
+export const Section = (props: SectionProps) => {
+ return (
+ <div className="flex flex-column" style={{ height: '100%' }}>
+ {props.header}
+ <div className="flex-auto">{props.body}</div>
+ </div>
+ );
+};
diff --git a/packages/website/ts/components/portal/text_header.tsx b/packages/website/ts/components/portal/text_header.tsx
new file mode 100644
index 000000000..4aabd47d0
--- /dev/null
+++ b/packages/website/ts/components/portal/text_header.tsx
@@ -0,0 +1,21 @@
+import { Styles } from '@0xproject/react-shared';
+import * as React from 'react';
+
+export interface TextHeaderProps {
+ labelText: string;
+}
+
+const styles: Styles = {
+ title: {
+ fontWeight: 'bold',
+ fontSize: 20,
+ },
+};
+
+export const TextHeader = (props: TextHeaderProps) => {
+ return (
+ <div className="py3" style={styles.title}>
+ {props.labelText}
+ </div>
+ );
+};
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx
index d4fd6aeaf..b327c9817 100644
--- a/packages/website/ts/components/relayer_index/relayer_index.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_index.tsx
@@ -59,19 +59,13 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
const readyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
if (!readyToRender) {
return (
- <div className="col col-12" style={{ ...styles.root, height: '100%' }}>
- <div
- className="relative sm-px2 sm-pt2 sm-m1"
- style={{ height: 122, top: '33%', transform: 'translateY(-50%)' }}
- >
- <div className="center pb2">
- {_.isUndefined(this.state.error) ? (
- <CircularProgress size={40} thickness={5} />
- ) : (
- <Retry onRetry={this._fetchRelayerInfosAsync.bind(this)} />
- )}
- </div>
- </div>
+ // TODO: consolidate this loading component with the one in portal
+ <div className="center">
+ {_.isUndefined(this.state.error) ? (
+ <CircularProgress size={40} thickness={5} />
+ ) : (
+ <Retry onRetry={this._fetchRelayerInfosAsync.bind(this)} />
+ )}
</div>
);
} else {
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
index 95f31582e..75dbd12e9 100644
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ b/packages/website/ts/components/wallet/wallet.tsx
@@ -18,6 +18,7 @@ import NavigationArrowDownward from 'material-ui/svg-icons/navigation/arrow-down
import NavigationArrowUpward from 'material-ui/svg-icons/navigation/arrow-upward';
import Close from 'material-ui/svg-icons/navigation/close';
import * as React from 'react';
+import { Link } from 'react-router-dom';
import ReactTooltip = require('react-tooltip');
import firstBy = require('thenby');
@@ -38,6 +39,7 @@ import {
TokenByAddress,
TokenState,
TokenStateByAddress,
+ WebsitePaths,
} from 'ts/types';
import { backendClient } from 'ts/utils/backend_client';
import { constants } from 'ts/utils/constants';
@@ -80,7 +82,7 @@ interface AccessoryItemConfig {
const styles: Styles = {
root: {
- width: 346,
+ width: '100%',
backgroundColor: colors.white,
borderBottomRightRadius: 10,
borderBottomLeftRadius: 10,
@@ -134,6 +136,10 @@ const styles: Styles = {
overflow: 'auto',
WebkitOverflowScrolling: 'touch',
},
+ manageYourWalletText: {
+ color: colors.mediumBlue,
+ fontWeight: 'bold',
+ },
};
const ETHER_ICON_PATH = '/images/ether.png';
@@ -237,13 +243,14 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
const userAddress = this.props.userAddress;
const primaryText = utils.getAddressBeginAndEnd(userAddress);
return (
- <ListItem
- key={HEADER_ITEM_KEY}
- primaryText={primaryText}
- leftIcon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
- style={{ ...styles.paddedItem, ...styles.borderedItem }}
- innerDivStyle={styles.headerItemInnerDiv}
- />
+ <Link key={HEADER_ITEM_KEY} to={`${WebsitePaths.Portal}/account`} style={{ textDecoration: 'none' }}>
+ <ListItem
+ primaryText={primaryText}
+ leftIcon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
+ style={{ ...styles.paddedItem, ...styles.borderedItem }}
+ innerDivStyle={styles.headerItemInnerDiv}
+ />
+ </Link>
);
}
private _renderBody(): React.ReactElement<{}> {
@@ -275,31 +282,50 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
}
private _renderFooterRows(): React.ReactElement<{}> {
return (
- <ListItem
- key={FOOTER_ITEM_KEY}
- primaryText={
- <div className="flex">
- <FloatingActionButton mini={true} zDepth={0} onClick={this.props.onAddToken}>
- <ContentAdd />
- </FloatingActionButton>
- <FloatingActionButton mini={true} zDepth={0} className="px1" onClick={this.props.onRemoveToken}>
- <ContentRemove />
- </FloatingActionButton>
- <div
- style={{
- paddingLeft: 10,
- position: 'relative',
- top: '50%',
- transform: 'translateY(33%)',
- }}
- >
- add/remove tokens
+ <div key={FOOTER_ITEM_KEY}>
+ <ListItem
+ primaryText={
+ <div className="flex">
+ <FloatingActionButton mini={true} zDepth={0} onClick={this.props.onAddToken}>
+ <ContentAdd />
+ </FloatingActionButton>
+ <FloatingActionButton
+ mini={true}
+ zDepth={0}
+ className="px1"
+ onClick={this.props.onRemoveToken}
+ >
+ <ContentRemove />
+ </FloatingActionButton>
+ <div
+ style={{
+ paddingLeft: 10,
+ position: 'relative',
+ top: '50%',
+ transform: 'translateY(33%)',
+ }}
+ >
+ add/remove tokens
+ </div>
</div>
- </div>
- }
- disabled={true}
- innerDivStyle={styles.footerItemInnerDiv}
- />
+ }
+ disabled={true}
+ innerDivStyle={styles.footerItemInnerDiv}
+ style={styles.borderedItem}
+ />
+ <Link to={`${WebsitePaths.Portal}/account`} style={{ textDecoration: 'none' }}>
+ <ListItem
+ primaryText={
+ <div className="flex right" style={styles.manageYourWalletText}>
+ {'manage your wallet'}
+ </div>
+ // https://github.com/palantir/tslint-react/issues/140
+ // tslint:disable-next-line:jsx-curly-spacing
+ }
+ style={{ ...styles.paddedItem, ...styles.borderedItem }}
+ />
+ </Link>
+ </div>
);
}
private _renderEthRows(): React.ReactNode {
diff --git a/packages/website/ts/pages/fullscreen_message.tsx b/packages/website/ts/pages/fullscreen_message.tsx
new file mode 100644
index 000000000..6fcf7b32c
--- /dev/null
+++ b/packages/website/ts/pages/fullscreen_message.tsx
@@ -0,0 +1,30 @@
+import { Styles } from '@0xproject/react-shared';
+import * as React from 'react';
+
+export interface FullscreenMessageProps {
+ headerText: string;
+ bodyText: string;
+}
+
+const styles: Styles = {
+ thin: {
+ fontWeight: 100,
+ },
+};
+
+export const FullscreenMessage = (props: FullscreenMessageProps) => {
+ return (
+ <div className="mx-auto max-width-4 py4">
+ <div className="center py4">
+ <div className="py4">
+ <div className="py4">
+ <h1 style={styles.thin}>{props.headerText}</h1>
+ <div className="py1">
+ <div className="py3">{props.bodyText}</div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+};
diff --git a/packages/website/ts/pages/not_found.tsx b/packages/website/ts/pages/not_found.tsx
index 96c73d4ec..674271636 100644
--- a/packages/website/ts/pages/not_found.tsx
+++ b/packages/website/ts/pages/not_found.tsx
@@ -3,6 +3,7 @@ import * as _ from 'lodash';
import * as React from 'react';
import { Footer } from 'ts/components/footer';
import { TopBar } from 'ts/components/top_bar/top_bar';
+import { FullscreenMessage } from 'ts/pages/fullscreen_message';
import { Dispatcher } from 'ts/redux/dispatcher';
import { Translate } from 'ts/utils/translate';
@@ -12,35 +13,15 @@ export interface NotFoundProps {
dispatcher: Dispatcher;
}
-interface NotFoundState {}
-
-const styles: Styles = {
- thin: {
- fontWeight: 100,
- },
+export const NotFound = (props: NotFoundProps) => {
+ return (
+ <div>
+ <TopBar blockchainIsLoaded={false} location={this.props.location} translate={this.props.translate} />
+ <FullscreenMessage
+ headerText={'404 Not Found'}
+ bodyText={"Hm... looks like we couldn't find what you are looking for."}
+ />
+ <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
+ </div>
+ );
};
-
-export class NotFound extends React.Component<NotFoundProps, NotFoundState> {
- public render(): React.ReactNode {
- return (
- <div>
- <TopBar blockchainIsLoaded={false} location={this.props.location} translate={this.props.translate} />
- <div className="mx-auto max-width-4 py4">
- <div className="center py4">
- <div className="py4">
- <div className="py4">
- <h1 style={{ ...styles.thin }}>404 Not Found</h1>
- <div className="py1">
- <div className="py3">
- Hm... looks like we couldn't find what you are looking for.
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
- </div>
- );
- }
-}