routing inside url

This commit is contained in:
Julian Krauser 2024-09-01 19:19:48 +02:00
parent 2d0fb30558
commit 6247c385c3
15 changed files with 278 additions and 203 deletions

View file

@ -1,6 +1,6 @@
<template> <template>
<footer <footer
v-if="authCheck && routeName == 'admin'" v-if="authCheck && routeName.includes('admin')"
class="md:hidden flex flex-row h-16 justify-center md:justify-normal p-1 bg-white" class="md:hidden flex flex-row h-16 justify-center md:justify-normal p-1 bg-white"
> >
<div class="w-full flex flex-row gap-2 h-full align-middle"> <div class="w-full flex flex-row gap-2 h-full align-middle">
@ -23,7 +23,7 @@ export default defineComponent({
...mapState(useAuthStore, ["authCheck"]), ...mapState(useAuthStore, ["authCheck"]),
...mapState(useNavigationStore, ["topLevel"]), ...mapState(useNavigationStore, ["topLevel"]),
routeName() { routeName() {
return this.$route.name; return typeof this.$route.name == "string" ? this.$route.name : "";
}, },
}, },
}); });

View file

@ -5,7 +5,7 @@
<h1 v-if="false" class="font-bold text-3xl w-fit whitespace-nowrap">Mitgliederverwaltung</h1> <h1 v-if="false" class="font-bold text-3xl w-fit whitespace-nowrap">Mitgliederverwaltung</h1>
</RouterLink> </RouterLink>
<div class="flex flex-row gap-2 items-center"> <div class="flex flex-row gap-2 items-center">
<div v-if="authCheck && routeName == 'admin'" class="hidden md:flex flex-row gap-2 h-full align-middle"> <div v-if="authCheck && routeName.includes('admin')" class="hidden md:flex flex-row gap-2 h-full align-middle">
<TopLevelLink v-for="item in topLevel" :key="item.key" :link="item" /> <TopLevelLink v-for="item in topLevel" :key="item.key" :link="item" />
</div> </div>
<UserMenu v-if="authCheck" /> <UserMenu v-if="authCheck" />
@ -29,7 +29,7 @@ export default defineComponent({
...mapState(useAuthStore, ["authCheck"]), ...mapState(useAuthStore, ["authCheck"]),
...mapState(useNavigationStore, ["topLevel"]), ...mapState(useNavigationStore, ["topLevel"]),
routeName() { routeName() {
return this.$route.name; return typeof this.$route.name == "string" ? this.$route.name : "";
}, },
}, },
}); });

View file

@ -1,16 +1,14 @@
<template> <template>
<div <RouterLink v-if="link" v-slot="{ isExactActive }" :to="{ name: `admin-${activeNavigation}-${link.key}` }">
v-if="link" <p
class="cursor-pointer w-full px-2 py-3" class="cursor-pointer w-full px-2 py-3"
:class=" :class="
activeLink?.key == link.key isExactActive ? 'rounded-r-lg bg-red-200 border-l-4 border-l-primary' : 'pl-3 hover:bg-red-200 rounded-lg'
? 'rounded-r-lg bg-red-200 border-l-4 border-l-primary'
: 'pl-3 hover:bg-red-200 rounded-lg'
" "
@click="setLink(link.key)"
> >
{{ link.title }} {{ link.title }}
</div> </p>
</RouterLink>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -20,6 +18,7 @@ import { useNavigationStore, type navigationLinkModel } from "@/stores/admin/nav
<script lang="ts"> <script lang="ts">
import { defineComponent, type PropType } from "vue"; import { defineComponent, type PropType } from "vue";
import { RouterLink } from "vue-router";
export default defineComponent({ export default defineComponent({
props: { props: {
link: { link: {
@ -28,11 +27,7 @@ export default defineComponent({
}, },
}, },
computed: { computed: {
...mapState(useNavigationStore, ["activeLink"]), ...mapState(useNavigationStore, ["activeNavigation"]),
},
methods: {
...mapActions(useNavigationStore, ["setLink"]),
}, },
}); });
</script> </script>
@/stores/contest/viewManager

View file

@ -1,25 +1,30 @@
<template> <template>
<div <RouterLink
v-if="link" v-if="link"
:to="{ name: `admin-${link.key}-${!disableSubLink ? link.levelDefault : 'default'}` }"
class="cursor-pointer w-full flex items-center justify-center self-center"
>
<p
class="cursor-pointer w-full flex flex-col md:flex-row items-center md:gap-2 justify-center p-1 md:rounded-full md:px-3 font-medium text-center text-base self-center" class="cursor-pointer w-full flex flex-col md:flex-row items-center md:gap-2 justify-center p-1 md:rounded-full md:px-3 font-medium text-center text-base self-center"
:class=" :class="
activeNavigation == link.key activeNavigation == link.key
? 'text-primary md:bg-primary md:text-white' ? 'text-primary md:bg-primary md:text-white'
: 'text-gray-700 hover:text-accent md:hover:bg-accent md:hover:text-white' : 'text-gray-700 hover:text-accent md:hover:bg-accent md:hover:text-white'
" "
@click="setTopLevel(link.key, disableSubLink)"
> >
{{ link.title }} {{ link.title }}
</div> </p>
</RouterLink>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { mapState, mapActions } from "pinia";
import { useNavigationStore, type topLevelNavigationModel } from "@/stores/admin/navigation"; import { useNavigationStore, type topLevelNavigationModel } from "@/stores/admin/navigation";
import { mapState } from "pinia";
</script> </script>
<script lang="ts"> <script lang="ts">
import { defineComponent, type PropType } from "vue"; import { defineComponent, type PropType } from "vue";
import { RouterLink } from "vue-router";
export default defineComponent({ export default defineComponent({
props: { props: {
link: { link: {
@ -34,8 +39,5 @@ export default defineComponent({
computed: { computed: {
...mapState(useNavigationStore, ["activeNavigation"]), ...mapState(useNavigationStore, ["activeNavigation"]),
}, },
methods: {
...mapActions(useNavigationStore, ["setTopLevel"]),
},
}); });
</script> </script>

View file

@ -2,16 +2,18 @@
<div class="flex flex-col h-fit w-full border border-primary rounded-md"> <div class="flex flex-col h-fit w-full border border-primary rounded-md">
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center"> <div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
<p>{{ role.role }} <small v-if="role.permissions?.isAdmin">(Admin)</small></p> <p>{{ role.role }} <small v-if="role.permissions?.isAdmin">(Admin)</small></p>
<PencilIcon class="w-5 h-5 p-1 box-content cursor-pointer" /> <PencilIcon class="w-5 h-5 p-1 box-content cursor-pointer" @click="openUpdateModal" />
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineComponent, type PropType } from "vue"; import { defineComponent, defineAsyncComponent, markRaw, type PropType } from "vue";
import { mapState, mapActions } from "pinia"; import { mapState, mapActions } from "pinia";
import { PencilIcon } from "@heroicons/vue/outline"; import { PencilIcon } from "@heroicons/vue/outline";
import type { RoleViewModel } from "@/viewmodels/admin/role.models"; import type { RoleViewModel } from "@/viewmodels/admin/role.models";
import { useModalStore } from "@/stores/modal";
import { useNavigationStore } from "@/stores/admin/navigation";
</script> </script>
<script lang="ts"> <script lang="ts">
@ -23,5 +25,14 @@ export default defineComponent({
return {}; return {};
}, },
mounted() {}, mounted() {},
methods: {
...mapActions(useModalStore, ["openModal"]),
openUpdateModal() {
this.openModal(
markRaw(defineAsyncComponent(() => import("@/components/admin/user/role/UpdateRoleModal.vue"))),
this.role.id
);
},
},
}); });
</script> </script>

View file

@ -0,0 +1,54 @@
<template>
<div class="flex flex-col items-center gap-2 w-full max-w-6xl h-1/2 max-h-3/4">
<div class="flex flex-col">
<p class="text-xl font-medium">Rolle bearbeiten</p>
</div>
<form class="flex flex-col gap-4 py-2 w-full max-w-xl" @submit.prevent="">
<div>
<label for="role">Rollenbezeichnung</label>
<input type="text" id="role" required />
</div>
<div class="flex flex-row gap-2">
<button primary type="submit" :disabled="createStatus == 'loading' || createStatus?.status == 'success'">
speichern
</button>
<Spinner v-if="createStatus == 'loading'" class="my-auto" />
<SuccessCheckmark v-else-if="createStatus?.status == 'success'" />
<FailureXMark v-else-if="createStatus?.status == 'failed'" />
</div>
</form>
<div class="flex flex-row self-end mt-auto">
<div class="flex flex-row gap-4 py-2">
<button primary-outline @click="closeModal">schließen</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { defineComponent } from "vue";
import { mapState, mapActions } from "pinia";
import { useModalStore } from "@/stores/modal";
import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue";
import { useRoleStore } from "@/stores/admin/role";
import Permission from "../../Permission.vue";
</script>
<script lang="ts">
export default defineComponent({
mounted() {
this.fetchRoleById(this.data);
},
computed: {
...mapState(useRoleStore, ["createStatus", "role"]),
...mapState(useModalStore, ["data"]),
},
methods: {
...mapActions(useModalStore, ["closeModal"]),
...mapActions(useRoleStore, ["fetchRoleById"]),
},
});
</script>

View file

@ -6,7 +6,7 @@
> >
<slot name="sidebar"></slot> <slot name="sidebar"></slot>
</div> </div>
<div class="max-w-full grow flex-col gap-4" :class="defaultRoute && defaultSidebar ? 'hidden md:flex' : 'flex'"> <div class="max-w-full grow flex-col gap-2" :class="defaultRoute && defaultSidebar ? 'hidden md:flex' : 'flex'">
<slot name="main"></slot> <slot name="main"></slot>
</div> </div>
</div> </div>
@ -29,7 +29,7 @@ export default defineComponent({
computed: { computed: {
...mapState(useNavigationStore, ["activeLink"]), ...mapState(useNavigationStore, ["activeLink"]),
defaultRoute() { defaultRoute() {
return this.activeLink == null; return ((this.$route?.name as string) ?? "").includes("-default");
}, },
}, },
}); });

24
src/router/adminGuard.ts Normal file
View file

@ -0,0 +1,24 @@
import NProgress from "nprogress";
import { useAbilityStore } from "../stores/ability";
import { useNavigationStore } from "../stores/admin/navigation";
export async function abilityAndNavUpdate(to: any, from: any, next: any) {
NProgress.start();
const ability = useAbilityStore();
const navigation = useNavigationStore();
let type = to.meta.type;
let section = to.meta.section;
let module = to.meta.module;
navigation.activeNavigation = to.name.split("-")[1];
navigation.activeLink = to.name.split("-")[2];
if (ability.can(type, section, module)) {
NProgress.done();
next();
} else {
NProgress.done();
next(false);
}
}

View file

@ -4,6 +4,8 @@ import Login from "../views/Login.vue";
import { isAuthenticated } from "./authGuards"; import { isAuthenticated } from "./authGuards";
import { loadAccountData } from "./accountGuard"; import { loadAccountData } from "./accountGuard";
import { isSetup } from "./setupGuard"; import { isSetup } from "./setupGuard";
import { abilityAndNavUpdate } from "./adminGuard";
import type { PermissionType, PermissionSection, PermissionModule } from "../types/permissionTypes";
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
@ -41,6 +43,110 @@ const router = createRouter({
name: "admin", name: "admin",
component: () => import("../views/admin/View.vue"), component: () => import("../views/admin/View.vue"),
beforeEnter: [isAuthenticated], beforeEnter: [isAuthenticated],
children: [
{
path: "",
name: "admin-default",
component: () => import("../views/RouterView.vue"),
},
{
path: "club",
name: "admin-club",
component: () => import("../views/RouterView.vue"),
meta: { type: "read", section: "club" },
beforeEnter: [abilityAndNavUpdate],
children: [
{
path: "",
name: "admin-club-default",
component: () => import("../views/admin/ViewSelect.vue"),
},
{
path: "members",
name: "admin-club-members",
component: () => import("../views/admin/members/Overview.vue"),
},
{
path: "calendar",
name: "admin-club-calendar",
component: () => import("../views/admin/members/Overview.vue"),
},
{
path: "newsletter",
name: "admin-club-newsletter",
component: () => import("../views/admin/members/Overview.vue"),
},
{
path: "protocol",
name: "admin-club-protocol",
component: () => import("../views/admin/members/Overview.vue"),
},
],
},
{
path: "settings",
name: "admin-settings",
component: () => import("../views/RouterView.vue"),
meta: { type: "read", section: "settings" },
beforeEnter: [abilityAndNavUpdate],
children: [
{
path: "",
name: "admin-settings-default",
component: () => import("../views/admin/ViewSelect.vue"),
},
{
path: "qualification",
name: "admin-settings-qualification",
component: () => import("../views/admin/members/Overview.vue"),
},
{
path: "award",
name: "admin-settings-award",
component: () => import("../views/admin/members/Overview.vue"),
},
{
path: "executive-position",
name: "admin-settings-executive_position",
component: () => import("../views/admin/members/Overview.vue"),
},
{
path: "communication",
name: "admin-settings-communication",
component: () => import("../views/admin/members/Overview.vue"),
},
],
},
{
path: "user",
name: "admin-user",
component: () => import("../views/RouterView.vue"),
meta: { type: "read", section: "user" },
beforeEnter: [abilityAndNavUpdate],
children: [
{
path: "",
name: "admin-user-default",
component: () => import("../views/admin/ViewSelect.vue"),
},
{
path: "user",
name: "admin-user-user",
component: () => import("../views/admin/user/User.vue"),
},
{
path: "role",
name: "admin-user-role",
component: () => import("../views/admin/user/Role.vue"),
},
],
},
{
path: ":pathMatch(.*)*",
name: "admin-404",
component: () => import("../views/notFound.vue"),
},
],
}, },
{ {
path: "/nopermissions", path: "/nopermissions",
@ -56,3 +162,11 @@ const router = createRouter({
}); });
export default router; export default router;
declare module "vue-router" {
interface RouteMeta {
type?: PermissionType | "admin";
section?: PermissionSection;
module?: PermissionModule;
}
}

View file

@ -1,6 +1,6 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { shallowRef, defineAsyncComponent } from "vue";
import { useAbilityStore } from "../ability"; import { useAbilityStore } from "../ability";
import router from "../../router";
export interface navigationModel { export interface navigationModel {
club: navigationSplitModel; club: navigationSplitModel;
@ -26,17 +26,15 @@ export interface topLevelNavigationModel {
export interface navigationLinkModel { export interface navigationLinkModel {
key: string; key: string;
title: string; title: string;
component: any;
} }
export const useNavigationStore = defineStore("navigation", { export const useNavigationStore = defineStore("navigation", {
state: () => { state: () => {
return { return {
activeNavigation: "club" as topLevelNavigationType, activeNavigation: "club" as topLevelNavigationType,
activeLink: null as null | navigationLinkModel, activeLink: null as null | string,
topLevel: [] as Array<topLevelNavigationModel>, topLevel: [] as Array<topLevelNavigationModel>,
navigation: {} as navigationModel, navigation: {} as navigationModel,
componentOverwrite: null as null | any,
}; };
}, },
getters: { getters: {
@ -45,42 +43,10 @@ export const useNavigationStore = defineStore("navigation", {
(state.topLevel.find((elem) => elem.key == state.activeNavigation) ?? {}) as topLevelNavigationModel, (state.topLevel.find((elem) => elem.key == state.activeNavigation) ?? {}) as topLevelNavigationModel,
}, },
actions: { actions: {
setTopLevel(key: topLevelNavigationType, disableSubLink: boolean = true) {
let level = this.topLevel.find((e) => e.key == key) ?? null;
if (!level) {
this.activeNavigation = "club";
if (!disableSubLink) this.setLink(this.topLevel.find((e) => e.key == "club")?.levelDefault ?? null);
else this.setLink(null);
} else {
this.activeNavigation = level.key;
if (!disableSubLink) this.setLink(level.levelDefault);
else this.setLink(null);
}
this.resetComponentOverwrite();
},
setLink(key: string | null) {
let nav = this.navigation[this.activeNavigation];
if (!nav) {
this.activeLink = null;
return;
}
let links = [...Object.values(nav.main), ...Object.values(nav.top ?? {})];
this.activeLink = links.find((e) => e.key == key) ?? null;
this.resetComponentOverwrite();
},
setTopLevelNav(topLeveLinks: Array<topLevelNavigationModel>) {
this.topLevel = topLeveLinks;
},
setComponentOverwrite(component: any) {
this.componentOverwrite = component;
},
resetComponentOverwrite() {
this.componentOverwrite = null;
},
resetNavigation() { resetNavigation() {
this.$reset(); this.$reset();
}, },
updateTopLevel() { updateTopLevel(first: boolean = false) {
const abilityStore = useAbilityStore(); const abilityStore = useAbilityStore();
this.topLevel = [ this.topLevel = [
...(abilityStore.canSection("read", "club") ...(abilityStore.canSection("read", "club")
@ -88,7 +54,7 @@ export const useNavigationStore = defineStore("navigation", {
{ {
key: "club", key: "club",
title: "Verein", title: "Verein",
levelDefault: "#members", levelDefault: "members",
} as topLevelNavigationModel, } as topLevelNavigationModel,
] ]
: []), : []),
@ -97,7 +63,7 @@ export const useNavigationStore = defineStore("navigation", {
{ {
key: "settings", key: "settings",
title: "Einstellungen", title: "Einstellungen",
levelDefault: "#qualification", levelDefault: "qualification",
} as topLevelNavigationModel, } as topLevelNavigationModel,
] ]
: []), : []),
@ -106,124 +72,51 @@ export const useNavigationStore = defineStore("navigation", {
{ {
key: "user", key: "user",
title: "Benutzer", title: "Benutzer",
levelDefault: "#user", levelDefault: "user",
} as topLevelNavigationModel, } as topLevelNavigationModel,
] ]
: []), : []),
]; ];
if (this.topLevel.findIndex((e) => e.key == this.activeNavigation) == -1) if (this.topLevel.findIndex((e) => e.key == this.activeNavigation) == -1 && !first)
this.activeNavigation = this.topLevel[0]?.key ?? "club"; router.push({ name: `admin-${this.topLevel[0]?.key ?? "club"}-default` });
}, },
updateNavigation() { updateNavigation(first: boolean = false) {
const abilityStore = useAbilityStore(); const abilityStore = useAbilityStore();
this.navigation = { this.navigation = {
club: { club: {
mainTitle: "Verein", mainTitle: "Verein",
main: [ main: [
...(abilityStore.can("read", "club", "members") ...(abilityStore.can("read", "club", "members") ? [{ key: "members", title: "Mitglieder" }] : []),
? [ ...(abilityStore.can("read", "club", "calendar") ? [{ key: "calendar", title: "Termine" }] : []),
{ ...(abilityStore.can("read", "club", "newsletter") ? [{ key: "newsletter", title: "Newsletter" }] : []),
key: "#members", ...(abilityStore.can("read", "club", "protocoll") ? [{ key: "protocol", title: "Protokolle" }] : []),
title: "Mitglieder",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
},
]
: []),
...(abilityStore.can("read", "club", "calendar")
? [
{
key: "#calendar",
title: "Termine",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
},
]
: []),
...(abilityStore.can("read", "club", "newsletter")
? [
{
key: "#newsletter",
title: "Newsletter",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
},
]
: []),
...(abilityStore.can("read", "club", "protocoll")
? [
{
key: "#protocol",
title: "Protokolle",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
},
]
: []),
], ],
}, },
settings: { settings: {
mainTitle: "Einstellungen", mainTitle: "Einstellungen",
main: [ main: [
...(abilityStore.can("read", "settings", "qualification") ...(abilityStore.can("read", "settings", "qualification")
? [ ? [{ key: "qualification", title: "Qualifikationen" }]
{
key: "#qualification",
title: "Qualifikationen",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
},
]
: []),
...(abilityStore.can("read", "settings", "award")
? [
{
key: "#award",
title: "Auszeichnungen",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
},
]
: []), : []),
...(abilityStore.can("read", "settings", "award") ? [{ key: "award", title: "Auszeichnungen" }] : []),
...(abilityStore.can("read", "settings", "executive_position") ...(abilityStore.can("read", "settings", "executive_position")
? [ ? [{ key: "executive_position", title: "Vereinsämter" }]
{
key: "#executive_position",
title: "Vereinsämter",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
},
]
: []), : []),
...(abilityStore.can("read", "settings", "communication") ...(abilityStore.can("read", "settings", "communication")
? [ ? [{ key: "communication", title: "Mitgliederdaten" }]
{
key: "#communication",
title: "Mitgliederdaten",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
},
]
: []), : []),
], ],
}, },
user: { user: {
mainTitle: "Benutzer", mainTitle: "Benutzer",
main: [ main: [
...(abilityStore.can("read", "user", "user") ...(abilityStore.can("read", "user", "user") ? [{ key: "user", title: "Benutzer" }] : []),
? [ ...(abilityStore.can("read", "user", "role") ? [{ key: "role", title: "Rollen" }] : []),
{
key: "#user",
title: "Benutzer",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/user/User.vue"))),
},
]
: []),
...(abilityStore.can("read", "user", "role")
? [
{
key: "#role",
title: "Rollen",
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/user/Role.vue"))),
},
]
: []),
], ],
}, },
} as navigationModel; } as navigationModel;
if (this.topLevel.findIndex((e) => e.key == this.activeLink?.key) == -1) this.setLink(null); if (this.topLevel.findIndex((e) => e.key == this.activeLink) == -1 && !first)
router.push({ name: `admin-${this.activeNavigation}-default` });
}, },
}, },
}); });

View file

@ -25,7 +25,7 @@ export const useRoleStore = defineStore("role", {
this.loadingAll = "failed"; this.loadingAll = "failed";
}); });
}, },
fetchRolesById(id: number) { fetchRoleById(id: number) {
this.role = null; this.role = null;
this.loadingSingle = "loading"; this.loadingSingle = "loading";
http http

View file

@ -24,7 +24,7 @@ export const useUserStore = defineStore("user", {
this.loadingAll = "failed"; this.loadingAll = "failed";
}); });
}, },
fetchUsersById(id: number) { fetchUserById(id: number) {
this.user = null; this.user = null;
this.loadingSingle = "loading"; this.loadingSingle = "loading";
http http

View file

@ -1,6 +1,8 @@
<template> <template>
<div v-if="!defaultRoute && showBack" class="flex md:hidden flex-row items-baseline"> <div v-if="!defaultRoute && showBack" class="flex md:hidden flex-row items-baseline">
<p v-if="!defaultRoute && showBack" class="text-primary" @click="setLink(null)">zur Übersicht</p> <RouterLink v-if="!defaultRoute && showBack" :to="{ name: `${rootRoute}-default` }" class="mid:hidden text-primary">
zur Übersicht
</RouterLink>
</div> </div>
<slot v-if="headerInsert" name="headerInsert"></slot> <slot v-if="headerInsert" name="headerInsert"></slot>
<div <div
@ -37,7 +39,10 @@ export default defineComponent({
computed: { computed: {
...mapState(useNavigationStore, ["activeLink"]), ...mapState(useNavigationStore, ["activeLink"]),
defaultRoute() { defaultRoute() {
return this.activeLink == null; return ((this.$route?.name as string) ?? "").includes("-default");
},
rootRoute() {
return ((this.$route?.name as string) ?? "").split("-")[0];
}, },
diffMain() { diffMain() {
return this.$slots.diffMain; return this.$slots.diffMain;
@ -49,8 +54,5 @@ export default defineComponent({
return window.matchMedia("(min-width: 800px)").matches; return window.matchMedia("(min-width: 800px)").matches;
}, },
}, },
methods: {
...mapActions(useNavigationStore, ["setLink"]),
},
}); });
</script> </script>

View file

@ -15,8 +15,7 @@
</SidebarTemplate> </SidebarTemplate>
</template> </template>
<template #main> <template #main>
<component v-if="display" :is="displayed" /> <RouterView />
<div v-else class="w-full h-full bg-white rounded-lg"></div>
</template> </template>
</SidebarLayout> </SidebarLayout>
</template> </template>
@ -29,6 +28,7 @@ import SidebarLayout from "@/layouts/Sidebar.vue";
import SidebarTemplate from "@/templates/Sidebar.vue"; import SidebarTemplate from "@/templates/Sidebar.vue";
import RoutingLink from "@/components/admin/RoutingLink.vue"; import RoutingLink from "@/components/admin/RoutingLink.vue";
import { useAbilityStore } from "../../stores/ability"; import { useAbilityStore } from "../../stores/ability";
import RouterView from "../RouterView.vue";
</script> </script>
<script lang="ts"> <script lang="ts">
@ -40,44 +40,21 @@ export default defineComponent({
}, },
}, },
computed: { computed: {
...mapState(useNavigationStore, [ ...mapState(useNavigationStore, ["activeNavigationObject", "activeTopLevelObject", "activeLink"]),
"activeNavigationObject",
"activeTopLevelObject",
"activeLink",
"componentOverwrite",
]),
display(): boolean {
return this.activeLink?.component || this.componentOverwrite;
},
displayed() {
if (this.componentOverwrite != null) {
return this.componentOverwrite;
} else {
return this.activeLink?.component;
}
},
}, },
created() { created() {
useAbilityStore().$subscribe(() => { useAbilityStore().$subscribe(() => {
this.updateTopLevel(); this.updateTopLevel();
this.updateNavigation(); this.updateNavigation();
}); });
this.updateTopLevel(); this.updateTopLevel(true);
this.updateNavigation(); this.updateNavigation(true);
this.setLink(this.activeTopLevelObject.levelDefault);
}, },
beforeUnmount() { beforeUnmount() {
this.resetNavigation(); this.resetNavigation();
}, },
methods: { methods: {
...mapActions(useNavigationStore, [ ...mapActions(useNavigationStore, ["resetNavigation", "updateTopLevel", "updateNavigation"]),
"setLink",
"resetNavigation",
"setTopLevel",
"updateTopLevel",
"updateNavigation",
]),
}, },
}); });
</script> </script>

View file

@ -0,0 +1,3 @@
<template>
<div class="w-full h-full bg-white rounded-md flex items-center justify-center">bitte auswählen</div>
</template>