action not found in Vuex store - firebase

I'm following a course here:
https://thinkster.io/tutorials/nuxt-js-project/adding-authentication
I am working on adding authentication to my app and have login/logout buttons that partially work with firebase authentication. I can log in fine, but the issue is that when I'm logged in, the action in my Vuex store doesn't seem to run, therefore leaving the user logged in and the state not updating to display the logout button.
default.vue
<template>
<v-app>
<v-navigation-drawer
v-model="drawer"
:mini-variant="miniVariant"
:clipped="clipped"
fixed
app
>
<v-list>
<v-list-item
v-for="(item, i) in items"
:key="i"
:to="item.to"
router
exact
>
<v-list-item-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title v-text="item.title" />
</v-list-item-content>
</v-list-item>
<button v-if="!mySession" #click="login">Login</button>
<button v-else #click="logout">Logout</button>
</v-list>
</v-navigation-drawer>
<!-- <v-toolbar fixed app :clipped-left="clipped">
<v-toolbar-side-icon #click="drawer = !drawer"></v-toolbar-side-icon>
<v-tool-bar-title v-text="title"></v-tool-bar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn #click="login">Login</v-btn>
<v-btn #click="logout">Logout</v-btn>
</v-toolbar-items>
</v-toolbar> -->
<v-app-bar
:clipped-left="clipped"
fixed
app
>
<v-app-bar-nav-icon #click.stop="drawer = !drawer" />
<v-btn
icon
#click.stop="clipped = !clipped"
>
<v-icon>mdi-application</v-icon>
</v-btn>
<v-btn
icon
#click.stop="fixed = !fixed"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
<v-toolbar-title v-text="title" />
<v-spacer />
</v-app-bar>
<v-content>
<v-container>
<nuxt />
</v-container>
</v-content>
<v-navigation-drawer
v-model="rightDrawer"
:right="right"
temporary
fixed
>
<v-list>
<v-list-item #click.native="right = !right">
<v-list-item-action>
<v-icon light>
mdi-repeat
</v-icon>
</v-list-item-action>
<v-list-item-title>Switch drawer (click me)</v-list-item-title>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-footer
:fixed="fixed"
app
>
<span>© 2019</span>
</v-footer>
</v-app>
</template>
<script>
import {db} from '#/plugins/firebase'
import firebase from 'firebase/app'
import 'firebase/auth'
export default {
created() {
this.$store.dispatch('setSession');
},
data () {
return {
clipped: false,
drawer: false,
fixed: false,
items: [
{
icon: 'mdi-apps',
title: 'Welcome',
to: '/'
},
{
icon: 'cart',
title: 'Checkout',
to: '/checkout'
}
],
miniVariant: false,
right: true,
rightDrawer: false,
title: 'Vuetify.js'
}
},
methods: {
login() {
console.log('login');
let provider = new firebase.auth.GoogleAuthProvider();
firebase.auth()
.signInWithPopup(provider)
.then(function(result) {
console.log('signed in');
})
.catch(function(error) {
console.log(error);
})
},
logout() {
console.log('logout');
firebase.auth()
.signOut()
.then(() => {
console.log('sign out')
}).catch((error) => {
console.log(error)
})
}
},
computed: {
mySession() {
return this.$store.getters.session;
}
}
}
</script>
store/index.js
import Vuex from 'vuex'
import firebase from 'firebase/app'
import 'firebase/auth'
const createStore = () => {
return new Vuex.Store({
state: {
session: false
},
mutations: {
SET_SESSION(state, session) {
state.session = session;
}
},
getters: {
session: state => state.session
},
actions: {
setSession({commit}) {
firebase.auth().onAuthStateChanged(user => {
console.log(user);
console.log('change');
commit('SET_SESSION', user || false);
})
}
}
})
}
export default createStore
in console I am getting an error message that says:
"[vuex] unknown action type: setSession"
To reiterate, I can login using Google oauth, but when logged in, the state does not change and the logout button does not appear.
Thanks for the help!
Update:
Well now I'm extra confused. I did push updates 15 mins ago but for some reason my store/index.js file is outdated and isn't updating/saving? I have no idea what I'm doing wrong.
When looking at my store/index.js file on Github, it shows the default template:
https://github.com/SIeep/US-kratom/blob/master/US-Kratom/store/index.js
But what I have, and what was just copied from the course I'm taking is:
import Vuex from 'vuex';
import firebase from 'firebase/app';
import 'firebase/auth';
const createStore = () => {
return new Vuex.Store({
state: {
session: false,
products: []
},
mutations: {
SET_SESSION(state, session) {
state.session = session;
},
SET_PRODUCT(state, product) {
state.products = product;
}
},
getters: {
session: state => state.session,
products: state => state.products
},
actions: {
setSession({ commit }) {
firebase.auth().onAuthStateChanged(user => {
commit('SET_SESSION', user || false);
});
},
setProduct({ commit }, products) {
commit('SET_PRODUCT', products);
}
}
});
};
export default createStore;
I am saving the file and everything but it's not updating on Github which is obviously the issue with my app as well.

Erik from Thinkster.io ended up fixing the code for me. Update is here:
[https://github.com/SIeep/US-kratom/commit/bd55deacadfc065edc7df9c1365ae832a32b9b43][1]

Related

Data not display inside vuetify v-text-field with Nuxt & Firestore

this is a related question which I've asked before:
Get document data from Firestore and show the data into each of the form input field using Nuxt & Vuetify
I want the data that I've submitted to display on the v-text-field input.
As you can see from the image, I can submit my form and I can get the data accordingly.
Name: siradley_ <-- this come from my firestore
but I want it to display inside the v-text-field input, not outside the input field.
Currently, I still not know how to do it.
Any help on how to do it?
<template>
<div>
<v-container>
<v-layout>
<v-flex>
<v-card>
<v-card-text>
<v-form>
<v-layout>
<v-row>
<v-col cols="12" sm="6" md="6" v-for="(test, id) in Test">
<v-text-field
v-model="editedItem.name">{{ test.name }}</v-text-field>
<p>Name: {{ test.name }}</p>
</v-col>
<v-col cols="12" sm="6" md="6">
<v-btn #click="test">Test</v-btn>
</v-col>
</v-row>
</v-layout>
</v-form>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</div>
</template>
my script
<script>
import firebase from "firebase/app";
import firestore from "#/plugins/firebasetest";
export default {
middleware: "authentication",
layout: 'dashboard',
data: () => ({
Test: [
{
name: '',
}
],
editedItem: {
name: '',
}
}),
created() {
this.readTest();
},
methods: {
readTest() {
this.Test = [];
firestore
.collection('test')
.doc(firebase.auth().currentUser.uid)
.get()
.then((doc) => {
this.Test.push({ ...doc.data(), id: doc.id });
console.log({ ...doc.data(), id: doc.id });
})
},
test() {
var data = {
name: this.editedItem.name,
}
firestore
.collection('test')
.doc(firebase.auth().currentUser.uid)
.set(data)
.then((doc) => {
window.location.reload();
console.log({ ...doc.data, id: doc.id })
})
},
},
}
</script>
you have to update the value editedItem.name in your data object after getting the value from the server.
you have two way data binding set on the v-text-field (i.e. v-model), so you just need to use v-text-field like this:
<v-text-field v-model="editedItem.name" ></v-text-field>
and then in the code after you get the data from the server update the mentioned field in the data:
async getDataFromServerExample() {
const data = await getData();
this.editedItem.name = data.properFieldFromServerResponse;
}
then everything should work fine.
Finally can solve it hehe.
Referring to this Unable to display data in Vue.js form after pulling from Cloud Firestore , I now can display my input data inside my v-text-field.
Here's how I do it:
<v-form>
<v-layout>
<v-row :items="Test">
<v-col cols="12" sm="6" md="6">
<v-text-field
v-model="editedItem.name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="6">
<v-btn #click="test">Test</v-btn>
</v-col>
</v-row>
</v-layout>
</v-form>
<script>
import firebase from "firebase/app";
import firestore from "#/plugins/firebasetest";
export default {
middleware: "authentication",
layout: 'dashboard',
data: () => ({
editedItem: {
name: '',
}
}),
created() {
this.readTest();
},
methods: {
readTest() {
let _this = this;
firestore
.collection('test')
.doc(firebase.auth().currentUser.uid)
.get()
.then((doc) => {
if (doc.exists) {
console.log("Document data:", doc.data())
_this.editedItem.name = doc.data().name
} else {
console.log("No Document!");
}
}).catch((error) => {
console.log("Error :(");
})
},
},
}
</script>
I added let _this = this; and _this.editedItem.name = doc.data().name and it works.

Problem using signInWithEmailAndPassword method form Firebase 9 in Nuxt Vue

I'm working on this problem for a few days and I don't know how to solve it.
This is my nuxt login page and I use the new Firebase 9 auth pack to authenticate a user.
I call the signInWithEmailAndPassword method to authenticate.
When I try it with the correct credentials I never get into the first then() of the Promise:
.then((userCredential) => {
alert(userCredential)
this.$store.commit('setUser', userCredential.user)
})
But when I type in the incorrect credentials, I always get the correct error (in the catch) and the second then() is always executed.
I don't understand why I can't log in.
Can anyone help me?
Sorry for the bad English.
My login page: (pages/index.vue)
<template>
<v-container fluid fill-height>
<v-layout align-center justify-center>
<v-flex xs12 sm8 md4>
<v-card class="elevation-12">
<v-toolbar dark color="primary">
<v-toolbar-title>Anmelden</v-toolbar-title>
</v-toolbar>
<v-card-text>
<v-form
id="login-form"
ref="form"
v-model="valid"
lazy-validation
#submit.prevent="emailLogin()"
>
<v-text-field
v-model="formData.email"
:rules="emailRules"
name="email"
label="E-Mail"
counter
required
/>
<v-text-field
v-model="formData.password"
:append-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
:rules="passwordRules"
:type="show ? 'text' : 'password'"
name="password"
label="Passwort"
counter
required
#click:append="show = !show"
/>
</v-form>
</v-card-text>
<v-snackbar
v-model="snackbar"
:timeout="timeout"
>
{{ text }}
<template #action="{ attrs }">
<v-btn
color="yellow accent-2"
text
v-bind="attrs"
#click="snackbar = false"
>
Schließen
</v-btn>
</template>
</v-snackbar>
<v-card-actions>
<v-spacer />
<v-btn
type="submit"
form="login-form"
:disabled="!valid"
block
color="primary"
class="mr-4"
>
Login
</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
import { auth, signInWithEmailAndPassword } from '#/plugins/firebase'
export default {
data: () => ({
show: false,
valid: true,
snackbar: '',
timeout: 10000,
text: '',
formData: {
email: '',
password: ''
},
emailRules: [
v => !!v || 'E-Mail ist verpflichtend',
v => /.+#.+\..+/.test(v) || 'Keine gültige E-Mail-Adresse'
],
passwordRules: [
v => !!v || 'Passwort ist verpflichtend'
]
}),
methods: {
emailLogin () {
signInWithEmailAndPassword(auth, this.formData.email, this.formData.password)
.then((userCredential) => {
alert(userCredential)
this.$store.commit('setUser', userCredential.user)
})
.catch((error) => {
switch (error.code) {
case 'auth/invalid-email':
this.text = 'Die E-Mail-Adresse ist falsch'
break
case 'auth/user-disabled':
this.text = 'Der User ist deaktiviert'
break
case 'auth/user-not-found':
this.text = 'Kein Account gefunden'
break
case 'auth/wrong-password':
this.text = 'Das Passwort ist falsch'
break
default:
this.text = 'Es ist ein Fehler aufgetreten: ' + error.message
break
}
this.snackbar = true
}).then(() => {
this.formData.email = ''
this.formData.password = ''
this.$refs.form.resetValidation()
this.$router.push('/post')
})
}
}
}
</script>
My firebase setup file: (plugins/firbase.js) --> is registered in nuxt.config.js
import { initializeApp } from 'firebase/app'
import { getFirestore } from 'firebase/firestore'
import { getStorage } from 'firebase/storage'
import { getAuth, signInWithEmailAndPassword, signOut, onAuthStateChanged } from 'firebase/auth'
const firebaseConfig = {
apiKey: 'key',
authDomain: 'domain',
projectId: 'project',
storageBucket: 'bucket',
messagingSenderId: 'message',
appId: 'app',
measurementId: 'measure'
}
const app = initializeApp(firebaseConfig)
const auth = getAuth(app)
const fire = getFirestore(app)
const storage = getStorage(app)
export { auth, fire, storage, signInWithEmailAndPassword, signOut, onAuthStateChanged }

Vue.js - Invalid prop: type check failed for prop "src". Expected String, Object, got Promise

I'm trying to get an image inserted into my firebase's firestore and storage and display it on a v-card
my v-card code:
<v-row>
<v-col cols="3" v-for="massage in massages" :key="massage.id">
<v-card
class="mx-auto"
max-width="400"
>
<v-img
v-if="massage.image"
class="white--text align-end"
height="200px"
:src="massage.image"
>
</v-img>
<v-card-title>{{massage.title}}</v-card-title>
<v-card-text class="text--primary">
<div>{{massage.shortDescription}}</div>
</v-card-text>
<v-card-actions>
<v-btn
color="orange"
text
#click="goTodetail(massage.id)"
>
Explore
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
my script:
<script>
import{ db, storage} from '#/firebase.js';
export default {
el: '#vue',
name: 'BaseHeading',
// massId:this.$route.params.Pid,
components: {
BaseInfoCard: () => import('#/components/base/InfoCard'),
},
data() {
return{
massages:[],
showmassage: false,
showrehabilitation: false,
showsupport: false,
modal_1: true,
modal_2: false,
modal_3: false,
}
},
created() {
try{
db.collection("massages").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
let img = ''
if(doc.data().image){
img = storage.ref().child(doc.data().image).getDownloadURL()
}
this.massages.push({
id: doc.id,
title: doc.data().title,
shortDescription: doc.data().shortDescription,
image: img
})
})
});
}catch(e){
console.log(e)
}
},
}
</script>
I think it provides promise but cannot figure out how to deal with it. The error is Invalid prop: type check failed for prop "src". Expected String, Object, got Promise.
I tried to put the following in the props:
props: {
src: [ String, Object],
},
but I still have the same error
Resolve the Promise when retrieving the image URL, before you pass it into your massage object.
created() {
try {
db.collection('massages')
.get()
.then((querySnapshot) => {
querySnapshot.forEach(async (doc) => {
// start pertinent change
if (doc.data().image) {
storage
.ref()
.child(doc.data().image)
.getDownloadURL()
.then((url) => {
this.massages.push({
id: doc.id,
title: doc.data().title,
shortDescription: doc.data().shortDescription,
image: url,
})
})
} else {
this.massages.push({
id: doc.id,
title: doc.data().title,
shortDescription: doc.data().shortDescription,
})
}
// end pertinent change
})
})
} catch (e) {
console.log(e)
}
}

Vue js - reload component on database insert

I have the following setup
Component.vue (display db collections as grid in main page)
...
<v-flex v-for="i in items" :key="i.id" xs6 sm3 md3>
<v-card color="primary">
<v-card-text>
<h2
class="font-weight-regular mb-4"
>
{{ i.description }}
</h2>
</v-card-text>
</v-card>
</v-flex>
...
<script>
import { db } from '~/plugins/firebase.js'
export default {
data: () => ({
items: []
}),
props: ['reload'],
watch: {
reload: function (newVal, oldVal) {
this.items = items
alert('changed reload')
}
},
methods: {
firestore() {
db.collection('items')
.get()
.then(querySnapshot => {
const items = []
querySnapshot.forEach(function(doc) {
const item = doc.data()
item.id = doc.id
items.push(useritem)
})
this.items = items
})
.catch(function(error) {
alert('Error getting documents: ' + error)
})
}
}
}
</script>
index.vue (main page that has grid component and button to add new collection)
....
<v-layout mb-4>
<v-btn
#click="submit"
>
Add Item
</v-btn>
</v-layout>
<v-layout mb-4>
<component :reload="reload" />
</v-layout>
....
<script>
import { db } from '~/plugins/firebase.js'
import component from '~/components/Component.vue'
import moment from 'moment'
export default {
components: {
component
},
data() {
return {
description: 'test',
date: moment(),
reload: false
}
},
methods: {
submit() {
db.collection('items')
.add({
description: this.description,
deadline: new Date(moment(this.date)),
status: true
})
.then(docRef => {
this.reload = true
})
.catch(error => {
alert('Error adding document: ', error)
})
}
}
}
</script>
As can be seen, I've added a prop to the component to sort of trigger a reload of data from database whenever a new item is added on the main page using the button.
On successful insert the value changes from false to true. However the component grid does not reload. Refreshing the page shows the new item in grid.
How can i make the component reactive or trigger reload on addition of new item?
In your firestore method in Component.vue, you are using the get method which according to the firestore documentation, only retrieves the data once, it doesn't listen to any change, you'd have to refresh your page to see your updated changes.
However, to listen to changes to your firestore DB and update accordingly on your website, you have to set a listener, Cloud Firestore sends your listener an initial snapshot of the data, and then another snapshot each time the document changes.
methods: {
firestore() {
db.collection("items").onSnapshot(
snapshot => {
const documents = snapshot.docs.map(doc => {
const item = doc.data();
item.id = doc.id;
return item;
});
this.items = documents;
},
error => {
// handle errors
alert("Error getting documents: " + error);
}
);
}

vuefire binding broke after using firebase auth & router

I've a simple vuejs app, connected to firebase, the v-for in the child component was working perfectly until I implemented authentication with firebase and the vue router.
Now its broken :(
Authentication happens fine, but the items from the query are not being there anymore (undefined).
Firebase credentials are good and the database herself has data on the selected path.
this is main.js
import 'onsenui';
import Vue from 'vue';
import VueOnsen from 'vue-onsenui';
import VueFire from 'vuefire';
import VueRouter from 'vue-router'
import firebaseui from 'firebaseui';
import router from './router'
import {connection} from './firebaseconfig';
require('onsenui/css-components-src/src/onsen-css-components.css');
require('onsenui/css/onsenui.css');
require('firebaseui/dist/firebaseui.css');
import App from './App.vue';
Vue.use(VueOnsen);
Vue.use(VueFire);
Vue.use(VueRouter);
var app = new Vue({
router,
created() {
connection.auth().onAuthStateChanged((user) => {
if(user) {
this.$router.push('/home')
} else {
this.$router.push('/auth')
}
});
} ,
el: '#app',
template: '<app></app>',
components:{
App
} ,
render: h => h(App)
});
App.vue
<template>
<router-view></router-view>
</template>
<script>
import auth from './components/auth'
import dashboard from './components/dashboard'
import home from './components/homePage'
import stores from './components/storesPage'
import social from './components/socialPage'
import settings from './components/settingsPage'
export default {
data() {
return {
currentPage: 'auth',
// pages: ['home', 'stores', 'settings' , 'social'],
pages: {
'dashboard' :
{ 'name' : 'dashboard' , 'icon' : 'md-view-dashboard' } ,
'home' :
{ 'name' : 'home' , 'icon' : 'md-view-home' } ,
'Stores' :
{ 'name' : 'stores' , 'icon' : 'md-store' } ,
'Social' :
{ 'name' : 'social' , 'icon' : 'md-share' } ,
'account' :
{ 'name' : 'account' , 'icon' : 'md-account-o' } ,
'auth' :
{ 'name' : 'auth' , 'icon' : 'md-settings' } ,
},
openSide: false
};
},
components: {
auth,
dashboard,
home,
stores,
settings ,
social
}
}
</script>
Fire base config :
import firebase from 'firebase';
const config = {
apiKey: "xxxxxxxxxx",
authDomain: "xxx",
databaseURL: "xxx",
projectId: "yyyyy",
storageBucket: "yyyyyyy",
messagingSenderId: "yyyyy"
};
export const FireBconfig = config;
export const connection = firebase.initializeApp(config);
export const db = connection.database();
auth.vue
<template lang="html">
<div id="firebaseui-auth-container">
</div>
</template>
<script>
import firebase from 'firebase';
import firebaseui from 'firebaseui'
import {FireBconfig} from '../firebaseconfig';
export default {
name: 'auth',
mounted() {
var uiConfig = {
signInSuccessUrl: '/success',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.EmailAuthProvider.PROVIDER_ID
]
};
var ui = new firebaseui.auth.AuthUI(firebase.auth());
ui.start('#firebaseui-auth-container', uiConfig);
},
}
</script>
and finally the child component displaying on successful auth and pulling data from the firebase path
<template>
<v-ons-page style="background-color:grey">
<custom-toolbar class="topbarback" :title="'Home'" :action="toggleMenu">
</custom-toolbar>
<v-ons-pull-hook :action="loadItem" #changestate="state = $event.state">
<span v-show="state === 'initial'"> Pull to refresh </span>
<span v-show="state === 'preaction'"> Release </span>
<span v-show="state === 'action'"> <v-ons-progress-bar indeterminate></v-ons-progress-bar> </span>
</v-ons-pull-hook>
<v-ons-row >
<v-ons-col v-bind:key="item" v-for="item in items" width="33%">
<div style="padding:5px;margin: 0px;border:solid 2px #E4E4E4;height:240px;vertical-align:middle;display:table-cell;background-color:#FFF;position: relative;">
<div style="text-align:center">
<ons-input #change="checkboxclick" :input-id="item.ItemID" v-model="selected" style=" position: absolute; top: 10px; right: 10px;" type="checkbox" ></ons-input>
<label :for="item.ItemID">
<span class="price">{{item.CurrentPriceAmount}} €</span>
<span class="watchers">10</span>
<img tappable style="width:85%;max-height:85%" class="item-thum" v-bind:src="item. PictureDetailsGalleryURL" />
</label>
</div>
<div class="item-title"> <span style="font-size:9px;background-color:#FFF">{{item.title}}</ span><br /><br /></div>
</div>
</v-ons-col>
</v-ons-row>
<v-ons-speed-dial position="bottom right" direction="up"
:visible="spdVisible"
:open.sync="spdOpen"
>
<v-ons-fab :style="spdStyle">
<v-ons-icon style="font-size:8px" icon="md-format-valign-top"><span style=" font-size:12px;font-family: 'Open Sans', sans-serif;">{{counter}}</span></v-ons-icon>
</v-ons-fab>
<v-ons-speed-dial-item v-for="(icon, name) in shareItems"
:style="spdStyle"
#click="$ons.notification.confirm(`Share on ${name}?`)"
>
<v-ons-icon :icon="icon"></v-ons-icon>
</v-ons-speed-dial-item>
</v-ons-speed-dial>
</v-ons-page>
</template>
<script>
import customToolbar from './toolbarHome'
import {db} from '../firebaseconfig';
export default {
data :
function() {
return {
spdVisible: false,
spdOpen: false,
spdStyle: {
backgroundColor: this.$ons.platform.isIOS() ? '#4282cc' : null
} ,
items : [1,2,3] ,
counter : 0 ,
selectedItems : [] ,
state: 'initial',
selected : [],
shareItems: {
'With Relist': 'md-swap-alt' ,
'Facebook': 'md-arrow-split',
}
}
},
firebase: {
items : {
source: db.ref('users/buisine/stores/ebay/red/items')
}
},
props: ['toggleMenu' , 'itemsRef'],
components: { customToolbar } ,
methods: {
checkboxclick(event) {
if(event.target.checked===true)
{
this.counter++;
this.selectedItems.push(event.target.id);
}
else
{
this.selectedItems.splice( this.selectedItems.indexOf(event.target.id) , 1);
this.counter--;
}
},
loadItem(done) {
setTimeout(() => {
this.items = [...this.items, this.items.length + 1];
done();
}, 1500);
},
}
}
</script>
Tried different code on the firebase object that should return the data, nothing worked.
Well, tried on clean blank vuejs project, failed again.
BUT worked again by supressing all Users in the authentication tab in firebase console !!

Resources