Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | 32x 32x 32x 4x 6x 2x 3x 1x 1x 1x 1x 1x 1x 32x 29x 29x 7x 7x 29x 16x 16x 29x 6x 6x 6x 6x 6x 29x 2x 27x 6x 21x | import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useTenantsStore } from '@/stores/tenants'
let userLoaded = false
let tenantsLoaded = false
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: () => import('@/views/HomePage.vue'),
meta: { requiresAuth: true }
},
{
path: '/login',
name: 'login',
component: () => import('@/views/LoginPage.vue')
},
{
path: '/signup',
name: 'signup',
component: () => import('@/views/SignupPage.vue')
},
{
path: '/forgot-password',
name: 'forgot-password',
component: () => import('@/views/ForgotPasswordPage.vue')
},
{
path: '/flows',
name: 'flows',
component: () => import('@/views/TenantsPage.vue'),
meta: { requiresAuth: true }
},
{
path: '/entities',
name: 'entities',
component: () => import('@/views/EntitiesPage.vue'),
meta: { requiresAuth: true }
},
{
path: '/entities/:entityId',
name: 'entity-items',
component: () => import('@/views/EntityItemsPage.vue'),
meta: { requiresAuth: true }
},
{
path: '/members',
name: 'members',
component: () => import('@/views/MembersPage.vue'),
meta: { requiresAuth: true }
},
{
path: '/roles',
name: 'roles',
component: () => import('@/views/RolesPage.vue'),
meta: { requiresAuth: true }
},
{
path: '/invitations',
name: 'invitations',
component: () => import('@/views/InvitationsPage.vue'),
meta: { requiresAuth: true }
},
{
path: '/profile',
name: 'profile',
component: () => import('@/views/UserProfilePage.vue'),
meta: { requiresAuth: true }
},
{
path: '/api-keys',
name: 'api-keys',
component: () => import('@/views/ApiKeysPage.vue'),
meta: { requiresAuth: true }
},
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('@/views/NotFoundPage.vue')
}
]
})
router.beforeEach(async (to, _from, next) => {
const authStore = useAuthStore()
// Reset state flags when user goes to login (e.g. after logout),
// so subsequent logins re-run loadUser + fetchMyTenants + auto-switch
if (to.name === 'login') {
userLoaded = false
tenantsLoaded = false
}
// Load user only once on first navigation
if (!userLoaded) {
await authStore.loadUser()
userLoaded = true
}
// Load tenants once after user is loaded and authenticated
if (authStore.isAuthenticated && !tenantsLoaded) {
const tenantsStore = useTenantsStore()
try {
await tenantsStore.fetchMyTenants()
// Auto-switch to first tenant if no active tenant in JWT
// This handles fresh logins where custom:tenantId is not yet set in the token.
// Prefer a tenant the user owns — otherwise fall back to the first one available.
Iif (!authStore.currentTenant && tenantsStore.myTenants.length > 0) {
const preferredTenant =
tenantsStore.myTenants.find((t) => t.isOwner) ?? tenantsStore.myTenants[0]
if (preferredTenant) {
try {
await tenantsStore.switchTenant(preferredTenant.tenantId)
} catch {
// Switch failed, user can manually select tenant from /flows
}
}
}
} catch {
// fetchMyTenants failing should not block navigation
}
tenantsLoaded = true
}
// If going to login/signup but already authenticated, redirect to home
if ((to.name === 'login' || to.name === 'signup') && authStore.isAuthenticated) {
next({ name: 'home' })
}
// If route requires auth and not authenticated, redirect to login
else if (to.meta.requiresAuth && !authStore.isAuthenticated) {
next({ name: 'login' })
} else {
next()
}
})
export default router
|