Closed simeon9696 closed 2 years ago
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!
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.
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.
@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!
@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.
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??
@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.
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.
@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()
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!
Is it still relevant to open a branch and start working on it?
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