Gammel components/new-round.tsx (3364 linjer) slettet, erstattet av
components/ny-runde/ + lib/ny-runde/ -- V0-eksporten (full teknisk spec,
null designføring) ported mot de faktiske backend-kontraktene i
app/routers/rounds.py: Gender-oversettelse, forenklet Tee-form (aldri
CR/Slope til klienten), CourseMeta-discriminated-union for teeoff- vs.
egen-bane, ekte POST /rounds -> sides -> participants-sekvens, ekte
kontosøk/gjeste-oppslag, ekte banesøk inkl. geolokasjon.
Fire bugs funnet og rettet under scratch-verifisering: manglende
forwardRef på TextInput (i selve V0-eksporten), manglende
tee-synk til eierens spillerkort etter banevalg (egen portingsfeil),
manglende Ingen/Alle-hurtigknapp i steg 5 (samme mangel rettet i appen
2026-08-06), og en produksjonsbug oppdaget EKTE brukere etter utrulling:
fetchFacilityCourses() leste responsen fra offisielt banesøk som en rå
array i stedet for {slug,name,courses}-objektet backend faktisk
returnerer -- ga en uendelig "Laster baner..."-hang for enhver runde
startet på en offisiell (teeoff-)bane. Rettet + lagt til reell
feilhåndtering i OfficialCourses (manglet helt, feilen ble tidligere
en stille, ufanget promise-rejection).
Se CHANGELOG.md punkt 41 og 43 for full verifiseringsdetalj.
53 lines
2 KiB
TypeScript
53 lines
2 KiB
TypeScript
"use client"
|
|
|
|
import { cn } from "@/lib/utils"
|
|
import { ArrowLeft, ArrowRight, Loader2 } from "lucide-react"
|
|
|
|
export function FooterBar({
|
|
onBack,
|
|
onNext,
|
|
nextLabel = "Neste",
|
|
nextDisabled,
|
|
backDisabled,
|
|
backLabel = "Tilbake",
|
|
submitting,
|
|
isSubmitStep,
|
|
}: {
|
|
onBack: () => void
|
|
onNext: () => void
|
|
nextLabel?: string
|
|
nextDisabled?: boolean
|
|
backDisabled?: boolean
|
|
backLabel?: string
|
|
submitting?: boolean
|
|
isSubmitStep?: boolean
|
|
}) {
|
|
return (
|
|
<div className="sticky bottom-0 z-10 border-t border-[var(--nr-border)] bg-[var(--nr-surface)]/90 backdrop-blur">
|
|
<div className="mx-auto flex max-w-2xl items-center justify-between gap-3 px-4 py-3">
|
|
<button
|
|
type="button"
|
|
onClick={onBack}
|
|
disabled={backDisabled}
|
|
className="inline-flex min-h-11 items-center gap-2 rounded-lg border border-[var(--nr-border)] bg-[var(--nr-surface)] px-4 text-sm font-medium text-[var(--nr-ink)] transition-colors hover:bg-[var(--nr-surface-2)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/40 disabled:cursor-not-allowed disabled:opacity-40"
|
|
>
|
|
<ArrowLeft className="h-4 w-4" aria-hidden="true" />
|
|
{backLabel}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={onNext}
|
|
disabled={nextDisabled || submitting}
|
|
className={cn(
|
|
"inline-flex min-h-11 items-center gap-2 rounded-lg px-5 text-sm font-semibold transition-colors focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[var(--nr-accent-ring)]/50",
|
|
"bg-[var(--nr-accent)] text-[var(--nr-accent-ink)] hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-40",
|
|
)}
|
|
>
|
|
{submitting ? <Loader2 className="h-4 w-4 animate-spin" aria-hidden="true" /> : null}
|
|
{nextLabel}
|
|
{!submitting && !isSubmitStep ? <ArrowRight className="h-4 w-4" aria-hidden="true" /> : null}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|