179 lines
4.9 KiB
TypeScript
Raw Normal View History

2026-01-24 22:59:20 +00:00
import { createRouter, createWebHistory } from 'vue-router'
import { useAppStore } from '../stores/app'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: () => import('../views/OnboardingWrapper.vue'),
meta: { public: true },
children: [
{
path: '',
redirect: (_to) => {
2026-01-24 22:59:20 +00:00
// Initial routing logic - determines first screen after splash
const devMode = import.meta.env.VITE_DEV_MODE
const seenOnboarding = localStorage.getItem('neode_onboarding_complete') === '1'
// const isSetup = localStorage.getItem('neode_setup_complete') === '1'
2026-01-24 22:59:20 +00:00
// Setup mode: go directly to login (original StartOS setup)
if (devMode === 'setup') {
return '/login'
2026-01-24 22:59:20 +00:00
}
// Onboarding mode: go to experimental onboarding flow
if (devMode === 'onboarding') {
return seenOnboarding ? '/login' : '/onboarding/intro'
}
// Existing user mode: go to login
if (devMode === 'existing') {
return '/login'
}
// Default: check if user has completed onboarding
return seenOnboarding ? '/login' : '/onboarding/intro'
},
},
{
path: 'login',
name: 'login',
component: () => import('../views/Login.vue'),
},
{
path: 'onboarding/intro',
name: 'onboarding-intro',
component: () => import('../views/OnboardingIntro.vue'),
},
{
path: 'onboarding/options',
name: 'onboarding-options',
component: () => import('../views/OnboardingOptions.vue'),
},
{
path: 'onboarding/path',
name: 'onboarding-path',
component: () => import('../views/OnboardingPath.vue'),
},
{
path: 'onboarding/did',
name: 'onboarding-did',
component: () => import('../views/OnboardingDid.vue'),
},
{
path: 'onboarding/backup',
name: 'onboarding-backup',
component: () => import('../views/OnboardingBackup.vue'),
},
{
path: 'onboarding/verify',
name: 'onboarding-verify',
component: () => import('../views/OnboardingVerify.vue'),
},
{
path: 'onboarding/done',
name: 'onboarding-done',
component: () => import('../views/OnboardingDone.vue'),
},
],
},
{
path: '/dashboard',
component: () => import('../views/Dashboard.vue'),
children: [
{
path: '',
name: 'home',
component: () => import('../views/Home.vue'),
},
{
path: 'apps',
name: 'apps',
component: () => import('../views/Apps.vue'),
},
{
path: 'apps/:id',
name: 'app-details',
component: () => import('../views/AppDetails.vue'),
},
{
path: 'marketplace',
name: 'marketplace',
component: () => import('../views/Marketplace.vue'),
},
{
path: 'marketplace/:id',
name: 'marketplace-app-detail',
component: () => import('../views/MarketplaceAppDetails.vue'),
},
{
path: 'cloud',
name: 'cloud',
component: () => import('../views/Cloud.vue'),
},
{
path: 'cloud/:folderId',
name: 'cloud-folder',
component: () => import('../views/CloudFolder.vue'),
},
{
path: 'server',
name: 'server',
component: () => import('../views/Server.vue'),
},
{
path: 'web5',
name: 'web5',
component: () => import('../views/Web5.vue'),
},
{
path: 'settings',
name: 'settings',
component: () => import('../views/Settings.vue'),
},
],
},
],
})
/**
* Navigation Guard
* Handles authentication and onboarding flow routing
*/
router.beforeEach(async (to, _from, next) => {
const store = useAppStore()
const isPublic = to.meta.public
// Allow all public routes (login, onboarding) without auth check
if (isPublic) {
// If already authenticated and trying to access login, redirect to dashboard
if (to.path === '/login' && store.isAuthenticated) {
next('/dashboard')
return
}
next()
return
}
// Protected routes require authentication
// Check session if not already authenticated
if (!store.isAuthenticated) {
const hasSession = await store.checkSession()
if (hasSession) {
next()
return
}
// No valid session - redirect to login
next('/login')
return
}
// Authenticated user accessing protected route
next()
})
export default router