Skip to content

Commit

Permalink
Feature complete
Browse files Browse the repository at this point in the history
  • Loading branch information
ChewingGlass committed Aug 9, 2023
1 parent c162d51 commit 844a9a1
Show file tree
Hide file tree
Showing 15 changed files with 322 additions and 205 deletions.
23 changes: 9 additions & 14 deletions src/components/ProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { BoxProps } from '@shopify/restyle'
import { Theme } from '@theme/theme'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { LayoutRectangle, LayoutChangeEvent } from 'react-native'
import { LayoutChangeEvent, LayoutRectangle } from 'react-native'
import {
Easing,
useAnimatedStyle,
useSharedValue,
withTiming,
withSpring,
} from 'react-native-reanimated'
import { Theme } from '@theme/theme'
import { ReAnimatedBox } from './AnimatedBox'
import Box from './Box'

Expand All @@ -16,7 +15,6 @@ const ProgressBar = ({
...rest
}: BoxProps<Theme> & { progress: number }) => {
const HEIGHT = 15
const DURATION = 1200

const [progressRect, setProgressRect] = useState<LayoutRectangle>()

Expand All @@ -31,20 +29,16 @@ const ProgressBar = ({
[progressRect],
)

const translateX = useSharedValue(-PROGRESS_WIDTH * 1.25)
const width = useSharedValue(0)

useEffect(() => {
// withRepeat to repeat the animation
translateX.value = withTiming((progressIn / 100) * PROGRESS_WIDTH, {
// Set the bezier curve function as the timing animation easing
easing: Easing.inOut(Easing.ease),
duration: DURATION,
})
}, [PROGRESS_WIDTH, translateX, progressIn])
width.value = withSpring((progressIn / 100) * PROGRESS_WIDTH)
}, [PROGRESS_WIDTH, width, progressIn])

const progress = useAnimatedStyle(() => {
return {
transform: [{ translateX: translateX.value - PROGRESS_WIDTH * 0.5 }],
width: width.value,
}
})

Expand All @@ -57,10 +51,11 @@ const ProgressBar = ({
height={HEIGHT}
backgroundColor="transparent10"
overflow="hidden"
flexDirection="row"
justifyContent="flex-start"
>
<ReAnimatedBox style={progress}>
<Box
width={PROGRESS_WIDTH / 2}
height={HEIGHT - 1}
borderRadius="round"
backgroundColor="lightGrey"
Expand Down
65 changes: 59 additions & 6 deletions src/features/collectables/ClaimAllRewardsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,69 @@ import CircleLoader from '@components/CircleLoader'
import { DelayedFadeIn } from '@components/FadeInOut'
import RewardItem from '@components/RewardItem'
import Text from '@components/Text'
import {
IOT_MINT,
MOBILE_MINT,
sendAndConfirmWithRetry,
toNumber,
} from '@helium/spl-utils'
import useAlert from '@hooks/useAlert'
import { useHntSolConvert } from '@hooks/useHntSolConvert'
import useHotspots from '@hooks/useHotspots'
import useSubmitTxn from '@hooks/useSubmitTxn'
import { useNavigation } from '@react-navigation/native'
import { IOT_LAZY_KEY, MOBILE_LAZY_KEY } from '@utils/constants'
import BN from 'bn.js'
import React, { memo, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { IOT_MINT, MOBILE_MINT, toNumber } from '@helium/spl-utils'
import { CollectableNavigationProp } from './collectablesTypes'
import { useSolana } from '../../solana/SolanaProvider'
import { BalanceChange } from '../../solana/walletSignBottomSheetTypes'
import { CollectableNavigationProp } from './collectablesTypes'

const ClaimAllRewardsScreen = () => {
const { t } = useTranslation()
const navigation = useNavigation<CollectableNavigationProp>()
const [redeeming, setRedeeming] = useState(false)
const [claimError, setClaimError] = useState<string | undefined>()
const { submitClaimAllRewards } = useSubmitTxn()
const {
hntEstimateLoading,
hntSolConvertTransaction,
hntEstimate,
hasEnoughSol,
} = useHntSolConvert()
const { showOKCancelAlert } = useAlert()
const { anchorProvider } = useSolana()
const showHNTConversionAlert = useCallback(async () => {
if (!anchorProvider || !hntSolConvertTransaction) return

const decision = await showOKCancelAlert({
title: t('browserScreen.insufficientSolToPayForFees'),
message: t('browserScreen.wouldYouLikeToConvert', {
amount: hntEstimate,
ticker: 'HNT',
}),
})

if (!decision) return
const signed = await anchorProvider.wallet.signTransaction(
hntSolConvertTransaction,
)
await sendAndConfirmWithRetry(
anchorProvider.connection,
signed.serialize(),
{
skipPreflight: true,
},
'confirmed',
)
}, [
anchorProvider,
hntSolConvertTransaction,
showOKCancelAlert,
t,
hntEstimate,
])

const {
hotspots,
Expand All @@ -45,6 +91,9 @@ const ClaimAllRewardsScreen = () => {
try {
setClaimError(undefined)
setRedeeming(true)
if (!hasEnoughSol) {
await showHNTConversionAlert()
}

const balanceChanges: BalanceChange[] = []

Expand Down Expand Up @@ -78,11 +127,13 @@ const ClaimAllRewardsScreen = () => {
setRedeeming(false)
}
}, [
navigation,
hasEnoughSol,
pendingIotRewards,
pendingMobileRewards,
submitClaimAllRewards,
hotspotsWithMeta,
pendingMobileRewards,
pendingIotRewards,
navigation,
showHNTConversionAlert,
])

const addAllToAccountDisabled = useMemo(() => {
Expand Down Expand Up @@ -161,7 +212,9 @@ const ClaimAllRewardsScreen = () => {
titleColor="black"
marginHorizontal="l"
onPress={onClaimRewards}
disabled={addAllToAccountDisabled || redeeming}
disabled={
addAllToAccountDisabled || redeeming || hntEstimateLoading
}
TrailingComponent={
redeeming ? (
<CircleLoader loaderSize={20} color="white" />
Expand Down
21 changes: 17 additions & 4 deletions src/features/collectables/ClaimingRewardsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,23 @@ const ClaimingRewardsScreen = () => {
</Text>
<Box flexDirection="row" marginHorizontal="xxl" marginTop="m">
{typeof solanaPayment.progress !== 'undefined' ? (
<ProgressBar
progress={solanaPayment.progress}
paddingHorizontal="l"
/>
<Box
width="100%"
flexDirection="column"
alignContent="stretch"
alignItems="stretch"
>
<ProgressBar progress={solanaPayment.progress.percent} />
<Text
textAlign="center"
variant="body2"
color="secondaryText"
marginTop="s"
numberOfLines={2}
>
{solanaPayment.progress.text}
</Text>
</Box>
) : (
<IndeterminateProgressBar paddingHorizontal="l" />
)}
Expand Down
1 change: 1 addition & 0 deletions src/features/collectables/CollectablesTopTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const CollectablesTopTabs = () => {
const screenOpts = useCallback(
({ route }: { route: RouteProp<CollectablesTabParamList> }) =>
({
lazy: true,
headerShown: false,
tabBarLabelStyle: {
fontFamily: Font.medium,
Expand Down
8 changes: 4 additions & 4 deletions src/features/collectables/HotspotList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,12 @@ const HotspotList = () => {
hasPressedState={false}
/>
<ListItem
key="show-all"
title={t('collectablesScreen.hotspots.all')}
key="show-1000"
title={t('collectablesScreen.hotspots.thousand')}
subtitle={t('collectablesScreen.hotspots.showAllHotspotsWarning')}
// Set an unrealistically high amount
onPress={handleSetPageAmount(10000)}
selected={pageAmount === 10000}
onPress={handleSetPageAmount(1000)}
selected={pageAmount === 1000}
hasPressedState={false}
subtitleColor="orange500"
/>
Expand Down
13 changes: 4 additions & 9 deletions src/hooks/useEntityKey.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { useEffect, useState } from 'react'
import { decodeEntityKey } from '@helium/helium-entity-manager-sdk'
import { HotspotWithPendingRewards } from '../types/solana'
import { useKeyToAsset } from './useKeyToAsset'

Check failure on line 3 in src/hooks/useEntityKey.ts

View workflow job for this annotation

GitHub Actions / build

Missing file extension for "./useKeyToAsset"

export const useEntityKey = (hotspot: HotspotWithPendingRewards) => {
const [entityKey, setEntityKey] = useState<string>()
const { info: kta } = useKeyToAsset(hotspot?.id)

useEffect(() => {
if (hotspot) {
setEntityKey(hotspot.content.json_uri.split('/').slice(-1)[0])
}
}, [hotspot, setEntityKey])

return entityKey
return kta ? decodeEntityKey(kta.entityKey, kta.keySerialization) : undefined
}
4 changes: 2 additions & 2 deletions src/hooks/useHntSolConvert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ export function useHntSolConvert() {
}, [baseUrl])

const hasEnoughSol = useMemo(() => {
if (!hntBalance || !solBalance || !hntEstimate) return true
if (!hntBalance || !hntEstimate) return true

if (hntBalance.lt(hntEstimate)) return true

return solBalance.gt(new BN(0.02 * LAMPORTS_PER_SOL))
return (solBalance || new BN(0)).gt(new BN(0.02 * LAMPORTS_PER_SOL))
}, [hntBalance, solBalance, hntEstimate])

const {
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useMetaplexMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const MPL_PID = new PublicKey('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const cache: Record<string, Promise<any>> = {}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getMetadata(uri: string | undefined): Promise<any | undefined> {
export function getMetadata(uri: string | undefined): Promise<any | undefined> {
if (uri) {
if (!cache[uri]) {
cache[uri] = fetch(uri).then((res) => res.json())
Expand Down
23 changes: 0 additions & 23 deletions src/hooks/useSubmitTxn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,29 +310,6 @@ export default () => {
throw new Error(t('errors.account'))
}

const txns = await solUtils.claimAllRewardsTxns(
anchorProvider,
lazyDistributors,
hotspots,
)

const serializedTxs = txns.map((txn) =>
txn.serialize({
requireAllSignatures: false,
}),
)

const decision = await walletSignBottomSheetRef.show({
type: WalletStandardMessageTypes.signTransaction,
url: '',
additionalMessage: t('transactions.signClaimAllRewardsTxn'),
serializedTxs: serializedTxs.map(Buffer.from),
})

if (!decision) {
throw new Error('User rejected transaction')
}

dispatch(
claimAllRewards({
account: currentAccount,
Expand Down
6 changes: 3 additions & 3 deletions src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export default {
claimingRewardsBody:
'You can exit this screen while you wait. We’ll update your Wallet momentarily.',
claimComplete: 'Rewards Claimed!',
claimCompleteBody: 'We’ve added your tokens to your wallet.',
claimCompleteBody: 'Your tokens have been added to your wallet.',
claimError: 'Claim failed. Please try again later.',
transferCollectableAlertTitle:
'Are you sure you will like to transfer your collectable?',
Expand Down Expand Up @@ -219,7 +219,7 @@ export default {
'Warning: Load times may be affected when showing all hotspots per page.',
twenty: '20',
fifty: '50',
all: 'All',
thousand: '1000',
copyEccCompact: 'Copy Hotspot Key',
assertLocation: 'Assert Location',
antennaSetup: 'Antenna Setup',
Expand Down Expand Up @@ -332,7 +332,7 @@ export default {
chooseTokenToSwap: 'Choose a token to swap',
chooseTokenToReceive: 'Choose a token to receive',
swapComplete: 'Tokens swapped!',
swapCompleteBody: 'We’ve updated the tokens on your wallet.',
swapCompleteBody: 'The tokens in your wallet have been updated.',
swappingTokens: 'Swapping your tokens...',
swappingTokensBody:
'You can exit this screen while you wait. We’ll update your Wallet momentarily.',
Expand Down
1 change: 1 addition & 0 deletions src/navigation/TabBarNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ const TabBarNavigator = () => {
tabBar={(props: BottomTabBarProps) => <MyTabBar {...props} />}
screenOptions={{
headerShown: false,
lazy: true,
}}
sceneContainerStyle={{
paddingBottom: NavBarHeight + bottom,
Expand Down
38 changes: 36 additions & 2 deletions src/solana/SolanaProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import { init as initHem } from '@helium/helium-entity-manager-sdk'
import { init as initHsd } from '@helium/helium-sub-daos-sdk'
import { init as initLazy } from '@helium/lazy-distributor-sdk'
import { DC_MINT, HNT_MINT } from '@helium/spl-utils'
import { Cluster, Transaction } from '@solana/web3.js'
import {
AccountInfo,
Cluster,
Commitment,
PublicKey,
RpcResponseAndContext,
Transaction,
} from '@solana/web3.js'
import React, {
ReactNode,
createContext,
Expand Down Expand Up @@ -85,13 +92,40 @@ const useSolanaHook = () => {
const cache = useMemo(() => {
if (!connection) return

return new AccountFetchCache({
const c = new AccountFetchCache({
connection,
delay: 100,
commitment: 'confirmed',
missingRefetchDelay: 60 * 1000,
extendConnection: true,
})
const oldGetAccountinfoAndContext =
connection.getAccountInfoAndContext.bind(connection)

// Anchor uses this call on .fetch and .fetchNullable even though it doesn't actually need the context. Add caching.
connection.getAccountInfoAndContext = async (
publicKey: PublicKey,
com?: Commitment,
): Promise<RpcResponseAndContext<AccountInfo<Buffer> | null>> => {
if (
(com || connection.commitment) === 'confirmed' ||
typeof (com || connection.commitment) === 'undefined'
) {
const [result, dispose] = await c.searchAndWatch(publicKey)
setTimeout(dispose, 30 * 1000) // cache for 30s
return {
value: result?.account || null,
context: {
slot: 0,
},
}
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return oldGetAccountinfoAndContext!(publicKey, com)
}

return c
}, [connection])
useEffect(() => {
// Don't sub to hnt or dc they change a bunch
Expand Down
Loading

0 comments on commit 844a9a1

Please sign in to comment.