772 viewsNext Amazona
0 Comments

Hi,
I watched your YouTube video on Next, Tailwind, and MongoDB Amazona project and was able to successfully deploy it on Vercel.I was wondering about implementing the strip payment option. I noticed that whichever payment choice I choose it goes directly to PayPal only. Can you please tell me how I can approach this task.

Thank you for your videos. They are really helpful.

Bassir Answered question October 13, 2022

hello there,

in backend:

npm i stripe

then create stripeRouter.js like this:

/* eslint-disable camelcase */
import Stripe from 'stripe';
import express from 'express';
import config from '../config.js';
import Order from '../models/orderModel.js';

const stripe = Stripe(config.STRIPE_SECRET_KEY);

const stripeRouter = express.Router();
stripeRouter.get('/secret/:id', async (req, res) => {
  const order = await Order.findById(req.params.id).populate(
    'user',
    '_id name email'
  );
  const paymentIntent = await stripe.paymentIntents.create({
    amount: order.totalPrice * 100,
    currency: 'usd',
    // Verify your integration in this guide by including this parameter
    metadata: { integration_check: 'accept_a_payment' },
  });
  res.send({ order, client_secret: paymentIntent.client_secret });
});

stripeRouter.get('/key', (req, res) => {
  res.send(config.STRIPE_PUBLISHABLE_KEY);
});

export default stripeRouter;

and add to the routes in server.js

import stripeRouter from './routers/stripeRouters.js';
...

app.use('/api/stripe', stripeRouter);

and set env variable in .env:

STRIPE_SECRET_KEY=sk_xxx
STRIPE_PUBLISHABLE_KEY=pk_xxx

get them from stripe.com

in frontend install

 npm i @stripe/react-stripe-js @stripe/stripe-js

and create this component:

import React, { useState } from 'react';
import {
  useStripe,
  useElements,
  CardElement,
  Elements,
} from '@stripe/react-stripe-js';
import { Button } from 'react-bootstrap';
import Axios from 'axios';

function CheckoutForm(props) {
  const [processing, setProcessing] = useState(false);
  const stripe = useStripe();
  const elements = useElements();

  const handleSubmit = async (event) => {
    // We don't want to let default form submission happen here,
    // which would refresh the page.
    event.preventDefault();

    if (!stripe || !elements) {
      // Stripe.js has not yet loaded.
      // Make sure to disable form submission until Stripe.js has loaded.
      return;
    }
    setProcessing(true);
    const { data } = await Axios(`/api/stripe/secret/${props.orderId}`);
    const clientSecret = data.client_secret;
    // Call stripe.confirmCardPayment() with the client secret.

    const result = await stripe.confirmCardPayment(clientSecret, {
      payment_method: {
        card: elements.getElement(CardElement),
        billing_details: {
          name: data.order.user.name,
          email: data.order.user.email,
        },
      },
    });

    if (result.error) {
      // Show error to your customer (e.g., insufficient funds)
      console.log(result.error.message);
      alert(result.error.message);
    } else {
      // The payment has been processed!
      if (result.paymentIntent.status === 'succeeded') {
        props.handleSuccessPayment(result.paymentIntent);
        console.log(result.paymentIntent);
        // alert(result.paymentIntent.status);
      }
    }
    setProcessing(false);
  };

  return (
    <form onSubmit={handleSubmit}>
      <CardElement />

      <Button
        type="submit"
        className="btn-block"
        disabled={!stripe || processing}
      >
        Pay With Stripe
      </Button>
    </form>
  );
}

const StripeCheckout = (props) => (
  <Elements stripe={props.stripe}>
    <CheckoutForm
      orderId={props.orderId}
      handleSuccessPayment={props.handleSuccessPayment}
    />
  </Elements>
);
export default StripeCheckout;

then use it in OrderScreen.js

import { loadStripe } from '@stripe/stripe-js/pure';
import StripeCheckout from '../components/StripeCheckout';

in useEffect:

const [stripe, setStripe] = useState(null);
useEffect(() => {
    const addStripeScript = async () => {
      const { data: clientId } = await axios.get('/api/stripe/key');
      const stripeObj = await loadStripe(clientId);
      setStripe(stripeObj);
    };
    if (order.paymentMethod === 'stripe') {
        if (!stripe) {
          addStripeScript();
        }

in the return part:

{!order.isPaid && !stripe && <LoadingBox />}
                  {!order.isPaid && stripe && (
                    <StripeCheckout
                      stripe={stripe}
                      orderId={order._id}
                      handleSuccessPayment={handleSuccessPayment}
                    />
                  )}

In the meantime please follow this guide: https://vercel.com/guides/getting-started-with-nextjs-typescript-stripe

Bassir Edited answer October 25, 2022