Extrahiere Sidebar-Routen-Logik in Composable und entferne toten Counter-Store
Layout.vue trug die Sidebar-Filterlogik (Visibility/Rolle/Pfadabgleich) inline. Sie liegt jetzt in composables/useSidebarRoutes.ts; Layout.vue verliert ~85 Zeilen Skript ohne Verhaltensänderung. Der ungenutzte stores/counter.ts (Vite-Boilerplate) wird entfernt.
This commit is contained in:
+3
-87
@@ -5,12 +5,11 @@ import { useDisplay, useTheme } from 'vuetify'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
import iconImage from '@/assets/images/icon.svg'
|
import iconImage from '@/assets/images/icon.svg'
|
||||||
import { Visibility, routes } from '@/plugins/routesLayout'
|
import { useSidebarRoutes } from '@/composables/useSidebarRoutes'
|
||||||
|
import { routes } from '@/plugins/routesLayout'
|
||||||
import {
|
import {
|
||||||
AuthRequestError,
|
AuthRequestError,
|
||||||
ROLE_ADMIN,
|
|
||||||
fetchCurrentUser,
|
fetchCurrentUser,
|
||||||
hasRole,
|
|
||||||
logout,
|
logout,
|
||||||
type CurrentUser,
|
type CurrentUser,
|
||||||
} from '@/services/authSession'
|
} from '@/services/authSession'
|
||||||
@@ -28,90 +27,7 @@ const isLoggingOut = ref(false)
|
|||||||
const appBannersStore = useAppBannersStore()
|
const appBannersStore = useAppBannersStore()
|
||||||
const { banners } = storeToRefs(appBannersStore)
|
const { banners } = storeToRefs(appBannersStore)
|
||||||
|
|
||||||
function normalizeRoutePath(path: string) {
|
const { adminSidebarRoutes, primarySidebarRoutes, footerRoutes } = useSidebarRoutes(currentUser)
|
||||||
if (!path || path === '/') {
|
|
||||||
return '/'
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.endsWith('/') ? path.slice(0, -1) : path
|
|
||||||
}
|
|
||||||
|
|
||||||
function isWithinRoutePath(currentPath: string, targetPath: string) {
|
|
||||||
const normalizedCurrentPath = normalizeRoutePath(currentPath)
|
|
||||||
const normalizedTargetPath = normalizeRoutePath(targetPath)
|
|
||||||
|
|
||||||
if (normalizedTargetPath === '/') {
|
|
||||||
return normalizedCurrentPath === '/'
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
normalizedCurrentPath === normalizedTargetPath ||
|
|
||||||
normalizedCurrentPath.startsWith(`${normalizedTargetPath}/`)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveVisibilityRoutes(path: string, visibilityRoute?: string | string[]) {
|
|
||||||
if (Array.isArray(visibilityRoute)) {
|
|
||||||
return visibilityRoute.map((entry) => entry.trim()).filter((entry) => entry.length > 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizedVisibilityRoute = visibilityRoute?.trim()
|
|
||||||
if (normalizedVisibilityRoute && normalizedVisibilityRoute.length > 0) {
|
|
||||||
return [normalizedVisibilityRoute]
|
|
||||||
}
|
|
||||||
|
|
||||||
return [path]
|
|
||||||
}
|
|
||||||
|
|
||||||
const sidebarRoutes = computed(() =>
|
|
||||||
routes.filter((item) => {
|
|
||||||
if (item.visible === Visibility.Public) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.visible === Visibility.Authenticated) {
|
|
||||||
return currentUser.value !== null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.visible === Visibility.Unauthenticated) {
|
|
||||||
return currentUser.value === null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.visible === Visibility.Authorized) {
|
|
||||||
if (!currentUser.value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item.requiredRoles || item.requiredRoles.length === 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return item.requiredRoles.every((role) => hasRole(currentUser.value, role))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.visible !== Visibility.Route) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolveVisibilityRoutes(item.path, item.visibilityRoute).some((targetPath) =>
|
|
||||||
isWithinRoutePath(route.path, targetPath),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
const adminSidebarRoutes = computed(() =>
|
|
||||||
sidebarRoutes.value.filter(
|
|
||||||
(item) =>
|
|
||||||
item.visible === Visibility.Authorized &&
|
|
||||||
Array.isArray(item.requiredRoles) &&
|
|
||||||
item.requiredRoles.some((role) => role.trim().toLowerCase() === ROLE_ADMIN),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
const primarySidebarRoutes = computed(() =>
|
|
||||||
sidebarRoutes.value.filter(
|
|
||||||
(item) => !adminSidebarRoutes.value.some((adminItem) => adminItem.path === item.path),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
const footerRoutes = computed(() => routes.filter((x) => x.visible === Visibility.Footer))
|
|
||||||
|
|
||||||
const activeRoute = computed(() => {
|
const activeRoute = computed(() => {
|
||||||
const byName = routes.find((x) => x.meta?.name === route.name)
|
const byName = routes.find((x) => x.meta?.name === route.name)
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { computed, type Ref } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
import { Visibility, routes, type LayoutRoute } from '@/plugins/routesLayout'
|
||||||
|
import { ROLE_ADMIN, hasRole, type CurrentUser } from '@/services/authSession'
|
||||||
|
|
||||||
|
function normalizeRoutePath(path: string) {
|
||||||
|
if (!path || path === '/') {
|
||||||
|
return '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.endsWith('/') ? path.slice(0, -1) : path
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWithinRoutePath(currentPath: string, targetPath: string) {
|
||||||
|
const normalizedCurrent = normalizeRoutePath(currentPath)
|
||||||
|
const normalizedTarget = normalizeRoutePath(targetPath)
|
||||||
|
|
||||||
|
if (normalizedTarget === '/') {
|
||||||
|
return normalizedCurrent === '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
normalizedCurrent === normalizedTarget ||
|
||||||
|
normalizedCurrent.startsWith(`${normalizedTarget}/`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveVisibilityRoutes(path: string, visibilityRoute?: string | string[]) {
|
||||||
|
if (Array.isArray(visibilityRoute)) {
|
||||||
|
return visibilityRoute.map((entry) => entry.trim()).filter((entry) => entry.length > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = visibilityRoute?.trim()
|
||||||
|
if (normalized && normalized.length > 0) {
|
||||||
|
return [normalized]
|
||||||
|
}
|
||||||
|
|
||||||
|
return [path]
|
||||||
|
}
|
||||||
|
|
||||||
|
function isVisible(item: LayoutRoute, currentPath: string, user: CurrentUser | null) {
|
||||||
|
switch (item.visible) {
|
||||||
|
case Visibility.Public:
|
||||||
|
return true
|
||||||
|
case Visibility.Authenticated:
|
||||||
|
return user !== null
|
||||||
|
case Visibility.Unauthenticated:
|
||||||
|
return user === null
|
||||||
|
case Visibility.Authorized:
|
||||||
|
if (!user) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!item.requiredRoles || item.requiredRoles.length === 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return item.requiredRoles.every((role) => hasRole(user, role))
|
||||||
|
case Visibility.Route:
|
||||||
|
return resolveVisibilityRoutes(item.path, item.visibilityRoute).some((target) =>
|
||||||
|
isWithinRoutePath(currentPath, target),
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAdminRoute(item: LayoutRoute) {
|
||||||
|
return (
|
||||||
|
item.visible === Visibility.Authorized &&
|
||||||
|
Array.isArray(item.requiredRoles) &&
|
||||||
|
item.requiredRoles.some((role) => role.trim().toLowerCase() === ROLE_ADMIN)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSidebarRoutes(currentUser: Ref<CurrentUser | null>) {
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const sidebarRoutes = computed(() =>
|
||||||
|
routes.filter((item) => isVisible(item, route.path, currentUser.value)),
|
||||||
|
)
|
||||||
|
|
||||||
|
const adminSidebarRoutes = computed(() => sidebarRoutes.value.filter(isAdminRoute))
|
||||||
|
|
||||||
|
const primarySidebarRoutes = computed(() =>
|
||||||
|
sidebarRoutes.value.filter((item) => !isAdminRoute(item)),
|
||||||
|
)
|
||||||
|
|
||||||
|
const footerRoutes = computed(() =>
|
||||||
|
routes.filter((item) => item.visible === Visibility.Footer),
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
sidebarRoutes,
|
||||||
|
adminSidebarRoutes,
|
||||||
|
primarySidebarRoutes,
|
||||||
|
footerRoutes,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { ref, computed } from 'vue'
|
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
|
|
||||||
export const useCounterStore = defineStore('counter', () => {
|
|
||||||
const count = ref(0)
|
|
||||||
const doubleCount = computed(() => count.value * 2)
|
|
||||||
function increment() {
|
|
||||||
count.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
return { count, doubleCount, increment }
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user