Res.json not sending data in React app and appearing as undefined - reactjs

I am developing a React with Nodejs backend and I have implemented "stripe" in order to process payments. The problem appears when I need to get the URL which should redirect me to the Stripe payment form. I should get it from a json response, but it is empty, no matter what I send. I've even tried sending really simple data, but it still doesn't work. I've used it before without problems in this project, so I don't know what I am doing wrong here. Can anyone offer any help? Thank you!
This is the router file, which creats the session for the payment and which is also supposed to send the needed URL. I tested and the URL is correct, it is just a matter of sending it through res.json
router.post("/payment", async(req, res) => {
const course = await Courses.findByPk(req.body.items[0].id);
const storeItems = new Map([
[course.id, { priceInCents: course.price, name: course.title }],
])
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
mode: 'payment',
line_items: req.body.items.map(item => {
const storeItem = storeItems.get(item.id)
return {
price_data: {
currency: "usd",
product_data: {
name: storeItem.name,
},
unit_amount: storeItem.priceInCents,
},
quantity: item.quantity,
}
}),
success_url: 'http://localhost:3000/profile-page',
cancel_url: `http://localhost:3000/course-details/${course.id}`
})
res.json({ url: session.url });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
And this is where I should be getting the URL back, but I don't. Instead, when I console.log it, I get "undefined".
if (response.data.error) {
alert(response.data.error);
} else {
axios.post("http://localhost:3001/users_courses/payment", {
items: [
{ id: data.id, quantity: 1 },
],
}, {
headers: {
accessToken: localStorage.getItem("accessToken"),
},
}).then(res => {
if(res.ok) return res.json();
return res.json().then(json => Promise.reject(json));
}).then (( { url }) => {
window.location.href = url;
console.log(url + " this is the url");
}).catch(e => {
console.error(e.error);
})
}

I think it has to do with how you’re handling your axios post, I think with a small change like I suggested below this should work for you.
axios
.post(
"http://localhost:3001/users_courses/payment",
{
items: [{ id: response.data.id, quantity: 1 }],
},
{
headers: {
accessToken: localStorage.getItem("accessToken"),
},
}
)
.then(({ data: { url } }) => {
window.location.replace(url);
console.log(url + " this is the url");
})
.catch((e) => {
console.error(e.error);
});
Note that axios is not like the fetch API where you have to handle the transformation of the response body into the json object.

Related

RedirectToCheckout() not working when processing Stripe payments with Netlify functions (ReactJs)

I have a function called stripe.js as follows
const stripe = require("stripe")(process.env.STRIPE_SECRET_TEST);
exports.handler = async (event, context) => {
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
line_items: [
{
price_data: {
currency: "gbp",
product_data: {
name: "Prunus serrulata",
},
unit_amount: 6000,
},
quantity: 1,
},
],
mode: "payment",
success_url: "/success",
cancel_url: "/cancel",
});
return {
statusCode: 200,
body: JSON.stringify({
id: session.id,
}),
};
};
that is called from the checkout component
import React from "react";
import Stripe from "stripe";
const stripe = Stripe(
"pk_test_51HqgwdGKpDMhyEuL11A63hDc42CNdjZbMH93xDPIumVyYlgGe5byVF9rXhgW0rs64r0uaDjQUqlwOUDXrbTZy9nx00cyCIwiBm"
);
const callApi = () => {
fetch("/api/stripe", {
method: "POST",
})
.then((response) => response.json())
.then((response) => console.log(response))
.then((session) => {
return stripe.redirectToCheckout({ sessionId: session.id });
})
.then((result) => {
if (result.err) {
alert(result.err.message);
}
})
.catch((err) => {
console.error("Error:", err);
});
};
const Checkout = () => {
return (
<div>
<form
onSubmit={callApi}
>
<ChkButton>Checkout</ChkButton>
</form>
</div>
);
};
I get this in Stripe:
Stripe session
The data is going to stripe successfully but the payment page does not load because I think I have the redirect wrong?
Can anyone point me out in the right direction please?
Any help would be much appreciated
I have been following this tutorial https://www.freecodecamp.org/news/serverless-online-payments/
trying to modify it to work in my app but I have only got this far.
I have googled it and I have not found a solution and neither in Netlify forums.
session is currently undefined because you aren't returning the response.json().
Overall, that second .then chain is not necessary as well though I assume you just have it for logging purposes. Try:
.then((response) => {
return response.json();
})
.then((session) => {
return stripe.redirectToCheckout({ sessionId: session.id });
})

MongoDB / ReactJS Patch handler / findOneAndUpdate not working

in the following code, I'm attempting to update the Checkpoints field for one of my objects within the projects collection. UpdatedCheckpoints is working correctly, so I believe the first block of code works. But the change isn't logging to the database so it doesn't persist. What's going wrong?
const onApprovedSubmit = useCallback(
async (e) => {
e.preventDefault();
let updatedCheckpoints = props.project.Checkpoints;
updatedCheckpoints[props.checkpointIndex].checkpointSubmitted = true;
console.log('here');
try {
let projectId = props.project._id;
await fetcher('/api/projects', {
method: 'PATCH',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({ Checkpoints: updatedCheckpoints }),
id: projectId,
});
toast.success('Your checkpoint has been updated');
} catch (e) {
toast.error(e.message);
}
},
[props],
);
handler.patch(async (req, res) => {
const db = await getMongoDb();
const project = await updateProjectById(db, req.id, req.body);
res.json({ project });
});
export async function updateProjectById(db, id, data) {
return db
.collection('projects')
.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$set: data,
},
{ returnDocument: 'after' },
)
.then(({ value }) => value);
}

Cookies are not authorized, we will not send any data. when trying to use Paystack inmy next app

I keep getting this message when I am trying to use payStack in Next.js, And I have looked for any possible means to solve this but I haven't seen the solution to it
const componentProps = {
email: userInfo.email,
amount: totalPrice * 100,
metadata: {
name: shippingAddress?.fullName,
},
publicKey,
text: "Pay Now",
onSuccess: async () => {
try {
dispatch({ type: "PAY_REQUEST" });
const { data } = await axios.put(
`/api/orders/${order._id}/pay`,
{
headers: {
authorization: `Bearer ${userInfo.token}`,
},
}
);
dispatch({ type: "PAY SUCESS", payload: data });
alert("Thanks for doing business with us! Come back soon!!");
} catch (error) {
alert(getError(error));
}
},
onClose: () => alert("Wait! Don't leave :("),
};
And the message on my console is "Cookies are not authorized, we will not send any data."
This is the endpoint
import axios from "axios";
import nc from "next-connect";
import { isAuth } from "../../../../lib/auth";
const handler = nc();
handler.use(isAuth);
handler.put(async (req, res) => {
const projectId = "projectId";
const dataset = "dataset";
const tokenWithAccess =token
await axios.post(
`https://${projectId}.api.sanity.io/v1/data/mutate/${dataset}`,
{
mutations: [
{
paths: {
id: req.query.id,
set: {
isPaid: true,
paidAt: new Date().toString(),
"paymentResult.id": req.body.id,
"paymentResult.status": req.body.email_address,
"paymentResult..email_address": req.body.id,
},
},
},
],
},
{
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${tokenWithAccess}`,
},
}
);
res.send({ message: "Order Successfully" });
});
export default handler;
Here is my endpoint for the order information

Paypal REST api "ORDER_NOT_APPROVED" after successfully going through checkout flow via react native webview

SOLUTION: Make sure you're not stuck in an infinite loop of redirects leading to no approval of the payment. Make sure you put a "return_url" such as the code snippet i used below... This solved my problem and i finally got an approval after nearly 7 hours of headaches.
const dataString = `{
"intent": "CAPTURE",
"purchase_units": [{
"amount": {
"currency_code": "USD",
"value": "${amount.toFixed(2).toString()}"
},
"payee": {
"email_address": "${user.paypal_payment_address.toString()}"
},
"payment_instruction": {
"disbursement_mode": "DELAYED"
}
}],
"payer": {
"email_address": "${email.toLowerCase()}"
},
"application_context": {
"return_url": "https://api.sandbox.paypal.com/v2/checkout/orders/9V25205876068781J/capture"
}
}`;
I'm using the MERN stack (mongodb, node, react native, express.JS - so just javascript) but I'm trying to do a "delayed" payment with the PayPal REST api. I successfully create the order with the following code...
mongo.connect(config.get("mongoURI"), { useNewUrlParser: true }, { useUnifiedTopology: true }, cors(), (err, db) => {
router.post("/", (req, res) => {
const { amount, vehicle, paypal_access_token } = req.body;
const database = db.db("<dbname>");
const collection = database.collection("users");
collection.findOne({ "broken_vehicles_listings.id": vehicle.id }).then((user) => {
if (user) {
const configgg = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${paypal_access_token}`,
"PayPal-Partner-Attribution-Id": null
}
}
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${paypal_access_token}`
};
const dataString = `{
"intent": "CAPTURE",
"purchase_units": [{
"amount": {
"currency_code": "USD",
"value": "${amount.toFixed(2).toString()}"
},
"payee": {
"email_address": "${user.paypal_payment_address.toString()}"
},
"payment_instruction": {
"disbursement_mode": "DELAYED"
}
}]
}`;
const options = {
url: 'https://api.sandbox.paypal.com/v2/checkout/orders',
method: 'POST',
headers: headers,
body: dataString
};
const callback = (error, response, body) => {
if (!error) {
const parsed = JSON.parse(body);
console.log("MAJIC HAPPENED!!!!!!: ", parsed);
res.json({
message: "Successfully executed paypal logic!",
links: parsed.links,
data: parsed
})
} else {
console.log(error);
}
}
request(options, callback);
} else {
res.json({
message: "Could not locate the appropriate user..."
})
}
}).catch((err) => {
console.log(err);
});
});
});
This successfully creates a paypal order but i need to get the order status to "APPROVED" which apparently isn't happening even though it redirects me "back to test store" after choosing and submitting the desired payment option. When i use the below code snippet to "CAPTURE" the order is get an error stating
"Payer has not yet approved the Order for payment. Please redirect the payer to the 'rel':'approve' url returned as part of the HATEOAS links within the Create Order call or provide a valid payment_source in the request."
I do exactly as it says and use the "approve" url in react native webview to process the interaction within my app instead of leaving the app. The package used is react-native-webview.
mongo.connect(config.get("mongoURI"), { useNewUrlParser: true }, { useUnifiedTopology: true }, cors(), (err, db) => {
router.post("/", (req, res) => {
const { id, paypal_access_token, order_id } = req.body;
console.log("req.body", req.body);
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${paypal_access_token}`
};
const dataString = `{}`;
const options = {
url: `https://api.sandbox.paypal.com/v2/checkout/orders/${order_id}/authorize`,
method: 'POST',
headers: headers,
body: dataString
};
const callback = (error, response, body) => {
if (!error) {
const parsed = JSON.parse(body);
console.log("IT WORKED!!~!", parsed);
} else {
console.log(error);
}
}
request(options, callback);
});
});
I'm either doing something significantly wrong or paypal documentation sucks. please help.....
EDIT: I just confirmed the order is in "created" status but i cannot figure out how to get it into "approved" status
I found the solution 100%, the problem is that when a user accepts payment, need to navigate to a waiting page, then call the CAPTURE api to complete :
"intent": "CAPTURE",
"application_context":{
"user_action":"PAY_NOW",
"return_url":"https://example.com/",// Very important
"cancel_url":"https://example.com/"
},
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
],

Axios > Express.router – Update(.put) method returning 404

I am trying to finish building the last CRUD method of my App. (C, R and D) all done. But updating seems to be proving bothersome. I have a function which combines the object ID with the new content to update with. I am getting Error: Request failed with status code 404printed to the console.
I think I'm failing to reach the database item using the ID.
Function which gathers the data and initiates the request
handleClick(e) {
e.preventDefault()
const data = {
id: this.props.sid, //someuniqueid
body: {
name: this.state.name, //foo
details: this.state.details, //bar
content: this.state.content, //baz
},
}
api
.updateSnippet(data)
.then(result => {
this.setState({
name: '',
details: '',
content: '',
message: `'${this.state.name}' has been created`,
})
setTimeout(() => {
this.setState({
message: null,
})
}, 2000)
console.log('UPDATE DATA SUCCESS!')
})
.catch(err => this.setState({ message: err.toString() }))
}
api.js - uses axios to fire the request (this may be where I am failing).
import axios from 'axios'
const service = axios.create({
baseURL:
process.env.NODE_ENV === 'production'
? '/api'
: 'http://localhost:5000/api',
withCredentials: true,
})
const errHandler = err => {
console.error(err)
if (err.response && err.response.data) {
console.error('API response', err.response.data)
throw err.response.data.message
}
throw err
}
export default {
service: service,
updateSnippet(data) {
console.log(data.id) //someuniqueid
console.log(data.body) //{name: "foo", details: "bar", content: "baz"}
return service
.put('/snippets' + data.id, {
data: data.body,
})
.then(res => res.data)
.catch(errHandler)
},
}
Snippet.js (schema)
const mongoose = require('mongoose')
const snippetSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'The snippet name is required'],
minlength: 1,
},
details: {
type: [String],
default: [],
},
content: {
type: String,
},
})
const Snippet = mongoose.model('Snippet', snippetSchema)
module.exports = Snippet
Relevant route in "routes/snippets.js" - This could also be where I am falling over
router.put('/', function(req, res) {
console.log(req.body)
Snippet.findByIdAndUpdate(
req.body.id,
{
name: req.body.name,
details: req.body.details,
content: req.body.content,
},
{ new: true },
function(err, response) {
if (err) {
console.log('we hit an error' + err)
res.json({
message: 'Database Update Failure',
})
}
console.log('This is the Response: ' + response)
}
)
})
You are sending the id in the url, so you need to parse it from req.params.id.
I also returned response.
routes/snippets.js
router.put("/:id", function(req, res) {
console.log(req.body);
Snippet.findByIdAndUpdate(
req.params.id,
{
name: req.body.name,
details: req.body.details,
content: req.body.content
},
{ new: true },
function(err, response) {
if (err) {
console.log("we hit an error" + err);
return res.json({
message: "Database Update Failure"
});
}
return res.send(response);
}
);
});
Also you need to update this line in api.js. Just add / after snippets
.put('/snippets' + data.id, { =>
.put('/snippets/' + data.id, {

Resources