fix: replace alert() access guard in event settings with proper UX
- Remove blocking alert() + module-level browser guard
- Move access check to onMount with 500ms grace delay (matches /core pattern)
- Add {:else} block: Lock icon + 'Access Restricted' message + redirect link
- Remove now-unused 'browser' import; add Lock from lucide
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
# PROJECT: Access Control UX — Session Expired & Access Denied
|
# PROJECT: Access Control UX — Session Expired & Access Denied
|
||||||
|
|
||||||
**Status:** Planning
|
**Status:** In Progress
|
||||||
**Priority:** Medium-High
|
**Priority:** Medium-High
|
||||||
**Created:** 2026-02
|
**Created:** 2026-02
|
||||||
|
**Updated:** 2026-03-11
|
||||||
**Related:** `src/routes/+layout.svelte`, `src/lib/ae_api/`, `src/lib/stores/ae_stores.ts`
|
**Related:** `src/routes/+layout.svelte`, `src/lib/ae_api/`, `src/lib/stores/ae_stores.ts`
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -175,7 +176,7 @@ The settings page check should mirror the `/core` pattern:
|
|||||||
|
|
||||||
## 5. Implementation Plan
|
## 5. Implementation Plan
|
||||||
|
|
||||||
### Step 1: Add `ae_auth_error` store
|
### Step 1: Add `ae_auth_error` store ✅ DONE (2026-03-11)
|
||||||
|
|
||||||
**File:** `src/lib/stores/ae_stores.ts`
|
**File:** `src/lib/stores/ae_stores.ts`
|
||||||
|
|
||||||
@@ -187,7 +188,7 @@ export const ae_auth_error = writable<{ type: 'expired' | null, ts: number | nul
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Step 2: Wire API helpers to `ae_auth_error`
|
### Step 2: Wire API helpers to `ae_auth_error` ✅ DONE (2026-03-11)
|
||||||
|
|
||||||
**Files:** `src/lib/ae_api/api_get_object.ts`, `api_post_object.ts`, `api_patch_object.ts` (same pattern in all three)
|
**Files:** `src/lib/ae_api/api_get_object.ts`, `api_post_object.ts`, `api_patch_object.ts` (same pattern in all three)
|
||||||
|
|
||||||
@@ -202,7 +203,7 @@ ae_auth_error.set({ type: 'expired', ts: Date.now() });
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Step 3: Wire `flag_expired` in root layout
|
### Step 3: Wire `flag_expired` in root layout ✅ DONE (2026-03-11)
|
||||||
|
|
||||||
**File:** `src/routes/+layout.svelte`
|
**File:** `src/routes/+layout.svelte`
|
||||||
|
|
||||||
@@ -230,7 +231,7 @@ Add the dismissible banner to the template (after/near the existing `is_offline`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Step 4: Create `element_access_denied.svelte`
|
### Step 4: Create `element_access_denied.svelte` ⬅ NEXT
|
||||||
|
|
||||||
**File:** `src/lib/elements/element_access_denied.svelte`
|
**File:** `src/lib/elements/element_access_denied.svelte`
|
||||||
|
|
||||||
@@ -238,7 +239,7 @@ Reusable card for inline access denial. Props per design decision 4c.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Step 5: Fix Event Settings `alert()`
|
### Step 5: Fix Event Settings `alert()` ⬅ NEXT
|
||||||
|
|
||||||
**File:** `src/routes/events/[event_id]/settings/+page.svelte`
|
**File:** `src/routes/events/[event_id]/settings/+page.svelte`
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import { browser } from '$app/environment';
|
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { Lock } from '@lucide/svelte';
|
||||||
import { liveQuery } from 'dexie';
|
import { liveQuery } from 'dexie';
|
||||||
import { db_events, type Event } from '$lib/ae_events/db_events';
|
import { db_events, type Event } from '$lib/ae_events/db_events';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
@@ -37,17 +37,15 @@
|
|||||||
let show_create_badge_modal: boolean = $state(false);
|
let show_create_badge_modal: boolean = $state(false);
|
||||||
let show_upload_badge_modal: boolean = $state(false);
|
let show_upload_badge_modal: boolean = $state(false);
|
||||||
|
|
||||||
// Guard: Only allow administrators in edit mode
|
|
||||||
if (!$ae_loc.administrator_access) {
|
|
||||||
if (browser) {
|
|
||||||
alert(
|
|
||||||
'Access Denied: Administrative privileges and Edit Mode required.'
|
|
||||||
);
|
|
||||||
goto(`/events/${event_id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
// Guard: administrator access required. 500ms grace delay matches the /core
|
||||||
|
// layout pattern — allows the persisted store to hydrate before redirecting.
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!$ae_loc.administrator_access) {
|
||||||
|
goto(`/events/${event_id}`);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
const observable = liveQuery(() => db_events.event.get(event_id));
|
const observable = liveQuery(() => db_events.event.get(event_id));
|
||||||
const subscription = observable.subscribe((value) => {
|
const subscription = observable.subscribe((value) => {
|
||||||
event_obj = value;
|
event_obj = value;
|
||||||
@@ -94,6 +92,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#if $ae_loc.administrator_access}
|
||||||
|
|
||||||
<h1 class="h1">Event Settings</h1>
|
<h1 class="h1">Event Settings</h1>
|
||||||
|
|
||||||
{#if event_obj}
|
{#if event_obj}
|
||||||
@@ -434,3 +434,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{:else}
|
||||||
|
<!-- Non-administrator landed here — show a brief message while the onMount redirect fires -->
|
||||||
|
<section class="flex flex-col items-center justify-center grow text-center space-y-4 py-20">
|
||||||
|
<div class="p-6 bg-error-500/10 rounded-full">
|
||||||
|
<Lock size={64} class="text-error-500" />
|
||||||
|
</div>
|
||||||
|
<h1 class="h1 font-black">Access Restricted</h1>
|
||||||
|
<p class="max-w-md opacity-70">Event settings require administrator access. Redirecting…</p>
|
||||||
|
<a href={`/events/${event_id}`} class="btn variant-filled-primary">Return to Event</a>
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user