How to send data from expressjs to react client? - reactjs

I have a payments.js page that use a custom form to make a payemnt with stripe which looks like this
async handleSubmit() {
const { firstName, lastName, email, cardNo, expiryDate, cvv, nameOnCard } = this.state
const { price } = this.props.location.state.item
this.setState({
loading: true
});
await axios.post("/charge", {
firstName,
lastName,
email,
cardNo,
expiryDate,
cvv,
nameOnCard,
price
}).then((res) => this.setState({ iframeLink: res.data.next_action.redirect_to_url.url, loading: false }))
.catch((error) => console.log('ERR', error))
// I want this to wait for changes
await axios.post("/api/stripe/webhooks").then((res) => console.log(res)).catch((err) => console.log(err))
}
I am opening the url received in first post in iframe and once the 3d secure is done I want to get stripe hooks with this line which is called once after first post and then will not update once another hook is received
await axios.post("/api/stripe/webhooks").then((res) => console.log(res)).catch((err) => console.log(err))
My problem here is that the data is never received in this action
In server the post function looks like this
// Stripe Webhooks
app.post("/api/stripe/webhooks", async function (req, res) {
try {
const query = req.body;
res.sendStatus(200);
console.log(query)
res.end(JSON.stringify(query))
} catch (err) {
console.log("/webhooks route error: ", err);
}
});
Any idea how to catch the data when is received?

Related

When sign in with google firebase always register user as new

Tech: Firebase, Next.js, Google Sign in, Firebase Stripe exstension
Bug reproduction:
When login with Google
Subscribe on stripe
Stripe saves subscription data for that user in firestore
Logout
Login in with Google and old data are overide with new one, and Subscription is lost
Does anyone had similar problem?
Maybe my implementation of Sign-in is bad, here is the Google Sign in code:
const handleGoogleLogin = () => {
signInWithPopup(auth, googleProvider)
.then(async result => {
if (!result.user) return;
const { displayName, email, uid, providerData, photoURL, phoneNumber } =
result.user;
const name = splitName(displayName as string);
const providerId =
(providerData.length && providerData[0]?.providerId) || '';
const data = {
firstName: name?.firstName || '',
lastName: name?.lastName || '',
email,
photoURL,
phoneNumber,
providerId,
};
await updateUser(uid, data);
})
.catch(error => {
console.log('Google login error: ', error);
});
};
Update user function:
export const updateUser = async (uid: string, data: UpdateUserParams) => {
try {
if (!uid) {
return;
}
await setDoc(doc(firestore, 'users', uid), {
account: {
...data,
initials: `${data.firstName[0]}${data.lastName[0]}`,
},
});
} catch (error) {
console.error('Error updating user: ', error);
}
};
setDoc is overwriting the contents of the document with each sign-in. You should instead use set with merge to prevent overwriting the fields you don't want to lose, or check first if the document exists before creating it.
See also:
https://firebase.google.com/docs/firestore/manage-data/add-data#set_a_document
Difference Between Firestore Set with {merge: true} and Update

users are not stored in the firestore database but are visible in authentication

I am trying to build a chat application with React and firebase. As soon as the user registers, the authentication works perfectly as well as their pictures get stored in the storage bucket but the user is not stored in the firestore database under the users collection.
I am getting this error in the console:
Below is a code snippet from my register component:
try {
const res = await createUserWithEmailAndPassword(auth, email, password);
const storageRef = ref(storage, displayName);
console.log(storageRef);
const uploadTask = uploadBytesResumable(storageRef, file);
console.log(uploadTask);
uploadTask.on(
(error) => {
setErr(true);
console.log(err);
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then(async (downloadURL) => {
await updateProfile(res.user, {
displayName,
photoURL: downloadURL,
});
await setDoc(doc(db, "users", res.user.uid), {
uid: res.user.uid,
displayName,
email,
photoURL: downloadURL,
});
//Document containing the user's chats
await setDoc(doc(db, "userChats", res.user.uid), {});
navigate("/");
});
}
);
} catch {
setErr(true);
}
Mixing Promise-based APIs and Callback-based APIs will lead to trouble. By exclusively sticking to one type, you can ensure that behaviour will be as you expect.
The UploadTask class is "Thenable" - it has a then() and catch() method which will be fed the upload complete and upload error events. This means you can use it with await or like any other Promise API.
Because you are doing further Promise-based work in the upload complete event, using UploadTask.on should be avoided and only be used for updating progress of the upload. As your code doesn't use this progress update feature, I'll be omitting it, but it would be done using something like:
uploadTask.on('state_changed', (snapshot) => /* progress update */);
Additionally, close to the end of your code you attempt to add an empty document to Firestore for the user's messages. This will do nothing as empty documents are automatically deleted by Firestore on the backend. As such, it will be omitted from the code below.
By applying these changes, your code becomes:
try {
// ⬇ you can unwrap user from the userCredential object, better than using "res"
const { user } = await createUserWithEmailAndPassword(auth, email, password);
const storageRef = ref(storage, displayName);
console.log(storageRef);
const uploadTask = uploadBytesResumable(storageRef, file);
console.log(uploadTask);
// if using it, add progress updater here
// uploadTask.on('state_changed', (snapshot) => /* progress update */);
const uploadSnapshot = await uploadTask; // waits for upload completion
const downloadURL = await getDownloadURL(uploadSnapshot.ref);
await updateProfile(user, {
displayName,
photoURL: downloadURL,
});
await setDoc(doc(db, "users", user.uid), {
uid: user.uid,
displayName,
email,
photoURL: downloadURL,
});
navigate("/");
} catch {
console.log(err); // don't forget to log the error so you can investigate
setErr(true);
}
Ideally, you would move most of this logic outside of your component into your UserContext using something similar to:
​const userCtx = useContext(YourAuthUserContext);
userCtx.createUserAndUserData({ email, password, displayName, file })
.then((user) => {
navigate("/");
})
.catch((err) => {
console.log("createUserAndUserData failed:", err);
setErr(true);
});

How can I properly handle request errors with React front end?

Currently I have my backend set up as such on the '/register' route:
registerRouter.post('/', async (req, res) => {
// Validate submitted registration form
const { error } = registerValidation(req.body)
if(error) {
return res.status(400).send(error.details[0].message)
}
try {
// Check if email exists already
const user = await User.findOne({ email: req.body.email })
if(user) {
return res.status(400).send('Email already exists')
}
// If not, begin registering user by hashing the password
const hashedPassword = await bcrypt.hash(req.body.password, 10)
const newUser = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: hashedPassword
})
const savedUser = await newUser.save()
res.send(savedUser)
} catch(error) {
res.sendStatus(500)
}
})
Using Postman I get the proper responses when I make correct/incorrect requests. But when I make requests on my frontend, if it is an incorrect request, e.g. not long enough password, missing a required field, then I just get a 400 response. How can I use the error response to, for example, display the error on-screen for the user to see?
This is my current onSubmit function for the form:
const register = async event => {
event.preventDefault()
axios
.post('/register', newUser)
.then(res => console.log(res))
.catch(err => console.log(err))
}
try to use:
axios
.post('/register', newUser)
.catch(function (error) {
console.log(error.toJSON()); // or maybe exist .toText()
});
(https://github.com/axios/axios#handling-errors)
also convert it on server side:
return res.status(400).send('Email already exists')
to
return res.status(400).send({ error: 'Email already exists' });

React Native (expo) and Firebase Firestore - Issue when a user is created within the app (Undefined is not an object...evaluating...)

I am having trouble with firebase and expo. When we do the signup process, and the user is generated through firebase, we sometimes get "undefined is not an object (evaluating 0.docs[0].data)" and the user is redirected to the entry point of the application instead of going to the next screen.
Most of the users will be able to go through the process without any problem. But few reported the same issues, and I have seen that with one account.
Here below the function that does not work properly
const createUser = async () => {
//Check if user already exists
await props.firebase.db
.collection('users')
.where('email', '==', props.userProfile.email)
.get()
.then(async (snapShot) => {
//if no document is found, save user to db
if (snapShot.docs.length === 0) {
await saveUserToDataBase()
.then(() => {
setShowLoader(false);
props.navigation.navigate('NotificationPermission');
})
.catch((err) => Alert.alert('An error occurred', err.message));
}
//else log an error, TODO: add error text in app.
else {
setShowLoader(false);
}
})
.catch((err) => {
Alert.alert('An error occurred', err.message);
});
};
const saveUserToDataBase = async () => {
//finds the correct collection and creates a new document within in containing the profile data.
await props.firebase.db
.collection('users')
.add({
first_name: props.userProfile.firstName,
email: props.userProfile.email.toLowerCase(),
phone_number: props.userProfile.phoneNumber,
organization: props.userProfile.organization,
profileId: props.userProfile.profileId,
})
.then(async (docRef) => {
await props.firebase.db
.collection('profile')
.doc(props.userProfile.profileId)
.update({
user_id: docRef.id,
})
.then(async () => {
await uploadProfilePhoto(docRef.id);
if (props.accessToken) {
props.navigation.navigate('NotificationPermission');
} else {
props.navigation.navigate('NotificationPermission');
}
})
.catch((err) => {
Alert.alert(
'An error occurred updating the users profile ',
err.message,
);
});
})
.catch((err) => {
Alert.alert('An error occurred creating the user', err.message);
});
};
I have used the Alert component to check the error directly, the error is consistent with few email addresses. I have upgraded the firebase package, did no do anything.
I feel like the onAuthStateChanged could be responsible of that but I am not sure how to handle that? Your help or suggestions will be greatly appreciated.

Axios-Redux in React to an Express endpoint-both .then and .catch triggered

I'm using a Redux Form to send a POST call to an Express endpoint. The endpoint is supposed to return the successfully saved object, or an error.
The endpoint successfully saves the posted data and returns the JSON. But Axios in the Redux action picks up both the .then and the .catch triggers-in the following action, it logs the following:
successful response: { …}
failure response: undefined
What am I doing wrong?
My Axios action:
export function addPlot(props) {
const user = JSON.parse(localStorage.getItem('user'));
return function(dispatch) {
axios
.post(
`${ROOT_URL}/plots`,
{
props
},
{ headers: { authorization: user.token } }
)
.then(response => {
console.log('successful response: ', response.data);
const plotModal = document.getElementById('plotModal');
plotModal.modal('dispose');
dispatch({ type: PLOT_ADDED, payload: response.data });
dispatch({ type: ADDING_PLOT, payload: false });
dispatch({
type: NEW_PLOT_GEOJSON,
payload: ''
});
})
.catch(response => {
console.log('failure response: ', response.data);
dispatch(authError(PLOT_ADD_FAILURE, 'Failed to add plot'));
});
}
My endpoint:
exports.newPlot = async (req, res, next) => {
console.log(JSON.stringify(req.body.props));
let company;
if (req.user.companyCode !== 'Trellis') {
company = req.user.companyCode;
} else {
company = req.body.props.company;
}
const {
name,
feature,
growerPhone,
plotCode,
rootStock,
region,
variety,
grower,
planted
} = req.body.props;
const plot = new Plot({
name,
grower,
variety,
planted,
region,
rootStock,
plotCode,
growerPhone,
feature,
company
});
try {
const newPlot = await plot.save();
res.json(newPlot);
} catch (e) {
console.log("couldn't save new plot", JSON.stringify(e));
return res.status(422).send({ error: { message: e, resend: true } });
}
};
You could use redux-thunk middleware to manage async actions.
The problem I see is that you are not dispatching the axios action, you must call dispatch(this.props.addPlot(props))in order to do something in the redux store.

Resources