diff --git a/native/account/registration/auth-navigator.react.js b/native/account/registration/auth-navigator.react.js --- a/native/account/registration/auth-navigator.react.js +++ b/native/account/registration/auth-navigator.react.js @@ -57,9 +57,11 @@ RestorePromptScreenRouteName, RestorePasswordAccountScreenRouteName, RestoreBackupScreenRouteName, + RestoreBackupErrorScreenRouteName, RestoreSIWEBackupRouteName, } from '../../navigation/route-names.js'; import QRCodeScreen from '../qr-code-screen.react.js'; +import RestoreBackupErrorScreen from '../restore-backup-error-screen.react.js'; import RestoreBackupScreen from '../restore-backup-screen.react.js'; import RestorePasswordAccountScreen from '../restore-password-account-screen.react.js'; import RestorePromptScreen from '../restore-prompt-screen.react.js'; @@ -223,6 +225,11 @@ component={RestoreBackupScreen} options={disableGesturesScreenOptions} /> + , + +route: NavigationRoute<'RestoreBackupErrorScreen'>, +}; + +export type RestoreBackupErrorScreenParams = { + +deviceType: 'primary' | 'secondary', + +errorDetails?: ?string, +}; + +function RestoreBackupErrorScreen(props: Props): React.Node { + const styles = useStyles(unboundStyles); + const { deviceType, errorDetails: errorDetailsProp } = props.route.params; + + const storedError = useSelector(state => + state.restoreBackupState.status === 'user_data_restore_failed' + ? state.restoreBackupState.payload.error + : null, + ); + const errorDetails = React.useMemo(() => { + if (errorDetailsProp) { + return errorDetailsProp; + } else if (storedError) { + const messageForException = getMessageForException(storedError); + return messageForException ?? 'unknown_error'; + } + + console.warn('Restore error screen shown but no error details provided'); + return 'unknown_error'; + }, [errorDetailsProp, storedError]); + + const dispatch = useDispatch(); + + const ignoreErrorAndLogIn = React.useCallback(() => { + dispatch({ + type: markBackupAsRestoredActionType, + }); + }, [dispatch]); + + const onPressIgnore = React.useCallback(() => { + Alert.alert( + 'Continue without full restoration?', + 'Some of your data could not be restored from backup. You can still use the app, but recent messages and settings may be missing.', + [ + { text: 'Cancel', style: 'cancel' }, + { + text: 'Continue', + onPress: ignoreErrorAndLogIn, + style: 'destructive', + }, + ], + { cancelable: true }, + ); + }, [ignoreErrorAndLogIn]); + + const onPressTryAgain = React.useCallback(() => { + dispatch({ + type: resetBackupRestoreStateActionType, + }); + + props.navigation.popToTop(); + }, [props.navigation, dispatch]); + + let deviceTypeWarning; + if (deviceType === 'secondary') { + deviceTypeWarning = ( + + Your backup appears to be corrupt. Be careful with your primary device, + as you may lose data if you log out of it at this time. + + ); + } else { + deviceTypeWarning = ( + + Failed to restore your data from backup. + + ); + } + + return ( + + + Restoration failed + {deviceTypeWarning} + + Error message: + + {errorDetails} Long long long long long long long long long long + long long text + + + + For help recovering your data, email support@comm.app or message + Ashoat on the app. + + + + + + + + ); +} + +const unboundStyles = { + header: { + fontSize: 24, + color: 'panelForegroundLabel', + paddingBottom: 16, + }, + section: { + fontFamily: 'Arial', + fontSize: 15, + lineHeight: 20, + color: 'panelForegroundSecondaryLabel', + paddingBottom: 16, + }, + errorDetailsContainer: { + backgroundColor: 'codeBackground', + padding: 12, + marginBottom: 16, + borderRadius: 8, + }, + errorDetailsHeader: { + fontFamily: 'Arial', + fontSize: 14, + fontWeight: 'bold', + color: 'panelForegroundLabel', + marginBottom: 8, + }, + errorDetails: { + fontFamily: 'Menlo', + fontSize: 12, + color: 'panelForegroundSecondaryLabel', + lineHeight: 16, + }, + scrollViewContentContainer: { + flexGrow: 1, + }, +}; + +export default RestoreBackupErrorScreen; diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js --- a/native/navigation/route-names.js +++ b/native/navigation/route-names.js @@ -3,7 +3,7 @@ import type { RouteProp } from '@react-navigation/core'; import type { ActionResultModalParams } from './action-result-modal.react.js'; -import type { InviteLinkModalParams } from './invite-link-modal.react'; +import type { InviteLinkModalParams } from './invite-link-modal.react.js'; import type { NUXTipsOverlayBackdropParams } from './nux-tip-overlay-backdrop.react.js'; import type { ConnectSecondaryDeviceParams } from '../account/qr-auth/connect-secondary-device.react.js'; import type { AvatarSelectionParams } from '../account/registration/avatar-selection.react.js'; @@ -16,7 +16,8 @@ import type { RegistrationTermsParams } from '../account/registration/registration-terms.react.js'; import type { CreateSIWEBackupMessageParams } from '../account/registration/siwe-backup-message-creation.react.js'; import type { UsernameSelectionParams } from '../account/registration/username-selection.react.js'; -import type { RestoreBackupScreenParams } from '../account/restore-backup-screen.react'; +import type { RestoreBackupErrorScreenParams } from '../account/restore-backup-error-screen.react.js'; +import type { RestoreBackupScreenParams } from '../account/restore-backup-screen.react.js'; import type { TermsAndPrivacyModalParams } from '../account/terms-and-privacy-modal.react.js'; import type { RestoreSIWEBackupParams } from '../backup/restore-siwe-backup.react.js'; import type { ThreadPickerModalParams } from '../calendar/thread-picker-modal.react.js'; @@ -159,6 +160,7 @@ export const RestorePasswordAccountScreenRouteName = 'RestorePasswordAccountScreen'; export const RestoreBackupScreenRouteName = 'RestoreBackupScreen'; +export const RestoreBackupErrorScreenRouteName = 'RestoreBackupErrorScreen'; export const UserProfileBottomSheetNavigatorRouteName = 'UserProfileBottomSheetNavigator'; export const UserProfileBottomSheetRouteName = 'UserProfileBottomSheet'; @@ -337,6 +339,7 @@ +RestorePromptScreen: void, +RestorePasswordAccountScreen: void, +RestoreBackupScreen: RestoreBackupScreenParams, + +RestoreBackupErrorScreen: RestoreBackupErrorScreenParams, +RestoreSIWEBackup: RestoreSIWEBackupParams, };