feat: add element_access_denied.svelte; use in badge review page
- New reusable element_access_denied.svelte with title, message, action props - Badge review page: swap inline 'Access Denied' card with the component - Project doc: all 6 steps complete, status → Complete
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# PROJECT: Access Control UX — Session Expired & Access Denied
|
# PROJECT: Access Control UX — Session Expired & Access Denied
|
||||||
|
|
||||||
**Status:** In Progress
|
**Status:** Complete
|
||||||
**Priority:** Medium-High
|
**Priority:** Medium-High
|
||||||
**Created:** 2026-02
|
**Created:** 2026-02
|
||||||
**Updated:** 2026-03-11
|
**Updated:** 2026-03-11
|
||||||
@@ -231,7 +231,7 @@ Add the dismissible banner to the template (after/near the existing `is_offline`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Step 4: Create `element_access_denied.svelte` ⬅ NEXT
|
### Step 4: Create `element_access_denied.svelte` ✅ DONE (2026-03-11)
|
||||||
|
|
||||||
**File:** `src/lib/elements/element_access_denied.svelte`
|
**File:** `src/lib/elements/element_access_denied.svelte`
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ Reusable card for inline access denial. Props per design decision 4c.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Step 5: Fix Event Settings `alert()` ⬅ NEXT
|
### Step 5: Fix Event Settings `alert()` ✅ DONE (2026-03-11)
|
||||||
|
|
||||||
**File:** `src/routes/events/[event_id]/settings/+page.svelte`
|
**File:** `src/routes/events/[event_id]/settings/+page.svelte`
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ Replace the module-level `if (!$ae_loc.administrator_access)` + `alert()` block
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Step 6 (Optional / Low Priority): Swap badge review inline card
|
### Step 6 (Optional / Low Priority): Swap badge review inline card ✅ DONE (2026-03-11)
|
||||||
|
|
||||||
**File:** `src/routes/events/[event_id]/(badges)/badges/[badge_id]/review/+page.svelte`
|
**File:** `src/routes/events/[event_id]/(badges)/badges/[badge_id]/review/+page.svelte`
|
||||||
|
|
||||||
|
|||||||
34
src/lib/elements/element_access_denied.svelte
Normal file
34
src/lib/elements/element_access_denied.svelte
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { ShieldX } from '@lucide/svelte';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title?: string;
|
||||||
|
message?: string;
|
||||||
|
action_label?: string;
|
||||||
|
on_action?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
title = 'Access Denied',
|
||||||
|
message = 'You do not have permission to view this content.',
|
||||||
|
action_label = '',
|
||||||
|
on_action = undefined
|
||||||
|
}: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="card p-6 space-y-4 max-w-sm">
|
||||||
|
<div class="flex items-center gap-2 text-error-500">
|
||||||
|
<ShieldX size="1.2em" />
|
||||||
|
<h3 class="text-lg font-semibold">{title}</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-700">{message}</p>
|
||||||
|
{#if action_label && on_action}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn preset-tonal-surface w-full"
|
||||||
|
onclick={on_action}
|
||||||
|
>
|
||||||
|
{action_label}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
import { ArrowLeft, Check, Link, LoaderCircle, Mail, Printer } from 'lucide-svelte';
|
import { ArrowLeft, Check, Link, LoaderCircle, Mail, Printer } from 'lucide-svelte';
|
||||||
|
|
||||||
import Comp_badge_review_form from '../ae_comp__badge_review_form.svelte';
|
import Comp_badge_review_form from '../ae_comp__badge_review_form.svelte';
|
||||||
|
import Element_access_denied from '$lib/elements/element_access_denied.svelte';
|
||||||
|
|
||||||
let event_badge_id = $derived(page.params.badge_id);
|
let event_badge_id = $derived(page.params.badge_id);
|
||||||
let event_id = $derived(page.params.event_id);
|
let event_id = $derived(page.params.event_id);
|
||||||
@@ -315,19 +316,11 @@
|
|||||||
|
|
||||||
{:else if passcode_checked && !passcode_valid}
|
{:else if passcode_checked && !passcode_valid}
|
||||||
<!-- Invalid passcode -->
|
<!-- Invalid passcode -->
|
||||||
<div class="card p-6 space-y-4 max-w-sm">
|
<Element_access_denied
|
||||||
<div class="flex items-center gap-2 text-error-500">
|
message={passcode_error}
|
||||||
<h3 class="text-lg font-semibold">Access Denied</h3>
|
action_label="Try Again"
|
||||||
</div>
|
on_action={() => { passcode_checked = false; passcode_error = ''; entered_passcode = ''; }}
|
||||||
<p class="text-sm text-gray-700">{passcode_error}</p>
|
/>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn preset-tonal-surface w-full"
|
|
||||||
onclick={() => { passcode_checked = false; passcode_error = ''; entered_passcode = ''; }}
|
|
||||||
>
|
|
||||||
Try Again
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{:else if is_loading_idb || !event_badge_id}
|
{:else if is_loading_idb || !event_badge_id}
|
||||||
|
|||||||
Reference in New Issue
Block a user