Refactor dashboard and UI components; add theming system
Introduce a centralized theming configuration via `ThemeConfig.vue`. Refactor various dashboard components for consistency and modularity, including new wrappers (`DepartmentDashboardPageWrapper`, `WhiteBox`, `ButtonsBox`). Enhance user context with `UserNavigationTop` and improve menu structure with reusable menus (`AdminLeftMenu`, `MenuDefault`). Update button and UI element styles using dynamic theming.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<script>
|
||||
import { ref } from "vue";
|
||||
|
||||
export const GlobalColors = {
|
||||
/** The primary color of the application */
|
||||
primaryColor: "#0064ff",
|
||||
/** The secondary color of the application */
|
||||
secondaryColor: "#363636",
|
||||
/** The secondary background color of the application */
|
||||
secondaryBackgroundColorDark: "#363636",
|
||||
/** The text color of the application */
|
||||
textColor: "#c8c8c8",
|
||||
/** The light text color of the application */
|
||||
lightTextColor: "#ffffff",
|
||||
/** The dark text color of the application */
|
||||
textColorDark: "#5a5a5a",
|
||||
/** The hover color of the application */
|
||||
hoverColor: "#e6e6e6",
|
||||
/** The active color of the application */
|
||||
activeColor: "#e6e6e6",
|
||||
/** The background color of the application */
|
||||
backgroundColor: "#e6efff",
|
||||
/** The secondary background color of the application */
|
||||
secondaryBackgroundColor: "#5a5a5a",
|
||||
/** Active Background Color */
|
||||
activeBackgroundColor: "#475c7c",
|
||||
};
|
||||
|
||||
export const MenuColors = {
|
||||
/** The background color of the menu */
|
||||
backgroundColor: GlobalColors.secondaryBackgroundColor,
|
||||
/** The text color of the menu */
|
||||
textColor: GlobalColors.textColor,
|
||||
/** The hover color of the menu */
|
||||
hoverColor: GlobalColors.hoverColor,
|
||||
/** The active color of the menu */
|
||||
activeColor: GlobalColors.primaryColor,
|
||||
/** The active background color of the menu */
|
||||
activeBackgroundColor: GlobalColors.activeBackgroundColor,
|
||||
/** The parent background color of the menu */
|
||||
parentBackgroundColor: GlobalColors.secondaryBackgroundColor,
|
||||
/** The parent text color of the menu */
|
||||
parentTextColor: GlobalColors.textColor,
|
||||
/** The parent hover color of the menu */
|
||||
parentHoverColor: GlobalColors.hoverColor,
|
||||
/** The parent active color of the menu */
|
||||
parentActiveColor: GlobalColors.activeColor,
|
||||
/** The child background color of the menu */
|
||||
childBackgroundColor: GlobalColors.secondaryBackgroundColor,
|
||||
/** The child text color of the menu */
|
||||
childTextColor: GlobalColors.textColor,
|
||||
/** The child hover color of the menu */
|
||||
childHoverColor: GlobalColors.hoverColor,
|
||||
/** The child active color of the menu */
|
||||
childActiveColor: GlobalColors.activeColor,
|
||||
};
|
||||
|
||||
export const HeaderColors = {
|
||||
/** The background color of the header */
|
||||
backgroundColor: GlobalColors.primaryColor,
|
||||
/** The text color of the header */
|
||||
textColor: GlobalColors.lightTextColor,
|
||||
/** The secondary text color of the header */
|
||||
textColorSecondary: GlobalColors.secondaryBackgroundColorDark,
|
||||
};
|
||||
|
||||
export const ButtonColors = {
|
||||
success: {
|
||||
/** The background color of the button */
|
||||
backgroundColor: "#00be29",
|
||||
/** The text color of the button */
|
||||
textColor: GlobalColors.lightTextColor,
|
||||
/** The hover color of the button */
|
||||
hoverColor: "#00a226",
|
||||
/** The active color of the button */
|
||||
activeColor: "#00a226",
|
||||
},
|
||||
default: {
|
||||
/** The background color of the button */
|
||||
backgroundColor: GlobalColors.secondaryBackgroundColor,
|
||||
/** The text color of the button */
|
||||
textColor: GlobalColors.lightTextColor,
|
||||
/** The hover color of the button */
|
||||
hoverColor: GlobalColors.hoverColor,
|
||||
/** The active color of the button */
|
||||
activeColor: GlobalColors.activeColor,
|
||||
},
|
||||
};
|
||||
|
||||
export const Colors = {
|
||||
/** The colors of the application */
|
||||
global: GlobalColors,
|
||||
/** The colors of the menus */
|
||||
menus: MenuColors,
|
||||
/** The colors of the headers */
|
||||
headers: HeaderColors,
|
||||
/** The colors of the buttons */
|
||||
buttons: ButtonColors,
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,13 @@
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,20 @@
|
||||
<script setup>
|
||||
import {useSlots} from 'vue';
|
||||
const slots = useSlots();
|
||||
|
||||
const isSlotEmpty = () => {
|
||||
return Object.keys(slots).length === 0;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="box has-sharp-edges" v-if="!isSlotEmpty()">
|
||||
<slot name="default"></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.box.has-sharp-edges {
|
||||
border-radius: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -8,6 +8,9 @@ import PosNotes from "@/components/displays/department/pos/PosNotes.vue";
|
||||
import PosSelectedCustomer from "@/components/displays/department/pos/PosSelectedCustomer.vue";
|
||||
import Cancel from "@/components/forms/department/pos/buttons/Cancel.vue";
|
||||
import { clearCache } from "@/components/shop/POSDepartmentProcess.vue";
|
||||
import WhiteBox from "@/components/displays/boxes/WhiteBox.vue";
|
||||
import ButtonsBox from "@/components/displays/boxes/ButtonsBox.vue";
|
||||
import { isCustomerSelected } from "@/components/shop/POSDepartmentProcess.vue";
|
||||
|
||||
// Clear cache
|
||||
clearCache();
|
||||
@@ -17,18 +20,39 @@ clearCache();
|
||||
<div>
|
||||
<div class="columns">
|
||||
<!-- Choose customer -->
|
||||
<div class="column is-8-desktop">
|
||||
<SelectCustomerFormPOS/>
|
||||
<div class="column is-8-desktop pl-0 pr-3">
|
||||
<WhiteBox>
|
||||
<template #default>
|
||||
<SelectCustomerFormPOS/>
|
||||
</template>
|
||||
</WhiteBox>
|
||||
<ButtonsBox>
|
||||
<div class="buttons">
|
||||
<Cancel
|
||||
style="width: 25%;"
|
||||
tabindex="2"
|
||||
class="is-fullwidth"
|
||||
/>
|
||||
</div>
|
||||
</ButtonsBox>
|
||||
</div>
|
||||
<!-- Last seen License Plates in department -->
|
||||
<div class="column is-4-desktop">
|
||||
<PosSelectedCustomer />
|
||||
<PosLastScannedLicensePlates class="my-3"/>
|
||||
<div class="column is-4-desktop pl-3 pr-0">
|
||||
<WhiteBox>
|
||||
<template #default v-if="isCustomerSelected()">
|
||||
<PosSelectedCustomer />
|
||||
</template>
|
||||
</WhiteBox>
|
||||
<WhiteBox>
|
||||
<template #default>
|
||||
<PosLastScannedLicensePlates class="my-3"/>
|
||||
</template>
|
||||
</WhiteBox>
|
||||
<NextStepError class="is-fullwidth" />
|
||||
<div class="buttons">
|
||||
<ButtonsBox>
|
||||
<NextStep class="is-fullwidth" tabindex="6"/>
|
||||
<Cancel class="is-fullwidth" tabindex="7"/>
|
||||
</div>
|
||||
</ButtonsBox>
|
||||
<NextStepError class="is-fullwidth" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<script setup>
|
||||
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
||||
console.log(SessionUser);
|
||||
console.log(SessionUser.user);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>{{SessionUser.user.display_name}}</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,9 +1,16 @@
|
||||
<script setup>
|
||||
import { deleteEverything, showDeleteEverythingDialog } from "@/components/shop/POSDepartmentProcess.vue";
|
||||
import { Colors } from "@/ThemeConfig.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button class="button is-inverted is-danger" @click="showDeleteEverythingDialog()">Slet alt</button>
|
||||
<button
|
||||
class="button"
|
||||
@click="showDeleteEverythingDialog()"
|
||||
:style="{backgroundColor: Colors.buttons.default.backgroundColor, color: Colors.buttons.default.textColor}"
|
||||
>
|
||||
Slet alt
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<script setup>
|
||||
import { nextStep, nextStepDelay } from "@/components/shop/POSDepartmentProcess.vue";
|
||||
import { Colors } from "@/ThemeConfig.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button class="button" @click="nextStep" v-if="nextStepDelay === 0">Next Step</button>
|
||||
<button
|
||||
class="button"
|
||||
@click="nextStep" v-if="nextStepDelay === 0"
|
||||
:style="{ 'background-color': Colors.buttons.success.backgroundColor, 'color': Colors.buttons.success.textColor }"
|
||||
>
|
||||
Næste</button>
|
||||
<button class="button is-loading" v-else>Please wait... {{ nextStepDelay }}</button>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -4,14 +4,25 @@ defineProps({
|
||||
subtitle: String
|
||||
})
|
||||
import { defineSlots } from 'vue'
|
||||
import { Colors } from '@/ThemeConfig.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mb-4">
|
||||
<div class="columns is-vcentered is-mobile">
|
||||
<div class="column">
|
||||
<h1 class="title is-3">{{ title }}</h1>
|
||||
<h2 class="subtitle is-5">{{ subtitle }}</h2>
|
||||
<h1
|
||||
style="margin-bottom: 0"
|
||||
class="is-size-3"
|
||||
:style="{ 'color': Colors.global.textColorDark }"
|
||||
>
|
||||
{{ title }}
|
||||
</h1>
|
||||
<p class="is-size-5"
|
||||
:style="{ 'color': Colors.global.textColorDark }"
|
||||
>
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
<slot name="buttons"></slot>
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { defineProps } from 'vue'
|
||||
import { Colors } from '@/ThemeConfig.vue'
|
||||
|
||||
const props = defineProps({
|
||||
menu_items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
show_icons: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const menu_items = ref([
|
||||
{
|
||||
name: 'Overblik',
|
||||
route: '/admin',
|
||||
icon: 'fas fa-tachometer-alt',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Vælg afdeling',
|
||||
options: [
|
||||
{
|
||||
label: 'Afdeling 1',
|
||||
value: 1,
|
||||
icon: 'fas fa-building',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
label: 'Afdeling 2',
|
||||
value: 2,
|
||||
icon: 'fas fa-building',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
label: 'Afdeling 3',
|
||||
value: 3,
|
||||
icon: 'fas fa-building',
|
||||
children: []
|
||||
}
|
||||
],
|
||||
selected: null,
|
||||
onSelect: async (value) => {
|
||||
console.log(value);
|
||||
},
|
||||
isExpanded: false
|
||||
},
|
||||
{
|
||||
name: 'Administration',
|
||||
route: '/administration',
|
||||
icon: 'fas fa-cogs',
|
||||
children: [
|
||||
{
|
||||
name: 'Team Settings',
|
||||
route: '/team-settings',
|
||||
icon: 'fas fa-users-cog',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Manage Your Team',
|
||||
route: '/manage-your-team',
|
||||
icon: 'fas fa-users',
|
||||
children: [
|
||||
{
|
||||
name: 'Members',
|
||||
route: '/members',
|
||||
icon: 'fas fa-user',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Plugins',
|
||||
route: '/plugins',
|
||||
icon: 'fas fa-plug',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Add a member',
|
||||
route: '/add-a-member',
|
||||
icon: 'fas fa-user-plus',
|
||||
children: []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Invitations',
|
||||
route: '/invitations',
|
||||
icon: 'fas fa-envelope',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Cloud Storage Environment Settings',
|
||||
route: '/cloud-storage-environment-settings',
|
||||
icon: 'fas fa-cloud',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Authentication',
|
||||
route: '/authentication',
|
||||
icon: 'fas fa-key',
|
||||
children: []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Transactions',
|
||||
route: '/transactions',
|
||||
icon: 'fas fa-exchange-alt',
|
||||
children: [
|
||||
{
|
||||
name: 'Payments',
|
||||
route: '/payments',
|
||||
icon: 'fas fa-money-bill-wave',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Transfers',
|
||||
route: '/transfers',
|
||||
icon: 'fas fa-exchange-alt',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Balance',
|
||||
route: '/balance',
|
||||
icon: 'fas fa-balance-scale',
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
// If the menu items are passed as props, use them instead
|
||||
if (props.menu_items.length > 0) {
|
||||
menu_items.value = props.menu_items
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<aside
|
||||
class="menu"
|
||||
:style="{ 'background-color': Colors.menus.parentBackgroundColor, 'color': Colors.menus.parentTextColor }"
|
||||
>
|
||||
<!-- Image -->
|
||||
<div class="menu-image" style="padding: 1rem;">
|
||||
<img src="@/assets/branding/truckwash-banner-white-compressed.png" alt="Truck Wash Logo" />
|
||||
</div>
|
||||
<p class="menu-label"
|
||||
:style="{ 'color': Colors.menus.parentTextColor, 'background-color': Colors.menus.parentBackgroundColor }"
|
||||
>
|
||||
|
||||
</p>
|
||||
<ul class="menu-list"
|
||||
:style="{ 'color': Colors.menus.textColor, 'background-color': Colors.menus.backgroundColor }"
|
||||
>
|
||||
<li v-for="item in menu_items" :key="item.name" :style="{'border-left':
|
||||
(item.selected)
|
||||
? '0.8rem solid ' + Colors.menus.activeColor
|
||||
: '0.8rem solid transparent' }
|
||||
">
|
||||
<a :class="{'is-active': route.path === item.route}" :href="item.route"
|
||||
:style="{ 'color': Colors.menus.textColor,
|
||||
'background-color': (item.selected)
|
||||
? Colors.menus.activeBackgroundColor
|
||||
: Colors.menus.backgroundColor }
|
||||
"
|
||||
@click="(item.options) ? item.isExpanded = !item.isExpanded : null"
|
||||
>
|
||||
<!-- If the item has options, show the dropdown icon -->
|
||||
<span class="icon is-small is-pulled-left mr-2 is-vcentered"
|
||||
v-if="item.options"
|
||||
:class="{'is-active': item.isExpanded}"
|
||||
:style="{ 'rotate': item.isExpanded ? '180deg' : '0deg' }"
|
||||
><i class="fas fa-angle-down"></i></span>
|
||||
<!-- If the item has an icon, show it -->
|
||||
<span class="icon is-small" v-if="props.show_icons"><i :class="item.icon"></i></span>
|
||||
<!-- If the item contains a selected value, show it -->
|
||||
<span v-if="item.selected && !item.isExpanded"><strong>{{ item.options.find(option => option.value === item.selected).label }}</strong></span>
|
||||
<span v-else><strong>{{ item.name }}</strong></span>
|
||||
</a>
|
||||
<ul v-if="item.options" class="menu-list" style="border-left: 0;">
|
||||
<!-- Dropdown -->
|
||||
<li v-for="option in item.options" :key="option.label" :style="{ 'color': Colors.menus.childTextColor,
|
||||
'background-color': (item.selected === option.value)
|
||||
? Colors.menus.activeBackgroundColor
|
||||
: Colors.menus.backgroundColor }"
|
||||
v-if="item.isExpanded">
|
||||
<a :class="{ 'is-active': item.selected === option.value }"
|
||||
class="menu-list-custom-hover-able-child-item"
|
||||
@click="item.onSelect(option.value)"
|
||||
:style="{ 'color': Colors.menus.childTextColor,
|
||||
'background-color': (item.selected === option.value)
|
||||
? Colors.menus.activeBackgroundColor
|
||||
: Colors.menus.childBackgroundColor
|
||||
}"
|
||||
>
|
||||
<span class="icon is-small" v-if="props.show_icons"><i :class="option.icon"></i></span>
|
||||
<span v-if="item.selected === option.value"><strong>{{ option.label }}</strong></span>
|
||||
<span v-else>{{ option.label }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul v-else class="menu-list">
|
||||
<!-- Children -->
|
||||
<li v-for="child in item.children" :key="child.name">
|
||||
<a :class="{'is-active': route.path === child.route}" :href="child.route"
|
||||
:style="{ 'color': Colors.menus.childTextColor, 'background-color': Colors.menus.childBackgroundColor }">
|
||||
<span class="icon is-small" v-if="props.show_icons"><i :class="child.icon"></i></span>
|
||||
{{ child.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.menu-list-custom-hover-able-child-item:hover {
|
||||
background-color: #4a4a4a !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,116 @@
|
||||
<script setup>
|
||||
import MenuDefault from "@/components/menus/MenuDefault.vue";
|
||||
import {ref} from "vue";
|
||||
import {SessionUser} from "@/components/session/token/SessionUser.vue";
|
||||
|
||||
// Define the isLoaded function
|
||||
// This is here, because the departments need to be loaded before the menu is shown,
|
||||
// otherwise the menu will look for a department with an id not defined.
|
||||
const isLoaded = ref(false);
|
||||
|
||||
// Load the departments
|
||||
SessionUser.objects.departments.get.all().then((departments) => {
|
||||
const options = [];
|
||||
departments.forEach((department) => {
|
||||
options.push({
|
||||
label: department.name,
|
||||
value: department.id,
|
||||
icon: 'fas fa-building',
|
||||
children: []
|
||||
});
|
||||
});
|
||||
console.log(departments);
|
||||
menu_items.value[1].options = options;
|
||||
isLoaded.value = true;
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
|
||||
const menu_items = ref([
|
||||
{
|
||||
name: 'Overblik',
|
||||
route: '/admin',
|
||||
icon: 'fas fa-tachometer-alt',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Vælg afdeling',
|
||||
options: [
|
||||
{
|
||||
label: 'Afdeling 1',
|
||||
value: 1,
|
||||
icon: 'fas fa-building',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
label: 'Afdeling 2',
|
||||
value: 2,
|
||||
icon: 'fas fa-building',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
label: 'Afdeling 3',
|
||||
value: 3,
|
||||
icon: 'fas fa-building',
|
||||
children: []
|
||||
}
|
||||
],
|
||||
selected: SessionUser.functions.getDepartmentIdFromUrl() !== null ? parseInt(SessionUser.functions.getDepartmentIdFromUrl()) : null,
|
||||
onSelect: async (value) => {
|
||||
selectDepartment(value);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Kassesystem',
|
||||
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/pos',
|
||||
permissions: [
|
||||
'canAccessAdmin'
|
||||
],
|
||||
icon: 'fas fa-cogs',
|
||||
children: [
|
||||
{
|
||||
name: 'Opret ny',
|
||||
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/pos',
|
||||
icon: 'fas fa-plus',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: 'Transaktioner',
|
||||
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/pos/orders',
|
||||
icon: 'fas fa-exchange-alt',
|
||||
children: []
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Bookinger',
|
||||
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/bookings',
|
||||
icon: 'fas fa-exchange-alt',
|
||||
children: []
|
||||
}
|
||||
]);
|
||||
|
||||
const selectDepartment = (department) => {
|
||||
// Get the current path (After /admin/:department_id)
|
||||
const currentPath = window.location.pathname.split('/').slice(3).join('/');
|
||||
console.log('Selected department: ' + department);
|
||||
menu_items.value[1].selected = department;
|
||||
// Hide the menu
|
||||
menu_items.value[1].isExpanded = false;
|
||||
// Redirect to the department
|
||||
SessionUser.functions.redirectTo.department(department, currentPath);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MenuDefault v-if="isLoaded"
|
||||
v-bind="{menu_items}"
|
||||
:show_icons="false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@ import '@sweetalert2/theme-bulma/bulma.scss';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container" style="padding-left: 10px; padding-right: 10px;">
|
||||
<div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -16,6 +16,7 @@ import {EconomicProducts} from "@/components/session/token/SessionUser/Objects/e
|
||||
import {Roles} from "@/components/session/token/SessionUser/Objects/Roles.vue";
|
||||
import {Permissions} from "@/components/session/token/SessionUser/Objects/Permissions.vue";
|
||||
import {ObjectsGlobal} from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
/**
|
||||
* Initiate the user session on app start
|
||||
@@ -68,6 +69,7 @@ export const getSessionData = async () => {
|
||||
SessionUser.user.group_id.value = response.data.data.group_id;
|
||||
SessionUser.user.created_at.value = response.data.data.created_at;
|
||||
SessionUser.user.updated_at.value = response.data.data.updated_at;
|
||||
SessionUser.user.display_name.value = response.data.data.display_name;
|
||||
// Set the last cached time to now, this is used to determine if the user's data is outdated
|
||||
SessionUser.user.cached_at.value = new Date();
|
||||
SessionUser.permissions.value = response.data.data.permissions;
|
||||
@@ -75,6 +77,10 @@ export const getSessionData = async () => {
|
||||
if (response.data.data.economic_customer.length > 0) {
|
||||
SessionUser.economicData.customerNumber.value = response.data.data.economic_customer.customerNumber;
|
||||
SessionUser.economicData.name.value = response.data.data.economic_customer.name;
|
||||
// Set the display name to the e-conomic name if it's empty
|
||||
if (SessionUser.user.display_name.value === null) {
|
||||
SessionUser.user.display_name.value = response.data.data.economic_customer.name;
|
||||
}
|
||||
SessionUser.economicData.address.value = response.data.data.economic_customer.address;
|
||||
SessionUser.economicData.zip.value = response.data.data.economic_customer.zip;
|
||||
SessionUser.economicData.city.value = response.data.data.economic_customer.city;
|
||||
@@ -251,6 +257,42 @@ export const SessionUser = {
|
||||
/** reCAPTCHA */
|
||||
reCAPTCHA: reCAPTCHA,
|
||||
},
|
||||
functions: {
|
||||
/** Get the department id from the url */
|
||||
getDepartmentIdFromUrl: () => {
|
||||
// Check if the department id is in the route
|
||||
const router = useRouter();
|
||||
return router.currentRoute.value.params.departmentId;
|
||||
},
|
||||
/** Redirect to */
|
||||
redirectTo: {
|
||||
/**
|
||||
* Redirect to a department
|
||||
* @note This will redirect the user to '/admin/:department(/:path)'
|
||||
* @param department The department id
|
||||
* @param path The path to redirect to (Optional)
|
||||
*/
|
||||
department: (department, path = null) => {
|
||||
window.location.href = '/admin/' + department + (path !== null ? '/' + path : '');
|
||||
},
|
||||
/**
|
||||
* Redirect to a superuser page
|
||||
* @note This will redirect the user to '/superuser(/:path)'
|
||||
* @param path The path to redirect to (Optional)
|
||||
*/
|
||||
superUser: (path = null) => {
|
||||
window.location.href = '/superuser' + (path !== null ? path : '');
|
||||
},
|
||||
/**
|
||||
* Redirect to a user page
|
||||
* @note This will redirect the user to '/user(/:path)'
|
||||
* @param path The path to redirect to (Optional)
|
||||
*/
|
||||
user: (path = null) => {
|
||||
window.location.href = '/user' + (path !== null ? path : '');
|
||||
},
|
||||
}
|
||||
},
|
||||
request: authenticatedRequest,
|
||||
editField: EditFieldForm,
|
||||
getSessionData: getSessionData,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import store from './store/user.vue'
|
||||
import {router} from "@/router.js";
|
||||
import {Colors} from "./ThemeConfig.vue";
|
||||
import applyMiddleware from '@/middleware/index.js';
|
||||
|
||||
applyMiddleware(router);
|
||||
@@ -16,4 +17,5 @@ applyMiddleware(router);
|
||||
createApp(App)
|
||||
.use(store)
|
||||
.use(router)
|
||||
.provide('Colors', Colors)
|
||||
.mount('#app')
|
||||
|
||||
@@ -13,8 +13,8 @@ const departmentId = ref(router.currentRoute.value.params.departmentId);
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<UserNavigation />
|
||||
<DepartmentDashboardNavigation />
|
||||
<!-- <UserNavigation /> -->
|
||||
<!-- <DepartmentDashboardNavigation /> -->
|
||||
<PageTitle :title="title" :subtitle="subtitle"><slot></slot></PageTitle>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<script setup>
|
||||
|
||||
import AdminLeftMenu from "@/components/menus/admin/AdminLeftMenu.vue";
|
||||
import { Colors } from "@/ThemeConfig.vue";
|
||||
import { defineProps } from "vue";
|
||||
import { defineSlots } from "vue";
|
||||
import PageTitle from "@/components/global/PageTitle.vue";
|
||||
import UserNavigationTop from "@/components/displays/user/UserNavigationTop.vue";
|
||||
|
||||
defineProps({
|
||||
title: String,
|
||||
subtitle: String
|
||||
})
|
||||
|
||||
defineSlots()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="columns is-multiline">
|
||||
<!-- Header -->
|
||||
<div
|
||||
class="column is-12 is-vcentered"
|
||||
:style="{ 'background-color': Colors.headers.backgroundColor, 'color': Colors.headers.textColor }"
|
||||
style="margin-bottom: 0; padding-bottom: 0;"
|
||||
>
|
||||
<slot name="header"></slot>
|
||||
<!-- If the header slot is empty, show the default header -->
|
||||
<UserNavigationTop class="my-4 is-float-right" style="margin-right: 5rem;" :style="{ 'color': Colors.headers.textColor }" />
|
||||
</div>
|
||||
<!-- Left menu -->
|
||||
<div class="column is-2"
|
||||
:style="{ 'background-color': Colors.menus.parentBackgroundColor, 'color': Colors.menus.textColor }">
|
||||
<AdminLeftMenu />
|
||||
</div>
|
||||
<!-- Page content -->
|
||||
<div
|
||||
class="column is-10"
|
||||
:style="{ 'background-color': Colors.global.backgroundColor, 'color': Colors.global.textColor }"
|
||||
>
|
||||
<div class="pl-6 pt-6 mb-0" v-if="title || subtitle">
|
||||
<div class="columns is-vcentered is-mobile">
|
||||
<PageTitle :title="title" :subtitle="subtitle">
|
||||
<slot name="buttons"></slot>
|
||||
</PageTitle>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-6 pr-6 pb-6">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -6,14 +6,23 @@ import PosDepartmentMVP from "@/components/displays/department/pos/PosDepartment
|
||||
import DepartmentPosNavigation from "@/views/dashboards/departmentDashboard/modules/Pos/DepartmentPosNavigation.vue";
|
||||
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
|
||||
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
||||
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
|
||||
import PageTitle from "@/components/global/PageTitle.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RestrictedPageWrapper :hasPermission="SessionUser.canAccessAdmin()">
|
||||
<DepartmentDashboardHero title="Kassesystem" subtitle="Point of Sale" />
|
||||
<DepartmentPosNavigation />
|
||||
<PosDepartmentMVP />
|
||||
</RestrictedPageWrapper>
|
||||
<DepartmentDashboardPageWrapper
|
||||
title="Kassesystem"
|
||||
subtitle="Point of Sale"
|
||||
>
|
||||
<template #default>
|
||||
<RestrictedPageWrapper :hasPermission="SessionUser.canAccessAdmin()">
|
||||
<!-- <DepartmentDashboardHero /> -->
|
||||
<!-- <DepartmentPosNavigation /> -->
|
||||
<PosDepartmentMVP />
|
||||
</RestrictedPageWrapper>
|
||||
</template>
|
||||
</DepartmentDashboardPageWrapper>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user