Header & userPanel componentization
This commit is contained in:
parent
44b823e376
commit
fade50dd2a
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<q-header class="bg-darker" color="white" elevated>
|
<q-header class="bg-darker" color="white" elevated>
|
||||||
<q-toolbar class="q-py-sm q-px-md">
|
<q-toolbar class="q-py-sm q-px-md">
|
||||||
<q-btn flat @click="drawer = !drawer" round dense icon="menu" />
|
<q-btn flat @click="$emit('on-toggle-drawer')" round dense icon="menu" />
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<q-btn flat round class="q-ml-xs" v-if="$q.screen.gt.xs">
|
<q-btn flat round class="q-ml-xs" v-if="$q.screen.gt.xs">
|
||||||
<q-avatar square size="md"><img src="@/assets/logo_icon.svg" alt="Logo" /></q-avatar>
|
<q-avatar square size="md"><img src="@/assets/logo_icon.svg" alt="Logo" /></q-avatar>
|
||||||
|
@ -9,74 +9,40 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
<q-toolbar-title shrink class="text-weight-bold"> Salix </q-toolbar-title>
|
<q-toolbar-title shrink class="text-weight-bold"> Salix </q-toolbar-title>
|
||||||
<q-space></q-space>
|
<q-space></q-space>
|
||||||
<q-btn dense flat no-wrap>
|
<div class="q-pl-sm q-gutter-sm row items-center no-wrap">
|
||||||
<q-avatar size="lg">
|
<q-btn v-if="$q.screen.gt.xs" dense flat size="md" icon="add">
|
||||||
<q-img
|
<q-icon name="arrow_drop_down" size="s" />
|
||||||
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`"
|
<q-menu>
|
||||||
spinner-color="white"
|
<q-list style="min-width: 150px">
|
||||||
/>
|
<q-item clickable>
|
||||||
</q-avatar>
|
<q-item-section>New customer</q-item-section>
|
||||||
<q-tooltip>Account</q-tooltip>
|
</q-item>
|
||||||
<q-icon name="arrow_drop_down" size="s" />
|
<q-item clickable>
|
||||||
|
<q-item-section>New ticket</q-item-section>
|
||||||
<q-menu>
|
</q-item>
|
||||||
<div class="row no-wrap q-pa-md">
|
</q-list>
|
||||||
<div class="column">
|
</q-menu>
|
||||||
<div class="text-h6 q-mb-md">Settings</div>
|
</q-btn>
|
||||||
<q-toggle
|
<q-btn v-if="$q.screen.gt.xs" dense flat round size="md" icon="notifications" />
|
||||||
:label="$t(`globals.lang['${language}']`)"
|
<q-btn dense flat no-wrap>
|
||||||
icon="public"
|
<q-avatar size="lg">
|
||||||
color="orange"
|
<q-img
|
||||||
false-value="es"
|
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`"
|
||||||
true-value="en"
|
spinner-color="white"
|
||||||
v-model="language"
|
/>
|
||||||
/>
|
</q-avatar>
|
||||||
<q-toggle
|
<q-tooltip>Account</q-tooltip>
|
||||||
v-model="mode"
|
<q-icon name="arrow_drop_down" size="s" />
|
||||||
checked-icon="dark_mode"
|
<UserPanel />
|
||||||
color="orange"
|
</q-btn>
|
||||||
unchecked-icon="light_mode"
|
</div>
|
||||||
/>
|
|
||||||
|
|
||||||
<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 size="80px">
|
|
||||||
<q-img
|
|
||||||
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`"
|
|
||||||
spinner-color="white"
|
|
||||||
/>
|
|
||||||
</q-avatar>
|
|
||||||
|
|
||||||
<div class="text-subtitle1 q-mt-md">
|
|
||||||
<strong>{{ user.nickname }}</strong>
|
|
||||||
</div>
|
|
||||||
<div class="text-subtitle3 text-grey-7 q-mb-xs">@{{ user.username }}</div>
|
|
||||||
|
|
||||||
<q-btn
|
|
||||||
color="orange"
|
|
||||||
flat
|
|
||||||
label="Log Out"
|
|
||||||
size="sm"
|
|
||||||
icon="logout"
|
|
||||||
@click="logout()"
|
|
||||||
v-close-popup
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-menu>
|
|
||||||
</q-btn>
|
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-header>
|
</q-header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Options, Vue } from 'vue-class-component';
|
import { Options, Vue } from 'vue-class-component';
|
||||||
import axios from 'axios';
|
import UserPanel from '@/components/UserPanel.vue';
|
||||||
import { Dark } from 'quasar';
|
|
||||||
|
|
||||||
interface UserProfile {
|
interface UserProfile {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -86,38 +52,11 @@ interface UserProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Options({
|
@Options({
|
||||||
props: {
|
components: {
|
||||||
drawer: {
|
UserPanel,
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class Topbar extends Vue {
|
export default class Topbar extends Vue {
|
||||||
drawer?: boolean;
|
|
||||||
private lang = 'es';
|
|
||||||
|
|
||||||
mounted(): void {
|
|
||||||
axios
|
|
||||||
.get('/api/accounts/acl')
|
|
||||||
.then((response) => {
|
|
||||||
this.$store.dispatch('updateUserData', response.data);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.$q.notify({
|
|
||||||
message: this.$t('globals.accessDenied'),
|
|
||||||
type: 'negative',
|
|
||||||
});
|
|
||||||
this.$store.dispatch('logOut');
|
|
||||||
this.$router.push('/login');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
logout(): void {
|
|
||||||
this.$store.dispatch('logOut');
|
|
||||||
this.$router.push('/login');
|
|
||||||
}
|
|
||||||
|
|
||||||
get user(): UserProfile {
|
get user(): UserProfile {
|
||||||
return this.$store.state.user;
|
return this.$store.state.user;
|
||||||
}
|
}
|
||||||
|
@ -125,22 +64,5 @@ export default class Topbar extends Vue {
|
||||||
get token(): string {
|
get token(): string {
|
||||||
return this.$store.getters.token;
|
return this.$store.getters.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
get mode(): boolean {
|
|
||||||
return Dark.isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
set mode(value: boolean) {
|
|
||||||
Dark.set(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
get language(): string {
|
|
||||||
return this.lang;
|
|
||||||
}
|
|
||||||
|
|
||||||
set language(value: string) {
|
|
||||||
this.lang = value;
|
|
||||||
this.$i18n.locale = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
<template>
|
||||||
|
<q-menu>
|
||||||
|
<div class="row no-wrap q-pa-md">
|
||||||
|
<div class="column">
|
||||||
|
<div class="text-h6 q-mb-md">{{ $t('components.userPanel.settings') }}</div>
|
||||||
|
<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-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 size="80px">
|
||||||
|
<q-img
|
||||||
|
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`"
|
||||||
|
spinner-color="white"
|
||||||
|
/>
|
||||||
|
</q-avatar>
|
||||||
|
|
||||||
|
<div class="text-subtitle1 q-mt-md">
|
||||||
|
<strong>{{ user.nickname }}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="text-subtitle3 text-grey-7 q-mb-xs">@{{ user.username }}</div>
|
||||||
|
|
||||||
|
<q-btn color="orange" flat label="Log Out" size="sm" icon="logout" @click="logout()" v-close-popup />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Options, Vue } from 'vue-class-component';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { Dark } from 'quasar';
|
||||||
|
|
||||||
|
interface UserProfile {
|
||||||
|
id: number;
|
||||||
|
username: string;
|
||||||
|
nickname: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Options({})
|
||||||
|
export default class UserPanel extends Vue {
|
||||||
|
private lang = 'es';
|
||||||
|
|
||||||
|
mounted(): void {
|
||||||
|
axios
|
||||||
|
.get('/api/accounts/acl')
|
||||||
|
.then((response) => {
|
||||||
|
this.$store.dispatch('updateUserData', response.data);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$q.notify({
|
||||||
|
message: this.$t('errors.statusUnauthorized'),
|
||||||
|
type: 'negative',
|
||||||
|
});
|
||||||
|
this.$store.dispatch('logOut');
|
||||||
|
this.$router.push('/login');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
logout(): void {
|
||||||
|
this.$store.dispatch('logOut');
|
||||||
|
this.$router.push('/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
get user(): UserProfile {
|
||||||
|
return this.$store.state.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
get token(): string {
|
||||||
|
return this.$store.getters.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
get mode(): boolean {
|
||||||
|
return Dark.isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
set mode(value: boolean) {
|
||||||
|
Dark.set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
get language(): string {
|
||||||
|
return this.lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
set language(value: string) {
|
||||||
|
this.lang = value;
|
||||||
|
this.$i18n.locale = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,5 @@
|
||||||
|
import toLowerCase from './toLowerCase';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
toLowerCase,
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function toLowerCase(value: string): string {
|
||||||
|
return value.toLowerCase();
|
||||||
|
}
|
|
@ -5,6 +5,10 @@
|
||||||
"en": "English"
|
"en": "English"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"errors": {
|
||||||
|
"statusUnauthorized": "Access denied",
|
||||||
|
"statusInternalServerError": "An internal server error has ocurred"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Login",
|
"title": "Login",
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
|
@ -16,7 +20,10 @@
|
||||||
},
|
},
|
||||||
"customer": {},
|
"customer": {},
|
||||||
"components": {
|
"components": {
|
||||||
"dialog": {},
|
"topbar": {},
|
||||||
"calendar": {}
|
"userPanel": {
|
||||||
|
"settings": "Settings",
|
||||||
|
"logOut": "Log Out"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,9 +3,11 @@
|
||||||
"lang": {
|
"lang": {
|
||||||
"es": "Español",
|
"es": "Español",
|
||||||
"en": "Inglés"
|
"en": "Inglés"
|
||||||
},
|
}
|
||||||
"accessDenied": "Acceso denegado",
|
},
|
||||||
"internalServerError": "Ha ocurrido un error interno del servidor"
|
"errors": {
|
||||||
|
"statusUnauthorized": "Acceso denegado",
|
||||||
|
"statusInternalServerError": "Ha ocurrido un error interno del servidor"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Iniciar sesión",
|
"title": "Iniciar sesión",
|
||||||
|
@ -18,7 +20,10 @@
|
||||||
},
|
},
|
||||||
"customer": {},
|
"customer": {},
|
||||||
"components": {
|
"components": {
|
||||||
"dialog": {},
|
"topbar": {},
|
||||||
"calendar": {}
|
"userPanel": {
|
||||||
|
"settings": "Configuración",
|
||||||
|
"logOut": "Cerrar sesión"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,8 +5,13 @@ import store from './store';
|
||||||
import { Quasar } from 'quasar';
|
import { Quasar } from 'quasar';
|
||||||
import quasarUserOptions from './quasar-user-options';
|
import quasarUserOptions from './quasar-user-options';
|
||||||
import i18n from './i18n';
|
import i18n from './i18n';
|
||||||
|
import filters from './core/filters';
|
||||||
|
|
||||||
createApp(App).use(i18n).use(Quasar, quasarUserOptions).use(store).use(router).mount('#app');
|
const app = createApp(App).use(i18n).use(Quasar, quasarUserOptions).use(store).use(router);
|
||||||
|
|
||||||
|
app.config.globalProperties.$filters = filters;
|
||||||
|
|
||||||
|
app.mount('#app');
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
axios.interceptors.request.use(
|
axios.interceptors.request.use(
|
||||||
|
|
|
@ -10,22 +10,23 @@ const routes: Array<RouteRecordRaw> = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Main',
|
name: 'Main',
|
||||||
component: () => import('../views/Main/Main.vue'),
|
component: () => import('../views/Layout/Main.vue'),
|
||||||
|
redirect: { name: 'Dashboard' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
component: () => import('../views/Main/Dashboard.vue'),
|
component: () => import('../views/Dashboard/Dashboard.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/customer',
|
path: '/customer',
|
||||||
name: 'Customer',
|
name: 'Customer',
|
||||||
component: () => import('../views/Customer/Main.vue'),
|
component: () => import('../views/Customer/Customer.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:pathMatch(.*)*',
|
path: '/:pathMatch(.*)*',
|
||||||
name: 'NotFound',
|
name: 'NotFound',
|
||||||
component: () => import('../views/Main/NotFound.vue'),
|
component: () => import('../views/Layout/NotFound.vue'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,5 +3,6 @@ import { Store } from '@/store'; // path to store file
|
||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
$store: Store;
|
$store: Store;
|
||||||
|
$filters: Record<string, T>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<q-layout>
|
<q-page class="q-pa-md">
|
||||||
<q-page class="q-pa-md">
|
<q-card class="q-pa-md"> Customer page.. </q-card>
|
||||||
<q-card class="q-pa-md"> Dashboard page.. </q-card>
|
</q-page>
|
||||||
</q-page>
|
|
||||||
</q-layout>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<q-page class="q-pa-md">
|
||||||
|
<q-card class="q-pa-md">
|
||||||
|
Dashboard page..
|
||||||
|
{{ $filters.toLowerCase('HELLO WORLD') }}
|
||||||
|
</q-card>
|
||||||
|
</q-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Options, Vue } from 'vue-class-component';
|
||||||
|
|
||||||
|
@Options({})
|
||||||
|
export default class Dashboard extends Vue {
|
||||||
|
get whatever(): string {
|
||||||
|
return this.$filters.toLowerCase('HELLO WORLD');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<q-layout>
|
<q-layout view="hHh lpR fFf">
|
||||||
<Topbar :drawer="drawer" />
|
<Topbar @on-toggle-drawer="onToggleDrawer()" />
|
||||||
<q-drawer
|
<q-drawer
|
||||||
v-model="drawer"
|
v-model="drawer"
|
||||||
show-if-above
|
show-if-above
|
||||||
|
@ -71,6 +71,10 @@ import Topbar from '@/components/Topbar.vue';
|
||||||
export default class Main extends Vue {
|
export default class Main extends Vue {
|
||||||
drawer = false;
|
drawer = false;
|
||||||
miniState = true;
|
miniState = true;
|
||||||
|
|
||||||
|
onToggleDrawer(): void {
|
||||||
|
this.drawer = !this.drawer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -111,7 +111,7 @@ export default class Login extends Vue {
|
||||||
message: this.$t('login.loginSuccess'),
|
message: this.$t('login.loginSuccess'),
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
});
|
});
|
||||||
this.$router.push('/');
|
this.$router.push('/dashboard');
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorCode = error.response.status;
|
const errorCode = error.response.status;
|
||||||
|
@ -122,7 +122,7 @@ export default class Login extends Vue {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.$q.notify({
|
this.$q.notify({
|
||||||
message: this.$t('globals.internalServerError'),
|
message: this.$t('errors.statusInternalServerError'),
|
||||||
type: 'negative',
|
type: 'negative',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<template>
|
|
||||||
<q-layout>
|
|
||||||
<q-page class="q-pa-md">
|
|
||||||
<q-card class="q-pa-md"> Dashboard page.. </q-card>
|
|
||||||
</q-page>
|
|
||||||
</q-layout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { Options, Vue } from 'vue-class-component';
|
|
||||||
|
|
||||||
@Options({})
|
|
||||||
export default class Dashboard extends Vue {}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
Loading…
Reference in New Issue