1

I’m creating a restaurant reservation app with Nuxt, Laravel API and FirebaseAuthentication.

I created a like/unlike feature that the heart color changes to red if the logged in user clicked a heart button on cards.

The function sometimes works fine but sometimes gets an error at getLikes() in store/auth.js when it’s reloaded.

GET http://localhost:8000/api/v1/users/ 405 (Method Not Allowed)

The API path to get the liked restaurant is api/v1/likes/{user_id}, bit since the user information is not stored, the information is taken according to the following flow.

  1. Get user information. (api/v1/users/{uid})

  2. Get a list of liked restaurants of a logged in user. (api/v1/likes/{user_id})

When I checked the execution history of Vuex, the execution order changed depending on whether it succeeded or failed.

When it succeeded, auth/setUserId is executed faster than likes/setLikedShops.

I think the problem is that the likes/setLikesShops process proceeds without getting the user information, but I don’t get the solution.

How can I make sure that I get the user_id first and then get the favorites?

// plugins/firebase.js
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
// middleware/auth.js
export default function({store}) {
    store.dispatch('auth/onAuth')
}
// pages/index.vue
async mounted() {
    await this.$store.dispatch('shop/getShops')
    await this.$store.dispatch('likes/getLikes')
    return
}
// store/auth.js
export const state = () => ({
    userId: '',
    userUid: '',
    userEmail: '',
    loggedIn: false,
})

export const mutations = {
    loginStatusChange(state, status) {
        state.loggedIn = status
    },
    setUserUid(state, userUid) {
        state.userUid = userUid
    },
    setUserEmail(state, userEmail) {
        state.userEmail = userEmail
    },
    setUserId(state, userId) {
        state.userId = userId
    }
}

export const actions = {
    login({ commit, dispatch }, payload) {
        firebase
            .auth()
            .signInWithEmailAndPassword(payload.email, payload.password)
        .then(async (result) => {
            const user = result.user
            commit('loginStatusChange', true)
            console.log('Login was successful')
            commit('setUserUid', user.uid)
            commit('setUserEmail', user.email)
            await dispatch('getUserInfo', user.uid)
            await this.$router.push('/')
        })
        .catch((error) => {
            const errorCode = error.code
            console.log('error: ' + errorCode)
        })
    },
    onAuth({ commit, dispatch }) {
        firebase.auth().onAuthStateChanged(async user => {
            user = user ? user : {}
            commit('setUserUid', user.uid)
            commit('setUserEmail', user.email)
            commit('loginStatusChange', user.uid ? true : false)
            await dispatch('getUserInfo', user.uid)
        })
    },
    async getUserInfo({commit}, uid) {
        const data = await axios.get(
            'http://localhost:8000/api/v1/users/'
            + uid
        )
        commit('setUserId', data.data.id)
    }
}

export const getters = {
    isAuthenticated(state) {
        return state.loggedIn != false
    }
}

// store/likes.js
export const state = () => (
    {
        likedShops: [],
        likedShopIds: []
    }
)

export const mutations = {
    setLikedShops(state, shops) {
        state.likedShops.push(...shops)
    },
    setLikedShopIds(state) {
        state.likedShopIds = state.likedShops.map(obj => obj.shop_id)
        console.log('likedShopIds: ' + state.likedShopIds)
    }
}

export const actions = {
    async getLikes({ rootState, commit }) {
        const userUid = await rootState.auth.userUid
        const user = await axios.get(
            `${process.env.baseUrl}/users/${userUid}`
        )
        const userId = await user.data.id
        const result = await axios.get(
            `${process.env.baseUrl}/likes/${userId}`
        )
        await commit('setLikedShops', result.data)
        await commit('setLikedShopIds')
    },
}

export const getters = {
    getLikedShops: (state) => {
        return state.likedShops
    },
    getLikedShopIds: (state) => {
        return state.likedShopIds
    }
}
Takichee
  • 85
  • 1
  • 6

1 Answers1

0

You should probably await store.dispatch('auth/onAuth') too, if you want to be sure that the middleware is fully ready before proceeding.

The use of async/await is recommended over .then (which is deprecated), so try to use it everywhere and not make a strange mix between them.

Also, even if your login method should work fine, I'd still try to wrap all the commit into an action, so that you're sure that they are properly executed, following the flow of your awaited dispatches.

You should probably configure your axios instance globally, use runtimeConfig env variables and strip your getters from the likes.js file since you're accessing them without any modification/formatting/sorting/etc (use regular state here).

kissu
  • 24,311
  • 11
  • 36
  • 67