Logout Button not appearing After login? - firebase

I setup firebase authentication for my react native application. I was able to create new login and authentication failure for any incorrect login .
Once the user is login , i want them to logout using a button but unfortunately the button is not visible and only the text is appearing on screen ..
“ App.js “
import React, { Component } from 'react';
import { View } from 'react-native';
import firebase from 'firebase';
import { Header, Button, Spinner } from './components/common';
import LoginForm from './components/LoginForm';
class App extends Component {
state = { loggedIn: null };
componentWillMount() {
firebase.initializeApp(
{
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: ""
}
);
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ loggedIn: true });
} else {
this.setState({ loggedIn: false });
}
});
}
renderContent() {
switch (this.state.loggedIn) {
case true:
return (
<Button onPress={() => firebase.auth().signOut()}>
Log Out
</Button>
);
case false:
return <LoginForm />;
default:
return <Spinner size="large" />;
}
}
render() {
return (
<View>
<Header headerText="Authentication" />
{this.renderContent()}
</View>
);
}
}
export default App;
"Button.js"
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
);
};
const styles = {
textStyle: {
alignSelf: 'center',
color: '#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10
},
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
}
};
export { Button };
Thanks in advance.

edit your button like this
<Button children="Log Out" onPress={() => firebase.auth().signOut()}>
</Button>

Related

Testing React Native with Jest - Doesn't test 'onPress' and 'onChangeText'

I'm testing a component called ForgotPasswordComponent in React Native with Jest. The code for the component is seen here:
import { StyleSheet, View, ToastAndroid, Dimensions } from 'react-native'
import React, {useState} from 'react'
import {Button, Headline, Text, TextInput} from 'react-native-paper';
import { getAuth, sendPasswordResetEmail } from "firebase/auth";
import { useNavigation } from '#react-navigation/native';
import { ScaledSheet } from 'react-native-size-matters';
const {height, width} = Dimensions.get('window')
export default function ForgotPasswordComponent() {
const [email, setEmail] = useState('');
const auth = getAuth();
const navigation = useNavigation();
const forgotPassword = () => {
sendPasswordResetEmail(auth, email)
.then(() => {
ToastAndroid.show('Reset password mail sent successfully!', ToastAndroid.LONG);
})
.catch(() => {
ToastAndroid.show('Error: Please check your entered e-mail!', ToastAndroid.LONG)
});
}
return (
<View style={styles.container}>
<View>
<Button style={styles.buttonBack} uppercase={false} onPress={() => {navigation.navigate("Login")}}>
<Text style={styles.buttonTextGoBack}>Go back</Text>
</Button>
</View>
<View>
<Headline style={styles.headline}>Forgot your password? No problem!</Headline>
</View>
<View>
<Text style={styles.inputText}>Email:</Text>
<TextInput style={styles.input} placeholder="Enter your email" value={email} onChangeText={text => setEmail(text)}></TextInput>
</View>
<View>
<Button style={styles.buttonResetPassword} mode="contained" uppercase={false} onPress={forgotPassword}>
<Text style={styles.buttonTextResetPassword}>Reset password</Text>
</Button>
</View>
</View>
)
}
const styles = ScaledSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
marginBottom: '200#s'
},
headline: {
fontSize: '18#s',
marginTop: '60#s',
padding: '20#s',
},
inputText: {
paddingLeft: '14#s',
paddingTop: '6#s',
fontSize: '14#s'
},
input: {
padding: '10#s',
margin: '15#s',
width: width * 0.8,
height: height * 0.03,
fontSize: '14#s'
},
buttonResetPassword: {
width: width * 0.5,
},
buttonBack: {
paddingRight: '260#s',
width: width * 1.1,
},
buttonTextResetPassword: {
color: 'white',
fontSize: '14#s'
},
buttonTextGoBack: {
fontSize: '14#s'
}
})
As it is seen, it uses two functions from Firebase and the component have very little functionality.
Here is the testcases that I have wrote so far:
import React from 'react';
import renderer from 'react-test-renderer'
import ForgotPasswordComponent from '../components/ForgotPassword/ForgotPasswordComponent';
import { NavigationContainer } from '#react-navigation/native';
import { fireEvent, render } from '#testing-library/react-native';
import { Button, TextInput } from 'react-native-paper';
jest.useFakeTimers()
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
const mockGetAuth = jest.fn()
const mockSendPassword = jest.fn(() => {
return Promise.resolve(true)
})
jest.mock('firebase/auth', () => {
return {
getAuth: () => mockGetAuth,
sendPasswordResetEmail: () => mockSendPassword
}
})
//Testing that navigation is working
describe("Navigation working", () => {
it("calls useNavigation and navigates", () => {
const mockedNavigate = jest.fn();
jest.mock('#react-navigation/native', () => (
{ useNavigation: () => ({ navigate: mockedNavigate }) }));
const onPress = jest.fn(mockedNavigate);
const {getByText} = render(
<Button onPress={onPress}>Go Back</Button>,
);
fireEvent.press(getByText('Go Back'));
expect(mockedNavigate).toBeCalledTimes(1);
})
})
//Testing buttons and inputfield are working
describe('Buttons and input on press working', () => {
it('Go back onpress is called', () => {
const onPress = jest.fn();
const {getByText} = render(
<Button onPress={onPress}>Go Back</Button>,
);
fireEvent.press(getByText('Go Back'));
expect(onPress).toBeCalledTimes(1);
});
it('Reset onpress is called', () => {
const onPress = jest.fn();
const {getByText} = render(
<Button onPress={onPress}>Reset password</Button>,
)
fireEvent.press(getByText('Reset password'));
expect(onPress).toBeCalledTimes(1);
})
it('Email onChange is called', () => {
const onChangeTextMock = jest.fn();
const {getByPlaceholderText} = render(
<TextInput placeholder="Enter your email" onChangeText={onChangeTextMock}/>
);
fireEvent.changeText(getByPlaceholderText("Enter your email"), "test#gmail.com");
expect(onChangeTextMock).toBeCalled();
})
});
//Snapshot testing
test('renders forgotPasswordComponent correctly 1', () => {
const tree = renderer.create(
<NavigationContainer>
<ForgotPasswordComponent/>
</NavigationContainer>)
.toJSON();
expect(tree).toMatchSnapshot();
});
All the testcases runs succesfully, but when I inspect the code coverage I don't understand why my onPress function on line 30 and onChangeText function on line 39 are red. It is like they are not getting tested at all despite I have made testcases for them.
Besides are there any solution of how I can test the Firebase function sendPasswordResetEmail is called when the button is pressed and it shows the succesfully toast-message?

How to debug "undefined is not an object" when navigating between screens

I'm trying when I press Login button to go to Drawer screen which contains all my other screens but I'm getting the following error:
TypeError: undefined is not an object (evaluating
'this.props.navigation.navigate')
Here is my DrawerScreen:
import React, {Component} from 'react';
import { Button, View, Text, Dimensions, ImageBackground } from 'react-native';
import { createStackNavigator, createAppContainer, createDrawerNavigator, DrawerItems } from 'react-navigation';
import HomeScreen from './HomeScreen';
import AboutScreen from './AboutScreen';
import Count from './CountScreen';
const DrawerContent = (props) => (
<View>
<ImageBackground
source={{uri:'https://cdn.pixabay.com/photo/2017/12/13/07/15/natural-3016177_960_720.jpg'}}
style={{}}
imageStyle= {{opacity: 0.7}}
>
<View
style={{
//backgroundColor: '#73a2ef',
height: 140,
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text style={{ color: 'black', fontSize: 40, fontWeight: 'bold' }}>
Menu
</Text>
</View>
</ImageBackground>
<DrawerItems {...props} />
</View>
)
const WIDTF = Dimensions.get('window').width;
const DrawerConfig = {
drawerWidth: WIDTF*0.80,
drawertType: 'back',
}
const Drawer = createDrawerNavigator ({
Home: {
screen: HomeScreen
},
About: {
screen: AboutScreen
},
Count: {
screen: Count
},
},
{
drawerBackgroundColor: '#c7d1a7',
contentComponent: DrawerContent,
contentOptions: {
activeTintColor: 'blue',
style: {
flex: 1,
paddingTop: 15,
}
}},
DrawerConfig
);
const AppContainer = createAppContainer(Drawer);
export default AppContainer;
And here is my LogInScreen:
import React, {Component} from 'react';
import * as firebase from 'firebase';
import {Container, Content, Header, Form, Input, Item, Button, Label, Drawer} from 'native-base';
import {StyleSheet, Text} from 'react-native';
import AppContainer from './DrawerNavigatorNew';
const firebaseConfig = {
apiKey:
authDomain:
databaseURL:
projectId:
storageBucket:
};
firebase.initializeApp(firebaseConfig);
export default class LoginScreen extends React.Component {
constructor (props) {
super(props)
this.state =({
email:'',
password:'',
})
}
signUpUser = (email, password) => {
try {
if(this.state.password.length <6)
{
alert("Please enter atleast 6 characters")
return;
}
firebase.auth().createUserWithEmailAndPassword(email, password)
}
catch (error){
console.log(error.toString())
}
}
loginUser =(email, password) => {
try{
firebase.auth().signInWithEmailAndPassword(email, password).then(function(user){
console.log(user)
})
}
catch (error) {
console.log(error.toString())
}
}
render() {
const {navigate} = this.props.navigation;
return (
<Container style={styles.container}>
<Form>
<Item floatingLabel>
<Label> Email </Label>
<Input
name='email'
autoCorrect={false}
autoCapitalize='none'
onChangeText={(email)=> this.setState({email})}
/>
</Item>
<Item floatingLabel>
<Label> Password </Label>
<Input
name='password'
secureTextEntry={true}
autoCorrect={false}
autoCapitalize='none'
onChangeText={(password)=> this.setState({password})}
/>
</Item>
<Button style={{marginTop: 10}}
full
rounded
success
onPress = {()=> this.loginUser(this.state.email,this.state.password) || navigate(AppContainer)}
>
<Text> Login </Text>
</Button>
<Button style={{marginTop: 10}}
full
rounded
primary
onPress = {()=> this.signUpUser(this.state.email,this.state.password)}
>
<Text style={{color: 'white' }}> Sign Up </Text>
</Button>
</Form>
</Container>
);
}
}
const styles = StyleSheet.create ({
container:{
flex: 1,
backgroundColor: 'white',
justifyContent: 'center',
padding: 10
}
})
And the Error:
I misread the code. 'Navigate' is a command to move the screen. The 'createDrawenavigator' must open the drawer.
Can you try this Code?
onPress = {()=> this.loginUser(this.state.email,this.state.password) || this.props.navigation.openDrawer();}
Change the Navigator configuration if you want to move the screen.
createStackNavigator({
A: {
screen: AScreen,
navigationOptions: () => ({
title: `A`,
headerBackTitle: 'A much too long text for back button from B to A',
headerTruncatedBackTitle: `to A`
}),
},
B: {
screen: BScreen,
navigationOptions: () => ({
title: `B`,
}),
}
});

expo react-native react-navigation react-intl how to trigger an update to the messages once the user locale is resolved

I am using expo, react-native, redux, react-navigation, and react-intl. Expo has this async Localization.getCurrentLocaleAsync() function to retrieve the locale asynchronously. I encountered problem propagating changes of locale and messages down to child components.
For example, if I set initial locale to "es" in "Root.js", when the Localization.getCurrentLocaleAsync() kick in and set the locale to "en", the updated messages was not reflected in the child component "Login.js". As such, the simulator throws a console.error: Missing message: "Login.login" for locale: "es", using default message as fallback while I updated the locale and message in the root.js state Here's my code:
root.js
import React from 'react';
import { Provider } from 'react-redux';
import { StyleSheet, Text, View, Alert } from 'react-native';
import { DangerZone } from 'expo';
import { IntlProvider, addLocaleData, injectIntl } from 'react-intl';
import { createBottomTabNavigator, createSwitchNavigator } from 'react-navigation';
import { PersistGate } from 'redux-persist/integration/react';
import AuthLoadingPage from './containers/authLoading';
import LoginPage from './containers/login';
import SignupPage from './containers/signup';
import HomePage from './containers/home';
import NotFoundPage from './containers/notFound';
import configureStore from './configureStore';
import en from 'react-intl/locale-data/en';
import es from 'react-intl/locale-data/es';
import localeData from './build/data.json';
addLocaleData([...en, ...es]);
const { Localization } = DangerZone;
const { persistor, store } = configureStore();
const AuthTab = createBottomTabNavigator({
login: { screen: LoginPage },
signup: { screen: SignupPage },
},{
navigationOptions: {
tabBarVisible: false,
},
lazyLoad: true,
});
const MainNavigator = createSwitchNavigator({
authLoading: AuthLoadingPage,
main: { screen: HomePage},
auth: AuthTab,
},{
initialRouteName: 'authLoading',
});
class Root extends React.Component {
constructor(p) {
super(p);
this.state = {
currentLocale: 'es',
messages: localeData['es'],
};
}
componentDidMount() {
Localization.getCurrentLocaleAsync()
.then(currentLocale => {
console.log("currentLocale is >>>", currentLocale);
this.setState({
currentLocale,
messages: localeData[currentLocale],
});
});
}
render() {
console.log("this.state.message???", this.state.messages);
return (
<IntlProvider
locale={this.state.currentLocale}
key={this.state.currentLocale}
messages={this.state.messages}
textComponent={Text}
>
<Provider store={store}>
<PersistGate
loading={<NotFoundPage />}
onBeforeLift={() => {}}
persistor={persistor}
>
<MainNavigator />
</PersistGate>
</Provider>
</IntlProvider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default Root;
and "containers/Login.js":
import React, { Component } from 'react';
import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import {
View,
Text,
TextInput,
Image,
Dimensions,
KeyboardAvoidingView,
StyleSheet,
Button,
TouchableOpacity
} from 'react-native';
import { FormLabel, FormInput } from 'react-native-elements';
import { authenticate } from '../modules/auth/actions';
const SCREEN_WIDTH = Dimensions.get('window').width;
class LoginPage extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
}
handleSubmit(e) {
e.preventDefault();
const { email, password } = this.state;
const { navigation } = this.props;
this.props.dispatch(authenticate(email, password))
.then(() => {
navigation.navigate('main');
})
}
gotoSignup(e) {
e.preventDefault();
const { navigation } = this.props;
navigation.navigate('signup');
}
render() {
const { isAuthenticated, navigation } = this.props;
return (
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.loginLogo}>
<FormattedMessage
id={ 'Login.login' }
defaultMessage={ 'Welcome to login screen!' }
/>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
width: Dimensions.get('window').width,
},
loginLogo: {
flex:1,
},
loginForm: {
flex: 2,
},
loginFormContainer: {
flex: 1,
padding: 20,
},
input: {
height: 40,
backgroundColor: 'rgba(255,255,255, 0.8)',
paddingLeft: 10,
marginBottom: 15,
},
buttoncontainer: {
backgroundColor: '#23618C',
marginTop: 10,
paddingVertical: 15,
},
buttontext: {
textAlign: 'center',
color: '#fff',
fontWeight: 'bold',
},
});
function mapStateToProps(state) {
const { auth } = state;
const { loading, isAuthenticated } = auth;
return {
loading,
isAuthenticated
};
}
export default connect(mapStateToProps)(LoginPage);
you can also find the relavent code in github:
root.js: https://github.com/7seven7lst/mobile-client-new/blob/master/root.js
containers/Login.js: https://github.com/7seven7lst/mobile-client-new/blob/master/containers/login.js
Never mind. the above should be working. I got this id messed up. it should be "Login.Login" because that's what I have in the data.json file.
<FormattedMessage
id={ 'Login.login' }
defaultMessage={ 'Welcome to login screen!' }
/>

React Native: Object is not a function

I am working with Firebase authentification in my React Native android app, however every time I try to login and press the button, it gives me this error:
Object is not a function(evaluating 'this2.state'({
error: 'Authentification failed', loading: false
}))
I have looked up similar answers as well, but it doesn't seem to match my problem. Any help would be appreciated.
Here is my code:
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PixelRatio,
TouchableOpacity,
Image,
Button,
} from 'react-native';
import * as firebase from 'firebase';
import { FormLabel, FormInput } from 'react-native-elements';
import Help from './app/components/Help';
import { Input } from './app/components/Input';
const util = require('util');
firebase.initializeApp({
apiKey: 'AIzaSyCmjeFuDoMeOkeG5J-TCXzDJ1vtaDqUXjE',
authDomain: 'dev-pre-do.firebaseapp.com',
databaseURL: 'https://dev-pre-do.firebaseio.com',
projectId: 'dev-pre-do',
storageBucket: 'dev-pre-do.appspot.com',
messagingSenderId: '943752089124'
}
);
class LoginScreen extends React.Component {
static navigationOptions ={
header: null,
};
constructor(props) {
super(props);
this.state = {email:'', password:'', error: '', loading:false};
}
onLoginPress(){
this.setState({error:'', loading:true});
const{email, password} = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(() => {
this.state({error: '', loading: false});
this.props.navigation.navigate('CreateIdeaMenu');
})
.catch(() => {
this.state({error: 'Authentification failed', loading: false});
})
}
renderButtonOrLoading(){
if(this.state.loading) {
return (
<Text style={styles.loading}> Loading </Text>
)}
return (
<View>
<Button style={styles.Button} title='Login'
onPress={this.onLoginPress.bind(this)}></Button>
</View>
)
}
render() {
return (
<View style={styles.container}>
<Help onPress = {()=> navigate("HelpFirst")}/>
<Image style={styles.logo}
source={require('./app/images/PREDO_logo_white.png')}
/>
<FormLabel> Email</FormLabel>
<FormInput onChangeText={email => this.setState({ email })}/>
<FormLabel> Password</FormLabel>
<FormInput onChangeText={password => this.setState({ password })}/>
<Text>{this.state.error}</Text>
{/* <Input
placeholder='Email'
label='Email'
onChangeText={email => this.setState({ email })}
value={this.state.email}
/>
<Input
placeholder='Password'
label='Password'
secureTextEntry
onChangeText={password => this.setState({ password })}
value={this.state.password} */}
{this.renderButtonOrLoading()}
{/* <Button onPress={() => console.log('pressed')}>Log in</Button>*/}
{/* <RegForm onPress = {()=> navigate("CreateIdeaMenu")} /> */}
</View>
);
}
};
const styles = StyleSheet.create({
container: {
flex:1,
justifyContent: 'flex-start',
alignItems: 'center',
backgroundColor: '#1e1f20',
paddingLeft: 60,
paddingRight: 60,
paddingTop: 10,
},
Button: {
width: 200,
height:100,
marginBottom: 10,
backgroundColor: 'purple',
alignItems: 'center',
justifyContent: 'center',
},
logo: {
width: 360,
height:94,
marginBottom: 80,
marginTop: 20,
},
loading: {
color: 'white',
fontSize: 50,
}
});
export default LoginScreen;
Update your code as below:
onLoginPress(){
this.setState({error:'', loading:true});
const{email, password} = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(() => {
this.setState({error: '', loading: false});
this.props.navigation.navigate('CreateIdeaMenu');
})
.catch(() => {
this.setState({error: 'Authentification failed', loading: false});
})
}

React-native firebase Signinwithemal and createuserwithemailandpassword

i am trying to make a simple login app, when you try to login with an account that isnt registered, it should just make a new account.
Like you can see on my onButtonPress function, my problem is that whatever i try to fill in, i get the error message. Which doesnt make sense, normally if i would fill in an email-adres and password for the first time, it should just register me, but instead of that, i just always get the error message.
Here you can see my LoginForm class
import React, { Component } from 'react';
import { Text } from 'react-native';
import firebase from 'firebase';
import { Button, Card, CardSection, Input } from './common';
class LoginForm extends Component {
state = { email: '', password: '', error: '' };
onButtonPress() {
const { email, password } = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.catch(() => {
this.setState({ error: 'Authentication failed' });
});
});
}
render() {
return (
<Card>
<CardSection>
<Input
placeholder="user#gmail.com"
label="Email"
value={this.state.email}
onChangeText={email => this.setState({ email })}
/>
</CardSection>
<CardSection>
<Input
secureTextEntry
placeholder="password"
label="Password"
value={this.state.password}
onChangeText={password => this.setState({ password })}
/>
</CardSection>
<Text style={styles.errorTextStyle}>
{this.state.error}
</Text>
<CardSection>
<Button onPress={this.onButtonPress.bind(this)}>
Log in
</Button>
</CardSection>
</Card>
);
}
}
const styles = {
errorTextStyle: {
fontSize: 20,
alignSelf: 'center',
color: 'red'
}
};
export default LoginForm;
I will add my Input class as well, you never know what could be wrong... :)
import React from 'react';
import { TextInput, View, Text } from 'react-native';
const Input = ({ label, value, onChangeText, placeholder, secureTextEntry })
=> {
const { inputStyle, labelStyle, containerStyle } = styles;
return (
<View style={containerStyle}>
<Text style={labelStyle}>{label}</Text>
<TextInput
placeholder={placeholder}
autoCorrect={false}
secureTextEntry={secureTextEntry}
style={inputStyle}
value={value}
onChangeText={onChangeText}
/>
</View>
);
};
const styles = {
inputStyle: {
color: '#000',
paddingRight: 5,
paddingLeft: 5,
fontSize: 18,
lineHeight: 23,
flex: 2,
height: 40
},
labelStyle: {
fontSize: 18,
paddingLeft: 20,
flex: 1
},
containerStyle: {
height: 40,
flex: 1,
flexDirection: 'row',
alignItems: 'center'
}
};
export { Input };
You do not have a .then(), only a .catch(). Maybe this can help?
firebase.auth().createUserWithEmailAndPassword(email, password).then()

Resources