Files
scavengerhunt-fe/src/routes/admin/AdminHome.svelte

82 lines
2.8 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 {push} from 'svelte-spa-router'
import {auth} from '../../lib/stores/auth.svelte'
import {apiGetAllHunts} from '../../lib/api/index'
import type {HuntResponse} from '../../lib/api/types'
import StatusBadge from '../../lib/components/StatusBadge.svelte'
import LoadingSpinner from '../../lib/components/LoadingSpinner.svelte'
$effect(() => {
if (!auth.isLoggedIn) push('/login')
if (!auth.isAdmin) push('/')
})
let hunts = $state<HuntResponse[]>([])
let loading = $state(true)
let error = $state('')
$effect(() => {
apiGetAllHunts()
.then(h => { hunts = h })
.catch(e => { error = e instanceof Error ? e.message : 'Failed to load' })
.finally(() => { loading = false })
})
function huntStatus(h: HuntResponse): 'ONGOING' | 'UNSTARTED' | 'CLOSED' {
if (h.isTerminated) return 'CLOSED'
const now = Date.now()
if (now < new Date(h.startDateTime).getTime()) return 'UNSTARTED'
if (now > new Date(h.endDateTime).getTime()) return 'CLOSED'
return 'ONGOING'
}
function formatDate(dt: string) {
return new Date(dt).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })
}
</script>
<div class="p-4 pb-6">
<div class="flex items-center justify-between mb-4">
<h1 class="text-xl font-bold">Hunts</h1>
<button class="btn btn-primary btn-sm" onclick={() => push('/admin/hunt/create')}>
+ New Hunt
</button>
</div>
{#if loading}
<LoadingSpinner />
{:else if error}
<div class="alert alert-error">{error}</div>
{:else if hunts.length === 0}
<div class="text-center py-16 text-base-content/50">
<p class="text-4xl mb-3">📋</p>
<p class="font-medium">No hunts yet</p>
<button class="btn btn-primary mt-4" onclick={() => push('/admin/hunt/create')}>Create First Hunt</button>
</div>
{:else}
<div class="flex flex-col gap-3">
{#each hunts as hunt}
<div class="card bg-base-100 shadow-sm border border-base-200">
<div class="card-body p-4 gap-2">
<div class="flex items-start justify-between gap-2">
<h2 class="font-semibold">{hunt.title}</h2>
<StatusBadge status={huntStatus(hunt)} />
</div>
<p class="text-xs text-base-content/50">
{formatDate(hunt.startDateTime)} {formatDate(hunt.endDateTime)}
</p>
<div class="card-actions justify-end gap-2 mt-1">
<button class="btn btn-outline btn-xs" onclick={() => push(`/admin/hunt/${hunt.id}/review`)}>
Review Photos
</button>
<button class="btn btn-primary btn-xs" onclick={() => push(`/admin/hunt/${hunt.id}`)}>
Manage
</button>
</div>
</div>
</div>
{/each}
</div>
{/if}
</div>