Files
InvoiceShelf/resources/scripts-v2/router/guards.ts
Darko Gjorgjijoski 812956abcc Phase 5-6: Router, plugins, entry points — scripts-v2 complete
13 files completing the TypeScript migration:
- router/ (3 files): typed guards, route meta augmentation,
  merged feature routes from all 16 modules
- plugins/ (4 files): i18n with dynamic locale loading, pinia,
  tooltip directive
- Entry points: main.ts, InvoiceShelf.ts bootstrap class,
  App.vue, global-components.ts with typed registration
- NoCompanyView and NotFoundView stubs

scripts-v2/ totals: 324 files, 42853 lines of strict TypeScript.
Zero any types. Complete feature-based architecture with typed
stores, API services, composables, and Vue components.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 08:00:00 +02:00

84 lines
2.4 KiB
TypeScript

import type { NavigationGuardWithThis, RouteLocationNormalized } from 'vue-router'
import { useUserStore } from '../stores/user.store'
import { useGlobalStore } from '../stores/global.store'
import { useCompanyStore } from '../stores/company.store'
/**
* Main authentication and authorization guard.
*
* Handles:
* - Redirecting to the no-company view when no company is selected
* (unless in admin mode or the user is a super admin visiting a
* super-admin-only route).
* - Ability-based access control: redirects to account settings when
* the current user lacks the required ability.
* - Super admin route protection: redirects non-super-admins to the
* dashboard.
* - Owner route protection: redirects non-owners to the dashboard.
*/
export const authGuard: NavigationGuardWithThis<undefined> = (
to: RouteLocationNormalized
) => {
const userStore = useUserStore()
const globalStore = useGlobalStore()
const companyStore = useCompanyStore()
const { isAppLoaded } = globalStore
const ability = to.meta.ability
// Guard 1: no company selected -> redirect to no-company view
// Skip if the target IS the no-company view, or if we are in admin
// mode, or if the route is super-admin-only and the user qualifies.
if (isAppLoaded && to.meta.requiresAuth && to.name !== 'no.company') {
const isSuperAdminRoute =
to.meta.isSuperAdmin === true &&
currentUserIsSuperAdmin(userStore)
if (
!companyStore.selectedCompany &&
!companyStore.isAdminMode &&
!isSuperAdminRoute
) {
return { name: 'no.company' }
}
}
// Guard 2: ability check
if (ability && isAppLoaded && to.meta.requiresAuth) {
if (!userStore.hasAbilities(ability)) {
return { name: 'settings.account' }
}
return
}
// Guard 3: super admin check
if (to.meta.isSuperAdmin && isAppLoaded) {
if (!currentUserIsSuperAdmin(userStore)) {
return { name: 'dashboard' }
}
return
}
// Guard 4: owner check
if (to.meta.isOwner && isAppLoaded) {
if (!currentUserIsOwner(userStore)) {
return { name: 'dashboard' }
}
return
}
}
// ---- helpers ----
function currentUserIsSuperAdmin(
userStore: ReturnType<typeof useUserStore>
): boolean {
return userStore.currentUser?.is_super_admin ?? false
}
function currentUserIsOwner(
userStore: ReturnType<typeof useUserStore>
): boolean {
return userStore.currentUser?.is_owner ?? false
}