React Native Google / Facebook Login - javascript

I'm quit new in React native but I would like to set up Google login but what I did didn't seem to work.
(That will be a long post haha )
For Google Login:
I tried several tutorials on YouTube (this one for example: https://www.youtube.com/watch?v=DN9dQ_6ezvA)
"Request is missing required authentication credential. Expected OAuth
2 access token, login cookie or other valid authentication credential.
See
https://developers.google.com/identity/sign-in/web/devconsole-project."
I tried a lot of thing but it's really hard for me. So if someone could give me some help? Thanks you in advance guys, I continue the research on my side
Here is my code:
WebBrowser.maybeCompleteAuthSession();
export default function GoogleFunc({largeur}) {
const fontRegular = require("../../assets/Manrope-Regular.ttf");
const fontBold = require("../../assets/Manrope-Bold.ttf");
const [fontsLoaded] = useFonts({
ManropeRegular: fontRegular,
ManropeBold: fontBold,
});
const [accessToken, setAccessToken] = React.useState();
const [userInfo, setUserInfo] = React.useState();
const [request, response, prompAsync] = Google.useIdTokenAuthRequest({
androidClientId:
"ANDROID_CLIENT_ID",
iosClientId:
"CLIENT_CLIENT_ID",
clientId:
"CLIENT_ID",
});
React.useEffect(() => {
if (response?.type === "success") {
console.log("response: ", response.params);
setAccessToken(response.params.id_token);
accessToken && fetchUserInfo();
}
}, [response, accessToken]);
async function fetchUserInfo() {
console.log("test222");
let response = await fetch("https://www.googleapis.com/userinfo/v2/me", {
headers: {Authorization: `Bearer ${accessToken}`},
});
const useInfo = await response.json();
console.log("useinfo: ", useInfo);
setUserInfo(useInfo);
}
const ShowUserInfo = () => {
if (userInfo) {
console.log("userinfooofofof: ", userInfo);
return (
<View style={styles.userInfo}>
<Image source={{uri: userInfo.picture}} style={styles.profilePic} />
<Text>Welcome {userInfo.name}</Text>
<Text>{userInfo.email}</Text>
</View>
);
}
};
return (
<View style={styles.container}>
{userInfo && <ShowUserInfo />}
{userInfo == null && (
<>
<TouchableOpacity
style={[styles.googleBtn, {width: largeur}]}
disabled={!request}
onPress={() => {
prompAsync();
}}
>
<Image
style={{
height: height * 0.024,
width: width * 0.057,
left: width * 0.035,
top: height * 0.013,
}}
source={require("../../assets/images/google-logo.png")}
/>
<Text
style={{
textAlign: "center",
fontFamily: "ManropeSemiBold",
fontSize: 17,
color: "#262626",
bottom: height * 0.01,
}}
>
Continuer avec Google
</Text>
</TouchableOpacity>
</>
)}
</View>
);
}
For Facebook:
I tried to set up the login with / without firebase but I already got the same issue : an error ...
I'm trying to solve it since last week but I don't understand how can i fix these problems ...
Here's my code without Firebase:
import React, {useState} from "react";
import {
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
ActivityIndicator,
} from "react-native";
import * as Facebook from "expo-facebook";
export default function FacebookFunc() {
const [isLoggedin, setLoggedinStatus] = useState(false);
const [userData, setUserData] = useState(null);
const [isImageLoading, setImageLoadStatus] = useState(false);
async function faceookLogIn() {
try {
await Facebook.initializeAsync({
appId: "APP ID",
});
const {type, token, expirationDate, permissions, declinedPermissions} =
await Facebook.logInWithReadPermissionsAsync({
permissions: ["public_profile"],
});
if (type === "success") {
// Get the user's name using Facebook's Graph API
const response = await fetch(
`https://graph.facebook.com/me?access_token=${token}`
);
Alert.alert("Logged in!", `Hi ${(await response.json()).name}!`);
} else {
// type === 'cancel'
}
} catch ({message}) {
alert(`Facebook Login Error: ${message}`);
}
}
logout = () => {
setLoggedinStatus(false);
setUserData(null);
setImageLoadStatus(false);
};
return isLoggedin ? (
userData ? (
<View style={styles.container}>
<Image
style={{width: 200, height: 200, borderRadius: 50}}
source={{uri: userData.picture.data.url}}
onLoadEnd={() => setImageLoadStatus(true)}
// GERER QUAND MARCHERA
/>
<ActivityIndicator
size={"large"}
color={"#0000ff"}
animating={!isImageLoading}
style={{position: "absolute"}}
/>
<Text style={{fontSize: 22, marginVertical: 10}}>
Hi {userData.name}!
</Text>
<TouchableOpacity style={styles.logoutBtn} onPress={logout}>
<Text style={{color: "#fff"}}>Logout</Text>
</TouchableOpacity>
</View>
) : null
) : (
<View style={styles.container}>
<TouchableOpacity style={styles.loginBtn} onPress={faceookLogIn}>
<Text style={{color: "#fff", textAlign: "center"}}>
Login with facebook
</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {},
loginBtn: {
backgroundColor: "#4267b2",
paddingVertical: 10,
borderRadius: 10,
width: "95%",
},
logoutBtn: {
backgroundColor: "grey",
includeFontPadding: 10,
paddingHorizontal: 20,
borderRadius: 20,
position: "absolute:",
bottom: 0,
marginBottom: 200,
},
});
And here my code when I trying with Firebase:
The error:
Possible Unhandled Promise Rejection (id: 0):
TypeError: null is not an object (evaluating 'LoginManager.logInWithPermissions')
The code:
import React from "react";
import {LoginManager, AccessToken} from "react-native-fbsdk-next";
import {
StyleSheet,
View,
Text,
Image,
TouchableOpacity,
Button,
} from "react-native";
import {
getAuth,
signInWithCredential,
FacebookAuthProvider,
} from "firebase/auth";
import "expo-dev-client";
import app from "./firebaseSetup";
export default function App() {
const SignInWithFB = async () => {
const result = await LoginManager.logInWithPermissions([
"public_profile",
"email",
]);
if (result.isCancelled) {
throw new Error("User cancelled login");
}
const data = await AccessToken.getCurrentAccessToken();
if (!data) {
throw new Error("Something went wrong obtaining access token");
}
const auth = getAuth(app);
const credential = FacebookAuthProvider.credential(data.accessToken);
const user = await signInWithCredential(auth, credential);
console.log(user);
};
return (
<View>
<Button title="Sign in with facebook" onPress={SignInWithFB}></Button>
</View>
);
}
const styles = StyleSheet.create({});
I initialize my firebaseSetup like this:
import {initializeApp} from "firebase/app";
// Initialize Firebase
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
};
const app = initializeApp(firebaseConfig);
export default app;
I continue my research by my side but if someone could help me with this problem (which is probably stupid), thanks you in advance...
PS: There is the error for Facebook without firebase:
Facebook Login Error: undefined is not an object (evaluating'_ExponentFacebook.default.InitializeAsync')

You have to use expo auth session to implement oAuth in Expo
import React,{useState} from 'react';
import { useNavigation } from "#react-navigation/native";
import Fontisto from '#expo/vector-icons/Fontisto';
import { TouchableOpacity,StyleSheet, Alert } from 'react-native';
import * as WebBrowser from 'expo-web-browser';
import * as Facebook from 'expo-auth-session/providers/facebook';
import {makeRedirectUri, ResponseType } from 'expo-auth-session';
import { useDispatch } from "react-redux";
WebBrowser.maybeCompleteAuthSession();
export default function FacebookAuth(){
const [isLoading, setIsLoading] = useState(false);
const navigation = useNavigation();
const dispatch = useDispatch();
const [request, response, promptAsync] = Facebook.useAuthRequest({
responseType: ResponseType.Token,
clientId: 'YOUR_CLIENT_ID',
scopes: ['public_profile', 'email'],
redirectUri: makeRedirectUri({ useProxy: true })
},
{ useProxy: true });
React.useEffect(() => {
if (response?.type === 'success') {
setIsLoading(true);
const accessToken = response.authentication.accessToken;
console.log(accessToken);
}
}, [response]);
return(
<>
<TouchableOpacity disabled={!request} style={styles.socialLoginButton}
onPress={() => {
promptAsync();
}}
>
<Fontisto name='facebook' color={'white'} size={25}/>
</TouchableOpacity>
</>
)
}
const styles = StyleSheet.create({
socialLoginButton:{
margin:3,
backgroundColor:'blue',
padding:10,
borderRadius:50,
width:50,
height:50,
justifyContent:'center',
alignItems:'center',
margin:10,
}
})
Here's the code for it, you have to configure it according to your needs.
here's the link for expo auth session. - here

For login with Google, I think the problem lies with this code:
React.useEffect(() => {
if (response?.type === "success") {
setAccessToken(response.params.id_token);
accessToken && fetchUserInfo();
}
}, [response, accessToken]);
You use the id_token from the response, and you should be using the access token. Also, I think you could split this into two useEffect methods:
React.useEffect(() => {
if (response?.type === "success") {
setAccessToken(response.params.access_token);
}
}, [response]);
React.useEffect(() => {
fetchUserInfo();
}, [accessToken]);
The other effect will trigger only when the state of accessToken changes. If it's possible that you change the state to an empty value then you should retain the null check.
As for Facebook and Firebase issues — are you sure you followed all the required setup for these libraries? Just skimming through the documentation shows that there are quite a few things that should be configured before you can call the libs. From your error messages, it seems that the libraries are not configured and initialized properly.

Related

Yelp Api business search not working in react native using axios - returns an empty array

Having trouble getting the yelp api to work, it is supposed to search for businesses based on the set of term. I am using a async await function to GET the businesses/search object, then I am setting my params then updating state using setResults
import React, { useState } from "react";
import { View, Text, StyleSheet } from "react-native";
import SearchBar from "../components/SearchBar";
import yelp from "../api/yelp";
const SearchScreen = () => {
const [term, setTerm] = useState("");
const [results, setResults] = useState([]);
console.log(results);
console.log(term);
const searchApi = async () => {
try {
const response = await yelp.get("/search", {
params: {
limit: 50,
term,
location: "san jose",
},
});
setResults(response.data.businesses);
} catch (err) {
console.log(err);
}
};
return (
<View style={styles.background}>
<SearchBar term={term} onTermChange={setTerm} onTermSubmit={searchApi} />
<Text>We have found {results.length} results </Text>
</View>
);
};
const styles = StyleSheet.create({});
export default SearchScreen;
Here is the SearchBar component
import React from "react";
import { View, TextInput, StyleSheet } from "react-native";
import { Feather } from "#expo/vector-icons";
const SearchBar = ({ term, onTermChange, onTermSubmit }) => {
return (
<View style={styles.backgroundStyle}>
<Feather name="search" style={styles.iconStyle} />
<TextInput
autoCapitalize="none"
autoCorrect={false}
style={styles.inputStyle}
placeholder="Search"
value={term}
onChangeText={onTermChange}
onEndEditing={onTermSubmit}
/>
</View>
);
};
const styles = StyleSheet.create({
backgroundStyle: {
backgroundColor: "#FFF",
height: 50,
borderRadius: 5,
marginHorizontal: 15,
top: 15,
flexDirection: "row",
marginBottom: 20
},
inputStyle: {
flex: 1,
borderRadius: 5,
fontSize: 18,
},
iconStyle: {
fontSize: 35,
alignSelf: "center",
marginHorizontal: 15,
},
});
export default SearchBar;
And here is where I used axios to set the baseUrl and header
import axios from "axios";
export default axios.create({
baseURL: "https://api.yelp.com/v3/businesses",
headers: {
Authorization:
"BearerZPzXkPFyF_mWgHVjj_a1QZqiFkktt_iXYcX8JED6Gp2i73aYJTsvfUSApIVh7w8B8CNYfwnvBKo50MZvR34dvO3Cm1tQxlFp_PnGgCFjce1h0I1UF3zcKHnr7eq8YnYx",
},
});
Any Help is greatly appreciated I console.logged the results and term to make sure all my state is working and it is so it has to be some issue with how i'm getting the yelp api. My results always return an empty array.
When Console logged
the {result} just shows an empty array the starting state –
the {term} shows the state of whatever has been typed
Expected result
the {result} is supposed to show an arrays of objects matching "pasta" in the San Jose area and the number in the Text is supposed to show results.length
I tried your repo. At first I got a 401 error because of no space in the auth token
sdk_gphone_x86_arm:
Error: "Request failed with status code 401" in
Then I got 400 for an invalid token
sdk_gphone_x86_arm:
start
sdk_gphone_x86_arm:
Error: "Request failed with status code 400" in
After corrected both, the app runs successfully, you can try it in
https://snack.expo.dev/#anthnoycc/searchscreen

React Component Not Re Rendering using Spread Operator

I've tried other solutions on this site, but I am not sure why this is not working. I have a response I am getting from a server each time a button is pressed. The response comes through fine and I am able to see it each time the button is pressed. I am receiving an array of objects from the server, and I am using the useState hook to set the state of a variable to keep track of the objects in the array. However, the component does not re render. Interestingly, if I add a console.log statement to see the contents of the state variable and then save the page, I can see that the state variable was updated properly. The component still does not re render though. The relevant code is here:
import React, { useEffect, useState } from "react";
import { StyleSheet, View, TouchableOpacity, Alert } from "react-native";
import tailwind from "tailwind-rn";
import colors from "../config/colors";
import useAuth from "../hooks/useAuth";
import Screen from "../components/Screen";
import AppText from "../components/AppText";
import { MaterialCommunityIcons } from "#expo/vector-icons";
import { getData } from "../hooks/useCache";
import { useIsFocused } from "#react-navigation/native";
import ListScreen from "./ListScreen";
const ProfileScreen = () => {
const { logout, user } = useAuth();
const [likes, setLikes] = useState("");
const [completed, setCompleted] = useState("");
const [responseJson, setResponseJson] = useState(null);
const isFocused = useIsFocused();
useEffect(() => {
const likesFunc = async() => {
setLikes(await getData("likes"));
setCompleted(await getData("eventsCompleted"));
try {
const response = await fetch(
"server url here",
{
headers: { Authorization: "Bearer " + user.idToken },
}
);
const responseJson = await response.json();
setLikes(responseJson.likes);
setCompleted(responseJson.eventsCompleted);
} catch {
Alert.alert("There has been an error processing your profile");
}
}
likesFunc();
}, []);
//get voted events
//run when questionsLeft is 0 to save num of calls
useEffect(() => {
const eventFunction = async() => {
try {
const response = await fetch(
"server url here",
{
headers: { Authorization: "Bearer " + user.idToken },
}
)
const res = await response.json();
setResponseJson([...res]);
} catch (error) {
Alert.alert(
"An error has occurred loading your questions. Close the app and try again."
);
console.log(error);
}
}
eventFunction();
}, [isFocused]);
return (
<Screen style={styles.bg}>
<View
style={[
tailwind("w-full flex-row py-4 justify-center items-center top-0"),
{ justifyContent: "space-between" },
]}
>
<AppText style={{ color: colors.white, fontSize: 30, marginLeft: 5 }}>
Hello, {user.displayName.split(" ")[0]}
</AppText>
<TouchableOpacity
style={styles.logoutButton}
onPress={() => {
Alert.alert("Log Out", "Are you sure you want to log out?", [
{
text: "Yes",
style: "destructive",
onPress: logout,
},
{
text: "Cancel",
style: "cancel",
},
]);
}}
>
<MaterialCommunityIcons
name="logout-variant"
size={25}
color={colors.primary}
/>
</TouchableOpacity>
</View>
<View
style={tailwind("w-full h-1/5 justify-center items-center")}
>
<View
style={[
tailwind("w-full flex-row p-10 justify-center"),
{ justifyContent: "space-between" },
]}
>
<View style={tailwind("justify-center items-center")}>
<AppText style={{ textDecorationLine: "underline" }}>
Total Likes
</AppText>
<AppText style={{ paddingVertical: 10 }}>{likes}</AppText>
</View>
<View style={tailwind("justify-center items-center")}>
<AppText style={{ textDecorationLine: "underline" }}>
Completed
</AppText>
<AppText style={{ paddingVertical: 10 }}>{completed}</AppText>
</View>
</View>
</View>
<View
style={tailwind("w-full h-4/5 flex-1 items-center")}
>
{responseJson == null ?
<AppText style={tailwind("mt-10")}>
Select events on the "Discover" page!
</AppText>
:
<ListScreen caller={{"sender": "profile", "json": responseJson}}/>
}
</View>
</Screen>
);
};
export default ProfileScreen;
const styles = StyleSheet.create({
logoutButton: {
color: colors.white,
paddingTop: 20,
paddingRight: 10,
},
bg: {
flex: 1,
backgroundColor: colors.black,
},
});
Update: If I set the state twice in a row, it works:
setResponseJson(null);
setResponseJson([...res]);
However, this is somewhat buggy and not optimal. Leads me to think it still is a reference issue, but I am not sure why the spread operator technique does not fix this.
Three things are wrong/weird in your code. Not sure it will fix your problem but here are they :
1- Do not pass an async function to the useEffect. Instead, create an async function inside and call it :
useEffect(() => {
const myFunc = async => {...};
myFunc();
},[]);
2- You are receiving an array of objects from your api call, so why do you want to spread it ? It would lead to multiple objects inside your state, which doesn't seems right. Just pass your res in your state as is or format it as you want.
3- You are mixing async/await pattern with the .then. Either use an async func and await the result :
const myFunc = async () => {
const resPromise = await fetch(...);
const json = await resPromise.json();
...
}
or only use the .then:
const myFunc = () => {
fetch(...)
.then(data => data.json())
.then(json => ...);
...
}

Firebase v9 not adding docs

I'm working with Firebase v9. The authentication works fine, but the Firestore does not work me for some reason. I don't even get an error--it just doesn't do anything.
I tried addDocs() but still nothing works.
EDIT: actually , i was using the firebase #9.1.0 i upgraded it to #9.6.7 and it worked perfectly fine ! i had to downgrade from #9.6.8 ( the latest ) to #9.1.0 because of the error ( Can't find variable: IDBIndex ) !
import React, { useLayoutEffect, useState } from "react";
import {
Text,
View,
StyleSheet,
TextInput,
TouchableOpacity,
KeyboardAvoidingView,
Platform,
ScrollView,
Alert,
} from "react-native";
import { AntDesign, Ionicons } from "#expo/vector-icons";
import { doc, setDoc } from "firebase/firestore";
import { db } from "../../firebase/firebaseConfig";
const NewChat = ({ navigation }) => {
const [input, setInput] = useState("");
useLayoutEffect(() => {
navigation.setOptions({
title: "Add a new Chat",
headerBackTitle: "Chats",
});
}, [navigation]);
const AddChat = async () => {
const myDoc = doc(db, "Chats", input);
const docData = {
chatName: input,
};
setDoc(myDoc, docData).then(() => {
navigation.goBack();
});
};
return (
<ScrollView>
<View
style={{
marginTop: 20,
marginHorizontal: 20,
borderColor: "black",
borderWidth: 1,
}}
>
<View style={styles.container}>
<AntDesign
name="wechat"
size={40}
color="black"
style={{ alignSelf: "center" }}
/>
<TextInput
placeholder="Enter a chat name"
value={input}
onChangeText={(text) => {
setInput(text);
}}
style={{ flexGrow: 1, marginLeft: 20 }}
/>
<TouchableOpacity style={{ alignSelf: "center" }} onPress={AddChat}>
<Ionicons name="checkmark-done-circle" size={40} color="black" />
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: "row",
backgroundColor: "white",
justifyContent: "center",
height: 60,
},
});
export default NewChat;
The function setDoc() asynchronously returns a promise which means all you're missing is the await keyword before you call the function.
const AddChat = async () => {
const myDoc = doc(db, "Chats", input);
const docData = {
chatName: input,
};
await setDoc(myDoc, docData).then(() => {
navigation.goBack();
});
};
Edit: I think I see the real problem, It has to do with the v9 document reference. Try using collection() within the document reference.
const AddChat = async () => {
const myDoc = doc(collection(db, "Chats"), input);
const docData = {
chatName: input,
};
await setDoc(myDoc, docData).then(() => {
navigation.goBack();
});
};

Format for registration of account in firebase via expo and how do i code my code to catch errors when creating new user via app

firebase.js:
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
import {getAuth} from "firebase/auth";
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: ****,
authDomain: ****,
projectId: ****,
storageBucket: ****,
messagingSenderId: ****,
appId: ****
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
export const auth = getAuth()
loginScreen.js
import { auth } from '../firebase'
import { createUserWithEmailAndPassword } from "firebase/auth"
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSignUp = async () => {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log(user);
}
New error appears when I key in the following: Email: Test#test.com, password:test
I have also refresh the firebase authentication page, no new user is added it. Also, I am referring to the guide: https://www.youtube.com/watch?v=ql4J6SpLXZA and in the video, the creator used 'matt#test.com' for email and it worked but when I try to do the same it has the warning problem and it is not synced in the firebase authentication table
How can I solve this problem?
Also, in this case, how can I code my loginscreen.js to catch when register fail?
I really need some help/advice on this. Thank you!
LoginScreen.js (Entire thing)
import { KeyBoardAvoidingView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'
import React, { useEffect, useState } from 'react'
import KeyboardAvoidingView from 'react-native/Libraries/Components/Keyboard/KeyboardAvoidingView'
import { auth } from '../firebase'
import { createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth"
import { useNavigation } from '#react-navigation/core'
const LoginScreen = () => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const navigation = useNavigation()
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
if(user){
navigation.replace("Home")
}
})
return unsubscribe
})
const handleSignUp = async () => {
try {
if (email && password) {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log('Registered as :' , user.email);
}
} catch (error) {
console.log({error});
}
}
const handleLogin = async () => {
try {
if (email && password) {
const { user } = await signInWithEmailAndPassword(auth, email, password)
console.log('Logged in as :' , user.email);
}
} catch (error) {
console.log({error});
}
}
return (
<KeyboardAvoidingView //To prevent keyboard from blocking the writing area
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 //Hide password
/>
</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 LoginScreen
const styles = StyleSheet.create({ //To make the text area for username and password to be center. If not it will be at the top left hand corner
container:{
flex:1,
justifyContent: 'center',
alignItems:'center',
},
inputContainer:{
width: '80%'
},
input:{ //Not working?
backgroundColor: 'white',
paddingHorizontal: 15,
paddingVertical: 10,
borderRadius: 10, //make edge more circle
marginTop: 5, //Spacing between the input boxes
},
buttonContainer:{
width: '60%',
justifyContent: 'center',
alignItems : 'center',
marginTop: 40,
},
button:{
backgroundColor: '#0782F9',
width: '100%',
padding: 15, //Making the button enlarge in horizontal and vertical
borderRadius: 10,
alignItems: 'center',
},
buttonOutline:{
backgroundColor: 'white',
marginTop: 5,
borderColor: '#0782F9',
borderWidth: 2, //Without the width, the colour won't show
},
buttonText:{ //For the login button
color: 'white',
fontWeight:'700',
fontSize: 16,
},
buttonOutlineText:{ //For the register button
color: '#0782F9',
fontWeight:'700',
fontSize: 16,
},
})
To avoid crashes I prefer you add try catch to your code like this:
import { auth } from '../firebase'
import { createUserWithEmailAndPassword } from "firebase/auth"
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSignUp = async () => {
try {
if (email && password) {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log(user);
}
} catch (e) {
console.log({e});
}
}
For error messages:
import { KeyBoardAvoidingView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'
import React, { useEffect, useState } from 'react'
import KeyboardAvoidingView from 'react-native/Libraries/Components/Keyboard/KeyboardAvoidingView'
import { auth } from '../firebase'
import { createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth"
import { useNavigation } from '#react-navigation/core'
const LoginScreen = () => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [showError, setShowError] = useState(false);
const navigation = useNavigation()
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
if(user){
navigation.replace("Home")
}
})
return unsubscribe
})
const handleSignUp = async () => {
try {
if (email && password) {
setShowError(false);
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log('Registered as :' , user.email);
}
} catch (error) {
console.log({error});
setShowError(true);
}
}
const handleLogin = async () => {
try {
if (email && password) {
const { user } = await signInWithEmailAndPassword(auth, email, password)
console.log('Logged in as :' , user.email);
}
} catch (error) {
console.log({error});
}
}
return (
<KeyboardAvoidingView //To prevent keyboard from blocking the writing area
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 //Hide password
/>
</View>
{showError && <View style={styles.error}>
<Text>Wrong username or password</Text>
</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 LoginScreen
const styles = StyleSheet.create({ //To make the text area for username and password to be center. If not it will be at the top left hand corner
container:{
flex:1,
justifyContent: 'center',
alignItems:'center',
},
inputContainer:{
width: '80%'
},
input:{ //Not working?
backgroundColor: 'white',
paddingHorizontal: 15,
paddingVertical: 10,
borderRadius: 10, //make edge more circle
marginTop: 5, //Spacing between the input boxes
},
buttonContainer:{
width: '60%',
justifyContent: 'center',
alignItems : 'center',
marginTop: 40,
},
button:{
backgroundColor: '#0782F9',
width: '100%',
padding: 15, //Making the button enlarge in horizontal and vertical
borderRadius: 10,
alignItems: 'center',
},
buttonOutline:{
backgroundColor: 'white',
marginTop: 5,
borderColor: '#0782F9',
borderWidth: 2, //Without the width, the colour won't show
},
buttonText:{ //For the login button
color: 'white',
fontWeight:'700',
fontSize: 16,
},
buttonOutlineText:{ //For the register button
color: '#0782F9',
fontWeight:'700',
fontSize: 16,
},
error: {
backgroundColor: 'red',
padding: 16,
textAlign: 'center'
},
})
I'd recommend handling some common errors such as short password or invalid email format locally using Javascript than to make an API call everytime without validation.
const handleSignUp = async () => {
if (email && password.length >= 8) {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log(user);
} else {
console.log("Please enter a valid email and password")
}
}

How to upload file in React native with imagepack

I would like to upload an image on the server, it appears in the preview, but it is sent in request.body, but I would like it to be sent in request.file. What am I doing wrong? I send it to the web in react and I have no problems, only in native react. When I send in request.body, the file goes as [Object] [Object], but I would like to extract the path and image from the file sent via mobile.
index.js
import React, { useState, useEffect } from "react";
import { useNavigation } from "#react-navigation/native";
import * as ImagePicker from "expo-image-picker";
import Constants from "expo-constants";
import {
View,
Image,
TextInput,
Text,
TouchableOpacity,
Picker,
ScrollView,
Alert,
} from "react-native";
import api from "../../services/api";
import logoImg from "../../assets/icon.png";
import styles from "./styles";
export default function NewProvider() {
const [name, setName] = useState("");
const [avatar, setAvatar] = useState(null);
const [pickerVisible, setPickerVisible] = useState(false);
const [loading, setLoading] = useState(false);
async function handleSubmit() {
try {
setLoading(true);
let localUri = avatar.uri;
let filename = localUri.split("/").pop();
let match = /\.(\w+)$/.exec(filename);
let typeImg = match ? `image/${match[1]}` : `image`;
let formdata = new FormData();
formdata.append("avatar", {
type: typeImg,
uri: localUri,
name: filename,
});
formdata.append("name", name);
await api.post("/providers", formdata, {
headers: {
"Content-Type": "multipart/form-data",
},
});
} catch (err) {
console.log(err)
}
setLoading(false);
}
async function getPermissionAsync() {
if (Constants.platform.ios) {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (status !== "granted") {
alert("Sorry, we need camera roll permissions to make this work!");
}
}
}
async function pickImage(e) {
try {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
base64: true,
});
if (!result.cancelled) {
setAvatar(result);
}
} catch (err) {
console.log("erro", err);
}
}
useEffect(() => {
getPermissionAsync();
}, []);
return (
<View style={styles.container}>
<View style={styles.header}>
<Image style={styles.logoImage} source={logoImg} />
</View>
<Text style={styles.loginTitle}>Cadastrar prestador de serviço</Text>
<View style={styles.login}>
<ScrollView
vertical
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ paddingHorizontal: 20 }}
>
<TextInput
placeholder="* Nome do(a) prestador(a)/empresa"
onChange={(e) => setName(e.target.value)}
style={styles.inputForm}
value={name}
/>
<View
style={{ flex: 1, alignItems: "center", justifyContent: "center" }}
>
<TouchableOpacity style={styles.getImage} onPress={pickImage}>
<Text style={styles.imageText}>Selecione uma imagem</Text>
</TouchableOpacity>
{avatar && (
<Image
source={{ uri: avatar.uri }}
style={{ width: 200, height: 200, marginTop: 20 }}
/>
)}
</View>
<TouchableOpacity style={styles.action} onPress={handleSubmit}>
<Text style={styles.actionText}>
{loading ? "Enviando..." : "Cadastrar"}
</Text>
</TouchableOpacity>
</ScrollView>
</View>
</View>
);
}
Bye looking at your code I think there is a better way of doing it.
First I recommend creating a function to handleImageUpload
as shown below
handleUploadPhoto = () => {
fetch("http://localhost:3000/api/upload", {
method: "POST",
body: createFormData(this.state.photo, { userId: "123" })
})
.then(response => response.json())
.then(response => {
console.log("upload succes", response);
alert("Upload success!");
this.setState({ photo: null });
})
.catch(error => {
console.log("upload error", error);
alert("Upload failed!");
});
};
This will force react native to send Image as request.file not request.file and if that all goes well it check your console and see if it says SUCSESS!
And to call it, you could use something like this
<Button title="Upload" onPress={this.handleUpload} />
Now remember THIS IS AN EXAMPLE change it to your needs.

Categories

Resources