ReactNative and firebase, Real time database when signUp - javascript

I build a react native signUp form with this fields (email, password, name, and phone) and I need to add it to the firebase database when user create his account.
I create the signUp function like this:
onSignUpPress() {
const navigation = this.props.navigation;
this.setState({ error: '', loading: true });
const { email, password } = this.state;
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(() => {
this.setState({ error: '', loading: false });
navigation.navigate("Profile");
})
.catch(() => {
this.setState({ error: 'Authentication failed.', loading: false });
console.log("Error creating user:");
});
}
and it's work
I need to know how can I add the field to a database
I try this :
writeUserData(uid, name, email, phone) {
let userId = firebaseApp.auth().currentUser.uid;
var newUser = {
name: name,
email: email,
phone: phone
}
var newUserKey = firebase.database().ref().child('users').push().key;
var updates = {};
updates['/users/' + newUserKey] = newUser;
updates['/user-users/' + uid + '/' + newPostKey] = postData;
return firebase.database().ref().update(updates);
}
onSignUpPress() {
....
....
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(() => {
....
this.writeUserData(uid, name, email, phone);
navigation.navigate("Profile");
})
....
.....
}
but it's not working correctly any help, please?

Firebase has many functionalities. Out of them two are authentication and real time database.
When you call createUserWithEmailPassword successfully, it automatically creates a UID of the user and stores the meta in Firebase Authentication.
You can now at point of time get this UID of this user when he is authenticated using firebase.auth(). currentUser.uid and then create a firebase reference where you want to save data database.ref().child(path)
Use the .set(object) or .push(object) to save data.
Tip : Create your database architecture properly (see documentation) to be able to fetch the saved data properly.

try this,
writeUserData(uid, name, email, phone) {
const userId = firebase.auth().currentUser.uid;
//You don't have to create key because userId is uniq value.
return firebase.database().ref(`users/${userId}`).update({name, email, phone});
}
onSignUpPress() {
....
....
// createUserWithEmailAndPassword promise resolve return userData!
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(userData => {
....
this.writeUserData(userData.uid, name, email, phone);
navigation.navigate("Profile");
})
....
.....
}
and I don't get it why you try to update,
updates['/user-users/' + uid + '/' + newPostKey] = postData;
even if you don't have postData at this moment!
You just set when user create post data like this
writePostData(uid, postData) {
const postRef = firebase.database().ref(`user-users/${uid}`);
//this way is useful when key handling before push
var push = postRef.push();
var key = push.key;
return postRef.child(key).set(postData);
//or just push
return postRef.push(postData);
}

Related

What is the difference between passing in argument as object vs string into a function

I have below is a method that signs a user up with their email and password and create a document in Firebase when the user enters their info into a form and clicks submit:
const onSubmitHandler = async (e) => {
e.preventDefault();
try {
const { user } = await createAuthUserWithEmailAndPassword(email, password);
console.log(user, 'user')
await createUserDocumentFromAuth(user, { displayName })
}catch(err) {
if(err === 'auth/email-already-in-use') {
alert('Account with this email already exists');
return;
}else {
console.log(err)
}
}
}
For this function call:
await createUserDocumentFromAuth(user, { displayName })
where displayName can be a string, such as ElonMusk.
In the actual createUserDocumentFromAuth, I am calling the setDoc method, which is one from Firebase to set a user document:
export const createUserDocumentFromAuth = async ( userAuth, additionalInfo = {} ) => {
if(!userAuth) return;
console.log(additionalInfo, 'additionalInfo')
const userDocRef = doc(db, 'users', userAuth.uid);
const userSnapshot = await getDoc(userDocRef);
if(!userSnapshot.exists()) {
const { displayName, email } = userAuth;
const createdAt = new Date();
try {
// set the doc here
await setDoc(userDocRef, {
displayName,
email,
createdAt,
...additionalInfo
});
} catch(err) {
console.log('err creating the user', err)
}
};
return userDocRef;
}
The reason I passed { displayName } in manually is because there is a case where the server's response to createAuthUserWithEmailAndPassword(email, password) has displayName to be null, but we want the user to have a displayName registered in the database.
My question is:
Why does displayName only work when it is passed in as an object and not just in its normal form? For example:
await createUserDocumentFromAuth(user, { displayName })
will replace the displayName: null
But not when I pass in:
await createUserDocumentFromAuth(user, displayName)
What is this technique called in JavaScript?
If you look into createUserDocumentFromAuth, you'll see that it's expects two arguments userAuth and additionalInfo, both arguments are expected to be objects.
It later uses data from additionalInfo to add/overwrite anything in userAuth when calling setDoc() method.
So, I'd recommend add
console.log(userDocRef, {
displayName,
email,
createdAt,
...additionalInfo
});
to see what what data is being sent to setDoc()

How can I set a user's display name and email with Firebase signInWithCredentials()

I am writing a login / signup page for my React Native app, and I am using Firebase's signInWithCredential() function.
As you can see in the code below, I pass a credential and if the response shows it's a new user, I append to my database, otherwise I sent them to the home screen.
await firebase
.auth()
.signInWithCredential(credential)
.then((response) => {
if (response.additionalUserInfo.isNewUser) {
setShowVerifier(false);
setShowRegistration(true);
// append data to database if user is new
const data = { firstName, lastName, email, phoneNumber };
db.collection("users")
.doc(response.user.uid)
.set(data)
.then(() => {
setShowPhoneNumber(true);
setShowVerifier(false);
setShowRegistration(false);
navigation.navigate("Home");
}).catch(() => {
alert("Error creating account, try again");
});
} else {
setShowVerifier(false);
setShowPhoneNumber(true);
// set verification code to empty string
setVerificationCode("");
navigation.navigate("Home");
}
});
When I find out that the user is in fact a new user, how would I go about updating that user's Firebase auth information, like their displayName and email? (shown below in JSON response)
"user": Object {
"displayName": null,
"email": null,
"emailVerified": false,
"isAnonymous": false,
"lastLoginAt": "1603914278694",
"photoURL": null,
}
Added this chunk of code to the code chunk found above.
auth.currentUser.updateProfile({
displayName: firstName + " " + lastName,
email: email,
});
Updated code chunk:
await firebase
.auth()
.signInWithCredential(credential)
.then((response) => {
if (response.additionalUserInfo.isNewUser) {
setShowVerifier(false);
setShowRegistration(true);
// append data to database if user is new
const data = { firstName, lastName, email, phoneNumber };
db.collection("users")
.doc(response.user.uid)
.set(data)
.then(() => {
setShowPhoneNumber(true);
setShowVerifier(false);
setShowRegistration(false);
navigation.navigate("Home");
}).catch(() => {
alert("Error creating account, try again");
});
} else {
setShowVerifier(false);
setShowPhoneNumber(true);
// set verification code to empty string
setVerificationCode("");
navigation.navigate("Home");
}
});

How to use multi Auth - firebase?

I have a register screen that contains "username, email, phone number, Password"
and in this case, I use Phone Number Authentication to verify the number so after user verify his number I save his data into firebase DB,
so after that, I navigate hem to login screen! that should contain Email, Password "he registered by them before"
So I don't just compare if his data exist in DB or not,
So it should be used Email/Password Firebase Auth,
But I think it's will take a lot of hits to my Bill or something,
so what you think to achieve these cases because I'm forced to register by Email For Reset Password later?
here is my register Code
signUp = async () => {
const {phoneNumber} = this.state;
this.setState({message: 'code was sent'});
const phoneWithAreaCode = phoneNumber.replace(/^0+/, '+972');
console.log(phoneWithAreaCode);
auth()
.signInWithPhoneNumber(phoneWithAreaCode, true)
.then(confirmResult => {
console.log('confirmResult', confirmResult);
this.setState({confirmResult, message: 'code was sent'});
// this.createUserDatabase();
})
.then(() => {
this.props.navigation.navigate('Confirmation', {
message: this.state.message,
confirmResult: this.state.confirmResult,
createUser: uid => this.createUserDatabase(uid),
phoneWithAreaCode: phoneWithAreaCode,
signInPhoneNumber: phone => auth().signInWithPhoneNumber(phone),
});
});
};
createUserDatabase = uid => {
const {userName, phoneNumber, email} = this.state;
// const uid = auth().currentUser.uid;
const data = {
uid,
name: userName,
email: email,
phoneNumber: phoneNumber,
};
database()
.ref(`users/${uid}`)
.set(data)
.then(() => {
console.log('New poll data sent!');
})
.catch(error => console.log('Error when creating new poll.', error));
};

ReactJS/AWS Cognito getting user input mid-execution

I have a simple login page built with React that uses the AWS Cognito API to authenticate the user. There are some authentication scenarios (password needs to be updated, need to enter an MFA code, etc.) that require me to get user input mid-execution of the authenticateUser workflow. I'm trying to find a way to get the user input dynamically without using the built-in prompt() method, especially when a user is entering a new password. Based on how the authenticateUser workflow is structured, I'm trying to get all user input within the workflow.
Perhaps I'm not thinking about this problem in the right way, but how can I have another React component dynamically render, get user input (new password, MFA code, etc), and then use that input within the authenticateUser workflow?
The main Login component has a form that upon clicking the Submit button triggers the following function:
handleSubmit = async (event) => {
event.preventDefault();
this.setState({ isLoading: true, loginError: null });
try {
await this.login(this.state.username, this.state.password);
this.props.userHasAuthenticated(true);
}
catch(e) {
//alert(e);
this.setState({ isLoading: false, loginError: e.toString() });
}
}
And then we have the login function that goes through the authenticateUser workflow:
login(username, password) {
const userPool = new CognitoUserPool({
UserPoolId: config.cognito.USER_POOL_ID,
ClientId: config.cognito.APP_CLIENT_ID
});
const authenticationData = {
Username: username,
Password: password
};
const user = new CognitoUser({ Username: username, Pool: userPool });
const authenticationDetails = new AuthenticationDetails(authenticationData);
return new Promise((resolve, reject) => (
user.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
// User authentication was successful
resolve();
},
onFailure: (err) => {
var error = err.toString();
// If password expired
if (error.includes('Password reset required for the user')) {
var verificationCode = prompt('Password reset required. Please enter the verification code sent to your trusted device.' ,'');
var newPassword1 = '';
var newPassword2 = '';
while (newPassword1 !== newPassword2 || newPassword1.length < 8) {
newPassword1 = prompt('Please enter a new password.','');
newPassword2 = prompt('Please confirm your new password','');
}
user.confirmPassword(verificationCode, newPassword1, {
onSuccess: (result) => {
//Not sure if this handleSubmit does anything
//this.handleSubmit;
this.setState({ loginError: 'Password updated successfully! Please login with new password.', loginAlert: "success", updatePasswordUpdateAttribute: true });
return;
},
onFailure: (err) => {
this.setState({ loginError: err.toString() });
reject(err)
}
});
}
// User authentication was not successful
console.error(err);
reject(err)
},
mfaRequired: (codeDeliveryDetails) => {
// MFA is required to complete user authentication.
// Get the code from user and call
var verificationCode = prompt('Please enter the multi-factor code sent to your trusted device.' ,'');
user.sendMFACode(verificationCode, this);
},
newPasswordRequired: (userAttributes, requiredAttributes) => {
// User was signed up by an admin and must provide new
// password and required attributes, if any, to complete
// authentication.
// Get these details and call
// newPassword: password that user has given
// attributesData: object with key as attribute name and value that the user has given.
user.completeNewPasswordChallenge(newPassword1, null, {
onSuccess: (result) => {
this.updatePasswordAttribute(user);
resolve()
},
onFailure: (err) => {
this.setState({ loginError: err.toString() });
reject(err)
}
})
}
})
));
}

Create user with firebase admin sdk that can signIn using email and password

I'm using firebase admin SDK on cloud functions to create users using
admin.auth().createUser({
email: someEmail,
password: somePassword,
})
now I want user to signIn using signInWithEmailAndPassword('someEmail', 'somePassword') but I cannot.
I get the following error
{code: "auth/user-not-found", message: "There is no user record corresponding to this identifier. The user may have been deleted."}
There doesn't seem to be a reason to Stringify/Parse. This worked after I struggled with an unrelated typo...
FUNCTION CALL FROM REACT JS BUTTON CLICK
<Button onClick={() => {
var data = {
"email": "name#example.com",
"emailVerified": true,
"phoneNumber": "+15551212",
"password": "randomPW",
"displayName": "User Name",
"disabled": false,
"sponsor": "Extra Payload #1 (optional)",
"study": "Extra Payload #2 (optional)"
};
var createUser = firebase.functions().httpsCallable('createUser');
createUser( data ).then(function (result) {
// Read result of the Cloud Function.
console.log(result.data)
});
}}>Create User</Button>
And in the index.js in your /functions subdirectory:
const functions = require("firebase-functions");
const admin = require('firebase-admin');
admin.initializeApp();
// CREATE NEW USER IN FIREBASE BY FUNCTION
exports.createUser = functions.https.onCall(async (data, context) => {
try {
const user = await admin.auth().createUser({
email: data.email,
emailVerified: true,
password: data.password,
displayName: data.displayName,
disabled: false,
});
return {
response: user
};
} catch (error) {
throw new functions.https.HttpsError('failed to create a user');
}
});
Screen shot of console output
In 2022 there still is no method built into the Admin SDK that would allow to create users in the emulator.
What you can do is to use the REST API of the emulator to create users there directly. The API is documented here: https://firebase.google.com/docs/reference/rest/auth#section-create-email-password
Provided you have got and nanoid installed you can use the following code to create users in the emulator.
import { nanoid } from 'nanoid'
import httpClientFor from '../lib/http-client/client.js'
const httpClient = httpClientFor('POST')
export const createTestUser = async ({ email = `test-${nanoid(5)}#example.io`, password = nanoid(10), displayName = 'Tony' } = {}) => {
const key = nanoid(31)
const { body: responseBody } = await httpClient(`http://localhost:9099/identitytoolkit.googleapis.com/v1/accounts:signUp?key=${key}`, {
json: {
email,
password,
displayName
}
})
const responseObject = JSON.parse(responseBody)
const { localId: userId, email: userEmail, idToken, refreshToken } = responseObject
return { userId, userEmail, idToken, refreshToken }
}
Please note: As there is no error handling implemented, this snippet is not suitable for production use.
Try like that
And please be ensure that user is created from the panel
admin.auth().createUser({
email: "user#example.com",
emailVerified: false,
phoneNumber: "+11234567890",
password: "secretPassword",
displayName: "John Doe",
photoURL: "http://www.example.com/12345678/photo.png",
disabled: false
})
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
console.log("Successfully created new user:", userRecord.uid);
})
.catch(function(error) {
console.log("Error creating new user:", error);
});
Just in case anyone else comes across this I was able to fix it with the help of this.
Here is a working example inside of an onCreate cloud function:
exports.newProjectLead = functions.firestore
.document('newProjectForms/{docId}')
.onCreate(async (snapshot) => {
const docId = snapshot.id
// this is what fixed it the issue
// stringify the data
const data = JSON.stringify(snapshot.data())
// then parse it back to JSON
const obj = JSON.parse(data)
console.log(obj)
const email = obj.contactEmail
console.log(email)
const password = 'ChangeMe123'
const response = await admin.auth().createUser({
email,
password
})
data
const uid = response.uid
const dbRef = admin.firestore().collection(`clients`)
await dbRef.doc(docId).set({
id: docId,
...data,
uid
}, {
merge: true
})
console.log('New Client Created')
})

Categories

Resources