Skip to content

Commit

Permalink
fix(keylessBackup): add homecard for keyless backup (#5041)
Browse files Browse the repository at this point in the history
### Description


![Screenshot_20240305_112356](https://github.com/valora-inc/wallet/assets/8432644/6fde89e1-197a-46e3-92a1-a515d560f929)


### Test plan

Updated unit tests
  • Loading branch information
jh2oman committed Mar 5, 2024
1 parent 3962849 commit e8b7017
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 29 deletions.
2 changes: 2 additions & 0 deletions locales/base/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@
"completeEducation": "I Understand",
"yourAccountKey": "Your Recovery Phrase",
"backupKeyNotification2": "Keep your funds safe. Back up your Recovery Phrase now.",
"keylessBackupCTA": "Back up now",
"keylessBackupNotification": "Set up your email & phone number to back up your seed phrase",
"backupKeyCTA": "Finish Backup Now",
"backupKeySummary": "Find a private place and write down your Recovery Phrase. Please store it somewhere safe. Do not save it in your phone.",
"backupKeyWarning": "If you lose your recovery phrase, you will lose access to all funds held in Valora.",
Expand Down
58 changes: 56 additions & 2 deletions src/home/NotificationBox.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { fireEvent, render } from '@testing-library/react-native'
import { act, fireEvent, render } from '@testing-library/react-native'
import * as React from 'react'
import { Provider } from 'react-redux'
import { openUrl } from 'src/app/actions'
import { fetchAvailableRewards } from 'src/consumerIncentives/slice'
import { ONE_CUSD_REWARD_RESPONSE } from 'src/consumerIncentives/testValues'
import NotificationBox from 'src/home/NotificationBox'
import { navigate } from 'src/navigator/NavigationService'
import { ensurePincode, navigate } from 'src/navigator/NavigationService'
import { Screens } from 'src/navigator/Screens'
import { getFeatureGate } from 'src/statsig'
import { NetworkId } from 'src/transactions/types'
import { createMockStore } from 'test/utils'
import {
Expand All @@ -20,6 +21,9 @@ import {
const TWO_DAYS_MS = 2 * 24 * 60 * 1000
const BACKUP_TIME = new Date().getTime() - TWO_DAYS_MS

const mockedEnsurePincode = jest.mocked(ensurePincode)
jest.mock('src/statsig')

jest.mock('src/web3/networkConfig', () => {
const originalModule = jest.requireActual('src/web3/networkConfig')
return {
Expand Down Expand Up @@ -126,6 +130,10 @@ const mockcUsdWithoutEnoughBalance = {
}

describe('NotificationBox', () => {
beforeEach(() => {
jest.clearAllMocks()
jest.mocked(getFeatureGate).mockReturnValue(false)
})
it('renders correctly for with all notifications', () => {
const store = createMockStore({
...storeDataNotificationsEnabled,
Expand Down Expand Up @@ -320,6 +328,52 @@ describe('NotificationBox', () => {
])
})

it('renders keylessBackup notification when flag is turned on', async () => {
const store = createMockStore({
account: {
backupCompleted: false,
},
})
jest.mocked(getFeatureGate).mockReturnValue(true)
mockedEnsurePincode.mockImplementation(() => Promise.resolve(true))
const { queryByTestId, getByTestId } = render(
<Provider store={store}>
<NotificationBox showOnlyHomeScreenNotifications={false} />
</Provider>
)

expect(queryByTestId('NotificationView/keyless_backup_prompt')).toBeTruthy()

await act(() => {
fireEvent.press(
getByTestId('KeylessBackupNotification/CallToActions/keylessBackupCTA/Button')
)
})
expect(navigate).toHaveBeenCalledWith(Screens.WalletSecurityPrimer)
})

it('renders seed phrase backup notification when keyless backup flag is turned off', async () => {
const store = createMockStore({
account: {
backupCompleted: false,
},
})
jest.mocked(getFeatureGate).mockReturnValue(false)
mockedEnsurePincode.mockImplementation(() => Promise.resolve(true))
const { queryByTestId, getByTestId } = render(
<Provider store={store}>
<NotificationBox showOnlyHomeScreenNotifications={false} />
</Provider>
)

expect(queryByTestId('NotificationView/backup_prompt')).toBeTruthy()

await act(() => {
fireEvent.press(getByTestId('BackupKeyNotification/CallToActions/backupKeyCTA/Button'))
})
expect(navigate).toHaveBeenCalledWith(Screens.BackupIntroduction)
})

it('renders claim rewards notification when there are supercharge rewards', () => {
const store = createMockStore(superchargeSetUp)
const { queryByTestId, getByTestId } = render(
Expand Down
89 changes: 62 additions & 27 deletions src/home/NotificationBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ export function useSimpleActions() {
StatsigFeatureGates.RESTRICT_SUPERCHARGE_FOR_CLAIM_ONLY
)

const showKeylessBackup = getFeatureGate(StatsigFeatureGates.SHOW_CLOUD_ACCOUNT_BACKUP_SETUP)

useEffect(() => {
dispatch(fetchAvailableRewards())
}, [])
Expand All @@ -99,36 +101,69 @@ export function useSimpleActions() {

const actions: SimpleAction[] = []
if (!backupCompleted) {
actions.push({
id: NotificationType.backup_prompt,
type: NotificationType.backup_prompt,
text: t('backupKeyNotification2'),
icon: <GuideKeyIcon />,
priority: BACKUP_PRIORITY,
testID: 'BackupKeyNotification',
callToActions: [
{
text: t('backupKeyCTA'),
onPress: (params) => {
ValoraAnalytics.track(HomeEvents.notification_select, {
notificationType: NotificationType.backup_prompt,
selectedAction: NotificationBannerCTATypes.accept,
notificationId: NotificationType.backup_prompt,
notificationPositionInList: params?.index,
})
ensurePincode()
.then((pinIsCorrect) => {
if (pinIsCorrect) {
navigate(Screens.BackupIntroduction)
}
if (showKeylessBackup) {
actions.push({
id: NotificationType.keyless_backup_prompt,
type: NotificationType.keyless_backup_prompt,
text: t('keylessBackupNotification'),
icon: <GuideKeyIcon />,
priority: BACKUP_PRIORITY,
testID: 'KeylessBackupNotification',
callToActions: [
{
text: t('keylessBackupCTA'),
onPress: (params) => {
ValoraAnalytics.track(HomeEvents.notification_select, {
notificationType: NotificationType.keyless_backup_prompt,
selectedAction: NotificationBannerCTATypes.accept,
notificationId: NotificationType.keyless_backup_prompt,
notificationPositionInList: params?.index,
})
.catch((error) => {
Logger.error(`${TAG}@backupNotification`, 'PIN ensure error', error)
ensurePincode()
.then((pinIsCorrect) => {
if (pinIsCorrect) {
navigate(Screens.WalletSecurityPrimer)
}
})
.catch((error) => {
Logger.error(`${TAG}@keylessBackupNotification`, 'PIN ensure error', error)
})
},
},
],
})
} else {
actions.push({
id: NotificationType.backup_prompt,
type: NotificationType.backup_prompt,
text: t('backupKeyNotification2'),
icon: <GuideKeyIcon />,
priority: BACKUP_PRIORITY,
testID: 'BackupKeyNotification',
callToActions: [
{
text: t('backupKeyCTA'),
onPress: (params) => {
ValoraAnalytics.track(HomeEvents.notification_select, {
notificationType: NotificationType.backup_prompt,
selectedAction: NotificationBannerCTATypes.accept,
notificationId: NotificationType.backup_prompt,
notificationPositionInList: params?.index,
})
ensurePincode()
.then((pinIsCorrect) => {
if (pinIsCorrect) {
navigate(Screens.BackupIntroduction)
}
})
.catch((error) => {
Logger.error(`${TAG}@backupNotification`, 'PIN ensure error', error)
})
},
},
},
],
})
],
})
}
}

if (numberVerifiedDecentrally && !phoneNumberVerified) {
Expand Down
1 change: 1 addition & 0 deletions src/home/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export enum NotificationType {
invite_prompt = 'invite_prompt',
verification_prompt = 'verification_prompt',
backup_prompt = 'backup_prompt',
keyless_backup_prompt = 'keyless_backup_prompt',
supercharge_available = 'supercharge_available',
remote_notification = 'remote_notification',
supercharging = 'supercharging',
Expand Down

0 comments on commit e8b7017

Please sign in to comment.