RoundsPage (liste + opret) og RoundDetailPage (/runder/:roundId — redigér, status-overgange, slet, "kopiér denne runde", nestet vinliste-CRUD). Ingen backend-ændringer nødvendige, al CRUD fandtes allerede (opgave 6). 409-fejl fra rundens dato-constraint vises direkte som API'ets fejlbesked i stedet for at duplikere reglen i frontend. To fund fra brugertest, begge rettet: 1. Åbningsdato og bestillingsfrist krævede et tidspunkt (datetime-local) uden reelt behov — skiftet til rene datofelter (dateUtils.ts). Afhentningstidspunktet beholder klokkeslæt. 2. Kun kladde-runder kunne slettes fra UI'et. Lukkede runder kan nu også slettes, når eleveret — samme elevations-mønster som deltager-hård-sletning i del 1 (elevatedToken fra AuthContext). Åbne runder kan fortsat aldrig slettes (håndhævet server-side). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import { useState } from 'react'
|
|
import { NavLink, Outlet } from 'react-router-dom'
|
|
import { ApiError } from './api'
|
|
import { useAuth } from './AuthContext'
|
|
|
|
export function Layout() {
|
|
const { currentUser, logout, isElevated, requestElevation } = useAuth()
|
|
const [elevationError, setElevationError] = useState<string | null>(null)
|
|
|
|
async function handleElevate() {
|
|
setElevationError(null)
|
|
try {
|
|
await requestElevation()
|
|
} catch (err) {
|
|
setElevationError(err instanceof ApiError ? err.message : 'Kunne ikke forhøje rettigheder')
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<nav className="navbar">
|
|
<span className="navbar-brand">Fælles Vinindkøb — Admin</span>
|
|
<div className="navbar-links">
|
|
<NavLink to="/deltagere">Deltagere</NavLink>
|
|
<NavLink to="/runder">Runder</NavLink>
|
|
{currentUser?.is_superadmin &&
|
|
(isElevated ? (
|
|
<span className="elevated-badge" title="Udløber automatisk efter 5 minutter">
|
|
Rettigheder forhøjet ✓
|
|
</span>
|
|
) : (
|
|
<button className="link-button" onClick={handleElevate}>
|
|
Forhøj rettigheder
|
|
</button>
|
|
))}
|
|
{currentUser && (
|
|
<>
|
|
<span className="navbar-user">{currentUser.name}</span>
|
|
<button className="link-button" onClick={logout}>
|
|
Log ud
|
|
</button>
|
|
</>
|
|
)}
|
|
</div>
|
|
</nav>
|
|
{elevationError && <p className="content error">{elevationError}</p>}
|
|
<main className="content">
|
|
<Outlet />
|
|
</main>
|
|
</div>
|
|
)
|
|
}
|