Files
familienarchiv/frontend/src/routes/admin/+page.svelte
Marcel daea748a20
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m37s
CI / OCR Service Tests (push) Successful in 32s
CI / OCR Service Tests (pull_request) Successful in 30s
CI / Backend Unit Tests (push) Failing after 2m47s
CI / Unit & Component Tests (pull_request) Failing after 2m29s
CI / Backend Unit Tests (pull_request) Failing after 2m46s
feat(frontend): invite-based registration UI
- Add /register route with invite code prefill, password show/hide
- Add /login?registered=1 success banner
- Add /admin/invites page: list, create, revoke, copy link
- Add Einladungen nav section to admin sidebar (ADMIN_USER perm)
- Add invite error codes to errors.ts
- Add 48 i18n keys across de/en/es
- Update hooks.server.ts to allow public access to invite/register API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 01:01:19 +02:00

79 lines
2.6 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
import { goto } from '$app/navigation';
import { onMount } from 'svelte';
import { m } from '$lib/paraglide/messages.js';
let { data } = $props();
// On desktop/tablet the layout shell with EntityNav is visible.
// On mobile this page IS the entity picker — tapping an entity pushes
// the user to that route so the browser back button returns here.
onMount(() => {
if (window.matchMedia('(min-width: 768px)').matches) {
goto('/admin/users', { replaceState: true });
}
});
</script>
<svelte:head>
<title>{m.page_title_admin()}</title>
</svelte:head>
<!-- Mobile entity picker (md+ viewports redirect to /admin/users on mount) -->
<div class="flex flex-1 flex-col bg-surface">
<div class="border-b border-line px-4 py-4">
<h1 class="font-sans text-lg font-bold text-ink">{m.admin_heading()}</h1>
</div>
<nav class="divide-y divide-line" aria-label={m.admin_heading()}>
{#if data.canManageUsers}
<a href="/admin/users" class="flex items-center justify-between px-4 py-4 hover:bg-muted">
<div>
<div class="font-sans text-sm font-bold text-ink">{m.admin_tab_users()}</div>
<div class="mt-0.5 font-sans text-xs text-ink-3">{data.userCount}</div>
</div>
<span class="text-ink-3"></span>
</a>
{/if}
{#if data.canManagePermissions}
<a href="/admin/groups" class="flex items-center justify-between px-4 py-4 hover:bg-muted">
<div>
<div class="font-sans text-sm font-bold text-ink">{m.admin_tab_groups()}</div>
<div class="mt-0.5 font-sans text-xs text-ink-3">{data.groupCount}</div>
</div>
<span class="text-ink-3"></span>
</a>
{/if}
{#if data.canManageUsers}
<a href="/admin/invites" class="flex items-center justify-between px-4 py-4 hover:bg-muted">
<div>
<div class="font-sans text-sm font-bold text-ink">{m.admin_tab_invites()}</div>
<div class="mt-0.5 font-sans text-xs text-ink-3">{data.inviteCount}</div>
</div>
<span class="text-ink-3"></span>
</a>
{/if}
{#if data.canManageTags}
<a href="/admin/tags" class="flex items-center justify-between px-4 py-4 hover:bg-muted">
<div>
<div class="font-sans text-sm font-bold text-ink">{m.admin_tab_tags()}</div>
<div class="mt-0.5 font-sans text-xs text-ink-3">{data.tagCount}</div>
</div>
<span class="text-ink-3"></span>
</a>
{/if}
{#if data.canRunMaintenance}
<a href="/admin/system" class="flex items-center justify-between px-4 py-4 hover:bg-muted">
<div>
<div class="font-sans text-sm font-bold text-ink">{m.admin_tab_system()}</div>
</div>
<span class="text-ink-3"></span>
</a>
{/if}
</nav>
</div>