How to use email and phone to authentication in Firebase? - javascript

I am looking for a way in react-native to make user sign up with his phone number then add his email and password.
But when a user logs in, he logs in only with email and password.
The phone number is only for security reasons.
I do a signInWithPhoneNumber() after user verify his number i call a createUserWithEmailAndPassword() but that's made in console Auth Two separate authentication in the same time
"Email" & "Phone Number"
code
// I just pass the result into separate screen then use it to confirm all stuff is work :D
...
auth()
.signInWithPhoneNumber(phoneWithAreaCode, true)
.then(confirmResult => {
console.log('2', phoneWithAreaCode);
console.log('confirmResult', confirmResult);
this.setState({
confirmResult,
loading: false,
});
})
...
confirmCode = codeInput => {
const {confirmResult, email, password} = this.state;
console.log('codeInput Is:', codeInput.length);
if (confirmResult && codeInput.length) {
confirmResult
.confirm(codeInput)
.then(async () => {
clearInterval(this.interval);
const {params} = this.props.navigation.state;
await auth()
.createUserWithEmailAndPassword(email, password)
.then(({user}) => {
console.log('hey u');
let uid = user.uid;
params.createUser(uid);
})
.catch(error => {
// Handle Errors here.
var errorCode = error.code;
switch (errorCode) {
case 'auth/email-already-in-use':
this.setState({loading: false, password: ''});
break;
case 'auth/invalid-email':
this.setState({loading: false, password: ''});
break;
case 'auth/operation-not-allowed':
this.setState({loading: false, password: ''});
break;
case 'auth/weak-password':
this.setState({loading: false, password: ''});
break;
default:
this.setState({loading: false, password: ''});
break;
}
});
//Check if any users exist
// database()
// .ref(`users`)
// .limitToFirst(1)
// .once('value', async snapshot => {
// if (snapshot.exists()) {
// console.log('exists!');
// return true;
// } else {
// // params.createUser(user.uid);
// console.log('No user found Hah');
// }
// });
this.setState({
timer: 0,
isValid: true,
});
})
.catch(error => {
let errorCode = error.code;
let errorMessage = error.message;
console.log(errorCode);
switch (errorCode) {
case 'auth/invalid-verification-code':
this.setState({codeInput: ''});
this.refs.codeInputRef2.clear();
break;
default:
break;
}
console.log(errorMessage);
});
} else {
console.log('Not here');
}
};
EDIT
confirmCode = codeInput => {
const {confirmResult, password, email} = this.state;
console.log('codeInput Is:', codeInput.length);
if (confirmResult && codeInput.length) {
confirmResult
.confirm(codeInput)
.then(user => {
console.log(user);
let userE = auth().currentUser;
// userE.updateEmail(email);
auth().createUserWithEmailAndPassword(email, password);
clearInterval(this.interval);
const {params} = this.props.navigation.state;
params.createUser(user.uid);
this.setState({
timer: 0,
isValid: true,
});
})
.catch(error => {
let errorCode = error.code;
let errorMessage = error.message;
switch (errorCode) {
case 'auth/invalid-verification-code':
this.refs.codeInputRef2.clear();
break;
default:
break;
}
console.log(errorMessage);
});
} else {
console.log('Not here');
}
};

If you want to use multiple auth providers for the same user, then you need to link them to prevent creating separate users. To link them you can use linkWithCredential() for example:
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
Here you pass the email and password to the EmailAuthProvider.credential method, then you can pass the AuthCredential object to the signed-in user's linkWithCredential method:
firebase.auth().currentUser.linkWithCredential(credential).then(function(usercred) {
var user = usercred.user;
console.log("Account linking success", user);
}, function(error) {
console.log("Account linking error", error);
});
You can check the docs for other ways to link multiple providers :
https://firebase.google.com/docs/auth/web/account-linking
https://firebase.google.com/docs/auth/web/account-linking#link-email-address-and-password-credentials-to-a-user-account

Related

Accessing value from dispatch

export async function signIn({ dispatch }, data) {
Loading.show()
firebaseAuth
.signInWithEmailAndPassword(data.email, data.password)
.then(async res => {
Loading.hide()
// if (!res.user.emailVerified) {
// dispatch('setNotification', {
// ...failed,
// message: 'Email not verified!'
// })
// return
// }
res.user.getIdToken().then(token => {
Loading.hide()
const { uid } = res.user
tempStorage.token = token
tempStorage.localId = uid
storage.delete(StorageKeys.token)
storage.set(StorageKeys.token, token)
storage.set(StorageKeys.localId, uid)
dispatch('setNotification', {
...success,
message: 'Successfully login!'
})
dispatch('getUserProfile')
// i need to access the value here from getUserProfile function
})
})
.catch(error => {
Loading.hide()
var msg = ''
switch (error.code) {
case 'auth/wrong-password':
msg = 'Wrong password'
break
case 'auth/user-not-found':
msg = 'User not found'
break
case 'auth/too-many-requests':
msg = 'Account temporarily suspended'
}
dispatch('setNotification', {
...failed,
message: msg
})
})
}
export async function getUserProfile({ dispatch, commit }) {
try {
const serviceUrl = `${urls.users}/${tempStorage.localId}`
const { data } = await request.get(serviceUrl)
commit('setUser', data)
} catch (err) {
console.log(err, 'err')
}
}
How do i access the value from this disptach(getUserProfile) function???
if (data.attributes.roles.includes('admin')) {
this.$router.push({ path: routesConfig.name.training })
} else {
this.$router.push({ path: routesConfig.name.profile })
}
i want this condition to run on basis of dispatch function
result and the upper condition will redirect me to different pages on basis of role
Thanks in advance!

Can I call function in previous screen - react native?

I have a function "signInWithPhoneNumber" in SignUp screen after call it navigates me to a Confirmation Screen and I pass some params after navigate to confirm a verification code I was received,
So in this screen "Confirmation", I have a button "Re-send Verification Code" so my question is
when I press to "re-send" I want to call a "signInWithPhoneNumber" function in SignUp screen to get a new code
So what you think? that's possible?
Or rewrite a signInWithPhoneNumber in a confirmation screen and call it after pressed re-send button?
SignUp Screen - Function
signUp = async () => {
const {phoneNumber} = this.state;
this.setState({message: 'Sending code ...'});
const phoneWithAreaCode = phoneNumber.replace(/^0+/, '+972');
console.log(phoneWithAreaCode);
auth()
.signInWithPhoneNumber(phoneWithAreaCode, true)
.then(confirmResult => {
console.log('confirmResult', confirmResult);
this.setState({confirmResult, message: 'Code has been sent!'});
// this.createUserDatabase();
})
.then(() => {
this.props.navigation.navigate('Confirmation', {
message: this.state.message,
confirmResult: this.state.confirmResult,
createUser: uid => this.createUserDatabase(uid),
});
});
};
Confirmation screen - function
confirmCode = codeInput => {
const confirmResult = this.props.navigation.state.params.confirmResult
if (confirmResult && codeInput.length) {
confirmResult
.confirm(codeInput)
.then(user => {
clearInterval(this.interval);
const {params} = this.props.navigation.state;
//Check if any users exist
database()
.ref(`users`)
.limitToFirst(1)
.once('value', snapshot => {
if (snapshot.exists()) {
console.log('exists!');
return true;
} else {
params.createUser(user.uid);
console.log('No user found Hah');
}
});
this.setState({
timer: 0,
message: 'Code Confirmed!',
isValid: true,
});
})
.catch(error => {
let errorCode = error.code;
let errorMessage = error.message;
console.log(errorCode);
switch (errorCode) {
case 'auth/invalid-verification-code':
this.setState({message: 'Code is invalid', codeInput: ''});
this.refs.codeInputRef2.clear();
break;
default:
alert(`Please, Check your Messages!`);
break;
}
console.log(errorMessage);
});
} else {
console.log('Not here');
}
};
You can send signInWithPhoneNumber to Confirmation screen, while navigating to it from SignUp screen, like so
this.props.navigation.navigate('Confirmation', {
message: this.state.message,
confirmResult: this.state.confirmResult,
createUser: uid => this.createUserDatabase(uid),
signInWithPhoneNumber: signInWithPhoneNumber // your actual function here
});
});
And then this function will be available in Confirmation screen as a prop, and you can call it when necessary

Couldn't call function after set them as variable in if statement - Javascript?

I have a multi-function for validation inputs and i don't call a master function before checking these inputs and validate them
so I have a "master function" SignUp Function and inside it, I set a validation function as a vars and check it before passing to other rest of function so the validation is invoked very well but I can't see other rest is invoked and my DB is empty
// sample of validations Func
handleUsername = () => {
const {userName} = this.state;
if (userName.length <= 0) {
this.setState({
NameValid: 'من فضللك قم بكتابة اسمك',
});
return;
} else {
this.setState({
NameValid: '',
});
}
}
signUpFunc = async () => {
console.log('im here');
const {email, password} = this.state;
// For Validations Inputs
const nameValid = this.handleUsername();
const emailValid = this.handleEmail();
const phoneValid = this.handlePhone();
const passwordValid = this.handlePassword();
if (!nameValid || !phoneValid || !emailValid || !passwordValid) {
console.log('Validations statment here');
return;
} else {
console.log('else statment'); // i can't see this in my console after validated
console.log('email', email);
console.log('password', password);
await auth()
.createUserWithEmailAndPassword(email, password)
.then(() => {
console.log('done');
this.setState({loading: true}, () => this.createUserDatabase());
})
.catch(error => {
// Handle Errors here.
var errorCode = error.code;
switch (errorCode) {
case 'auth/email-already-in-use':
alert('هذا البريد مستخدم من قبل ، جرب بريد أخر');
this.setState({loading: false, password: ''});
break;
case 'auth/invalid-email':
alert('الريد الإلكتروني غير صالح، جرب بريد آخر');
this.setState({loading: false, password: ''});
break;
case 'auth/operation-not-allowed':
alert('هذا البريد معطل من قبل إدارة التطبيق');
this.setState({loading: false, password: ''});
break;
case 'auth/weak-password':
alert('كلمة المرور ضعيفة');
this.setState({loading: false, password: ''});
break;
default:
alert('تحقق من اتصال الانترنت لديك');
this.setState({loading: false, password: ''});
break;
}
});
}
};
First of all, if you use if and else, the code will execute only the if or the else, so:
if (true) {
console.log('Here'); // enters here
} else {
console.log('Not here'); // so don't enter here
}
The first condition will execute only.
Second thing, if you assigned a function to a variable, e don't return nothing from this function, this variable will be false, like this:
function example() {
return;
}
const variable = example();
if(!variable) { // false, but you use `not`, so it's true
console.log('is true');
}
If you want to check, if something is valid or not, return true or false from your function, like this:
function example() {
if(1 === 1) {
return true;
} else {
return false;
}
}
const variable = example();
console.log(variable);
So, in your code, you may want something like this:
// sample of validations Func
handleUsername = () => {
const {userName} = this.state;
if (userName.length <= 0) {
this.setState({
NameValid: 'من فضللك قم بكتابة اسمك',
});
return false; // is it's invalid, return false
} else {
this.setState({
NameValid: '',
});
return true; // else, return true
}
}
signUpFunc = async () => {
console.log('im here');
const {email, password} = this.state;
// For Validations Inputs
const nameValid = this.handleUsername();
const emailValid = this.handleEmail();
const phoneValid = this.handlePhone();
const passwordValid = this.handlePassword();
if (nameValid || phoneValid || emailValid || passwordValid) {
console.log('Validations statment here');
// So if any validator is true, the code below will execute
console.log('else statment');
console.log('email', email);
console.log('password', password);
await auth()
.createUserWithEmailAndPassword(email, password)
.then(() => {
console.log('done');
this.setState({loading: true}, () => this.createUserDatabase());
})
.catch(error => {
// Handle Errors here.
var errorCode = error.code;
switch (errorCode) {
case 'auth/email-already-in-use':
alert('هذا البريد مستخدم من قبل ، جرب بريد أخر');
this.setState({loading: false, password: ''});
break;
case 'auth/invalid-email':
alert('الريد الإلكتروني غير صالح، جرب بريد آخر');
this.setState({loading: false, password: ''});
break;
case 'auth/operation-not-allowed':
alert('هذا البريد معطل من قبل إدارة التطبيق');
this.setState({loading: false, password: ''});
break;
case 'auth/weak-password':
alert('كلمة المرور ضعيفة');
this.setState({loading: false, password: ''});
break;
default:
alert('تحقق من اتصال الانترنت لديك');
this.setState({loading: false, password: ''});
break;
}
});
}
};

Why isn't my dispatch working? React Redux

I´m trying to change my firebase username using the redux store.
I have a register form that receive the email, password and username of the input and then the form create a firebase account with email and password, then I update the displayName using updateProfile of firebase. See this
That´s my redux reducer:
case "CHANGE_USERNAME":
const currentUser = firebase.auth().currentUser;
currentUser.updateProfile({ displayName: state.user.displayName });
return { ...state.user, displayName: action.payload };
This is the store:
const initialState = {
logged: null,
user: {}
};
And this is part of my register form:
firebase
.auth()
.createUserWithEmailAndPassword(this.state.email, this.state.password)
.then(() => {
this.props.dispatch({
type: "CHANGE_USERNAME",
payload: { ...this.state.username }
});
alert("Account created!");
})
.catch(error => {
// Handling errors
var errorCode = error.code;
var errorMessage = error.message;
alert(errorCode);
});
Why the username is not changing?
You aren't returning anything from your promise. Assuming that createUserWithEmailAndPassword returns a promise, and that the response contains a username field, you want to dispatch response.username to your reducer.
.then((response) => {
this.props.dispatch({
type: "CHANGE_USERNAME",
payload: { response.username }
});
alert("Account created!");
})
In your reducer, you want to add the new username state. Something like:
return { ...this.state, username: payload }
Thanks all, I had fixed the problem using:
case "CHANGE_USERNAME": {
const currentUser = firebase.auth().currentUser;
currentUser.updateProfile({ displayName: action.payload });
return {
...state,
user: { ...currentUser.providerData[0] }
};
}
At my reducer and:
this.props.dispatch({
type: "CHANGE_USERNAME",
payload: this.state.displayName
});
At my dispatch, thanks!

Firebase create user with email and password and put data in database

I want to create users with the function createUserWithEmailAndPassword and then put the data of that user into my database but it doesn't work.. the user is added to my authentication tab in firebase but not in my database. I also don't get an error.
registerUser.addEventListener('click', function (user) {
event.preventDefault();
closeRegisterForm();
email = registerEmail.value;
password = registerPassword.value;
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(function (event) {
var ref = firebase.database().ref("users").child(user.uid).set({
email: user.email,
uid: user.uid
});
})
.catch(function (error) {
var errorCode = error.code;
var errorMessage = error.message;
});
});
Hi I was having the exact same problem. But i used a local function to solve it. Something like this:
createNewUser(form) {
//create new user with provided data of the form
this.afAuth.auth.createUserWithEmailAndPassword(form.email, form.password)
.then(function(firebaseUser) {
console.log("User " + firebaseUser.uid + " created successfully!");
updateFirestore(form, firebaseUser.uid);
return firebaseUser;
}).catch(function(error) {
alert(error)
});
function updateFirestore(form, uidNewUser) {
//push data into firestore using the uid provided
let data = {};
data['mail'] = form.email;
data['name'] = form.name;
//se empuja el arreglo data en el documento del usuario
this.afs.collection('users').doc(uidNewUser).set(data);
console.log(data, uidNewUser);
}
}
You refer to user.uid and user.email but never define user. The return type of sign in method createUserWithEmailAndPassword is a user but you define it as event. Also make sure you wait for the db write promise to resolve and catch any errors there as Frank advised.
Working for me:
const val = this.signupForm.value;
this.authService.doRegister(val)
.then(res => {
this.msg = 'You have registered successfully!';
this.msgType = 'success';
this.authService.updateUser(val.name, null)
.then(suc => {
const created = firebase.firestore.FieldValue.serverTimestamp();
const user = {
first_name: val.name,
last_name: '',
email_personal: val.email,
created: created,
updated: created
};
this.userCollection = this.afs.collection<User>('users');
this.userCollection.doc(suc).set(user);
}, err => {
// console.log(err);
});
this.router.navigate(['/']);
}, err => {
this.msg = err.message;
})
const [phone, setPhone] = useState()
const [email, setEmail] = useState()
const [password, setPassword] = useState()
const handleSignUp = async () => {
if (!email == ' ' && !password == ' ') {
try {
const result = await auth().createUserWithEmailAndPassword(email, password)
firestore()
.collection('Users')
.doc(result?.user?.uid)
.set({
email: result?.user?.email,
phoneNumber: phone,
uid: result?.user?.uid,
displayName: result?.user?.email.split('#')[0],
})
.then(() => {
alert('User added!');
});
} catch (error) {
if (error.code === 'auth/email-already-in-use') {
Alert.alert('That email address is already in use!');
}
else if (error.code === 'auth/invalid-email') {
Alert.alert('That email address is invalid!');
}
else {
Alert.alert(error)
}
}
} else {
Alert.alert("Please Enter Your All Field");
}
}

Categories

Resources