Vuejs & Auth0 : I need to reload page to be Authenticated - api

I'm a beginner in Vue, and I implemented Auth0 to my Web App using Vue3.
My issue: after logging in, my API call to retrieve data get an unauthorized error 403. If I reload the page, everything is working fine.
What should I do to avoid reloading the page to get authenticated directly?
Here are my scripts:
Main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'
import dayjs from 'dayjs'
import Datepicker from 'vue3-date-time-picker'
import 'vue3-date-time-picker/dist/main.css'
import { setupAuth } from './auth/index.js'
import authConfig from './auth/config.js'
function callbackRedirect(appState) {
router.push(appState && appState.targetUrl ? appState.targetUrl : '/' );
}
setupAuth(authConfig, callbackRedirect).then((auth) => {
let app = createApp(App).use(router);
app.config.globalProperties.$dayjs = dayjs;
app.component('Datepicker', Datepicker);
app.use(auth).mount('#app');
})
My App.vue script:
<template>
<div v-if="isAuthenticated">
<NavBar />
<router-view/>
</div>
</template>
<script>
import NavBar from './components/NavBar.vue'
export default {
components: { NavBar },
data(){
return {
isAuthenticated: false,
}
},
async mounted(){
await this.getAccessToken()
},
methods: {
async getAccessToken(){
try {
const accessToken = await this.$auth.getTokenSilently()
localStorage.setItem('accessToken', accessToken)
this.isAuthenticated = true
} catch (error) {
console.log('Error occured while trying to retrieve Access Token...', error)
}
},
},
}
</script>
and my Home.vue loading the data:
<template>
<div class="home">
<div class="py-10">
<header>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold leading-tight text-gray-900">Monitoring Dashboard</h1>
</div>
</header>
<main>
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<h3 class="m-5 text-lg leading-6 font-medium text-gray-900">Main KPIs</h3>
<div class="md:grid md:grid-cols-3 md:gap-6">
<div v-for="(item, index) in stats" :key="index" class="md:col-span-1">
<div class="bg-white p-5 border-gray-50 rounded-lg shadow-lg mb-5">
<span class="text-sm font-medium text-gray-500 truncate">{{ item.name }}</span>
<p class="mt-1 text-3xl font-bold text-gray-900">{{ parseFloat(item.stat.toFixed(2)) }}</p>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</template>
<script>
import _ from 'lodash'
import ProductsService from '../services/products.service'
export default {
name: 'Home',
data(){
return{
user: '',
products: '',
stats: '',
}
},
async mounted(){
await this.readProducts()
await this.buildStats()
},
methods: {
async readProducts(){
let temp = null
try {
temp = await ProductsService.readProducts()
this.products = temp.data
} catch (error) {
console.log('Error: cannot retrieve all products...')
}
},
async buildStats(){
//Nb products
const nbProducts = this.products.length
//Nb offers & Uniq NbRetailers
let nbOffers = 0
let retailers = []
for(let product of this.products){
for(let offer of product.offers){
retailers.push(offer.retailer)
nbOffers += 1
}
}
const nbRetailers = _.uniq(retailers).length
this.stats = [
{ name: 'Number of Retailers', stat: nbRetailers },
{ name: 'Number of Products', stat: nbProducts },
{ name: 'Number of Offers', stat: nbOffers },
]
},
},
watch: {
products: function(){
this.buildStats()
}
}
}
</script>
My ./auth/index.js file:
import createAuth0Client from '#auth0/auth0-spa-js'
import { computed, reactive, watchEffect } from 'vue'
let client
const state = reactive({
loading: true,
isAuthenticated: false,
user: {},
popupOpen: false,
error: null,
})
async function loginWithPopup() {
state.popupOpen = true
try {
await client.loginWithPopup(0)
} catch (e) {
console.error(e)
} finally {
state.popupOpen = false
}
state.user = await client.getUser()
state.isAuthenticated = true
}
async function handleRedirectCallback() {
state.loading = true
try {
await client.handleRedirectCallback()
state.user = await client.getUser()
state.isAuthenticated = true
} catch (e) {
state.error = e
} finally {
state.loading = false
}
}
function loginWithRedirect(o) {
return client.loginWithRedirect(o)
}
function getIdTokenClaims(o) {
return client.getIdTokenClaims(o)
}
function getTokenSilently(o) {
return client.getTokenSilently(o)
}
function getTokenWithPopup(o) {
return client.getTokenWithPopup(o)
}
function logout(o) {
return client.logout(o)
}
export const authPlugin = {
isAuthenticated: computed(() => state.isAuthenticated),
loading: computed(() => state.loading),
user: computed(() => state.user),
getIdTokenClaims,
getTokenSilently,
getTokenWithPopup,
handleRedirectCallback,
loginWithRedirect,
loginWithPopup,
logout,
}
export const routeGuard = (to, from, next) => {
const { isAuthenticated, loading, loginWithRedirect } = authPlugin
const verify = () => {
// If the user is authenticated, continue with the route
if (isAuthenticated.value) {
return next()
}
// Otherwise, log in
loginWithRedirect({ appState: { targetUrl: to.fullPath } })
}
// If loading has already finished, check our auth state using `fn()`
if (!loading.value) {
return verify()
}
// Watch for the loading property to change before we check isAuthenticated
watchEffect(() => {
if (loading.value === false) {
return verify()
}
})
}
export const setupAuth = async (options, callbackRedirect) => {
client = await createAuth0Client({
...options,
})
try {
// If the user is returning to the app after authentication
if (
window.location.search.includes('code=') &&
window.location.search.includes('state=')
) {
// handle the redirect and retrieve tokens
const { appState } = await client.handleRedirectCallback()
// Notify subscribers that the redirect callback has happened, passing the appState
// (useful for retrieving any pre-authentication state)
callbackRedirect(appState)
}
} catch (e) {
state.error = e
} finally {
// Initialize our internal authentication state
state.isAuthenticated = await client.isAuthenticated()
state.user = await client.getUser()
state.loading = false
}
return {
install: (app) => {
app.config.globalProperties.$auth = authPlugin
},
}
}

Related

Vue: Pinia state property doesn't update in component with node-forge

I read the other stackoverflow questions but does not help. I use pinia=2.0.27. I could extend the example if neccessary.
I have a component with a button with a spinner.
<template>
....
<button
type="submit"
class="btn btn-primary"
:disabled="loading ? true : false"
#click="submitForm"
>
<span
v-show="loading"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
<span v-show="loading"> Wait </span>
<span v-show="!loading">
Create certificate
</span>
</button>
....
</template>
<script setup>
import { storeToRefs } from "pinia";
import { useUserStore } from "#/store/UserStore";
const { loading } = storeToRefs(useUserStore());
</script>
<script>
export default {
async submitForm() {
try {
await useUserStore().createCertificate();
} catch (error) {
console.log(error);
}
},
};
</script>
This is the pinia store:
import { defineStore } from "pinia";
import forge from "node-forge";
export const useUserStore = defineStore({
id: "UserStore",
state: () => {
return {
loading: false,
};
},
actions: {
async createCertificate() {
this.loading = true;
try {
const keys = forge.pki.rsa.generateKeyPair(2048);
} catch (error) {
console.log(error);
} finally {
this.loading = false;
}
},
},
});
The problem is, that the doStuff function already runs and the loading property is still false inside the component and the spinner is very late visible.

Vue js: set notification count to zero

in my Vue Js code below, i created count for notification socket, so whenever a new notification received it count+ and appears beside the icon ... now i wanted to set back the count to zero when a user click on notification icon but i couldn't figure out how to do it.
below in app.vue i set a prop called number and i pass it to the sidebar to appear on all project pages , this number is the count of the notifications .. is there a way to set it back to zero after user click on the icon in the side bar?
<template>
<router-view :number="count" #send="getNewCount">
<sidebar :number="count" />
</router-view>
</template>
<script>
import sidebar from "#/views/Layout/DashboardLayout.vue";
import axios from "axios";
import {
io
} from "socket.io-client";
let socket = io("h***********/");
export default {
components: {
sidebar,
},
data() {
return {
user2: JSON.parse(sessionStorage.getItem("user")),
count: 0,
today: null,
};
},
props: {
number: {
type: Number,
default: 0,
},},
async created() {
console.log(this.count);
const response = await axios.get(
`https://l*********rs/api/${this.user2._id}/`, {
headers: {
Authorization: "Bearer " + sessionStorage.getItem("user"),
},
}
);
// await this.$store.dispatch("user", response.data.response);
socket.emit("user_connected", this.user2.username);
// console.log(this.user2,"userr")
socket.on("verify_connection", (data) => {
this.verify_connection = data;
console.log(data, "s")
});
socket.emit("user_connected", this.user2.username);
socket.on("verify_connection", (data) => {
console.log("heyy", data);
this.verify_connection = data;
});
socket.on("updated_flat", (data) => {
console.log("heyy", data);
this.makeToast(" success ", "'b-toaster-top-center");
});
socket.on("test", (data) => {
console.log("heyy", data);
// this.makeToast("success", "b-toaster-top-right");
});
;
},
methods: {
// playSound() {
// var audio = document.getElementById("audio");
// audio.play();
// },
getNewCount(data) {
this.count = data;
},
makeToast(variant = null, toaster, append = false) {
this.$bvToast.toast(" edited ", {
title: "BootstrapVue Toast",
variant: variant,
autoHideDelay: 10000,
toaster: toaster,
position: "top-right",
appendToast: append,
});
// this.playSound();
this.count = this.count + 1;
console.log(this.count,"count");
},
}
}
</script>
sidebar:
<template>
<div class="wrapper">
<side-bar >
<template slot="links">
<sidebar-item v-if="roles ==='Admin'"
:link="{
name: ' notifications',
path: '/notifications',
icon: 'ni ni-bell-55 text-green'
}">
</sidebar-item>
<p class="notifCount" v-if="roles ==='Admin'"> {{ number }} </p>
</template>
</side-bar>
<div class="main-content">
<dashboard-navbar :type="$route.meta.navbarType"></dashboard-navbar>
<div #click="$sidebar.displaySidebar(false)">
<fade-transition :duration="200" origin="center top" mode="out-in">
<!-- your content here -->
<router-view></router-view>
</fade-transition>
</div>
<content-footer v-if="!$route.meta.hideFooter"></content-footer>
</div>
</div>
</template>
<script>
/* eslint-disable no-new */
import PerfectScrollbar from 'perfect-scrollbar';
import 'perfect-scrollbar/css/perfect-scrollbar.css';
function hasElement(className) {
return document.getElementsByClassName(className).length > 0;
}
function initScrollbar(className) {
if (hasElement(className)) {
new PerfectScrollbar(`.${className}`);
} else {
// try to init it later in case this component is loaded async
setTimeout(() => {
initScrollbar(className);
}, 100);
}
}
import DashboardNavbar from './DashboardNavbar.vue';
import ContentFooter from './ContentFooter.vue';
import DashboardContent from './Content.vue';
import { FadeTransition } from 'vue2-transitions';
export default {
components: {
DashboardNavbar,
ContentFooter,
DashboardContent,
FadeTransition
},
props: {
number: {
type: Number,
default: 0,
},
},
methods: {
initScrollbar() {
let isWindows = navigator.platform.startsWith('Win');
if (isWindows) {
initScrollbar('sidenav');
}
},
},
computed: {
roles() {
let roles = JSON.parse(sessionStorage.getItem('user')).role;
return roles;
},},
mounted() {
this.initScrollbar()
}
};
</script>
Emit an event from sidebar and handle the event in the main app.
main app:
<template>
<!-- ... -->
<sidebar :number="count" #reset="onReset" />
<!-- ... -->
</template>
<script>
export default {
// ...
methods: {
onReset() {
// api calls, etc.
this.count = 0;
}
}
}
</script>
sidebar:
<template>
<!-- ... -->
<button #click="$emit('reset')">Reset notification count</button>
<!-- ... -->
</template>

Migrating "detect click outside" custom directive from Vue 2 to Vue 3

Based on this question Detect click outside element and this answer https://stackoverflow.com/a/42389266, I'm trying to migrate the directive from Vue 2 to Vue 3. It seems that binding.expression and vnode.context not exists more. How can I make it work?
app.directive('click-outside', {
beforeMount (el, binding, vnode) {
el.clickOutsideEvent = function (event) {
if (!(el === event.target || el.contains(event.target))) {
vnode.context[binding.expression](event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent);
},
unmounted (el) {
document.body.removeEventListener('click', el.clickOutsideEvent);
}
});
You can use binding.value instead like this:
const { createApp } = Vue;
const highlightEl = (color ) => (event, el) => {
if (el) {
el.style.background = color;
} else {
event.target.style.background = color;
}
}
const clearHighlightEl = (event, el) => {
if (el) {
el.style.background = '';
} else {
event.target.style.background = '';
}
}
const app = Vue.createApp({
setup() {
return {
highlightEl,
clearHighlightEl
}
}
})
app.directive('click-outside', {
mounted(el, binding, vnode) {
el.clickOutsideEvent = function(event) {
if (!(el === event.target || el.contains(event.target))) {
binding.value(event, el);
}
};
document.body.addEventListener('click', el.clickOutsideEvent);
},
unmounted(el) {
document.body.removeEventListener('click', el.clickOutsideEvent);
}
});
app.mount('#app')
<script src="https://unpkg.com/vue#3.0.0-rc.11/dist/vue.global.prod.js"></script>
<div id="app">
<h1 v-click-outside="highlightEl('yellow')" #click="clearHighlightEl">Element 1</h1>
<p v-click-outside="highlightEl('#FFCC77')" #click="clearHighlightEl">Element 2</p>
</div>
out of the context, there's an easier way in vue3 with composition.
Link to Vueuse ClickOutside (Vue 3)
Link to Vueuse ClickOutside(Vue 2)
<template>
<div ref="target">
Hello world
</div>
<div>
Outside element
</div>
</template>
<script>
import { ref } from 'vue'
import { onClickOutside } from '#vueuse/core'
export default {
setup() {
const target = ref(null)
onClickOutside(target, (event) => console.log(event))
return { target }
}
}
</script>
you can use ref to find out if the element contains the element clicked
<template>
<div ref="myref">
Hello world
</div>
<div>
Outside element
</div>
</template>
<script>
export default {
data() {
return {
show=false
}
},
mounted(){
let self = this;
document.addEventListener('click', (e)=> {
if (self.$refs.myref !==undefined && self.$refs.myref.contains(e.target)===false) {
//click outside!
self.show = false;
}
})
}
}
</script>
vue2 solution:
<script>
export default {
name: 'onClickOutside',
props: ['clickOutside'],
mounted() {
const listener = e => {
if (e.target === this.$el || this.$el.contains(e.target)) {
return
}
this.clickOutside()
}
document.addEventListener('click', listener)
this.$once('hook:beforeDestroy', () => document.removeEventListener('click', listener))
},
render() {
return this.$slots.default[0]
},
}
</script>
vue3:
<script>
import { getCurrentInstance, onMounted, onBeforeUnmount, ref, defineComponent } from 'vue'
export default defineComponent({
name: 'OnClickOutside',
props: ['clickOutside'],
setup(props, { emit, attrs, slots }) {
const vm = getCurrentInstance()
const listener = event => {
const isClickInside = vm.subTree.children.some(element => {
const el = element.el
return event.target === el || el.contains(event.target)
})
if (isClickInside) {
console.log('clickInside')
return
}
props.clickOutside && props.clickOutside()
}
onMounted(() => {
document.addEventListener('click', listener)
})
onBeforeUnmount(() => {
document.removeEventListener('click', listener)
})
return () => slots.default()
},
})
</script>

vue.js Data Pre-Fetching Problems

I'm building an app following guide https://ssr.vuejs.org/en/data.html.
So i have structure:
server.js
const express = require('express');
const server = express();
const fs = require('fs');
const path = require('path');
const bundle = require('./dist/server.bundle.js');
const renderer = require('vue-server-renderer').createRenderer({
template: fs.readFileSync('./index.html', 'utf-8')
});
server.get('*', (req, res) => {
bundle.default({url: req.url}).then((app) => {
const context = {
title: app.$options.router.history.current.meta.title
};
renderer.renderToString(app, context, function (err, html) {
console.log(html)
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found')
} else {
res.status(500).end('Internal Server Error')
}
} else if (context.title === '404') {
res.status(404).end(html)
} else {
res.end(html)
}
});
}, (err) => {
res.status(404).end('Page not found')
});
});
server.listen(8080);
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
import axios from 'axios';
export function createStore() {
return new Vuex.Store({
state: {
articles: [
]
},
actions: {
fetchArticlesList({commit}, params) {
return axios({
method: 'post',
url: 'http://test.local/api/get-articles',
data: {
start: params.start,
limit: params.limit,
language: params.language
}
})
.then((res) => {
commit('setArticles', res.data.articles);
});
},
},
mutations: {
setArticles(state, articles) {
state.articles = articles;
}
}
})
}
router.js
import BlogEn from '../components/pages/BlogEn.vue';
import Vue from 'vue';
import Router from 'vue-router';
export function createRouter() {
return new Router({
mode: 'history',
routes: [
{
path: '/en/blog',
name: 'blogEn',
component: BlogEn,
meta: {
title: 'Blog',
language: 'en'
}
},
});
}
main.js
import Vue from 'vue'
import App from './App.vue'
import {createRouter} from './router/router.js'
import {createStore} from './store/store.js'
import {sync} from 'vuex-router-sync'
export function createApp() {
const router = createRouter();
const store = createStore();
sync(store, router);
const app = new Vue({
router,
store,
render: h => h(App)
});
return {app, router, store};
}
entry-server.js
import {createApp} from './main.js';
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
router.push(context.url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
Promise.all(matchedComponents.map(Component => {
// This code not from manual because i want load this in my content-component
if (Component.components['content-component'].asyncData) {
return Component.components['content-component'].asyncData({
store,
route: router.currentRoute
})
}
// This code from manual
// if (Component.asyncData) {
// return Component.asyncData({
// store,
// route: router.currentRoute
// })
// }
})).then(() => {
context.state = store.state
resolve(app)
}).catch(reject)
}, reject)
})
}
entry-client.js
import Vue from 'vue'
import {createApp} from './main.js';
const {app, router, store} = createApp();
if (window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__)
}
router.onReady(() => {
router.beforeResolve((to, from, next) => {
const matched = router.getMatchedComponents(to)
const prevMatched = router.getMatchedComponents(from)
let diffed = false
const activated = matched.filter((c, i) => {
return diffed || (diffed = (prevMatched[i] !== c))
})
if (!activated.length) {
return next()
}
Promise.all(activated.map(c => {
if (c.asyncData) {
return c.asyncData({ store, route: to })
}
})).then(() => {
next()
}).catch(next)
})
app.$mount('#app')
});
Components
BlogEn.vue
<template>
<div>
<header-component></header-component>
<div class="content" id="content">
<content-component></content-component>
<div class="buffer"></div>
</div>
<footer-component></footer-component>
</div>
</template>
<script>
import Header from '../blanks/Header.vue';
import Content from '../pages/content/blog/Content.vue';
import Footer from '../blanks/Footer.vue';
export default {
data() {
return {
};
},
components: {
'header-component': Header,
'breadcrumbs-component' : Breadcrumbs,
'content-component' : Content,
'footer-component': Footer
},
};
</script>
Content.vue
<template>
<section class="blog">
<div v-for="item in articles">
<p>{{ item.title }}</p>
</div>
</section>
</template>
<script>
export default {
data() {
let obj = {
};
return obj;
},
asyncData({store, route}) {
let params = {
start: 0,
limit: 2,
language: 'ru'
};
return store.dispatch('fetchArticlesList', params);
},
computed: {
articles () {
return this.$store.state.articles;
}
}
};
</script>
When i load page /en/blog
My DOM in browser looks like
<div id="app">
<div id="content" class="content">
<!-- There is should be loop content -->
<div class="buffer"></div>
</div>
<footer></footer>
</div>
But! When i look at source code page and html that server sends to me its OK.
<div id="app">
<div id="content" class="content">
<section class="blog">
<div><p>Article Title</p></div>
<div><p>Article Title 2</p></div>
</section>
<div class="buffer"></div>
</div>
<footer></footer>
</div>
Thats not all. I have other pages in my app that i dont show here. When i move at any page and go to "/en/blog" after that DOM is ok.
What's wrong here?

navigation gaurd not working properly

I store the log in status of the user in my store.js (using vuex for state management)
When the user is logged in the login status is set to true in store.js
I check if the user is logged in and using v-if i hide the login button . Till he everything works fine
Now for checking purpose i removed the v-if condition on login button
I set up á before enter navigation guard in my !ogin.vue component as below
login.vue
beforeRouteEnter(to, from, next){
next(vm => {
if(vm.$store.getters.g_loginStatus === true){
next('/');
}else{
next();
}
})
}
If the user is logged in and presses the login button he is redirected to the home page
This works fine as the navigation guard is set up.
but the problem arises when i directly type in the login component url (localhost:8080/login) in the search.
The login component gets loaded normally without getting redirected to home page...
Why does this happen¿ Am i doing something wrong
I enen tried another approach using route meta fields following the documentation at route meta fields
But same problem
when i type the direct url to login component in search not getting redirected
import Vue from 'vue'
import Vuex from 'vuex'
import * as firebase from 'firebase'
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
loggedIn: false,
userName: 'Guest',
error: {
is: false,
errorMessage: ''
},
toast: {
is: false,
toastMessage: ''
}
},
getters: {
g_loginStatus: state => {
return state.loggedIn;
},
g_userName: state => {
return state.userName;
},
g_error: state => {
return state.error;
},
g_toast: (state) => {
return state.toast;
}
},
mutations: {
m_logInUser: (state) => {
state.loggedIn = true;
},
m_loggedOut: (state) => {
state.loggedIn = false;
}
},
actions: {
a_logInUser: ({state, dispatch}, user) => {
return new Promise((resolve, reject) => {
firebase.auth().signInWithEmailAndPassword(user.e, user.p).then(
() =>{
resolve(dispatch('a_authStateObserver'));
}, error => {
state.error.is = true;
let errorCode = error.code;
let errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
state.error.errorMessage = 'Wrong password.';
} else {
state.errorMessage = errorMessage;
}
}
);
});
},
a_loggedOut: () => {
firebase.auth().signOut().then(() => {
dispatch('a_authStateObserver');
});
},
a_signUpUser: ({state, dispatch}, user) => {
return new Promise((resolve, reject) => {
firebase.auth().createUserWithEmailAndPassword(user.e, user.p).then(
(u) =>{
let uid = u.uid;
resolve(dispatch('a_authStateObserver'));
}, error => {
state.error.is = true;
let errorCode = error.code;
let errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
state.error.errorMessage = 'Wrong password.';
} else {
state.errorMessage = errorMessage;
}
}
);
});
},
a_authStateObserver: ({commit, state}) => {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var displayName = user.displayName;
state.userName = user.email;
state.error.is = false;
commit('m_logInUser');
} else {
// User is signed out.
commit('m_loggedOut');
}
});
}
}
});
login.vue
<template>
<div class="container">
<div class="row">
<div class="form_bg center-block">
<form #submit.prevent="loginUser">
<h3 class="text-center">Log in</h3>
<br/>
<div class="form-group">
<input v-model="email" type="email" class="form-control" placeholder="Your Email">
</div>
<div class="form-group">
<input v-model="password" type="password" class="form-control" placeholder="Password">
</div>
<div class="align-center">
<p class="error" v-if="g_error.is">{{ g_error.errorMessage }}</p>
<button type="submit" class="btn btn-success center-block">Log in</button>
</div>
</form>
<br>
<p style="display:inline-block">Don't have an account?</p>
<router-link to="/signup" tag="a" style="display:inline-block">Sign up</router-link>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default{
data(){
return{
email: '',
password: ''
};
},
methods: {
loginUser(){
this.$store.dispatch('a_logInUser', {e: this.email, p: this.password}).then(() =>{
this.$router.replace('/statuses');
});
}
},
computed: {
...mapGetters([
'g_error'
])
},
beforeRouteEnter(to, from, next){
next(vm => {
console.log(vm.$store.getters.g_loginStatus);
if(vm.$store.getters.g_loginStatus === true){
next('/');
}else{
next();
}
})
}
}
**routs.js**
import Home from './components/Home.vue'
import Users from './components/user/Users.vue'
import Statuses from './components/user/Statuses.vue'
import Post from './components/Post.vue'
import UserStatus from './components/user/UserStatus.vue'
import Signup from './components/auth/Signup.vue'
import Login from './components/auth/Login.vue'
export const routes = [
{path: '/', component: Home, name:'home'},
{path: '/users', component: Users, name:'users'},
{path: '/statuses', component: Statuses, name:'statuses'},
{path: '/current', component: UserStatus, name:'currentUser'},
{path: '/signup', component: Signup, name:'signup'},
{path: '/login', component: Login, name:'login'},
{path: '/post', component: Post}
];