Search code examples
javascriptreact-nativeundefined

How can I call the newPasswordHandler when isPasscodeEntry is true?


Thanks for taking a look at this! I'm working on a reset password workflow. On the 'isForgot' screen I enter email and press 'Reset Password', the forgotHandler function is run a 6-digit code is stored in AsyncStorage.

    async function forgotHandler({ email }) {
        try {
            await expensesCtx.resetPassword({ email })
        } catch (error) {
            console.error('Error creating user:', error);
        } finally {
            setIsLoading(false)
        }
    }

That will also set isPasscodeEntry true and I successfully see the 'isPasscodeEntry' screen.

This is where the problem starts. I enter the 6-digit code, and when I press 'Submit Passcode' i'm expecting to set 'isNewPassword' true and render the isNewPassword screen where I set the new password. Except i'm getting the error:

WARN Possible Unhandled Promise Rejection (id: 0): TypeError: onNewPassword is not a function (it is undefined)

Here are the relevant parts of my LoginScreen.js:

function LoginScreen({ navigation }) {
    const expensesCtx = useContext(ExpensesContext);
    const { isAuthenticated } = expensesCtx;
    const [isLogin, setIsLogin] = useState(true);
    const [isForgot, setIsForgot] = useState(false);
    const [isPasscodeEntry, setIsPasscodeEntry] = useState(false);
    const [isNewPassword, setIsNewPassword] = useState(false)

async function forgotHandler({ email }) {
        try {
            await expensesCtx.resetPassword({ email })
        } catch (error) {
            console.error('Error creating user:', error);
        } finally {
            setIsLoading(false)
        }
    }

    async function newPasswordHandler({ passcode }) {
        try {
            // Check if the entered resetCode matches the one stored in AsyncStorage
            const storedCode = await AsyncStorage.getItem('resetCode');
            if (storedCode === passcode) {
                return
            } else {
                console.error('Invalid resetCode');
            }
        } catch (error) {
            console.error('Error creating user:', error);
        } finally {
            setIsLoading(false);
        }
    }

return (
        <SafeAreaView style={styles.container}>
            {!isForgot ? (
                <>

                    {isPasscodeEntry ? (
                        <>
                            {/** Renders the Passcode Entry Screen */}
                            <AuthContent
                                isLogin={isLogin}
                                isPasscodeEntry={isPasscodeEntry}
                                setIsPasscodeEntry={() => setPasscodeEntry}
                                setIsNewPassword={() => setNewPassword}
                                isNewPassword={isNewPassword}
                                setIsForgot={() => setForgot}
                                onNewPassword={() => newPasswordHandler}
                            />
                            <View style={styles.forgot}>
                                <Button onPress={() => { setIsForgot(true), setIsLogin(false) }}>
                                    Forgot Password
                                </Button>
                            </View>
                            <View style={styles.buttons}>
                                <Button onPress={() => setIsLogin(!isLogin)}>
                                    {isLogin ? 'Register Here' : 'Login Here'}
                                </Button>
                                {isLoading && <LoadingOverlay />}
                            </View>
                        </>
                    ) : (
                        <>
                            {/** Renders the Login or Registration Screen */}
                            <AuthContent
                                isLogin={isLogin}
                                isPasscodeEntry={isPasscodeEntry}
                                setIsPasscodeEntry={() => setPasscodeEntry}
                                onSignUp={signUpHandler}
                                onLogin={loginHandler}
                                isNewPassword={isNewPassword}
                                setIsNewPassword={() => setNewPassword}                
                            />
                            {isLogin && (
                                <View style={styles.forgot}>
                                    <Button onPress={() => { setIsForgot(true), setIsLogin(false) }}>
                                        Forgot Password
                                    </Button>
                                </View>
                            )}
                            <View style={styles.buttons}>
                                <Button onPress={() => setIsLogin(!isLogin)}>
                                    {isLogin ? 'Register Here' : 'Login Here'}
                                </Button>
                                {isLoading && <LoadingOverlay />}
                            </View>
                        </>
                    )}
                </>
            ) : (
                <>
                    {/** Renders the Forgot Password or New Password Screen */}
                    <AuthContent
                        isLogin={false}
                        isForgot={isForgot}
                        onForgot={forgotHandler}
                        isPasscodeEntry={isPasscodeEntry}
                        setIsPasscodeEntry={() => setPasscodeEntry()}
                        setIsNewPassword={() => setNewPassword}
                        isNewPassword={isNewPassword}
                    />
                    {!isPasscodeEntry && (
                        <View style={styles.buttons}>
                            <Button onPress={() => setIsForgot(false)}>
                                Go Back
                            </Button>
                            {isLoading && <LoadingOverlay />}
                        </View>
                    )}
                </>
            )}
        </SafeAreaView>
    );

}

export default LoginScreen;

I left the conditional jsx renderings so you can follow the logic and maybe see something I don't.

And here are the relevant parts of AuthContent which is rendered in LoginScreen.js:

function AuthContent({ isLogin, isForgot, isPasscodeEntry, isNewPassword, setIsForgot, setIsPasscodeEntry, setIsNewPassword, onSignUp, onLogin, onForgot, onNewPassword, enteredCode }) {

if (isForgot && !isPasscodeEntry) {
            // Handle the submission for Passcode Entry screen
            onForgot({ email });
        } else if (isPasscodeEntry) {
            // Handle the submission for New Password screen
            onNewPassword({ passcode });
        } else if 
            // Handle the submission for Login or Registration screen
            (isLogin) {
                onLogin({ email, password });
            } else if (!isLogin) {
                onSignUp({ email, password });
            }
        
    }

    return (
        <View style={styles.authContent}>
            <View style={styles.logoContainer}>
                <Image source={logo} style={styles.logo} resizeMode='contain' />
            </View>
            <View style={styles.logoc}>
                <AuthForm
                    isLogin={isLogin}
                    isForgot={isForgot}
                    isPasscodeEntry={isPasscodeEntry}
                    setIsPasscodeEntry={setIsPasscodeEntry}
                    setIsForgot={setIsForgot}
                    isNewPassword={isNewPassword}
                    onNewPassword={isNewPassword? onNewPassword: undefined}
                    onSubmit={submitHandler}
                    onForgot={isForgot ? onForgot : undefined}
                    credentialsInvalid={credentialsInvalid}
                />

                {loginError && (
                    Alert.alert('Login failed', 'Please check your entered credentials. ')
                )}
            </View>
        </View>
    );
}

export default AuthContent;

I tried adding onNewPassword prop to AuthContent when isPasscodeEntry is true but i'm still getting the error "onNewPassword is not a function"

{/** Renders the Passcode Entry Screen */}
                            <AuthContent
                                isLogin={isLogin}
                                isPasscodeEntry={isPasscodeEntry}
                                setIsPasscodeEntry={() => setPasscodeEntry}
                                setIsNewPassword={() => setNewPassword}
                                isNewPassword={isNewPassword}
                                setIsForgot={() => setForgot}
                                onNewPassword={() => newPasswordHandler}
                            />

And passing it as a prop to AuthForm in AuthContent:

<AuthForm
                    isLogin={isLogin}
                    isForgot={isForgot}
                    isPasscodeEntry={isPasscodeEntry}
                    setIsPasscodeEntry={setIsPasscodeEntry}
                    setIsForgot={setIsForgot}
                    isNewPassword={isNewPassword}
                    onNewPassword={isNewPassword? onNewPassword: undefined}
                    onSubmit={submitHandler}
                    onForgot={isForgot ? onForgot : undefined}
                    credentialsInvalid={credentialsInvalid}
                />

Solution

  • I added '!isNewPassword' in the jsx of the LoginScreen and the set new password screen is now rendering:

    return (
            <SafeAreaView style={styles.container}>
                {!isForgot ? (
                    <>
    
                        {isPasscodeEntry && !isNewPassword? (
                            <>