aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/components/relayer_index
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/components/relayer_index')
-rw-r--r--packages/website/ts/components/relayer_index/relayer_grid_tile.tsx77
-rw-r--r--packages/website/ts/components/relayer_index/relayer_index.tsx70
-rw-r--r--packages/website/ts/components/relayer_index/relayer_top_tokens.tsx16
3 files changed, 109 insertions, 54 deletions
diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
index 0c4b2841c..d88a59d15 100644
--- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
@@ -12,38 +12,6 @@ export interface RelayerGridTileProps {
networkId: number;
}
-// TODO: Get top tokens and headerurl from remote
-const headerUrl = '/images/og_image.png';
-const topTokens = [
- {
- address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba',
- decimals: 18,
- iconUrl: '/images/token_icons/makerdao.png',
- isRegistered: true,
- isTracked: true,
- name: 'Maker DAO',
- symbol: 'MKR',
- },
- {
- address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
- decimals: 18,
- iconUrl: '/images/token_icons/melon.png',
- isRegistered: true,
- isTracked: true,
- name: 'Melon Token',
- symbol: 'MLN',
- },
- {
- address: '0xb18845c260f680d5b9d84649638813e342e4f8c9',
- decimals: 18,
- iconUrl: '/images/token_icons/augur.png',
- isRegistered: true,
- isTracked: true,
- name: 'Augur Reputation Token',
- symbol: 'REP',
- },
-];
-
const styles: Styles = {
root: {
backgroundColor: colors.white,
@@ -68,6 +36,9 @@ const styles: Styles = {
borderBottomLeftRadius: 4,
borderTopRightRadius: 4,
borderTopLeftRadius: 4,
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: colors.walletBorder,
},
body: {
paddingLeft: 6,
@@ -91,11 +62,20 @@ const styles: Styles = {
},
};
+const FALLBACK_IMG_SRC = '/images/landing/hero_chip_image.png';
+
export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (props: RelayerGridTileProps) => {
+ const link = props.relayerInfo.appUrl || props.relayerInfo.url;
return (
<GridTile style={styles.root}>
<div style={styles.innerDiv}>
- <img src={headerUrl} style={styles.header} />
+ <a href={link} target="_blank" style={{ textDecoration: 'none' }}>
+ <ImgWithFallback
+ src={props.relayerInfo.headerImgUrl}
+ fallbackSrc={FALLBACK_IMG_SRC}
+ style={styles.header}
+ />
+ </a>
<div style={styles.body}>
<div className="py1" style={styles.relayerNameLabel}>
{props.relayerInfo.name}
@@ -104,7 +84,7 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (
<div className="py1" style={styles.subLabel}>
Daily Trade Volume
</div>
- <TopTokens tokens={topTokens} networkId={props.networkId} />
+ <TopTokens tokens={props.relayerInfo.topTokens} networkId={props.networkId} />
<div className="py1" style={styles.subLabel}>
Top tokens
</div>
@@ -113,3 +93,32 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (
</GridTile>
);
};
+
+interface ImgWithFallbackProps {
+ src?: string;
+ fallbackSrc: string;
+ style: React.CSSProperties;
+}
+interface ImgWithFallbackState {
+ imageLoadFailed: boolean;
+}
+class ImgWithFallback extends React.Component<ImgWithFallbackProps, ImgWithFallbackState> {
+ constructor(props: ImgWithFallbackProps) {
+ super(props);
+ this.state = {
+ imageLoadFailed: false,
+ };
+ }
+ public render() {
+ if (this.state.imageLoadFailed || _.isUndefined(this.props.src)) {
+ return <img src={this.props.fallbackSrc} style={this.props.style} />;
+ } else {
+ return <img src={this.props.src} onError={this._onError.bind(this)} style={this.props.style} />;
+ }
+ }
+ private _onError() {
+ this.setState({
+ imageLoadFailed: true,
+ });
+ }
+}
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx
index 50760c32d..dffd0f83f 100644
--- a/packages/website/ts/components/relayer_index/relayer_index.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_index.tsx
@@ -1,5 +1,7 @@
import { colors, Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
+import CircularProgress from 'material-ui/CircularProgress';
+import FlatButton from 'material-ui/FlatButton';
import { GridList } from 'material-ui/GridList';
import * as React from 'react';
@@ -32,9 +34,9 @@ const styles: Styles = {
},
};
-const CELL_HEIGHT = 260;
+const CELL_HEIGHT = 290;
const NUMBER_OF_COLUMNS = 4;
-const GRID_PADDING = 16;
+const GRID_PADDING = 20;
export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerIndexState> {
private _isUnmounted: boolean;
@@ -55,7 +57,24 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
}
public render() {
const readyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
- if (readyToRender) {
+ 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>
+ </div>
+ );
+ } else {
return (
<div style={styles.root}>
<GridList
@@ -64,23 +83,22 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
padding={GRID_PADDING}
style={styles.gridList}
>
- {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo) => (
- <RelayerGridTile
- key={relayerInfo.id}
- relayerInfo={relayerInfo}
- networkId={this.props.networkId}
- />
+ {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => (
+ <RelayerGridTile key={index} relayerInfo={relayerInfo} networkId={this.props.networkId} />
))}
</GridList>
</div>
);
- } else {
- // TODO: loading and error states with a scrolling container
- return null;
}
}
private async _fetchRelayerInfosAsync(): Promise<void> {
try {
+ if (!this._isUnmounted) {
+ this.setState({
+ relayerInfos: undefined,
+ error: undefined,
+ });
+ }
const relayerInfos = await backendClient.getRelayerInfosAsync();
if (!this._isUnmounted) {
this.setState({
@@ -96,3 +114,31 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
}
}
}
+
+interface RetryProps {
+ onRetry: () => void;
+}
+const Retry = (props: RetryProps) => (
+ <div className="clearfix center" style={{ color: colors.black }}>
+ <div className="mx-auto inline-block align-middle" style={{ lineHeight: '44px', textAlign: 'center' }}>
+ <div className="h2" style={{ fontFamily: 'Roboto Mono' }}>
+ Something went wrong.
+ </div>
+ <div className="py3">
+ <FlatButton
+ label={'reload'}
+ backgroundColor={colors.black}
+ labelStyle={{
+ fontSize: 18,
+ fontFamily: 'Roboto Mono',
+ fontWeight: 'lighter',
+ color: colors.white,
+ textTransform: 'lowercase',
+ }}
+ style={{ width: 280, height: 62, borderRadius: 5 }}
+ onClick={props.onRetry}
+ />
+ </div>
+ </div>
+ </div>
+);
diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
index 233590b78..db4d3a211 100644
--- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
@@ -3,10 +3,10 @@ import * as _ from 'lodash';
import * as React from 'react';
import { TokenIcon } from 'ts/components/ui/token_icon';
-import { Token } from 'ts/types';
+import { WebsiteBackendTokenInfo } from 'ts/types';
export interface TopTokensProps {
- tokens: Token[];
+ tokens: WebsiteBackendTokenInfo[];
networkId: number;
}
@@ -23,17 +23,17 @@ const styles: Styles = {
export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTokensProps) => {
return (
<div className="flex">
- {_.map(props.tokens, (token: Token, index: number) => {
+ {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo, index: number) => {
const firstItemStyle = { ...styles.tokenLabel, ...styles.followingTokenLabel };
const style = index !== 0 ? firstItemStyle : styles.tokenLabel;
return (
<a
- key={token.address}
- href={tokenLinkFromToken(token, props.networkId)}
+ key={tokenInfo.address}
+ href={tokenLinkFromToken(tokenInfo, props.networkId)}
target="_blank"
style={style}
>
- {token.symbol}
+ {tokenInfo.symbol}
</a>
);
})}
@@ -41,6 +41,6 @@ export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTo
);
};
-function tokenLinkFromToken(token: Token, networkId: number) {
- return sharedUtils.getEtherScanLinkIfExists(token.address, networkId, EtherscanLinkSuffixes.Address);
+function tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number) {
+ return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address);
}