Skip to content

Commit

Permalink
CP-5857 User agrees to CoreAnalytics during login with existing wallet (
Browse files Browse the repository at this point in the history
#744)

Co-authored-by: An Nguyen <[email protected]>
  • Loading branch information
neven-s and atn4z7 authored Jul 10, 2023
1 parent db71c4a commit 0cc0085
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 64 deletions.
20 changes: 14 additions & 6 deletions app/AppHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import { selectSelectedCurrency } from 'store/settings/currency'
import { onLogOut, setWalletState, WalletState } from 'store/app'
import { resetLoginAttempt } from 'store/security'
import { formatCurrency } from 'utils/FormatCurrency'
import {
selectCoreAnalyticsConsent,
selectTouAndPpConsent
} from 'store/settings/securityPrivacy'

export type AppHook = {
onExit: () => Observable<ExitEvents>
Expand All @@ -33,8 +37,9 @@ export function useApp(
const selectedCurrency = useSelector(selectSelectedCurrency)
const [navigationContainerSet, setNavigationContainerSet] = useState(false)
const [initRouteSet, setInitRouteSet] = useState(false)
const { getSetting } = repository.userSettingsRepo
const { setAnalyticsConsent } = usePosthogContext()
const coreAnalyticsConsentSetting = useSelector(selectCoreAnalyticsConsent)
const touAndPpConsentSetting = useSelector(selectTouAndPpConsent)

const deleteWallet = useCallback(() => {
walletSetupHook.destroyWallet()
Expand All @@ -49,19 +54,22 @@ export function useApp(
}, [appNavHook, deleteWallet])

useEffect(waitForNavigationContainer, [appNavHook.navigation])
useEffect(watchCoreAnalyticsFlagFx, [getSetting, setAnalyticsConsent])
useEffect(watchCoreAnalyticsFlagFx, [
coreAnalyticsConsentSetting,
setAnalyticsConsent
])
useEffect(decideInitialRoute, [
appNavHook,
dispatch,
initRouteSet,
navigationContainerSet,
repository,
signOut
signOut,
touAndPpConsentSetting
])

function watchCoreAnalyticsFlagFx() {
const setting = getSetting('CoreAnalytics') as boolean | undefined
setAnalyticsConsent(setting)
setAnalyticsConsent(coreAnalyticsConsentSetting)
}

function waitForNavigationContainer() {
Expand All @@ -83,7 +91,7 @@ export function useApp(
setInitRouteSet(true)
AsyncStorage.getItem(SECURE_ACCESS_SET).then(result => {
if (result) {
if (!repository.userSettingsRepo.getSetting('ConsentToTOU&PP')) {
if (!touAndPpConsentSetting) {
//User has probably killed app before consent to TOU, so we'll clear all data and
//return him to onboarding
signOut()
Expand Down
41 changes: 1 addition & 40 deletions app/Repo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from 'react'
import { useEffect, useState } from 'react'
import StorageTools from 'repository/StorageTools'

/**
Expand All @@ -7,7 +7,6 @@ import StorageTools from 'repository/StorageTools'
*
* Suffix "_<increasing number>" is for destructive migration of database. In the future, we want gracefully migrate data with no data loss.
*/
const USER_SETTINGS = 'USER_SETTINGS'
const VIEW_ONCE_INFORMATION = 'VIEW_ONCE_INFORMATION'

/**
Expand Down Expand Up @@ -40,7 +39,6 @@ export type RecentContact = {
type: AddrBookItemType
}

export type Setting = 'CoreAnalytics' | 'ConsentToTOU&PP'
export type SettingValue = number | string | boolean | undefined

export type AddrBookItemType = 'account' | 'contact'
Expand All @@ -51,23 +49,13 @@ export type Repo = {
infoHasBeenShown: (info: ViewOnceInformation) => boolean
saveViewOnceInformation: (info: ViewOnceInformation[]) => void
}
/**
* Store any simple user settings here
*/
userSettingsRepo: {
setSetting: (setting: Setting, value: SettingValue) => void
getSetting: (setting: Setting) => SettingValue | undefined
}
flush: () => void
initialized: boolean
}

export function useRepo(): Repo {
const [initialized, setInitialized] = useState(false)
const [viewOnceInfo, setViewOnceInfo] = useState<ViewOnceInformation[]>([])
const [userSettings, setUserSettings] = useState<Map<Setting, SettingValue>>(
new Map()
)

useEffect(() => {
;(async () => {
Expand All @@ -76,22 +64,6 @@ export function useRepo(): Repo {
})()
}, [])

const setSetting = (setting: Setting, value: SettingValue) => {
const updatedSettings = new Map(userSettings)
updatedSettings.set(setting, value)
setUserSettings(updatedSettings)
StorageTools.saveMapToStorage(USER_SETTINGS, updatedSettings).catch(
reason => console.error(reason)
)
}

const getSetting = useCallback(
(setting: Setting) => {
return userSettings.get(setting)
},
[userSettings]
)

const saveViewOnceInformation = (info: ViewOnceInformation[]) => {
// we use set so we don't allow duplicates
const infoSet = [...new Set(info)]
Expand All @@ -109,17 +81,10 @@ export function useRepo(): Repo {
* Clear hook states
*/
const flush = () => {
setUserSettings(new Map())
setInitialized(false)
}

async function loadInitialStatesFromStorage() {
setUserSettings(
await StorageTools.loadFromStorageAsMap<Setting, SettingValue>(
USER_SETTINGS
)
)

const initialViewOnceInfoFromStorage =
await StorageTools.loadFromStorageAsArray<ViewOnceInformation>(
VIEW_ONCE_INFORMATION
Expand All @@ -129,10 +94,6 @@ export function useRepo(): Repo {
}

return {
userSettingsRepo: {
setSetting,
getSetting
},
informationViewOnceRepo: {
viewOnceInfo: viewOnceInfo,
saveViewOnceInformation,
Expand Down
7 changes: 5 additions & 2 deletions app/components/TermsNConditionsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ import {
useBeforeRemoveListener
} from 'hooks/useBeforeRemoveListener'
import { PRIVACY_POLICY_URL, TERMS_OF_USE_URL } from 'resources/Constants'
import { useDispatch } from 'react-redux'
import { setTouAndPpConsent } from 'store/settings/securityPrivacy'

interface Props {
onNext: () => void
onReject: () => void
}

const TermsNConditionsModal = ({ onNext, onReject }: Props) => {
const { theme, repo } = useApplicationContext()
const { theme } = useApplicationContext()
const [touChecked, setTouChecked] = useState(false)
const [ppChecked, setPpChecked] = useState(false)
const nextBtnEnabled = touChecked && ppChecked
const dispatch = useDispatch()

useBeforeRemoveListener(onReject, [RemoveEvents.GO_BACK], true)

Expand All @@ -32,7 +35,7 @@ const TermsNConditionsModal = ({ onNext, onReject }: Props) => {
// he would be able to enter app without consent to Terms n Conditions.
// To prevent this, we set 'ConsentToTOU&PP' to repo and check that on app startup.
function saveConsentAndProceed() {
repo.userSettingsRepo.setSetting('ConsentToTOU&PP', true)
dispatch(setTouAndPpConsent(true))
onNext()
}

Expand Down
7 changes: 4 additions & 3 deletions app/navigation/onboarding/CreateWalletStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from 'hooks/useBeforeRemoveListener'
import { usePostCapture } from 'hooks/usePosthogCapture'
import OwlLoader from 'components/OwlLoader'
import { setCoreAnalytics } from 'store/settings/securityPrivacy'
import { CreateWalletScreenProps } from '../types'

export type CreateWalletStackParamList = {
Expand Down Expand Up @@ -96,13 +97,13 @@ const CreateWalletScreen = () => {
const createWalletContext = useContext(CreateWalletContext)
const { navigate } = useNavigation<CreateWalletNavigationProp>()
const { capture } = usePostCapture()
const { userSettingsRepo } = useApplicationContext().repo
const dispatch = useDispatch()

useBeforeRemoveListener(
useCallback(() => {
capture('OnboardingCancelled')
userSettingsRepo.setSetting('CoreAnalytics', undefined)
}, [capture, userSettingsRepo]),
dispatch(setCoreAnalytics(undefined))
}, [capture, dispatch]),
[RemoveEvents.GO_BACK]
)

Expand Down
7 changes: 4 additions & 3 deletions app/navigation/onboarding/EnterWithMnemonicStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from 'hooks/useBeforeRemoveListener'
import { usePostCapture } from 'hooks/usePosthogCapture'
import OwlLoader from 'components/OwlLoader'
import { setCoreAnalytics } from 'store/settings/securityPrivacy'
import { EnterWithMnemonicScreenProps } from '../types'

export type EnterWithMnemonicStackParamList = {
Expand Down Expand Up @@ -86,14 +87,14 @@ const LoginWithMnemonicScreen = () => {
const enterWithMnemonicContext = useContext(EnterWithMnemonicContext)
const { navigate, goBack } = useNavigation<LoginNavigationProp>()
const { capture } = usePostCapture()
const { userSettingsRepo } = useApplicationContext().repo
const dispatch = useDispatch()
const { deleteWallet } = useApplicationContext().appHook

useBeforeRemoveListener(
useCallback(() => {
capture('OnboardingCancelled')
userSettingsRepo.setSetting('CoreAnalytics', undefined)
}, [capture, userSettingsRepo]),
dispatch(setCoreAnalytics(undefined))
}, [capture, dispatch]),
[RemoveEvents.GO_BACK]
)

Expand Down
13 changes: 9 additions & 4 deletions app/screens/drawer/security/SecurityPrivacy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import BiometricsSDK from 'utils/BiometricsSDK'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { SECURE_ACCESS_SET } from 'resources/Constants'
import Switch from 'components/Switch'
import { useDispatch, useSelector } from 'react-redux'
import {
selectCoreAnalyticsConsent,
setCoreAnalytics
} from 'store/settings/securityPrivacy'

function SecurityPrivacy({
onChangePin,
Expand All @@ -19,8 +24,8 @@ function SecurityPrivacy({
onShowConnectedDapps: () => void
}) {
const theme = useApplicationContext().theme
const { setSetting, getSetting } =
useApplicationContext().repo.userSettingsRepo
const dispatch = useDispatch()
const coreAnalyticsConsent = useSelector(selectCoreAnalyticsConsent)
const [isBiometricSwitchEnabled, setIsBiometricSwitchEnabled] =
useState(false)
const [isBiometricEnabled, setIsBiometricEnabled] = useState(false)
Expand All @@ -44,7 +49,7 @@ function SecurityPrivacy({
}

const handleAnalyticsSwitchChange = (value: boolean) => {
setSetting('CoreAnalytics', value)
dispatch(setCoreAnalytics(value))
}

return (
Expand Down Expand Up @@ -85,7 +90,7 @@ function SecurityPrivacy({
background={theme.background}
rightComponent={
<Switch
value={getSetting('CoreAnalytics') as boolean}
value={coreAnalyticsConsent}
onValueChange={handleAnalyticsSwitchChange}
/>
}
Expand Down
9 changes: 6 additions & 3 deletions app/screens/onboarding/AnalyticsConsent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import CheckmarkSVG from 'components/svg/CheckmarkSVG'
import { useApplicationContext } from 'contexts/ApplicationContext'
import { PRIVACY_POLICY_URL } from 'resources/Constants'
import { usePostCapture } from 'hooks/usePosthogCapture'
import { useDispatch } from 'react-redux'
import { setCoreAnalytics } from 'store/settings/securityPrivacy'

type Props = {
nextScreen:
Expand All @@ -23,7 +25,8 @@ type Props = {
}

const AnalyticsConsent = ({ onNextScreen, nextScreen }: Props) => {
const { theme, repo } = useApplicationContext()
const dispatch = useDispatch()
const { theme } = useApplicationContext()
const { capture } = usePostCapture()

function openPrivacyPolicy() {
Expand All @@ -32,13 +35,13 @@ const AnalyticsConsent = ({ onNextScreen, nextScreen }: Props) => {

function acceptAnalytics() {
capture('OnboardingAnalyticsAccepted')
repo.userSettingsRepo.setSetting('CoreAnalytics', true)
dispatch(setCoreAnalytics(true))
onNextScreen(nextScreen)
}

function rejectAnalytics() {
capture('OnboardingAnalyticsRejected')
repo.userSettingsRepo.setSetting('CoreAnalytics', false)
dispatch(setCoreAnalytics(false))
onNextScreen(nextScreen)
}

Expand Down
10 changes: 8 additions & 2 deletions app/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { WatchlistBlacklistTransform } from './transforms/WatchlistBlacklistTran
import { WalletConnectBlacklistTransform } from './transforms/WalletConnectBlacklistTransform'
import { AppBlacklistTransform } from './transforms/AppBlacklistTransform'

const VERSION = 5
const VERSION = 6

// list of reducers that don't need to be persisted
// for nested/partial blacklist, please use transform
Expand Down Expand Up @@ -77,7 +77,13 @@ const rootReducer = (state: any, action: AnyAction) => {
// notes: keeping settings and network because watchlist depends on them
state = {
app: state.app,
settings: state.settings,
settings: {
...state.settings,
securityPrivacy: {
...state.settings.securityPrivacy,
consentToTOUnPP: false //don't keep consent to Terms of use and Privacy policy
}
},
network: state.network,
watchlist: state.watchlist
}
Expand Down
21 changes: 21 additions & 0 deletions app/store/migrations.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ChainId } from '@avalabs/chains-sdk'
import StorageTools from 'repository/StorageTools'
import { initialState as watchlistInitialState } from './watchlist'
import { initialState as posthogInitialState } from './posthog'

Expand Down Expand Up @@ -69,5 +70,25 @@ export const migrations = {
active: updatedActive
}
}
},
6: async (state: any) => {
const map = await StorageTools.loadFromStorageAsMap<
'CoreAnalytics' | 'ConsentToTOU&PP',
boolean | undefined
>('USER_SETTINGS')

const coreAnalytics = map.get('CoreAnalytics')
const consentToTOUnPP = Boolean(map.get('ConsentToTOU&PP'))

return {
...state,
settings: {
...state.settings,
securityPrivacy: {
coreAnalytics: coreAnalytics,
consentToTOUnPP
}
}
}
}
}
4 changes: 3 additions & 1 deletion app/store/settings/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { combineReducers } from '@reduxjs/toolkit'
import { currencyReducer as currency } from './currency'
import { advancedReducer as advanced } from './advanced'
import { securityPrivacyReducer as securityPrivacy } from './securityPrivacy'

export default combineReducers({
currency,
advanced
advanced,
securityPrivacy
})
2 changes: 2 additions & 0 deletions app/store/settings/securityPrivacy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './slice'
export * from './types'
Loading

0 comments on commit 0cc0085

Please sign in to comment.