diff --git a/src/points/PointsHome.test.tsx b/src/points/PointsHome.test.tsx index 9c7d7788323..94142091495 100644 --- a/src/points/PointsHome.test.tsx +++ b/src/points/PointsHome.test.tsx @@ -1,15 +1,18 @@ import { fireEvent, render, waitFor } from '@testing-library/react-native' import * as React from 'react' import { Provider } from 'react-redux' -import { PointsEvents } from 'src/analytics/Events' import AppAnalytics from 'src/analytics/AppAnalytics' +import { PointsEvents } from 'src/analytics/Events' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import PointsHome from 'src/points/PointsHome' import { getHistoryStarted, getPointsConfigRetry } from 'src/points/slice' import { RootState } from 'src/redux/store' +import { getDynamicConfigParams, getFeatureGate } from 'src/statsig' +import { NetworkId } from 'src/transactions/types' import { RecursivePartial, createMockStore, getMockStackScreenProps } from 'test/utils' +jest.mock('src/statsig') jest.mock('src/points/PointsHistoryBottomSheet') const mockScreenProps = () => getMockStackScreenProps(Screens.PointsHome) @@ -36,6 +39,16 @@ const renderPointsHome = (storeOverrides?: RecursivePartial) => { }, pointsConfigStatus: 'success', }, + tokens: { + tokenBalances: { + ['celo-alfajores:0xusd']: { + tokenId: 'celo-alfajores:0xabcd', + address: '0xabcd', + networkId: NetworkId['celo-alfajores'], + balance: '10', + }, + }, + }, } ) const tree = render( @@ -53,6 +66,10 @@ const renderPointsHome = (storeOverrides?: RecursivePartial) => { describe(PointsHome, () => { beforeEach(() => { jest.clearAllMocks() + jest.mocked(getFeatureGate).mockReturnValue(true) + jest + .mocked(getDynamicConfigParams) + .mockReturnValue({ jumpstartContracts: { 'celo-alfajores': '0x1234' } }) }) it('renders a loading state while loading config', async () => { diff --git a/src/points/selectors.test.ts b/src/points/selectors.test.ts index bef564c0e63..b0b03c68afe 100644 --- a/src/points/selectors.test.ts +++ b/src/points/selectors.test.ts @@ -1,6 +1,10 @@ import { pointsActivitiesSelector, pointsHistorySelector } from 'src/points/selectors' +import { getDynamicConfigParams, getFeatureGate } from 'src/statsig' +import { NetworkId } from 'src/transactions/types' import { getMockStoreData } from 'test/utils' +jest.mock('src/statsig') + describe('pointsHistorySelector', () => { it('returns UNIX timestamp', () => { const stateWithPointsHistory = getMockStoreData({ @@ -27,6 +31,12 @@ describe('pointsHistorySelector', () => { }) describe('pointsActivitiesSelector', () => { + beforeEach(() => { + jest + .mocked(getDynamicConfigParams) + .mockReturnValue({ jumpstartContracts: { 'celo-alfajores': '0x1234' } }) + }) + it('should return an empty array if there are no activities', () => { const stateWithoutPointsConfig = getMockStoreData({ points: { @@ -61,4 +71,85 @@ describe('pointsActivitiesSelector', () => { { activityId: 'create-wallet', pointsAmount: 10, completed: true }, ]) }) + + it('should return points activities with live links when enabled and user has jumpstart tokens', () => { + jest.mocked(getFeatureGate).mockReturnValue(true) + + const stateWithPointsConfig = getMockStoreData({ + points: { + pointsConfig: { + activitiesById: { + 'create-live-link': { pointsAmount: 10 }, + }, + }, + }, + tokens: { + tokenBalances: { + ['celo-alfajores:0xusd']: { + tokenId: 'celo-alfajores:0xabcd', + address: '0xabcd', + networkId: NetworkId['celo-alfajores'], + balance: '10', + }, + }, + }, + }) + const result = pointsActivitiesSelector(stateWithPointsConfig) + + expect(result).toEqual([{ activityId: 'create-live-link', pointsAmount: 10, completed: false }]) + }) + + it('should return points activities without live links if they are disabled', () => { + jest.mocked(getFeatureGate).mockReturnValue(false) + + const stateWithPointsConfig = getMockStoreData({ + points: { + pointsConfig: { + activitiesById: { + 'create-live-link': { pointsAmount: 10 }, + }, + }, + }, + tokens: { + tokenBalances: { + ['celo-alfajores:0xusd']: { + tokenId: 'celo-alfajores:0xabcd', + address: '0xabcd', + networkId: NetworkId['celo-alfajores'], + balance: '10', + }, + }, + }, + }) + const result = pointsActivitiesSelector(stateWithPointsConfig) + + expect(result).toEqual([]) + }) + + it('should return points activities without live links if user has no jumpstart tokens', () => { + jest.mocked(getFeatureGate).mockReturnValue(true) + + const stateWithPointsConfig = getMockStoreData({ + points: { + pointsConfig: { + activitiesById: { + 'create-live-link': { pointsAmount: 10 }, + }, + }, + }, + tokens: { + tokenBalances: { + ['celo-alfajores:0xusd']: { + tokenId: 'celo-alfajores:0xabcd', + address: '0xabcd', + networkId: NetworkId['celo-alfajores'], + balance: '0', + }, + }, + }, + }) + const result = pointsActivitiesSelector(stateWithPointsConfig) + + expect(result).toEqual([]) + }) }) diff --git a/src/points/selectors.ts b/src/points/selectors.ts index 34d3304d79f..dc1cd617d74 100644 --- a/src/points/selectors.ts +++ b/src/points/selectors.ts @@ -1,6 +1,9 @@ import { createSelector } from 'reselect' import { ClaimHistoryCardItem, PointsActivity, PointsActivityId } from 'src/points/types' import { RootState } from 'src/redux/reducers' +import { getFeatureGate } from 'src/statsig' +import { StatsigFeatureGates } from 'src/statsig/types' +import { jumpstartSendTokensSelector } from 'src/tokens/selectors' export const nextPageUrlSelector = (state: RootState) => { return state.points.nextPageUrl @@ -35,14 +38,29 @@ export const pointsConfigStatusSelector = (state: RootState) => state.points.poi const pointsConfigSelector = (state: RootState) => state.points.pointsConfig +const showJumpstartSendSelector = () => getFeatureGate(StatsigFeatureGates.SHOW_JUMPSTART_SEND) + export const pointsActivitiesSelector = createSelector( - [pointsConfigSelector, trackOnceActivitiesSelector], - (pointsConfig, trackOnceActivities) => { - return Object.entries(pointsConfig.activitiesById).map(([activityId, metadata]) => ({ - ...metadata, - activityId, - completed: trackOnceActivities[activityId as PointsActivityId] ?? false, - })) as PointsActivity[] + [ + pointsConfigSelector, + trackOnceActivitiesSelector, + jumpstartSendTokensSelector, + showJumpstartSendSelector, + ], + (pointsConfig, trackOnceActivities, jumpstartTokens, jumpstartSendEnabled) => { + const showJumpstart = jumpstartSendEnabled && jumpstartTokens.length > 0 + const excludedActivities = new Set() + if (!showJumpstart) { + excludedActivities.add('create-live-link') + } + + return ( + Object.entries(pointsConfig.activitiesById).map(([activityId, metadata]) => ({ + ...metadata, + activityId, + completed: trackOnceActivities[activityId as PointsActivityId] ?? false, + })) as PointsActivity[] + ).filter(({ activityId }) => !excludedActivities.has(activityId)) } )