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}
/>
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? (
<>