I cannot save data to the database after creating user authentication - javascript

I cannot save data to the database after creating user authentication on firebase, the following error appears on the console: "TypeError: firebase.auth (...). CurrentUser is null". it seems that the code cannot read the user's uid after creating the authentication
the code:
createUserButton.addEventListener('click', function(){
firebase.auth().createUserWithEmailAndPassword(emailInput.value, passwordInput.value)
var user = {
nome: "Pedro",
sobrenome: "Ribeiro",
cpf: "946.201.340-31",
uid: firebase.auth().currentUser.uid,
email: emailInput.value,
password: passwordInput.value
}
writeUserData(user)
.catch(function(error) {
// Handle Errors here.
})
})
function writeUserData(user) {
firebase.database().ref('users/' + firebase.auth().currentUser.uid).set(user).catch(error =>{
console.log(error.message)
})
}
what needs to be changed so that the code can read the user's uid and save the data in the database?

You're not waiting until the new user creation process is complete before writing the database. createUserWithEmailAndPassword returns a promise which resolves when the work is done. It will give you a UserCredential object to work with.
firebase.auth().createUserWithEmailAndPassword(emailInput.value, passwordInput.value)
.then(userCredential => {
// write the database here
})
.catch(error => {
// there was an error creating the user
})

Related

Retrieve an array from a Firestore document and store it to Node.Js then use it as tokens to send notifications

I've been trying to figure this out for hours and I just can't. I'm still a beginner with Node.js and Firebase. I need your help to be able to retrieve the tokens array in my "userdata" collection to Node.js and be able to use it to send notifications in the Cloud Function. So far this is what I've been working on. Here is what my database looks like:
The receiverId is gathered from when I have an onCreate function whenever a user sends a new message. Then I used it to access the userdata of a specific user which uses the receiverId as their uid.
In the cloud function, I was able to start the function and retrieve the receiverId and print the userToken[key]. However, when I try to push the token it doesnt go through and it results in an error that says that the token is empty. See the image:
Your help would mean a lot. Thank you!
newData = snapshot.data();
console.log("Retrieving Receiver Id");
console.log(newData.receiverId); //uid of the user
const tokens = [];
const docRef = db.collection('userdata').doc(newData.receiverId);
docRef.get().then((doc) => {
if (doc.exists) {
console.log("DocRef exist");
const userToken = doc.data().tokens;
for(var key in userToken){
console.log(userToken[key]);
tokens.push(userToken[key]);
}
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch((error) => {
console.log("Error getting document:", error);
});
//Notification Payload
var payload = {
notification: {
title: newData.sendBy,
body: 'Sent you a message',
sound: 'default',
},
data: {
click_action : 'FLUTTER_NOTIFICATION_CLICK',
route: '/telconsultinbox',
}
};
console.log("Sending Notification now.");
console.log(tokens);
try{
//send to device
const response = await admin.messaging().sendToDevice(tokens, payload);
console.log('Notification sent successfully');
console.log(newData.sendBy);
}catch(err){
console.log(err);
}
I think you should avoid using for..in to iterate through an array (you can read more about it in this answer). Try one of these 2 options:
You could use forEach(), which is more elegant:
userToken.forEach((token) => {
console.log(token);
tokens.push(token);
});
for-of statement:
for(const token of userToken){
console.log(token);
tokens.push(token);
}
Also, I would consider renaming userToken to userTokens, since it should contain multiple values. Makes the code a bit more readable.

Check Firestore Database boolean return value

I am working for a task related to react native app based user management. After they successful sign up themselves as a user, I include a data which is store Boolean value and I have named it as emailVerifiedAccount (this is the stored data if they registered themselves successful and indicate if they are a verified user if they click on email verification link send to them). In login screen I would like to check the Boolean value that I get from firestore in onAuthStateChanged and only direct them to index screen when the emailVerifiedAccount that I get is return true. Code below is authstatechanged for login screen .
const onAuthStateChanged = (user) => {
if (user) {
checkEmailVerifiedAccount=firestoreService.isEmailVerifiedAccount(user);
try {
if(checkEmailVerifiedAccount===true){
navigation.navigate('Index');
}else{
Alert.alert(
"Verify as a Playbookx user",
"Please click on email verification link send to your email. If you do not receive any email ,please contact user support",
"You may come back to login again after you verified your email",
[
{ text: "OK"}
]
)
}
} catch (error) {
console.log(error);
}
}
};
and in firestore.js is where all the code and function that is related with Firestore database. isEmailVerifiedAccount is one of the class object which checking verified user using email.
isEmailVerifiedAccount = async (user) => {
return await firestore()
.collection('users')
.doc(user)
.get()
.then(snapshot => {
if (snapshot.exists){
const user=snapshot.data();
const emailVerifiedAccount={
emailVerifiedAccount:user.emailVerifiedAccount
};
return emailVerifiedAccount
}
})
.catch(error => {
console.log(error);
});
};
And the problem that I facing right now is that, it lead me to index screen when the emailVerifiedAccount in Firestore is false. Picture below is the structure for Firestore.
Your isEmailVerifiedAccount function is asynchronous, so when calling it you have to await the result:
checkEmailVerifiedAccount = await firestoreService.isEmailVerifiedAccount(user);
const checkEmailVerifiedAccount = firestoreService.isEmailVerifiedAccount(user);
checkEmailVerifiedAcccount seems to be an object but you are checking if it's equal to true. Either return user.emailVerifiedAccount directly from isEmailVerifiedAccount function or read that property like this:
const checkEmailVerifiedAccount = firestoreService.isEmailVerifiedAccount(user);
if(checkEmailVerifiedAccount.emailVerifiedAccount) {
navigation.navigate('Index');
}

How to create user auth without closing the current firebase session [duplicate]

This question already has answers here:
Firebase kicks out current user
(19 answers)
Closed 1 year ago.
I want to make a system where the administrator can create user auth from an email. I have developed as the documentation says but the current session is closed. I only want to create the auth to get the uid and then create a user in the database with the data I want to store.
This is what I have:
var email = emailInput.value;
var password = "Abcd1234";
firebase.auth().createUserWithEmailAndPassword(email, password).then((userCredential) => {
var user = userCredential.user;
//user.uid contains the id I want to create the instance on ref usuarios
database.ref("usuarios/"+ user.uid).set({...});
});
Edit:
You cannot create new users using client SDK. By that I mean a user creating new users as required. You need to use Firebase Admin SDK (which must be in a secure server environment - like Firebase Cloud Functions).
You can write a cloud function like this:
exports.createNewUser = functions.https.onCall((data, context) => {
if (isAdmin(context.auth.uid)) {
return admin.auth().createUser({
email: data.email,
password: data.password,
displayName: data.name
}).then((userRecord) => {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully created new user:', userRecord.uid);
return { uid: userRecord.uid }
}).catch((error) => {
console.log('Error creating new user:', error);
return { error: "Something went wrong" }
});
}
return {error: "unauthorized" }
})
Now there are multiple ways you could verify that the user who is calling this function is an admin. First one would be using Firebase Custom Claims which are somewhat like roles you assign to users. Another option would be storing UID of using in database and checking the UID exists in admin node of db. Just make sure only you can edit that part of the database.
To call the function from client:
const createNewUser = firebase.functions().httpsCallable('createNewUser');
createNewUser({ name: "test", email: "test#test.test", password: "122345678" })
.then((result) => {
// Read result of the Cloud Function.
var response = result.data;
});

firestore valueChanges() is not updating userdata instantly

I am using Angular and cloud firestore for backend. I have a user profile, a logged in user and other users with follow or unfollow action button, based on the logged in user's current following list. I want the button text and the list of followers and following to get updated in the front end as soon as the click event is successfully completed. But, I am able to see the updated values only after there is a change in route, or I click the button twice.
Is there any way that, as soon as follow or unfollow is successful, data of loggedUser and selectedUser gets updated and the same updated data is reflected in my component.
userDetails.component.ts
ngOnInit(): void {
this.loggedUser = this.userService.getLoggedUserData();
//--------Get displayed user data
this.userService.SelectedUserChanged.pipe(take(1))
.subscribe(
(user:User)=>{
this.user=user;
if(this.user){
this.btnToDisplay(); //.....To show follow or unfollow depending on logged user's data
}}
);
}
I have a UserService, where I have subscribed to logged user's valueChanges()
fetchLoggedUser(uid: string) { //Subscribed in the appcomponent using authenticated user's id.
return this.db.collection('Users').doc(uid)
.valueChanges()
.pipe(
tap((user: User) => {
this.loggeduser = user;
this.loggeduser.id = user.userid;
this.fetchAllUsers();
})
);
}
fetchAllUsers() {
this.userSubs.push(
this.db
.collection('Users')
.valueChanges({ idField: 'id' })
.subscribe((users: User[]) => {
this.allUsers = users;
this.usersChanged.next([...this.allUsers]);
})
);
}
selectUser(uid: string) {
this.selectedUser = this.allUsers.find((user) => user.id === uid);
this.SelectedUserChanged.next({ ...this.selectedUser });
}
getLoggedUserData() {
return ({...this.loggeduser});
}
followUser(uid: string, email: string) {
this.db.collection('Users').doc(this.loggeduser.userid)
.update({
following: firebase.firestore.FieldValue.arrayUnion({
uid: uid,
email: email,
}),
});
this.db.collection('Users').doc(uid)
.update({
followers: firebase.firestore.FieldValue.arrayUnion({
uid: this.loggeduser.userid,
email: this.loggeduser.email,
}),
});
}
According to this post, valueChanges() and onSnapshot() automatically return the changes taking place to the document or collection that they are listening to. get() is used to get the data only once.
To achieve what you would like to, you'll need to follow the instructions on
Get real time updates with Cloud Firestore.
Based on this documentation, I have tested this code sample and when I am updating a value in the database the new document with the updated data are returned.
async function monitorUser(uid){
const doc = db.collection('users').doc(uid);
const observer = doc.onSnapshot(docSnapshot => {
console.log(`Received doc snapshot:`, docSnapshot.data());
}, err => {
console.log(`Encountered error: ${err}`);
});
}
Then you can update the public variable that corresponds to your user's data with the new values and the view should be updated.

createUserWithEmailAndPassword VUEJS error updating user profile

i have this issue with a firebase app i'm also developing , my intentions are to create an user and update his profile with a name using the firebase method createUserWithEmailAndPassword.
I evolve the process and eventually it works but also throws an error which says kind of :
Uncaught TypeError: Cannot read property user of undefined
at eval (index.js?xxxx)
at e.g (auth.esm.js?xxx)
at kc (auth.esm.js?xxxxx)
at gc (auth.esm.js?xxxxxx)
at B.k.Zb (auth.esm.js?xxxxxx)
at Qb (auth.esm.js?xxxx)
despite of having already modified the user info, then i need to refresh the page to get this error to dissapear.
Here part of my code:
signUserUp({ commit }, payload) {
commit("settingLoader", true);
firebase
.auth()
.createUserWithEmailAndPassword(payload.email, payload.password)
.then(() => {
let user = firebase.auth().currentUser;
console.log(user);
user
.updateProfile({
displayName: payload.name
})
.then(usermod => {
const User = {
id:usermod.user.uid, undefined usermod
email:usermod.user.email, undefined usermod
name:usermod.user.displayName undefined usermod
};
commit("settingUserIn", User);
commit("settingLoader", false);
});
})
.catch(error => {
console.log(error);
commit("settingLoader", false);
});
}
Then the error does reference to an eventual undefined "usermod" for user.uid, user.displayName ,and user.email.
Any advice about what i'm missing?
thanks in advance!!
https://firebase.google.com/docs/reference/js/firebase.User#updateprofile
Firebase's user.updateProfile method returns a void promise, meaning it returns a promise with no value.
You still have access to your user variable in your then, so why not just change it to
...
user
.updateProfile({
displayName: payload.name
})
.then(() => {
const User = {
id: user.uid,
email: user.email,
name:user.displayName
};
commit("settingUserIn", User);
commit("settingLoader", false);
});
...

Categories