'Whenever I Put the payment page on my app, it goes blank on ReactJS

I'm doing an e-commerce app in which you rent tuxedos but when I go to the payments page it goes blank. It happened when I installed Stripe API on my app and it became buggy in the specific page. In this version of React, I tried to put on the payment page but it goes blank. Can you guys help me solve this problem please?

Here's my code on App.js:

import './App.css';
import Header from './Header.js';
import Home from './Home.js';
import Checkout from './Checkout.js';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Login from './Login';
import { useEffect } from 'react';
import { auth } from './firebase';
import { useStateValue } from './StateProvider';
import Payment from './Payment';
import { loadStripe } from '@stripe/stripe-js';
import { Elements } from '@stripe/react-stripe-js';

const promise = loadStripe('some stripe api here');

function App() {
  const [{}, dispatch] =useStateValue();
  useEffect(() => {
    //Only run once the app component logs
    auth.onAuthStateChanged(authUser => {
      console.log('User is signed in', authUser)
      if (authUser) {
        dispatch({
          type:'SET_USER',
          user: authUser
        })
      } else {
        dispatch({
          type:'SET_USER',
          user: null
        })
      }
    })
  }, [])
  return (
    //BEM
    <Router>
      <div className="app">
        <Routes>
          <Route path="/login" element={[<Login />]}/>
          <Route path="/checkout" element={[<Header />, <Checkout />]}/>
          <Route path="/payment" element={[<Header />, <Elements stripe={promise} />, <Payment />]}/>
          <Route path="/" element={[<Header />, <Home />]}/>
        </Routes>
      </div>
    </Router>
  );
}

export default App;

Now here's my code on the Payment page (Payment.js):

import { CardElement, useElements, useStripe } from '@stripe/react-stripe-js';
import React, { useEffect, useState } from 'react';
import CurrencyFormat from 'react-currency-format';
import { Link, useNavigate } from 'react-router-dom';
import CheckoutProduct from './CheckoutProduct';
import './Payment.css';
import { useStateValue } from './StateProvider';
import { getCartTotal } from './reducer';
import axios from 'axios';

function Payment() {
    const [{cart, user}, dispatch] = useStateValue();
    const navigate = useNavigate();

    const stripe = useStripe();
    const elements = useElements();

    const [succeeded, setSucceeded] = useState(false);
    const [processing, setProcessing] = useState(""); 
    const [error, setError] = useState(null);
    const [disabled, setDisabled] = useState(true);
    const [clientSecret, setClientSecret] = useState(true);

    useEffect(() => {
        const getClientSecret = async() => {
            const response = await axios({
                method: 'post',
                url: `/payments/create?total=${getCartTotal(cart) * 100}`
            });
            setClientSecret(response.data.clientSecret)
        }
        getClientSecret();
    }, [cart])

    const handleSubmit = async(event) => {
        event.preventDefault();
        setProcessing(true);
        const payload = await stripe.confirmCardPayment(clientSecret, {
            payment_method : {
                card: elements.getElement(CardElement)
            }
        }).then(({paymentIntent}) => {
            setSucceeded(true);
            setError(null)
            setProcessing(false)
            navigate('/orders', {replace:true});
        })
    }
    const handleChange = event => {
        setDisabled(event.empty);
        setError(event.error ? event.error.message : '');
        
    }
  return (
    <div className='payment'>
        <div className='payment_container'>
            <h1> Checkout (<Link to='/checkout'> {cart?.length} items </Link>) </h1>
            {/* Payment section - Delivery address */}
            <div className='payment_section'>
                <div className='payment_title'>
                    <h3> Delivery Address </h3>
                </div>
                <div className='payment_address'>
                    <p> {user?.email} </p>
                    <p> 123 Elvis Lane </p>
                    <p> Austin, Texas </p>
                </div>
            </div>
            {/* Payment section - Review items */}
            <div className='payment_section'>
                <div className='payment_title'>
                    <h3> Review items and delivery </h3>
                    <div className='payment_items'>
                        {cart.map(item => (
                            <CheckoutProduct 
                                id = {item.id}
                                title = {item.title}
                                image = {item.image}
                                price = {item.price}
                                rating = {item.rating}
                            />
                        ))}
                    </div>
                </div>
            </div>
            {/* Payment section - Payment method */}
            <div className='payment_section'>
                <div className='payment_title'>
                    <h3> Payment Method </h3>
                    <div className='payment_details'>
                        {/* Stripe API */}
                        <form onSubmit={handleSubmit}>
                            <CardElement onChange={handleChange} />
                            <div className='payment_priceContainer'>
                                <CurrencyFormat 
                                    renderText={(value) => (
                                        <>
                                            <h3> Order Total: {value} </h3>
                                        </>
                                    )}
                                    decimalScale={2}
                                    value= {getCartTotal(cart)}
                                    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>
    </div>
  )
}

export default Payment

Is this an error on App.js or is it in Payment.js? The page should display the info and the payment form.

Edit: I found out it was in the Payment.js code somewhere around here:

const navigate = useNavigate();

const stripe = useStripe();
const elements = useElements();

const [succeeded, setSucceeded] = useState(false);
const [processing, setProcessing] = useState(""); 
const [error, setError] = useState(null);
const [disabled, setDisabled] = useState(true);
const [clientSecret, setClientSecret] = useState(true);

useEffect(() => {
    const getClientSecret = async() => {
        const response = await axios({
            method: 'post',
            url: `/payments/create?total=${getCartTotal(cart) * 100}`
        });
        setClientSecret(response.data.clientSecret)
    }
    getClientSecret();
}, [cart])

const handleSubmit = async(event) => {
    event.preventDefault();
    setProcessing(true);
    const payload = await stripe.confirmCardPayment(clientSecret, {
        payment_method : {
            card: elements.getElement(CardElement)
        }
    }).then(({paymentIntent}) => {
        setSucceeded(true);
        setError(null)
        setProcessing(false)
        navigate('/orders', {replace:true});
    })
}
const handleChange = event => {
    setDisabled(event.empty);
    setError(event.error ? event.error.message : '');

Can you guys help me fix this please? It seems that in this section is where the error is occurring.

Edit 2: Here's of how it should look like: How it should look like

Here's what actually happens:

Here's what happens

Edit 3: Here's what the console gives me as an error, maymbe it is in the elements tag that causes the problem.

enter image description here



Solution 1:[1]

It looks like you need to wrap your checkout page in an Elements provider:

To use the Payment Element component, wrap your checkout page component in an Elements provider. Call loadStripe with your publishable key, and pass the returned Promise to the Elements provider. Also pass the client secret from the previous step as options to the Elements provider.

The sample code Stripe provides shows how to properly structure your app:

import React from 'react';
import ReactDOM from 'react-dom';
import {Elements} from '@stripe/react-stripe-js';
import {loadStripe} from '@stripe/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 stripePromise = loadStripe('pk_test_123');

function App() {
  const options = {
    // passing the client secret obtained in step 2
    clientSecret: '{{CLIENT_SECRET}}',
    // Fully customizable with appearance API.
    appearance: {/*...*/},
  };

  return (
    <Elements stripe={stripePromise} options={options}>
      <CheckoutForm />
    </Elements>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
import React from 'react';
import {PaymentElement} from '@stripe/react-stripe-js';

const CheckoutForm = () => {
  return (
    <form>
      <PaymentElement />
      <button>Submit</button>
    </form>
  );
};

export default CheckoutForm;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Justin Michael