aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/components/portal/portal.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/components/portal/portal.tsx')
-rw-r--r--packages/website/ts/components/portal/portal.tsx98
1 files changed, 92 insertions, 6 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 {