"use client"
// Delte, utelukkende trykkbaserte input-primitiver for hull-for-hull-
// statistikkregistrering (ALDRI dropdowns) -- trukket ut av round-detail.tsx
// sin ScoringWizard (frittstående runder) 2026-08-15 (ADR-071) for gjenbruk
// i org-turneringers nye HoleStatsSheet, som nå har samme statistikkdybde
// (migrasjon 075). Ren UI, ingen datahenting/state utover det som sendes inn.
//
// HoleHistoryPanel (ADR-072) er unntaket -- den HENTER selv (GET .../history),
// siden begge scoringsflytene bruker nøyaktig samme henting/visning og det
// ville vært ren duplisering å bygge den to ganger.
import { useEffect, useState, type ReactNode } from "react"
import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, ChevronRight, Flag, Minus, Plus, Target } from "lucide-react"
import { cn } from "@/lib/utils"
export function golfTermForScore(n: number, par: number): string | null {
const diff = n - par
if (diff <= -3) return "Albatross"
if (diff === -2) return "Eagle"
if (diff === -1) return "Birdie"
if (diff === 0) return "Par"
if (diff === 1) return "Bogey"
if (diff === 2) return "Dobbel bogey"
return null
}
export function NumberPicker({
label,
value,
directValues,
expandValues,
expandLabel,
parValue,
showGolfTerms,
maxValue,
strokesReceived,
accent,
onChange,
readOnly,
}: {
label: string
value: number | null
directValues: number[]
expandValues: number[]
expandLabel: string
// Hullets par -- brukt til golf-term-bildeteksten når showGolfTerms er satt.
parValue?: number
// Viser Eagle/Birdie/Par/Bogey/Dobbel bogey under HVERT tall (relativt til
// parValue), i stedet for kun å merke selve par-knappen -- kun meningsfullt
// for Slag-velgeren, ikke Putter/Anywayslag.
showGolfTerms?: boolean
// Skjuler valg høyere enn dette (f.eks. Putter kan aldri overstige
// antall slag registrert på hullet) -- ingen vits i å tilby et tall som
// uansett ville vært selvmotsigende.
maxValue?: number
// Spillerens tildelte handicap-slag PÅ DETTE hullet. Når satt (og
// showGolfTerms er på, dvs. Slag-velgeren), markeres knappen som
// tilsvarer spillerens PERSONLIGE netto par (rå par + mottatte slag) med
// en liten, diskret prikk -- tydelig forskjellig fra "valgt"-tilstanden,
// og de to kan opptre samtidig på samme knapp.
strokesReceived?: number | null
// Valgfri egen aksent for seksjonen (brukes til å gi Putter-velgeren en
// distinkt visuell identitet så den ikke forveksles med Slag-velgeren).
// Rører IKKE selve tallknappene -- kun tittelrad/ikon.
accent?: "primary" | "orange"
onChange: (value: number) => void
readOnly: boolean
}) {
const cap = (values: number[]) => (maxValue === undefined ? values : values.filter((n) => n <= maxValue))
const cappedDirect = cap(directValues)
const cappedExpand = cap(expandValues)
const valueInExpand = value !== null && cappedExpand.includes(value)
const [expanded, setExpanded] = useState(false)
const showExpanded = expanded || valueInExpand
const visibleValues = showExpanded ? [...cappedDirect, ...cappedExpand] : cappedDirect
// Spillerens netto par for hullet = rå par + tildelte slag. Kun beregnet
// når vi faktisk har begge (Slag-velgeren med kjent strokesReceived).
const netPar =
parValue !== undefined && strokesReceived !== null && strokesReceived !== undefined
? parValue + strokesReceived
: null
// Putter-velgeren får en egen aksent (oransje) og et eget ikon på
// tittelraden, så den ikke er til å forveksle med Slag-velgeren -- som
// ellers er nøyaktig samme rutenett. Kun tittelraden/venstre aksentbånd
// endres; selve tallknappene beholder den etablerte grønne "valgt"-stilen.
const isOrange = accent === "orange"
return (
{isOrange && (
)}
{label}
{/* Netto par-forklaring: gjør prikken selvforklarende uten å stole på
fargesyn alene (tilgjengelighet -- sol/utendørs). Vises kun når det
faktisk finnes en netto par-markør å forklare. */}
{netPar !== null && (
Ditt netto par ({netPar})
)}
{/* Numpad: tre kolonner, knappene fyller bredden -- store trykkflater
for bruk utendørs, ofte med sol på skjermen. */}
)
}
// --- Stepper (+/-) ---------------------------------------------------------
export function Stepper({
label,
value,
onChange,
readOnly,
max,
}: {
label: string
value: number
onChange: (value: number) => void
readOnly: boolean
// Kan ikke telle høyere enn antall slag registrert på hullet -- f.eks.
// umulig å ha chippet flere ganger enn totalt antall slag.
max?: number
}) {
const atMax = max !== undefined && value >= max
const atMin = value <= 0
// Teller-FLIS (ADR-078, 2026-08-16, V0-designet) -- selvstendig kort med
// etikett + stort tall + -/+ på bunnen, ment for et 2x2-rutenett (se
// holeDetails-steget i round-detail.tsx/individual-tournament-detail.tsx).
// Interaksjonskontrakten er uendret: -/tall/+, minus disabled på 0, pluss
// disabled på max, alle trykkflater >=44px. Kun app-tokens.
return (
{label}
{/* Tallet bærer selve informasjonen (aldri farge alene); nullverdi
dempes kun visuelt via muted-foreground, som fortsatt er AA på
kort. */}
{value}
)
}
export function WizardSection({ title, children }: { title: string; children: ReactNode }) {
return (
{title}
{children}
)
}
// --- Spillerens per-hull-historikk (ADR-072) --------------------------------
// "Hvordan spiller jeg egentlig dette hullet?" -- aggregert på tvers av ALLE
// tidligere frittstående runder OG turneringsrunder (custom/håndlagde baner
// og gjestespillere er allerede filtrert bort server-side, se
// app/hole_history.py). Panelet skjuler seg selv (viser ingenting) når
// endepunktet svarer null -- ikke en feil, bare "ingen historikk å vise
// ennå/denne banen støtter det ikke".
type HoleHistoryInstance = {
source: "personal" | "tournament"
played_at: string | null
label: string
score: number
par: number
putts: number | null
tee_shot_result: string | null
approach_result: string | null
chip_count: number | null
bunker_shot_count: number | null
penalty_strokes: number | null
first_putt_distance_bucket: string | null
}
type HoleHistory = {
times_played: number
times_personal: number
times_tournament: number
average_score: number
average_score_vs_par: number
gir_percent: number | null
fairway_hit_percent: number | null
average_putts: number | null
best_score: number
worst_score: number
instances: HoleHistoryInstance[]
}
// ADR-079 (2026-08-16): panelet åpner nå den FULLE historikk-skjermen
// (components/hole-history-detail.tsx) ved klikk i stedet for å ekspandere
// en enkel liste inline -- flyttet HIT ut av selve slagvinduet/-arket til
// "skjermen før" (PlayerHoleCards for frittstående runder, "Oversikt"-
// steget for org-turneringer), se round-detail.tsx/individual-tournament-
// detail.tsx for de to bruksstedene.
export function HoleHistoryPanel({ url, onOpenFull }: { url: string; onOpenFull: () => void }) {
// undefined = laster ennå, null = ingen historikk å vise (custom bane,
// gjest, eller genuint aldri spilt før).
const [history, setHistory] = useState(undefined)
useEffect(() => {
let cancelled = false
setHistory(undefined)
fetch(url, { credentials: "include" })
.then((res) => (res.ok ? res.json() : null))
.then((data) => {
if (!cancelled) setHistory(data)
})
.catch(() => {
if (!cancelled) setHistory(null)
})
return () => {
cancelled = true
}
}, [url])
if (!history) return null
const parSign = history.average_score_vs_par >= 0 ? "+" : ""
return (
)
}