1
import React, { useEffect, useState } from 'react'
import db from '../firebase'
import './PlansScreen.css'
import { useSelector } from 'react-redux'
import { selectUser } from '../features/userSlice'
import { loadStripe } from "@stripe/stripe-js"

function PlansScreen() {

    const [products, setProducts] = useState([])
    const user = useSelector(selectUser)

    useEffect(() => {
        db.collection("products")
            .where("active", "==", true)
            .get()
            .then(querySnapshot => {
                const products = {}
                querySnapshot.forEach(async productDoc => {
                    products[productDoc.id] = productDoc.data();
                    const priceSnap = await productDoc.ref.collection('prices').get();
                    priceSnap.docs.forEach(price => {
                        products[productDoc.id].prices = {
                            prceId: price.id,
                            priceData: price.data()
                        }
                    })
                })
                setProducts(products);
            })
    }, [])

    console.log(products);

    const loadCheckout = async (priceId) => {

        const docRef = await db
            .collection('customers')
            .doc(user.uid)
            .collection("checkout_sessions")
            .add({
                price: priceId,
                success_url: window.location.origin,
                cancel_url: window.location.origin,
            });
        docRef.onSnapshot(async (snap) => {
            const { error, sessionId } = snap.data();

            if (error) {
                alert(`An error occured:${error.message}`);
            }

            if (sessionId) {
                // init stripe
                const stripe = await loadStripe('pk_test_51NSki0SGjMohrz4zbSg4JN71tlTFUkGLWemybtRS31PP94Tzd08kFLUgzTgmxUGjoPQ36S4orri0J2tT8EY5GQZk00NThIU3fu');
                stripe.redirectToCheckout({ sessionId });
            }
        });
    };

    return (
        <div className='plansScreen'>
            {Object.entries(products).map(([productId, productData]) => {
                ///TODO: Add some logic to check if user subscription is active
                return (
                    <div key={productId} className="plansScreen__plan">
                        <div className="planScreen__info">
                            <h3>{productData.name}</h3>
                            <h5>{productData.description}</h5>
                        </div>
                        <button onClick={() => loadCheckout(productData.prices.priceId)}>
                            Subscribe
                        </button>
                    </div>
                );
            })}

        </div>
    )
}

export default PlansScreen;

It is mapping correctly while displaying plan and even in the console is is logging the prices correctly. But on clicking the subscribe button is is showing this error rather than going into stripe checkout session.

If the mapping is going on perfectly then there is no problem with the firebase part right

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Your call to `setProducts` happens **before** all of the products data is populated. `async` inside a `forEach` loop doesn't work the way you expect. You can add some logging to observe this yourself. See: https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop – Doug Stevenson Jul 12 '23 at 14:27

1 Answers1

0

While I'm not a firebase expert, you appear to have a typo in setting your productData

prceId: price.id,

That says prceId not priceId like you reference later in loadCheckout(productData.prices.priceId) but I'm not clear on whether this is the same reference. Generally speaking you'll need to spend some time debugging this carefully to understand what's going on different than you expect.

Nolan H
  • 6,205
  • 1
  • 5
  • 19