React Stripe Payment Create Customer and Order / Shipping Address etc - javascript

I created stripe payment page using gatsby react and aws lambda. But this code not create customer data like ( shipping address, email etc. )
Lamdba Code
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
module.exports.handler = (event, context, callback) => {
console.log("creating charge...");
// Pull out the amount and id for the charge from the POST
console.log(event);
const requestData = JSON.parse(event.body);
console.log(requestData);
const amount = requestData.amount;
const token = requestData.token.id;
// Headers to prevent CORS issues
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
};
return stripe.charges
.create({
// Create Stripe charge with token
amount,
source: token,
currency: "usd",
description: "Tshirt"
})
.then(charge => {
// Success response
console.log(charge);
const response = {
headers,
statusCode: 200,
body: JSON.stringify({
message: `Charge processed!`,
charge
})
};
callback(null, response);
})
.catch(err => {
// Error response
console.log(err);
const response = {
headers,
statusCode: 500,
body: JSON.stringify({
error: err.message
})
};
callback(null, response);
});
};
Gatsby Payment Code
Code is working , payment is working. but shipping details not working.
openStripeCheckout(event) {
event.preventDefault();
this.setState({ disabled: true, buttonText: "WAITING..." });
this.stripeHandler.open({
name: "Demo Product",
amount: amount,
shippingAddress: true,
billingAddress: true,
description: "",
token: (token, args) => {
fetch(`AWS_LAMBDA_URL`, {
method: "POST",
body: JSON.stringify({
token,
args,
amount,
}),
headers: new Headers({
"Content-Type": "application/json",
}),
})
.then(res => {
console.log("Transaction processed successfully");
this.resetButton();
this.setState({ paymentMessage: "Payment Successful!" });
return res.json();
})
.catch(error => {
console.error("Error:", error);
this.setState({ paymentMessage: "Payment Failed" });
});
},
});
}
I want to see customer data , shipping address etc.
Thanks for helping.

The billing and shipping address are both available in the args-argument of the token callback you're collecting.
https://jsfiddle.net/qh7g9f8w/
var handler = StripeCheckout.configure({
key: 'pk_test_xxx',
locale: 'auto',
token: function(token, args) {
// Print the token response
$('#tokenResponse').html(JSON.stringify(token, null, '\t'));
// There will only be args returned if you include shipping address in your config
$('#argsResponse').html(JSON.stringify(args, null, '\t'));
}
});

Related

Send jwt to API in request header from Reactjs frontend

I have a quick question. I am using Axios to send requests to the nodejs API, when I set the token in the request header the API returns "jwt must be provided". The API expects the token with a custom name attached to it - here's how far I've gotten.
Snippet of API code that sends the token on login:
const token = jwt.sign(
{
userID: result[0].userID,
firstName: result[0].firstName,
lastName: result[0].lastName,
email: result[0].email,
role: result[0].role,
// exp: Math.floor(Date.now() / 1000) + 60 * 60,
},
"HeyImaPrivateKeyyy"
);
res.json({ token });
console.log("Login Attempt", res.statusMessage, req.body);
} else {
res.status(400).send({ message: "Invalid credentials!" });
console.log("Login Attempt", res.statusMessage, req.body);
}
-- React code from here --
Response from API on successful login:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOjEsImZpcnN0TmFtZSI6IkNhbWVyb24iLCJsYXN0TmFtZSI6IkVyYXNtdXMiLCJlbWFpbCI6ImNhbWVyb25AY2xpZnRjb2xsZWdlLmNvbSIsInJvbGUiOiJzdXBlckFkbWluIiwiaWF0IjoxNjYzMzEzNTM2fQ.9R6vXn-5Vb5fj48eUJGPNUGnXMw9TXOjJCox7U36WMI"
}
Saving the token on successful login (React)
const login = async ({ email, password }) => {
const res = await api.post(
"/auth",
{
email: email, //varEmail is a variable which holds the email
password: password,
},
{
headers: {
"Content-type": "application/json",
Authorization: false,
},
}
);
const { from } = state || {};
let token = jwt(res.data.token);
setToken("x-auth-token", token); // your token
localStorage.setItem("x-auth-token", res.data.token);
localStorage.setItem("userLogged", true);
localStorage.setItem("name", token.firstName);
localStorage.setItem("role", token.role);
navigate("/auth/dashboard" || from.pathname, { replace: true });
};
Here is the React component that is trying to call the API:
const [count, setCount] = useState(null);
const token = localStorage.getItem("x-auth-token");
const studentCount = useEffect(() => {
const config = {
headers: { "x-auth-token": token },
"Content-type": "application/json",
};
api.get("/students/", {}, config).then((response) => {
setCount(response.data);
});
}, [token]);
if (!count) return null;
This is what the API is expecting on request:
export const teacher = (req, res, next) => {
const token = req.header("x-auth-token");
if (!auth && !token)
return res.status(401).send({ message: "Access denied." });
const decoded = jwt.verify(token, "DemoPrivateKey");
if (auth && ["superAdmin", "admin", "teacher"].includes(decoded.role)) {
next();
} else {
res.status(400).send({ message: "Access denied!" });
}
};
Ideally, I would like to send the token as a header on successful login, but it saves as undefined on the client (have no idea how to fix that).
If you're using Axios then, as per the doc, get method should have config parameter in second position not third one.
So maybe, simply updating api.get("/students/", {}, config) into api.get("/students/", config) should solve your issue.

How to get a response from nodemailer using netlify functions?

I am using netlify functions to send an email from the frontend and it works fine... as in it does send the email.
However on the clientside (browser) I can't get any response. I need a basic response that would allow me to do a if (status==="success") displayMessage() but I can't seem to get any response on the browser.
I get this message Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data However on sending the request via POSTMAN I get a response 'Email Sent Succesfully' which is the body part of the callback response.
Here's the function that I am using at .netlify/functions/sendMail
const nodemailer = require("nodemailer");
exports.handler = function (event, context, callback) {
const mailConfig = {
host: "smtp.mailgun.org",
port: 465,
secure: true,
auth: {
user: process.env.MAILGUN_USER,
pass: process.env.MAILGUN_PASSWORD,
},
};
const transporter = nodemailer.createTransport(mailConfig);
transporter.verify((error, success) => {
if (error) {
console.log(error);
} else {
console.log("Ready to send emails");
}
});
const messageData = JSON.parse(event.body);
const { email, name, mobile, message, subject, recipient } = messageData;
console.log(messageData);
const mailOptions = {
from: email,
to: recipient,
subject: subject,
text: message,
};
transporter.sendMail(mailOptions, (error, success) => {
if (error) {
console.log(error);
callback(error);
} else {
console.log("email sent");
callback(null, {
statusCode: 200,
body: "Email sent successfully",
});
}
});
};
and on the client side I have this
const form = document.querySelector("#message");
const submitMessage = (event) => {
event.preventDefault();
const formData = new FormData(form);
formData.append("recipient", "testing#gmail.com");
formData.append("subject", "Submission from website");
const messageData = Object.fromEntries(formData);
console.log(messageData);
const url = ".netlify/functions/sendMail";
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(messageData),
};
fetch(url, options)
.then((response) => response.json())
.then((data) => console.log(data));
};
form.addEventListener("submit", submitMessage);
in the fetch request, I expected data to give me a response so I could trigger some action to display a success message..
Can someone advise me what I am doing wrong here?
I realised what I was doing wrong and here's the solution in case someone else faces the same issues.
In the callback from the netlify function I was sending the body as text
callback(null, {
statusCode: 200,
body: "Email sent successfully",
});
but in the clientside fetch request I was treating it as json
fetch(url, options)
.then((response) => response.json())
.then((data) => console.log(data));
So basically I could either use a response.text() instead of response.json() for the fetch request or use JSON.stringify and return a JSON object from the callback. I preferred the JSON.stringify option as below for the callback
callback(null, {
statusCode: 200,
body: JSON.stringify({
status: "success",
message: "Email sent successfully",
}),
});

Cookie error while trying to authenticate for data scraping

I'm trying to scrape some data from truepush website, but first it needs to be authenticated. So here is what I'm doing:
const loginUrl = 'https://app.truepush.com/api/v1/login'
let loginResult = await axios.get(loginUrl)
.then(({ headers }, err) => {
if (err) console.error(err);
return headers['set-cookie'][0];
})
.then((cookie, err) => {
if (err) console.error(err);
const splitByXsrfCookieName = cookie.split("XSRF-TOKEN=")[1]
return splitByXsrfCookieName.split(';')[0];
}).then(xsrfToken => {
return axios.post(loginUrl, {
headers: {
"Content-Type": "application/json",
"X-XSRF-TOKEN": xsrfToken
}
})
}).then(res => console.log(res))
It throws xrsfToken on second then response and when I try to login in third response with that xsrf token, it shows me this error:
{
"status_code": "XSRF-ERROR",
"status": "ERROR",
"message": "Cross domain requests are not accepting to this endpoint. If you cleared the cookies, please refresh your browser."
}
I'm not sure what wrong I'm doing :(
The main issue is that the call also requires the original cookie to be sent. You need to keep the original cookie your get from set-cookie header and pass it in cookie header in the second call like cookie: originalCookie. Also in your code, there is no body sent in the POST call.
The following code reproduces the login :
const axios = require("axios");
const originalUrl = 'https://app.truepush.com';
const loginUrl = 'https://app.truepush.com/api/v1/login';
const email = "your-email#xxxxxx";
const password = "your-password";
(async () => {
await axios.get(originalUrl)
.then(({ headers }, err) => {
if (err) console.error(err);
const cookie = headers['set-cookie'][0];
return {
cookie: cookie,
xsrfToken: cookie.split("XSRF-TOKEN=")[1].split(";")[0]
};
})
.then((data, err) => {
if (err) console.error(err);
return axios.post(loginUrl, {
"email": email,
"password": password,
"keepMeLoggedIn": "yes"
}, {
headers: {
"X-XSRF-TOKEN": data.xsrfToken,
"cookie": data.cookie
}
})
})
.then(res => console.log(res.data))
})();
Output:
{
status_code: 'SUCCESS',
status: 'SUCCESS',
message: 'Login Successful',
data: {
id: 'xxxxxxxxxxxxxxxxxxx',
name: 'xxxxx',
email: 'xxxxxxx#xxxxxx'
}
}
Note that both cookie and xsrfToken are consumed by the second promise

Stripe subscription checkout with Firebase Functions - IntegrationError: stripe.redirectToCheckout

I'm trying to test the process of creating a checkout session for a stripe subscription. However I get this error on the client: IntegrationError: stripe.redirectToCheckout: You must provide one of lineItems, items, or sessionId.
Here is my code on the front end:
var priceId = "price_1IGpOIFE3UXETakjtSs1Wq6x";
var createCheckoutSession = function(priceId) {
return fetch("https://us-central1-streamline-14fc8.cloudfunctions.net/createCheckoutSession", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
priceId: priceId
})
}).then(function(result) {
return result.json();
});
};
document
.getElementById("checkout")
.addEventListener("click", function(evt) {
createCheckoutSession(priceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
console.log(data);
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
Then my code in Firebase Functions:
//stripe checkout
exports.createCheckoutSession = functions.https.onCall(async (req, res) => {
const {
priceId
} = req.body;
// See https://stripe.com/docs/api/checkout/sessions/create
// for additional parameters to pass.
try {
const session = await stripe.checkout.sessions.create({
mode: "subscription",
payment_method_types: ["card"],
line_items: [{
price: priceId,
// For metered billing, do not pass quantity
quantity: 1,
}, ],
// {CHECKOUT_SESSION_ID} is a string literal; do not change it!
// the actual Session ID is returned in the query parameter when your customer
// is redirected to the success page.
success_url: 'https://example.com/success.html?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/canceled.html',
});
res.send({
sessionId: session.id,
});
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
})

Why is my fetch function giving me a 400 bad request?

I am trying to integrate the stripe checkout sessions in my React app. In order to create the session I have a node/express server running in the background that has a "/billing" post.
When I try to hit it using fetch I get a 400 bad request from my chrome console.
Here's the function in my frontend:
const submitReq = () =>{
const price = {price: "price_1HmAziJIQLh7k5Y65s1Hyupc"};
fetch("http://localhost:8282/billing", {
method: "POST",
redirect: "follow",
headers:{
"Content-Type": "application/json"
},
body: JSON.stringify(price),
}).then(response => {
if(response.ok){
console.log(response);
response.json()}
else{ throw Error(`Request rejected with status ${response.status}`);}
})
.then(price =>{
console.log('success:', price);
})
.catch((error)=>{
console.error("error:", error);
});
}
Then in the node/express I have the "/billing" post which looks like this
app.options("/billing", cors(corsConfig));
app.post("/billing", async (req, res) => {
const {priceId} = req.body;
console.log(priceId);
try {
const session = await stripe.checkout.sessions.create({
mode: "subscription",
payment_method_types: ["card"],
line_items: [
{
price: priceId,
quantity: 1,
},
],
success_url: 'https://example.com/success.html',
cancel_url: 'https://example.com/canceled.html',
});
res.send({
sessionId: session.id,
});
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
});

Categories