import { watch } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import ChildLayout from '../layout/ChildLayout.vue' import ParentLayout from '../layout/ParentLayout.vue' import ChildrenListView from '../components/shared/ChildrenListView.vue' import ChildView from '../components/child/ChildView.vue' import ParentView from '../components/child/ParentView.vue' import TaskSubNav from '../components/task/TaskSubNav.vue' import ChoreView from '../components/task/ChoreView.vue' import KindnessView from '../components/task/KindnessView.vue' import PenaltyView from '../components/task/PenaltyView.vue' import ChoreEditView from '@/components/task/ChoreEditView.vue' import KindnessEditView from '@/components/task/KindnessEditView.vue' import PenaltyEditView from '@/components/task/PenaltyEditView.vue' import RewardView from '../components/reward/RewardView.vue' import RewardEditView from '@/components/reward/RewardEditView.vue' import ChildEditView from '@/components/child/ChildEditView.vue' import ChoreAssignView from '@/components/child/ChoreAssignView.vue' import KindnessAssignView from '@/components/child/KindnessAssignView.vue' import PenaltyAssignView from '@/components/child/PenaltyAssignView.vue' import RewardAssignView from '@/components/child/RewardAssignView.vue' import NotificationView from '@/components/notification/NotificationView.vue' import AuthLayout from '@/layout/AuthLayout.vue' import Signup from '@/components/auth/Signup.vue' import AuthLanding from '@/components/auth/AuthLanding.vue' import Login from '@/components/auth/Login.vue' import { isUserLoggedIn, isParentAuthenticated, isAuthReady, logoutParent, enforceParentExpiry, } from '../stores/auth' import ParentPinSetup from '@/components/auth/ParentPinSetup.vue' import LandingPage from '@/components/landing/LandingPage.vue' const routes = [ { path: '/auth', component: AuthLayout, children: [ { path: '', name: 'AuthLanding', component: AuthLanding, }, { path: 'signup', name: 'Signup', component: Signup, }, { path: 'login', name: 'Login', component: Login, }, { path: 'verify', name: 'VerifySignup', component: () => import('@/components/auth/VerifySignup.vue'), }, { path: 'forgot-password', name: 'ForgotPassword', component: () => import('@/components/auth/ForgotPassword.vue'), }, { path: 'reset-password', name: 'ResetPassword', component: () => import('@/components/auth/ResetPassword.vue'), }, ], }, { path: '/child', component: ChildLayout, children: [ { path: '', name: 'ChildrenListView', component: ChildrenListView, }, { path: ':id', name: 'ChildView', component: ChildView, props: true, }, ], }, { path: '/parent', component: ParentLayout, meta: { requiresAuth: true }, children: [ { path: '', name: 'ParentChildrenListView', component: ChildrenListView, }, { path: ':id', name: 'ParentView', component: ParentView, props: true, }, { path: 'children/create', name: 'CreateChild', component: ChildEditView, }, { path: ':id/edit', name: 'ChildEditView', component: ChildEditView, props: true, }, { path: 'tasks', component: TaskSubNav, children: [ { path: '', name: 'TaskView', redirect: { name: 'ChoreView' }, }, { path: 'chores', name: 'ChoreView', component: ChoreView, }, { path: 'kindness', name: 'KindnessView', component: KindnessView, }, { path: 'penalties', name: 'PenaltyView', component: PenaltyView, }, ], }, { path: 'tasks/chores/create', name: 'CreateChore', component: ChoreEditView, }, { path: 'tasks/chores/:id/edit', name: 'EditChore', component: ChoreEditView, props: true, }, { path: 'tasks/kindness/create', name: 'CreateKindness', component: KindnessEditView, }, { path: 'tasks/kindness/:id/edit', name: 'EditKindness', component: KindnessEditView, props: true, }, { path: 'tasks/penalties/create', name: 'CreatePenalty', component: PenaltyEditView, }, { path: 'tasks/penalties/:id/edit', name: 'EditPenalty', component: PenaltyEditView, props: true, }, { path: 'rewards', name: 'RewardView', component: RewardView, props: false, }, { path: 'rewards/create', name: 'CreateReward', component: RewardEditView, }, { path: 'rewards/:id/edit', name: 'EditReward', component: RewardEditView, props: true, }, { path: ':id/assign-chores', name: 'ChoreAssignView', component: ChoreAssignView, props: true, }, { path: ':id/assign-kindness', name: 'KindnessAssignView', component: KindnessAssignView, props: true, }, { path: ':id/assign-penalties', name: 'PenaltyAssignView', component: PenaltyAssignView, props: true, }, { path: ':id/assign-rewards', name: 'RewardAssignView', component: RewardAssignView, props: true, }, { path: 'notifications', name: 'NotificationView', component: NotificationView, props: false, }, { path: 'profile', name: 'UserProfile', component: () => import('@/components/profile/UserProfile.vue'), }, { path: 'pin-setup', name: 'ParentPinSetup', component: ParentPinSetup, meta: { requiresAuth: true, allowNoParent: true }, }, ], }, { path: '/', name: 'LandingPage', component: LandingPage, meta: { isPublic: true }, }, ] const router = createRouter({ history: createWebHistory(), routes, scrollBehavior() { return { top: 0, left: 0, behavior: 'smooth' } }, }) // Auth guard router.beforeEach(async (to, from, next) => { if (!isAuthReady.value) { await new Promise((resolve) => { const stop = watch(isAuthReady, (ready) => { if (ready) { stop() resolve(true) } }) }) } // If already logged in and trying to access /auth or landing, redirect to appropriate view // Allow reset-password and verify through even when logged in (valid use-case from profile page) const authBypassRoutes = ['/auth/reset-password', '/auth/verify'] if ( (to.path.startsWith('/auth') || to.path === '/') && isUserLoggedIn.value && !authBypassRoutes.some((p) => to.path.startsWith(p)) ) { if (isParentAuthenticated.value) { return next('/parent') } else { return next('/child') } } // Always allow /auth, landing page, and /parent/pin-setup if (to.path.startsWith('/auth') || to.path === '/' || to.name === 'ParentPinSetup') { return next() } // If not logged in, redirect to landing page if (!isUserLoggedIn.value) { return next('/') } // If parent-authenticated, allow all /parent routes // Enforce expiry first so an elapsed session is caught immediately on navigation enforceParentExpiry() if (isParentAuthenticated.value && to.path.startsWith('/parent')) { return next() } // If not parent-authenticated, allow all /child routes if (!isParentAuthenticated.value && to.path.startsWith('/child')) { return next() } // Otherwise, redirect based on parent authentication if (isParentAuthenticated.value) { return next('/parent') } else { // Ensure parent auth is fully cleared when redirecting away from /parent logoutParent() return next('/child') } }) export default router