Trekkspillet på statistikk-siden viser nå sammenslått som default — alle seksjonene (Scorer, Fairway, GIR, osv.) er kollapset til man trykker på dem. Rullet ut live.

Notert i FEATURE_BACKLOG.md: Flaggturnering lagt til som et femte fremtidig turneringsformat, med kravet om en gjenstående-slag-visning (oppdatert per hull) og den betingede fremtidsideen om GPS-basert markering av hvor langt spilleren kom — ingenting bygget, bare fanget opp slik at det ikke går i glemmeboken.
This commit is contained in:
Erol Haagenrud 2026-07-25 05:32:23 +02:00
parent bba63b6cc9
commit 714c64e82e
4 changed files with 87 additions and 42 deletions

View file

@ -2570,16 +2570,27 @@ uendret bortsett fra å rette `/rounds/...`-hrefs til `/my-rounds/...`.
Anywayslag manglet helt fra `round-stats.tsx` sin "Chip, bunker og Anywayslag manglet helt fra `round-stats.tsx` sin "Chip, bunker og
straffeslag"-seksjon (verken `anyway_strokes` i `ApiHole`-typen eller straffeslag"-seksjon (verken `anyway_strokes` i `ApiHole`-typen eller
noe utledet total fantes). Lagt til `anyway_strokes` i typen, ny noe utledet total fantes). Lagt til `anyway_strokes` i typen, ny
`anywayPerRound`-aggregat i `computeStats()`, ny generalisert `anywayPerRound`-aggregat i `computeStats()`.
`StatTileRow`-komponent (2 ELLER 3 fliser -- `StatTilePair` var fast to) **Feilrettet SAMME dag, rett etterpå:** min første fiks slo sammen
brukt for Bunkerslag/Straffeslag/(Anywayslag når tilgjengelig). Anywayslag-tallet INN I den eksisterende "Chip, bunker og
Seksjonen omdøpt fra "Chip, bunker og straffeslag" til "Annet" (bredere straffeslag"-seksjonen og omdøpte HELE seksjonen til "Annet" -- feil,
navn, bruker nevnte at et fritekst-notatfelt trolig havner der senere). påpekt av bruker. Rettet: "Chip, bunker og straffeslag" beholder sitt
opprinnelige navn og innhold UENDRET (Bunkerslag/Straffeslag-flisene
tilbake til to, ikke tre). Ny, EGEN "Annet"-seksjon lagt til RETT ETTER
den (ikke slått sammen), med kun Anywayslag-statistikk: total per runde
+ andel hull med minst ett anywayslag (samme "andel hull med..."-mønster
som straffeslag-statistikken). Ny `pctHolesWithAnyway`-beregning i
`computeStats()`. Den midlertidige `StatTileRow`-komponenten (bygget for
den feilaktig sammenslåtte tre-flis-varianten) fjernet igjen som dødt
kode -- `StatTilePair` (fast to fliser) er tilstrekkelig for begge
seksjonene nå. Notert for senere: brukeren ser for seg at et
fritekst-notatfelt havner i "Annet"-seksjonen etter hvert.
**Verifisert:** ekte typesjekket produksjonsbuild kjørt og bekreftet, **Verifisert:** ekte typesjekket produksjonsbuild kjørt og bekreftet,
ny rute `/my-rounds/[id]/scorecard` listet. Ingen ny backend-endring ny rute `/my-rounds/[id]/scorecard` listet. Ingen ny backend-endring
(`anyway_strokes`/`strokes_received` fantes allerede i `RoundHoleOut`). (`anyway_strokes`/`strokes_received` fantes allerede i `RoundHoleOut`).
**Rullet ut live 2026-07-25**, ren frontend-endring, ingen migrasjon, **Rullet ut live 2026-07-25** (to runder, feilrettingen rullet ut rett
`teeoff.no` upåvirket. etter originalen), ren frontend-endring, ingen migrasjon, `teeoff.no`
upåvirket.
**Motor-komponenten (punkt 1-11) er ✅ BYGGET OG TESTET 2026-07-22,** **Motor-komponenten (punkt 1-11) er ✅ BYGGET OG TESTET 2026-07-22,**
som første, isolerte byggesteg (ren Python, ingen DB/API/frontend ennå — som første, isolerte byggesteg (ren Python, ingen DB/API/frontend ennå —

View file

@ -2533,12 +2533,29 @@ Ferdig og verifisert:
til en "Se scorekort"-knapp i `CompletedBanner` (round-detail.tsx) ved til en "Se scorekort"-knapp i `CompletedBanner` (round-detail.tsx) ved
siden av den eksisterende "Se full rundestatistikk" -- tatt inn. siden av den eksisterende "Se full rundestatistikk" -- tatt inn.
**Samtidig, rapportert av bruker:** Anywayslag manglet helt fra **Samtidig, rapportert av bruker:** Anywayslag manglet helt fra
rundestatistikk-siden sin "Chip, bunker og straffeslag"-seksjon -- rundestatistikk-siden sin "Chip, bunker og straffeslag"-seksjon.
lagt til som en tredje per-runde-flis, og seksjonen omdøpt til "Annet" **Feilrettet rett etterpå, samme dag:** min første fiks slo feilaktig
(bredere navn, siden et notatfelt trolig havner der senere også). sammen Anywayslag-tallet i DEN eksisterende seksjonen og omdøpte hele
Ekte typesjekket build kjørt og bekreftet (ny rute seksjonen til "Annet" -- brukeren påpekte at "Chip, bunker og
`/my-rounds/[id]/scorecard` listet). Rullet ut, ren frontend-endring, straffeslag" skulle beholde navn+innhold uendret, og at "Annet" skulle
ingen backend/migrasjon, `teeoff.no` upåvirket. være en EGEN, ny seksjon RETT ETTER med kun anywayslag-tall (total per
runde + andel hull med anywayslag). Rettet umiddelbart. Notert at et
fritekst-notatfelt trolig havner i "Annet" senere. Ekte typesjekket
build kjørt og bekreftet (ny rute `/my-rounds/[id]/scorecard` listet).
Rullet ut (to runder), ren frontend-endring, ingen backend/migrasjon,
`teeoff.no` upåvirket.
- **Rundestatistikk-seksjonene starter nå kollapset, LIVE samme dag
(2026-07-25):** brukeren ba om at "trekkspillet" (StatCard-seksjonene
`/my-rounds/[id]/stats`) skal vises sammenslått -- må klikkes for å
se innholdet. `StatCard` sin `defaultOpen` endret fra `true` til
`false` (ingen kallsted overstyrte den, så én linje dekket alle
seksjonene). Ekte typesjekket build, rullet ut, `teeoff.no` upåvirket.
- **Notert i FEATURE_BACKLOG.md, IKKE bygget:** brukeren ba om et notat
om et femte fremtidig turneringsformat, "Flaggturnering" (utover de
fire fra 2026-07-19-runden) -- krever en visning av GJENSTÅENDE slag
for spilleren, oppdatert etter hvert hull, pluss en fremtidig idé om
å bruke GPS (når/hvis integrert) til å markere hvor langt spilleren
faktisk kom. Lagt til i samme seksjon som de fire andre formatene.
Neste steg: Neste steg:
1. **Pauset, venter på retning:** dashbordets tom-tilstand ved første 1. **Pauset, venter på retning:** dashbordets tom-tilstand ved første

View file

@ -545,6 +545,21 @@
poengmodell, bare en annen fremgangsmåte de to første slagene) — trenger poengmodell, bare en annen fremgangsmåte de to første slagene) — trenger
trolig ikke ny datamodell, bare en presisering i regelverket/UI-teksten. trolig ikke ny datamodell, bare en presisering i regelverket/UI-teksten.
**«Flaggturnering»** (Flag tournament), reist av bruker 2026-07-25 —
IKKE del av den opprinnelige fire-formater-listen over, notert som et
eget femte format. Hver spiller får et fast antall slag (typisk par +
handicap for hele runden) og spiller til slagene er brukt opp — den som
kommer lengst rundt banen før slagene tar slutt, vinner ("planter
flagget" der siste slag ble brukt). **Konkret krav fra bruker, eksplisitt
formulert:** en visning som viser GJENSTÅENDE slag for spilleren,
oppdatert etter hvert spilte hull (nedtelling, ikke bare et sluttall).
**Fremtidig idé, uttrykkelig betinget av at GPS er integrert i appen
først** (se GPS/avstandsmåling-notatet lenger opp i denne filen, ADR-033-
seksjonen — samme avhengighet): bruk GPS til å markere/registrere HVOR på
banen spilleren faktisk endte opp når slagene tok slutt, ikke bare hvilket
hull. Ingen datamodell eller UI designet ennå for noen del av dette —
rent notat.
- **Ingenting av dette er designet eller bygget ennå** — kun fanget her slik - **Ingenting av dette er designet eller bygget ennå** — kun fanget her slik
at det ikke går i glemmeboken. Naturlig neste steg når dette tas fatt på: at det ikke går i glemmeboken. Naturlig neste steg når dette tas fatt på:
vurder de fire hver for seg (ikke som én stor runde), start med «Try all» vurder de fire hver for seg (ikke som én stor runde), start med «Try all»

View file

@ -18,6 +18,7 @@ import {
ChevronRight, ChevronRight,
Flag, Flag,
Info, Info,
MoreHorizontal,
MoveHorizontal, MoveHorizontal,
Target, Target,
Wind, Wind,
@ -56,7 +57,10 @@ const C = {
function StatCard({ function StatCard({
title, title,
icon: Icon, icon: Icon,
defaultOpen = true, // Alle seksjonene starter kollapset (etterspurt av bruker 2026-07-25:
// "trekkspillet skal vises sammenslått") -- må trykkes på hver enkelt
// for å se innholdet, i stedet for at hele siden lastes åpen.
defaultOpen = false,
children, children,
}: { }: {
title: string title: string
@ -252,22 +256,6 @@ function ProgressRow({
) )
} }
// --- Row of N stat tiles (2 eller 3 -- StatTilePair er en fast to-tiles-
// variant, denne generaliserer for "Annet"-seksjonens tre per-runde-tall) ---
function StatTileRow({ tiles }: { tiles: { label: string; value: string }[] }) {
return (
<div className={cn("grid gap-3", tiles.length === 3 ? "grid-cols-3" : "grid-cols-2")}>
{tiles.map((t) => (
<div key={t.label} className="flex flex-col gap-1 rounded-2xl border border-border bg-muted/40 p-4">
<span className="text-3xl font-extrabold tabular-nums text-foreground">{t.value}</span>
<span className="text-sm font-semibold leading-snug text-muted-foreground text-pretty">{t.label}</span>
</div>
))}
</div>
)
}
// --- Paired stat tiles ----------------------------------------------------- // --- Paired stat tiles -----------------------------------------------------
function StatTilePair({ function StatTilePair({
@ -519,6 +507,10 @@ function computeStats(holes: ApiHole[]) {
const anywayEligible = played.filter((h) => h.anyway_strokes !== null) const anywayEligible = played.filter((h) => h.anyway_strokes !== null)
const anywayPerRound = const anywayPerRound =
anywayEligible.length > 0 ? anywayEligible.reduce((s, h) => s + (h.anyway_strokes as number), 0) : null anywayEligible.length > 0 ? anywayEligible.reduce((s, h) => s + (h.anyway_strokes as number), 0) : null
const pctHolesWithAnyway =
anywayEligible.length > 0
? (anywayEligible.filter((h) => (h.anyway_strokes as number) >= 1).length / anywayEligible.length) * 100
: null
return { return {
playedCount: played.length, playedCount: played.length,
@ -560,6 +552,7 @@ function computeStats(holes: ApiHole[]) {
avgToParWithoutBunker, avgToParWithoutBunker,
pctHolesWithPenalty, pctHolesWithPenalty,
anywayPerRound, anywayPerRound,
pctHolesWithAnyway,
} }
} }
@ -939,12 +932,8 @@ export function RoundStats({ roundId }: { roundId: string }) {
</StatCard> </StatCard>
)} )}
{/* 7. Annet -- "catch all" for chip/bunker/straffeslag/anywayslag {/* 7. Chip, bunker og straffeslag */}
(het tidligere "Chip, bunker og straffeslag", men Anywayslag <StatCard title="Chip, bunker og straffeslag" icon={Waves}>
manglet helt fra oppsummeringen -- rettet + omdøpt til noe
bredere 2026-07-25, siden et fritekst-notatfelt trolig havner
her senere også). */}
<StatCard title="Annet" icon={Waves}>
{(s.scramblingPct !== null || s.sandSavePct !== null) && ( {(s.scramblingPct !== null || s.sandSavePct !== null) && (
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<InfoStat <InfoStat
@ -979,12 +968,9 @@ export function RoundStats({ roundId }: { roundId: string }) {
</div> </div>
)} )}
<StatTileRow <StatTilePair
tiles={[ a={{ label: "Bunkerslag per runde", value: String(s.bunkerPerRound) }}
{ label: "Bunkerslag per runde", value: String(s.bunkerPerRound) }, b={{ label: "Straffeslag per runde", value: String(s.penaltyPerRound) }}
{ label: "Straffeslag per runde", value: String(s.penaltyPerRound) },
...(s.anywayPerRound !== null ? [{ label: "Anywayslag per runde", value: String(s.anywayPerRound) }] : []),
]}
/> />
{(s.avgToParWithBunker !== null || s.avgToParWithoutBunker !== null) && ( {(s.avgToParWithBunker !== null || s.avgToParWithoutBunker !== null) && (
<StatTilePair <StatTilePair
@ -999,6 +985,22 @@ export function RoundStats({ roundId }: { roundId: string }) {
</div> </div>
)} )}
</StatCard> </StatCard>
{/* 8. Annet -- egen seksjon for rundens anywayslag, ETTER
chip/bunker/straffeslag (rettet 2026-07-25 -- feilaktig slått
sammen med den seksjonen i forrige runde). Notatfelt kommer
trolig hit senere. */}
{s.anywayPerRound !== null && (
<StatCard title="Annet" icon={MoreHorizontal}>
<StatTilePair
a={{ label: "Anywayslag per runde", value: String(s.anywayPerRound) }}
b={{
label: "Andel hull med anywayslag",
value: s.pctHolesWithAnyway !== null ? pct(s.pctHolesWithAnyway) : "",
}}
/>
</StatCard>
)}
</> </>
)} )}
</main> </main>