Skip to content

Commit

Permalink
feat(shortcuts): add claim rewards button in assets screen (#4012)
Browse files Browse the repository at this point in the history
### Description

This adds the claim rewards button in the assets screen.

It hides automatically when scrolling down, to show more of the assets.
And shows up again when scrolling up.

### Test plan


https://github.com/valora-inc/wallet/assets/57791/30f6bb1c-fe6a-4f3e-826a-2b189c9899b1

### Related issues

- Fixes RET-733

### Backwards compatibility

Yes
  • Loading branch information
jeanregisser authored Jul 31, 2023
1 parent 754f083 commit 6f6ff49
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 6 deletions.
3 changes: 3 additions & 0 deletions locales/base/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1783,5 +1783,8 @@
},
"invalidApiUrl": "Invalid hooks preview API URL",
"bannerTitle": "Hooks preview enabled, tap to disable"
},
"assets": {
"claimRewards": "Claim Rewards"
}
}
1 change: 1 addition & 0 deletions src/analytics/Events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ export enum AssetsEvents {
view_wallet_assets = 'view_wallet_assets', // When a user taps on the "Wallet Assets" segmented control
view_dapp_positions = 'view_dapp_positions', // When a user taps on the "Dapp Positions" segmented control
tap_asset = 'tap_asset', // When a user taps on an asset
tap_claim_rewards = 'tap_claim_rewards', // When a user taps on the "Claim Rewards" button
}

export enum NftEvents {
Expand Down
3 changes: 2 additions & 1 deletion src/analytics/Properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import {
AssetsEvents,
AuthenticationEvents,
BuilderHooksEvents,
CICOEvents,
CeloExchangeEvents,
CeloNewsEvents,
CICOEvents,
CoinbasePayEvents,
ContractKitEvents,
DappExplorerEvents,
Expand Down Expand Up @@ -1299,6 +1299,7 @@ interface AssetsEventsProperties {
description: string
balanceUsd: number
}
[AssetsEvents.tap_claim_rewards]: undefined
}

interface NftsEventsProperties {
Expand Down
87 changes: 82 additions & 5 deletions src/tokens/TokenBalances.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useSelector } from 'react-redux'
import { AssetsEvents, HomeEvents } from 'src/analytics/Events'
import ValoraAnalytics from 'src/analytics/ValoraAnalytics'
import { showPriceChangeIndicatorInBalancesSelector } from 'src/app/selectors'
import Button, { BtnSizes, BtnTypes } from 'src/components/Button'
import { AssetsTokenBalance } from 'src/components/TokenBalance'
import Touchable from 'src/components/Touchable'
import OpenLinkIcon from 'src/icons/OpenLinkIcon'
Expand All @@ -33,7 +34,11 @@ import { navigate } from 'src/navigator/NavigationService'
import { Screens } from 'src/navigator/Screens'
import useScrollAwareHeader from 'src/navigator/ScrollAwareHeader'
import { StackParamList } from 'src/navigator/types'
import { positionsSelector, totalPositionsBalanceUsdSelector } from 'src/positions/selectors'
import {
positionsSelector,
positionsWithClaimableRewardsSelector,
totalPositionsBalanceUsdSelector,
} from 'src/positions/selectors'
import { Position } from 'src/positions/types'
import { getFeatureGate } from 'src/statsig'
import { StatsigFeatureGates } from 'src/statsig/types'
Expand Down Expand Up @@ -97,19 +102,48 @@ function TokenBalancesScreen({ navigation, route }: Props) {
const showPositions = getFeatureGate(StatsigFeatureGates.SHOW_POSITIONS)
const displayPositions = showPositions && positions.length > 0

const dappShortcutsEnabled = getFeatureGate(StatsigFeatureGates.SHOW_CLAIM_SHORTCUTS)
const positionsWithClaimableRewards = useSelector(positionsWithClaimableRewardsSelector)
const showClaimRewards = dappShortcutsEnabled && positionsWithClaimableRewards.length > 0

const totalPositionsBalanceUsd = useSelector(totalPositionsBalanceUsdSelector)
const totalPositionsBalanceLocal = useDollarsToLocalAmount(totalPositionsBalanceUsd)
const totalBalanceLocal = totalTokenBalanceLocal?.plus(totalPositionsBalanceLocal ?? 0)

const [nonStickyHeaderHeight, setNonStickyHeaderHeight] = useState(0)
const [listHeaderHeight, setListHeaderHeight] = useState(0)
const [listFooterHeight, setListFooterHeight] = useState(0)

const scrollPosition = useSharedValue(0)
const handleScroll = useAnimatedScrollHandler({
onScroll: (event) => {
scrollPosition.value = event.contentOffset.y
const footerPosition = useSharedValue(0)
const handleScroll = useAnimatedScrollHandler<{ prevScrollY: number }>(
{
onScroll: (event, ctx) => {
const scrollY = event.contentOffset.y
scrollPosition.value = scrollY

function clamp(value: number, min: number, max: number) {
return Math.min(Math.max(value, min), max)
}

// Omit overscroll in the calculation
const clampedScrollY = clamp(
scrollY,
0,
event.contentSize.height - event.layoutMeasurement.height
)

// This does the same as React Native's Animated.diffClamp
const diff = clampedScrollY - ctx.prevScrollY
footerPosition.value = clamp(footerPosition.value + diff, 0, listFooterHeight)
ctx.prevScrollY = clampedScrollY
},
onBeginDrag: (event, ctx) => {
ctx.prevScrollY = event.contentOffset.y
},
},
})
[listFooterHeight]
)

const animatedListHeaderStyles = useAnimatedStyle(() => {
if (nonStickyHeaderHeight === 0 || !displayPositions) {
Expand Down Expand Up @@ -140,6 +174,16 @@ function TokenBalancesScreen({ navigation, route }: Props) {
}
}, [scrollPosition.value, nonStickyHeaderHeight, displayPositions])

const animatedFooterStyles = useAnimatedStyle(() => {
return {
transform: [
{
translateY: footerPosition.value,
},
],
}
}, [footerPosition.value])

useScrollAwareHeader({
navigation,
title: t('totalAssets'),
Expand Down Expand Up @@ -170,6 +214,10 @@ function TokenBalancesScreen({ navigation, route }: Props) {
setListHeaderHeight(event.nativeEvent.layout.height)
}

const handleMeasureListFooterHeight = (event: LayoutChangeEvent) => {
setListFooterHeight(event.nativeEvent.layout.height)
}

const handleChangeActiveView = (_: string, index: number) => {
navigation.setParams({ activeView: index })
ValoraAnalytics.track(
Expand Down Expand Up @@ -300,6 +348,26 @@ function TokenBalancesScreen({ navigation, route }: Props) {
scrollEventThrottle={16}
ListHeaderComponent={<View style={{ height: listHeaderHeight }} />}
/>
{showClaimRewards && (
<Animated.View
style={[
styles.footerContainer,
{ paddingBottom: Math.max(insets.bottom, Spacing.Regular16) },
animatedFooterStyles,
]}
onLayout={handleMeasureListFooterHeight}
>
<Button
type={BtnTypes.SECONDARY}
size={BtnSizes.FULL}
text={t('assets.claimRewards')}
onPress={() => {
ValoraAnalytics.track(AssetsEvents.tap_claim_rewards)
navigate(Screens.DappShortcutsRewards)
}}
/>
</Animated.View>
)}
</>
)
}
Expand Down Expand Up @@ -349,6 +417,15 @@ const styles = StyleSheet.create({
nonStickyHeaderContainer: {
zIndex: 1,
},
footerContainer: {
backgroundColor: Colors.light,
position: 'absolute',
bottom: 0,
left: 10, // so the scroll bar is still visible
right: 10,
paddingHorizontal: Spacing.Thick24 - 10,
paddingTop: Spacing.Regular16,
},
})

export default TokenBalancesScreen

0 comments on commit 6f6ff49

Please sign in to comment.