I am currently using ReactJS, node, and express with the Stripe Payment API. After clicking the pay button and entering the dummy credit card credentials, the page doesnt process the payment. I have entered the correct publishing key and api key that I got from my dashboard.I believe it likely has somnething to do with what I need to add in the server.js file(aka node backend).I have read through the docs for any clues I can get. Also have searched here on Stack Overflow. None of the questions had the same thing I was looking for. Please see below for pictures and code. Thanks
This is before pressing the button. Please Note the console on the right side.
This is after pressing the button. The loading spinner just displays forever. Also note the console on right side
// Donate.js
import React from "react";
import "./Donate.css";
import { loadStripe } from "@stripe/stripe-js";
import { Elements } from "@stripe/react-stripe-js";
import CheckoutForm from "./CheckoutForm";
// Make sure to call `loadStripe` outside of a component’s render to avoid
// recreating the `Stripe` object on every render.
const stripe = loadStripe(
"pk*****************************"
);
stripe.then((data) => {
console.log(data);
});
const Donate = () => {
return (
<div className="donate">
<h1 className="donate__sectionHeader">Donate Now</h1>
<Elements stripe={stripe}>
<CheckoutForm />
</Elements>
</div>
);
};
export default Donate;
//CheckoutForm
import React, { useState, useEffect } from "react";
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";
import "./CheckoutForm.css";
export default function CheckoutForm() {
const [succeeded, setSucceeded] = useState(false);
const [error, setError] = useState(null);
const [processing, setProcessing] = useState("");
const [disabled, setDisabled] = useState(true);
const [clientSecret, setClientSecret] = useState("");
const stripe = useStripe();
const elements = useElements();
useEffect(() => {
// Create PaymentIntent as soon as the page loads
window
.fetch("/donate", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ items: [{ id: "xl-tshirt" }] }),
})
.then((res) => {
return res.json();
})
.then((data) => {
setClientSecret(data.clientSecret);
});
}, []);
const cardStyle = {
style: {
base: {
color: "#32325d",
fontFamily: "Arial, sans-serif",
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#32325d",
},
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a",
},
},
};
const handleChange = async (event) => {
// Listen for changes in the CardElement
// and display any errors as the customer types their card details
setDisabled(event.empty);
setError(event.error ? event.error.message : "");
};
const handleSubmit = async (ev) => {
ev.preventDefault();
setProcessing(true);
const payload = await stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: elements.getElement(CardElement),
},
});
if (payload.error) {
setError(`Payment failed ${payload.error.message}`);
setProcessing(false);
} else {
setError(null);
setProcessing(false);
setSucceeded(true);
}
console.log(clientSecret);
};
return (
<form id="payment-form" onSubmit={handleSubmit}>
<CardElement
id="card-element"
options={{ hidePostalCode: true, cardStyle }}
onChange={handleChange}
/>
<button disabled={processing || disabled || succeeded} id="submit">
<span id="button-text">
{processing ? <div className="spinner" id="spinner"></div> : "Pay"}
</span>
</button>
{/* Show any error that happens when processing the payment */}
{error && (
<div className="card-error" role="alert">
{error}
</div>
)}
{/* Show a success message upon completion */}
<p className={succeeded ? "result-message" : "result-message hidden"}>
Payment succeeded, see the result in your
<a href={`https://dashboard.stripe.com/test/payments`}>
{" "}
Stripe dashboard.
</a>{" "}
Refresh the page to pay again.
</p>
</form>
);
}
//server.js
const express = require("express");
const app = express();
const { resolve } = require("path");
// This is your real test secret API key.
const stripe = require("stripe")(
"sk_test_**********************************"
);
app.use(express.static("."));
app.use(express.json());
const calculateOrderAmount = (items) => {
// Replace this constant with a calculation of the order's amount
// Calculate the order total on the server to prevent
// people from directly manipulating the amount on the client
return 1400;
};
app.post("/create-payment-intent", async (req, res) => {
const { items } = req.body;
// Create a PaymentIntent with the order amount and currency
const paymentIntent = await stripe.paymentIntents.create({
amount: 1099,
currency: "usd",
// Verify your integration in this guide by including this parameter
metadata: { integration_check: "accept_a_payment" },
});
res.send({
clientSecret: paymentIntent.client_secret,
});
});
app.listen(4242, () => console.log("Node server listening on port 4242!"));
You need to review the server call/network response with the client_secret
. The console error indicates you've provided an invalid secret to confirmCardPayment
, apparently an empty string.
You specified: .
It would appear that your app is not setting the state via setClientSecret
as intended, and you end up with the initial empty string value from useState("");
.
Check your client_secret
value before the confirmCardPayment
call, and step backwards to find where the value is being dropped.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.