|
1 | 1 | <script lang="ts"> |
2 | | - import type { Snippet } from 'svelte'; |
3 | 2 | import { onMount, onDestroy } from 'svelte'; |
4 | | - import { Router, type Route } from "@mateothegreat/svelte5-router"; |
5 | | - import Home from "./routes/Home.svelte"; |
6 | | - import Login from "./routes/Login.svelte"; |
7 | | - import Register from "./routes/Register.svelte"; |
8 | | - import Editor from "./routes/Editor.svelte"; |
9 | | - import AdminEvents from "./routes/admin/AdminEvents.svelte"; |
10 | | - import AdminUsers from "./routes/admin/AdminUsers.svelte"; |
11 | | - import AdminSettings from "./routes/admin/AdminSettings.svelte"; |
12 | | - import AdminSagas from "./routes/admin/AdminSagas.svelte"; |
13 | | - import Settings from "./routes/Settings.svelte"; |
14 | | - import NotificationsPage from "./routes/Notifications.svelte"; |
15 | | - import Privacy from "./routes/Privacy.svelte"; |
| 3 | + import { Router, type Route, goto } from "@mateothegreat/svelte5-router"; |
16 | 4 | import Header from "./components/Header.svelte"; |
17 | 5 | import Footer from "./components/Footer.svelte"; |
18 | 6 | import ToastContainer from "./components/ToastContainer.svelte"; |
19 | | - import ProtectedRoute from "./components/ProtectedRoute.svelte"; |
20 | 7 | import Spinner from "./components/Spinner.svelte"; |
21 | 8 | import ErrorDisplay from "./components/ErrorDisplay.svelte"; |
22 | 9 | import { theme } from './stores/theme'; |
23 | | - import { initializeAuth } from './lib/auth-init'; |
| 10 | + import { initializeAuth, AuthInitializer } from './lib/auth-init'; |
24 | 11 | import { appError } from './stores/errorStore'; |
| 12 | + import { isAuthenticated } from './stores/auth'; |
| 13 | + import { get } from 'svelte/store'; |
| 14 | +
|
| 15 | + // Page components |
| 16 | + import Home from "./routes/Home.svelte"; |
| 17 | + import Login from "./routes/Login.svelte"; |
| 18 | + import Register from "./routes/Register.svelte"; |
| 19 | + import Privacy from "./routes/Privacy.svelte"; |
| 20 | + import Editor from "./routes/Editor.svelte"; |
| 21 | + import Settings from "./routes/Settings.svelte"; |
| 22 | + import Notifications from "./routes/Notifications.svelte"; |
| 23 | + import AdminEvents from "./routes/admin/AdminEvents.svelte"; |
| 24 | + import AdminSagas from "./routes/admin/AdminSagas.svelte"; |
| 25 | + import AdminUsers from "./routes/admin/AdminUsers.svelte"; |
| 26 | + import AdminSettings from "./routes/admin/AdminSettings.svelte"; |
25 | 27 |
|
26 | 28 | // Theme value derived from store with proper cleanup |
27 | 29 | let themeValue = $state('auto'); |
|
50 | 52 | } |
51 | 53 | }); |
52 | 54 |
|
53 | | - // Routes for public pages (no auth required) |
54 | | - const publicRoutes: Route[] = [ |
55 | | - { path: "/", component: homeSnippet }, |
56 | | - { path: "/login", component: loginSnippet }, |
57 | | - { path: "/register", component: registerSnippet }, |
58 | | - { path: "/privacy", component: privacySnippet }, |
59 | | - ]; |
60 | | -
|
61 | | - // Routes for protected pages (auth required) |
62 | | - const protectedRoutes: Route[] = [ |
63 | | - { path: "/editor", component: editorSnippet }, |
64 | | - { path: "/settings", component: settingsSnippet }, |
65 | | - { path: "/notifications", component: notificationsSnippet }, |
66 | | - { path: "/admin/events", component: adminEventsSnippet }, |
67 | | - { path: "/admin/sagas", component: adminSagasSnippet }, |
68 | | - { path: "/admin/users", component: adminUsersSnippet }, |
69 | | - { path: "/admin/settings", component: adminSettingsSnippet }, |
70 | | - { path: "/admin", component: adminEventsSnippet }, |
| 55 | + // Auth hook for protected routes |
| 56 | + const requireAuth = async () => { |
| 57 | + await AuthInitializer.waitForInit(); |
| 58 | + if (!get(isAuthenticated)) { |
| 59 | + const currentPath = window.location.pathname + window.location.search; |
| 60 | + if (currentPath !== '/login' && currentPath !== '/register') { |
| 61 | + sessionStorage.setItem('redirectAfterLogin', currentPath); |
| 62 | + } |
| 63 | + goto('/login'); |
| 64 | + return false; |
| 65 | + } |
| 66 | + return true; |
| 67 | + }; |
| 68 | +
|
| 69 | + // Routes configuration |
| 70 | + const routes: Route[] = [ |
| 71 | + // Public routes |
| 72 | + { path: "/", component: Home }, |
| 73 | + { path: "/login", component: Login }, |
| 74 | + { path: "/register", component: Register }, |
| 75 | + { path: "/privacy", component: Privacy }, |
| 76 | + // Protected routes |
| 77 | + { path: "/editor", component: Editor, hooks: { pre: requireAuth } }, |
| 78 | + { path: "/settings", component: Settings, hooks: { pre: requireAuth } }, |
| 79 | + { path: "/notifications", component: Notifications, hooks: { pre: requireAuth } }, |
| 80 | + { path: "/admin/events", component: AdminEvents, hooks: { pre: requireAuth } }, |
| 81 | + { path: "/admin/sagas", component: AdminSagas, hooks: { pre: requireAuth } }, |
| 82 | + { path: "/admin/users", component: AdminUsers, hooks: { pre: requireAuth } }, |
| 83 | + { path: "/admin/settings", component: AdminSettings, hooks: { pre: requireAuth } }, |
| 84 | + { path: "/admin", component: AdminEvents, hooks: { pre: requireAuth } }, |
71 | 85 | ]; |
72 | | -
|
73 | | - const allRoutes: Route[] = [...publicRoutes, ...protectedRoutes]; |
74 | 86 | </script> |
75 | 87 |
|
76 | | -<!-- Layout wrapper snippet --> |
77 | | -{#snippet layoutWrapper(content: Snippet, isProtected: boolean = false, isFullWidth: boolean = false)} |
78 | | - {#if isProtected} |
79 | | - <ProtectedRoute> |
80 | | - <div class="flex flex-col min-h-screen bg-bg-default dark:bg-dark-bg-default pt-16"> |
81 | | - <Header/> |
82 | | - <div class="flex-grow flex flex-col"> |
83 | | - <ToastContainer/> |
84 | | - <main class={isFullWidth ? "flex-grow" : "flex-grow w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"}> |
85 | | - {@render content()} |
86 | | - </main> |
87 | | - </div> |
88 | | - <Footer/> |
89 | | - </div> |
90 | | - </ProtectedRoute> |
91 | | - {:else} |
92 | | - <div class="flex flex-col min-h-screen bg-bg-default dark:bg-dark-bg-default pt-16"> |
93 | | - <Header/> |
94 | | - <div class="flex-grow flex flex-col"> |
95 | | - <ToastContainer/> |
96 | | - <main class={isFullWidth ? "flex-grow" : "flex-grow w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"}> |
97 | | - {@render content()} |
98 | | - </main> |
99 | | - </div> |
100 | | - <Footer/> |
101 | | - </div> |
102 | | - {/if} |
103 | | -{/snippet} |
104 | | - |
105 | | -<!-- Public route snippets --> |
106 | | -{#snippet homeSnippet()} |
107 | | - {@render layoutWrapper(homeContent, false)} |
108 | | -{/snippet} |
109 | | - |
110 | | -{#snippet homeContent()} |
111 | | - <Home/> |
112 | | -{/snippet} |
113 | | - |
114 | | -{#snippet loginSnippet()} |
115 | | - {@render layoutWrapper(loginContent, false)} |
116 | | -{/snippet} |
117 | | - |
118 | | -{#snippet loginContent()} |
119 | | - <Login/> |
120 | | -{/snippet} |
121 | | - |
122 | | -{#snippet registerSnippet()} |
123 | | - {@render layoutWrapper(registerContent, false)} |
124 | | -{/snippet} |
125 | | - |
126 | | -{#snippet registerContent()} |
127 | | - <Register/> |
128 | | -{/snippet} |
129 | | - |
130 | | -{#snippet privacySnippet()} |
131 | | - {@render layoutWrapper(privacyContent, false)} |
132 | | -{/snippet} |
133 | | - |
134 | | -{#snippet privacyContent()} |
135 | | - <Privacy/> |
136 | | -{/snippet} |
137 | | - |
138 | | -<!-- Protected route snippets --> |
139 | | -{#snippet editorSnippet()} |
140 | | - {@render layoutWrapper(editorContent, true)} |
141 | | -{/snippet} |
142 | | - |
143 | | -{#snippet editorContent()} |
144 | | - <Editor/> |
145 | | -{/snippet} |
146 | | - |
147 | | -{#snippet settingsSnippet()} |
148 | | - {@render layoutWrapper(settingsContent, true)} |
149 | | -{/snippet} |
150 | | - |
151 | | -{#snippet settingsContent()} |
152 | | - <Settings/> |
153 | | -{/snippet} |
154 | | - |
155 | | -{#snippet notificationsSnippet()} |
156 | | - {@render layoutWrapper(notificationsContent, true)} |
157 | | -{/snippet} |
158 | | - |
159 | | -{#snippet notificationsContent()} |
160 | | - <NotificationsPage/> |
161 | | -{/snippet} |
162 | | - |
163 | | -<!-- Admin route snippets (full width) --> |
164 | | -{#snippet adminEventsSnippet()} |
165 | | - {@render layoutWrapper(adminEventsContent, true, true)} |
166 | | -{/snippet} |
167 | | - |
168 | | -{#snippet adminEventsContent()} |
169 | | - <AdminEvents/> |
170 | | -{/snippet} |
171 | | - |
172 | | -{#snippet adminSagasSnippet()} |
173 | | - {@render layoutWrapper(adminSagasContent, true, true)} |
174 | | -{/snippet} |
175 | | - |
176 | | -{#snippet adminSagasContent()} |
177 | | - <AdminSagas/> |
178 | | -{/snippet} |
179 | | - |
180 | | -{#snippet adminUsersSnippet()} |
181 | | - {@render layoutWrapper(adminUsersContent, true, true)} |
182 | | -{/snippet} |
183 | | - |
184 | | -{#snippet adminUsersContent()} |
185 | | - <AdminUsers/> |
186 | | -{/snippet} |
187 | | - |
188 | | -{#snippet adminSettingsSnippet()} |
189 | | - {@render layoutWrapper(adminSettingsContent, true, true)} |
190 | | -{/snippet} |
191 | | - |
192 | | -{#snippet adminSettingsContent()} |
193 | | - <AdminSettings/> |
194 | | -{/snippet} |
195 | | - |
196 | 88 | {#if globalError} |
197 | 89 | <ErrorDisplay error={globalError.error} title={globalError.title} /> |
198 | | -{:else if !authInitialized} |
199 | | - <div class="flex items-center justify-center min-h-screen bg-bg-default dark:bg-dark-bg-default"> |
200 | | - <Spinner size="large" /> |
201 | | - </div> |
202 | 90 | {:else} |
203 | | - <Router base="/" routes={allRoutes} /> |
| 91 | + <div class="flex flex-col min-h-screen bg-bg-default dark:bg-dark-bg-default pt-16"> |
| 92 | + <Header/> |
| 93 | + <div class="flex-grow flex flex-col"> |
| 94 | + <ToastContainer/> |
| 95 | + <main class="flex-grow"> |
| 96 | + {#if !authInitialized} |
| 97 | + <div class="flex items-center justify-center min-h-[50vh]"> |
| 98 | + <Spinner size="large" /> |
| 99 | + </div> |
| 100 | + {:else} |
| 101 | + <Router base="/" {routes} /> |
| 102 | + {/if} |
| 103 | + </main> |
| 104 | + </div> |
| 105 | + <Footer/> |
| 106 | + </div> |
204 | 107 | {/if} |
205 | | - |
206 | | -<style> |
207 | | - /* Styles moved to Tailwind classes */ |
208 | | -</style> |
0 commit comments