Skip to content

Commit

Permalink
fix(tokens): avoid filters in hooks (#4319)
Browse files Browse the repository at this point in the history
### Description

More context
[here](https://valora-app.slack.com/archives/C025V1D6F3J/p1697203116036359?thread_ts=1696932462.287309&cid=C025V1D6F3J)

### Test plan

Unit tests

### Related issues

N/A

### Backwards compatibility

Yes
  • Loading branch information
satish-ravi authored Oct 18, 2023
1 parent b7d503d commit 07aaab8
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 167 deletions.
56 changes: 55 additions & 1 deletion src/tokens/Assets.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Provider } from 'react-redux'
import ValoraAnalytics from 'src/analytics/ValoraAnalytics'
import { navigate } from 'src/navigator/NavigationService'
import { Screens } from 'src/navigator/Screens'
import { getFeatureGate } from 'src/statsig'
import { getDynamicConfigParams, getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
import AssetsScreen from 'src/tokens/Assets'
import { NetworkId } from 'src/transactions/types'
Expand All @@ -20,6 +20,7 @@ import {
mockNftNullMetadata,
mockPositions,
mockShortcuts,
mockTokenBalances,
} from 'test/values'

jest.mock('src/statsig', () => {
Expand All @@ -31,6 +32,8 @@ jest.mock('src/statsig', () => {
}
})

const ethTokenId = 'ethereum-sepolia:native'

const storeWithTokenBalances = {
tokens: {
tokenBalances: {
Expand Down Expand Up @@ -332,4 +335,55 @@ describe('AssetsScreen', () => {
fireEvent.press(getByText('assets.claimRewards'))
expect(navigate).toHaveBeenCalledWith(Screens.DappShortcutsRewards)
})

it('displays tokens with balance and ones marked with showZeroBalance in the expected order', () => {
jest.mocked(getDynamicConfigParams).mockReturnValueOnce({
showBalances: [NetworkId['celo-alfajores'], NetworkId['ethereum-sepolia']],
})
const store = createMockStore({
tokens: {
tokenBalances: {
...mockTokenBalances,
[ethTokenId]: {
tokenId: ethTokenId,
balance: '0',
priceUsd: '5',
networkId: NetworkId['ethereum-sepolia'],
showZeroBalance: true,
isNative: true,
symbol: 'ETH',
},
['token1']: {
tokenId: 'token1',
networkId: NetworkId['celo-alfajores'],
balance: '10',
symbol: 'TK1',
},
['token2']: {
tokenId: 'token2',
networkId: NetworkId['celo-alfajores'],
balance: '0',
symbol: 'TK2',
},
['token3']: {
tokenId: 'token3',
networkId: NetworkId['ethereum-sepolia'],
balance: '20',
symbol: 'TK3',
},
},
},
})

const { getAllByTestId } = render(
<Provider store={store}>
<MockedNavigator component={AssetsScreen} />
</Provider>
)

expect(getAllByTestId('TokenBalanceItem')).toHaveLength(6)
;['POOF', 'TK3', 'TK1', 'CELO', 'ETH', 'cUSD'].map((symbol, index) => {
expect(getAllByTestId('TokenBalanceItem')[index]).toHaveTextContent(symbol)
})
})
})
47 changes: 39 additions & 8 deletions src/tokens/Assets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import Animated, {
useSharedValue,
} from 'react-native-reanimated'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import { AssetsEvents } from 'src/analytics/Events'
import ValoraAnalytics from 'src/analytics/ValoraAnalytics'
import Button, { BtnSizes, BtnTypes } from 'src/components/Button'
import { AssetsTokenBalance } from 'src/components/TokenBalance'
import Touchable from 'src/components/Touchable'
import { TOKEN_MIN_AMOUNT } from 'src/config'
import ImageErrorIcon from 'src/icons/ImageErrorIcon'
import { useDollarsToLocalAmount } from 'src/localCurrency/hooks'
import { getLocalCurrencySymbol } from 'src/localCurrency/selectors'
Expand All @@ -46,6 +46,7 @@ import {
totalPositionsBalanceUsdSelector,
} from 'src/positions/selectors'
import { Position } from 'src/positions/types'
import useSelector from 'src/redux/useSelector'
import { getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
import Colors from 'src/styles/colors'
Expand All @@ -55,13 +56,14 @@ import { Shadow, Spacing, getShadowStyle } from 'src/styles/styles'
import variables from 'src/styles/variables'
import { PositionItem } from 'src/tokens/AssetItem'
import { TokenBalanceItem } from 'src/tokens/TokenBalanceItem'
import {
useTokenPricesAreStale,
useTokensForAssetsScreen,
useTotalTokenBalance,
} from 'src/tokens/hooks'
import { useTokenPricesAreStale, useTotalTokenBalance } from 'src/tokens/hooks'
import { tokensListSelector } from 'src/tokens/selectors'
import { TokenBalance } from 'src/tokens/slice'
import { getSupportedNetworkIdsForTokenBalances, getTokenAnalyticsProps } from 'src/tokens/utils'
import {
getSupportedNetworkIdsForTokenBalances,
getTokenAnalyticsProps,
usdBalance,
} from 'src/tokens/utils'

const DEVICE_WIDTH_BREAKPOINT = 340
const NUM_OF_NFTS_PER_ROW = 2
Expand Down Expand Up @@ -116,7 +118,36 @@ function AssetsScreen({ navigation, route }: Props) {
const activeTab = route.params?.activeTab ?? AssetTabType.Tokens

const supportedNetworkIds = getSupportedNetworkIdsForTokenBalances()
const tokens = useTokensForAssetsScreen()
const allTokens = useSelector((state) => tokensListSelector(state, supportedNetworkIds))
const tokens = useMemo(
() =>
allTokens
.filter((tokenInfo) => tokenInfo.balance.gt(TOKEN_MIN_AMOUNT) || tokenInfo.showZeroBalance)
.sort((token1, token2) => {
// Sorts by usd balance, then token balance, then zero balance natives by
// network id, then zero balance non natives by network id
const usdBalanceCompare = usdBalance(token2).comparedTo(usdBalance(token1))
if (usdBalanceCompare) {
return usdBalanceCompare
}

const balanceCompare = token2.balance.comparedTo(token1.balance)
if (balanceCompare) {
return balanceCompare
}

if (token1.isNative && !token2.isNative) {
return -1
}
if (!token1.isNative && token2.isNative) {
return 1
}

return token1.networkId.localeCompare(token2.networkId)
}),
[allTokens]
)

const localCurrencySymbol = useSelector(getLocalCurrencySymbol)
const totalTokenBalanceLocal = useTotalTokenBalance() ?? new BigNumber(0)
const tokensAreStale = useTokenPricesAreStale(supportedNetworkIds)
Expand Down
4 changes: 2 additions & 2 deletions src/tokens/TokenDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ import { TokenBalanceItem } from 'src/tokens/TokenBalanceItem'
import {
useCashInTokens,
useCashOutTokens,
useSendableTokens,
useSwappableTokens,
useTokenInfo,
useTokensForSend,
} from 'src/tokens/hooks'
import { TokenBalance } from 'src/tokens/slice'
import { TokenDetailsActionName } from 'src/tokens/types'
Expand Down Expand Up @@ -138,7 +138,7 @@ function PriceInfo({ token }: { token: TokenBalance }) {

function Actions({ token }: { token: TokenBalance }) {
const { t } = useTranslation()
const sendableTokens = useSendableTokens()
const sendableTokens = useTokensForSend()
const swappableTokens = useSwappableTokens()
const cashInTokens = useCashInTokens()
const cashOutTokens = useCashOutTokens()
Expand Down
78 changes: 4 additions & 74 deletions src/tokens/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import {
useCashInTokens,
useCashOutTokens,
useLocalToTokenAmountByAddress,
useSendableTokens,
useSwappableTokens,
useTokenPricesAreStale,
useTokenToLocalAmountByAddress,
useTokensForAssetsScreen,
useTokensForSend,
} from 'src/tokens/hooks'
import { TokenBalance } from 'src/tokens/slice'
import { NetworkId } from 'src/transactions/types'
Expand Down Expand Up @@ -219,80 +218,11 @@ describe('token to fiat exchanges', () => {
})
})

describe('useTokensForAssetsScreen', () => {
it('returns tokens with balance and tokens with showZeroBalance set to true', () => {
const store = createMockStore({ tokens: { tokenBalances: mockTokenBalances } })

const { getByTestId } = render(
<Provider store={store}>
<TokenHookTestComponent hook={useTokensForAssetsScreen} />
</Provider>
)

expect(getByTestId('tokenIDs').props.children).toEqual([
mockPoofTokenId,
mockCeloTokenId,
mockCusdTokenId,
])
})

it('sorts by usd balance, then balance if price is not available, then zero balance tokens with natives first', () => {
jest.mocked(getDynamicConfigParams).mockReturnValueOnce({
showBalances: [NetworkId['celo-alfajores'], NetworkId['ethereum-sepolia']],
})
const store = createMockStore({
tokens: {
tokenBalances: {
...mockTokenBalances,
[ethTokenId]: {
tokenId: ethTokenId,
balance: '0',
priceUsd: '5',
networkId: NetworkId['ethereum-sepolia'],
showZeroBalance: true,
isNative: true,
},
['token1']: {
tokenId: 'token1',
networkId: NetworkId['celo-alfajores'],
balance: '10',
},
['token2']: {
tokenId: 'token2',
networkId: NetworkId['celo-alfajores'],
balance: '0',
},
['token3']: {
tokenId: 'token3',
networkId: NetworkId['ethereum-sepolia'],
balance: '20',
},
},
},
})

const { getByTestId } = render(
<Provider store={store}>
<TokenHookTestComponent hook={useTokensForAssetsScreen} />
</Provider>
)

expect(getByTestId('tokenIDs').props.children).toEqual([
mockPoofTokenId,
'token3',
'token1',
mockCeloTokenId,
ethTokenId,
mockCusdTokenId,
])
})
})

describe('useSendableTokens', () => {
describe('useTokensForSend', () => {
it('returns tokens with balance', () => {
const { getByTestId } = render(
<Provider store={storeWithMultipleNetworkTokens()}>
<TokenHookTestComponent hook={useSendableTokens} />
<TokenHookTestComponent hook={useTokensForSend} />
</Provider>
)

Expand All @@ -309,7 +239,7 @@ describe('useSendableTokens', () => {
})
const { getByTestId } = render(
<Provider store={storeWithMultipleNetworkTokens()}>
<TokenHookTestComponent hook={useSendableTokens} />
<TokenHookTestComponent hook={useTokensForSend} />
</Provider>
)

Expand Down
Loading

0 comments on commit 07aaab8

Please sign in to comment.