Skip to content

Commit e34ca3b

Browse files
chore: more app updates for UK compliance (#6221)
### Description This PR contains all the requested changes described in the task. Some features that were required to be hidden to UK users could be done through existing feature flags, but I opted to consolidate the UK changes under the `SHOW_UK_COMPLIANT_VARIANT` flag for readability. ### Test plan User with activity: https://github.com/user-attachments/assets/e294569d-1165-45d1-be25-b810014468a5 User with no activity: https://github.com/user-attachments/assets/d61054df-7445-4753-a804-7de065554e2c ### Related issues - Fixes RET-1239 ### Backwards compatibility Y ### Network scalability If a new NetworkId and/or Network are added in the future, the changes in this PR will: - [ ] Continue to work without code changes, OR trigger a compilation error (guaranteeing we find it when a new network is added)
1 parent ab5e17a commit e34ca3b

18 files changed

+305
-152
lines changed

e2e/src/Discover.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ describe('Discover tab', () => {
1313
})
1414
await waitForElementByIdAndTap('Tab/Discover')
1515

16-
await scrollIntoView('Explore All', 'DiscoverScrollView')
17-
await element(by.text('Explore All')).tap()
16+
await scrollIntoView('View All', 'DiscoverScrollView')
17+
await element(by.text('View All')).tap()
1818

1919
await waitFor(element(by.id(`DappsScreen/DappsList`)))
2020
})

locales/base/translation.json

+7-4
Original file line numberDiff line numberDiff line change
@@ -1460,14 +1460,15 @@
14601460
"dappsScreen": {
14611461
"title": "Dapps",
14621462
"titleDiscover": "Discover",
1463-
"exploreDapps": "Explore Dapps",
1464-
"exploreAll": "Explore All",
1463+
"exploreDapps": "Dapps",
1464+
"exploreAll": "View All",
14651465
"message": "Explore ways to use your assets",
14661466
"errorMessage": "There was an error loading dapps",
14671467
"featuredDapp": "Featured",
14681468
"allDapps": "All",
14691469
"favoriteDapps": "My Favorites",
14701470
"mostPopularDapps": "Most Popular",
1471+
"mostPopularDapps_UK": "Other Dapps",
14711472
"favoriteDappsAndAll": "My Favorites & All",
14721473
"searchPlaceHolder": "Search dapps",
14731474
"noFavorites": {
@@ -1483,7 +1484,8 @@
14831484
"message": "<0>{{filter}}</0> filter applied",
14841485
"removeFilter": "Remove filter",
14851486
"searchMessage": "No matching results found for <0>\"{{searchTerm}}\"</0>"
1486-
}
1487+
},
1488+
"disclaimer_UK": "This is a list of third-party Dapps. The description for each Dapp is purely informational, and not an invitation to use them."
14871489
},
14881490
"dappRankings": {
14891491
"title": "Dapp rankings",
@@ -2298,7 +2300,8 @@
22982300
"claimRewardSubtitle_noTxAppName": "from unknown app",
22992301
"error": {
23002302
"fetchError": "Oops, there was an issue refreshing your feed. Your transaction history may be incomplete for now."
2301-
}
2303+
},
2304+
"noTransactions": "Congratulations, you've successfully created a {{appName}} wallet!"
23022305
},
23032306
"transactionDetails": {
23042307
"descriptionLabel": "Details",

src/dapps/DappsScreen.test.tsx

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { fireEvent, render, within } from '@testing-library/react-native'
22
import * as React from 'react'
33
import { Provider } from 'react-redux'
4-
import { DappExplorerEvents } from 'src/analytics/Events'
54
import AppAnalytics from 'src/analytics/AppAnalytics'
5+
import { DappExplorerEvents } from 'src/analytics/Events'
6+
import DappsScreen from 'src/dapps/DappsScreen'
67
import { dappSelected, favoriteDapp, fetchDappsList, unfavoriteDapp } from 'src/dapps/slice'
78
import { DappCategory, DappSection } from 'src/dapps/types'
8-
import DappsScreen from 'src/dapps/DappsScreen'
99
import { getFeatureGate } from 'src/statsig'
10+
import { StatsigFeatureGates } from 'src/statsig/types'
1011
import MockedNavigator from 'test/MockedNavigator'
1112
import { createMockStore } from 'test/utils'
1213
import { mockDappListWithCategoryNames } from 'test/values'
@@ -45,7 +46,6 @@ describe('DappsScreen', () => {
4546
beforeEach(() => {
4647
defaultStore.clearActions()
4748
jest.clearAllMocks()
48-
jest.mocked(getFeatureGate).mockReturnValue(false)
4949
})
5050

5151
it('renders correctly and fires the correct actions on press dapp', () => {
@@ -59,6 +59,7 @@ describe('DappsScreen', () => {
5959
expect(queryByText('featuredDapp')).toBeFalsy()
6060
expect(getByText('Dapp 1')).toBeTruthy()
6161
expect(getByText('Dapp 2')).toBeTruthy()
62+
expect(queryByText('dappsScreen.disclaimer_UK')).toBeFalsy()
6263

6364
fireEvent.press(getByText('Dapp 1'))
6465

@@ -68,6 +69,20 @@ describe('DappsScreen', () => {
6869
])
6970
})
7071

72+
it('renders the disclaimer for UK compliance', () => {
73+
jest
74+
.mocked(getFeatureGate)
75+
.mockImplementation((gate) => gate === StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT)
76+
77+
const { getByText } = render(
78+
<Provider store={defaultStore}>
79+
<MockedNavigator component={DappsScreen} />
80+
</Provider>
81+
)
82+
83+
expect(getByText('dappsScreen.disclaimer_UK')).toBeTruthy()
84+
})
85+
7186
it('renders correctly and fires the correct actions on press deep linked dapp', () => {
7287
const { getByText, queryByText } = render(
7388
<Provider store={defaultStore}>
@@ -88,7 +103,7 @@ describe('DappsScreen', () => {
88103
])
89104
})
90105

91-
it('pens dapps directly', () => {
106+
it('opens dapps directly', () => {
92107
const store = createMockStore({
93108
dapps: {
94109
dappListApiUrl: 'http://url.com',

src/dapps/DappsScreen.tsx

+18-8
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import { Screens } from 'src/navigator/Screens'
3737
import useScrollAwareHeader from 'src/navigator/ScrollAwareHeader'
3838
import { StackParamList } from 'src/navigator/types'
3939
import { useDispatch, useSelector } from 'src/redux/hooks'
40+
import { getFeatureGate } from 'src/statsig'
41+
import { StatsigFeatureGates } from 'src/statsig/types'
4042
import Colors from 'src/styles/colors'
4143
import { typeScale } from 'src/styles/fonts'
4244
import { Spacing } from 'src/styles/styles'
@@ -86,6 +88,8 @@ function DappsScreen({ navigation }: Props) {
8688
const { onSelectDapp } = useOpenDapp()
8789
const { onFavoriteDapp, DappFavoritedToast } = useDappFavoritedToast(sectionListRef)
8890

91+
const showUKCompliantVariant = getFeatureGate(StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT)
92+
8993
const removeFilter = (filter: BooleanFilterChip<DappWithCategoryNames>) => {
9094
AppAnalytics.track(DappExplorerEvents.dapp_filter, {
9195
filterId: filter.id,
@@ -215,15 +219,21 @@ function DappsScreen({ navigation }: Props) {
215219
// @ts-expect-error
216220
ref={sectionListRef}
217221
ListFooterComponent={
218-
<Text style={styles.disclaimer}>{t('dappsDisclaimerAllDapps')}</Text>
222+
<Text style={[styles.disclaimer, { textAlign: 'center' }]}>
223+
{t('dappsDisclaimerAllDapps')}
224+
</Text>
219225
}
220226
ListHeaderComponent={
221227
<>
222-
{
228+
<View style={styles.titleContainer}>
223229
<Text onLayout={handleMeasureTitleHeight} style={styles.title}>
224230
{t('dappsScreen.exploreDapps')}
225231
</Text>
226-
}
232+
{showUKCompliantVariant && (
233+
<Text style={styles.disclaimer}>{t('dappsScreen.disclaimer_UK')}</Text>
234+
)}
235+
</View>
236+
227237
<DappFeaturedActions />
228238
<SearchInput
229239
onChangeText={(text) => {
@@ -335,18 +345,18 @@ const styles = StyleSheet.create({
335345
disclaimer: {
336346
...typeScale.bodyXSmall,
337347
color: Colors.gray4,
338-
textAlign: 'center',
339-
marginTop: Spacing.Large32,
340-
marginBottom: Spacing.Regular16,
341348
},
342349
listFooterComponent: {
343-
flex: 1,
344-
justifyContent: 'flex-end',
350+
marginTop: Spacing.Large32,
351+
marginBottom: Spacing.Regular16,
345352
},
346353
title: {
347354
...typeScale.titleMedium,
348355
color: Colors.black,
356+
},
357+
titleContainer: {
349358
marginBottom: Spacing.Thick24,
359+
gap: Spacing.Tiny4,
350360
},
351361
dappCard: {
352362
marginTop: Spacing.Regular16,

src/dappsExplorer/DiscoverDappsCard.tsx

+22-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import useOpenDapp from 'src/dappsExplorer/useOpenDapp'
1212
import { navigate } from 'src/navigator/NavigationService'
1313
import { Screens } from 'src/navigator/Screens'
1414
import { useDispatch, useSelector } from 'src/redux/hooks'
15+
import { getFeatureGate } from 'src/statsig'
16+
import { StatsigFeatureGates } from 'src/statsig/types'
1517
import Colors from 'src/styles/colors'
1618
import { typeScale } from 'src/styles/fonts'
1719
import { Spacing } from 'src/styles/styles'
@@ -36,6 +38,8 @@ function DiscoverDappsCard() {
3638

3739
const { onSelectDapp } = useOpenDapp()
3840

41+
const showUKCompliantVariant = getFeatureGate(StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT)
42+
3943
useEffect(() => {
4044
dispatch(fetchDappsList())
4145
AppAnalytics.track(DappExplorerEvents.dapp_screen_open)
@@ -57,7 +61,9 @@ function DiscoverDappsCard() {
5761
data: mostPopularDapps
5862
.filter((dapp) => !favoriteDappIds.includes(dapp.id))
5963
.slice(0, MAX_DAPPS - favoriteDapps.length),
60-
sectionName: t('dappsScreen.mostPopularDapps'),
64+
sectionName: t('dappsScreen.mostPopularDapps', {
65+
context: showUKCompliantVariant ? 'UK' : '',
66+
}),
6167
dappSection: DappSection.MostPopular,
6268
testID: 'DiscoverDappsCard/MostPopularSection',
6369
},
@@ -91,7 +97,14 @@ function DiscoverDappsCard() {
9197
<SectionList
9298
ref={sectionListRef}
9399
scrollEnabled={false}
94-
ListHeaderComponent={<Text style={styles.title}>{t('dappsScreen.exploreDapps')}</Text>}
100+
ListHeaderComponent={
101+
<View style={styles.titleContainer}>
102+
<Text style={styles.title}>{t('dappsScreen.exploreDapps')}</Text>
103+
{showUKCompliantVariant && (
104+
<Text style={styles.disclaimer}>{t('dappsScreen.disclaimer_UK')}</Text>
105+
)}
106+
</View>
107+
}
95108
ListFooterComponent={
96109
<View>
97110
<Text style={styles.footer}>{t('dappsScreen.exploreAll')}</Text>
@@ -150,7 +163,14 @@ const styles = StyleSheet.create({
150163
title: {
151164
...typeScale.labelSemiBoldMedium,
152165
color: Colors.black,
166+
},
167+
titleContainer: {
153168
marginBottom: Spacing.Smallest8,
169+
gap: Spacing.Tiny4,
170+
},
171+
disclaimer: {
172+
...typeScale.bodyXSmall,
173+
color: Colors.gray3,
154174
},
155175
})
156176

src/earn/EarnEntrypoint.test.tsx

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
11
import { fireEvent, render } from '@testing-library/react-native'
22
import React from 'react'
3-
import { EarnEvents } from 'src/analytics/Events'
43
import AppAnalytics from 'src/analytics/AppAnalytics'
4+
import { EarnEvents } from 'src/analytics/Events'
55
import EarnEntrypoint from 'src/earn/EarnEntrypoint'
66
import { navigate } from 'src/navigator/NavigationService'
77
import { Screens } from 'src/navigator/Screens'
8+
import { getFeatureGate } from 'src/statsig'
9+
import { StatsigFeatureGates } from 'src/statsig/types'
10+
11+
jest.mock('src/statsig')
812

913
describe('EarnEntrypoint', () => {
1014
beforeEach(() => {
1115
jest.clearAllMocks()
16+
jest
17+
.mocked(getFeatureGate)
18+
.mockImplementation((gate) => gate !== StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT)
19+
})
20+
21+
it('renders nothing for UK compliant variant', () => {
22+
jest
23+
.mocked(getFeatureGate)
24+
.mockImplementation((gate) => gate === StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT)
25+
26+
const { toJSON } = render(<EarnEntrypoint />)
27+
28+
expect(toJSON()).toBeNull()
1229
})
1330

1431
it('renders correctly', () => {

src/earn/EarnEntrypoint.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
import React from 'react'
22
import { useTranslation } from 'react-i18next'
33
import { StyleSheet, Text, View } from 'react-native'
4-
import { EarnEvents } from 'src/analytics/Events'
54
import AppAnalytics from 'src/analytics/AppAnalytics'
5+
import { EarnEvents } from 'src/analytics/Events'
66
import Touchable from 'src/components/Touchable'
77
import CircledIcon from 'src/icons/CircledIcon'
88
import EarnCoins from 'src/icons/EarnCoins'
99
import { navigate } from 'src/navigator/NavigationService'
1010
import { Screens } from 'src/navigator/Screens'
11+
import { getFeatureGate } from 'src/statsig'
12+
import { StatsigFeatureGates } from 'src/statsig/types'
1113
import Colors from 'src/styles/colors'
1214
import { typeScale } from 'src/styles/fonts'
1315
import { Spacing } from 'src/styles/styles'
1416

1517
export default function EarnEntrypoint() {
1618
const { t } = useTranslation()
19+
const showUKCompliantVariant = getFeatureGate(StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT)
20+
21+
if (showUKCompliantVariant) {
22+
return null
23+
}
1724

1825
return (
1926
<View style={styles.container}>

src/images/Celebration.tsx

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from 'react'
2+
import Svg, { Path } from 'react-native-svg'
3+
4+
interface Props {
5+
width?: number
6+
height?: number
7+
testID?: string
8+
}
9+
10+
export default function Celebration({ width = 58, height = 53, testID }: Props) {
11+
return (
12+
<Svg width={width} height={height} viewBox="0 0 58 53" fill="none" testID={testID}>
13+
<Path fill="#FD56B5" d="M11.617 22.922 1 52.267l30.61-10.395" />
14+
<Path
15+
stroke="#000"
16+
strokeLinecap="round"
17+
strokeLinejoin="round"
18+
d="M11.617 22.922 1 52.267l30.61-10.395"
19+
/>
20+
<Path
21+
fill="#6E75EE"
22+
stroke="#000"
23+
strokeLinecap="round"
24+
strokeLinejoin="round"
25+
d="M27.69 26.477c5.654 5.464 8.058 12 5.373 14.598-.74.715-1.794 1.06-3.045 1.064-3.29.015-7.967-2.296-12.062-6.257-5.654-5.464-8.058-12-5.373-14.598 2.688-2.598 9.452-.276 15.106 5.193Z"
26+
/>
27+
<Path
28+
stroke="#000"
29+
strokeLinecap="round"
30+
strokeLinejoin="round"
31+
d="M15.148 32.76s8.669-9.555 9.322-18.02M17.952 35.882S37.232 18.483 40.12 6.066M21.187 38.592s15.388-12.395 30.899-11.966M30.719 12.173l1.853-3.9M50.3 20.645l4.411-.474M18.895 14.74l.003-1.205M34.445 25.46l.919-.816M38.931 43.845l1.212.284M25.175 9.514c-3.54-1.826-2.253-4.24-.123-4.367 3.251-.19 3.338-4.909-3.318-4.04M41.038 20.955c-1.644-3.28-.523-5.51 2.257-5.296 2.97.23 7.484 2.323 7.013-3.038-.539-6.13 3.385-6.7 6.692-5.063M41.065 36.892c1.382-3.168 4.289-2.77 5.295-.076 1.005 2.694 4.803 3.838 6.7-.402"
32+
/>
33+
</Svg>
34+
)
35+
}

src/points/PointsDiscoverCard.test.tsx

+25-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import PointsDiscoverCard from 'src/points/PointsDiscoverCard'
99
import { pointsDataRefreshStarted } from 'src/points/slice'
1010
import { RootState } from 'src/redux/store'
1111
import { getFeatureGate } from 'src/statsig/index'
12+
import { StatsigFeatureGates } from 'src/statsig/types'
1213
import { RecursivePartial, createMockStore } from 'test/utils'
1314

1415
jest.mock('src/analytics/AppAnalytics')
@@ -32,8 +33,31 @@ const renderPointsDiscoverCard = (storeOverrides?: RecursivePartial<RootState>)
3233
describe('PointsDiscoverCard', () => {
3334
beforeEach(() => {
3435
jest.clearAllMocks()
36+
jest.mocked(getFeatureGate).mockImplementation((gate) => {
37+
if (gate === StatsigFeatureGates.SHOW_POINTS) {
38+
return true
39+
}
40+
if (gate === StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT) {
41+
return false
42+
}
43+
throw new Error('Unexpected gate')
44+
})
45+
})
46+
47+
it('renders nothing for UK compliant variant', () => {
48+
jest.mocked(getFeatureGate).mockImplementation((gate) => {
49+
if (gate === StatsigFeatureGates.SHOW_POINTS) {
50+
return true
51+
}
52+
if (gate === StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT) {
53+
return true
54+
}
55+
throw new Error('Unexpected gate')
56+
})
57+
58+
const { toJSON } = renderPointsDiscoverCard()
3559

36-
jest.mocked(getFeatureGate).mockReturnValue(true)
60+
expect(toJSON()).toBeNull()
3761
})
3862

3963
it('renders when feature gate is enabled', () => {

src/points/PointsDiscoverCard.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { Spacing } from 'src/styles/styles'
1919

2020
export default function PointsDiscoverCard() {
2121
const showPoints = getFeatureGate(StatsigFeatureGates.SHOW_POINTS)
22+
const showUKCompliantVariant = getFeatureGate(StatsigFeatureGates.SHOW_UK_COMPLIANT_VARIANT)
2223

2324
const dispatch = useDispatch()
2425
const { t } = useTranslation()
@@ -38,7 +39,7 @@ export default function PointsDiscoverCard() {
3839
dispatch(pointsDataRefreshStarted())
3940
}, [])
4041

41-
if (!showPoints) {
42+
if (!showPoints || showUKCompliantVariant) {
4243
return null
4344
}
4445

0 commit comments

Comments
 (0)