feat: add parent PIN setup functionality and email notifications
All checks were successful
Gitea Actions Demo / build-and-push (push) Successful in 23s

- Implemented User model updates to include PIN and related fields.
- Created email sender utility for sending verification and reset emails.
- Developed ParentPinSetup component for setting up a parent PIN with verification code.
- Enhanced UserProfile and EntityEditForm components to support new features.
- Updated routing to include PIN setup and authentication checks.
- Added styles for new components and improved existing styles for consistency.
- Introduced loading states and error handling in various components.
This commit is contained in:
2026-01-27 14:47:49 -05:00
parent cd9070ec99
commit 3066d7d356
19 changed files with 852 additions and 257 deletions

View File

@@ -18,6 +18,7 @@ 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 } from '../stores/auth'
import ParentPinSetup from '@/components/auth/ParentPinSetup.vue'
const routes = [
{
@@ -157,6 +158,12 @@ const routes = [
name: 'UserProfile',
component: () => import('@/components/profile/UserProfile.vue'),
},
{
path: 'pin-setup',
name: 'ParentPinSetup',
component: ParentPinSetup,
meta: { requiresAuth: true, allowNoParent: true },
},
],
},
{
@@ -172,19 +179,12 @@ const router = createRouter({
// 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)
}
})
})
}
console.log('navigating to', to.fullPath, 'from', from.fullPath)
console.log('isParentAuthenticated:', isParentAuthenticated.value)
console.trace()
// Always allow access to /auth routes
if (to.path.startsWith('/auth')) {
// Always allow /auth and /parent/pin-setup
if (to.path.startsWith('/auth') || to.name === 'ParentPinSetup') {
return next()
}
@@ -193,13 +193,22 @@ router.beforeEach(async (to, from, next) => {
return next('/auth')
}
// If logged in but not parent-authenticated, redirect to /child (unless already there)
if (!isParentAuthenticated.value && !to.path.startsWith('/child')) {
return next('/child')
// If parent-authenticated, allow all /parent routes
if (isParentAuthenticated.value && to.path.startsWith('/parent')) {
return next()
}
// Otherwise, allow navigation
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 {
return next('/child')
}
})
export default router