Ferdig og live. Oppsummert:
Slag og Putter hopper nå videre av seg selv i det øyeblikket en verdi velges — ingen "Neste"-trykk nødvendig. "Avstand første putt" lå tidligere sammen med putt-tallet på samme steg — auto-hopp der ville gjort feltet uoppnåelig, så det fikk et eget steg (som også auto-hopper). "Flere detaljer"-steget (kølle/retning/chip/bunker/straffeslag/anywayslag) beholder bevisst "Neste"/"Ferdig"-knappen, siden det har flere felt samtidig og ingen entydig "nå er jeg ferdig"-verdi. Gjelder både vanlig scoring og delt-ball-scoring (foursome/greensome/scramble). "Forrige" fungerer fortsatt trygt — går du tilbake til et allerede besvart steg, hopper det ikke automatisk fremover igjen. Browserverifisert i scratch (full flyt gjennom alle steg + tilbake-navigasjon + delt-ball), rullet ut mot ekte systemer — ingen migrasjon, begge containere boot-et rent, teeoff.no upåvirket.
This commit is contained in:
parent
83c4749516
commit
b21609915d
3 changed files with 133 additions and 37 deletions
37
CLAUDE.md
37
CLAUDE.md
|
|
@ -4290,6 +4290,43 @@ Ferdig og verifisert:
|
|||
ingen backend-kode rørt). Begge containere boot-et rent, `/health`/
|
||||
`/dashboard` → 200, `teeoff.no` upåvirket. **ADR-039 er dermed
|
||||
fullstendig ferdig, backend og frontend, live.**
|
||||
- **Auto-hopp i scoringsveiviserne, LIVE (2026-07-28), samme dag:**
|
||||
brukeren ba om at "i det øyeblikket [scoren] nå registreres" skal
|
||||
veiviseren hoppe videre av seg selv, uten å måtte trykke "Neste"/
|
||||
"Ferdig". Presiserende avklaring FØR bygging (AskUserQuestion): "Avstand
|
||||
første putt" lå tidligere PÅ SAMME steg som selve putt-tallet i
|
||||
`ScoringWizard` -- auto-hopp idet putt-tallet velges ville gjort
|
||||
avstandsfeltet uoppnåelig (ingen annen inngang finnes). Løst ved å
|
||||
splitte putt-steget i to (bekreftet anbefalt løsning): `WizardStep`
|
||||
utvidet med et eget `"puttDistance"`-steg, `wizardStepsFor()` gir nå
|
||||
`["strokes","putts","puttDistance"]`/`["strokes","putts","puttDistance",
|
||||
"details"]` for de to høyere statistikknivåene.
|
||||
**Mekanisme (samme mønster i `ScoringWizard` og den enklere
|
||||
`SideScoreWizard` for delt-ball-formater):** to refs -- `enteredWithValueRef`
|
||||
fanger om steget sitt eget felt ALLEREDE hadde en verdi idet steget ble
|
||||
vist (et allerede utfylt hull skal ikke hoppe videre bare fordi
|
||||
veiviseren åpnes, og "Forrige" tilbake til et allerede besvart steg skal
|
||||
ikke re-trigge et nytt hopp), `firedRef` hindrer dobbelt-triggering.
|
||||
Kun steg med ETT entydig felt (Slag, Putter, Avstand, samt hele
|
||||
`SideScoreWizard` sitt eneste Slag-felt) auto-hopper -- "flere
|
||||
detaljer"-steget (kølle/retning/chip/bunker/straffeslag/anywayslag) har
|
||||
ingen enkelt "dette er ferdig"-verdi og beholder derfor "Neste"/
|
||||
"Ferdig"-knappen som manuell handling, bevisst uendret.
|
||||
**Verifisert grundig i en isolert scratch-nettleserøkt** (fersk
|
||||
database/MinIO/API-container, ekte `next dev`, Chrome DevTools):
|
||||
full "full"-nivå-runde spilt gjennom Slag→Putter→Avstand (alle tre
|
||||
auto-hoppet uten et eneste "Neste"-trykk) →detaljer (korrekt IKKE
|
||||
auto-hoppet, krevde et bevisst "Ferdig"-trykk, som deretter gikk videre
|
||||
til neste hull av seg selv). "Forrige" fra Putter tilbake til Slag
|
||||
bekreftet trygt (viste den allerede valgte verdien, hoppet IKKE
|
||||
automatisk fremover igjen). Delt-ball (`SideScoreWizard`, foursome)
|
||||
bekreftet separat: valgt slagtall for "Rødt" hoppet umiddelbart til
|
||||
"Blått" uten trykk. Ekte typesjekket + full produksjonsbuild kjørt før
|
||||
utrulling, alle 24 ruter listet.
|
||||
**Rullet ut live 2026-07-28**, bruker bekreftet eksplisitt: ingen
|
||||
migrasjon (ren frontend), `docker compose up -d --build
|
||||
teecup_frontend`. Begge containere boot-et rent, `/health`/`/dashboard`
|
||||
→ 200, `teeoff.no` upåvirket.
|
||||
|
||||
Neste steg:
|
||||
0a. **Spillerliste-redesign — nå FAKTISK nettleser-bekreftet
|
||||
|
|
|
|||
|
|
@ -1145,25 +1145,41 @@ export function RoundDetail({ roundId }: { roundId: string }) {
|
|||
)
|
||||
}
|
||||
|
||||
// --- Scoringsveiviser (2026-07-26) ------------------------------------------
|
||||
// --- Scoringsveiviser (2026-07-26, auto-hopp lagt til 2026-07-28) ----------
|
||||
// Skjermovertagende, ett-spiller-om-gangen registreringsflyt -- inspirert av
|
||||
// en konkurrentapps samlebåndsflyt (video studert bilde for bilde), men
|
||||
// BEVISST forenklet til TeeCups eget stat_level-drevne steg-antall i stedet
|
||||
// for å kopiere konkurrentens nøyaktige skjermrekkefølge/design:
|
||||
// - "strokes_only": ett steg (Slag)
|
||||
// - "strokes_and_putts": to steg (Slag, Putter+avstand første putt)
|
||||
// - "full": tre steg (Slag, Putter+avstand første putt, resten samlet)
|
||||
// "Neste"/"Forrige" beveger seg gjennom stegene for ÉN spiller; på siste
|
||||
// steg blir knappen "Neste: {navn}" (bytter til neste spiller, nullstiller
|
||||
// til steg 1) eller "Ferdig" (er spilleren den siste, lukker veiviseren og
|
||||
// varsler forelderen om å gå videre til neste hull).
|
||||
// - "strokes_and_putts": to steg (Slag, Putter, Avstand første putt)
|
||||
// - "full": fire steg (Slag, Putter, Avstand første putt, resten samlet)
|
||||
// Slag/Putter hopper AUTOMATISK videre i det øyeblikket en verdi velges --
|
||||
// ingen "Neste"-trykk nødvendig (etterspurt av bruker 2026-07-28: "Avstand
|
||||
// første putt" lå tidligere PÅ SAMME steg som selve putt-tallet, som ville
|
||||
// gjort feltet uoppnåelig hvis auto-hopp fyrte idet putt-tallet ble valgt --
|
||||
// derfor et eget, eget steg for avstanden, som ELLERS ville vært umulig å
|
||||
// nå). "Avstand"/"detaljer" er valgfrie/flerfelts og auto-hopper derfor
|
||||
// ikke -- "Neste"/"Forrige"-knappene i bunnen fungerer fortsatt som
|
||||
// manuell reserve for disse (og for å rette et allerede registrert steg).
|
||||
// På siste steg blir knappen "Neste: {navn}" (bytter til neste spiller,
|
||||
// nullstiller til steg 1) eller "Ferdig" (er spilleren den siste, lukker
|
||||
// veiviseren og varsler forelderen om å gå videre til neste hull).
|
||||
|
||||
type WizardStep = "strokes" | "putts" | "details"
|
||||
type WizardStep = "strokes" | "putts" | "puttDistance" | "details"
|
||||
|
||||
function wizardStepsFor(statLevel: StatLevel): WizardStep[] {
|
||||
if (statLevel === "strokes_only") return ["strokes"]
|
||||
if (statLevel === "strokes_and_putts") return ["strokes", "putts"]
|
||||
return ["strokes", "putts", "details"]
|
||||
if (statLevel === "strokes_and_putts") return ["strokes", "putts", "puttDistance"]
|
||||
return ["strokes", "putts", "puttDistance", "details"]
|
||||
}
|
||||
|
||||
// Hvilket HoleStat-felt (om noen) som "eier" auto-hopp for et gitt steg --
|
||||
// null for steg uten noe entydig enkeltfelt å trigge på (flerfelts/valgfritt).
|
||||
function autoAdvanceFieldFor(step: WizardStep): "strokes" | "putts" | "firstPuttBucket" | null {
|
||||
if (step === "strokes") return "strokes"
|
||||
if (step === "putts") return "putts"
|
||||
if (step === "puttDistance") return "firstPuttBucket"
|
||||
return null
|
||||
}
|
||||
|
||||
function ScoringWizard({
|
||||
|
|
@ -1206,6 +1222,29 @@ function ScoringWizard({
|
|||
|
||||
const canProceed = step === "strokes" ? stat.strokes !== null : step === "putts" ? stat.putts !== null : true
|
||||
|
||||
// Auto-hopp (2026-07-28): så snart steget sitt eget felt får en verdi,
|
||||
// hopp videre av seg selv -- ingen "Neste"-trykk nødvendig. `enteredWith
|
||||
// ValueRef` fanger om feltet ALLEREDE hadde en verdi idet vi ankom steget
|
||||
// (et allerede utfylt hull skal ikke hoppe videre bare fordi veiviseren
|
||||
// åpnes) -- kun en FERSK endring gjort AV BRUKEREN akkurat nå skal utløse
|
||||
// hoppet. `firedRef` hindrer at samme hopp trigges to ganger.
|
||||
const autoField = autoAdvanceFieldFor(step)
|
||||
const enteredWithValueRef = useRef(false)
|
||||
const firedRef = useRef(false)
|
||||
useEffect(() => {
|
||||
firedRef.current = false
|
||||
enteredWithValueRef.current = autoField !== null && stat[autoField] !== null
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [step, player.id, hole.holeNumber])
|
||||
useEffect(() => {
|
||||
if (!autoField || firedRef.current || enteredWithValueRef.current) return
|
||||
if (stat[autoField] !== null) {
|
||||
firedRef.current = true
|
||||
forward()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [stat.strokes, stat.putts, stat.firstPuttBucket])
|
||||
|
||||
function back() {
|
||||
if (isFirstStep) {
|
||||
onClose()
|
||||
|
|
@ -1278,7 +1317,6 @@ function ScoringWizard({
|
|||
)}
|
||||
|
||||
{step === "putts" && (
|
||||
<>
|
||||
<NumberPicker
|
||||
label="Putter"
|
||||
value={stat.putts}
|
||||
|
|
@ -1289,6 +1327,9 @@ function ScoringWizard({
|
|||
onChange={(v) => onUpdate({ putts: v })}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
)}
|
||||
|
||||
{step === "puttDistance" && (
|
||||
<ChoiceRow
|
||||
label="Avstand første putt"
|
||||
options={[
|
||||
|
|
@ -1303,7 +1344,6 @@ function ScoringWizard({
|
|||
onChange={(v) => onUpdate({ firstPuttBucket: v as PuttBucket })}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{step === "details" && (
|
||||
|
|
@ -3757,6 +3797,25 @@ function SideScoreWizard({
|
|||
return s.label?.trim() || `Side ${idx === 0 ? "A" : "B"}`
|
||||
}
|
||||
|
||||
// Auto-hopp (2026-07-28, samme mønster som ScoringWizard) -- registrer
|
||||
// slagtall for siden, hopp umiddelbart videre til neste side/hull. Kun
|
||||
// ETT felt her, så ingen splitt-i-flere-steg-problematikk.
|
||||
const enteredWithValueRef = useRef(score !== null)
|
||||
const firedRef = useRef(false)
|
||||
useEffect(() => {
|
||||
firedRef.current = false
|
||||
enteredWithValueRef.current = score !== null
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [side.id, hole.holeNumber])
|
||||
useEffect(() => {
|
||||
if (firedRef.current || enteredWithValueRef.current) return
|
||||
if (score !== null) {
|
||||
firedRef.current = true
|
||||
onAdvance()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [score])
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex flex-col bg-background">
|
||||
<header className="flex min-h-14 shrink-0 items-center gap-2 border-b border-border px-3">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue