Skip to content

Add a Frontend View

Add a new page to the Vue SPA — including the route, the view component, and optional state management.

Step 1 — Create the view component

Create a new file in src/views/. Follow the existing naming convention (PascalCase):

vue
<!-- src/views/Notes.vue -->
<script setup lang="ts">
import { Notes } from '@/api/sdk.gen'
import { useTenant } from '@/stores/tenant.store'

const tenant = useTenant()

const { data, isLoading } = useQuery({
  queryKey: ['notes', tenant.id],
  queryFn: () =>
    Notes.noteControllerFindAll({
      path: { tenantId: tenant.id! },
    }),
  enabled: computed(() => !!tenant.id),
})
</script>

<template>
  <div class="p-4">
    <h1 class="text-xl font-semibold">Notes</h1>
    <p v-if="isLoading">Loading...</p>
    <ul v-else>
      <li v-for="note in data?.data" :key="note.id">{{ note.content }}</li>
    </ul>
  </div>
</template>

Step 2 — Register the route

Open src/router/routes.ts and add the route to the appropriate parent:

typescript
// For a worker-facing page, add to the LayoutApp children:
{ path: 'notes', name: 'notes', component: () => import('@/views/Notes.vue') },

// For an admin page, add to the AdminWrapper children:
{ path: 'notes', name: 'admin-notes', component: () => import('@/views/Admin/Notes.vue') },

Use lazy imports (() => import(...)) for code-splitting — only the route components that exist in the codebase as static imports use eager loading.

Step 3 — Add navigation (optional)

To link to the new view from the sidebar or navigation bar, find the relevant layout component:

  • Worker navigation: src/components/Layout/LayoutApp.vue
  • Admin navigation: src/components/Layout/AdminSidebar.vue (or equivalent)

Add a <RouterLink :to="{ name: 'notes' }"> entry.

Step 4 — Guard with a feature flag (optional)

If the view should only be accessible when a tenant feature is enabled, add a redirect guard in the router or check the store inline:

typescript
// In routes.ts, using a navigation guard
{
  path: 'notes',
  name: 'notes',
  component: () => import('@/views/Notes.vue'),
  beforeEnter: () => {
    const tenant = useTenant()
    if (!tenant.hasProjects) return { name: 'home' }
  },
},

Or check in the component itself using the useTenant() store's computed properties. See Feature Flags for available toggles.

TT Time Tracker — Internal Documentation