diff --git a/native/account/restore-password-account-screen.react.js b/native/account/restore-password-account-screen.react.js
--- a/native/account/restore-password-account-screen.react.js
+++ b/native/account/restore-password-account-screen.react.js
@@ -3,15 +3,26 @@
import * as React from 'react';
import { Text, TextInput, View } from 'react-native';
+import { usePasswordLogIn } from 'lib/hooks/login-hooks.js';
+import { getMessageForException } from 'lib/utils/errors.js';
+
+import { setNativeCredentials } from './native-credentials.js';
import PromptButton from './prompt-button.react.js';
import RegistrationButtonContainer from './registration/registration-button-container.react.js';
import RegistrationContainer from './registration/registration-container.react.js';
import RegistrationContentContainer from './registration/registration-content-container.react.js';
import RegistrationTextInput from './registration/registration-text-input.react.js';
import type { SignInNavigationProp } from './sign-in-navigator.react.js';
+import { useClientBackup } from '../backup/use-client-backup.js';
import type { NavigationRoute } from '../navigation/route-names.js';
import { RestoreBackupScreenRouteName } from '../navigation/route-names.js';
import { useStyles } from '../themes/colors.js';
+import {
+ appOutOfDateAlertDetails,
+ unknownErrorAlertDetails,
+ userNotFoundAlertDetails,
+} from '../utils/alert-messages.js';
+import Alert from '../utils/alert.js';
type Props = {
+navigation: SignInNavigationProp<'RestorePasswordAccountScreen'>,
@@ -27,9 +38,36 @@
passwordInputRef.current?.focus();
}, []);
+ const usernameInputRef = React.useRef>();
+ const focusUsernameInput = React.useCallback(() => {
+ usernameInputRef.current?.focus();
+ }, []);
+
+ const onUnsuccessfulLoginAlertAcknowledged = React.useCallback(() => {
+ setUsername('');
+ setPassword('');
+ focusUsernameInput();
+ }, [focusUsernameInput]);
+
+ const identityPasswordLogIn = usePasswordLogIn();
+ const { retrieveLatestBackupInfo } = useClientBackup();
const areCredentialsPresent = !!username && !!password;
- const onProceed = React.useCallback(() => {
- if (areCredentialsPresent) {
+ const [isProcessing, setIsProcessing] = React.useState(false);
+ const onProceed = React.useCallback(async () => {
+ if (!areCredentialsPresent) {
+ return;
+ }
+ setIsProcessing(true);
+ try {
+ const latestBackupInfo = await retrieveLatestBackupInfo(username);
+ if (!latestBackupInfo) {
+ await identityPasswordLogIn(username, password);
+ await setNativeCredentials({
+ username,
+ password,
+ });
+ return;
+ }
props.navigation.navigate(RestoreBackupScreenRouteName, {
userIdentifier: username,
credentials: {
@@ -37,8 +75,46 @@
password,
},
});
+ } catch (e) {
+ const messageForException = getMessageForException(e);
+ let alertMessage = unknownErrorAlertDetails;
+ let onPress = null;
+ if (
+ messageForException === 'user_not_found' ||
+ messageForException === 'login_failed'
+ ) {
+ alertMessage = userNotFoundAlertDetails;
+ onPress = onUnsuccessfulLoginAlertAcknowledged;
+ } else if (
+ messageForException === 'unsupported_version' ||
+ messageForException === 'client_version_unsupported' ||
+ messageForException === 'use_new_flow'
+ ) {
+ alertMessage = appOutOfDateAlertDetails;
+ }
+ Alert.alert(
+ alertMessage.title,
+ alertMessage.message,
+ [{ text: 'OK', onPress }],
+ { cancelable: false },
+ );
+ } finally {
+ setIsProcessing(false);
}
- }, [areCredentialsPresent, password, props.navigation, username]);
+ }, [
+ areCredentialsPresent,
+ identityPasswordLogIn,
+ onUnsuccessfulLoginAlertAcknowledged,
+ password,
+ props.navigation,
+ retrieveLatestBackupInfo,
+ username,
+ ]);
+
+ let restoreButtonVariant = 'loading';
+ if (!isProcessing) {
+ restoreButtonVariant = areCredentialsPresent ? 'enabled' : 'disabled';
+ }
const styles = useStyles(unboundStyles);
return (
@@ -57,6 +133,7 @@
autoComplete="username"
returnKeyType="next"
onSubmitEditing={focusPasswordInput}
+ ref={usernameInputRef}
/>
diff --git a/native/account/restore-prompt-screen.react.js b/native/account/restore-prompt-screen.react.js
--- a/native/account/restore-prompt-screen.react.js
+++ b/native/account/restore-prompt-screen.react.js
@@ -3,6 +3,7 @@
import * as React from 'react';
import { Text, View } from 'react-native';
+import { useWalletLogIn } from 'lib/hooks/login-hooks.js';
import type { SIWEResult } from 'lib/types/siwe-types.js';
import { getMessageForException } from 'lib/utils/errors.js';
@@ -20,7 +21,10 @@
RestorePasswordAccountScreenRouteName,
} from '../navigation/route-names.js';
import { useColors, useStyles } from '../themes/colors.js';
-import { unknownErrorAlertDetails } from '../utils/alert-messages.js';
+import {
+ appOutOfDateAlertDetails,
+ unknownErrorAlertDetails,
+} from '../utils/alert-messages.js';
import Alert from '../utils/alert.js';
import RestoreIcon from '../vectors/restore-icon.react.js';
@@ -40,12 +44,19 @@
props.navigation.navigate(RestorePasswordAccountScreenRouteName);
}, [props.navigation]);
+ const [authInProgress, setAuthInProgress] = React.useState(false);
const { retrieveLatestBackupInfo } = useClientBackup();
+ const walletLogIn = useWalletLogIn();
const onSIWESuccess = React.useCallback(
async (result: SIWEResult) => {
try {
+ setAuthInProgress(true);
const { address, signature, message } = result;
const backupInfo = await retrieveLatestBackupInfo(address);
+ if (!backupInfo) {
+ await walletLogIn(result.address, result.message, result.signature);
+ return;
+ }
const { siweBackupData } = backupInfo;
if (!siweBackupData) {
@@ -71,16 +82,30 @@
console.log(
`SIWE restore error: ${messageForException ?? 'unknown error'}`,
);
- const alertDetails = unknownErrorAlertDetails;
+ let alertDetails = unknownErrorAlertDetails;
+ if (
+ messageForException === 'unsupported_version' ||
+ messageForException === 'client_version_unsupported' ||
+ messageForException === 'use_new_flow'
+ ) {
+ alertDetails = appOutOfDateAlertDetails;
+ } else if (messageForException === 'nonce_expired') {
+ alertDetails = {
+ title: 'Login attempt timed out',
+ message: 'Please try again',
+ };
+ }
Alert.alert(
alertDetails.title,
alertDetails.message,
[{ text: 'OK', onPress: props.navigation.goBack }],
{ cancelable: false },
);
+ } finally {
+ setAuthInProgress(false);
}
},
- [props.navigation, retrieveLatestBackupInfo],
+ [props.navigation, retrieveLatestBackupInfo, walletLogIn],
);
const {
@@ -104,6 +129,12 @@
);
}
+ const openSIWEPanel = React.useCallback(() => {
+ if (!authInProgress) {
+ openPanel();
+ }
+ }, [authInProgress, openPanel]);
+
const colors = useColors();
return (
<>
@@ -130,8 +161,10 @@