Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for v9 beta #531

Closed
simeon9696 opened this issue May 20, 2021 · 12 comments
Closed

Support for v9 beta #531

simeon9696 opened this issue May 20, 2021 · 12 comments
Labels
feature New feature or request help wanted

Comments

@simeon9696
Copy link

Following the keynote yesterday they released the v9 Javascript SDK. This has support for treeshaking, firestore-lite and other benefits.

I'm not sure if you'd want to support something that's still in beta but I just thought I'd put it on your radar

@dosstx
Copy link

dosstx commented May 20, 2021

When I talked to @lupas on discord a while back, he alluded to the possibility of updating the nuxt module for this. Lets hope he does!

@lupas lupas added the feature New feature or request label Jun 11, 2021
@lupas lupas pinned this issue Jun 11, 2021
@lupas
Copy link
Member

lupas commented Jun 11, 2021

Hey guys

Been playing around with v9 Beta lately and I completely love it, but it will require quite the refactoring of the module. Many things of this module might even not make sense anymore... so I would probably have to build it up from scratch.

Definitely don't have time at the moment, and since it's still in Beta I will probably tackle this later this year.

If anyone wants to start a branch and start working on it, feel free, would appreciate it!

We might be able to simplify many things with v9.

@lupas
Copy link
Member

lupas commented Jun 14, 2021

Wrote a short Medium article on how to setup Firebase v9 Beta in Nuxt.js (without this module).
Module integration coming shortly before it is out of Beta, might start working on it soon.

@dosstx
Copy link

dosstx commented Jul 13, 2021

@lupas Love your medium article, but what benefits/advantages would an upgraded Nuxt/Firebase module have over the regular firebase plugin you made in the medium article? You stated that many of the features in your previous Firebase module may no longer be needed. Thanks for any insight!

@lupas
Copy link
Member

lupas commented Jul 13, 2021

@dosstx
Answered you on medium. Would be interested in everyone's thoughts on whether a new version of the module even makes sense - or if some micro-modules/plugins/helpers that solve some of the remaining difficulties would be the better approach.

@dosstx
Copy link

dosstx commented Jul 17, 2021

I've so far implemented the new v9 SDK into my app. So far so good, however, not sure how to "hook up" the onAuthStateChanged action? Can you or someone provide an example? Are we putting this back in nuxt.config.js or??

@lupas
Copy link
Member

lupas commented Jul 19, 2021

@dosstx
For SSR auth or regular client side auth?

For regular auth: Haven't tried it myself yet but you should be able to just create a plugins/myAuthInit.client.js file as a plugin, with the following content:

import { onAuthStateChanged } from "firebase/auth";

export default ({ store }) => {
  onAuthStateChanged(auth, (user) => {
    if (user) {
      store.commit("SET_USER", {
        email: user.email,
      });
    } else {
      store.commit("UNSET_USER");
    }
  });
};

Load the plugin on client side only and it should be all fine.

@dosstx
Copy link

dosstx commented Jul 28, 2021

Sorry to bother again about this....but @lupas ...with your above onAuthStateChanged() code in the plugins , how would I unsubscribe from the auth observer ? My use case is that I have a sign up button like so:

async signUp() {
      const auth = getAuth()
      const batch = writeBatch(db)

      try {
        const UserCredential = await createUserWithEmailAndPassword(
          auth,
          this.formValues.email,
          this.formValues.password
        )

        const userDocRef = doc(db, 'users', UserCredential.user.uid)
        batch.set(userDocRef, {
          uid: UserCredential.user.uid,
          displayName: this.formValues.displayName,
          photoURL: `https://gravatar.com/avatar/${md5(
            this.formValues.email
          )}?d=identicon`
        })
        const usernameDocRef = doc(db, 'usernames', this.formValues.displayName)
        batch.set(usernameDocRef, { uid: UserCredential.user.uid })

        // Commit batch
        await batch.commit()
        console.log('batch commited, user is:', UserCredential.user.uid)
        await this.verifyEmail()

I need to only let a user sign in after their email is verified. So, in your plugin code, I have:

export default ({ store }) => {
  const auth = getAuth()
  onAuthStateChanged(auth, (user) => {
    if (user) {
      if (!user.emailVerified) {
        // User has not verified the email yet
        store.dispatch('logOutUser')
      }

Problem is that I can't use the sendEmailVerification(auth.currentUser, actionCodeSettings) method because the auth observer sees that the user is not verified, hence the log out.

Hope my question makes sense.

@lupas
Copy link
Member

lupas commented Jul 30, 2021

@dosstx
Out of the top of my head, you could do something like this:

import { onAuthStateChanged } from "firebase/auth";

export default ({ store }) => {
  const unsubscribeAuthListener = onAuthStateChanged(auth, (user) => {
    if (user) {
      store.commit("SET_USER", {
        email: user.email,
      });
    } else {
      store.commit("UNSET_USER");
    }
  });
 store.commit("SET_AUTH_LISTENER", unsubscribeAuthListener); // <--- do this, and add the mutation also
}

And then somewhere in your code, unsubscribe like so:

// assuming you named it `unsubscribeAuthListener` in your state
store.state.unsubscribeAuthListener()

@dosstx
Copy link

dosstx commented Jul 30, 2021

Thanks! I think your solution is more simple. I had an overengineered version of this where I could just inject the plugin into my components and be able to use this.

import { doc, getDoc } from 'firebase/firestore'
import { db } from '~/plugins/firebase'

export default ({ store }, inject) => {
  const auth = getAuth()
  inject(
    'authObserver',
    onAuthStateChanged(auth, async (user) => {
      console.log('state:', user)
      if (user) {
        if (!user.emailVerified) {
          // Force logout user and reset store
          store.dispatch('logOutUser')
        } else {
          // Otherwise User object (not doc) has verified email .. lets move on to next steps
          const { uid } = user
          const userDocRef = doc(db, 'users', uid)
          const userDocSnap = await getDoc(userDocRef)
          if (!userDocSnap.data().emailVerified) {
            await store.dispatch('updateUserProfile', user)
            store.dispatch('onAuthStateChangedAction', user)
          } else {
            store.dispatch('onAuthStateChangedAction', user)
          }
        }
      } else {
        store.dispatch('logOutUser')
      }
    })
  )
}

and my store stuff:

  async onAuthStateChangedAction({ commit, dispatch }, authUser) {
    const { displayName, email, emailVerified, photoURL, providerData, uid } =
      authUser
    commit('SET_AUTH_USER', {
      displayName,
      email,
      emailVerified,
      photoURL,
      providerData,
      uid
    })
    await dispatch('getUserProfile', authUser)
  },
  async getUserProfile({ commit }, authUser) {
    try {
      const docRef = doc(db, 'users', authUser.uid)
      const profile = await getDoc(docRef)
      commit('SET_USER_PROFILE', profile.data())
      console.log('fetched profile and set')
    } catch (error) {
      console.error('Error fetching user profile', error)
    }
  },
  async updateUserProfile({ commit }, user) {
    try {
      const docRef = doc(db, 'users', user.uid)
      await updateDoc(docRef, {
        updatedAt: serverTimestamp(),
        emailVerified: user.emailVerified
      })
      const profile = await getDoc(docRef)
      commit('SET_USER_PROFILE', profile.data())
      console.log('User profile updated and set')
    } catch (error) {
      console.error('Error updating user profile', error)
    }
  },
  async logOutUser({ commit }) {
    const auth = getAuth()
    await signOut(auth)
    console.log('user logged out')
    commit('RESET_STORE')
  },

Then, in my sign up page I unsubscribe to listener like so:

data() {
return {
unsubscribe: null
}
}
  mounted() {
    this.unsubscribe = this.$authObserver
  },
    async signUp() {
      this.unsubscribe() < --- detach listener here and then continue with sign up process. Then, during user login, the user will get observed again automatically
...snip...
}

The use case for me is that the data model requires two root collections users and usernames. They use a simple reverse mapping (point to each other) that enables uniqueness validation so my users can pick unique usernames. Email validation is required and a user doc is created prior to that. Hence, the observer needs to watch that, but if I don't detach it during the sign up process, it causes issues with the createUserWithEmailAndPassword() and the sendEmailVerification().

It works...but I am still in testing stage. Thanks!

@1shaked
Copy link
Contributor

1shaked commented Aug 11, 2021

Is it still relevant to open a branch and start working on it?

@lupas lupas changed the title Support for v9 beta Support for Firebase Version 9+ Sep 4, 2021
@lupas lupas changed the title Support for Firebase Version 9+ Support for v9 beta Sep 4, 2021
@lupas
Copy link
Member

lupas commented Sep 4, 2021

See #573

@lupas lupas closed this as completed Sep 4, 2021
@lupas lupas unpinned this issue Sep 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request help wanted
Projects
None yet
Development

No branches or pull requests

4 participants