I have an observer who checks whether the user has logged in, if SO, writes it to the AuthUser variable.
But the variable lives only in the observer
export let authUser = "";
const user = auth.currentUser;
function WatchToUser() {
onAuthStateChanged(auth, (user) => {
if (user) {
authUser = user.email;
} else {
}
});
Later I want to check this user on another page, if he is authorized, then show him the database, if not, then send it to the home page. But on another page, the variable is already an empty string.
It turns out that when switching to another html page, the user disappears, what to do?
showUsers.addEventListener("click", () => {
if (authUser != null && authUser != "") {
window.location.replace("users.html");
} else {
modalVisible("Need to login", isError());
}
});
You can create a function that returns a Promise once Auth state is loaded like this:
function getUser() {
return new Promise((resolve, _) => {
const unsub = onAuthStateChanged(auth, (user) => {
unsub();
return resolve(user) // or throw error is user is not logged in
})
})
}
// await getUser()
However, it seems you are calling a function when a button is click. So the auth state could be loaded already so you could just use currentUser (assuming the page is shown to user only if they are authenticated).
showUsers.addEventListener("click", () => {
const user = auth.currentUser;
if (user) {
window.location.replace("users.html");
} else {
modalVisible("Need to login", isError());
}
});
Related
I need your help.
I have an app. I can login with normal (email and password) and using Google Auth.
When i print my informations to console.log, it successfully prints, but I use firebase and i need to firebase.auth().onStateChanged for control the state.
For example, if i login with email and password, then onstateChanged function works with useEffect, and it redirect homepage (because this function know user has signed in), but when i login with google, i can't inform about user signed in or not because of google.
How can i use both google sign in and firebase? How can i tell firebase, i login with google, there are my informations don't worry.
Here google logs (my google name and googleId):
my codes:
google codes:
const GoogleAuth = () => {
const saveFirebase = (email, uid) => {
return firebase.firestore().collection("users").doc(uid).set({
email: email,
});
};
const onSuccess = (response) => {
const name = response.profileObj.name;
const uid = response.profileObj.googleId;
console.log(uid);
console.log(name);
return saveFirebase(name, uid);
};
const handleClick = () => {
return (
<GoogleLogin
clientId="1093050194946-tcn6k22l190klav7cat182leq09luthu.apps.googleusercontent.com"
buttonText="Login"
onSuccess={onSuccess}
onFailure={onSuccess}
cookiePolicy={"single_host_origin"}
theme="dark"
/>
);
};
return <div className="google-button">{handleClick()}</div>;
};
my constant variables:
const [user, setUser] = useState("");
onAuthStateChanged codes with useEffect:
const authListener = () => {
auth.onAuthStateChanged((user) => {
if (user) {
setUser(user);
setUsername(user.displayName);
} else {
}
});
};
useEffect(() => {
authListener();
});
To check if the user loged in with email or Google just use the providerId from user you get from the onAuthStateChanged like here:
const authListener = () => {
auth.onAuthStateChanged((user) => {
if (user) {
setUser(user);
setUsername(user.displayName);
//Here you can se what provider the user used
console.log('provider',user.providerId)
} else {
}
});
};
I have the following function to get the user id:
currentUser.js
import firebase from './firebase';
export default function getCurrentUserID() {
var user = firebase.auth().currentUser;
var uid;
if (user != null) {
uid = user.uid; // The user's ID, unique to the Firebase project. Do NOT use
// this value to authenticate with your backend server, if
// you have one. Use User.getToken() instead.
return uid;
}
return uid;
}
The following code to enable adding projects using the button, works fine:
addProject.js
import getCurrentUserID from './currentUserID';
import getFirestoreDB from './firestoreDB';
import Project from './project';
const addProjectBtn = document.getElementById('addProjectBtn');
function addProject() {
const title = prompt('Insert title');
const description = prompt('Insert Description');
const project = new Project(title, description);
const db = getFirestoreDB();
const currentUserUID = getCurrentUserID();
alert(currentUserUID);
db.doc(`users/${currentUserUID}/projects/${title}`).set({ ...project }).then(() => {
alert("Success");
}).catch((error) => {
alert("Error " + error);
});
}
export default function enableAddProjectBtnFunctionality() {
addProjectBtn.addEventListener('click', addProject);
}
But, the following code to display projects, doesn't work. The alert(uid) shows undefined here but shows the correct user id above.
displayProjects.js
import getCurrentUserID from "./currentUserID";
import getFirestoreDB from './firestoreDB';
var db = getFirestoreDB();
export default function displayProjects(){
var uid = getCurrentUserID();
if(uid){
alert(uid);
var projectsRef = db.collection("users").doc(`${uid}`).collection("projects");
projectsRef.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
});
}
}
Could someone help me figure out what's the problem here and how I could fix it?
Most likely the displayProjects method is executed before the user sign-in has been completed.
The proper way to pick up the user state in such scenarios is to use an auth state listener as shown in the first code fragment in the documentation on getting the current user.
In your code that'd look like this:
export default function displayProjects(){
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
var uid = user.uid;
var projectsRef = db.collection("users").doc(`${uid}`).collection("projects");
projectsRef.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
});
});
}
});
}
handleSubmit function called in onClick of a button
handleSubmit = async (name) => {
let registerResponse = await registerAPI(this.state)
const resultResponse = await registerResponse.json()
console.log(registerResponse)
console.log(resultResponse)
if (registerResponse.status === 200) {
const userInfo = {
hasura_id: resultResponse.hasura_id,
name: name
}
let setUserResponse = await setUserAPI(userInfo)
const resultResponseSetUser = await setUserResponse.json()
console.log(setUserResponse)
console.log(resultResponseSetUser)
if (setUserResponse["affected_rows"]) {
this.setRegisterError('')
}
else {
this.setRegisterError(resultResponseSetUser.message)
}
}
else {
this.setRegisterError(resultResponse.message)
}
}
setRegisterError function is supposed to change the state of error and if there's no error it's supposed to navigate to a new screen
setRegisterError = error => {
// If there's an error display that, otherwise send to new screen to tell the user to verify email address and then login
this.setState({error})
if(error === '') {
this.props.navigation.navigate('PostRegister')
}
}
I have the following code which check the user_id if available and then log me in but it logs me in only if I refresh the app. Any idea how to make this happen without this?
This is the order of functions:
First when you click the login button from Login.js:
<TouchableOpacity onPress={handleSubmit(_signIn)} style={{margin: 10, alignItems: 'center'}}>
then _signIn function which is in Login.js
_signIn = (values, dispatch) => {
const email = values.email;
const password = values.password;
dispatch(loginUser(email, password));
}
Now we dispatched email and password to loginUser from authActions.js
export function loginUser(email, password) {
return function (dispatch) {
return axios.post(SIGNIN_URL, { email, password }).then((response) => {
var { user_id, token } = response.data;
onSignIn(user_id); // Here I pass 'user_id' to onSignIn function
}).catch((error) => {
dispatch(addAlert("Could not log in."));
});
};
}
Now we get the user_id from loginUser inside Auth.js
import { AsyncStorage } from "react-native";
const USER_KEY = "auth_key";
export const onSignIn = (user_id) => AsyncStorage.setItem(USER_KEY, user_id);
export const onSignOut = () => AsyncStorage.removeItem(USER_KEY);
export const isSignedIn = () => {
return new Promise((resolve, reject) => {
AsyncStorage.getItem(USER_KEY)
.then(res => {
if (res !== null) {
resolve(true);
} else {
resolve(false);
}
})
.catch(err => reject(err));
});
};
Now in App.js I am calling the function isSignedIn to check if user_id is available and if so will choose which screen to show
constructor(props) {
super(props);
this.state = {
signedIn: false,
checkedSignIn: false
};
}
componentDidMount() {
isSignedIn()
.then(res => this.setState({ signedIn: res, checkedSignIn: true }))
.catch(err => alert("An error occurred"));
}
render() {
const { checkedSignIn, signedIn } = this.state;
// If we haven't checked AsyncStorage yet, don't render anything (better ways to do this)
if (!checkedSignIn) {
return null;
}
const Layout = createRootNavigator(signedIn);
It`s not async function callback issue - I do know how to use it, coz you are already use it in the isSignedIn function.
You did called onSignIn(userId), but you inform nobody about it. Those function, that calls isSignedIn should somehow know about a user logged in.
Based on this issue and previous one, I guess you should choose an architecture of your app (redux or just functional programming or something else) and keep it in mind.
If you wanna use redux, you should dispatch an action about a user logged in and reflect to state change where you need it.
This may seem like an obvious question, but i'm having trouble creating a user inside of my Firebase db. I'm very new to firebase and coding for that matter.
How I understand it to be is when a user clicks the sign up button, a user with the newly authenticated uid will be created under 'object/users". However the user is always null. In the google documentation it says that sometimes the user is null because it hasn't finished initializing the user. And to put it inside of onAuthStateChanged. This works, however, if I did this a user would be created/overwritten every time they log in or log out.
I suppose what I'm looking for is some solution to create a user inside of my firebase db when a user first signs up with valid information.
Here is my code:
function LoginCtrl($scope) {
$scope.txtEmail = document.getElementById('txtEmail');
$scope.txtPassword = document.getElementById('txtPassword');
$scope.btnLogin = document.getElementById('btnLogin');
$scope.btnSignUp = document.getElementById('btnSignUp');
$scope.btnLogout = document.getElementById('btnLogout');
btnLogin.addEventListener('click', e => {
const email = txtEmail.value;
const pass = txtPassword.value;
const auth = firebase.auth();
const promise = auth.signInWithEmailAndPassword(email, pass);
promise.catch(e => console.log(e.message));
});
btnSignUp.addEventListener('click', e => {
const email = txtEmail.value;
const pass = txtPassword.value;
const auth = firebase.auth();
const promise = auth.createUserWithEmailAndPassword(email, pass);
promise.catch(e => console.log(e.message));
createUser();
});
function createUser() {
var user = firebase.auth().currentUser;
if (user != null) {
const dbRefObject = firebase.database().ref().child('object');
const dbRefList = dbRefObject.child("users/" + user.uid);
dbRefList.set({
name: "jim",
});
}
}
btnLogout.addEventListener('click', e => {
firebase.auth().signOut();
});
firebase.auth().onAuthStateChanged(firebaseUser => {
if (firebaseUser) {
console.log(firebaseUser);
btnLogout.classList.remove('hide');
btnLogin.classList.add('hide');
} else {
console.log('not logged in');
btnLogout.classList.add('hide');
btnLogin.classList.remove('hide');
}
})
}
The culprit is in these three lines:
const promise = auth.createUserWithEmailAndPassword(email, pass);
promise.catch(e => console.log(e.message));
createUser();
You are firing off createUser() too soon. In the above code fragment, this happens right after starting the (asynchronous) registration process – the SDK never had a chance to actually create the user in the auth database!
The createUserWithEmailAndPassword returns a promise, as reflected in your local variable. What you need to do here is chaining the two calls, i.e. start the database manipulation after the promise is fulfilled.
Try this:
// inside the click handler
btnSignUp.addEventListener('click', e => {
const email = txtEmail.value;
const pass = txtPassword.value;
const auth = firebase.auth();
auth.createUserWithEmailAndPassword(email, pass)
.then(user => createUser(user)) // <-- important!
.catch(e => console.log(e.message));
});
function createUser(user) {
// no need for currentUser if you pass it in as an argument
if (user) {
...
}
}