Get Current User Login User Information in Profile Page - Firebase and Vuejs - vue.js

I'm trying to create a user profile for signed up users in my application.
I created a collection named profiles and field name in my cloud firestore to store the user's name when they register for an account.
So, I'm using vuex for better management. Here is a piece of code for what I've done so far.
My Store.js
signUserUp ({commit}, payload) {
commit('setLoading', true)
commit('clearError')
firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(
user => {
commit('setLoading', false)
const newUser = {
id: user.uid
}
commit('setUser', newUser)
// Add a new document in collection "cities"
db.collection('profiles').doc(user.user.uid).set({
name: payload.name
})
.then(function () {
console.log('Document successfully written!')
})
.catch(function (error) {
console.error('Error writing document: ', error)
})
toastr.success('Your Account was created successfully')
}
)
.catch(
error => {
commit('setLoading', false)
commit('setError', error)
toastr.error('Oops' + error.message)
}
)
}
My SignUp.vue
This is my text field to collect the user name first followed by the email and password of the user.
<form #submit.prevent="onSignup">
<v-layout row>
<v-flex xs12>
<v-text-field
name="name"
label="Name"
id="name"
v-model="name"
type="text"
required></v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-text-field
name="email"
label="Email"
id="email"
v-model="email"
type="email"
required></v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-text-field
:append-icon="showPassword ? 'visibility' : 'visibility_off'"
:type="showPassword ? 'text' : 'password'"
name="password input-10-2"
label="Password"
id="password"
value=""
class="input-group--focused"
v-model="password"
#click:append="showPassword = !showPassword"
required
></v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-text-field
:append-icon="showPasswordConfirm ? 'visibility' : 'visibility_off'"
:type="showPasswordConfirm ? 'text' : 'password'"
name="confirmPassword input-10-2"
label="Confirm Password"
id="confirmPassword"
value=""
class="input-group--focused"
v-model="confirmPassword"
#click:append="showPasswordConfirm = !showPasswordConfirm"
:rules="[comparePasswords]"
></v-text-field>
</v-flex>
</v-layout>
<v-layout row wrap>
<v-flex xs12 sm6 class="text-xs-center text-sm-left">
<v-btn
color="#4527a0"
type="submit"
class="btn__content"
:loading="loading"
:disabled="loading"
#click="loader = 'loading'"
>
Sign up
<span slot="loader" class="custom-loader">
<v-icon light>cached</v-icon>
</span>
</v-btn>
</v-flex>
<v-flex xs12 sm6 class="mt-3 text-xs-center text-sm-right">
<router-link to="/signin" tag="span" style="cursor: pointer;">Already have an Account? Sign in</router-link>
</v-flex>
</v-layout>
</form>
The script for my SignUp.vue
export default {
data () {
return {
name: null,
email: null,
password: '',
confirmPassword: '',
showPassword: false,
showPasswordConfirm: false,
loader: null
}
},
methods: {
onSignup () {
this.$store.dispatch('signUserUp', {email: this.email, password: this.password})
}
}
I want the name the user enters during signing up for an account being pushed to the field I've in the profiles collection. But I'm getting this error
DocumentReference.set() called with invalid data. Unsupported field value: undefined (found in field name)

In your code, you are using
firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password).then(user=>{
//getting your user details
});
But there is no any
then(user=>{//user details})
function in firebase to get user detail after sign up or log in.
There is a separate function to check the authentication state of a user where you can get your user detail and then store it is Firestore.
You can use the following method:-
For Signup of a user:
firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
After signup you have to signIn your user to get user detail in authentication observer.
For SignIn of a user:
firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
When a user successfully signs in, you can get information about the user in the observer.
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var displayName = user.displayName;
var email = user.email;
var emailVerified = user.emailVerified;
var photoURL = user.photoURL;
var isAnonymous = user.isAnonymous;
var uid = user.uid;
var providerData = user.providerData;
// ...
} else {
// User is signed out.
// ...
}
});

Related

Custom form Validation by Vuetify Showing Error _this.$refs[f].validate is not a function

I want to make custom validation with Vuetify. My Vuetify version is 1.11.3. Here is my template. I set a ref to v-card according to this documentation.
<v-card ref="form">
<v-card-text>
<v-text-field
ref="name"
v-model="name"
label="Full Name:"
:rules="[() => !!name || 'Name is required']"
:error-messages="errorMessages"
required
light
>
</v-text-field>
<v-text-field
ref="email"
v-model="email"
label="Email Address:"
:rules="[
() => !!email || 'Email is required',
() => (!!email && /.+#.+/.test(email)) || 'Email must be valid',
]"
required
light
></v-text-field>
<VuePhoneNumberInput
ref="phone"
v-model="phone"
color="black"
dark-color="white"
size="lg"
default-country-code="BD"
light
required
/>
<v-textarea
ref="msg"
v-model="msg"
label="Message"
:rules="[() => !!msg || 'Message is required']"
light
></v-textarea>
</v-card-text>
<v-card-actions>
<v-btn #click="sendForm"> Submit </v-btn>
</v-card-actions>
</v-card>
I am trying to validate the form and textfields with their references.
This is my code:
data() {
return {
name: null,
email: null,
phone: null,
msg: null,
submitStatus: null,
formHasErrors: false,
errorMessages: '',
}
},
computed: {
form() {
return {
name: this.name,
email: this.email,
phone: this.phone,
msg: this.msg,
}
},
},
watch: {
name() {
this.errorMessages = ''
},
},
methods: {
sendForm() {
this.formHasErrors = false
Object.keys(this.form).forEach((f) => {
if (!this.form[f]) this.formHasErrors = true
this.$refs[f].validate(true)
})
}
When I submit the button, It shows
client.js?06a0:103 TypeError: _this.$refs[f].validate is not a
function
I get following error. What is the wrong with that?
I would recommence using V-form instead of v-card here.
Then you can check if your form is valid with the function this.$ref.myForm.validate() which returns a boolean
Here is a small example:
<v-card>
<v-card-text>
<v-form ref="myForm">
<v-row>
<v-col
cols="12"
sm="7"
>
<v-text-field
prepend-icon="mdi-tag-text"
v-model="form.name"
:rules="[
(v) => !!v || 'Name is requierd',
]"
label="Name"
/>
</v-col>
</v-row>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
#click="check"
>
Check
</v-btn>
</v-card-actions>
</v-card>
And the script :
export default {
data: () => ({
form:{
name : ""
},
}),
methods:{
check(){
if (this.$refs.myForm.validate()){
//form is valid
} else {
//form is not valid
}
}
}
}

Unspecified variables although I've used them

I have a site that I initially want to create an interface for SignUp and login, I created a page for Login with all the data needed to be placed, but this error appeared to me how can I handle it?
C:\Users\Super\Desktop\tatbekat\my-app\src\pages\Auth\login.vue
60:8 error 'axios' is defined but never used no-unused-vars
81:13 error 'success' is defined but never used no-unused-vars
84:14 error 'error' is defined but never used no-unused-vars
This is the login page that contains the login form and a set of data that must be set in addition to a special login function.
login.vue:
<template>
<v-container>
<v-layout row>
<v-flex xs12 sm6 offset-sm3>
<v-card>
<v-alert color="error" :value="error" icon="close"> </v-alert>
<v-card-text>
<v-container>
<form #click="onLogin">
<v-layout row>
<v-flex xs12>
<v-text-field
name="email"
label="Email"
id="email"
v-model="loginUser.email"
type="text"
color="#43A047"
required
>
{{ email }}
</v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-text-field
name="password"
label="Password"
id="password"
v-model="loginUser.password"
type="password"
color="#43A047"
required
>
{{ password }}
</v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-btn class="green darken-1 color">
Sign In
</v-btn>
</v-flex>
</v-layout>
</form>
</v-container>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
import { mapActions } from 'vuex'
import axios from "axios";
export default {
data() {
return {
loginUser: {
email: "",
password: "",
error: false
},
};
},
method: {
...mapActions([
'LOGIN'
]),
onSignIn(){
this.$store.dispatch('LOGIN',{
email:this.loginUser.email,
password:this.loginUser.password
})
.then(success=>{
this.$router.push("/")
})
.catch(error => {
this.error = true
})
}
},
};
</script>
<style scoped>
.color {
color: #fafafa;
}
</style>
And in this file, they wrote the necessary actions for the login and signup process.
user-store.js:
import axios from "axios";
export default {
state: {},
getters: {},
mutations: {},
actions: {
SIGNUP: (/*{ commit },*/ payload) => {
return new Promise((resolve, reject) => {
axios.post(`/signup` , payload)
.then(({/*data ,*/ status }) => {
if (status === 200){
resolve(true)
}
})
.catch(error =>{
reject(error)
})
});
},
LOGIN: (/*{ commit },*/ payload) => {
return new Promise((resolve, reject) => {
axios.post(`/signin` , payload)
.then(({/*data ,*/ status }) => {
if (status === 200){
resolve(true)
}
})
.catch(error =>{
reject(error)
})
});
},
},
};
All the errors are coming from login.vue file:.
axios: you have imported axios in login.vue but the actual axios calling is in the store file so the axios in login.vue is not used and you can delete the import.
success: in onSignIn method in login.vue you didn't use success in then call back so you can rewrite it like this:.
.then(() => {this.$router.push('/')}).
error: like the previous one you can rewrite catch block in login.vue like this:.
.catch(() => {this.error = true})

How to programatically close a Veutify dialog

Hello everyone i was searching on the vuetify documentation a function or something like that to close a form dialog just after getting the axios response with the status 200 ..
i don't if there's a way to get a dialog instance and use a close() method on it like the bootstrap modals
here's my code :
template code
<template>
<v-dialog justify-center max-width="500px">
<template v-slot:activator="{on}">
<v-icon
small
v-on="on"
>
mdi-pencil
</v-icon>
</template>
<v-card>
<form #submit.prevent="submit">
<v-card-text>
<v-text-field
v-model="name"
label="Name"
required
></v-text-field>
<v-text-field
v-model="email"
label="E-mail"
required
></v-text-field>
<v-text-field
v-model="password"
label="password"
required>
</v-text-field>
</v-card-text>
<v-card-actions>
<v-btn
color="blue darken-1"
text
>close</v-btn>
<v-btn
color="blue darke-1"
text
type="submit"
>apply</v-btn>
</v-card-actions>
</form>
</v-card>
</v-dialog>
</template>
and here's the script
<script>
export default {
data () {
return {
name: '',
email: '',
password: ''
}
},
methods: {
submit() {
let Data = new FormData()
Data.append('name', this.name)
Data.append('email', this.email)
Data.append('password', this.password)
axios.post('http://stage.test/admin/users', Data)
.then(Response => {
if (Response.status === 200) {
}
})
}
},
}
</script>
Try to bind dialog component to a data property called open as follows :
<template>
<v-dialog v-model="open" justify-center max-width="500px">
<template v-slot:activator="{on}">
<v-icon
small
v-on="on"
>
mdi-pencil
</v-icon>
.....
then in then callback assign false to this.open
<script>
export default {
data () {
return {
open:false,
name: '',
email: '',
password: ''
}
},
methods: {
submit() {
let Data = new FormData()
Data.append('name', this.name)
Data.append('email', this.email)
Data.append('password', this.password)
axios.post('http://stage.test/admin/users', Data)
.then(Response => {
if (Response.status === 200) {
this.open=false
}
})
}
},
}
</script>

Handling of user status already exists at login

I have a form to sign in and another form to sign up, and I have a store file, and when I enter user data, the data is stored in the local storage and VueX.
And all users are stored in the matrix "user".
And now I want to verify when I'm running a login.
If the user already exists, a message that "he already exists" should appear.
How can I solve the problem?
This is store file, in which a set of functions is written and in it there is a "user" array.
store.js:
import Vue from 'vue'
import Vuex from 'vuex'
const LOGIN = "LOGIN";
const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGOUT = "LOGOUT";
import image1 from '../assets/img/image4.jpg'
import image2 from '../assets/img/image2.jpg'
import image3 from '../assets/img/image3.jpg'
import image4 from '../assets/img/insta2.jpg'
Vue.use(Vuex)
export const store = new Vuex.Store({
state:{
isLoggedIn: !!localStorage.getItem('token'),
user:[
{name:'Hiba',
email:'Hiba69#gmail.com',
password:'123442321325'
}
]
},
mutations:{
createUser(state,payload){
state.user.push(payload)
}
},
},
getters:{
loadedUsers(state){
return state.user.sort((userA,userB)=>{
return userA.id >userB.id
})
},
isLoggedIn: state => {
return state.isLoggedIn
}
}
})
This is the signup file, through which you sign up to the site by entering the user's data.
signup.vue:
<template>
<div>
<v-container>
<v-layout row>
<v-flex xs12 sm6 offset-sm3>
<v-card>
<v-img
height="180px"
:src="
'https://cdn.awave.se/wp-content/uploads/sites/3/2019/02/case_greenfood_1new.jpg'
"
></v-img>
<v-card-text>
<v-container>
<form #click="onSignUp">
<v-layout row>
<v-flex xs12>
<v-text-field
name="id"
label="Id"
id="id"
v-model="id"
type="number"
color="#43A047"
required
>
{{ id }}
</v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-text-field
name="name"
label="Name"
id="name"
v-model="name"
type="text"
color="#43A047"
required
>
{{ name }}
</v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-text-field
name="email"
label="Email"
id="email"
v-model="email"
type="text"
color="#43A047"
required
>
{{ email }}
</v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-text-field
name="password"
label="Password"
id="password"
v-model="password"
type="password"
color="#43A047"
required
>
{{ password }}
</v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-btn class="green darken-1 color">
Sign up
</v-btn>
</v-flex>
</v-layout>
</form>
</v-container>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</div>
</template>
<script>
export default {
data() {
return {
id: "",
name: "",
email: "",
password: "",
};
},
computed: {
formIsValid() {
return (
this.id !== "" &&
this.name !== "" &&
this.email !== "" &&
this.password !== ""
);
},
},
watch: {
name(newName) {
localStorage.name = newName;
},
},
methods: {
onSignUp() {
if (!this.formIsValid) {
return;
}
const signup = {
name: this.name,
email: this.email,
password: this.password,
};
console.log(signup);
this.$store.commit("createUser", signup);
const stringifiedData = JSON.stringify(signup);
// console.log("S: ", stringifiedData);
localStorage.setItem("signup", stringifiedData);
console.log("We got : ", JSON.parse(localStorage.getItem("signup")));
},
},
};
</script>
<style scoped>
.color {
color: #fafafa;
}
</style>
This is the login file, through which you log in to the site by entering the user's data.
signin.vue:
<template>
<v-container>
<v-layout row>
<v-flex xs12 sm6 offset-sm3>
<v-card>
<v-card-text>
<v-container>
<form #click="onSignIn">
<v-layout row>
<v-flex xs12>
<v-text-field
name="email"
label="Email"
id="email"
v-model="email"
type="text"
color="#43A047"
required
>
{{ email }}
</v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-text-field
name="password"
label="Password"
id="password"
v-model="password"
type="password"
color="#43A047"
required
>
{{ password }}
</v-text-field>
</v-flex>
</v-layout>
<v-layout row>
<v-flex xs12>
<v-btn class="green darken-1 color">
Sign In
</v-btn>
</v-flex>
</v-layout>
</form>
</v-container>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
export default {
data() {
return {
email: "",
password: "",
};
},
methods: {
onSignIn() {
const signin = {
email: this.email,
password: this.password,
};
console.log(signin);
const stringifiedData = JSON.stringify(signin);
localStorage.setItem("signin", stringifiedData);
console.log("We got : ", JSON.parse(localStorage.getItem("signin")));
},
}
};
</script>
<style scoped>
.color {
color: #fafafa;
}
</style>
You should check if there is an user, when you created the app.
At main.js, you could use something like that;
new Vue({
el: '#app',
router,
store,
render: h => h(App),
created() {
if (localStorage.getItem("user")) {
store.dispatch("autoSignIn", localStorage.getItem("user"));
}
}
And in your vuex store, create autoSignIn method,
autoSignIn({ commit }, payload) {
commit("setLoading", true);
var token = JSON.parse(payload);
var decoded = jwt.verify(token, process.env.VUE_APP_TOKEN);
var loggedUser = {
id: decoded.id,
email: decoded.email
};
commit("setUser", loggedUser);
commit("setLoading", false);
},
And in your signup or login page, if your user state is not null, you can redirect them to the page you want to..
It is better practice to redirect user before rendering the page, so you could use router to check;
{
path: "/login",
beforeEnter: (to, from, next) => {
if (!store.getters.user) {
{
next();
}
} else {
next("/user_secret_page");
}
}
},

Call to database after successful login is not being made

I'm having difficulty in getting an axios call to my database being initiated after a user has logged into my SPA.
A route (gaplist/3) brings the user to a page (gaplist.vue) which
detects if the user is logged in or not.
If not logged in, a login form is presented.
Once the entered username/password combo is accepted, the user is "pushed" to the same page (gaplist/3)
Here, the logged in status is detected and - this is where it all falls down - a call to the database would return a bunch of records associated with the user and the parameter "3".
Unfortunately, the last step doesn't fully happen. The logged in status is detected, but the database call is not made. Only if I refresh the page is the call made and the results presented.
What concept am I not grasping here?
Thanks, Tom.
My code is as follows:
GapList.vue (route: gaplist/3)
<template>
<v-content>
<v-container fluid fill-height>
<v-layout justify-center>
<v-flex xs12 sm6>
<h1>Production and sale of produce</h1>
<v-card flat>
<div v-if="isIn">
<p v-for="(card, id) in cards">{{card.product}}</p>
<logout-button></logout-button>
</div>
<div v-else>
<gap-login :gapid=gapid></gap-login>
</div>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-content>
</template>
<script>
import GapLogin from '../components/gap/GapLogin';
import LogoutButton from '../components/gap/LogoutButton'
export default {
name: 'GapList',
components: {
GapLogin,
LogoutButton
},
data () {
return {
gapid: this.$route.params.id,
cards: [],
lang: this.$i18n.locale,
bNoRecords: false,
}
},
created(){
this.loadCrops(this.gapid,this.lang)
},
computed: {
isIn : function(){ return this.$store.getters.isLoggedIn},
},
methods: {
loadCrops(gapid,lang){
var vm = this;
if (this.isIn){
axios.get('/gapcroplist/' + gapid)
.then(function (resp) {
vm.cards = resp.data;
})
.catch(function (resp) {
vm.bNoRecords = true;
});
}
},
}
}
</script>
GapLogin.vue
<template>
<div class="formdiv">
<v-layout justify-center>
<h3>Login</h3>
<v-card flat>
<v-alert
v-if="loginError"
:value="true"
type="error"
transition="scale-transition"
dismissible
>
You didn't enter correct information
</v-alert>
<v-form class="login" #submit.prevent="login">
<v-text-field
v-model="form.email"
type="email"
label="Email"
required
autofocus
></v-text-field>
<v-text-field
v-model="form.password"
type="password"
label="Password"
required
></v-text-field>
<v-btn
type="submit"
>Login in </v-btn>
</v-form>
</v-card>
</v-layout>
</div>
</template>
<script>
export default {
name: "GapLogin",
props: ['gapid'],
data() {
return {
form: {
email: null,
password: null
},
loginError:false
}
},
methods: {
login: function () {
this.loginError = false
this.$store.dispatch('login', this.form)
.then(() =>
{this.$router.push({path: '/gaplist/' + this.gapid})
})
.catch(err => {
this.loginError = true
}
)
},
}
}
</script>
Updated answer:
created hook will not be called again. Using updated will result in an error as well, as you would trigger another update and have an endless loop.
Instead of pushing to same route I would suggest that you emit a completed event:
In your login method in then instead of $router.push:
this.$emit('completed')
And register the event on the gap-login-component:
<gap-login #completed="completed" :gapid=gapid></gap-login>
And add that method to the GapList.vue-file:
completed () {
this.loadCrops(this.gapid, this.lang)
}
You are using axios in a global context, but it doesn't exists, it seems.
Try using this.$axios:
this.$axios.get('/gapcroplist/' + gapid)