Why isn't my dispatch working? React Redux - javascript

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!

Related

Not getting auth.currentUser after registration until I reload the page (VUE3 + Quasar + Firebase)

Facing a little issue in regards to user registration. Everything works fine except this one detail where I have to reload the page after user registration or else their data will not render. I am displaying the username on the Navbar once they log in/register so this is not ideal.
Here is my App.vue:
<template>
<router-view />
</template>
<script setup>
import { onMounted } from "vue";
import { useAuthStore } from "stores/auth";
const storeAuth = useAuthStore();
onMounted(() => {
storeAuth.init();
});
</script>
Here is my init() function in the auth Store:
init() {
onAuthStateChanged(auth, (user) => {
if (user) {
this.user.id = user.uid;
this.user.email = user.email;
this.user.displayName = user.displayName;
} else {
this.user = {};
}
});
and in the Registration Form component, this is the function that triggers when clicking SUBMIT:
\\ Triggering Firebase registration and opening a confirmation modal if successful.
const onSubmit = () => {
storeAuth.registerUser(credentials);
registered.value = true;
};
\\When the user clicks OK in the confirmation modal he/she is redirected to their profile page
function redirectUser() {
const id = auth.currentUser.uid;
router.push({ name: "user", params: { id } });
}
and finally, this is the registerUser method in the auth Store:
registerUser(credentials) {
createUserWithEmailAndPassword(
auth,
credentials.email,
credentials.password
)
.then((userCredential) => {
console.log(userCredential);
const user = userCredential.user;
updateProfile(auth.currentUser, {
displayName: credentials.displayName,
});
setDoc(doc(db, "users", auth.currentUser.uid), {
displayName: credentials.displayName,
email: credentials.email,
countryCode: credentials.countryCode,
phoneNumber: `+${credentials.countryCode.value}${credentials.phoneNumber}`,
userType: "Persona",
uid: auth.currentUser.uid,
});
})
.catch((error) => {
console.log("error.message: ", error.message);
});
}
Any pointers would be greatly appreciated. Basically I want to avoid having to refresh the page for the displayName to appear in the NavBar.
The default value of user.diplayName name is null. Although you are using updateProfile() to set a value, but you are not handling the promises correctly. First, try refactoring the code as shown below:
// async function
async registerUser(credentials) {
const { user } = await createUserWithEmailAndPassword(auth, credentials.email, credentials.password)
await updateProfile(user, {
displayName: credentials.displayName
});
await setDoc(doc(db, "users", auth.currentUser.uid), {
displayName: credentials.displayName,
email: credentials.email,
countryCode: credentials.countryCode,
phoneNumber: `+${credentials.countryCode.value}${credentials.phoneNumber}`,
userType: "Persona",
uid: auth.currentUser.uid,
});
}
The profile may not update right away. You can use reload() to reload current user's data.
// add this after updateProfile()
await reload(user);
You are updating the state from inside of onAuthStateChanged() that'll trigger right after user is signed in. It'll be best to update the displayName in state manually in case of registration after updateProfile().

How to save a session on firebase 9?

please help.
I'm trying to ensure that the user does not log out after reloading the page.
const signUp = async (loginEmail, loginPassword) => {
const auth = getAuth()
setPersistence(auth, browserSessionPersistence)
.then(({ user }) => {
dispatch(
setUser({
email: user.email,
id: user.uid,
token: user.accessToken,
})
)
return signInWithEmailAndPassword(auth, loginEmail, loginPassword)
})
.catch((error) => {
console.log(error.message)
})
}
This is what the example looks like in the official documentation
const auth = getAuth();
setPersistence(auth, browserSessionPersistence)
.then(() => {
// Existing and future Auth states are now persisted in the current
// session only. Closing the window would clear any existing state even
// if a user forgets to sign out.
// ...
// New sign-in will be persisted with session persistence.
return signInWithEmailAndPassword(auth, email, password);
})
.catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
});
The recommended way to get the current user is by setting an observer on the Auth object:
import { getAuth, onAuthStateChanged } from "firebase/auth";
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const uid = user.uid;
// ...
} else {
// User is signed out
// ...
}
});
documentation

Vuex and firebase: The user id is undefined in the firebase database

I am creating an e-commerce web site.
Now I finished creating the new account with email and password.
And I want to insert the user email, full name, and timestamp in the database.
As you can see in the picture below, I could see the USER data in the google chrome dev console.
But when I checked the firebase database in the browser, I cannot see the user id. And instead, I see undefined in the user id column.
Now I am on the step3 process.
Add user data into database
I cannot figure out why it's happening, so I hope you can help me out.
This is my store/index.js file.
import fireApp from '#/plugins/firebase'
export const state = () => ({
user: null,
error: null,
busy: false,
jobDone: false
})
export const mutations = {
setUser (state, payload) {
state.user = payload
},
setError (state, payload) {
state.error = payload
},
clearError (state, payload) {
state.error = null
},
setBusy (state, payload) {
state.busy = payload
},
setJobDone (state, payload) {
state.jobDone = payload
},
}
export const actions = {
signUpUser({commit}, payload) {
commit('setBusy', true)
commit('clearError')
//1.Signup new user.
//2.Update firebase user profile & set local user data.
//3.Add user data into database
//4.Attach user to consumer group
let newUser = null
fireApp.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(user => {
newUser = user
var user = fireApp.auth().currentUser;
user.updateProfile({ displayName: payload.fullname })
const currentUser = {
id: user.uid,
email: payload.email,
name: payload.fullname,
role: 'consumer'
}
console.log('USER', currentUser)
commit('setUser', currentUser)
})
.then(() => {
const userData = {
email: payload.email,
fullname: payload.fullname,
createdAt: new Date().toISOString()
}
fireApp.database().ref(`users/${newUser.uid}`).set(userData)
})
.then(() => {
commit('setJobDone', true)
commit('setBusy', false)
})
.catch(error => {
commit('setBusy', false)
commit('setError', error)
})
}
}
export const getters = {
user (state) {
return state.user
},
error (state) {
return state.error
},
busy (state) {
return state.busy
},
jobDone (state) {
return state.jobDone
}
}
This is because the promise returned by createUserWithEmailAndPassword() method resolves with an UserCredential object and not with a User one.
You should use the user property of the UserCredential, as follows:
let newUser = null
fireApp.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(userCredential => {
newUser = userCredential.user;
//...
Note also that you don't need to call fireApp.auth().currentUser to get the user.
When using the createUserWithEmailAndPassword() method, on successful creation of the user account, this user will also be signed in to your application, so just get the user with userCredential.user, as explained above.
In addition, note that the updateProfile() method is asynchronous and returns a Promise, which you need to include in your promises chain.
So the following should do the trick (untested):
signUpUser({commit}, payload) {
commit('setBusy', true)
commit('clearError')
//1.Signup new user.
//2.Update firebase user profile & set local user data.
//3.Add user data into database
//4.Attach user to consumer group
let user = null;
fireApp.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(userCredential => {
user = userCredential.user;
return user.updateProfile({ displayName: payload.fullname });
})
.then(() => {
const currentUser = {
id: user.uid,
email: payload.email,
name: payload.fullname,
role: 'consumer'
}
console.log('USER', currentUser)
commit('setUser', currentUser)
const userData = {
email: payload.email,
fullname: payload.fullname,
createdAt: new Date().toISOString()
}
return fireApp.database().ref(`users/${user.uid}`).set(userData)
})
.then(() => {
commit('setJobDone', true)
commit('setBusy', false)
})
.catch(error => {
commit('setBusy', false)
commit('setError', error)
})
}

How do I handle errors in a redux action?

import axios from "axios";
export const createNewUser = (newUser, history) => async dispatch => {
try {
await axios.post("http://localhost:9090/users/register", newUser);
history.push("/login");
dispatch({
type: "GET_ERRORS",
payload: {}
});
} catch (err) {
dispatch({
type: "GET_ERRORS",
payload: err.response.data
});
}
};
This is my action,I have a form where I bind the inputs to my state and I'm calling the action when I submit the form as such:
onSubmit(e) {
e.preventDefault();
const newUser = {
"username": this.state.username,
"fullName": this.state.fullName,
"password": this.state.password,
"confirmPassword": this.state.confirmPassword
};
console.log(this.props)
this.props.createNewUser(newUser, this.props.history);
}
componentWillReceiveProps(nextProps) {
console.log(nextProps)
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
This is all covered in a tutorial for spring boot and react, I believe that I followed it exactly however I am not getting the same results. I even copied the code as it is in the tutorial. When I click submit I see a 400 error in the console, but the state ( errors) stays undefined.
This is what my backend returns when I checked with debugger:
<400 BAD_REQUEST Bad Request,{password=Password must be atleast 6 characters, fullName=Please enter your full name, username=username is required},[]>

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