From b49b5358fd1db32be3e1c4da2e085ac4b6ba6894 Mon Sep 17 00:00:00 2001 From: Cal Leung Date: Fri, 3 Dec 2021 17:06:06 -0800 Subject: [PATCH] Bug/3464 fix login bug (#3467) * Fix switch navigator replacement logic * Update unit tests * Fix unit tests. Commit changes from yarn setup * Fix login bug. Temporarily control splash animation. * Fix login bug Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com> Co-authored-by: Curtis --- app/actions/user/index.js | 6 ++ app/components/Nav/App/index.js | 97 ++++++++++++------- app/components/UI/DrawerView/index.js | 1 + app/components/UI/MetaMaskAnimation/index.tsx | 2 +- app/components/Views/LockScreen/index.js | 1 + app/components/Views/Login/index.js | 17 +++- app/components/Views/Onboarding/index.js | 1 + app/reducers/user/index.js | 6 ++ app/store/index.js | 12 ++- 9 files changed, 101 insertions(+), 42 deletions(-) diff --git a/app/actions/user/index.js b/app/actions/user/index.js index 737dd76e71a..95c7cc29afc 100644 --- a/app/actions/user/index.js +++ b/app/actions/user/index.js @@ -76,3 +76,9 @@ export function logOut() { type: 'LOGOUT', }; } + +export function checkedAuth() { + return { + type: 'CHECKED_AUTH', + }; +} diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index ea450ce7213..c271c6da1b4 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { NavigationContainer, CommonActions } from '@react-navigation/native'; -import { Animated } from 'react-native'; +import { Animated, StyleSheet, View } from 'react-native'; import { createStackNavigator } from '@react-navigation/stack'; import { createDrawerNavigator } from '@react-navigation/drawer'; import Login from '../../Views/Login'; @@ -30,10 +30,14 @@ import { trackErrorAsAnalytics } from '../../../util/analyticsV2'; import { routingInstrumentation } from '../../../util/setupSentry'; import Analytics from '../../../core/Analytics'; import AsyncStorage from '@react-native-community/async-storage'; -import { connect } from 'react-redux'; - +import { connect, useSelector, useDispatch } from 'react-redux'; import { EXISTING_USER, CURRENT_APP_VERSION, LAST_APP_VERSION } from '../../../constants/storage'; import { getVersion } from 'react-native-device-info'; +import { checkedAuth } from '../../../actions/user'; + +const styles = StyleSheet.create({ + fill: { flex: 1 }, +}); const Stack = createStackNavigator(); const Drawer = createDrawerNavigator(); @@ -147,6 +151,10 @@ const App = ({ userLoggedIn }) => { const [route, setRoute] = useState(); const [animationPlayed, setAnimationPlayed] = useState(); + const isAuthChecked = useSelector((state) => state.user.isAuthChecked); + const dispatch = useDispatch(); + const triggerCheckedAuth = () => dispatch(checkedAuth()); + const handleDeeplink = useCallback(({ error, params, uri }) => { if (error) { trackErrorAsAnalytics(error, 'Branch:'); @@ -196,6 +204,9 @@ const App = ({ userLoggedIn }) => { const existingUser = await AsyncStorage.getItem(EXISTING_USER); const route = !existingUser ? 'OnboardingRootNav' : 'Login'; setRoute(route); + if (!existingUser) { + triggerCheckedAuth(); + } } checkExsiting(); @@ -225,14 +236,23 @@ const App = ({ userLoggedIn }) => { } catch (error) { Logger.error(error); } - - animation?.current?.play(); - animationName?.current?.play(); } startApp(); }, []); + useEffect(() => { + if (!isAuthChecked) { + return; + } + const startAnimation = async () => { + await new Promise((res) => setTimeout(res, 50)); + animation?.current?.play(); + animationName?.current?.play(); + }; + startAnimation(); + }, [isAuthChecked]); + const onAnimationFinished = useCallback(() => { Animated.timing(opacity, { toValue: 0, @@ -244,41 +264,44 @@ const App = ({ userLoggedIn }) => { }); }, [opacity]); - if (!animationPlayed) { - return ( - - ); - } + const renderSplash = () => { + if (!animationPlayed) { + return ( + + ); + } + return null; + }; return ( // do not render unless a route is defined (route && ( - { - routingInstrumentation.registerNavigationContainer(navigator); - }} - > - - {userLoggedIn ? ( - - ) : ( - <> - - - - )} - - + + { + routingInstrumentation.registerNavigationContainer(navigator); + }} + > + + + + {userLoggedIn && ( + + )} + + + {renderSplash()} + )) || null ); diff --git a/app/components/UI/DrawerView/index.js b/app/components/UI/DrawerView/index.js index 25ae0f36a1f..35d0d7b74bb 100644 --- a/app/components/UI/DrawerView/index.js +++ b/app/components/UI/DrawerView/index.js @@ -566,6 +566,7 @@ class DrawerView extends PureComponent { }; logOut = () => { + this.props.navigation.navigate('Login'); this.props.logOut(); }; diff --git a/app/components/UI/MetaMaskAnimation/index.tsx b/app/components/UI/MetaMaskAnimation/index.tsx index a68730f9ea2..f0fed6606d9 100644 --- a/app/components/UI/MetaMaskAnimation/index.tsx +++ b/app/components/UI/MetaMaskAnimation/index.tsx @@ -9,7 +9,7 @@ const LOGO_PADDING = 25; const styles = StyleSheet.create({ main: { - flex: 1, + ...StyleSheet.absoluteFillObject, backgroundColor: colors.white, }, metamaskName: { diff --git a/app/components/Views/LockScreen/index.js b/app/components/Views/LockScreen/index.js index f8155117738..c4b157b8606 100644 --- a/app/components/Views/LockScreen/index.js +++ b/app/components/Views/LockScreen/index.js @@ -96,6 +96,7 @@ class LockScreen extends PureComponent { } logOut = () => { + this.props.navigation.navigate('Login'); this.props.logOut(); }; diff --git a/app/components/Views/Login/index.js b/app/components/Views/Login/index.js index 56118fdeff5..fe2911d70bf 100644 --- a/app/components/Views/Login/index.js +++ b/app/components/Views/Login/index.js @@ -25,7 +25,7 @@ import { strings } from '../../../../locales/i18n'; import SecureKeychain from '../../../core/SecureKeychain'; import FadeOutOverlay from '../../UI/FadeOutOverlay'; import setOnboardingWizardStep from '../../../actions/wizard'; -import { logIn, logOut } from '../../../actions/user'; +import { logIn, logOut, checkedAuth } from '../../../actions/user'; import { connect } from 'react-redux'; import Device from '../../../util/device'; import { OutlinedTextField } from 'react-native-material-textfield'; @@ -214,6 +214,10 @@ class Login extends PureComponent { selectedAddress: PropTypes.string, logIn: PropTypes.func, logOut: PropTypes.func, + /** + * TEMPORARY state for animation control on Nav/App/index.js + */ + checkedAuth: PropTypes.func, }; state = { @@ -272,10 +276,15 @@ class Login extends PureComponent { } catch (e) { console.warn(e); } + if (!enabled) { + await this.checkIfRememberMeEnabled(); + } } else { - this.checkIfRememberMeEnabled(); + await this.checkIfRememberMeEnabled(); } } + + this.props.checkedAuth(); } componentWillUnmount() { @@ -293,7 +302,6 @@ class Login extends PureComponent { */ checkIfRememberMeEnabled = async () => { const credentials = await SecureKeychain.getGenericPassword(); - //This if (credentials) { this.setState({ rememberMe: true }); // Restore vault with existing credentials @@ -440,6 +448,8 @@ class Login extends PureComponent { updateBiometryChoice = async (biometryChoice) => { if (!biometryChoice) { await AsyncStorage.setItem(BIOMETRY_CHOICE_DISABLED, TRUE); + // This line will disable biometrics the next time SecureKeychain.getGenericPassword is called + await SecureKeychain.resetGenericPassword(); } else { await AsyncStorage.removeItem(BIOMETRY_CHOICE_DISABLED); } @@ -653,6 +663,7 @@ const mapDispatchToProps = (dispatch) => ({ setOnboardingWizardStep: (step) => dispatch(setOnboardingWizardStep(step)), logIn: () => dispatch(logIn()), logOut: () => dispatch(logOut()), + checkedAuth: () => dispatch(checkedAuth()), }); export default connect(mapStateToProps, mapDispatchToProps)(Login); diff --git a/app/components/Views/Onboarding/index.js b/app/components/Views/Onboarding/index.js index 41c1eb17ed2..d884acaa0dc 100644 --- a/app/components/Views/Onboarding/index.js +++ b/app/components/Views/Onboarding/index.js @@ -247,6 +247,7 @@ class Onboarding extends PureComponent { } logOut = () => { + this.props.navigation.navigate('Login'); this.props.logOut(); }; diff --git a/app/reducers/user/index.js b/app/reducers/user/index.js index 698f73dbb1d..f4369581a7d 100644 --- a/app/reducers/user/index.js +++ b/app/reducers/user/index.js @@ -7,10 +7,16 @@ const initialState = { protectWalletModalVisible: false, gasEducationCarouselSeen: false, userLoggedIn: false, + isAuthChecked: false, }; const userReducer = (state = initialState, action) => { switch (action.type) { + case 'CHECKED_AUTH': + return { + ...state, + isAuthChecked: true, + }; case 'LOGIN': return { ...state, diff --git a/app/store/index.js b/app/store/index.js index 52466cf71c5..d1ca9267476 100644 --- a/app/store/index.js +++ b/app/store/index.js @@ -85,12 +85,22 @@ const persistTransform = createTransform( { whitelist: ['engine'] } ); +const persistUserTransform = createTransform( + (inboundState) => { + const { isAuthChecked, ...state } = inboundState; + // Reconstruct data to persist + return state; + }, + null, + { whitelist: ['user'] } +); + const persistConfig = { key: 'root', version, blacklist: ['onboarding'], storage: MigratedStorage, - transforms: [persistTransform], + transforms: [persistTransform, persistUserTransform], stateReconciler: autoMergeLevel2, // see "Merge Process" section for details. migrate: createMigrate(migrations, { debug: false }), timeout: TIMEOUT,