am using reactjs redux to manage my states and stripe to integrate payments and i am getting this error while trying handle payment confirmation in stripe stripe.confirmPayment elements should have mounted a payment element or an express checkout element.

import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import {
    PaymentElement,
    useStripe,
    useElements,
} from "@stripe/react-stripe-js";

import styles from "./CheckoutForm.module.scss";
import Card from "../card/Card";
import CheckoutSummary from "../checkoutSummary/CheckoutSummary";
import spinnerImg from "../../assets/spinner (1).jpg";
import { toast } from "react-toastify";
import { useDispatch, useSelector } from "react-redux";
import { selectEmail, selectUserID } from "../../redux/slices/authSlice";

import {
    CLEAR_CART,
    selectCartItems,
    selectCartTotalAmount,
} from "../../redux/slices/cartSlice";

import { selectShippingAddress } from "../../redux/slices/checkoutSlice";
import { addDoc, collection, Timestamp } from "firebase/firestore";
import { db } from "../../firebase/config";


const CheckoutForm = () => {
    const [message, setMessage] = useState(null);
    const [isLoading, setIsLoading] = useState(false);
    const stripe = useStripe();
    const elements = useElements();
    
    const dispatch = useDispatch();
    const navigate = useNavigate();

    const userID = useSelector(selectUserID);
    const userEmail = useSelector(selectEmail);
    const cartItems = useSelector(selectCartItems);
    const cartTotalAmount = useSelector(selectCartTotalAmount);
    const shippingAddress = useSelector(selectShippingAddress);

    useEffect(() => {
        if (!stripe) {
            return;
        }

        const clientSecret = new URLSearchParams(window.location.search).get(
            "payment_intent_client_secret"
        );

        if (!clientSecret) {
            return;
        }
    }, [stripe]);

    const saveOrder = () => {
        const today = new Date();
        const date = today.toDateString();
        const time = today.toLocaleTimeString();

        const orderConfig = {
            userID,
            userEmail,
            orderDate: date,
            orderTime: time,
            orderAmount: cartTotalAmount,
            orderStatus: "Order Status",
            cartItems,
            shippingAddress,
            createdAt: Timestamp.now().toDate(),
        };

        try {
            addDoc(collection(db, "orders"), orderConfig);
            dispatch(CLEAR_CART());
            toast.success("your order has been saved")
            navigate("/checkout-success");
        } catch (error) {
            toast.error(error.message);
        }
    };

    const handleSubmit = async (e) => {
        e.preventDefault();
        setMessage(null);

        if (!stripe || !elements) {
            return;
        }
        

        setIsLoading(true);

        const confirmPayment = await stripe.confirmPayment({
            elements,
            confirmParams: {
                return_url: "http::/localhost:3000/checkout-success",
            },
            redirect: "if_required",
        })
            .then((result) => {
                
                if (result.error) {
                    toast.error(result.error.message);
                    //maybe the customer has entered wrong account details 
                    setMessage(result.error.message);
                    return;
                }

                if (result.paymentIntent) {
                    if (result.paymentIntent.status === "succeeded") {
                        setIsLoading(false);
                        //customer will be directed to the return url you provided or redirected if it needs inter mediate
                        toast.success("payment successful");
                        saveOrder();
                    }
                }
            });
        setIsLoading(false);

      
    };
    

    
    return (
        <section>
            <div className={`container ${styles.checkout}`}>
                <h2>Checkout</h2>
                <form onSubmit={handleSubmit}>
                    <div>
                        <Card cardClass={styles.card}>
                            <CheckoutSummary />
                        </Card>
                    </div>
                    <div>
                        <Card cardClass={`${styles.card} ${styles.pay}`}>
                            <h3>Stripe Checkout</h3>
                            {isLoading ? (<img src={spinnerImg} style={{ witdh: "20px" }} /> ) : (
                                <div>
                            <PaymentElement id={styles["payment-element"]} />
                            <button
                                disabled={isLoading || !stripe || !elements}
                                id="submit"
                                className={styles.button}
                            >
                                <span id="button-text">
                                    {isLoading ? (
                                        <img src={spinnerImg} alt="loading.." style={{ witdh: "20px" }} />
                                    ) : (
                                        "Pay Now"
                                    )}
                                </span>
                                    </button>
                                    </div>
                                )}
                            {/* s*/}
                            {message && <div id={styles["payment-message"]}>{message}</div>}
                        </Card>
                    </div>
                </form>
            </div>
        </section>
    );
}

export default CheckoutForm;

in my logs in the stripe dashboard i am getting status 200 ok and incomplete under payments my response from the backend has both client_secret and paymentintent id help out i have tried to go through this issue here text which is related to the error that am getting but i am still stack. This is how am initializing stripe

import { useEffect, useState } from "react";
import { loadStripe } from "@stripe/stripe-js";
import { Elements } from "@stripe/react-stripe-js";
import { useDispatch, useSelector } from "react-redux";
import {
    CALCULATE_SUB_TOTAL,
    CALCULATE_TOTAL_QUANTITY,
    selectCartItems,
    selectCartTotalAmount,
} from "../../redux/slices/cartSlice";
import { selectEmail } from "../../redux/slices/authSlice";
import {
    selectBillingAddress,
    selectShippingAddress,
} from "../../redux/slices/checkoutSlice";
import { toast } from "react-toastify";
import CheckoutForm from "../../components/checkoutForm/CheckoutForm";

const stripePromise = loadStripe(`${process.env.STRIPE_PUBLISHABLE_KEY}`);


const Checkout = () => {
    const [message, setMessage] = useState("Initializing checkout....");
    const [clientSecret, setClientSecret] = useState("");

    const cartItems = useSelector(selectCartItems);
    const totalAmount = useSelector(selectCartTotalAmount);
    const customerEmail = useSelector(selectEmail);
    
    const shippingAddress = useSelector(selectShippingAddress);
    const billingAddress = useSelector(selectBillingAddress);

    const dispatch = useDispatch();
    
    useEffect(() => {
        dispatch(CALCULATE_SUB_TOTAL());
        dispatch(CALCULATE_TOTAL_QUANTITY());
    }, [dispatch, cartItems]);

    const description = `commerce platform Payment: email: ${customerEmail}`;

    useEffect(() => {
        //create a payment intent as soon as the page loads 
        fetch("http://localhost:4242/create-payment-intent", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
                items: cartItems,
                userEmail: customerEmail,
                shipping: shippingAddress,
                billing: billingAddress,
                description,
            }),
        })
            .then((res) => {
                if (res.ok) {
                    return res.json();
                }
                return res.json().then((json) => Promise.reject(json));
            })
            .then((data) => {
                setClientSecret(data.clientSecret);
            })
            .catch((error) => {
                setMessage("Failled to  initialize checkout");
                toast.error(error.message);
                
            });
            
    }, []);

    const appearance = {
        theme: "stripe",
    };

    const options = {
        clientSecret,
        appearance,
    };


    return ( 
        <div>
            <section>
                <div className="container">{!clientSecret && <h3>{ message}</h3>}</div>
            </section>
            {clientSecret && (
                <Elements options={options} stripe={stripePromise}>
                <CheckoutForm/>
                </Elements>
            )}
        </div>
    )
}

export default Checkout
0

There are 0 best solutions below