Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to refresh tokens in case of uncaught balance changes #447

Merged
merged 1 commit into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -861,17 +861,17 @@ SPEC CHECKSUMS:
FBLazyVector: f1897022b53abf1469d6ad692ee2c69f57d967f3
FBReactNativeSpec: 627fd07f1b9d498c9fa572e76d7f1a6b1ee9a444
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
glog: 791fe035093b84822da7f0870421a25839ca7870
helium-react-native-sdk: 32c0a7e3abc733a7f3d291013b2db31475fc6980
hermes-engine: 0784cadad14b011580615c496f77e0ae112eed75
hermes-engine: 7a53ccac09146018a08239c5425625fdb79a6162
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
MapboxCommon: fdf7fd31c90b7b607cd9c63e37797f023c01d860
MapboxCoreMaps: 24270c7c6b8cb71819fc2f3c549db9620ee4d019
MapboxMaps: cb76511b98d3b95c74b0771ed105bc69f30ace6b
MapboxMobileEvents: de50b3a4de180dd129c326e09cd12c8adaaa46d6
MultiplatformBleAdapter: 5a6a897b006764392f9cef785e4360f54fb9477d
OneSignalXCFramework: 81ceac017a290f23793443323090cfbe888f74ea
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCT-Folly: 85766c3226c7ec638f05ad7cb3cf6a268d6c4241
RCTRequired: bd6045fbd511da5efe6db89eecb21e4e36bd7cbf
RCTTypeSafety: c06d9f906faa69dd1c88223204c3a24767725fd8
React: b9ea33557ef1372af247f95d110fbdea114ed3b2
Expand Down
26 changes: 26 additions & 0 deletions src/features/account/AccountManageTokenListScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ import { usePublicKey } from '@hooks/usePublicKey'
import CheckBox from '@react-native-community/checkbox'
import { useNavigation } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
import { useAccountStorage } from '@storage/AccountStorageProvider'
import { useVisibleTokens } from '@storage/TokensProvider'
import { useColors, useHitSlop } from '@theme/themeHooks'
import { useBalance } from '@utils/Balance'
import { humanReadable } from '@utils/solanaUtils'
import BN from 'bn.js'
import React, { memo, useCallback, useMemo } from 'react'
import { useAsyncCallback } from 'react-async-hook'
import { RefreshControl } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import { Edge } from 'react-native-safe-area-context'
import { useSolana } from '../../solana/SolanaProvider'
import { syncTokenAccounts } from '../../store/slices/balancesSlice'
import { useAppDispatch } from '../../store/store'
import { HomeNavigationProp } from '../home/homeTypes'
import AccountTokenCurrencyBalance from './AccountTokenCurrencyBalance'
import { getSortValue } from './AccountTokenList'
Expand Down Expand Up @@ -120,7 +126,18 @@ const AccountManageTokenListScreen: React.FC = () => {
return getSortValue(b) - getSortValue(a)
})
}, [tokenAccounts])
const dispatch = useAppDispatch()
const { anchorProvider, cluster } = useSolana()
const { currentAccount } = useAccountStorage()
const colors = useColors()

const { loading: refetchingTokens, execute: refetchTokens } =
useAsyncCallback(async () => {
if (!anchorProvider || !currentAccount || !cluster) return
await dispatch(
syncTokenAccounts({ cluster, acct: currentAccount, anchorProvider }),
)
})
const renderItem = useCallback(
// eslint-disable-next-line react/no-unused-prop-types
({ index, item: token }: { index: number; item: string }) => {
Expand Down Expand Up @@ -163,6 +180,15 @@ const AccountManageTokenListScreen: React.FC = () => {
</Box>

<FlatList
refreshControl={
<RefreshControl
enabled
refreshing={refetchingTokens}
onRefresh={refetchTokens}
title=""
tintColor={colors.primaryText}
/>
}
data={mints}
renderItem={renderItem}
keyExtractor={keyExtractor}
Expand Down
64 changes: 62 additions & 2 deletions src/features/account/AccountTokenList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,24 @@ import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { BottomSheetFlatList } from '@gorhom/bottom-sheet'
import { BottomSheetFlatListProps } from '@gorhom/bottom-sheet/lib/typescript/components/bottomSheetScrollable/types'
import { useAccountFetchCache } from '@helium/account-fetch-cache-hooks'
import { DC_MINT, HNT_MINT, IOT_MINT, MOBILE_MINT } from '@helium/spl-utils'
import { useNavigation } from '@react-navigation/native'
import { getAssociatedTokenAddressSync } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
import { useVisibleTokens, DEFAULT_TOKENS } from '@storage/TokensProvider'
import { useAccountStorage } from '@storage/AccountStorageProvider'
import { DEFAULT_TOKENS, useVisibleTokens } from '@storage/TokensProvider'
import { useColors } from '@theme/themeHooks'
import { useBalance } from '@utils/Balance'
import { times } from 'lodash'
import React, { useCallback, useMemo } from 'react'
import React, { useCallback, useEffect, useMemo } from 'react'
import { useAsyncCallback } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { AppState, RefreshControl } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSolana } from '../../solana/SolanaProvider'
import { syncTokenAccounts } from '../../store/slices/balancesSlice'
import { useAppDispatch } from '../../store/store'
import { HomeNavigationProp } from '../home/homeTypes'
import TokenListItem, { TokenSkeleton } from './TokenListItem'

Expand All @@ -33,6 +42,46 @@ const AccountTokenList = ({ onLayout }: Props) => {
const navigation = useNavigation<HomeNavigationProp>()
const { t } = useTranslation()
const { visibleTokens } = useVisibleTokens()
const { currentAccount } = useAccountStorage()
const dispatch = useAppDispatch()
const { anchorProvider, cluster } = useSolana()
const colors = useColors()
const cache = useAccountFetchCache()

const { loading: refetchingTokens, execute: refetchTokens } =
useAsyncCallback(async () => {
if (!anchorProvider || !currentAccount || !cluster) return
await dispatch(
syncTokenAccounts({ cluster, acct: currentAccount, anchorProvider }),
)
await Promise.all(
[...visibleTokens].map((mintStr) => {
// Trigger a refetch on all visible token accounts
return cache.search(
getAssociatedTokenAddressSync(
new PublicKey(mintStr),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
new PublicKey(currentAccount!.solanaAddress!),
),
undefined,
false,
true,
)
}),
)
})

// Trigger refresh when the app comes into the foreground from the background
useEffect(() => {
const listener = AppState.addEventListener('change', (state) => {
if (state === 'active') {
refetchTokens()
}
})
return () => {
listener.remove()
}
}, [refetchTokens])

const onManageTokenList = useCallback(() => {
navigation.navigate('AccountManageTokenListScreen')
Expand Down Expand Up @@ -107,6 +156,17 @@ const AccountTokenList = ({ onLayout }: Props) => {
onLayout={onLayout}
data={mints}
numColumns={2}
refreshControl={
<RefreshControl
enabled
refreshing={refetchingTokens}
onRefresh={refetchTokens}
title=""
tintColor={colors.primaryText}
/>
}
refreshing={refetchingTokens}
onRefresh={refetchTokens}
columnWrapperStyle={{
flexDirection: 'column',
}}
Expand Down
Loading