Token Balance retry button & equivalent values fix (#1453)
* Add refresh button to token balances error. Refactor actions a bit. * Fix assertion error from bn on rates
This commit is contained in:
parent
c9676cac62
commit
c3d1e4e3af
|
@ -160,9 +160,16 @@ export function setWalletConfig(config: WalletConfig): types.SetWalletConfigActi
|
|||
};
|
||||
}
|
||||
|
||||
export type TSetAccountBalance = typeof setAccountBalance;
|
||||
export function setAccountBalance(): types.SetAccountBalanceAction {
|
||||
export type TRefreshAccountBalance = typeof refreshAccountBalance;
|
||||
export function refreshAccountBalance(): types.RefreshAccountBalanceAction {
|
||||
return {
|
||||
type: TypeKeys.WALLET_SET_ACCOUNT_BALANCE
|
||||
type: TypeKeys.WALLET_REFRESH_ACCOUNT_BALANCE
|
||||
};
|
||||
}
|
||||
|
||||
export type TRefreshTokenBalances = typeof refreshTokenBalances;
|
||||
export function refreshTokenBalances(): types.RefreshTokenBalancesAction {
|
||||
return {
|
||||
type: TypeKeys.WALLET_REFRESH_TOKEN_BALANCES
|
||||
};
|
||||
}
|
||||
|
|
|
@ -125,8 +125,12 @@ export interface SetPasswordPendingAction {
|
|||
type: TypeKeys.WALLET_SET_PASSWORD_PENDING;
|
||||
}
|
||||
|
||||
export interface SetAccountBalanceAction {
|
||||
type: TypeKeys.WALLET_SET_ACCOUNT_BALANCE;
|
||||
export interface RefreshAccountBalanceAction {
|
||||
type: TypeKeys.WALLET_REFRESH_ACCOUNT_BALANCE;
|
||||
}
|
||||
|
||||
export interface RefreshTokenBalancesAction {
|
||||
type: TypeKeys.WALLET_REFRESH_TOKEN_BALANCES;
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
|
@ -148,4 +152,5 @@ export type WalletAction =
|
|||
| SetWalletTokensAction
|
||||
| SetWalletConfigAction
|
||||
| SetPasswordPendingAction
|
||||
| SetAccountBalanceAction;
|
||||
| RefreshAccountBalanceAction
|
||||
| RefreshTokenBalancesAction;
|
||||
|
|
|
@ -20,5 +20,6 @@ export enum TypeKeys {
|
|||
WALLET_SET_CONFIG = 'WALLET_SET_CONFIG',
|
||||
WALLET_RESET = 'WALLET_RESET',
|
||||
WALLET_SET_PASSWORD_PENDING = 'WALLET_SET_PASSWORD_PENDING',
|
||||
WALLET_SET_ACCOUNT_BALANCE = 'WALLET_SET_ACCOUNT_BALANCE'
|
||||
WALLET_REFRESH_ACCOUNT_BALANCE = 'WALLET_REFRESH_ACCOUNT_BALANCE',
|
||||
WALLET_REFRESH_TOKEN_BALANCES = 'WALLET_REFRESH_TOKEN_BALANCES'
|
||||
}
|
||||
|
|
|
@ -58,24 +58,39 @@ export interface CCResponse {
|
|||
[symbol: string]: ISymbol;
|
||||
}
|
||||
|
||||
interface IRates extends ISymbol {
|
||||
Response?: 'Error';
|
||||
interface IRatesResponse {
|
||||
[key: string]: number;
|
||||
}
|
||||
interface IRatesError {
|
||||
Response: 'Error';
|
||||
}
|
||||
|
||||
export const fetchRates = (symbols: string[] = []): Promise<CCResponse> =>
|
||||
fetch(CCRates(symbols))
|
||||
.then(response => handleJSONResponse(response, ERROR_MESSAGE))
|
||||
.then((rates: IRates) => {
|
||||
.then((rates: IRatesResponse | IRatesError) => {
|
||||
// API errors come as 200s, so check the json for error
|
||||
if (rates.Response && rates.Response === 'Error') {
|
||||
if ((rates as IRatesError).Response === 'Error') {
|
||||
throw new Error('Failed to fetch rates');
|
||||
}
|
||||
|
||||
return rates;
|
||||
})
|
||||
.then((rates: IRatesResponse) => {
|
||||
// Sometimes the API erroneously gives tokens an extremely high value,
|
||||
// like 10000000 ETH to 1 token. Filter those out. If that ever turns
|
||||
// out to be true, we should all go home.
|
||||
return Object.keys(rates).reduce((filteredRates: IRatesResponse, key) => {
|
||||
if (rates[key] > 0.000001) {
|
||||
filteredRates[key] = rates[key];
|
||||
}
|
||||
return filteredRates;
|
||||
}, {});
|
||||
})
|
||||
.then((rates: IRatesResponse) => {
|
||||
// All currencies are in ETH right now. We'll do token -> eth -> value to
|
||||
// do it all in one request
|
||||
// to their respective rates via ETH.
|
||||
// do it all in one request to their respective rates via ETH.
|
||||
return symbols.reduce(
|
||||
(eqRates, sym: keyof ISymbol) => {
|
||||
(eqRates, sym) => {
|
||||
if (rates[sym]) {
|
||||
eqRates[sym] = rateSymbols.symbols.all.reduce(
|
||||
(symRates, rateSym) => {
|
||||
|
|
|
@ -9,7 +9,7 @@ import Spinner from 'components/ui/Spinner';
|
|||
import { getNetworkConfig, getOffline } from 'selectors/config';
|
||||
import { AppState } from 'reducers';
|
||||
import { NetworkConfig } from 'types/network';
|
||||
import { TSetAccountBalance, setAccountBalance } from 'actions/wallet';
|
||||
import { TRefreshAccountBalance, refreshAccountBalance } from 'actions/wallet';
|
||||
import './AccountInfo.scss';
|
||||
|
||||
interface OwnProps {
|
||||
|
@ -30,7 +30,7 @@ interface State {
|
|||
}
|
||||
|
||||
interface DispatchProps {
|
||||
setAccountBalance: TSetAccountBalance;
|
||||
refreshAccountBalance: TRefreshAccountBalance;
|
||||
}
|
||||
|
||||
type Props = OwnProps & StateProps & DispatchProps;
|
||||
|
@ -170,7 +170,7 @@ class AccountInfo extends React.Component<Props, State> {
|
|||
!isOffline && (
|
||||
<button
|
||||
className="AccountInfo-section-refresh"
|
||||
onClick={this.props.setAccountBalance}
|
||||
onClick={this.props.refreshAccountBalance}
|
||||
>
|
||||
<i className="fa fa-refresh" />
|
||||
</button>
|
||||
|
@ -214,5 +214,5 @@ function mapStateToProps(state: AppState): StateProps {
|
|||
isOffline: getOffline(state)
|
||||
};
|
||||
}
|
||||
const mapDispatchToProps: DispatchProps = { setAccountBalance };
|
||||
const mapDispatchToProps: DispatchProps = { refreshAccountBalance };
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AccountInfo);
|
||||
|
|
|
@ -33,6 +33,19 @@
|
|||
margin-top: $space;
|
||||
}
|
||||
|
||||
&-error {
|
||||
color: $brand-danger;
|
||||
text-align: center;
|
||||
|
||||
&-message {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.fa {
|
||||
margin-left: $space-md;
|
||||
}
|
||||
}
|
||||
|
||||
&-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
|
|
@ -11,7 +11,9 @@ import {
|
|||
scanWalletForTokens,
|
||||
TScanWalletForTokens,
|
||||
setWalletTokens,
|
||||
TSetWalletTokens
|
||||
TSetWalletTokens,
|
||||
refreshTokenBalances,
|
||||
TRefreshTokenBalances
|
||||
} from 'actions/wallet';
|
||||
import { getAllTokens, getOffline } from 'selectors/config';
|
||||
import { getTokenBalances, getWalletInst, getWalletConfig, TokenBalance } from 'selectors/wallet';
|
||||
|
@ -36,6 +38,7 @@ interface ActionProps {
|
|||
removeCustomToken: TRemoveCustomToken;
|
||||
scanWalletForTokens: TScanWalletForTokens;
|
||||
setWalletTokens: TSetWalletTokens;
|
||||
refreshTokenBalances: TRefreshTokenBalances;
|
||||
}
|
||||
type Props = StateProps & ActionProps;
|
||||
|
||||
|
@ -56,12 +59,18 @@ class TokenBalances extends React.Component<Props> {
|
|||
let content;
|
||||
if (isOffline) {
|
||||
content = (
|
||||
<div className="TokenBalances-offline well well-sm">
|
||||
Token balances are unavailable offline
|
||||
</div>
|
||||
<div className="TokenBalances-offline well well-sm">{translate('SCAN_TOKENS_OFFLINE')}</div>
|
||||
);
|
||||
} else if (tokensError) {
|
||||
content = <h5>{tokensError}</h5>;
|
||||
content = (
|
||||
<div className="TokenBalances-error well well-md">
|
||||
<h5 className="TokenBalances-error-message">{tokensError}</h5>
|
||||
<button onClick={this.props.refreshTokenBalances} className="btn btn-default btn-sm">
|
||||
{translate('X_TRY_AGAIN')}
|
||||
<i className="fa fa-refresh" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
} else if (isTokensLoading) {
|
||||
content = (
|
||||
<div className="TokenBalances-loader">
|
||||
|
@ -126,5 +135,6 @@ export default connect(mapStateToProps, {
|
|||
addCustomToken,
|
||||
removeCustomToken,
|
||||
scanWalletForTokens,
|
||||
setWalletTokens
|
||||
setWalletTokens,
|
||||
refreshTokenBalances
|
||||
})(TokenBalances);
|
||||
|
|
|
@ -104,7 +104,7 @@ function setTokenBalanceRejected(state: State): State {
|
|||
return {
|
||||
...state,
|
||||
isTokensLoading: false,
|
||||
tokensError: 'Failed to fetch token value'
|
||||
tokensError: translateRaw('SCAN_TOKENS_FAIL')
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ export function* fetchRatesSaga(action: FetchCCRatesRequested): SagaIterator {
|
|||
const rates: CCResponse = yield call(fetchRates, action.payload);
|
||||
yield put(fetchCCRatesSucceeded(rates));
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch rates:', e);
|
||||
yield put(fetchCCRatesFailed());
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -320,7 +320,8 @@ export default function* walletSaga(): SagaIterator {
|
|||
takeEvery(TypeKeys.WALLET_SCAN_WALLET_FOR_TOKENS, scanWalletForTokens),
|
||||
takeEvery(TypeKeys.WALLET_SET_WALLET_TOKENS, handleSetWalletTokens),
|
||||
takeEvery(TypeKeys.WALLET_SET_TOKEN_BALANCE_PENDING, updateTokenBalance),
|
||||
takeEvery(TypeKeys.WALLET_SET_ACCOUNT_BALANCE, updateAccountBalance),
|
||||
takeEvery(TypeKeys.WALLET_REFRESH_ACCOUNT_BALANCE, updateAccountBalance),
|
||||
takeEvery(TypeKeys.WALLET_REFRESH_TOKEN_BALANCES, updateTokenBalances),
|
||||
// Foreign actions
|
||||
takeEvery(ConfigTypeKeys.CONFIG_TOGGLE_OFFLINE, updateBalances),
|
||||
takeEvery(CustomTokenTypeKeys.CUSTOM_TOKEN_ADD, handleCustomTokenAdd)
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
"X_PRIVKEY2": "Private Key",
|
||||
"X_PRIVKEYDESC": "This is the unencrypted text version of your private key, meaning no password is necessary. If someone were to find your unencrypted private key, they could access your wallet without a password. For this reason, encrypted versions are typically recommended. ",
|
||||
"X_SAVE": "Save ",
|
||||
"X_TRY_AGAIN": "Try again",
|
||||
"CX_WARNING_1": "Make sure you have **external backups** of any wallets you store here. Many things could happen that would cause you to lose the data in this Chrome Extension, including uninstalling and reinstalling the extension. This extension is a way to easily access your wallets, **not** a way to back them up. ",
|
||||
"SIDEBAR_ACCOUNTADDR": "Account Address ",
|
||||
"SIDEBAR_ACCOUNTBAL": "Account Balance ",
|
||||
|
@ -103,6 +104,7 @@
|
|||
"SCAN_TOKENS": "Scan For Tokens",
|
||||
"SCAN_TOKENS_FAIL": "Failed to fetch token values",
|
||||
"SCAN_TOKENS_FAIL_NO_TOKENS": "No tokens found",
|
||||
"SCAN_TOKENS_OFFLINE": "Token balances are unavailable offline",
|
||||
"SEND_GAS": "Gas ",
|
||||
"SEND_TRANSFERTOTAL": "Send Entire Balance ",
|
||||
"SEND_GENERATE": "Generate Transaction ",
|
||||
|
|
Loading…
Reference in New Issue