0
0
Fork 0

Added axios interceptor

This commit is contained in:
Joan Sanchez 2022-03-01 15:19:42 +01:00
parent 4edb7de3ad
commit f423cc2a1d
9 changed files with 300 additions and 8 deletions

View File

@ -7,3 +7,20 @@ import quasarUserOptions from './quasar-user-options';
import i18n from './i18n';
createApp(App).use(i18n).use(Quasar, quasarUserOptions).use(store).use(router).mount('#app');
import axios from 'axios';
axios.interceptors.request.use(
function (config) {
const token = localStorage.getItem('token');
if (token && config.headers) {
config.headers.Authorization = token;
}
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);

View File

@ -2,14 +2,31 @@ import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
const routes: Array<RouteRecordRaw> = [
{
path: '/',
path: '/login',
name: 'Login',
component: () => import('../views/Login/Login.vue'),
},
{
path: '/dashboard',
path: '/',
name: 'Main',
component: () => import('../views/Main/Main.vue'),
children: [
{
path: '',
name: 'Dashboard',
component: () => import('../views/Dashboard/Dashboard.vue'),
component: () => import('../views/Main/Dashboard.vue'),
},
/* {
path: '/Client',
name: 'Client',
component: () => import('../views/Client/client.vue'),
}, */
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('../views/Main/NotFound.vue'),
},
],
},
];
@ -18,4 +35,14 @@ const router = createRouter({
routes,
});
router.beforeEach((to, from, next) => {
const loggedIn = localStorage.getItem('token');
if (to.name !== 'Login' && !loggedIn) {
next({ path: '/login', query: { redirect: to.fullPath } });
} else {
next();
}
});
export default router;

7
src/shims-vuex.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import { Store } from '@/store'; // path to store file
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$store: Store;
}
}

View File

@ -1,8 +1,38 @@
import { createStore } from 'vuex';
export default createStore({
state: {},
mutations: {},
actions: {},
state: {
user: null,
roles: [],
},
mutations: {
setUser(state, user) {
state.user = user;
},
setRoles(state, roles) {
state.roles = roles;
},
},
actions: {
logIn({ commit }, auth) {
localStorage.setItem('token', auth.token);
commit('setUser', auth);
},
logOut({ commit }) {
localStorage.removeItem('token');
commit('setUser', null);
},
updateUserData({ commit }, data) {
commit('setUser', data.user);
commit('setRoles', data.roles);
},
},
getters: {
hasData(state) {
return !!state.user;
},
},
modules: {},
});

View File

@ -6,6 +6,7 @@ $secondary : #26A69A;
$accent : #9C27B0;
$dark : #1D1D1D;
$darker : #111111;
$positive : #21BA45;
$negative : #C10015;

View File

@ -100,7 +100,11 @@ export default class Login extends Vue {
user: this.username,
password: this.password,
})
.then(() => {
.then((response) => {
this.$store.dispatch('logIn', {
token: response.data.token,
});
this.$q.notify({
message: this.$t('login.loginSuccess'),
type: 'positive',

194
src/views/Main/Main.vue Normal file
View File

@ -0,0 +1,194 @@
<template>
<q-layout>
<q-header class="bg-darker" color="white" elevated>
<q-toolbar>
<q-btn flat round dense icon="menu" />
<q-toolbar-title>Salix</q-toolbar-title>
<q-space></q-space>
<q-btn dense flat no-wrap>
<q-avatar size="lg" color="orange">
<img :src="`/api/Images/user/160x160/${id}/download?access_token=${token}`" alt="" />
</q-avatar>
<q-tooltip>Account</q-tooltip>
<q-icon name="arrow_drop_down" size="s" />
<q-menu>
<div class="row no-wrap q-pa-md">
<div class="column">
<div class="text-h6 q-mb-md">Settings</div>
<q-toggle label="Dark mode" />
<q-toggle label="Language" class="q-mb-md" />
<q-btn color="orange" outline size="sm" label="Settings" icon="settings" />
</div>
<q-separator vertical inset class="q-mx-lg" />
<div class="column items-center" style="min-width: 150px">
<q-avatar color="orange" size="80px">
<img
:src="`/api/Images/user/160x160/${id}/download?access_token=${token}`"
alt=""
/>
</q-avatar>
<div class="text-subtitle1 q-mt-md">
<strong>{{ nickname }}</strong>
</div>
<div class="text-subtitle3 text-grey-7 q-mb-xs">@{{ nickname }}</div>
<q-btn
color="orange"
flat
label="Log Out"
size="sm"
icon="logout"
@click="logout()"
v-close-popup
/>
</div>
</div>
</q-menu>
<!-- <q-menu auto-close>
<q-list dense>
<q-item>
<q-item-section>
<div>
<strong>{{ nickname }}</strong>
</div>
</q-item-section>
</q-item>
<q-separator />
<q-item clickable>
<q-item-section>Your profile</q-item-section>
</q-item>
<q-separator />
<q-item clickable>
<q-item-section>Settings</q-item-section>
</q-item>
<q-item clickable @click="logout()">
<q-item-section>Sign out</q-item-section>
</q-item>
</q-list>
</q-menu> -->
</q-btn>
<!-- <q-toggle
:label="$t(`globals.lang['${language}']`)"
icon="public"
color="orange"
false-value="es"
true-value="en"
v-model="language"
/>
<q-toggle v-model="mode" checked-icon="dark_mode" color="orange" unchecked-icon="light_mode" /> -->
</q-toolbar>
</q-header>
<q-drawer show-if-above :mini="true" mini-to-overlay :width="200" :breakpoint="500">
<q-scroll-area class="fit">
<q-list padding>
<q-item active clickable v-ripple>
<q-item-section avatar>
<q-icon name="dashboard" />
</q-item-section>
<q-item-section> Dashboard </q-item-section>
</q-item>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="people" />
</q-item-section>
<q-item-section> Customers </q-item-section>
</q-item>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="receipt" />
</q-item-section>
<q-item-section> Invoice Out </q-item-section>
</q-item>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="shopping_cart" />
</q-item-section>
<q-item-section> Catalog </q-item-section>
</q-item>
<q-separator />
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="drafts" />
</q-item-section>
<q-item-section> Drafts </q-item-section>
</q-item>
</q-list>
</q-scroll-area>
</q-drawer>
<q-page-container>
<router-view></router-view>
</q-page-container>
</q-layout>
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component';
import axios from 'axios';
@Options({})
export default class Main extends Vue {
mounted(): void {
axios.get('/api/accounts/acl').then((response) => {
this.$store.dispatch('updateUserData', response.data);
});
}
logout(): void {
this.$store.dispatch('logOut');
this.$router.push('/login');
}
get nickLetter(): string {
if (this.nickname) {
return this.nickname.charAt(0);
}
return '';
}
get nickname(): string {
if (this.$store.getters.hasData) {
return this.$store.state.user.nickname;
}
return '';
}
get id(): string {
if (this.$store.getters.hasData) {
return this.$store.state.user.id;
}
return '';
}
get token(): string {
const token = localStorage.getItem('token');
return token ? token : '';
}
}
</script>
<style lang="scss" scoped>
.bg-darker {
background-color: $darker;
}
</style>

View File

@ -0,0 +1,12 @@
<template>
<q-page> Page not found </q-page>
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component';
@Options({})
export default class NotFound extends Vue {}
</script>
<style lang="scss" scoped></style>