State don't update after login by google in react native - reactjs

i hope you are doing well.
I have a few problem when i try to log in with Google in react native.
I have a global state for user :
const initialState = {
userId: null,
token: null,
email: "",
firstName: "",
lastName: "",
nom: "",
dateOfBirth: null,
roles: [],
photoUrl: "",
phoneNumber: "",
favorites: [],
};
With Login, it work well and my global state is update. The logic :
export const login = (email, password) => {
return async (dispatch) => {
const response = await auth.signInWithEmailAndPassword(email, password).then().catch((error) => {
Alert.alert("L'email ou le mot de passe est invalide");
throw new Error()
} );
if (response && response.user.uid === null) {
throw new Error("Something went wrong!");
}
const user = await db.collection("Users").doc(response.user.uid).get();
const expirationTime = (await response.user.getIdTokenResult())
.expirationTime;
const newDate = new Date(expirationTime).getTime();
const token = (await response.user.getIdTokenResult()).token;
await dispatch(authenticate(response.user.uid, token, newDate));
await dispatch(
addUserInfos(
user.get("email"),
user.get("username"),
user.get("firstName"),
user.get("lastName"),
user.get("dateOfBirth")?.toDate(),
user.get("roles"),
user.get("photoUrl"),
user.get("phoneNumber"),
user.get("favorites"),
)
);
const expirationDate = new Date(new Date().getTime() + newDate);
saveDataToStorage(token, response.user.uid, expirationDate);
};
};
But when i want to connect with Google. The app connect me but my global state only contain value userId and token. I need the reload the app for set my global state. However the 2 functions use the same logic.
export const addUserOnFirestore = (id, email, firstName, lastName, photoUrl, response, navigation) => {
return async (dispatch) => {
let isNeedOnboarding = false;
const user = await db
.collection('Users')
.doc(id)
.get();
// Create user in firestore in it not exist
if (!user.exists) {
isNeedOnboarding = true;
console.log('onboard : ', isNeedOnboarding);
await db.collection('Users').doc(id).set({
email: email,
username: '',
firstName: firstName ? firstName : '',
lastName: lastName ? lastName : '',
dateOfBirth: null,
roles: [],
photoUrl: photoUrl ? photoUrl : '',
phoneNumber: '',
favorites: [],
}).then(res => {
console.log("Effectué")
})
.catch(error => {
console.log("firestore error:", error);
});
} else {
console.log('Document data:', user.data());
}
const expirationTime = (await response.user.getIdTokenResult())
.expirationTime;
const newDate = new Date(expirationTime).getTime() * 1000;
const token = (await response.user.getIdTokenResult()).token;
await dispatch(authenticate(token, id, newDate));
if (isNeedOnboarding) {
await dispatch(addUserInfos(email, '', firstName, lastName, '', '', photoUrl, '', []));
navigation.navigate("Onboarding");
} else {
await dispatch(
addUserInfos(
user.get("email"),
user.get("username"),
user.get("firstName"),
user.get("lastName"),
user.get("dateOfBirth")?.toDate(),
user.get("roles"),
user.get("photoUrl"),
user.get("phoneNumber"),
user.get("favorites"),
)
);
}
const expirationDate = new Date(new Date().getTime() + newDate);
saveDataToStorage(token, id, expirationDate);
if (isNeedOnboarding) {
navigation.navigate("Onboarding");
}
};
};
The dispatch function addUserInfo :
const addUserInfos = (
email,
username,
firstName,
lastName,
dateOfBirth,
roles,
photoUrl,
phoneNumber,
favorites,
) => {
return (dispatch) => {
dispatch({
type: ADD_USER_INFO,
payload: {
email: email,
username: username,
firstName: firstName,
lastName: lastName,
dateOfBirth: dateOfBirth,
roles: roles,
photoUrl: photoUrl,
phoneNumber: phoneNumber,
favorites: favorites,
},
});
};
};
And the authenticate :
export const authenticate = (userId, token, expiryTime) => {
return (dispatch) => {
dispatch(setLogoutTimer(expiryTime));
dispatch({ type: AUTHENTICATE, payload: { userId, token } });
};
};
Do you have any idea why it works in the simple login but not when I want to connect with google?
Then why it is only when I reload the application that my global state is updated ?
Thanks in advance.

Related

Defining Role in backend MERN

How to define role to Admin, Customer, Worker and Log in with different roles in frontend ? Im new in coding.
For authentication, I'm using JWT. Now I want to add roles and rules for admin, worker and customer.
1 -> Permissions can be assigned to a role ( Create, Update, delete etc...).
As a result, a user can have one or more roles. A user can use APIs for which he has rights, such as creating data, deleting data, updating data, and so on.
Here is the user schema:
UserSchema.model
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const userSchema = mongoose.Schema(
{
role: {
type: String,
enum: ["admin", "customer", "worker"],
},
firstname: {
type: String,
required: true,
},
lastname: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
role: {
type: Boolean,
// required: true,
default: false,
enum: ["admin", "customer", "worker"],
},
pic: {
type: String,
// required: true,
default:
"https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg",
},
},
{
timestamps: true,
}
);
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
// will encrypt password everytime its saved
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
const User = mongoose.model("User", userSchema);
module.exports = User;
UserController
const asyncHandler = require("express-async-handler");
const User = require("../models/user.model");
const generateToken = require("../utility/token");
const authUser = asyncHandler(async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user && (await user.matchPassword(password))) {
res.json({
_id: user._id,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
isAdmin: user.isAdmin,
pic: user.pic,
token: generateToken(user._id),
});
} else {
res.status(401);
throw new Error("Invalid Email or Password");
}
});
const registerUser = asyncHandler(async (req, res) => {
const { firstname, lastname, email, password, pic } = req.body;
try {
const userExists = await User.findOne({ email });
if (userExists) {
return res.status(400).json({ error: "User already exist." });
}
const user = await User.create({
firstname,
lastname,
email,
password,
pic,
});
res.status(201).json({
_id: user._id,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
isAdmin: user.isAdmin,
pic: user.pic,
token: generateToken(user._id),
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
const updateUserProfile = asyncHandler(async (req, res) => {
const user = await User.findById(req.user._id);
if (user) {
user.firstname = req.body.firstname || user.firstname;
user.lastname = req.body.lastname || user.lastname;
user.email = req.body.email || user.email;
user.pic = req.body.pic || user.pic;
if (req.body.password) {
user.password = req.body.password;
}
const updatedUser = await user.save();
res.json({
_id: updatedUser._id,
firstname: updatedUser.firstname,
lastname: updatedUser.lastname,
email: updatedUser.email,
pic: updatedUser.pic,
isAdmin: updatedUser.isAdmin,
token: generateToken(updatedUser._id),
});
} else {
res.status(404);
throw new Error("User Not Found");
}
});
module.exports = { authUser, updateUserProfile, registerUser };
UserSchema.model
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const userSchema = mongoose.Schema(
{
role: {
type: String,
enum: ["admin", "customer", "worker"],
},
firstname: {
type: String,
required: true,
},
lastname: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
role: {
type: Boolean,
// required: true,
default: false,
enum: ["admin", "customer", "worker"],
},
pic: {
type: String,
// required: true,
default:
"https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg",
},
},
{
timestamps: true,
}
);
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
// will encrypt password everytime its saved
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
const User = mongoose.model("User", userSchema);
module.exports = User;
UserController
const asyncHandler = require("express-async-handler");
const User = require("../models/user.model");
const generateToken = require("../utility/token");
const authUser = asyncHandler(async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user && (await user.matchPassword(password))) {
res.json({
_id: user._id,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
isAdmin: user.isAdmin,
pic: user.pic,
token: generateToken(user._id),
});
} else {
res.status(401);
throw new Error("Invalid Email or Password");
}
});
const registerUser = asyncHandler(async (req, res) => {
const { firstname, lastname, email, password, pic } = req.body;
try {
const userExists = await User.findOne({ email });
if (userExists) {
return res.status(400).json({ error: "User already exist." });
}
const user = await User.create({
firstname,
lastname,
email,
password,
pic,
});
res.status(201).json({
_id: user._id,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
isAdmin: user.isAdmin,
pic: user.pic,
token: generateToken(user._id),
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
const updateUserProfile = asyncHandler(async (req, res) => {
const user = await User.findById(req.user._id);
if (user) {
user.firstname = req.body.firstname || user.firstname;
user.lastname = req.body.lastname || user.lastname;
user.email = req.body.email || user.email;
user.pic = req.body.pic || user.pic;
if (req.body.password) {
user.password = req.body.password;
}
const updatedUser = await user.save();
res.json({
_id: updatedUser._id,
firstname: updatedUser.firstname,
lastname: updatedUser.lastname,
email: updatedUser.email,
pic: updatedUser.pic,
isAdmin: updatedUser.isAdmin,
token: generateToken(updatedUser._id),
});
} else {
res.status(404);
throw new Error("User Not Found");
}
});
module.exports = { authUser, updateUserProfile, registerUser };

Mongoose FindOneandUpdate - Only update Specific fields leave others with the previous values

I would like to update just the fields that the user chose to update, but right now if I don't fill all the inputs, they became null in the data base.
this is the back end
router.put('/user/:id', async (req, res) => {
let id = req.params.id
const salt = await bcrypt.genSalt(10)
const hashPassword = await bcrypt.hash(req.body.password, salt)
const emailExist = await User.findOne({ email: req.body.email })
if (emailExist) {
return res.status(400).send('Email already exists')
}
//creat user
const update = {
name: req.body.name,
lastName: req.body.lastName,
phone: req.body.phone,
email: req.body.email,
bio: req.body.bio,
password: hashPassword,
role: "basic"
}
User.findByIdAndUpdate(id, { $set: update }, { new: true }, (error, userObj) => {
if (error) {
res.status(400).send(err)
} else {
res.send('user updated')
}
})
})
Front end (react)
const updateUser = async (event) => {
event.preventDefault()
const response = await axios.put(`/userinfo/user/${localStorage.getItem('id')}`, {
name: name,
lastName: lastName,
phone: phone,
email: email,
password: password,
confPassword: confPassword,
bio: bio,
})
history.push('/home-login')
const reload = window.location.reload()
}
Thank you
Try handy methods of lodash NPM, install it and import in your node.js file,
Pick update fields from body:
let update = _.pick(req.body, ["name", "lastName", "phone", "email", "bio"]);
Remove undefined, null and "" empty fields:
update = _.pickBy(update, _.identity);
Merge other fields:
update = _.merge(update, {
password: hashPassword,
role: "basic"
});
Use in query:
User.findByIdAndUpdate(id, { $set: update }, { new: true }, (error, userObj) => {
if (error) res.status(400).send(err)
else res.send('user updated')
})

React frontend + WordPress API create/register user with frontend registration form

I have an issue with frontend form submission with React Axios. Using WordPress API to create a user through the frontend registration form. The form has 3 fields username, email and password. Also, I have JWT plugin installed for the token authorisation. The current error is 400 bad request. And the catch error message is "Missing parameter(s): password"
const Register = ({ props }) => {
const [register, setRegister] = useState({
username: '',
email: '',
password: '',
userCreated: false,
loading: false,
token: '',
message: ''
})
const handleOnSubmit = e => {
e.preventDefault()
setRegister({ loading: true })
console.log(register)
const userData = {
username: e.target[0].value,
email: e.target[2].value,
password: e.target[4].value
//role: 'Administrator'
}
const authToken = localStorage.getItem('token')
axios.post('http://localhost:8888/react/wp-json/wp/v2/users', userData, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`
}
})
.then(res => {
setRegister({
loading: false,
userCreated: !!res.data.id,
message: res.data.id ? 'New user created' : '',
})
console.log(res)
})
.catch(err => {
setRegister({
loading: false,
message: err.response.data.message,
})
console.log(err)
})
}
const handleOnChange = e => {
setRegister({ ...register, [e.target.name]: e.target.value })
console.log(register)
}
const { password, username, email, loading, error } = useState()
return ( my form here )

How to request with nested json in react native?

I am trying to send the nested object to the server with authorization token, I searched for this issue but not getting a solution from any sites
This is how I send Data:
CallUpdateProfile = () => {
AsyncStorage.getItem('token', (err, token) => {
tokenAuth = token
});
AsyncStorage.getItem('userId', (err, userID) => {
UserID = userID
});
const insideData={
userId : UserID,
contactparam :{
firstName: this.state.firstName,
lastName: this.state.lastName,
emailAddress: this.state.emailAddress,
cellPhoneNumber: this.state.cellPhoneNumber,
}
};
console.log(insideData);
updateProfile(insideData)
.then(response => {
let data = response.data.data;
})
.catch(error => {
console.error(error);
})
}
but result is
{
"contactparam": {
"firstName": "DK2",
"lastName": "KHATRI",
"emailAddress": "abc#hmail.com",
"cellPhoneNumber": "9999999990"
}
}
what is the expected result ?
userId: 1,
{
"contactparam": {
"firstName": "DK2",
"lastName": "KHATRI",
"emailAddress": "abc#hmail.com",
"cellPhoneNumber": "9999999990"
}
}
In your code insideData object create before AsyncStorage fetch userId. So make CallUpdateProfile as async & wait until AsyncStorage fetch userId as below.
CallUpdateProfile = async () => {
await AsyncStorage.getItem("token", (err, token) => {
tokenAuth = token;
});
await AsyncStorage.getItem("userId", (err, userID) => {
UserID = userID;
});
const insideData = {
userId: UserID,
contactparam: {
firstName: this.state.firstName,
lastName: this.state.lastName,
emailAddress: this.state.emailAddress,
cellPhoneNumber: this.state.cellPhoneNumber
}
};
console.log(insideData);
updateProfile(insideData)
.then(response => {
let data = response.data.data;
})
.catch(error => {
console.error(error);
});
};
You can use the following snippet to archive the desired object
CallUpdateProfile = async () => {
const UserID = await AsyncStorage.getItem('userId');
if (UserID !== null) {
const insideData = {
userId: UserID,
contactparam: {
firstName: this.state.firstName,
lastName: this.state.lastName,
emailAddress: this.state.emailAddress,
cellPhoneNumber: this.state.cellPhoneNumber,
}
}
// continue you implentation
}
};

Add array of images to Firebase storage and realtime database using React JS

I am trying to push an array of local images to Firebase store and my database. The images are being outputted in my database json scheme but nothing is showing up in storage and keep receveing the following errors below. Any thoughts?
Error:
Database JSON scheme:
{
"users" : {
"XhLxS1KUS8UyHjsuHYrEuyipQX53" : {
"Email" : "ssssss#gmail.com",
"code" : "bob",
"image1" : {
"id" : "223d7f60-331b-11e9-b680-6b36b34d4cc6",
"url" : "holder1.png"
},
"image2" : {
"id" : "223da670-331b-11e9-b680-6b36b34d4cc6",
"url" : "holder2.png"
},
"image3" : {
"id" : "223da671-331b-11e9-b680-6b36b34d4cc6",
"url" : "holder3.png"
},
"location" : "fl"
}
}
}
React JS:
const images = [
{
id: uuid(),
url: `holder1.png`
},
{
id: uuid(),
url: `holder2.png`
},
{
id: uuid(),
url: `holder3.png`
}
];
class Register extends Component {
state = {
email: '',
password: '',
code: 'bob',
location: 'fl',
image: null,
url: '',
error: null,
arr: images,
};
handleInputChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
handleChange = e => {
if (e.target.files[0]) {
const image = this.state.arr;
this.setState(() => ({ image }));
console.log(image)
}
}
handleSubmit = (event) => {
event.preventDefault();
const { email, password, image, url } = this.state;
const storageRef = storage.ref(`images/`);
this.state.image.map((file, index) => {
storageRef
.child(`${file.url}`)
.getDownloadURL().then(url => {
this.setState({ url }); <---Should I set state?
})
});
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((user) => {
firebase
.database()
.ref('users/' + user.user.uid)
.set({
Email: user.user.email,
code: this.state.code,
location: this.state.location,
image1: images[0],
image2: images[1],
image3: images[2]
})
//console.log(this.state.url)
this.props.history.push('/');
})
.catch((error) => {
this.setState({ error: error });
});
};
....
This works for a single image to storage:
React JS:
class Register extends Component {
state = {
email: '',
password: '',
code: 'bob',
location: 'fl',
image: null,
url: '',
error: null,
};
handleInputChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
handleChange = e => {
if (e.target.files[0]) {
const image = e.target.files[0];
this.setState(() => ({image}));
}
}
handleSubmit = (event) => {
event.preventDefault();
const { email, password, image, url } = this.state;
const uploadTask = storage.ref(`images/${image.name}`).put(image);
uploadTask.on('state_changed', () => {
storage.ref('images').child(image.name).getDownloadURL().then(url => {
console.log(url);
this.setState({url});
})
});
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((user) => {
firebase
.database()
.ref('users/' + user.user.uid)
.set({
Email: user.user.email,
code: this.state.code,
location: this.state.location,
image: this.state.url
})
this.props.history.push('/');
})
.catch((error) => {
this.setState({ error: error });
});
};
...
As I commented on your previous question:
You need to write the URL to the database from within the callback to getDownloadUrl(). So where you now call this.setState({url});, call something like firebase.database().ref('users/' + user.user.uid + '/image').set(url); too.
In addition, as far as I can see from the documentation, there are three callbacks for UploadTask.on('state_changed' and the third is called when the upload is completed.
So:
uploadTask.on('state_changed', function(snapshot) {
// handle progress messages here
},(error) => {
// handle errors here
},() => {
storage.ref('images').child(image.name).getDownloadURL().then(url => {
console.log(url);
this.setState({url});
firebase.database().ref('users/' + user.user.uid + '/image').set(url);
})
});

Resources