How to request with nested json in react native? - reactjs

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
}
};

Related

Can't cover lines inside a React/Typescript try catch with Jest

I have the following code in React/TypeScript:
const logUser = async () => {
console.log(`Logging: ${email} - ${password}`);
try {
const res = await axios({
method: "post",
url: `${process.env.REACT_APP_BASE_URL}/api/auth`,
headers: {
"Content-Type": "application/json",
"Accept-Language": localStorage.getItem("i18nextLng"),
},
data: {
email: email,
password: password,
},
});
const user = buildUserData(res.data.data);
saveUserData(user.name, user.email, user.roles, user.token);
setDismissAlert(true);
console.log(res.data);
login().then(() => navigate("/dashboard/overview"));
} catch (err: any) {
if (err.response?.data.otp) {
navigate("/otp", { state: { email: email, password: password } });
} else if (err.data?.data.message) {
setLoginError(err.data?.data.message);
setDismissAlert(false);
} else {
setLoginError(t("login.validation.loginError"));
setDismissAlert(false);
}
}
};
In my tests, besides the axios.post.mockResolvedValueOnce(); returns what is expected with the sucessful request, the lines below just don't get covered:
const user = buildUserData(res.data.data);
saveUserData(user.name, user.email, user.roles, user.token);
setDismissAlert(true);
console.log(res.data);
login().then(() => navigate("/dashboard/overview"));
I tried to return a mock data in this way:
const mockResponse = {
data: {
user: {
id: 1,
name: "user",
email: "user#mail.com",
email_verified_at: null,
created_at: "2022-12-27T17:10:23.000000Z",
updated_at: "2022-12-27T17:10:29.000000Z",
deleted_at: null,
last_login_at: "2022-12-27T17:10:29.301355Z",
roles: ["user"],
},
token: {
access_token: "1|Buc8kgCTGFzHdS2HU11ZmWS30SEXHEiLCEQGbBnH",
token_type: "Bearer",
},
},
};
And in my tests:
axios.post.mockResolvedValueOnce(mockResponse);
But this won't solve the uncovered lines.
What I need to do to cover the lines after the axios request inside the try block (not catch)?
Try this - instead of using this API:
const res = await axios({
method: "post",
url: `${process.env.REACT_APP_BASE_URL}/api/auth`,
use this:
const res = await axios.post(`${process.env.REACT_APP_BASE_URL}/api/auth`, {...
Then in your tests:
import axios from "axios";
jest.mock("axios");
it('some test', async () => {
axios.post.mockResolvedValueOnce(mockResponse);
// here your test
});

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

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.

NextJs creating user document in mongodb after google sign in

i want to create a user document after i sign in with google in my nextjs application. I can sign in but it's not creating the document after it. This is my function
const handleSignIn = async () => {
try {
await signIn("google");
await addUser();
} catch (error) {
console.log("Erro");
}
};
The addUser function is
const addUser = async () => {
if (status === "authenticated") {
const user = {
name: session.user.name,
email: session.user.email,
avatar: session.user.image,
};
try {
await fetch("/api/new_user", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(user),
});
} catch (error) {
console.log(error);
}
} else {
console.log("Not logged in");
}
};
This is how i'm creating the new document in my new_user.ts file in the api folder
export default async function handleNewUser(req:NextApiRequest, res:NextApiResponse){
const client = await clientPromise;
const db = client.db("bookdb");
const coll: Collection = db.collection("users");
const user = req.body
console.log(user)
try {
await coll.insertOne(user)
res.status(200).json({response:'Success'})
} catch (error) {
res.status(500).json({error:'Erro'})
To make sure it was working, i triggered manually the addUser function after signing in and it worked.
What am i doing wrong here?
this is my snippet for google auth sign in with mongodb and nextjs using typescript and prisma.
signIn: async ({user, account}) => {
if (account?.provider === 'google') {
const googleAuthData = {
name: user.name,
email: user.email,
image: user.image,
authProvider: 'google',
password: ''
}
const exist = await prisma.user.findFirst({
where: {email: user.email},
});
if (exist) {
const result = await prisma.user.update({
where: {email: user.email},
data: {image: user.image},
});
} else {
const result = await prisma.user.create({
data: googleAuthData,
});
}
}
return true;
},

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')
})

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