Create a project folder as for example stripe-card-payment and then create a folder
named backend inside the project directory and install some NPM packages with the backend directory like...
npm install express stripe dotenv
Create environment variables:
Create a file named.env in the root directory of the project and then add the following codes...
NODE_ENV = production PORT = 5000 PUBLISHABLE_KEY = pk_test_51HrpB1A3RwZlQsxbFQeHBjXsTwtX3... STRIPE_SECRET_KEY = sk_test_51HrpB1A3RwZlQsxbaw6ocrnmKPF...
Now create a file named server.js and add the following code ...
const express = require('express'); const dotenv = require('dotenv'); const path = require('path'); dotenv.config(); const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use((_, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header( 'Access-Control-Allow-Headers', 'Accept, X-Requested-With, Origin, Content-Type', ); next(); }); // Send stripe publishable key to stripe client side api or react client for safety of the key app.get('/config', (req, res) => { res.json({ publishableKey: process.env.PUBLISHABLE_KEY, }); }); app.use('/create-payment-intent', async (req, res) => { const userPrice = parseInt(req.body.price) * 100; const intent = await stripe.paymentIntents.create({ amount: userPrice, currency: 'usd', }); res.json({ clientSecret: intent.client_secret, client_id: intent.id }); }); app.post('/confirm-payment', async (req, res) => { const paymentType = String(req.body.payment_type); if (paymentType == 'stripe') { const paymentid = String(req.body.payment_id); const confirmIntent = await stripe.paymentIntents .retrieve(paymentid) .then((response) => { res.json(response); }) .catch(); } }); // This code is for the deployment to the Heroku if (process.env.NODE_ENV === 'production') { // To use static assets in the production build app.use(express.static(path.join('./', '/frontend/build'))); // To use the index file like index.html for the production build app.get('*', (req, res) => res.sendFile(path.resolve(__dirname, 'frontend', 'build', 'index.html')), ); } else { app.get('/', (req, res) => { res.send('API is running...'); }); } const PORT = process.env.PORT || 5000; app.listen(PORT, () => { console.log( `Server is running in ${process.env.NODE_ENV} mode on port ${PORT}`, ); });
Here, the route "/config" has been used for the security of the publishable key of the stripe that has been passed from the backend to the frontend.
Create a frontend project:
npx create-react-app frontend
npm @stripe/stripe-js @stripe/react-stripe-js
react-bootstrap bootstrap react-router-dom axios;
// document.addEventListener('DOMContentLoaded', async () => {
(async () => {
const { publishableKey } = await fetch('/config').then((response) =>
response.json(),
);
const stripePromise = loadStripe(publishableKey);
ReactDOM.render(
// <React.StrictMode>
<Elements stripe={stripePromise}>
<App />
</Elements>,
// </React.StrictMode>,
document.getElementById('root'),
);
})();
// });
Step - 1:
When a customer fillup a web form and click on submit button.
Step - 2:
Stripe client-side API takes the payment information from the web form and creates a payment method. Stripe client-side API asks Stripe server-side API for a payment intent object through Axios or fetch API.
Step - 3:
Stripe server-side API creates a payment intent with a secret value. After that, pass the secrete value with payment intent to the Stripe client-side API.
Step - 4:
Stripe client-side API then receives the secret value from Stripe server-side API and processes the transaction through the stripe payment processor service.
Step - 5:
Stripe client-side API waits for confirmation from the Stripe payment processor service.
Step - 6:
When got the confirmation from the Stripe payment processor service, the Stripe client-side API sends another request to the Stripe server-side API through Axios or fetch API.
Step - 7:
Now, we can handle the payment confirmation through Stripe server-side API according to our requirements.
Code example as same as follows ...
// import axios from 'axios'; import { CardElement, useElements, useStripe } from '@stripe/react-stripe-js'; import React, { useState } from 'react'; import { Button, Card, Col, Container, Form, Modal, Row, } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import StatusMessages, { useMessages } from './StatusMessages'; import { useHistory } from 'react-router'; const CardComponent = () => { // useStripe and useElements hooks are used to interact with CardElement const stripe = useStripe(); const elements = useElements(); // to show error, success, processing, and card complete message const [error, setError] = useState(null); const [success, setSuccess] = useState(false); const [processing, setProcessing] = useState(false); const [cardComplete, setCardComplete] = useState(false); const [messages, addMessage] = useMessages(); const history = useHistory(); // to reset the state const reset = () => { setError(null); setSuccess(false); setProcessing(false); }; const handleSubmit = async (event) => { event.preventDefault(); if (!stripe || !elements) { return; } if (cardComplete) { setProcessing(true); setSuccess(true); } else { return; } addMessage('Creating Payment Intent...'); // Create a payment method const payload = await stripe.createPaymentMethod({ type: 'card', card: elements.getElement(CardElement), billing_details: { name: 'mozahedul1', email: 'mozahedul1@gmail.com', }, }); if (payload.error) { return; } // request stripe server side API for paymentIntent object const { clientSecret, client_id } = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ price: 1000, }), }).then((response) => response.json()); addMessage(`Payment Intent Created: ${clientSecret}, ${client_id}`); // After getting client secret and paymentIntent object from stripe server side API, // send to payment processor service for payment confirmation const { paymentIntent } = await stripe.confirmCardPayment(clientSecret, { payment_method: payload.paymentMethod.id, }); addMessage(`PaymentIntent (${paymentIntent.id}): ${paymentIntent.status}`); // stripe client side API will wait for confirmation from stripe payment processor service // when gets confirmation, then it will send another request to stripe server side // API to complete the transaction if (paymentIntent.status === 'succeeded') { const confirmedPayment = await fetch('/confirm-payment', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ payment_id: client_id, payment_type: 'stripe', }), }) .then((res) => res.json()) .catch(); if (confirmedPayment.status === 'succeeded') { reset(); setProcessing(true); setSuccess(true); } } }; return ( <Container className="mt-5"> <Row className="justify-content-center"> <Col md={6}> <Card className="py-3 px-4"> <Link to="/"> <Button className="btn-light btn-sm">Home page</Button> </Link> <h2 className="mb-3">Stripe Payment Form</h2> <Form onSubmit={handleSubmit}> <Modal show={success}> <Modal.Header> <Modal.Title>Payment Succeeded</Modal.Title> </Modal.Header> <Modal.Body>Your transaction has been completed.</Modal.Body> <Modal.Footer> <Button onClick={() => history.push('/')}>Close</Button> </Modal.Footer> </Modal> <Modal show={error != null}> <Modal.Header> <Modal.Title>Error! Enter Correct Card Number</Modal.Title> </Modal.Header> <Modal.Body>{error}</Modal.Body> <Modal.Footer> <Button onClick={() => setError(null)}>Close</Button> </Modal.Footer> </Modal> <Form.Group> <Form.Label htmlFor="card-element">Card</Form.Label> <CardElement id="card-element" onChange={(event) => { setError(event.error && event.error.message); setCardComplete(event.complete); }} /> </Form.Group> <Form.Group className="mt-4"> <Button type="submit" disabled={processing || !stripe}> {processing ? 'Processing...' : 'Pay Now'} </Button> </Form.Group> </Form> <StatusMessages messages={messages} /> </Card> </Col> </Row> </Container> ); }; export default CardComponent;
Post a Comment