Reputation: 23
index.js //backend
const functions = require("firebase-functions");
const express = require("express");
const cors = require("cors");
const stripe = require("stripe")
('sk_test_51IvTMySJHm59a7wpdl1wmkkj3uAIYN4XEBKuZO0ezF3vKR2dubLbzOEDLjCug
6wtULBK2mUsPWjJLol0NfMw67A000kWGNbvkb'); //Security code provide via stripe
//API
// - App config
const app = express();
// - Middlewares
app.use(cors({ origin: true }));
app.use(express.json());
// - API routes
app.get('/', (req, res) => {
res.status(200).send('hello world');
})
app.post("/payments/create", async (req, res) => {
const total = req.query.total;
console.log('Payment has been received !!! for this amount >>> ', total);
const paymentIntent = await stripe.paymentIntents.create({
amount: total, //This is in sub units
currency: "usd",
});
res.status(201).send({
clientSecret: paymentIntent.client_secret,
})
})
// - Listen Command
exports.api = functions.https.onRequest(app);
Payment.js //FrontEnd Raect Component
import { CardElement, useElements, useStripe } from '@stripe/react-stripe-js';
import axios from 'axios';
import React, { useEffect, useState } from 'react'
import CurrencyFormat from 'react-currency-format';
import { Link, useHistory } from 'react-router-dom';
import CheckoutProduct from './CheckoutProduct';
import './Payment.css';
import { getBasketTotal } from './reducer';
import { useStateValue } from './StateProvider';
function Payment() {
const [{ user, basket }, dispatch] = useStateValue();
const stripe = useStripe();
const elements = useElements();
const history = useHistory();
const [error, setError] = useState(null);
const [disabled, setDisabled] = useState(true)
const [succeeded, setSucceeded] = useState(false)
const [processing, setProcessing] = useState('')
const [clientSecret, setClientSecret] = useState(true)
useEffect(() => {
//generate the special stripe secret which allows us to charge a customer
const getClientSecret = async () => {
const responce = await axios({
method: 'post',
// Stripe expects the subunit of whatever currency you are using
url: `/payments/create?total=${getBasketTotal(basket) * 100}`
});
setClientSecret(responce.data.clientSecret);
}
getClientSecret();
}, [basket])
console.log('The Secret is >>>', clientSecret);
const handleSubmit = async e => {
e.preventDefault();
setProcessing(true);
const payload = await stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: elements.getElement(CardElement)
}
}).then(({ paymentIntent }) => {
//paymentIntent = payment confirmation
setSucceeded(true);
setError(null);
setProcessing(false);
history.replace('/orders');
})
}
const handleChange = e => {
setDisabled(e.empty);
setDisabled(e.error ? e.error.message : '')
}
return (
<div className='payment'>
<div className="paymentContainer">
<h1>
Checkout (<Link to='/checkout'>{basket.length} items</Link>)
</h1>
<div className="paymentSection">
<div className="paymentTitle">
<h3>Delivery Address</h3>
</div>
<div className="paymentAddress">
<p>{user?.email}</p>
<p>Om nagar</p>
<p>Jayraj Building, Vasai</p>
</div>
</div>
<div className="paymentSection">
<div className="paymentTitle">
<h3>Review items and delivery</h3>
</div>
<div className="paymentItems">
{basket.map(item => (
<CheckoutProduct
id={item.id}
title={item.title}
price={item.price}
rating={item.rating}
img={item.img} />
))}
</div>
</div>
<div className="paymentSection">
<div className="paymentTitle">
<h3>Payment Method</h3>
</div>
<div className="paymentDetails">
<form onSubmit={handleSubmit}>
<CardElement onChange={handleChange} />
<div className="paymentPriceContainer">
<CurrencyFormat
renderText={(value) => (
<>
<h3>Order Total : {value}</h3>
</>
)}
decimalScale={2}
value={getBasketTotal(basket)}
displayType={"text"}
thousandSeparator={true}
prefix={"$"}
/>
<button disabled={processing || disabled || succeeded}>
<span>{processing ? <p>Processing</p> : 'Buy Now'}</span>
</button>
</div>
{error && <div>{error}</div>}
</form>
</div>
</div>
</div>
</div>
)
}
export default Payment
axios.js
import axios from 'axios';
const instance = axios.create({
baseURL='http://localhost:5001/app-eea29/us-central1/api' //baseurl from firebase emulator suite
})
export default instance;
xhr.js:177 POST http://localhost:3000/payments/create?total=4534 404 (Not Found)
Uncaught (in promise) Error: Request failed with status code 404 at createError (createError.js:16) at settle (settle.js:17) at XMLHttpRequest.handleLoad (xhr.js:62)
Upvotes: 0
Views: 831
Reputation: 21
In handleChange function, you have done some mistake...
const handleChange = e => {
setDisabled(e.empty);
setDisabled(e.error ? e.error.message : '')
}
// Instead of this add this code...
const handleChange = e => {
setDisabled(e.empty);
setError(e.error ? e.error.message : "");
}
Upvotes: 1
Reputation: 856
It looks like you are missing the "data" property inside your axios.
I attached the code. Try and see if it works.
import instance from './path-to-axios'; <------- IMPORTANT
useEffect(() => {
//generate the special stripe secret which allows us to charge a customer
const getClientSecret = async () => {
const responce = await instance({
method: 'post',
// Stripe expects the subunit of whatever currency you are using
url: `/payments/create`,
data: getBasketTotal(basket) * 100
});
setClientSecret(responce.data.clientSecret);
}
getClientSecret();
}, [basket])
EDIT: (because of the first answer provided)
Remember to use your instance
you created instead of axios itself.
Upvotes: 0
Reputation: 11116
You export instance
as an instance of axios with a base URL, but then in your react component, you aren't using it - you use axios({ ...})
, which doesn't have the base URL in it. I have a feeling that's where your problem lies
Upvotes: 1