docs(ui): Add UI layout refactor plan and OpenSpec changes
- Update decision-log with UI layout decisions (Feb 18, 2026) - Update architecture with frontend layout patterns - Update config.yaml with TDD, documentation, UI standards rules - Create p00-api-documentation change (Scribe annotations) - Create p01-ui-foundation change (types, stores, Lucide) - Create p02-app-layout change (AppLayout, Sidebar, TopBar) - Create p03-dashboard-enhancement change (PageHeader, StatCard) - Create p04-content-patterns change (DataTable, FilterBar) - Create p05-page-migrations change (page migrations) - Fix E2E auth tests (11/11 passing) - Add JWT expiry validation to dashboard guard
This commit is contained in:
@@ -2,15 +2,25 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { isAuthenticated } from '$lib/stores/auth';
|
||||
import { browser } from '$app/environment';
|
||||
import { page } from '$app/stores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
// Redirect based on auth state
|
||||
$: if (browser) {
|
||||
if ($isAuthenticated) {
|
||||
goto('/dashboard');
|
||||
} else {
|
||||
goto('/login');
|
||||
// Only redirect when actually on the root page, not during navigation
|
||||
onMount(() => {
|
||||
if (browser) {
|
||||
const unsubscribe = isAuthenticated.subscribe((authenticated) => {
|
||||
// Only redirect if we're actually on the root page
|
||||
if ($page.url.pathname === '/') {
|
||||
if (authenticated) {
|
||||
goto('/dashboard');
|
||||
} else {
|
||||
goto('/login');
|
||||
}
|
||||
}
|
||||
});
|
||||
return unsubscribe;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-center min-h-screen">
|
||||
|
||||
5
frontend/src/routes/dashboard/+layout.svelte
Normal file
5
frontend/src/routes/dashboard/+layout.svelte
Normal file
@@ -0,0 +1,5 @@
|
||||
<script lang="ts">
|
||||
let { children }: { children: import('svelte').Snippet } = $props();
|
||||
</script>
|
||||
|
||||
{@render children()}
|
||||
@@ -1,17 +1,21 @@
|
||||
import { browser } from '$app/environment';
|
||||
import { goto } from '$app/navigation';
|
||||
import { getAccessToken } from '$lib/services/api';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { clearTokens, getAccessToken, isJwtExpired, isValidJwtFormat } from '$lib/services/api';
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const ssr = false;
|
||||
|
||||
export const load: LayoutLoad = async () => {
|
||||
// Check authentication on client side using localStorage (source of truth)
|
||||
if (browser) {
|
||||
const token = getAccessToken();
|
||||
|
||||
if (!token) {
|
||||
goto('/login');
|
||||
return { authenticated: false };
|
||||
}
|
||||
if (!browser) {
|
||||
return { authenticated: false };
|
||||
}
|
||||
|
||||
const token = getAccessToken();
|
||||
const isAuthenticated = Boolean(token && isValidJwtFormat(token) && !isJwtExpired(token));
|
||||
|
||||
if (!isAuthenticated) {
|
||||
clearTokens();
|
||||
throw redirect(307, '/login');
|
||||
}
|
||||
|
||||
return { authenticated: true };
|
||||
|
||||
Reference in New Issue
Block a user