aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrandon Millman <brandon@0xproject.com>2018-06-01 04:34:12 +0800
committerGitHub <noreply@github.com>2018-06-01 04:34:12 +0800
commit6fd87568e738c114dbba9be85cf470c11117ec0a (patch)
tree18115a5876a17885f1f9798f0bfde84af6b3a560
parent484fd68495bf921c57a09b413d978b028f0c80e8 (diff)
parent00df102c295b833b7e8ec5c34916f256e560de5e (diff)
downloaddexon-sol-tools-6fd87568e738c114dbba9be85cf470c11117ec0a.tar
dexon-sol-tools-6fd87568e738c114dbba9be85cf470c11117ec0a.tar.gz
dexon-sol-tools-6fd87568e738c114dbba9be85cf470c11117ec0a.tar.bz2
dexon-sol-tools-6fd87568e738c114dbba9be85cf470c11117ec0a.tar.lz
dexon-sol-tools-6fd87568e738c114dbba9be85cf470c11117ec0a.tar.xz
dexon-sol-tools-6fd87568e738c114dbba9be85cf470c11117ec0a.tar.zst
dexon-sol-tools-6fd87568e738c114dbba9be85cf470c11117ec0a.zip
Merge pull request #643 from 0xProject/feature/website/wallet-loading
Add loading states to wallet and provider display
-rw-r--r--packages/website/ts/blockchain_watcher.ts6
-rw-r--r--packages/website/ts/components/eth_weth_conversion_button.tsx2
-rw-r--r--packages/website/ts/components/eth_wrappers.tsx2
-rw-r--r--packages/website/ts/components/legacy_portal/legacy_portal.tsx2
-rw-r--r--packages/website/ts/components/onboarding/portal_onboarding_flow.tsx4
-rw-r--r--packages/website/ts/components/portal/portal.tsx2
-rw-r--r--packages/website/ts/components/token_balances.tsx3
-rw-r--r--packages/website/ts/components/top_bar/provider_display.tsx36
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx25
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx191
-rw-r--r--packages/website/ts/components/wallet/wallet_disconnected_item.tsx2
-rw-r--r--packages/website/ts/containers/legacy_portal.ts2
-rw-r--r--packages/website/ts/containers/portal.ts2
-rw-r--r--packages/website/ts/containers/portal_onboarding_flow.ts4
-rw-r--r--packages/website/ts/redux/dispatcher.ts2
-rw-r--r--packages/website/ts/redux/reducer.ts4
16 files changed, 195 insertions, 94 deletions
diff --git a/packages/website/ts/blockchain_watcher.ts b/packages/website/ts/blockchain_watcher.ts
index c420a98a4..0d376bc74 100644
--- a/packages/website/ts/blockchain_watcher.ts
+++ b/packages/website/ts/blockchain_watcher.ts
@@ -10,7 +10,7 @@ export class BlockchainWatcher {
private _prevNetworkId: number;
private _shouldPollUserAddress: boolean;
private _watchNetworkAndBalanceIntervalId: NodeJS.Timer;
- private _prevUserEtherBalanceInWei: BigNumber;
+ private _prevUserEtherBalanceInWei?: BigNumber;
private _prevUserAddressIfExists: string;
constructor(
dispatcher: Dispatcher,
@@ -41,7 +41,7 @@ export class BlockchainWatcher {
}
let prevNodeVersion: string;
- this._prevUserEtherBalanceInWei = new BigNumber(0);
+ this._prevUserEtherBalanceInWei = undefined;
this._dispatcher.updateNetworkId(this._prevNetworkId);
this._watchNetworkAndBalanceIntervalId = intervalUtils.setAsyncExcludingInterval(
async () => {
@@ -94,7 +94,7 @@ export class BlockchainWatcher {
}
private async _updateUserWeiBalanceAsync(userAddress: string): Promise<void> {
const balanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(userAddress);
- if (!balanceInWei.eq(this._prevUserEtherBalanceInWei)) {
+ if (_.isUndefined(this._prevUserEtherBalanceInWei) || !balanceInWei.eq(this._prevUserEtherBalanceInWei)) {
this._prevUserEtherBalanceInWei = balanceInWei;
this._dispatcher.updateUserWeiBalance(balanceInWei);
}
diff --git a/packages/website/ts/components/eth_weth_conversion_button.tsx b/packages/website/ts/components/eth_weth_conversion_button.tsx
index 4b91a2ebd..2fb35cc1c 100644
--- a/packages/website/ts/components/eth_weth_conversion_button.tsx
+++ b/packages/website/ts/components/eth_weth_conversion_button.tsx
@@ -18,7 +18,7 @@ interface EthWethConversionButtonProps {
ethToken: Token;
dispatcher: Dispatcher;
blockchain: Blockchain;
- userEtherBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
isOutdatedWrappedEther: boolean;
onConversionSuccessful?: () => void;
isDisabled?: boolean;
diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx
index a5758a66a..1db5ff77f 100644
--- a/packages/website/ts/components/eth_wrappers.tsx
+++ b/packages/website/ts/components/eth_wrappers.tsx
@@ -33,7 +33,7 @@ interface EthWrappersProps {
dispatcher: Dispatcher;
tokenByAddress: TokenByAddress;
userAddress: string;
- userEtherBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
lastForceTokenStateRefetch: number;
}
diff --git a/packages/website/ts/components/legacy_portal/legacy_portal.tsx b/packages/website/ts/components/legacy_portal/legacy_portal.tsx
index a5ea95629..6a3a54303 100644
--- a/packages/website/ts/components/legacy_portal/legacy_portal.tsx
+++ b/packages/website/ts/components/legacy_portal/legacy_portal.tsx
@@ -55,7 +55,7 @@ export interface LegacyPortalProps {
providerType: ProviderType;
screenWidth: ScreenWidths;
tokenByAddress: TokenByAddress;
- userEtherBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
userAddress: string;
shouldBlockchainErrDialogBeOpen: boolean;
userSuppliedOrderCache: Order;
diff --git a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
index edaeb3736..2014dd7b0 100644
--- a/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
+++ b/packages/website/ts/components/onboarding/portal_onboarding_flow.tsx
@@ -14,7 +14,7 @@ export interface PortalOnboardingFlowProps {
providerType: ProviderType;
injectedProviderName: string;
blockchainIsLoaded: boolean;
- userEthBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
tokenByAddress: TokenByAddress;
updateIsRunning: (isRunning: boolean) => void;
updateOnboardingStep: (stepIndex: number) => void;
@@ -85,7 +85,7 @@ export class PortalOnboardingFlow extends React.Component<PortalOnboardingFlowPr
}
private _userHasEth(): boolean {
- return this.props.userEthBalanceInWei > new BigNumber(0);
+ return this.props.userEtherBalanceInWei > new BigNumber(0);
}
private _userHasWeth(): boolean {
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx
index 0e1506e17..e08393791 100644
--- a/packages/website/ts/components/portal/portal.tsx
+++ b/packages/website/ts/components/portal/portal.tsx
@@ -57,7 +57,7 @@ export interface PortalProps {
providerType: ProviderType;
screenWidth: ScreenWidths;
tokenByAddress: TokenByAddress;
- userEtherBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
userAddress: string;
shouldBlockchainErrDialogBeOpen: boolean;
userSuppliedOrderCache: Order;
diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx
index f5a51dabb..7a0742bbe 100644
--- a/packages/website/ts/components/token_balances.tsx
+++ b/packages/website/ts/components/token_balances.tsx
@@ -85,6 +85,9 @@ interface TokenBalancesState {
}
export class TokenBalances extends React.Component<TokenBalancesProps, TokenBalancesState> {
+ public static defaultProps: Partial<TokenBalancesProps> = {
+ userEtherBalanceInWei: new BigNumber(0),
+ };
private _isUnmounted: boolean;
public constructor(props: TokenBalancesProps) {
super(props);
diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx
index 679ec07dc..8a337119a 100644
--- a/packages/website/ts/components/top_bar/provider_display.tsx
+++ b/packages/website/ts/components/top_bar/provider_display.tsx
@@ -1,5 +1,6 @@
import { Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
+import CircularProgress from 'material-ui/CircularProgress';
import RaisedButton from 'material-ui/RaisedButton';
import * as React from 'react';
@@ -23,7 +24,8 @@ export interface ProviderDisplayProps {
injectedProviderName: string;
providerType: ProviderType;
onToggleLedgerDialog: () => void;
- blockchain: Blockchain;
+ blockchain?: Blockchain;
+ blockchainIsLoaded: boolean;
}
interface ProviderDisplayState {}
@@ -44,11 +46,18 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
this.props.providerType,
this.props.injectedProviderName,
);
- const displayAddress = isAddressAvailable
- ? utils.getAddressBeginAndEnd(this.props.userAddress)
- : isExternallyInjectedProvider
- ? 'Account locked'
- : '0x0000...0000';
+ let displayMessage;
+ if (!this._isBlockchainReady()) {
+ displayMessage = 'loading account';
+ } else if (isAddressAvailable) {
+ displayMessage = utils.getAddressBeginAndEnd(this.props.userAddress);
+ // tslint:disable-next-line: prefer-conditional-expression
+ } else if (isExternallyInjectedProvider) {
+ displayMessage = 'Account locked';
+ } else {
+ displayMessage = '0x0000...0000';
+ }
+
// If the "injected" provider is our fallback public node, then we want to
// show the "connect a wallet" message instead of the providerName
const injectedProviderName = isExternallyInjectedProvider
@@ -60,10 +69,14 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
const hoverActiveNode = (
<div className="flex right lg-pr0 md-pr2 sm-pr2 p1" style={styles.root}>
<div>
- <Identicon address={this.props.userAddress} diameter={ROOT_HEIGHT} />
+ {this._isBlockchainReady() ? (
+ <Identicon address={this.props.userAddress} diameter={ROOT_HEIGHT} />
+ ) : (
+ <CircularProgress size={ROOT_HEIGHT} thickness={2} />
+ )}
</div>
<div style={{ marginLeft: 12, paddingTop: 3 }}>
- <div style={{ fontSize: 16, color: colors.darkGrey }}>{displayAddress}</div>
+ <div style={{ fontSize: 16, color: colors.darkGrey }}>{displayMessage}</div>
</div>
{isProviderMetamask && (
<div style={{ marginLeft: 16 }}>
@@ -87,7 +100,9 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
);
}
public renderPopoverContent(hasInjectedProvider: boolean, hasLedgerProvider: boolean): React.ReactNode {
- if (hasInjectedProvider || hasLedgerProvider) {
+ if (!this._isBlockchainReady()) {
+ return null;
+ } else if (hasInjectedProvider || hasLedgerProvider) {
return (
<ProviderPicker
dispatcher={this.props.dispatcher}
@@ -159,4 +174,7 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
);
}
}
+ private _isBlockchainReady(): boolean {
+ return this.props.blockchainIsLoaded && !_.isUndefined(this.props.blockchain);
+ }
}
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
index db8e3cb82..0855d2584 100644
--- a/packages/website/ts/components/top_bar/top_bar.tsx
+++ b/packages/website/ts/components/top_bar/top_bar.tsx
@@ -261,19 +261,18 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
</div>
)}
- {this.props.blockchainIsLoaded && (
- <div className="sm-hide xs-hide col col-5" style={{ paddingTop: 8, marginRight: 36 }}>
- <ProviderDisplay
- dispatcher={this.props.dispatcher}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- onToggleLedgerDialog={this.props.onToggleLedgerDialog}
- blockchain={this.props.blockchain}
- />
- </div>
- )}
+ <div className="sm-hide xs-hide col col-5" style={{ paddingTop: 8, marginRight: 36 }}>
+ <ProviderDisplay
+ dispatcher={this.props.dispatcher}
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ injectedProviderName={this.props.injectedProviderName}
+ providerType={this.props.providerType}
+ onToggleLedgerDialog={this.props.onToggleLedgerDialog}
+ blockchain={this.props.blockchain}
+ blockchainIsLoaded={this.props.blockchainIsLoaded}
+ />
+ </div>
<div className={`col ${isExpandedDisplayType ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}>
<div style={menuIconStyle}>
<i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} />
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
index 30d1285f4..18dada22f 100644
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ b/packages/website/ts/components/wallet/wallet.tsx
@@ -7,6 +7,7 @@ import {
import { BigNumber } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
+import CircularProgress from 'material-ui/CircularProgress';
import FlatButton from 'material-ui/FlatButton';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import { ListItem } from 'material-ui/List';
@@ -23,6 +24,7 @@ import firstBy = require('thenby');
import { Blockchain } from 'ts/blockchain';
import { AllowanceToggle } from 'ts/components/inputs/allowance_toggle';
+import { Container } from 'ts/components/ui/container';
import { IconButton } from 'ts/components/ui/icon_button';
import { Identicon } from 'ts/components/ui/identicon';
import { Island } from 'ts/components/ui/island';
@@ -59,7 +61,7 @@ export interface WalletProps {
dispatcher: Dispatcher;
tokenByAddress: TokenByAddress;
trackedTokens: Token[];
- userEtherBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
lastForceTokenStateRefetch: number;
injectedProviderName: string;
providerType: ProviderType;
@@ -92,9 +94,6 @@ const styles: Styles = {
zIndex: zIndex.aboveOverlay,
position: 'relative',
},
- headerItemInnerDiv: {
- paddingLeft: 65,
- },
footerItemInnerDiv: {
paddingLeft: 24,
borderTopColor: colors.walletBorder,
@@ -108,6 +107,7 @@ const styles: Styles = {
},
tokenItem: {
backgroundColor: colors.walletDefaultItemBackground,
+ minHeight: 85,
},
amountLabel: {
fontWeight: 'bold',
@@ -129,10 +129,13 @@ const styles: Styles = {
color: colors.mediumBlue,
fontWeight: 'bold',
},
+ loadingBody: {
+ height: 381,
+ },
};
const ETHER_ICON_PATH = '/images/ether.png';
-const ICON_DIMENSION = 24;
+const ICON_DIMENSION = 28;
const TOKEN_AMOUNT_DISPLAY_PRECISION = 3;
const BODY_ITEM_KEY = 'BODY';
const HEADER_ITEM_KEY = 'HEADER';
@@ -191,26 +194,40 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
}
}
public render(): React.ReactNode {
- const isReadyToRender = this.props.blockchainIsLoaded && this.props.blockchainErr === BlockchainErrs.NoError;
- const isAddressAvailable = !_.isEmpty(this.props.userAddress);
+ const isBlockchainLoaded = this.props.blockchainIsLoaded && this.props.blockchainErr === BlockchainErrs.NoError;
return (
<Island className="flex flex-column wallet" style={styles.root}>
- {isReadyToRender && isAddressAvailable
- ? _.concat(this._renderConnectedHeaderRows(), this._renderBody(), this._renderFooterRows())
- : _.concat(this._renderDisconnectedHeaderRows(), this._renderDisconnectedRows())}
+ {isBlockchainLoaded ? this._renderLoadedRows() : this._renderLoadingRows()}
</Island>
);
}
+ private _renderLoadedRows(): React.ReactNode {
+ const isAddressAvailable = !_.isEmpty(this.props.userAddress);
+ return isAddressAvailable
+ ? _.concat(this._renderConnectedHeaderRows(), this._renderBody(), this._renderFooterRows())
+ : _.concat(this._renderDisconnectedHeaderRows(), this._renderDisconnectedRows());
+ }
+ private _renderLoadingRows(): React.ReactNode {
+ return _.concat(this._renderDisconnectedHeaderRows(), this._renderLoadingBodyRows());
+ }
+ private _renderLoadingBodyRows(): React.ReactElement<{}> {
+ return (
+ <div key={BODY_ITEM_KEY} className="flex items-center" style={styles.loadingBody}>
+ <div className="mx-auto">
+ <CircularProgress size={40} thickness={5} />
+ </div>
+ </div>
+ );
+ }
private _renderDisconnectedHeaderRows(): React.ReactElement<{}> {
const userAddress = this.props.userAddress;
const primaryText = 'wallet';
return (
- <ListItem
+ <StandardIconRow
key={HEADER_ITEM_KEY}
- primaryText={primaryText.toUpperCase()}
- leftIcon={<ActionAccountBalanceWallet color={colors.mediumBlue} />}
- style={styles.paddedItem}
- innerDivStyle={styles.headerItemInnerDiv}
+ icon={<ActionAccountBalanceWallet color={colors.mediumBlue} />}
+ main={primaryText.toUpperCase()}
+ style={styles.borderedItem}
/>
);
}
@@ -229,11 +246,10 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
const primaryText = utils.getAddressBeginAndEnd(userAddress);
return (
<Link key={HEADER_ITEM_KEY} to={ACCOUNT_PATH} style={{ textDecoration: 'none' }}>
- <ListItem
- primaryText={primaryText}
- leftIcon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
- style={{ ...styles.paddedItem, ...styles.borderedItem }}
- innerDivStyle={styles.headerItemInnerDiv}
+ <StandardIconRow
+ icon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
+ main={primaryText}
+ style={styles.borderedItem}
/>
</Link>
);
@@ -320,26 +336,23 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
private _renderEthRows(): React.ReactNode {
const icon = <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />;
const primaryText = this._renderAmount(
- this.props.userEtherBalanceInWei,
+ this.props.userEtherBalanceInWei || new BigNumber(0),
constants.DECIMAL_PLACES_ETH,
constants.ETHER_SYMBOL,
+ _.isUndefined(this.props.userEtherBalanceInWei),
);
const etherToken = this._getEthToken();
- const etherPrice = this.state.trackedTokenStateByAddress[etherToken.address].price;
+ const etherTokenState = this.state.trackedTokenStateByAddress[etherToken.address];
+ const etherPrice = etherTokenState.price;
const secondaryText = this._renderValue(
- this.props.userEtherBalanceInWei,
+ this.props.userEtherBalanceInWei || new BigNumber(0),
constants.DECIMAL_PLACES_ETH,
etherPrice,
+ _.isUndefined(this.props.userEtherBalanceInWei) || !etherTokenState.isLoaded,
);
const accessoryItemConfig = {
wrappedEtherDirection: Side.Deposit,
};
- const isInWrappedEtherState =
- !_.isUndefined(this.state.wrappedEtherDirection) &&
- this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection;
- const style = isInWrappedEtherState
- ? { ...walletItemStyles.focusedItem, ...styles.paddedItem }
- : { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
const key = ETHER_ITEM_KEY;
return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig, 'eth-row');
}
@@ -360,10 +373,15 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
EtherscanLinkSuffixes.Address,
);
const icon = <TokenIcon token={token} diameter={ICON_DIMENSION} link={tokenLink} />;
- const primaryText = this._renderAmount(tokenState.balance, token.decimals, token.symbol);
- const secondaryText = this._renderValue(tokenState.balance, token.decimals, tokenState.price);
const isWeth = token.symbol === constants.ETHER_TOKEN_SYMBOL;
const wrappedEtherDirection = isWeth ? Side.Receive : undefined;
+ const primaryText = this._renderAmount(tokenState.balance, token.decimals, token.symbol, !tokenState.isLoaded);
+ const secondaryText = this._renderValue(
+ tokenState.balance,
+ token.decimals,
+ tokenState.price,
+ !tokenState.isLoaded,
+ );
const accessoryItemConfig: AccessoryItemConfig = {
wrappedEtherDirection,
allowanceToggleConfig: {
@@ -391,22 +409,24 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
): React.ReactNode {
const shouldShowWrapEtherItem =
!_.isUndefined(this.state.wrappedEtherDirection) &&
- this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection;
- const style = shouldShowWrapEtherItem
- ? { ...walletItemStyles.focusedItem, ...styles.paddedItem }
- : { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
+ this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection &&
+ !_.isUndefined(this.props.userEtherBalanceInWei);
+ const additionalStyle = shouldShowWrapEtherItem ? walletItemStyles.focusedItem : styles.borderedItem;
+ const style = { ...styles.tokenItem, ...additionalStyle };
const etherToken = this._getEthToken();
return (
<div key={key} className={`flex flex-column ${className || ''}`}>
- <div className="flex items-center" style={style}>
- <div className="px2">{icon}</div>
- <div className="flex-none pr2 pt2 pb2">
- {primaryText}
- {secondaryText}
- </div>
- <div className="flex-auto" />
- <div>{this._renderAccessoryItems(accessoryItemConfig)}</div>
- </div>
+ <StandardIconRow
+ icon={icon}
+ main={
+ <div className="flex flex-column">
+ {primaryText}
+ <Container marginTop="3px">{secondaryText}</Container>
+ </div>
+ }
+ accessory={this._renderAccessoryItems(accessoryItemConfig)}
+ style={style}
+ />
{shouldShowWrapEtherItem && (
<WrapEtherItem
userAddress={this.props.userAddress}
@@ -458,21 +478,45 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
/>
);
}
- private _renderAmount(amount: BigNumber, decimals: number, symbol: string): React.ReactNode {
+ private _renderAmount(
+ amount: BigNumber,
+ decimals: number,
+ symbol: string,
+ isLoading: boolean = false,
+ ): React.ReactNode {
const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
const formattedAmount = unitAmount.toPrecision(TOKEN_AMOUNT_DISPLAY_PRECISION);
const result = `${formattedAmount} ${symbol}`;
- return <div style={styles.amountLabel}>{result}</div>;
+ return (
+ <PlaceHolder hideChildren={isLoading}>
+ <div style={styles.amountLabel}>{result}</div>
+ </PlaceHolder>
+ );
}
- private _renderValue(amount: BigNumber, decimals: number, price?: BigNumber): React.ReactNode {
- if (_.isUndefined(price)) {
- return null;
+ private _renderValue(
+ amount: BigNumber,
+ decimals: number,
+ price?: BigNumber,
+ isLoading: boolean = false,
+ ): React.ReactNode {
+ let result;
+ if (!isLoading) {
+ if (_.isUndefined(price)) {
+ result = '--';
+ } else {
+ const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
+ const value = unitAmount.mul(price);
+ const formattedAmount = value.toFixed(USD_DECIMAL_PLACES);
+ result = `$${formattedAmount}`;
+ }
+ } else {
+ result = '$0.00';
}
- const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- const value = unitAmount.mul(price);
- const formattedAmount = value.toFixed(USD_DECIMAL_PLACES);
- const result = `$${formattedAmount}`;
- return <div style={styles.valueLabel}>{result}</div>;
+ return (
+ <PlaceHolder hideChildren={isLoading}>
+ <div style={styles.valueLabel}>{result}</div>
+ </PlaceHolder>
+ );
}
private _renderWrappedEtherButton(wrappedEtherDirection: Side): React.ReactNode {
const isWrappedEtherDirectionOpen = this.state.wrappedEtherDirection === wrappedEtherDirection;
@@ -589,4 +633,41 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
private _getEthToken(): Token {
return utils.getEthToken(this.props.tokenByAddress);
}
-} // tslint:disable:max-file-line-count
+}
+
+interface StandardIconRowProps {
+ icon: React.ReactNode;
+ main: React.ReactNode;
+ accessory?: React.ReactNode;
+ style?: React.CSSProperties;
+}
+const StandardIconRow = (props: StandardIconRowProps) => {
+ return (
+ <div className="flex items-center" style={props.style}>
+ <div className="p2">{props.icon}</div>
+ <div className="flex-none pr2 pt2 pb2">{props.main}</div>
+ <div className="flex-auto" />
+ <div>{props.accessory}</div>
+ </div>
+ );
+};
+interface PlaceHolderProps {
+ hideChildren: React.ReactNode;
+ children?: React.ReactNode;
+}
+const PlaceHolder = (props: PlaceHolderProps) => {
+ const rootBackgroundColor = props.hideChildren ? colors.lightGrey : 'transparent';
+ const rootStyle: React.CSSProperties = {
+ backgroundColor: rootBackgroundColor,
+ display: 'inline-block',
+ borderRadius: 2,
+ };
+ const childrenVisibility = props.hideChildren ? 'hidden' : 'visible';
+ const childrenStyle: React.CSSProperties = { visibility: childrenVisibility };
+ return (
+ <div style={rootStyle}>
+ <div style={childrenStyle}>{props.children}</div>
+ </div>
+ );
+};
+// tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/wallet/wallet_disconnected_item.tsx b/packages/website/ts/components/wallet/wallet_disconnected_item.tsx
index 39a62e1fb..17fd8a19e 100644
--- a/packages/website/ts/components/wallet/wallet_disconnected_item.tsx
+++ b/packages/website/ts/components/wallet/wallet_disconnected_item.tsx
@@ -31,7 +31,7 @@ const styles: Styles = {
},
};
-const ITEM_HEIGHT = 292;
+const ITEM_HEIGHT = 381;
const METAMASK_ICON_WIDTH = 35;
const LEDGER_ICON_WIDTH = 30;
const BUTTON_BOTTOM_PADDING = 80;
diff --git a/packages/website/ts/containers/legacy_portal.ts b/packages/website/ts/containers/legacy_portal.ts
index 3b1172a44..eae450c21 100644
--- a/packages/website/ts/containers/legacy_portal.ts
+++ b/packages/website/ts/containers/legacy_portal.ts
@@ -24,7 +24,7 @@ interface ConnectedState {
providerType: ProviderType;
tokenByAddress: TokenByAddress;
lastForceTokenStateRefetch: number;
- userEtherBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
screenWidth: ScreenWidths;
shouldBlockchainErrDialogBeOpen: boolean;
userAddress: string;
diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts
index 3f0feb6e9..b8c8fb999 100644
--- a/packages/website/ts/containers/portal.ts
+++ b/packages/website/ts/containers/portal.ts
@@ -21,7 +21,7 @@ interface ConnectedState {
providerType: ProviderType;
tokenByAddress: TokenByAddress;
lastForceTokenStateRefetch: number;
- userEtherBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
screenWidth: ScreenWidths;
shouldBlockchainErrDialogBeOpen: boolean;
userAddress: string;
diff --git a/packages/website/ts/containers/portal_onboarding_flow.ts b/packages/website/ts/containers/portal_onboarding_flow.ts
index 84739192f..8202fb2ae 100644
--- a/packages/website/ts/containers/portal_onboarding_flow.ts
+++ b/packages/website/ts/containers/portal_onboarding_flow.ts
@@ -17,7 +17,7 @@ interface ConnectedState {
providerType: ProviderType;
injectedProviderName: string;
blockchainIsLoaded: boolean;
- userEthBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
tokenByAddress: TokenByAddress;
}
@@ -33,7 +33,7 @@ const mapStateToProps = (state: State): ConnectedState => ({
providerType: state.providerType,
injectedProviderName: state.injectedProviderName,
blockchainIsLoaded: state.blockchainIsLoaded,
- userEthBalanceInWei: state.userEtherBalanceInWei,
+ userEtherBalanceInWei: state.userEtherBalanceInWei,
tokenByAddress: state.tokenByAddress,
hasBeenSeen: state.hasPortalOnboardingBeenSeen,
});
diff --git a/packages/website/ts/redux/dispatcher.ts b/packages/website/ts/redux/dispatcher.ts
index 0b4cc3938..e0ce43ae5 100644
--- a/packages/website/ts/redux/dispatcher.ts
+++ b/packages/website/ts/redux/dispatcher.ts
@@ -155,7 +155,7 @@ export class Dispatcher {
type: ActionTypes.UpdateOrderECSignature,
});
}
- public updateUserWeiBalance(balance: BigNumber): void {
+ public updateUserWeiBalance(balance?: BigNumber): void {
this._dispatch({
data: balance,
type: ActionTypes.UpdateUserEtherBalance,
diff --git a/packages/website/ts/redux/reducer.ts b/packages/website/ts/redux/reducer.ts
index 5c57792f7..9d3d8f7d9 100644
--- a/packages/website/ts/redux/reducer.ts
+++ b/packages/website/ts/redux/reducer.ts
@@ -39,7 +39,7 @@ export interface State {
tokenByAddress: TokenByAddress;
lastForceTokenStateRefetch: number;
userAddress: string;
- userEtherBalanceInWei: BigNumber;
+ userEtherBalanceInWei?: BigNumber;
portalOnboardingStep: number;
isPortalOnboardingShowing: boolean;
hasPortalOnboardingBeenSeen: boolean;
@@ -81,7 +81,7 @@ export const INITIAL_STATE: State = {
tokenByAddress: {},
lastForceTokenStateRefetch: moment().unix(),
userAddress: '',
- userEtherBalanceInWei: new BigNumber(0),
+ userEtherBalanceInWei: undefined,
userSuppliedOrderCache: undefined,
portalOnboardingStep: 0,
isPortalOnboardingShowing: false,