diff --git a/backend/src/handlers/me.rs b/backend/src/handlers/me.rs index 71c1df1..79ecd88 100644 --- a/backend/src/handlers/me.rs +++ b/backend/src/handlers/me.rs @@ -55,6 +55,9 @@ pub struct MeContextDto { pub privacy_note: String, pub quota_enabled: bool, pub storage_quota_enabled: bool, + /// Whether uploads are currently locked for the event, so the client can show + /// a banner + disable the upload affordance on load (not just via SSE). + pub uploads_locked: bool, } pub async fn get_context( @@ -68,6 +71,10 @@ pub async fn get_context( let privacy_note = config::get_str(&state.pool, "privacy_note", "").await; let quota_enabled = config::get_bool(&state.pool, "quota_enabled", true).await; let storage_quota_enabled = config::get_bool(&state.pool, "storage_quota_enabled", true).await; + let uploads_locked = crate::models::event::Event::find_by_slug(&state.pool, &state.config.event_slug) + .await? + .map(|e| e.uploads_locked_at.is_some()) + .unwrap_or(false); Ok(Json(MeContextDto { user_id: user.id, @@ -76,5 +83,6 @@ pub async fn get_context( privacy_note, quota_enabled, storage_quota_enabled, + uploads_locked, })) } diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 2ac3b4b..1d90d9c 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -1,3 +1,5 @@ +import { goto } from '$app/navigation'; +import { browser } from '$app/environment'; import { getToken, clearAuth } from './auth'; const BASE = '/api/v1'; @@ -42,6 +44,11 @@ async function request( if (!res.ok) { if (res.status === 401) { clearAuth(); + // Don't strand the user on a now-unauthenticated page with no nav — + // send them to /join. Guard against loops on the auth screens. + if (browser && !/^\/(join|recover|admin\/login)/.test(window.location.pathname)) { + void goto('/join'); + } } throw new ApiError(res.status, data.error ?? 'unknown', data.message ?? 'Fehler'); } diff --git a/frontend/src/lib/components/BottomNav.svelte b/frontend/src/lib/components/BottomNav.svelte index e92f6b5..b6389f7 100644 --- a/frontend/src/lib/components/BottomNav.svelte +++ b/frontend/src/lib/components/BottomNav.svelte @@ -3,6 +3,7 @@ import { page } from '$app/stores'; import { uploadSheetOpen, uploadBadgeCount } from '$lib/ui-store'; import { exportStatus, initExportStatus } from '$lib/export-status-store'; + import { uploadsLocked } from '$lib/event-state-store'; function isActive(path: string): boolean { return $page.url.pathname.startsWith(path); @@ -43,8 +44,9 @@