I have been encountering an error when trying to use Firebase's SignIn With google auth method. So far I have:
Enabled the google auth method in my admin console
Looked at the docs for it and implemented the requirements
Enabled, and correctly got the Email/Password auth to work
I am trying to use the signInWithPopup method instead of a redirect.
Here is the SignIn.js code file:
import React, { useState } from 'react';
import { StyleSheet, Text, View, Button, TextInput, Pressable } from 'react-native';
import tw from 'tailwind-react-native-classnames';
import { signInWithEmailAndPassword, signInWithPopup, GoogleAuthProvider } from "firebase/auth";
import { auth, provider } from "../firebaseConfig";
import { Ionicons } from '#expo/vector-icons';
import { Feather } from '#expo/vector-icons';
import SignInHeader from '../components/SignInHeader';
export default function SignIn({ navigation }) {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
let signInWithGoogle = () => {
signInWithPopup(auth, provider)
.then((result) => {
const credential = GoogleAuthProvider.credentialFromResult(result);
const token = credential.accessToken;
const user = result.user;
navigation.navigate("Home");
console.log(user);
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
const email = error.customData.email;
const credential = GoogleAuthProvider.credentialFromError(error);
console.log(errorCode, errorMessage, email, credential);
});
}
let signIn = () => {
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
const user = userCredential.user;
navigation.navigate("Home");
console.log(user);
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(errorCode, errorMessage);
switch (errorCode) {
case "auth/invalid-email":
alert("Please Enter a valid email address");
break;
case "auth/user-not-found":
alert("User not found");
break;
case "auth/wrong-password":
alert("Incorrect Password. Try again.");
break;
case "auth/internal-error":
alert("Please enter a valid password");
break;
}
});
}
return (
<>
<SignInHeader />
<View style={{ alignItems: 'center', marginTop: '25%', paddingTop: 10 }}>
<View style={styles.searchSection}>
<Ionicons name="mail-outline" size={20} color="black" style={styles.searchIcon} />
<TextInput
style={styles.input}
placeholder="Email"
onChangeText={text => setEmail(text)}
value={email}
clearButtonMode="always"
/>
</View>
<View style={{ padding: 25 }}>
<View style={styles.searchSection}>
<Feather name="lock" size={20} color="black" style={styles.searchIcon} />
<TextInput
style={styles.input}
placeholder="Password"
onChangeText={text => setPassword(text)}
value={password}
secureTextEntry={true}
clearButtonMode="always"
/>
</View>
</View>
<Pressable style={{ marginLeft: '55%', marginTop: -10 }} onPress={() => navigation.navigate("ResetPassword")}>
<Text style={{ color: '#cdcdcd' }}>Forgot Password?</Text>
</Pressable>
<Pressable onPress={signIn} style={({ pressed }) => [
{
backgroundColor: pressed
? '#34AE65'
: '#64DA93'
},
styles.notPressed,
]}>
<Text style={{ fontFamily: "OpenSans_600SemiBold", fontSize: 20, color: 'white' }}>Log In</Text>
</Pressable>
<Pressable onPress={signInWithGoogle} style={({ pressed }) => [
{
backgroundColor: pressed
? '#34AE65'
: '#64DA93'
},
styles.notPressed,
]}>
<Text style={{ fontFamily: "OpenSans_600SemiBold", fontSize: 20, color: 'white' }}>Log In with Google</Text>
</Pressable>
<Pressable onPress={() => navigation.navigate("SignUp")}>
<Text style={{ flex: 1, color: '#cdcdcd', marginTop: 20, flexDirection: 'row' }}>Don't have and account?<Text style={{ color: 'grey' }}> Sign Up</Text></Text>
</Pressable>
</View >
</>
);
}
const styles = StyleSheet.create({
searchSection: {
flexDirection: 'row',
alignItems: 'center',
width: 360,
height: 45,
borderBottomColor: '#64DA93',
borderBottomWidth: 2,
},
searchIcon: {
padding: 1,
},
input: {
flex: 1,
paddingTop: 10,
paddingRight: 10,
paddingBottom: 10,
paddingLeft: 10,
},
notPressed: {
height: 45,
width: 360,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
marginTop: 50
}
});
Next, which is important is my firebaseConfig.js code file:
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAuth, GoogleAuthProvider } from "firebase/auth";
const firebaseConfig = {
apiKey: "xx",
authDomain: "xx",
projectId: "xx",
storageBucket: "xx",
messagingSenderId: "xx",
appId: "xx",
measurementId: "xx"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth();
const provider = new GoogleAuthProvider();
export { auth, provider };
This is the error:
ERROR TypeError: (0, _auth.signInWithPopup) is not a function. (In '(0, _auth.signInWithPopup)(_firebaseConfig.auth, _firebaseConfig.provider)', '(0, _auth.signInWithPopup)' is undefined)
Thanks for the help.
signInWithPopup is not supported in React Native. Use auth().signInWithCredential(googleCredential) instead.
Upon successful sign-in, any onAuthStateChanged listeners will trigger with the new authentication state of the user.
Consider using this library instead as the one you are using is really meant for the web
Related
I am having issues when a user signs up using firebase auth, I am unable to capture the username so that it can be used in other parts of the app.
The error that i see in the console is:
"Function DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field displayName in document"...)
Would really appreciate if someone can point me to where the mistake is. Here are my files:
AuthProvider.js
import React, { createContext, useState } from "react";
import { auth, db } from "../firebase";
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider
value={{
user,
setUser,
login: async (email, password) => {
try {
await auth.signInWithEmailAndPassword(email, password);
} catch (e) {
console.log(e);
}
},
register: async (email, password, display_name) => {
try {
await auth
.createUserWithEmailAndPassword(email, password)
.then(async (res) => {
const userInfo = {
displayName: display_name,
};
await db
.collection("users")
.doc(res.user.uid)
.set(userInfo)
.then(() => {
console.log("user added")
console.log(res);
});
});
} catch (e) {
console.log(e);
}
},
logout: async () => {
try {
await auth.signOut();
} catch (e) {
console.log(e);
}
},
}}
>
{children}
</AuthContext.Provider>
);
};
SignUpScreen.js
import React, { useContext, useState } from "react";
import {
View,
Text,
TouchableOpacity,
Image,
Platform,
StyleSheet,
ScrollView,
Alert,
} from "react-native";
import FormInput from "../components/FormInput";
import FormButton from "../components/FormButton";
import SocialButton from "../components/SocialButton";
import { AuthContext } from "../navigation/AuthProvider";
const SignupScreen = ({ navigation }) => {
const [display_name, setDisplay_Name] = useState();
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const [confirmPassword, setConfirmPassword] = useState();
const { register } = useContext(AuthContext);
const registerCheck = () => {
if (
display_name != "" &&
email != "" &&
password != "" &&
confirmPassword != ""
) {
if (password == confirmPassword) {
register(email, password);
} else {
Alert.alert("Oops! Passwords did not match");
}
} else {
Alert.alert("Oops! Some information is missing");
}
console.log(display_name, email, password, confirmPassword);
};
return (
<ScrollView contentContainerStyle={styles.container}>
<Text style={styles.text}>Create an Account</Text>
<FormInput
labelValue={display_name}
onChangeText={(userDisplay_Name) => setDisplay_Name(userDisplay_Name)}
placeholderText="Name"
iconType="user"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
/>
<FormInput
labelValue={email}
onChangeText={(userEmail) => setEmail(userEmail)}
placeholderText="Email"
iconType="user"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
/>
<FormInput
labelValue={password}
onChangeText={(userPassword) => setPassword(userPassword)}
placeholderText="Password"
iconType="lock"
secureTextEntry={true}
/>
<FormInput
labelValue={confirmPassword}
onChangeText={(userConfirmPassword) =>
setConfirmPassword(userConfirmPassword)
}
placeholderText="Confirm Password"
iconType="lock"
secureTextEntry={true}
/>
<FormButton
buttonTitle="Sign Up"
onPress={() => registerCheck(email, password)}
/>
<View style={styles.textPrivate}>
<Text style={styles.color_textPrivate}>
By registering, you confirm that you accept our{" "}
</Text>
<TouchableOpacity onPress={() => alert("Terms Clicked!")}>
<Text style={[styles.color_textPrivate, { color: "#e88832" }]}>
Terms of service
</Text>
</TouchableOpacity>
<Text style={styles.color_textPrivate}> and </Text>
<Text style={[styles.color_textPrivate, { color: "#e88832" }]}>
Privacy Policy
</Text>
</View>
<SocialButton
buttonTitle="Sign Up with Facebook"
btnType="facebook"
color="#4867aa"
backgroundColor="#e6eaf4"
onPress={() => {}}
/>
<SocialButton
buttonTitle="Sign Up with Google"
btnType="google"
color="#de4d41"
backgroundColor="#f5e7ea"
onPress={() => {}}
/>
<TouchableOpacity
style={styles.navButton}
onPress={() => navigation.navigate("Login")}
>
<Text style={styles.navButtonText}>Have an account? Sign In</Text>
</TouchableOpacity>
</ScrollView>
);
};
export default SignupScreen;
const styles = StyleSheet.create({
container: {
backgroundColor: "#f9fafd",
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 20,
},
text: {
fontFamily: "Helvetica",
fontSize: 28,
marginBottom: 10,
color: "#051d5f",
},
navButton: {
marginTop: 15,
},
navButtonText: {
fontSize: 18,
fontWeight: "500",
color: "#2e64e5",
fontFamily: "Helvetica",
},
textPrivate: {
flexDirection: "row",
flexWrap: "wrap",
marginVertical: 35,
justifyContent: "center",
},
color_textPrivate: {
fontSize: 13,
fontWeight: "400",
fontFamily: "Helvetica",
color: "grey",
},
});
I'm new to React Native and currently trying to integrate Deso Identity into my React Native App.
Question: How should I retrieve user data if I use WebView and what is the correct implementation to generate derived key?
Goal:
Navigate to Deso Identity Page when clicking on a button from LogIn screen
Receive derived key and all user response data after logging in
What I have tried:
I'm currently trying to generate derive key by making a call to Deso's window API without using WebView
I have tried using WebView with a DesoLogin.js component below but there's not much details from Deso's documentation and I was not able to retrieve response data after logging in
DesoLogin.js
import React, { useState, useEffect } from 'react';
import { WebView, WebViewNavigation } from 'react-native-webview';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useNavigation } from '#react-navigation/native';
import Home from '../screens/Home';
const DesoLogin = () =>{
const navigation = useNavigation();
// const webView = WebView();
const [signIn, setSignIn] = useState(false)
const [userProfile, setUserProfile] = useState(null)
// function onMessage(data) {
// alert(data.nativeEvent.data);
// }
// const handleLogin = (e) => {
// const data = webView.getUrl(e);
// setUserProfile(data)
// }
const handleNavigationStateChange = () => {
navigation.navigate("Home", {userProfile});
}
const onNavigationStateChange = e => {
if (userProfile!==e.url) {
console.log(e.url);
setUserProfile(e.url);
console.log(userProfile);
}
};
useEffect(() => {
setSignIn(true);
if (userProfile) {
handleNavigationStateChange();
}
},[userProfile])
return (
<SafeAreaView style={{ flex: 1 }}>
<WebView
source={{
uri: 'https://identity.deso.org/derive?callback=auth://derive'
}}
// onMessage={onMessage}s
// injectedJavaScript={handleLogin}
onNavigationStateChange={onNavigationStateChange}
javaScriptEnabled
style={{ marginTop: 20 }}
/>
</SafeAreaView>
);
}
export default DesoLogin;
Error:
I know that windows.open() doesn't work in react native like it does in web application
Deso Mobile Integration Doc
Window API-Callbacks section
Login.js Screen code below
import React, { useEffect, useState } from "react";
import { useNavigation } from "#react-navigation/native";
import axios from 'axios';
import DesoLogin from "../components/DesoLogin";
import DesoIdentity from "../libs/DesoIdentity";
import { KeyboardAvoidingView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'
import { COLORS, FONTS, SIZES, SHADOWS, assets } from "../constants";
import { CircleButton, RectButton, DetailsDesc, DetailsBid, FocusedStatusBar } from "../components";
const LogIn = () => {
const [loading, setLoading] = useState(null);
const [error, setError] = useState(null);
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [publicKey, setSetPublicKey] = useState(null)
const [desoIdentity, setDesoIdentity] = useState(null)
const navigation = useNavigation()
useEffect(() => {
axios('https://identity.deso.org/derive?callback=auth://derive')
.then(response => {
setSetPublicKey(response.accessSignature)
})
.catch(error => {
console.error("Error Fetching data", error);
setError(error);
throw error;
})
} , [])
const handleSignUp = () => {
return 0;
}
const handleLogin = async () => {
setSetPublicKey(publicKey);
setLoggedIn(true);
}
const handleLogout = () => {
setSetPublicKey(null);
setLoggedIn(false);
}
return (
<KeyboardAvoidingView
style={styles.container}
behavior="padding"
>
<View style={styles.inputContainer}>
<TextInput
placeholder="Email"
value={email}
onChangeText={text => setEmail(text)}
style={styles.input}
/>
<TextInput
placeholder="Password"
value={password}
onChangeText={text => setPassword(text)}
style={styles.input}
secureTextEntry
/>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={handleLogin}
style={styles.button}
>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<TouchableOpacity
// onPress={handleSignUp}
style={[styles.button, styles.buttonOutline]}
>
<Text style={styles.buttonOutlineText}>Register</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
)
}
export default LogIn;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
inputContainer: {
width: '80%'
},
input: {
backgroundColor: COLORS.white,
paddingHorizontal: 15,
paddingVertical: 10,
borderRadius: 10,
marginTop: 5,
},
buttonContainer: {
width: '60%',
justifyContent: 'center',
alignItems: 'center',
marginTop: 40,
},
button: {
backgroundColor: '#0782F9',
width: '100%',
padding: 15,
borderRadius: 10,
alignItems: 'center',
},
buttonOutline: {
backgroundColor: COLORS.white,
marginTop: 5,
borderColor: '#0782F9',
borderWidth: 2,
},
buttonText: {
color: COLORS.white,
fontWeight: '700',
fontSize: 16,
},
buttonOutlineText: {
color: '#0782F9',
fontWeight: '700',
fontSize: 16,
},
})
I recently have been making a app for my IOS app and am introducing firebase email/password auth to my project. The registration part works good but when i do the handleSignin function it doesnt quite work as expected. Any ideas why
my code:
import React from 'react';
import { Button,StyleSheet,View,Text, Image,SafeAreaView, TextInput, KeyboardAvoidingView, TouchableOpacity} from 'react-native';
import {auth} from "../firebase"
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword} from "firebase/auth";
import { FirebaseError } from 'firebase/app';
export const Login = () => {
const [email, setEmail] = React.useState("")
const [password, setPassword] = React.useState("")
const handleSignUp = (e) => {
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ..
});
}
const handleLogin = () => {
auth
.signInWithEmailAndPassword(email, password)
.then(userCredentials => {
const user = userCredentials.user;
console.log('Logged in with:', user.email);
})
.catch(error => alert(error.message))
}
return (
<KeyboardAvoidingView
style={styles.container}
behavior="padding"
>
<Text style={styles.heading}>Unlock the power of time managment</Text>
<View style={styles.inputContainer}>
<TextInput
value={email}
placeholder="Email"
style={styles.input}
onChangeText={text => setEmail(text)}
/>
<TextInput
placeholder="Password"
style={styles.input}
onChangeText={text => setPassword(text)}
value={password}
secureTextEntry
/>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.button}
onPress={handleLogin}
>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.buttonOutline]}
onPress={handleSignUp}
>
<Text style={styles.buttonOutlineText} >Register</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
)
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
inputContainer: {
width: '80%'
},
input: {
backgroundColor: 'white',
paddingHorizontal: 15,
paddingVertical: 10,
borderRadius: 10,
marginTop: 5,
},
heading: {
fontSize: 30,
fontWeight: "700"
},
buttonContainer: {
width: '60%',
justifyContent: 'center',
alignItems: 'center',
marginTop: 40,
},
button: {
backgroundColor: '#0782F9',
width: '100%',
padding: 15,
borderRadius: 10,
alignItems: 'center',
},
buttonOutline: {
backgroundColor: 'white',
marginTop: 5,
borderColor: '#0782F9',
borderWidth: 2,
},
buttonText: {
color: 'white',
fontWeight: '700',
fontSize: 16,
},
buttonOutlineText: {
color: '#0782F9',
fontWeight: '700',
fontSize: 16,
},
});
expo go error:
firebase.auth.signinwithemailandpassword not a function
firebase.auth.signinwithemailandpassword returned undefined
You're using the new, modular SDK syntax, where most functionality is exposed as a top-level function, instead of as a method on an object. When you call createUserWithEmailAndPassword as a top-level function you pass in the auth object, and you need to do the same for signing in:
const handleLogin = () => {
signInWithEmailAndPassword(auth, email, password)
...
I recommend keeping the Firebase documentation handy when troubleshooting problems like this, as the above is almost exactly the code shown in the Web version 9 (modular) tab in the section signing in a user with an email address and password
Below is the guideline on what worked for me, you can try it.
Here is the explanation:
You have to import signInWithEmailAndPassword from firebase/auth.
Note: signInWithEmailAndPassword is a function that takes three arguments, ie auth, email and password.
import { signInWithEmailAndPassword } from "firebase/auth";
const signIn= (e) => {
e.preventDefault();
// for login
signInWithEmailAndPassword(auth, email, password).then((auth) => {
console.log(auth);
if (auth) {
// if successfully signed in, redirect the new user to the home page
navigate('/');
}
}).catch(error => alert(error.message));
};
I am trying to create a social media app with React Native / Expo and Firebase, and I have successfully been able to create accounts and login, but I am still trying to figure out how to get user data such as username when the user logs in. Basically, when I log in or create an account, I want the profile page to show the username and profile picture associated with the user that logged in, but I'm not sure how to do that. It probably has something to do with the AuthStateChanged() function or something like that, but I'm not sure.
Here is my App.js file:
import 'react-native-gesture-handler';
import React, { useState } from 'react';
import { LogBox, Text, View } from 'react-native';
import AppLoading from 'expo-app-loading';
import * as Font from 'expo-font';
import Feather from '#expo/vector-icons/Feather'
import { useFonts, Nunito_400Regular as NunitoRegular, Nunito_700Bold as NunitoBold } from '#expo-google-fonts/nunito';
import { NavigationContainer, DefaultTheme } from '#react-navigation/native';
import Navigator from './src/navigation/index';
import * as firebase from "firebase";
import "firebase/auth";
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "AIzaSyB1TxcRpLQq0Zqs0f0FvPitIto0tZo_0xM",
authDomain: "shutter-42e70.firebaseapp.com",
projectId: "shutter-42e70",
storageBucket: "shutter-42e70.appspot.com",
messagingSenderId: "149059508529",
appId: "1:149059508529:web:0dbc5bbbb75bf022ef7810"
};
if (firebase.apps.length === 0) {
firebase.initializeApp(firebaseConfig);
}
// The theme we'll be using for our navigator
const MyTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: '#FAFAFA'
},
};
// Loads the Feather icons (https://docs.expo.io/guides/icons/)
function cacheFonts(fonts) {
return fonts.map(font => Font.loadAsync(font));
}
export default function App() {
const [assetsReady, setAssetsReady] = useState(false);
async function _loadFonts() {
const iconFontAssets = cacheFonts([Feather.font])
await Promise.all([...iconFontAssets]);
}
// Loads the Nunito font (https://docs.expo.io/guides/using-custom-fonts/)
let [fontsLoaded] = useFonts({
NunitoRegular, NunitoBold
});
// If the fonts or assets are not loaded, we show a default App Loading screen.
// Otherwise, we return our Photo Sharing App!
if (!fontsLoaded || !assetsReady) {
return <AppLoading
startAsync={_loadFonts}
onFinish={() => setAssetsReady(true)}
onError={console.warn}
/>
}
return (
<NavigationContainer theme={MyTheme}>
<Navigator />
</NavigationContainer>
);
}
Here is my Login.js file:
import React from 'react';
import { StyleSheet, View, Text, Image, TextInput, TouchableOpacity } from 'react-native';
import theme from '../../assets/themes';
import { Formik } from 'formik';
import { Octicons, Fontisto } from '#expo/vector-icons';
import Separator from './Separator';
import KeyBoardAvoidingWrapper from './KeyboardAvoidingWrapper';
import firebase from 'firebase';
var errorMsg = '...'
const Login = ({navigation}) => {
return (
<KeyBoardAvoidingWrapper>
<View>
<View style = {styles.StyledContainer}>
<View style = {styles.InnerContainer}>
<Image style = {styles.PageLogo} resizeMode = "cover" source = {require('./../../assets/images/logo.png')} />
<Text style = {styles.PageTitle}>Shutter</Text>
<Text style = {styles.TagLine}>Social Media for Photographers</Text>
</View>
</View>
<Formik
initialValues = {{email: '', password: ''}}
onSubmit = {(values) => {
firebase.auth().signInWithEmailAndPassword(values.email, values.password)
.then((result) => {
navigation.navigate('Feed');
})
.catch((error) => {
alert(error)
})
}}
>
{({handleChange, handleBlur, handleSubmit, values}) => (
<View style = {styles.styledFormArea}>
<MyTextInput
label = " "
icon = "mail"
placeholder = "email#email.com"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('email')}
onBlur = {handleBlur('email')}
value = {values.email}
keyboardType = "email-address"
/>
<MyTextInput
label = " "
icon = "lock"
placeholder = "password"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('password')}
onBlur = {handleBlur('password')}
value = {values.password}
secureTextEntry = {true}
/>
<Text style = {styles.msgBox}>{errorMsg}</Text>
<TouchableOpacity onPress = {handleSubmit} style = {styles.loginButton}>
<Text style = {styles.loginButtonText}>Login</Text>
</TouchableOpacity>
<Separator />
<TouchableOpacity onPress = {handleSubmit} style = {styles.googleSigninButton}>
<Fontisto name = "google" color = {theme.colors.white} size = {25} ></Fontisto>
<Text style = {styles.googleSigninButtonText}>Sign in with Google</Text>
</TouchableOpacity>
<View style = {styles.signupLinkView}>
<Text style = {styles.signupText}>Don't have an account? </Text>
<TouchableOpacity style = {styles.signupLinkButton}>
<Text onPress = {() => navigation.navigate('Sign Up')} style = {styles.signupLinkText}>Sign up</Text>
</TouchableOpacity>
</View>
</View>
)}
</Formik>
</View>
</KeyBoardAvoidingWrapper>
);
};
const MyTextInput = ({label, icon, ...props}) => {
return (
<View>
<View style = {styles.leftIcon}>
<Octicons name = {icon} size = {30} color = {theme.colors.primary} />
</View>
<Text style = {styles.styledTextInput}>{label}</Text>
<TextInput style = {styles.textInput} {...props} />
</View>
)
}
const styles = StyleSheet.create({
StyledContainer: {
flex: 1,
padding: theme.spacing.m,
paddingTop: theme.spacing.l,
backgroundColor: theme.colors.white,
marginTop: 80,
},
InnerContainer: {
justifyContent: 'center',
alignItems: 'center',
},
PageLogo: {
width: 100,
height: 100,
},
PageTitle: {
...theme.textVariants.h1,
marginTop: theme.spacing.m,
},
TagLine: {
...theme.textVariants.body3,
},
styledFormArea: {
justifyContent: 'center',
marginHorizontal: theme.spacing.l,
borderRadius: theme.borderRadius.m,
marginTop: 40,
},
leftIcon: {
position: 'absolute',
zIndex: 1,
marginTop: 28,
marginLeft: 12,
},
styledTextInput: {
...theme.textVariants.body3,
},
textInput: {
backgroundColor: theme.colors.gray,
paddingVertical: 10,
paddingLeft: 50,
paddingRight: theme.spacing.l,
borderRadius: theme.borderRadius.m,
},
loginButton: {
backgroundColor: theme.colors.primary,
alignItems: 'center',
marginTop: 20,
paddingVertical: 8,
borderRadius: theme.borderRadius.m,
},
loginButtonText: {
...theme.textVariants.body2,
color: theme.colors.white,
},
msgBox: {
...theme.textVariants.body3,
alignSelf: 'center',
},
googleSigninButton: {
backgroundColor: theme.colors.primary,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginTop: 16,
paddingVertical: 8,
borderRadius: theme.borderRadius.m,
},
googleSigninButtonText: {
...theme.textVariants.body2,
color: theme.colors.white,
paddingLeft: 25,
},
signupLinkView: {
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
padding: theme.spacing.sm,
},
signupText: {
...theme.textVariants.body3,
},
signupLinkButton: {
},
signupLinkText: {
...theme.textVariants.body3,
opacity: 0.6,
},
})
export default Login;
Here is my Signup.js file:
import React from 'react';
import { StyleSheet, View, Text, Image, TextInput, TouchableOpacity } from 'react-native';
import theme from '../../assets/themes';
import { Formik } from 'formik';
import { Octicons } from '#expo/vector-icons';
import Separator from './Separator';
import KeyboardAvoidingWrapper from './KeyboardAvoidingWrapper';
import firebase from 'firebase';
var errorMsg = '...'
const SignUp = ({navigation}) => {
return (
<KeyboardAvoidingWrapper>
<View>
<View style = {styles.StyledContainer}>
<View style = {styles.InnerContainer}>
<Image style = {styles.PageLogo} resizeMode = "cover" source = {require('./../../assets/images/logo.png')} />
<Text style = {styles.PageTitle}>Shutter</Text>
<Text style = {styles.TagLine}>Social Media for Photographers</Text>
</View>
</View>
<Formik
initialValues = {{fullName: '', email: '', username: '', password: '', confirmPassword: ''}}
onSubmit = {(values) => {
firebase.auth().createUserWithEmailAndPassword(values.email, values.password)
.then((result) => {
firebase.firestore().collection("users")
.doc(firebase.auth().currentUser.uid)
.set({
fullName: values.fullName,
displayName: values.email,
username: values.username,
password: values.password,
})
if (values.password === values.confirmPassword)
navigation.navigate('Signup Options')
else
errorMsg = 'Passwords do not match'
})
.catch((error) => {
alert(error)
})
}}
>
{({handleChange, handleBlur, handleSubmit, values}) => (
<View style = {styles.styledFormArea}>
<MyTextInput
label = "Name"
icon = "person"
placeholder = "John Doe"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('fullName')}
onBlur = {handleBlur('fullName')}
value = {values.fullName}
/>
<MyTextInput
label = "Email"
icon = "mail"
placeholder = "email#email.com"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('email')}
onBlur = {handleBlur('email')}
value = {values.email}
keyboardType = "email-address"
/>
<MyTextInput
label = "Username"
icon = "person"
placeholder = "username"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('username')}
onBlur = {handleBlur('username')}
value = {values.username}
/>
<MyTextInput
label = "Password"
icon = "lock"
placeholder = "password"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('password')}
onBlur = {handleBlur('password')}
value = {values.password}
secureTextEntry = {true}
/>
<MyTextInput
label = "Confirm Password"
icon = "lock"
placeholder = "retype password"
placeholderTextColor = {theme.colors.black}
onChangeText = {handleChange('confirmPassword')}
onBlur = {handleBlur('confirmPassword')}
value = {values.confirmPassword}
secureTextEntry = {true}
/>
<Text style = {styles.msgBox}>{errorMsg}</Text>
<TouchableOpacity onPress = {handleSubmit} style = {styles.loginButton}>
<Text style = {styles.loginButtonText}>Sign Up</Text>
</TouchableOpacity>
<Separator />
<View style = {styles.signupLinkView}>
<Text style = {styles.signupText}>Already have an account? </Text>
<TouchableOpacity style = {styles.signupLinkButton}>
<Text onPress = {() => navigation.navigate('Login')} style = {styles.signupLinkText}>Login</Text>
</TouchableOpacity>
</View>
</View>
)}
</Formik>
</View>
</KeyboardAvoidingWrapper>
);
};
const onSignUp = ({values}) => {
console.log(values);
}
const MyTextInput = ({label, icon, ...props}) => {
return (
<View style = {styles.inputFieldView}>
<View style = {styles.leftIcon}>
<Octicons name = {icon} size = {30} color = {theme.colors.primary} />
</View>
<Text style = {styles.styledTextInput}>{label}</Text>
<TextInput style = {styles.textInput} {...props} />
</View>
)
}
const styles = StyleSheet.create({
StyledContainer: {
flex: 1,
padding: theme.spacing.m,
paddingTop: theme.spacing.l,
backgroundColor: theme.colors.white,
marginTop: 80,
},
InnerContainer: {
justifyContent: 'center',
alignItems: 'center',
},
PageLogo: {
width: 100,
height: 100,
},
PageTitle: {
...theme.textVariants.h1,
marginTop: theme.spacing.m,
},
TagLine: {
...theme.textVariants.body3,
},
inputFieldView: {
marginTop: 12,
},
styledFormArea: {
justifyContent: 'center',
marginHorizontal: theme.spacing.l,
borderRadius: theme.borderRadius.m,
marginTop: 40,
},
leftIcon: {
position: 'absolute',
zIndex: 1,
marginTop: 28,
marginLeft: 12,
},
styledTextInput: {
...theme.textVariants.body3,
},
textInput: {
backgroundColor: theme.colors.gray,
paddingVertical: 10,
paddingLeft: 50,
paddingRight: theme.spacing.l,
borderRadius: theme.borderRadius.m,
},
loginButton: {
backgroundColor: theme.colors.primary,
alignItems: 'center',
marginTop: 20,
paddingVertical: 8,
borderRadius: theme.borderRadius.m,
},
loginButtonText: {
...theme.textVariants.body2,
color: theme.colors.white,
},
msgBox: {
...theme.textVariants.body3,
alignSelf: 'center',
},
signupLinkView: {
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
padding: theme.spacing.sm,
},
signupText: {
...theme.textVariants.body3,
},
signupLinkButton: {
},
signupLinkText: {
...theme.textVariants.body3,
opacity: 0.6,
},
})
export default SignUp;
Sorry if my code isn't written very well and isn't very organized. I couldn't find very many good tutorials on firebase authentication so this is what I came up with after watching like 5 different firebase authentication tutorials lol. Any help would be greatly appreciated!
Also, here is the link to my github repo if you want to see my entire project file: github repo
You should use redux or React hooks to save user info into global state.
https://reactjs.org/docs/hooks-reference.html#usecontext
https://redux.js.org/introduction/getting-started
In the callback of signInWithEmailAndPassword() return user profile data
firebase.auth().signInWithEmailAndPassword(email, password)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
/* user:
- email
- uid
- displayName
- emailVerified
- phoneNumber
- photoURL
- metadata
...
*/
})
.catch((error) => {
// catch error
});
Then in your components/screens, you can call the state to show user's data.
Hi I'm getting the error undefined is not an object(evaluating 'navigation.navigate') after I'm submitting the form. I searched many google/stackoverflow answers but none of them helped me.
I'm not sure if this is cause by firebase or actual prop navigation. Any insights on this ???
Please see the code below:
// parent component
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import LoginForm from '../components/LoginForm';
const Login = () => {
return (
<View style={styles.mainWrapper}>
<Image style={styles.logo} title="Logo" source={require('../assets/box.png')}/>
<LoginForm/>
</View>
);
}
const styles = StyleSheet.create({
logo: {
width: 150,
height: 150,
marginTop: 55
},
mainWrapper: {
display: "flex",
alignItems: "center"
}
});
export default Login;
// login form component
import React, { useState } from 'react';
import { StyleSheet, Text, View, TextInput, TouchableOpacity, Alert} from 'react-native';
import firebase from 'firebase/app';
import 'firebase/auth';
import { firebaseConfig } from '../config';
if(!firebase.apps.length){
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
}
const auth = firebase.auth();
const LoginForm = ({navigation}) => {
const [email,setEmail] = useState('');
const [password, setPassword] = useState('');
const signIn = async() => {
try {
let response = await auth.signInWithEmailAndPassword(email,password);
if(response.user){
Alert.alert('logged in' + response.user.email);
navigation.navigate('Driver');
}
}catch(e){
Alert.alert(e.message);
}
};
return (
<View style={styles.formView}>
<TextInput
value={email}
placeholder="Email"
style={styles.input}
onChangeText={userEmail => setEmail(userEmail)}
autoCapitalize='none'
keyboardType='email-address'
autoCorrect={false}
/>
<TextInput
value={password}
placeholder="Password"
secureTextEntry={true}
style={styles.input}
onChangeText={userPassword => setPassword(userPassword)}
/>
<TouchableOpacity style={styles.submitBtn} title="Login" onPress={() => signIn()}>
<Text style={styles.appButtonText}>Login</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
formView: {
marginTop: 45,
display: "flex",
alignItems: "center",
},
input: {
marginTop: 20,
width: 300,
height: 40,
paddingHorizontal: 10,
borderRadius: 5,
backgroundColor: 'white',
},
submitBtn: {
backgroundColor: "#FFE17D",
color: "#E6646E",
fontWeight: "bold",
width: 150,
height: 40,
marginTop: 20,
borderColor: "#E6646E",
borderRadius: 5,
display: "flex",
justifyContent: "center",
borderWidth: 1,
},
appButtonText: {
fontSize: 18,
color: "#E6646E",
fontWeight: "bold",
alignSelf: "center",
textTransform: "uppercase"
}
});
Only the stack screens have access to the props navigation. You can try sending navigation to LoginForm but that works only if Login is a Stack Screen.
const Login = ({navigation}) => {
return (
<View style={styles.mainWrapper}>
<Image style={styles.logo} title="Logo" source={require('../assets/box.png')}/>
<LoginForm navigation={navigation}/>
</View>
);
}
Or you can have a look in the useNavigation hook