From e9d94f706c740a42585bd39d2e725a37f61a86db Mon Sep 17 00:00:00 2001 From: Sami Abuzakuk Date: Sat, 1 Nov 2025 16:05:52 +0100 Subject: [PATCH] Add frontend support for user --- frontend/src/lib/api.ts | 132 +++++++++++++----- frontend/src/routes/+layout.svelte | 73 +++++++--- frontend/src/routes/login/+page.svelte | 91 ++++++++++++ .../src/routes/notifications/+page.server.ts | 12 -- .../src/routes/notifications/+page.svelte | 74 ++++++++-- .../[subscription_id]/+page.server.ts | 18 --- .../[subscription_id]/+page.svelte | 38 +++-- .../notifications/[subscription_id]/+page.ts | 23 +++ frontend/src/routes/register/+page.svelte | 86 ++++++++++++ frontend/src/routes/scripts/+page.server.js | 12 -- frontend/src/routes/scripts/+page.svelte | 24 ++-- .../src/routes/scripts/[id]/+page.server.ts | 22 --- frontend/src/routes/scripts/[id]/+page.svelte | 108 +++++--------- frontend/src/routes/settings/+page.svelte | 93 ++++++------ 14 files changed, 521 insertions(+), 285 deletions(-) create mode 100644 frontend/src/routes/login/+page.svelte delete mode 100644 frontend/src/routes/notifications/+page.server.ts delete mode 100644 frontend/src/routes/notifications/[subscription_id]/+page.server.ts create mode 100644 frontend/src/routes/notifications/[subscription_id]/+page.ts create mode 100644 frontend/src/routes/register/+page.svelte delete mode 100644 frontend/src/routes/scripts/+page.server.js delete mode 100644 frontend/src/routes/scripts/[id]/+page.server.ts diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 6e85cde..e502526 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -2,6 +2,56 @@ import { env } from '$env/dynamic/public'; export const API_URL = env.PUBLIC_API_URL || 'http://localhost:8000'; +// Helper to get token from localStorage +export function getToken(): string | null { + return localStorage.getItem('token'); +} + +// Helper to add Authorization header if token exists +export function authHeaders(headers: Record = {}): Record { + const token = getToken(); + return token ? { ...headers, Authorization: `Bearer ${token}` } : headers; +} + +/** + * Login and Register API + */ +export interface AuthResponse { + access_token: string; + token_type: string; +} + +export async function login(username: string, password: string): Promise { + const form = new FormData(); + form.append('username', username); + form.append('password', password); + + const response = await fetch(`${API_URL}/login`, { + method: 'POST', + body: form + }); + if (!response.ok) { + const data = await response.json(); + throw new Error(data.detail || 'Login failed'); + } + return response.json(); +} + +export async function register(username: string, password: string): Promise { + const response = await fetch(`${API_URL}/register`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ username, password }) + }); + if (!response.ok) { + const data = await response.json(); + throw new Error(data.detail || 'Registration failed'); + } + return response.json(); +} + /** * Type definitions for Subscriptions and Notifications */ @@ -67,7 +117,9 @@ export interface Script { // Fetch all scripts export async function fetchScripts(): Promise { - const response = await fetch(`${API_URL}/script`); + const response = await fetch(`${API_URL}/script`, { + headers: authHeaders() + }); if (!response.ok) { throw new Error('Failed to fetch scripts ' + response.statusText); } @@ -80,9 +132,7 @@ export async function addScript( ): Promise @@ -41,29 +64,37 @@
Project Monitor
- Scripts - Notifications - - - + {#if isAuthenticated} + Scripts + Notifications + + + + + {:else} + Login + Register + {/if}
- {@render children()} + {#if isAuthenticated || page.url.pathname === '/login' || page.url.pathname === '/register'} + {@render children()} + {/if} +
-
- {#each notifications as notification (notification.id)} -
- {notification.message} -
- {/each} -
+
+ {#each notifications as notification (notification.id)} +
+ {notification.message} +
+ {/each}
diff --git a/frontend/src/routes/login/+page.svelte b/frontend/src/routes/login/+page.svelte new file mode 100644 index 0000000..45df626 --- /dev/null +++ b/frontend/src/routes/login/+page.svelte @@ -0,0 +1,91 @@ + + +
+
+

Login

+ {#if loginError} +
{loginError}
+ {/if} +
+ + +
+
+ + +
+
+ + + Create an account + +
+
+
diff --git a/frontend/src/routes/notifications/+page.server.ts b/frontend/src/routes/notifications/+page.server.ts deleted file mode 100644 index c5dcdc6..0000000 --- a/frontend/src/routes/notifications/+page.server.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { fetchSubscriptions } from '$lib/api'; -import type { PageServerLoad } from './$types'; - -export const load: PageServerLoad = async () => { - try { - const subscriptions = await fetchSubscriptions(); - return { subscriptions }; - } catch (error) { - console.error('Failed to load subscriptions:', error); - return { subscriptions: [] }; - } -}; diff --git a/frontend/src/routes/notifications/+page.svelte b/frontend/src/routes/notifications/+page.svelte index 945dec6..1a00675 100644 --- a/frontend/src/routes/notifications/+page.svelte +++ b/frontend/src/routes/notifications/+page.svelte @@ -1,10 +1,25 @@
-

Notifications for {data.subscription.topic}:

+

Notifications for {subscription.topic}:

← Return to Subscriptions
- @@ -141,7 +139,7 @@
diff --git a/frontend/src/routes/notifications/[subscription_id]/+page.ts b/frontend/src/routes/notifications/[subscription_id]/+page.ts new file mode 100644 index 0000000..0e0c377 --- /dev/null +++ b/frontend/src/routes/notifications/[subscription_id]/+page.ts @@ -0,0 +1,23 @@ +import type { PageLoad } from './$types'; +import { getSubscription, fetchSubscriptionNotifications } from '$lib/api'; + +export const load: PageLoad = async ({ params }) => { + if (import.meta.env.SSR) { + return { + subscription: null, + notifications: [] + }; + } else { + const subscription_id = params.subscription_id; + + const subscription = await getSubscription(subscription_id); + const notifications = (await fetchSubscriptionNotifications(subscription_id)).sort( + (a, b) => new Date(b.created_at!).getTime() - new Date(a.created_at!).getTime() + ); + + return { + subscription: subscription, + notifications: notifications + }; + } +}; diff --git a/frontend/src/routes/register/+page.svelte b/frontend/src/routes/register/+page.svelte new file mode 100644 index 0000000..556a7ea --- /dev/null +++ b/frontend/src/routes/register/+page.svelte @@ -0,0 +1,86 @@ + + +
+
+

Register

+ {#if error} +
{error}
+ {/if} +
+ + +
+
+ + +
+
+ + + Already have an account? + +
+
+
diff --git a/frontend/src/routes/scripts/+page.server.js b/frontend/src/routes/scripts/+page.server.js deleted file mode 100644 index 37dfa45..0000000 --- a/frontend/src/routes/scripts/+page.server.js +++ /dev/null @@ -1,12 +0,0 @@ -import { error } from '@sveltejs/kit'; -import { fetchScripts } from '$lib/api'; - -/** @type {import('./$types').PageServerLoad} */ -export async function load() { - try { - const scripts = await fetchScripts(); - return { scripts }; - } catch (err) { - throw error(500, 'Failed to fetch scripts - ' + err); - } -} diff --git a/frontend/src/routes/scripts/+page.svelte b/frontend/src/routes/scripts/+page.svelte index e56b76f..f776c1d 100644 --- a/frontend/src/routes/scripts/+page.svelte +++ b/frontend/src/routes/scripts/+page.svelte @@ -1,19 +1,27 @@