0
votes

I have installed the "Run Subscription Payments with Stripe" extension in Firebase.

When I try the to subscribe a user to a plan I get an error saying "snap.data is not a function". I use the following code:

 db
      .collection('customers')
      .doc(cred.user.uid)
      .collection('checkout_sessions')
      .add({
        price: 'price_1GqIC8HYgolSBA35zoTTN2Zl',
        success_url: window.location.origin,
        cancel_url: window.location.origin,
      }).then(() => {
    // Wait for the CheckoutSession to get attached by the extension
      db
      .collection('customers')
      .doc(cred.user.uid)
      .collection('checkout_sessions').onSnapshot((snap) => {

          console.log(snap)

          const { sessionId } = snap.data();
          if ({sessionId}) {

            console.log(sessionId)
            // We have a session, let's redirect to Checkout
            // Init Stripe
            const stripe = Stripe('pk_test_ZEgiqIsOgob2wWIceTh0kCV4001CPznHi4');
            stripe.redirectToCheckout({ sessionId });
          };
    });
  });

This is a .then variation on the code example provided by the Firebase team:

const docRef = await db
  .collection('customers')
  .doc(currentUser.uid)
  .collection('checkout_sessions')
  .add({
    price: 'price_1GqIC8HYgolSBA35zoTTN2Zl',
    success_url: window.location.origin,
    cancel_url: window.location.origin,
  });
// Wait for the CheckoutSession to get attached by the extension
docRef.onSnapshot((snap) => {
  const { sessionId } = snap.data();
  if (sessionId) {
    // We have a session, let's redirect to Checkout
    // Init Stripe
    const stripe = Stripe('pk_test_1234');
    stripe.redirectToCheckout({ sessionId });
  }
});

I got an error with the await function, saying "Uncaught SyntaxError: await is only valid in async function". So I refactered the code to a .then variant.

When I run this code from a button.addEventListener("click) I get an error saying snap.data is not a function.

I checked snap and it is populated

snapshot of console.log()

The customer gets created in Firestore and in Stripe dashboard, the customer session gets created.

What goes wrong here? There is a similair question on Stackoveflow (Run Subscription Payments with Stripe Firebase Extension Webhook Not Firing), but there is no answer, so I'm trying again.

2

2 Answers

2
votes

Your query:

  db
      .collection('customers')
      .doc(cred.user.uid)
      .collection('checkout_sessions')

can fetch possibly multiple documents at once. The object it yields is a QuerySnapshot type object that can contain zero or more documents in the results et. That's what your snap is here - a QuerySnapshot. You'll notice that it doesn't have a data() method. That's for DocumentSnapshot objects, where you know you either have a single document or not.

If you have a QuerySnapshot, you'll have to iterate it to get all possible document snapshots out of it, as illustrated in the documentation.

But it seems that's not even what you want to do. It looks like you want to access the document that was previously added using add(). If that's what you want, you shouldn't be querying the entire collection as you are now. Just locate the single document you want and add a listener to it.

1
votes

You need to listen to updates to the specific document that you juts added via the .add() function. This function returns a reference to that specific document: https://github.com/stripe/stripe-firebase-extensions/blob/next/firestore-stripe-subscriptions/POSTINSTALL.md#start-a-subscription-with-stripe-checkout

If you don't want to / can't use async/await syntax you will need to get that document reference from the .then() function: https://firebase.google.com/docs/firestore/manage-data/add-data#web_6

db.collection("customers")
  .doc(user)
  .collection("checkout_sessions")
  .add({
    price: "price_1I42zfKct2IqsPff6b6vFNKx",
    success_url: window.location.origin,
    cancel_url: window.location.origin,
  })
  .then((docRef) => {
    docRef.onSnapshot((snap) => {
      const { sessionId } = snap.data();
      if ({ sessionId }) {
        console.log(sessionId);
        // We have a session, let's redirect to Checkout
        // Init Stripe
        const stripe = Stripe("pk_test_ZEgiqIsOgob2wWIceTh0kCV4001CPznHi4");
        stripe.redirectToCheckout({ sessionId });
      }
    });
  });