Files
Hoard/GUI/src/composables/useSidebarRoutes.ts
T
Claude 2c882fce4a 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.
2026-04-28 10:22:32 +00:00

99 lines
2.7 KiB
TypeScript

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,
}
}