diff --git a/app/src/alerts.ts b/app/src/alerts.ts index 46b0502..58d4fa3 100644 --- a/app/src/alerts.ts +++ b/app/src/alerts.ts @@ -1,3 +1,9 @@ +/** + * Shows a simple message dialog, with a 'close' button. It uses a pre-rendered + * dialog element that's globally defined for the whole app. + * @param msg The message to show. + * @returns A promise that resolves when the alert is closed. + */ export function showAlert(msg: string): Promise { const dialog = document.getElementById('alert-dialog') as HTMLDialogElement const messageBox = document.getElementById('alert-dialog-message') as HTMLParagraphElement diff --git a/app/src/apps/classroom_compliance/router.ts b/app/src/apps/classroom_compliance/router.ts new file mode 100644 index 0000000..e2ee707 --- /dev/null +++ b/app/src/apps/classroom_compliance/router.ts @@ -0,0 +1,40 @@ +import { enforceAuth } from '@/router' +import type { RouteRecordRaw } from 'vue-router' + +export function createClassroomComplianceRoutes(): RouteRecordRaw { + return { + path: '/classroom-compliance', + component: () => import('@/apps/classroom_compliance/MainView.vue'), + beforeEnter: [enforceAuth], + children: [ + { + path: '', + component: () => import('@/apps/classroom_compliance/ClassesView.vue'), + }, + { + path: 'classes/:id', + component: () => import('@/apps/classroom_compliance/ClassView.vue'), + props: true, + }, + { + path: 'edit-class', + component: () => import('@/apps/classroom_compliance/EditClassView.vue'), + }, + { + path: 'classes/:classId/students/:studentId', + component: () => import('@/apps/classroom_compliance/StudentView.vue'), + props: true, + }, + { + path: 'classes/:classId/edit-student', + component: () => import('@/apps/classroom_compliance/EditStudentView.vue'), + props: true, + }, + { + path: 'classes/:classId/import-students', + component: () => import('@/apps/classroom_compliance/ImportStudentsView.vue'), + props: true, + }, + ], + } +} diff --git a/app/src/router/index.ts b/app/src/router/index.ts index 6db4a96..f9254f9 100644 --- a/app/src/router/index.ts +++ b/app/src/router/index.ts @@ -1,13 +1,21 @@ -import { createRouter, createWebHistory } from 'vue-router' +import { createRouter, createWebHistory, type RouteLocationNormalized } from 'vue-router' import HomeView from '@/views/HomeView.vue' import LoginView from '@/views/LoginView.vue' import { useAuthStore } from '@/stores/auth' import MyAccountView from '@/views/MyAccountView.vue' +import { createClassroomComplianceRoutes } from '@/apps/classroom_compliance/router' -function enforceAuth() { +/** + * Ensures that only authenticate users can access a route. + * @param to The route the user is navigating to. + * @returns True if the user is authenticated. Otherwise, returns a redirect to + * the login page, so the user can login to access the page. + */ +export function enforceAuth(to: RouteLocationNormalized) { const authStore = useAuthStore() - if (!authStore.state) return '/login' - return true + if (authStore.state) return true + console.log(to.fullPath, to.path) + return '/login?next=' + encodeURIComponent(to.path) } const router = createRouter({ @@ -26,41 +34,7 @@ const router = createRouter({ component: MyAccountView, beforeEnter: [enforceAuth], }, - { - path: '/classroom-compliance', - component: () => import('@/apps/classroom_compliance/MainView.vue'), - beforeEnter: [enforceAuth], - children: [ - { - path: '', - component: () => import('@/apps/classroom_compliance/ClassesView.vue'), - }, - { - path: 'classes/:id', - component: () => import('@/apps/classroom_compliance/ClassView.vue'), - props: true, - }, - { - path: 'edit-class', - component: () => import('@/apps/classroom_compliance/EditClassView.vue'), - }, - { - path: 'classes/:classId/students/:studentId', - component: () => import('@/apps/classroom_compliance/StudentView.vue'), - props: true, - }, - { - path: 'classes/:classId/edit-student', - component: () => import('@/apps/classroom_compliance/EditStudentView.vue'), - props: true, - }, - { - path: 'classes/:classId/import-students', - component: () => import('@/apps/classroom_compliance/ImportStudentsView.vue'), - props: true, - }, - ], - }, + createClassroomComplianceRoutes(), ], }) diff --git a/app/src/views/LoginView.vue b/app/src/views/LoginView.vue index e6f64bb..fc96094 100644 --- a/app/src/views/LoginView.vue +++ b/app/src/views/LoginView.vue @@ -2,7 +2,7 @@ import { AuthenticationAPIClient } from '@/api/auth' import { useAuthStore } from '@/stores/auth' import { ref, type Ref } from 'vue' -import { useRouter } from 'vue-router' +import { useRoute, useRouter } from 'vue-router' interface Credentials { username: string @@ -10,6 +10,7 @@ interface Credentials { } const router = useRouter() +const route = useRoute() const authStore = useAuthStore() const credentials: Ref = ref({ username: '', password: '' }) const apiClient = new AuthenticationAPIClient(authStore) @@ -18,7 +19,11 @@ async function doLogin() { const user = await apiClient.login(credentials.value.username, credentials.value.password).handleErrorsWithAlert() if (user) { authStore.logIn(credentials.value.username, credentials.value.password, user) - await router.replace('/') + if ('next' in route.query && typeof (route.query.next) === 'string') { + await router.replace(route.query.next) + } else { + await router.replace('/') + } } }