Skip to content

Commit

Permalink
fix: Add 'zero balance' data when refreshAccountOwner is rejected
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick1904 committed Apr 13, 2022
1 parent 0f623db commit 4ccb820
Show file tree
Hide file tree
Showing 17 changed files with 90 additions and 33 deletions.
4 changes: 2 additions & 2 deletions packages/frontend/src/components/buy/BuyNear.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import OkCoinLogo from '../../images/ok-coin-logo.svg';
import OkexLogo from '../../images/okex-logo.svg';
import RainbowBridgeLogo from '../../images/rainbow-bridge-logo.svg';
import { Mixpanel } from '../../mixpanel';
import { selectAccountLocalStorageAccountId } from '../../redux/slices/account';
import { selectAccountId } from '../../redux/slices/account';
import { isMoonpayAvailable, getSignedUrl } from '../../utils/moonpay';
import FormButton from '../common/FormButton';
import Container from '../common/styled/Container.css';
Expand Down Expand Up @@ -149,7 +149,7 @@ const StyledContainer = styled(Container)`
`;

export function BuyNear({ history }) {
const accountId = useSelector(selectAccountLocalStorageAccountId);
const accountId = useSelector(selectAccountId);
const [moonPayAvailable, setMoonPayAvailable] = useState(null);
const [signedMoonPayUrl, setSignedMoonPayUrl] = useState(null);

Expand Down
2 changes: 2 additions & 0 deletions packages/frontend/src/components/common/AlertBanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const Container = styled.div`
border-radius: 4px;
margin-bottom: 30px;
align-items: center;
word-break: break-word;
@media (max-width: 450px) {
margin: -25px -14px 30px -14px;
Expand Down Expand Up @@ -76,6 +77,7 @@ const Container = styled.div`
font-style: italic;
margin-left: 20px;
font-size: 13px;
line-height: 150%;
}
button, a {
Expand Down
14 changes: 12 additions & 2 deletions packages/frontend/src/components/profile/Profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ import {
selectAccountHasLockup,
selectAccountId,
selectAccountLedgerKey,
selectAccountLocalStorageAccountId
selectAccountLocalStorageAccountId,
selectAccountExists
} from '../../redux/slices/account';
import { selectAllAccountsHasLockup } from '../../redux/slices/allAccounts';
import { actions as recoveryMethodsActions, selectRecoveryMethodsByAccountId } from '../../redux/slices/recoveryMethods';
import { selectNearTokenFiatValueUSD } from '../../redux/slices/tokenFiatValues';
import isMobile from '../../utils/isMobile';
import AlertBanner from '../common/AlertBanner';
import FormButton from '../common/FormButton';
import SkeletonLoading from '../common/SkeletonLoading';
import Container from '../common/styled/Container.css';
Expand Down Expand Up @@ -139,6 +141,7 @@ const StyledContainer = styled(Container)`

export function Profile({ match }) {
const [transferring, setTransferring] = useState(false);
const accountExists = useSelector(selectAccountExists);
const has2fa = useSelector(selectAccountHas2fa);
const authorizedApps = useSelector(selectAccountAuthorizedApps);
const ledgerKey = useSelector(selectAccountLedgerKey);
Expand All @@ -147,7 +150,7 @@ export function Profile({ match }) {
const nearTokenFiatValueUSD = useSelector(selectNearTokenFiatValueUSD);
const accountIdFromUrl = match.params.accountId;
const accountId = accountIdFromUrl || loginAccountId || accountLocalStorageAccountId;
const isOwner = accountId && accountId === loginAccountId;
const isOwner = accountId && accountId === loginAccountId && accountExists;
const account = useAccount(accountId);
const dispatch = useDispatch();
const profileBalance = selectProfileBalance(account);
Expand Down Expand Up @@ -230,6 +233,13 @@ export function Profile({ match }) {
}
<div className='split'>
<div className='left'>
{accountExists === false &&
<AlertBanner
title='profile.accountDoesNotExistBanner.desc'
data={accountId}
theme='light-blue'
/>
}
<h2><UserIcon/><Translate id='profile.pageTitle.default'/></h2>
{profileBalance ? (
<BalanceContainer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { selectAccountLocalStorageAccountId, selectAccountId, selectBalance } from '../../redux/slices/account';
import { selectAccountId, selectBalance } from '../../redux/slices/account';
import ReceiveContainer from './ReceiveContainer';

export function ReceiveContainerWrapper() {
const accountId = useSelector(selectAccountId);
const accountLocalStorageAccountId = useSelector(selectAccountLocalStorageAccountId);
const balance = useSelector(selectBalance);

const availableBalance = balance?.balanceAvailable || (!accountId && '0');
const availableBalance = balance?.balanceAvailable;

//TODO: Add support for receiver in URL

return (
<ReceiveContainer
accountId={accountLocalStorageAccountId}
accountId={accountId}
availableBalance={availableBalance}
/>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/send/SendContainerV2.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ const SendContainerV2 = ({
setUserInputAmount(formattedTokenAmount.replace(/,/g, ''));
}
}}
availableToSend={selectedToken.balance || '0'}
availableToSend={selectedToken.balance}
continueAllowed={enterAmountIsComplete()}
onContinue={() => {
setActiveView(VIEWS.ENTER_RECEIVER);
Expand Down
13 changes: 7 additions & 6 deletions packages/frontend/src/components/staking/StakingContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
handleStakingAction,
handleUpdateCurrent
} from '../../redux/actions/staking';
import { selectAccountHas2fa, selectAccountHasLockup, selectAccountId, selectBalance, selectAccountLocalStorageAccountId } from '../../redux/slices/account';
import { selectAccountHas2fa, selectAccountHasLockup, selectAccountId, selectBalance } from '../../redux/slices/account';
import { selectLedgerHasLedger } from '../../redux/slices/ledger';
import { selectStakingSlice } from '../../redux/slices/staking';
import { selectStatusSlice } from '../../redux/slices/status';
Expand Down Expand Up @@ -166,7 +166,6 @@ const StyledContainer = styled(Container)`

export function StakingContainer({ history, match }) {
const dispatch = useDispatch();
const accountLocalStorageAccountId = useSelector(selectAccountLocalStorageAccountId);
const accountId = useSelector(selectAccountId);
const has2fa = useSelector(selectAccountHas2fa);
const balance = useSelector(selectBalance);
Expand All @@ -177,9 +176,11 @@ export function StakingContainer({ history, match }) {
const hasLockup = useSelector(selectAccountHasLockup);

const { currentAccount } = staking;
const stakingAccounts = staking.accounts.length
? staking.accounts
: [{ accountId: accountLocalStorageAccountId, totalUnstaked: '0', totalStaked: '0' }];
const currentAccountDataForInactiveAccount = {
accountId: accountId,
...currentAccount
};
const stakingAccounts = staking.accounts.length ? staking.accounts : [currentAccountDataForInactiveAccount];
const validators = staking.allValidators;
const currentValidators = currentAccount.validators;
const validatorId = history.location.pathname.split('/')[2];
Expand Down Expand Up @@ -235,7 +236,7 @@ export function StakingContainer({ history, match }) {
currentValidators={currentValidators}
onSwitchAccount={handleSwitchAccount}
accounts={stakingAccounts}
activeAccountId={currentAccount.accountId || accountLocalStorageAccountId}
activeAccount={currentAccount}
accountId={accountId}
loading={status.mainLoader && !stakingAccounts.length}
loadingDetails={(status.mainLoader && !stakingAccounts.length) || loadingBalance}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const Container = styled.div`

export default function SelectAccount({ accounts, onChange, selectedAccount }) {
return (
<RadioGroup onChange={accounts.every((account) => !!account.totalUnstaked) ? (e) => onChange(e) : null} selectedValue={selectedAccount}>
<RadioGroup onChange={accounts.length > 1 && accounts.every((account) => !!account.totalUnstaked) ? (e) => onChange(e) : null} selectedValue={selectedAccount}>
{accounts.map((account, i) =>
<RadioButton value={account.accountId} key={i}>
<Container>
Expand Down
11 changes: 5 additions & 6 deletions packages/frontend/src/components/staking/components/Staking.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@ export default function Staking({
totalPending,
onSwitchAccount,
accounts,
activeAccountId,
activeAccount,
loading,
hasLockup,
loadingDetails,
stakeFromAccount,
selectedValidator,
multipleAccounts,
accountId
multipleAccounts
}) {
const NEARAsTokenWithMetadata = useSelector(selectNEARAsTokenWithMetadata);

Expand All @@ -46,7 +45,7 @@ export default function Staking({
<SelectAccount
accounts={accounts}
onChange={(e) => onSwitchAccount(e.target.value)}
selectedAccount={activeAccountId}
selectedAccount={activeAccount.accountId}
/>
}
<SkeletonLoading
Expand All @@ -56,7 +55,7 @@ export default function Staking({
className='account-loader'
/>
<FormButton
disabled={loadingDetails || !accountId}
disabled={loadingDetails || !activeAccount.accountId}
linkTo='/staking/validators'
trackingId="STAKE Click stake my tokens button"
data-test-id="stakeMyTokensButton"
Expand Down Expand Up @@ -119,7 +118,7 @@ export default function Staking({
/>
)}
</ListWrapper>
: <NoValidators accountId={accountId}/>
: <NoValidators accountId={activeAccount.accountId}/>
: <SkeletonLoading
height='200px'
show={true}
Expand Down
9 changes: 5 additions & 4 deletions packages/frontend/src/components/wallet/Wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ export function Wallet({
tab,
setTab,
accountId,
accountExists,
balance,
linkdropAmount,
createFromImplicitSuccess,
Expand Down Expand Up @@ -291,7 +292,7 @@ export function Wallet({
balance={balance}
tokensLoader={tokensLoader}
fungibleTokens={fungibleTokensList}
accountId={accountId}
accountExists={accountExists}
/>

}
Expand Down Expand Up @@ -328,15 +329,15 @@ export function Wallet({
);
}

const FungibleTokens = ({ balance, tokensLoader, fungibleTokens, accountId }) => {
const zeroBalanceAccount = !accountId && !tokensLoader;
const FungibleTokens = ({ balance, tokensLoader, fungibleTokens, accountExists }) => {
const zeroBalanceAccount = accountExists === false;
return (
<>
<div className='total-balance'>
<Textfit mode='single' max={48}>
<Balance
showBalanceInNEAR={false}
amount={balance?.balanceAvailable || '0'}
amount={balance?.balanceAvailable}
showAlmostEqualSignUSD={false}
showSymbolUSD={false}
showSignUSD={true}
Expand Down
5 changes: 1 addition & 4 deletions packages/frontend/src/redux/actions/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -593,10 +593,7 @@ export const { makeAccountActive, refreshAccountExternal, refreshUrl, updateStak
}
}),
(accountId) => ({
accountId,
...showAlert({ onlyError: true, data: { accountId } })
// TODO: Should we show an alert if the account is not found / has no record on chain?
// Show zero balance instead of error with an on-page disclaimer that the acccount either doesn't exist or has no record on chain, yet?
accountId
})
],
REFRESH_URL: null,
Expand Down
15 changes: 15 additions & 0 deletions packages/frontend/src/redux/reducers/account/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import refreshAccountOwner from '../../sharedThunks/refreshAccountOwner';

const initialState = {
accountExists: null,
formLoader: false,
sentMessage: false,
requestPending: null,
Expand Down Expand Up @@ -104,6 +105,7 @@ const account = handleActions({
return {
...state,
...payload,
accountExists: true,
balance: {
...payload?.balance,
...state.balance
Expand All @@ -113,6 +115,19 @@ const account = handleActions({
loader: false
};
},
[refreshAccountOwner.rejected]: (state, { error, payload }) => {
return {
...state,
...payload,
accountExists: error.message.includes('does not exist while viewing') ? false : null,
accountId: state.localStorage.accountFound ? state.localStorage.accountId : '',
balance: {
balanceAvailable: '0'
},
ledger: undefined,
loader: false
};
},
[staking.updateAccount]: (state, { ready, error, payload }) =>
(!ready || error)
? state
Expand Down
21 changes: 20 additions & 1 deletion packages/frontend/src/redux/reducers/selectors/balance.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,27 @@ import BN from 'bn.js';
import { MIN_BALANCE_FOR_GAS } from '../../../config';

export const selectProfileBalance = (walletAccount) => {
let walletBalance = {
available: '0',
inStakingPools: {
availableForWithdraw: '0',
pendingRelease: '0',
staked: '0',
sum: '0',
},
reservedForStorage: '0',
reservedForTransactions: '0',
walletBalance: '0'
};

const balance = walletAccount?.balance;

if (walletAccount?.accountExists === false) {
return {
walletBalance
};
}

if (!balance || !balance.available) {
return false;
}
Expand All @@ -26,7 +45,7 @@ export const selectProfileBalance = (walletAccount) => {

const lockupIdExists = !!lockedAmount;

const walletBalance = {
walletBalance = {
walletBalance: walletAccount?.amount,
reservedForStorage: stateStaked.toString(),
reservedForTransactions: BN.min(new BN(available), new BN(MIN_BALANCE_FOR_GAS)).toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ export default createAsyncThunk(
}
if (nextAccountId) {
dispatch(makeAccountActive(nextAccountId));
//FIX: Automatic switching when account doesn't exist makes it impossible to switch to a zero balance account
// However, redux 'availableAccounts' array becomes empty if you switch to a zero balance account and refresh the page
}

console.log('createAsyncThunk refreshAccountOwner wallet.accounts',wallet.accounts);

// TODO: Make sure "problem creating" only shows for actual creation
return {
resetAccount: {
Expand Down
2 changes: 2 additions & 0 deletions packages/frontend/src/redux/slices/account/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const selectAccountId = createSelector(selectAccountSlice, (account) => a

export const selectActiveAccountIdIsImplicitAccount = createSelector(selectAccountSlice, (account) => isImplicitAccount(account.accountId));

export const selectAccountExists = createSelector(selectAccountSlice, (account) => account.accountExists);

export const selectAccountHas2fa = createSelector(selectAccountSlice, (account) => account.has2fa);

export const selectAccountHasLockup = createSelector(selectAccountSlice, (account) => account.hasLockup);
Expand Down
4 changes: 4 additions & 0 deletions packages/frontend/src/redux/slices/availableAccounts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const availableAccountsSlice = createSlice({
builder.addCase(refreshAccountOwner.fulfilled, (state, action) => {
set(state, ['items'], Object.keys((action.payload && action.payload.accounts) || {}).sort());
});
builder.addCase(refreshAccountOwner.rejected, (state, action) => {
// FIX: should accounts be loaded from localStorage regardless of status?
set(state, ['items'], Object.keys((action.payload && action.payload.accounts) || {}).sort());
});
handleAsyncThunkStatus({
asyncThunk: refreshAccountOwner,
buildStatusPath: () => [],
Expand Down
5 changes: 3 additions & 2 deletions packages/frontend/src/routes/WalletWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useSelector, useDispatch } from 'react-redux';
import { Wallet } from '../components/wallet/Wallet';
import { useFungibleTokensIncludingNEAR } from '../hooks/fungibleTokensIncludingNEAR';
import { Mixpanel } from '../mixpanel/index';
import { selectAccountId, selectBalance } from '../redux/slices/account';
import { selectAccountId, selectBalance, selectAccountExists } from '../redux/slices/account';
import { selectAvailableAccounts } from '../redux/slices/availableAccounts';
import { selectCreateFromImplicitSuccess, selectCreateCustomName, actions as createFromImplicitActions } from '../redux/slices/createFromImplicit';
import { selectLinkdropAmount, actions as linkdropActions } from '../redux/slices/linkdrop';
Expand All @@ -20,8 +20,8 @@ export function WalletWrapper({
tab,
setTab
}) {

const accountId = useSelector(selectAccountId);
const accountExists = useSelector(selectAccountExists);
const balance = useSelector(selectBalance);
const dispatch = useDispatch();
const linkdropAmount = useSelector(selectLinkdropAmount);
Expand All @@ -47,6 +47,7 @@ export function WalletWrapper({
tab={tab}
setTab={setTab}
accountId={accountId}
accountExists={accountExists}
balance={balance}
linkdropAmount={linkdropAmount}
createFromImplicitSuccess={createFromImplicitSuccess}
Expand Down
3 changes: 3 additions & 0 deletions packages/frontend/src/translations/en.global.json
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,9 @@
"walletBalance": "Wallet balance",
"walletId": "Wallet ID"
},
"accountDoesNotExistBanner": {
"desc": "No activity has been recorded for <a href='https://explorer.near.org/accounts/${data}' rel='noopener noreferrer' target='_blank'><b>this account</b></a>. Send NEAR to your account to begin using all features of the NEAR Wallet."
},
"authorizedApps": {
"title": "Authorized Apps"
},
Expand Down

0 comments on commit 4ccb820

Please sign in to comment.