diff --git a/src/components/backup/AddWalletToCloudBackupStep.tsx b/src/components/backup/AddWalletToCloudBackupStep.tsx index 4341770c35e..62f92a99e2f 100644 --- a/src/components/backup/AddWalletToCloudBackupStep.tsx +++ b/src/components/backup/AddWalletToCloudBackupStep.tsx @@ -6,6 +6,7 @@ import WalletsAndBackupIcon from '@/assets/WalletsAndBackup.png'; import { Source } from 'react-native-fast-image'; import { cloudPlatform } from '@/utils/platform'; import { ButtonPressAnimation } from '../animations'; +import Routes from '@/navigation/routesNames'; import { useNavigation } from '@/navigation'; import { useWallets } from '@/hooks'; import { WalletCountPerType, useVisibleWallets } from '@/screens/SettingsSheet/useVisibleWallets'; @@ -28,11 +29,17 @@ export default function AddWalletToCloudBackupStep() { const { onSubmit } = useCreateBackup({ walletId: selectedWallet.id, + navigateToRoute: { + route: Routes.SETTINGS_SHEET, + params: { + screen: Routes.SETTINGS_SECTION_BACKUP, + }, + }, }); const potentiallyLoginAndSubmit = useCallback(async () => { await login(); - return onSubmit(); + return onSubmit({}); }, [onSubmit]); const onMaybeLater = useCallback(() => goBack(), [goBack]); diff --git a/src/components/backup/BackupChooseProviderStep.tsx b/src/components/backup/BackupChooseProviderStep.tsx index bd232ed22ca..da9520335df 100644 --- a/src/components/backup/BackupChooseProviderStep.tsx +++ b/src/components/backup/BackupChooseProviderStep.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { useCreateBackup } from '@/components/backup/useCreateBackup'; import { Bleed, Box, Inline, Inset, Separator, Stack, Text } from '@/design-system'; import * as lang from '@/languages'; import { ImgixImage } from '../images'; @@ -11,11 +12,15 @@ import { useTheme } from '@/theme'; import { ButtonPressAnimation } from '../animations'; import { useNavigation } from '@/navigation'; import Routes from '@/navigation/routesNames'; -import walletBackupStepTypes from '@/helpers/walletBackupStepTypes'; import { SETTINGS_BACKUP_ROUTES } from '@/screens/SettingsSheet/components/Backups/routes'; import { useWallets } from '@/hooks'; import walletTypes from '@/helpers/walletTypes'; import walletBackupTypes from '@/helpers/walletBackupTypes'; +import { IS_ANDROID } from '@/env'; +import { GoogleDriveUserData, getGoogleAccountUserData, isCloudBackupAvailable, login } from '@/handlers/cloudBackup'; +import { WrappedAlert as Alert } from '@/helpers/alert'; +import { RainbowError, logger } from '@/logger'; +import { Linking } from 'react-native'; const imageSize = 72; @@ -24,11 +29,59 @@ export default function BackupSheetSectionNoProvider() { const { navigate, goBack } = useNavigation(); const { selectedWallet } = useWallets(); + const { onSubmit, loading } = useCreateBackup({ + walletId: selectedWallet.id, + navigateToRoute: { + route: Routes.SETTINGS_SHEET, + params: { + screen: Routes.SETTINGS_SECTION_BACKUP, + }, + }, + }); + const onCloudBackup = async () => { - navigate(Routes.BACKUP_SHEET, { - step: walletBackupStepTypes.backup_cloud, - isSettingsRoute: true, - }); + if (loading !== 'none') { + return; + } + // NOTE: On Android we need to make sure the user is signed into a Google account before trying to backup + // otherwise we'll fake backup and it's confusing... + if (IS_ANDROID) { + try { + await login(); + getGoogleAccountUserData().then((accountDetails: GoogleDriveUserData | undefined) => { + if (!accountDetails) { + Alert.alert(lang.t(lang.l.back_up.errors.no_account_found)); + return; + } + }); + } catch (e) { + Alert.alert(lang.t(lang.l.back_up.errors.no_account_found)); + logger.error(e as RainbowError); + } + } else { + const isAvailable = await isCloudBackupAvailable(); + if (!isAvailable) { + Alert.alert( + lang.t(lang.l.modal.back_up.alerts.cloud_not_enabled.label), + lang.t(lang.l.modal.back_up.alerts.cloud_not_enabled.description), + [ + { + onPress: () => { + Linking.openURL('https://support.apple.com/en-us/HT204025'); + }, + text: lang.t(lang.l.modal.back_up.alerts.cloud_not_enabled.show_me), + }, + { + style: 'cancel', + text: lang.t(lang.l.modal.back_up.alerts.cloud_not_enabled.no_thanks), + }, + ] + ); + return; + } + } + + onSubmit({}); }; const onManualBackup = async () => { @@ -59,6 +112,7 @@ export default function BackupSheetSectionNoProvider() { + {/* replace this with BackUpMenuButton */} diff --git a/src/components/backup/BackupCloudStep.tsx b/src/components/backup/BackupCloudStep.tsx index 1ed16e47832..b40e5a7622b 100644 --- a/src/components/backup/BackupCloudStep.tsx +++ b/src/components/backup/BackupCloudStep.tsx @@ -11,7 +11,7 @@ import { Text } from '@/components/text'; import WalletAndBackup from '@/assets/WalletsAndBackup.png'; import { analytics } from '@/analytics'; import { cloudBackupPasswordMinLength, isCloudBackupPasswordValid } from '@/handlers/cloudBackup'; -import { useDimensions, useMagicAutofocus } from '@/hooks'; +import { useDimensions, useMagicAutofocus, useWallets } from '@/hooks'; import styled from '@/styled-thing'; import { padding } from '@/styles'; import { Box, Inset, Stack } from '@/design-system'; @@ -23,9 +23,13 @@ import { usePasswordValidation } from './usePasswordValidation'; import { TextInput } from 'react-native'; import { useTheme } from '@/theme'; import { useNavigation } from '@/navigation'; +import Routes from '@/navigation/routesNames'; +import { SETTINGS_BACKUP_ROUTES } from '@/screens/SettingsSheet/components/Backups/routes'; +import walletTypes from '@/helpers/walletTypes'; type BackupCloudStepParams = { BackupCloudStep: { + isFromWalletReadyPrompt?: boolean; walletId?: string; onSuccess: (password: string) => Promise; onCancel: () => Promise; @@ -46,7 +50,7 @@ export function BackupCloudStep() { const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); - const { onSuccess, onCancel } = params; + const { onSuccess, onCancel, isFromWalletReadyPrompt = false } = params; const { validPassword, label, labelColor } = usePasswordValidation(password, confirmPassword); @@ -90,10 +94,14 @@ export function BackupCloudStep() { const onSuccessAndNavigateBack = useCallback( async (password: string) => { - goBack(); + console.log({ password, isFromWalletReadyPrompt }); + if (!isFromWalletReadyPrompt) { + goBack(); + } + onSuccess(password); }, - [goBack, onSuccess] + [goBack, isFromWalletReadyPrompt, onSuccess] ); useEffect(() => { diff --git a/src/components/backup/BackupSheet.tsx b/src/components/backup/BackupSheet.tsx index 2d8b2f8f6bb..be2bd57ebd8 100644 --- a/src/components/backup/BackupSheet.tsx +++ b/src/components/backup/BackupSheet.tsx @@ -26,11 +26,7 @@ export default function BackupSheet() { const renderStep = useCallback(() => { switch (step) { case WalletBackupStepTypes.backup_now_to_cloud: - return ( - - - - ); + return ; case WalletBackupStepTypes.backup_now_manually: return ; case WalletBackupStepTypes.backup_cloud: @@ -44,17 +40,19 @@ export default function BackupSheet() { }, [step]); return ( - - {({ backgroundColor }) => ( - - {renderStep()} - - )} - + + + {({ backgroundColor }) => ( + + {renderStep()} + + )} + + ); } diff --git a/src/components/backup/useCreateBackup.ts b/src/components/backup/useCreateBackup.ts index b800c4a1b3d..fb1747090c8 100644 --- a/src/components/backup/useCreateBackup.ts +++ b/src/components/backup/useCreateBackup.ts @@ -7,13 +7,17 @@ import { analytics } from '@/analytics'; import { useWalletCloudBackup, useWallets } from '@/hooks'; import Routes from '@/navigation/routesNames'; import walletBackupStepTypes from '@/helpers/walletBackupStepTypes'; -import { Navigation } from '@/navigation'; +import { Navigation, useNavigation } from '@/navigation'; import { InteractionManager } from 'react-native'; import { DelayedAlert } from '../alerts'; import { useDispatch } from 'react-redux'; type UseCreateBackupProps = { walletId?: string; + navigateToRoute?: { + route: string; + params?: any; + }; }; export type useCreateBackupStateType = 'none' | 'loading' | 'success' | 'error'; @@ -23,8 +27,9 @@ export enum BackupTypes { All = 'all', } -export const useCreateBackup = ({ walletId }: UseCreateBackupProps) => { +export const useCreateBackup = ({ walletId, navigateToRoute }: UseCreateBackupProps) => { const dispatch = useDispatch(); + const { navigate } = useNavigation(); const { fetchBackups } = useCloudBackups(); const walletCloudBackup = useWalletCloudBackup(); @@ -66,7 +71,7 @@ export const useCreateBackup = ({ walletId }: UseCreateBackupProps) => { ); const onConfirmBackup = useCallback( - async (password: string, type: BackupTypes) => { + async ({ password, type }: { password: string; type: BackupTypes }) => { analytics.track('Tapped "Confirm Backup"'); setLoading('loading'); @@ -99,8 +104,12 @@ export const useCreateBackup = ({ walletId }: UseCreateBackupProps) => { password, walletId, }); + + if (navigateToRoute) { + navigate(navigateToRoute.route, navigateToRoute.params || {}); + } }, - [walletId, walletCloudBackup, onError, onSuccess, wallets, latestBackup, dispatch] + [walletId, walletCloudBackup, onError, onSuccess, navigateToRoute, wallets, latestBackup, dispatch, navigate] ); const getPassword = useCallback(async (): Promise => { @@ -128,10 +137,13 @@ export const useCreateBackup = ({ walletId }: UseCreateBackupProps) => { }, [walletId]); const onSubmit = useCallback( - async (type = BackupTypes.Single) => { + async ({ type = BackupTypes.Single }: { type?: BackupTypes }) => { const password = await getPassword(); if (password) { - onConfirmBackup(password, type); + onConfirmBackup({ + password, + type, + }); return true; } setLoadingStateWithTimeout('error'); diff --git a/src/hooks/useWalletCloudBackup.ts b/src/hooks/useWalletCloudBackup.ts index 76b52aa3703..c0c76e6e0cb 100644 --- a/src/hooks/useWalletCloudBackup.ts +++ b/src/hooks/useWalletCloudBackup.ts @@ -55,7 +55,7 @@ export default function useWalletCloudBackup() { onSuccess?: () => void; password: string; walletId: string; - }) => { + }): Promise => { const isAvailable = await isCloudBackupAvailable(); if (!isAvailable) { analytics.track('iCloud not enabled', { @@ -81,7 +81,7 @@ export default function useWalletCloudBackup() { text: lang.t('modal.back_up.alerts.cloud_not_enabled.no_thanks'), }, ]); - return; + return false; } // For Android devices without biometrics enabled, we need to ask for PIN @@ -92,7 +92,7 @@ export default function useWalletCloudBackup() { userPIN = (await authenticateWithPIN()) ?? undefined; } catch (e) { onError?.(i18n.t(i18n.l.back_up.wrong_pin)); - return; + return false; } } @@ -127,7 +127,7 @@ export default function useWalletCloudBackup() { error: userError, label: cloudPlatform, }); - return null; + return false; } try { @@ -135,6 +135,7 @@ export default function useWalletCloudBackup() { await dispatch(setWalletBackedUp(walletId, WalletBackupTypes.cloud, updatedBackupFile)); logger.log('backup saved everywhere!'); !!onSuccess && onSuccess(); + return true; } catch (e) { logger.sentry('error while trying to save wallet backup state'); captureException(e); @@ -145,6 +146,8 @@ export default function useWalletCloudBackup() { label: cloudPlatform, }); } + + return false; }, [dispatch, latestBackup, wallets] ); diff --git a/src/navigation/routesNames.ts b/src/navigation/routesNames.ts index 31f9d9c8e71..0b4424c4f4b 100644 --- a/src/navigation/routesNames.ts +++ b/src/navigation/routesNames.ts @@ -98,7 +98,7 @@ const Routes = { SETTINGS_SECTION: 'SettingsSection', SETTINGS_WALLET_NOTIFICATIONS: 'WalletNotificationsSettings', - SETTINGS_BACKUP_VIEW: 'WiewWalletBackup', + SETTINGS_BACKUP_VIEW: 'ViewWalletBackup', SETTINGS_SECTION_APP_ICON: 'AppIconSection', SETTINGS_SECTION_BACKUP: 'BackupSection', SETTINGS_SECTION_CURRENCY: 'CurrencySection', diff --git a/src/screens/AddWalletSheet.tsx b/src/screens/AddWalletSheet.tsx index 7e6a75a914c..dbad7feed37 100644 --- a/src/screens/AddWalletSheet.tsx +++ b/src/screens/AddWalletSheet.tsx @@ -7,7 +7,7 @@ import React, { useRef } from 'react'; import * as i18n from '@/languages'; import { HARDWARE_WALLETS, PROFILES, useExperimentalFlag } from '@/config'; import { analytics, analyticsV2 } from '@/analytics'; -import { InteractionManager } from 'react-native'; +import { InteractionManager, Linking } from 'react-native'; import { createAccountForWallet, walletsLoadState } from '@/redux/wallets'; import WalletBackupTypes from '@/helpers/walletBackupTypes'; import { createWallet } from '@/model/wallet'; @@ -24,6 +24,7 @@ import { backupUserDataIntoCloud, getGoogleAccountUserData, GoogleDriveUserData, + isCloudBackupAvailable, login, logoutFromGoogleDrive, } from '@/handlers/cloudBackup'; @@ -215,11 +216,28 @@ export const AddWalletSheet = () => { logger.error(e as RainbowError); } } else { - try { - navigate(Routes.RESTORE_SHEET); - } catch (e) { - logger.error(e as RainbowError); + const isAvailable = await isCloudBackupAvailable(); + if (!isAvailable) { + Alert.alert( + i18n.t(i18n.l.modal.back_up.alerts.cloud_not_enabled.label), + i18n.t(i18n.l.modal.back_up.alerts.cloud_not_enabled.description), + [ + { + onPress: () => { + Linking.openURL('https://support.apple.com/en-us/HT204025'); + }, + text: i18n.t(i18n.l.modal.back_up.alerts.cloud_not_enabled.show_me), + }, + { + style: 'cancel', + text: i18n.t(i18n.l.modal.back_up.alerts.cloud_not_enabled.no_thanks), + }, + ] + ); + return; } + + navigate(Routes.RESTORE_SHEET); } }; diff --git a/src/screens/SettingsSheet/components/Backups/ViewWalletBackup.tsx b/src/screens/SettingsSheet/components/Backups/ViewWalletBackup.tsx index 53206f43e7c..a4cb1b300ee 100644 --- a/src/screens/SettingsSheet/components/Backups/ViewWalletBackup.tsx +++ b/src/screens/SettingsSheet/components/Backups/ViewWalletBackup.tsx @@ -395,7 +395,7 @@ const ViewWalletBackup = () => { cloudPlatformName: cloudPlatform, })} loading={loading} - onPress={onSubmit} + onPress={() => onSubmit({})} /> )} @@ -415,7 +415,7 @@ const ViewWalletBackup = () => { cloudPlatformName: cloudPlatform, })} loading={loading} - onPress={onSubmit} + onPress={() => onSubmit({})} /> )} diff --git a/src/screens/SettingsSheet/components/Backups/WalletsAndBackup.tsx b/src/screens/SettingsSheet/components/Backups/WalletsAndBackup.tsx index c48147107e8..e8df33515f4 100644 --- a/src/screens/SettingsSheet/components/Backups/WalletsAndBackup.tsx +++ b/src/screens/SettingsSheet/components/Backups/WalletsAndBackup.tsx @@ -167,7 +167,7 @@ export const WalletsAndBackup = () => { await login(); } - onSubmit(BackupTypes.All); + onSubmit({ type: BackupTypes.All }); }, [onSubmit]); const onViewCloudBackups = useCallback(async () => {