aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts')
-rw-r--r--packages/website/ts/components/portal/portal.tsx98
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx85
2 files changed, 100 insertions, 83 deletions
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx
index 589ad00ad..af90e2a09 100644
--- a/packages/website/ts/components/portal/portal.tsx
+++ b/packages/website/ts/components/portal/portal.tsx
@@ -37,7 +37,9 @@ import {
Order,
ProviderType,
ScreenWidths,
+ Token,
TokenByAddress,
+ TokenStateByAddress,
TokenVisibility,
WebsitePaths,
} from 'ts/types';
@@ -77,6 +79,7 @@ interface PortalState {
isDisclaimerDialogOpen: boolean;
isLedgerDialogOpen: boolean;
tokenManagementState: TokenManagementState;
+ trackedTokenStateByAddress: TokenStateByAddress;
}
interface AccountManagementItem {
@@ -127,6 +130,9 @@ export class Portal extends React.Component<PortalProps, PortalState> {
const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER);
const hasAcceptedDisclaimer =
!_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer);
+ const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(
+ this._getCurrentTrackedTokens(),
+ );
this.state = {
prevNetworkId: this.props.networkId,
prevNodeVersion: this.props.nodeVersion,
@@ -135,6 +141,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
isDisclaimerDialogOpen: !hasAcceptedDisclaimer,
tokenManagementState: TokenManagementState.None,
isLedgerDialogOpen: false,
+ trackedTokenStateByAddress: initialTrackedTokenStateByAddress,
};
}
public componentDidMount(): void {
@@ -143,6 +150,9 @@ export class Portal extends React.Component<PortalProps, PortalState> {
}
public componentWillMount(): void {
this._blockchain = new Blockchain(this.props.dispatcher);
+ const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
+ // tslint:disable-next-line:no-floating-promises
+ this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
}
public componentWillUnmount(): void {
this._blockchain.destroy();
@@ -178,6 +188,39 @@ export class Portal extends React.Component<PortalProps, PortalState> {
prevPathname: nextProps.location.pathname,
});
}
+ if (
+ nextProps.userAddress !== this.props.userAddress ||
+ nextProps.networkId !== this.props.networkId ||
+ nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch
+ ) {
+ const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
+ // tslint:disable-next-line:no-floating-promises
+ this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
+ }
+
+ const nextTrackedTokens = this._getTrackedTokens(nextProps.tokenByAddress);
+ const trackedTokens = this._getCurrentTrackedTokens();
+
+ if (!_.isEqual(nextTrackedTokens, trackedTokens)) {
+ const newTokens = _.difference(nextTrackedTokens, trackedTokens);
+ const newTokenAddresses = _.map(newTokens, token => token.address);
+ // Add placeholder entry for this token to the state, since fetching the
+ // balance/allowance is asynchronous
+ const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
+ for (const tokenAddress of newTokenAddresses) {
+ trackedTokenStateByAddress[tokenAddress] = {
+ balance: new BigNumber(0),
+ allowance: new BigNumber(0),
+ isLoaded: false,
+ };
+ }
+ this.setState({
+ trackedTokenStateByAddress,
+ });
+ // Fetch the actual balance/allowance.
+ // tslint:disable-next-line:no-floating-promises
+ this._fetchBalancesAndAllowancesAsync(newTokenAddresses);
+ }
}
public render(): React.ReactNode {
const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind(
@@ -283,8 +326,6 @@ export class Portal extends React.Component<PortalProps, PortalState> {
);
}
private _renderWallet(): React.ReactNode {
- const allTokens = _.values(this.props.tokenByAddress);
- const trackedTokens = _.filter(allTokens, t => t.isTracked);
return (
<div>
<Wallet
@@ -295,16 +336,18 @@ export class Portal extends React.Component<PortalProps, PortalState> {
blockchainErr={this.props.blockchainErr}
dispatcher={this.props.dispatcher}
tokenByAddress={this.props.tokenByAddress}
- trackedTokens={trackedTokens}
+ trackedTokens={this._getCurrentTrackedTokens()}
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
injectedProviderName={this.props.injectedProviderName}
providerType={this.props.providerType}
screenWidth={this.props.screenWidth}
location={this.props.location}
+ trackedTokenStateByAddress={this.state.trackedTokenStateByAddress}
onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)}
onAddToken={this._onAddToken.bind(this)}
onRemoveToken={this._onRemoveToken.bind(this)}
+ refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this)}
/>
<Container marginTop="15px">
<Island>
@@ -424,8 +467,6 @@ export class Portal extends React.Component<PortalProps, PortalState> {
);
}
private _renderTokenBalances(): React.ReactNode {
- const allTokens = _.values(this.props.tokenByAddress);
- const trackedTokens = _.filter(allTokens, t => t.isTracked);
return (
<TokenBalances
blockchain={this._blockchain}
@@ -434,7 +475,7 @@ export class Portal extends React.Component<PortalProps, PortalState> {
dispatcher={this.props.dispatcher}
screenWidth={this.props.screenWidth}
tokenByAddress={this.props.tokenByAddress}
- trackedTokens={trackedTokens}
+ trackedTokens={this._getCurrentTrackedTokens()}
userAddress={this.props.userAddress}
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
networkId={this.props.networkId}
@@ -515,6 +556,51 @@ export class Portal extends React.Component<PortalProps, PortalState> {
const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
return isSmallScreen;
}
+
+ private _getCurrentTrackedTokens(): Token[] {
+ return this._getTrackedTokens(this.props.tokenByAddress);
+ }
+
+ private _getTrackedTokens(tokenByAddress: TokenByAddress): Token[] {
+ const allTokens = _.values(tokenByAddress);
+ const trackedTokens = _.filter(allTokens, t => t.isTracked);
+ return trackedTokens;
+ }
+
+ private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]): TokenStateByAddress {
+ const trackedTokenStateByAddress: TokenStateByAddress = {};
+ _.each(trackedTokens, token => {
+ trackedTokenStateByAddress[token.address] = {
+ balance: new BigNumber(0),
+ allowance: new BigNumber(0),
+ isLoaded: false,
+ };
+ });
+ return trackedTokenStateByAddress;
+ }
+
+ private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]): Promise<void> {
+ const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
+ const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
+ for (const tokenAddress of tokenAddresses) {
+ const [balance, allowance] = await this._blockchain.getTokenBalanceAndAllowanceAsync(
+ userAddressIfExists,
+ tokenAddress,
+ );
+ trackedTokenStateByAddress[tokenAddress] = {
+ balance,
+ allowance,
+ isLoaded: true,
+ };
+ }
+ this.setState({
+ trackedTokenStateByAddress,
+ });
+ }
+
+ private async _refetchTokenStateAsync(tokenAddress: string): Promise<void> {
+ await this._fetchBalancesAndAllowancesAsync([tokenAddress]);
+ }
}
interface LargeLayoutProps {
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
index 18dada22f..af6b216c5 100644
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ b/packages/website/ts/components/wallet/wallet.tsx
@@ -67,13 +67,14 @@ export interface WalletProps {
providerType: ProviderType;
screenWidth: ScreenWidths;
location: Location;
+ trackedTokenStateByAddress: TokenStateByAddress;
onToggleLedgerDialog: () => void;
onAddToken: () => void;
onRemoveToken: () => void;
+ refetchTokenStateAsync: (tokenAddress: string) => Promise<void>;
}
interface WalletState {
- trackedTokenStateByAddress: TokenStateByAddress;
wrappedEtherDirection?: Side;
isHoveringSidebar: boolean;
}
@@ -151,48 +152,12 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
constructor(props: WalletProps) {
super(props);
this._isUnmounted = false;
- const trackedTokenAddresses = _.map(props.trackedTokens, token => token.address);
- const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(trackedTokenAddresses);
this.state = {
- trackedTokenStateByAddress: initialTrackedTokenStateByAddress,
wrappedEtherDirection: undefined,
isHoveringSidebar: false,
};
}
- public componentWillMount(): void {
- const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
- }
- public componentWillUnmount(): void {
- this._isUnmounted = true;
- }
- public componentWillReceiveProps(nextProps: WalletProps): void {
- if (
- nextProps.userAddress !== this.props.userAddress ||
- nextProps.networkId !== this.props.networkId ||
- nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch
- ) {
- const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
- }
- if (!_.isEqual(nextProps.trackedTokens, this.props.trackedTokens)) {
- const newTokens = _.difference(nextProps.trackedTokens, this.props.trackedTokens);
- const newTokenAddresses = _.map(newTokens, token => token.address);
- // Add placeholder entry for this token to the state, since fetching the
- // balance/allowance is asynchronous
- const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
- const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(newTokenAddresses);
- _.assign(trackedTokenStateByAddress, initialTrackedTokenStateByAddress);
- this.setState({
- trackedTokenStateByAddress,
- });
- // Fetch the actual balance/allowance.
- // tslint:disable-next-line:no-floating-promises
- this._fetchBalancesAndAllowancesAsync(newTokenAddresses);
- }
- }
+
public render(): React.ReactNode {
const isBlockchainLoaded = this.props.blockchainIsLoaded && this.props.blockchainErr === BlockchainErrs.NoError;
return (
@@ -342,7 +307,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
_.isUndefined(this.props.userEtherBalanceInWei),
);
const etherToken = this._getEthToken();
- const etherTokenState = this.state.trackedTokenStateByAddress[etherToken.address];
+ const etherTokenState = this.props.trackedTokenStateByAddress[etherToken.address];
const etherPrice = etherTokenState.price;
const secondaryText = this._renderValue(
this.props.userEtherBalanceInWei || new BigNumber(0),
@@ -366,7 +331,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
}
private _renderTokenRow(token: Token, index: number): React.ReactNode {
- const tokenState = this.state.trackedTokenStateByAddress[token.address];
+ const tokenState = this.props.trackedTokenStateByAddress[token.address];
const tokenLink = sharedUtils.getEtherScanLinkIfExists(
token.address,
this.props.networkId,
@@ -438,7 +403,8 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
etherToken={etherToken}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
onConversionSuccessful={this._closeWrappedEtherActionRow.bind(this)}
- refetchEthTokenStateAsync={this._refetchTokenStateAsync.bind(this, etherToken.address)}
+ // tslint:disable:jsx-no-lambda
+ refetchEthTokenStateAsync={() => this.props.refetchTokenStateAsync(etherToken.address)}
/>
)}
</div>
@@ -474,7 +440,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
onErrorOccurred={_.noop} // TODO: Error handling
userAddress={this.props.userAddress}
isDisabled={!config.tokenState.isLoaded}
- refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this, config.token.address)}
+ refetchTokenStateAsync={() => this.props.refetchTokenStateAsync(config.token.address)}
/>
);
}
@@ -557,42 +523,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
});
return trackedTokenStateByAddress;
}
- private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]): Promise<void> {
- const balanceAndAllowanceTupleByAddress: ItemByAddress<BigNumber[]> = {};
- const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
- for (const tokenAddress of tokenAddresses) {
- const balanceAndAllowanceTuple = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
- userAddressIfExists,
- tokenAddress,
- );
- balanceAndAllowanceTupleByAddress[tokenAddress] = balanceAndAllowanceTuple;
- }
- const priceByAddress = await this._getPriceByAddressAsync(tokenAddresses);
- const trackedTokenStateByAddress = _.reduce(
- tokenAddresses,
- (acc, address) => {
- const [balance, allowance] = balanceAndAllowanceTupleByAddress[address];
- const priceIfExists = _.get(priceByAddress, address);
- acc[address] = {
- balance,
- allowance,
- price: priceIfExists,
- isLoaded: true,
- };
- return acc;
- },
- this.state.trackedTokenStateByAddress,
- );
- if (!this._isUnmounted) {
- this.setState({
- trackedTokenStateByAddress,
- });
- }
- }
- private async _refetchTokenStateAsync(tokenAddress: string): Promise<void> {
- await this._fetchBalancesAndAllowancesAsync([tokenAddress]);
- }
private async _getPriceByAddressAsync(tokenAddresses: string[]): Promise<ItemByAddress<BigNumber>> {
if (_.isEmpty(tokenAddresses)) {
return {};