Page MenuHomeDevCentral

D3977.id10316.diff
No OneTemporary

D3977.id10316.diff

diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js
--- a/frontend/src/router/index.js
+++ b/frontend/src/router/index.js
@@ -3,50 +3,57 @@
import { authApi } from '@/plugins/api'
const router = createRouter({
- history: createWebHistory(import.meta.env.BASE_URL),
- routes: [
- {
- path: '/',
- name: 'status',
- component: StatusPage,
- },
- {
- path: '/confirm/:token',
- name: 'confirm-subscription',
- component: () => import('@/views/ConfirmSubscription.vue'),
- },
- {
- path: '/unsubscribe/:token',
- name: 'unsubscribe',
- component: () => import('@/views/Unsubscribe.vue'),
- },
- {
- path: '/admin/login',
- name: 'admin-login',
- component: () => import('@/views/AdminLogin.vue'),
- },
- {
- path: '/admin',
- name: 'admin',
- component: () => import('@/views/AdminDashboard.vue'),
- meta: { requiresAuth: true },
- },
- ],
+ history: createWebHistory(import.meta.env.BASE_URL),
+ routes: [
+ {
+ path: '/',
+ name: 'status',
+ component: StatusPage,
+ },
+ {
+ path: '/confirm/:token',
+ name: 'confirm-subscription',
+ component: () => import('@/views/ConfirmSubscription.vue'),
+ },
+ {
+ path: '/unsubscribe/:token',
+ name: 'unsubscribe',
+ component: () => import('@/views/Unsubscribe.vue'),
+ },
+ {
+ path: '/admin/login',
+ name: 'admin-login',
+ component: () => import('@/views/AdminLogin.vue'),
+ },
+ {
+ path: '/admin',
+ name: 'admin',
+ component: () => import('@/views/AdminDashboard.vue'),
+ meta: { requiresAuth: true },
+ },
+ {
+ path: '/:pathMatch(.*)*',
+ name: 'not-found',
+ component: () => import('@/views/NotFound.vue'),
+ },
+ ],
})
router.beforeEach(async (to) => {
- if (to.meta.requiresAuth) {
- const token = localStorage.getItem('servpulse_token')
- if (!token) {
- return { name: 'admin-login' }
+ if (to.meta.requiresAuth) {
+ const token = localStorage.getItem('servpulse_token')
+ if (!token) {
+ return { name: 'admin-login' }
+ }
+ try {
+ await authApi.verify(token)
+ } catch {
+ localStorage.removeItem('servpulse_token')
+ return { name: 'admin-login' }
+ }
}
- try {
- await authApi.verify(token)
- } catch {
- localStorage.removeItem('servpulse_token')
- return { name: 'admin-login' }
- }
- }
})
export default router
+
+export default router
diff --git a/frontend/src/views/NotFound.vue b/frontend/src/views/NotFound.vue
new file mode 100644
--- /dev/null
+++ b/frontend/src/views/NotFound.vue
@@ -0,0 +1,25 @@
+<template>
+ <div class="min-h-[70vh] flex items-center justify-center px-4">
+ <div class="card p-8 w-full max-w-md text-center">
+
+ <!-- 404 number -->
+ <p class="text-6xl font-bold text-brand-500 mb-4">404</p>
+
+ <!-- Headline -->
+ <h1 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-2">
+ The page you're looking for can't be found.
+ </h1>
+
+ <!-- Subtext -->
+ <p class="text-sm text-gray-500 dark:text-gray-400 mb-6">
+ It may have been moved or deleted.
+ </p>
+
+ <!-- Actions -->
+ <RouterLink to="/" class="btn-primary flex items-center justify-center w-full">
+ Back to Home
+ </RouterLink>
+
+ </div>
+ </div>
+</template>
diff --git a/frontend/src/views/__tests__/NotFound.test.js b/frontend/src/views/__tests__/NotFound.test.js
new file mode 100644
--- /dev/null
+++ b/frontend/src/views/__tests__/NotFound.test.js
@@ -0,0 +1,17 @@
+import { mount } from '@vue/test-utils'
+import { describe, it, expect } from 'vitest'
+import NotFound from '../NotFound.vue'
+
+describe('NotFound.vue', () => {
+ it('renders the 404 message correctly', () => {
+ // We pass a 'global' option to stub out RouterLink safely
+ const wrapper = mount(NotFound, {
+ global: {
+ stubs: ['RouterLink']
+ }
+ })
+
+ expect(wrapper.text()).toContain('404')
+ expect(wrapper.text()).toContain("The page you're looking for can't be found.")
+ })
+})
\ No newline at end of file

File Metadata

Mime Type
text/plain
Expires
Thu, Feb 26, 19:21 (19 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3475342
Default Alt Text
D3977.id10316.diff (4 KB)

Event Timeline