/dashboard/settings/flags war nur über einen Link im Leerzustand verlinkt — sobald ein Team einen Flag-Typ hat, verschwand der einzige Weg dorthin. Neuer Navigationspunkt "Einstellungen" im Dashboard-Menü. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBMBfip6BAG8VV9raSf6vu
188 lines
7.9 KiB
Svelte
188 lines
7.9 KiB
Svelte
<script lang="ts">
|
|
import { auth } from '$lib/stores/pocketbase.svelte'
|
|
import { goto } from '$app/navigation'
|
|
import { app } from '$lib/stores/app.svelte'
|
|
import { setTeamContext } from '$lib/stores/teams.svelte'
|
|
import { setEventContext } from '$lib/stores/events.svelte'
|
|
import { setRunContext } from '$lib/stores/runs.svelte'
|
|
import { setRiderContext } from '$lib/stores/riders.svelte'
|
|
import { setTimeContext } from '$lib/stores/times.svelte'
|
|
import { setTrailContext } from '$lib/stores/trails.svelte'
|
|
import { setTrailVersionContext } from '$lib/stores/trailVersions.svelte'
|
|
import { setTrailFlagContext } from '$lib/stores/trailFlags.svelte'
|
|
import { setTrailMarkerContext } from '$lib/stores/trailMarkers.svelte'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Separator } from '@/components/ui/separator'
|
|
import Logo from '$lib/components/Logo.svelte'
|
|
import TeamSwitcher from '$lib/components/TeamSwitcher.svelte'
|
|
import { Home, Calendar, Flag, Timer, LogOut, Menu, X, Moon, Sun, Route, Settings } from 'lucide-svelte'
|
|
import { toggleMode, mode } from 'mode-watcher'
|
|
import { onDestroy, onMount } from 'svelte'
|
|
|
|
let { children } = $props()
|
|
|
|
// Teams MUSS vor den anderen Stores stehen, weil die anderen Stores
|
|
// getTeamContext() im Constructor aufrufen
|
|
const teams = setTeamContext()
|
|
const events = setEventContext()
|
|
const runs = setRunContext()
|
|
const riders = setRiderContext()
|
|
const times = setTimeContext()
|
|
const trails = setTrailContext()
|
|
const trailVersions = setTrailVersionContext()
|
|
const trailFlags = setTrailFlagContext()
|
|
const trailMarkers = setTrailMarkerContext()
|
|
|
|
let isMobileMenuOpen = $state(false)
|
|
|
|
onMount(async () => {
|
|
if (!auth.user) {
|
|
goto('/login', { replaceState: true })
|
|
return
|
|
}
|
|
// Teams zuerst laden, weil die anderen Stores nach team filtern
|
|
await teams.load()
|
|
teams.subscribe()
|
|
await Promise.all([
|
|
events.load(), runs.load(), riders.load(), times.load(),
|
|
trails.load(), trailVersions.load(), trailFlags.load(), trailMarkers.load(),
|
|
])
|
|
events.subscribe()
|
|
runs.subscribe()
|
|
riders.subscribe()
|
|
times.subscribe()
|
|
trails.subscribe()
|
|
trailVersions.subscribe()
|
|
trailFlags.subscribe()
|
|
trailMarkers.subscribe()
|
|
})
|
|
|
|
onDestroy(() => {
|
|
teams.destroy()
|
|
events.destroy()
|
|
runs.destroy()
|
|
riders.destroy()
|
|
times.destroy()
|
|
trails.destroy()
|
|
trailVersions.destroy()
|
|
trailFlags.destroy()
|
|
trailMarkers.destroy()
|
|
})
|
|
|
|
function handleLogout() {
|
|
app.confirm.request({
|
|
title: 'Abmelden?',
|
|
text: 'Möchten Sie sich wirklich abmelden?',
|
|
yes: async () => {
|
|
await auth.logout()
|
|
app.confirm.close()
|
|
goto('/login')
|
|
},
|
|
no: () => app.confirm.close(),
|
|
})
|
|
}
|
|
|
|
const nav = [
|
|
{ href: '/dashboard', icon: Home, label: 'Dashboard' },
|
|
{ href: '/dashboard/events', icon: Calendar, label: 'Events' },
|
|
{ href: '/dashboard/trails', icon: Route, label: 'Trails' },
|
|
{ href: '/dashboard/timing', icon: Timer, label: 'Zeitnahme' },
|
|
{ href: '/dashboard/results', icon: Flag, label: 'Ergebnisse' },
|
|
{ href: '/dashboard/settings/flags', icon: Settings, label: 'Einstellungen' },
|
|
]
|
|
</script>
|
|
|
|
{#if auth.user}
|
|
<div class="min-h-screen bg-background">
|
|
<header class="border-b bg-card">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex h-16 items-center justify-between">
|
|
<div class="flex items-center gap-2">
|
|
<Logo />
|
|
<div class="hidden md:block">
|
|
<TeamSwitcher />
|
|
</div>
|
|
<Button variant="ghost" size="icon" onclick={toggleMode} title="Design wechseln">
|
|
{#if mode.current === 'dark'}
|
|
<Sun class="h-4 w-4" />
|
|
{:else}
|
|
<Moon class="h-4 w-4" />
|
|
{/if}
|
|
</Button>
|
|
</div>
|
|
|
|
<nav class="hidden md:flex items-center gap-1">
|
|
{#each nav as item}
|
|
{@const Icon = item.icon}
|
|
<a
|
|
href={item.href}
|
|
class="inline-flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
|
|
>
|
|
<Icon class="h-4 w-4" />
|
|
<span>{item.label}</span>
|
|
</a>
|
|
{/each}
|
|
</nav>
|
|
|
|
<div class="flex items-center gap-2">
|
|
<div class="hidden md:flex items-center gap-2">
|
|
<div class="text-sm text-right">
|
|
<p class="font-medium leading-tight">{auth.user.name || auth.user.email}</p>
|
|
<p class="text-xs text-muted-foreground leading-tight">{auth.user.email}</p>
|
|
</div>
|
|
<Button variant="ghost" size="icon" onclick={handleLogout} title="Abmelden">
|
|
<LogOut class="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
class="md:hidden"
|
|
onclick={() => (isMobileMenuOpen = !isMobileMenuOpen)}
|
|
title="Menü"
|
|
>
|
|
{#if isMobileMenuOpen}
|
|
<X class="h-4 w-4" />
|
|
{:else}
|
|
<Menu class="h-4 w-4" />
|
|
{/if}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{#if isMobileMenuOpen}
|
|
<div class="md:hidden border-t">
|
|
<nav class="px-2 py-2 space-y-1">
|
|
{#each nav as item}
|
|
{@const Icon = item.icon}
|
|
<a
|
|
href={item.href}
|
|
onclick={() => (isMobileMenuOpen = false)}
|
|
class="flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent"
|
|
>
|
|
<Icon class="h-4 w-4" />
|
|
<span>{item.label}</span>
|
|
</a>
|
|
{/each}
|
|
<Separator class="my-2" />
|
|
<div class="flex items-center justify-between px-3 py-2">
|
|
<div class="text-sm">
|
|
<p class="font-medium leading-tight">{auth.user.name || auth.user.email}</p>
|
|
<p class="text-xs text-muted-foreground leading-tight">{auth.user.email}</p>
|
|
</div>
|
|
<Button variant="ghost" size="icon" onclick={handleLogout}>
|
|
<LogOut class="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
{/if}
|
|
</header>
|
|
|
|
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
{@render children?.()}
|
|
</main>
|
|
</div>
|
|
{/if}
|