Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
"use client"
|
|
|
|
|
|
|
|
|
|
|
|
import { useEffect, useRef, useState } from "react"
|
|
|
|
|
|
import dynamic from "next/dynamic"
|
|
|
|
|
|
import { Crosshair, LocateFixed, MapPin, X, ChevronLeft, Check } from "lucide-react"
|
|
|
|
|
|
import { ClubPicker } from "@/components/teecup/club-picker"
|
|
|
|
|
|
import { Textarea } from "@/components/ui/textarea"
|
|
|
|
|
|
import { cn } from "@/lib/utils"
|
2026-08-10 07:00:11 +02:00
|
|
|
|
import { haversineMeters } from "@/lib/geo"
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Lazy, client-only reference to the map step. Because dynamic() defers the
|
|
|
|
|
|
* underlying import() until <MapPointPicker /> is actually rendered, neither
|
|
|
|
|
|
* this module nor a GPS-only run ever pulls in mapbox-gl. A Mapbox map load
|
|
|
|
|
|
* (which is billed) only happens once the user chooses "Velg punkt på kart".
|
|
|
|
|
|
*/
|
|
|
|
|
|
const MapPointPicker = dynamic(
|
|
|
|
|
|
() => import("@/components/shot/map-point-picker").then((m) => m.MapPointPicker),
|
|
|
|
|
|
{
|
|
|
|
|
|
ssr: false,
|
|
|
|
|
|
loading: () => (
|
|
|
|
|
|
<div className="flex h-full items-center justify-center">
|
|
|
|
|
|
<div className="size-8 animate-spin rounded-full border-4 border-primary/20 border-t-primary" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
},
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type LngLat = { lng: number; lat: number }
|
2026-08-10 07:00:11 +02:00
|
|
|
|
type Step = "start" | "map" | "end" | "club" | "result"
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
type GeoStatus = "idle" | "loading" | "error"
|
|
|
|
|
|
|
|
|
|
|
|
export type ShotMeasurementSheetProps = {
|
|
|
|
|
|
holeNumber: number
|
|
|
|
|
|
existingShotCount: number
|
|
|
|
|
|
ownBagClubs: string[]
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Computed by the caller (Haversine) once both points are known. Optional
|
|
|
|
|
|
* here so the sheet stays previewable; when absent a rough preview-only
|
|
|
|
|
|
* stub is used purely for display.
|
|
|
|
|
|
*/
|
|
|
|
|
|
distanceMeters?: number
|
Fiks: slagmåling ga alltid 0m, delinger forsvant stille
Produksjonsbug rapportert av bruker rett etter forrige utrulling: "den
målte aldri mer enn 0 meter. Jeg så ingen bilder."
Rotårsak 1: "end"-steget (ballens posisjon) avfyrte GPS-målingen
automatisk idet steget ble aktivt, uten tid for brukeren til faktisk å
gå fra utslagsstedet til ballen -- start/slutt endte på samme sted,
samme øyeblikk. Fjernet auto-avfyringen, krever nå et eksplisitt "Jeg
er ved ballen nå"-trykk.
Rotårsak 2 (konsekvens av #1): en 0m-avstand avvist av backendens
distance_meters > 0-validering (422) gjorde at submitShot() bare lukket
arket stille, ingen feilmelding. Lagt til submitError/submitting-state,
parser både appens {detail:{message}} og FastAPI/Pydantic sin rå
{detail:[{msg}]}-valideringsform (bekreftet eksakt hvilken ved å
trigge en ekte 422), viser feilen i arket, holder det åpent ved feil.
Scratch-verifisert med navigator.geolocation midlertidig overstyrt
(ekte GPS-tillatelse permanent denied i CDP-automatiserte nettleser-
sesjoner): "Jeg er ved ballen nå" vises korrekt, et ekte gap ga
"130 m" (ikke 0) og delingen postet riktig, og en 0m-innsending viser nå
feilmeldingen i stedet for å lukke stille. Se CHANGELOG.md punkt 49.
2026-08-08 15:06:48 +02:00
|
|
|
|
/** Vises som en feilmelding i resultat-steget, f.eks. når serveren avviste
|
|
|
|
|
|
* innsendingen (ADR-048: reell bug 2026-08-08 -- uten dette lukket arket
|
|
|
|
|
|
* seg stille ved en avvist innsending, ingen feil synlig for brukeren). */
|
|
|
|
|
|
submitError?: string | null
|
|
|
|
|
|
submitting?: boolean
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
onSubmit: (result: {
|
|
|
|
|
|
club: string
|
|
|
|
|
|
distanceMeters: number
|
|
|
|
|
|
startMethod: "gps" | "map_tap"
|
|
|
|
|
|
startLat: number
|
|
|
|
|
|
startLng: number
|
2026-08-08 21:38:10 +02:00
|
|
|
|
endMethod: "gps" | "map_tap"
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
endLat: number
|
|
|
|
|
|
endLng: number
|
|
|
|
|
|
share: boolean
|
|
|
|
|
|
shareText: string
|
|
|
|
|
|
}) => void
|
|
|
|
|
|
onCancel: () => void
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Preview-only rough distance so the result step shows a real number in v0.
|
|
|
|
|
|
// The real app passes distanceMeters computed server-/caller-side.
|
|
|
|
|
|
function previewDistance(a: LngLat | null, b: LngLat | null): number {
|
|
|
|
|
|
if (!a || !b) return 0
|
2026-08-10 07:00:11 +02:00
|
|
|
|
return Math.round(haversineMeters(a, b))
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function ShotMeasurementSheet({
|
|
|
|
|
|
holeNumber,
|
|
|
|
|
|
existingShotCount,
|
|
|
|
|
|
ownBagClubs,
|
|
|
|
|
|
distanceMeters,
|
Fiks: slagmåling ga alltid 0m, delinger forsvant stille
Produksjonsbug rapportert av bruker rett etter forrige utrulling: "den
målte aldri mer enn 0 meter. Jeg så ingen bilder."
Rotårsak 1: "end"-steget (ballens posisjon) avfyrte GPS-målingen
automatisk idet steget ble aktivt, uten tid for brukeren til faktisk å
gå fra utslagsstedet til ballen -- start/slutt endte på samme sted,
samme øyeblikk. Fjernet auto-avfyringen, krever nå et eksplisitt "Jeg
er ved ballen nå"-trykk.
Rotårsak 2 (konsekvens av #1): en 0m-avstand avvist av backendens
distance_meters > 0-validering (422) gjorde at submitShot() bare lukket
arket stille, ingen feilmelding. Lagt til submitError/submitting-state,
parser både appens {detail:{message}} og FastAPI/Pydantic sin rå
{detail:[{msg}]}-valideringsform (bekreftet eksakt hvilken ved å
trigge en ekte 422), viser feilen i arket, holder det åpent ved feil.
Scratch-verifisert med navigator.geolocation midlertidig overstyrt
(ekte GPS-tillatelse permanent denied i CDP-automatiserte nettleser-
sesjoner): "Jeg er ved ballen nå" vises korrekt, et ekte gap ga
"130 m" (ikke 0) og delingen postet riktig, og en 0m-innsending viser nå
feilmeldingen i stedet for å lukke stille. Se CHANGELOG.md punkt 49.
2026-08-08 15:06:48 +02:00
|
|
|
|
submitError,
|
|
|
|
|
|
submitting,
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
onSubmit,
|
|
|
|
|
|
onCancel,
|
|
|
|
|
|
}: ShotMeasurementSheetProps) {
|
|
|
|
|
|
const [step, setStep] = useState<Step>("start")
|
|
|
|
|
|
const [startMethod, setStartMethod] = useState<"gps" | "map_tap" | null>(null)
|
|
|
|
|
|
const [startPoint, setStartPoint] = useState<LngLat | null>(null)
|
2026-08-08 21:38:10 +02:00
|
|
|
|
const [endMethod, setEndMethod] = useState<"gps" | "map_tap" | null>(null)
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
const [endPoint, setEndPoint] = useState<LngLat | null>(null)
|
|
|
|
|
|
|
|
|
|
|
|
const [startStatus, setStartStatus] = useState<GeoStatus>("idle")
|
|
|
|
|
|
|
|
|
|
|
|
const [club, setClub] = useState<string>("")
|
|
|
|
|
|
const [share, setShare] = useState(false)
|
|
|
|
|
|
const [shareText, setShareText] = useState("")
|
|
|
|
|
|
const shareEdited = useRef(false)
|
|
|
|
|
|
|
|
|
|
|
|
function acquirePosition(onOk: (p: LngLat) => void, onFail: () => void) {
|
|
|
|
|
|
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
|
|
|
|
onFail()
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
navigator.geolocation.getCurrentPosition(
|
|
|
|
|
|
(pos) => onOk({ lng: pos.coords.longitude, lat: pos.coords.latitude }),
|
|
|
|
|
|
() => onFail(),
|
|
|
|
|
|
{ enableHighAccuracy: true, timeout: 10000 },
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Start via device GPS.
|
|
|
|
|
|
function useMyPosition() {
|
|
|
|
|
|
setStartStatus("loading")
|
|
|
|
|
|
acquirePosition(
|
|
|
|
|
|
(p) => {
|
|
|
|
|
|
setStartPoint(p)
|
|
|
|
|
|
setStartMethod("gps")
|
|
|
|
|
|
setStartStatus("idle")
|
|
|
|
|
|
setStep("end")
|
|
|
|
|
|
},
|
|
|
|
|
|
() => setStartStatus("error"),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const distance =
|
|
|
|
|
|
typeof distanceMeters === "number" ? distanceMeters : previewDistance(startPoint, endPoint)
|
|
|
|
|
|
|
Fiks: kart-steget kollapset til 0px høyde (mapbox-gl.css CSS-krasj)
Produksjonsbug: "Kunne ikke laste kartet" for alle, bekreftet av bruker
etter oppfølgingsspørsmål ("alle tre" -- kart-valg, resultat-forhånds-
visning, delt bilde).
Rotårsak: mapbox-gl.css sin egen ".mapboxgl-map { position: relative }"
overstyrte Tailwind sin "absolute"-klasse på kart-beholderen (samme
klassenavn Mapbox GL JS legger til ved init, senere i CSS-cascaden).
Så snart position ikke lenger var absolute, mistet inset-0 all effekt
på størrelsen -- beholderen kollapset til height:0, kartet lastet helt
fint (style/tiles/events alle 200/204) men ble klippet vekk, usynlig.
Rettet ved å bytte til h-full w-full, som løser størrelsen via prosent-
arv uavhengig av hvilken position-verdi som vinner.
Kunne ikke fanges opp i tidligere scratch-tester siden Mapbox sin
URL-restriksjon alltid avviste localhost-scratch-opprinnelser før
kartet fikk lastet/rendret. Verifisert denne runden ved å overstyre
Referer-headeren for å simulere det ekte domenet.
Bygget i samme runde (ikke opprinnelig planlagt, brukerønske): en
client-side satellitt-forhåndsvisning i resultatsteget før lagring, med
det offentlige tokenet direkte som <img src> mot Mapbox Static Images
API.
Se CHANGELOG.md punkt 51 for full diagnose, inkl. en separat snubletråd
i mitt eget scratch-testverktøy (grep uten ^-anker matchet en
kommentarlinje) og en ekte service-worker-cache-fallgruve funnet
underveis.
2026-08-08 17:23:59 +02:00
|
|
|
|
// Forhåndsvisning av satellittutsnittet FØR lagring (brukerønske
|
|
|
|
|
|
// 2026-08-08, ikke opprinnelig planlagt -- selve DELINGEN genererer sitt
|
|
|
|
|
|
// eget, server-side bilde med samme markører+linje uavhengig av dette).
|
|
|
|
|
|
// Bygget client-side med det OFFENTLIGE tokenet (trygt i nettleseren,
|
|
|
|
|
|
// URL-restriktert) -- ingen server-tur-retur nødvendig kun for en
|
|
|
|
|
|
// forhåndsvisning.
|
|
|
|
|
|
const previewUrl =
|
|
|
|
|
|
startPoint && endPoint && process.env.NEXT_PUBLIC_MAPBOX_TOKEN
|
|
|
|
|
|
? `https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v12/static/pin-s-a+ff5a1f(${startPoint.lng},${startPoint.lat}),pin-s-b+2f7a3f(${endPoint.lng},${endPoint.lat})/auto/500x300@2x?padding=50&access_token=${process.env.NEXT_PUBLIC_MAPBOX_TOKEN}`
|
|
|
|
|
|
: null
|
|
|
|
|
|
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
// Prefill the (editable) share text once the result step is reached.
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (step === "result" && !shareEdited.current) {
|
|
|
|
|
|
setShareText(`⛳ ${club || "slag"}, ${distance} m – hull ${holeNumber}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [step, club, distance, holeNumber])
|
|
|
|
|
|
|
|
|
|
|
|
function goBack() {
|
|
|
|
|
|
if (step === "map" || step === "end") {
|
|
|
|
|
|
setStartStatus("idle")
|
|
|
|
|
|
setStep("start")
|
|
|
|
|
|
} else if (step === "club") {
|
|
|
|
|
|
// Re-measure the ball position rather than reusing a stale fix.
|
|
|
|
|
|
setEndPoint(null)
|
2026-08-08 21:38:10 +02:00
|
|
|
|
setEndMethod(null)
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
setStep("end")
|
|
|
|
|
|
} else if (step === "result") {
|
|
|
|
|
|
setStep("club")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function confirmSubmit() {
|
|
|
|
|
|
if (!startPoint || !endPoint || !club) return
|
|
|
|
|
|
onSubmit({
|
|
|
|
|
|
club,
|
|
|
|
|
|
distanceMeters: distance,
|
|
|
|
|
|
startMethod: startMethod ?? "gps",
|
|
|
|
|
|
startLat: startPoint.lat,
|
|
|
|
|
|
startLng: startPoint.lng,
|
2026-08-08 21:38:10 +02:00
|
|
|
|
endMethod: endMethod ?? "gps",
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
endLat: endPoint.lat,
|
|
|
|
|
|
endLng: endPoint.lng,
|
|
|
|
|
|
share,
|
|
|
|
|
|
shareText: share ? shareText : "",
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 07:00:11 +02:00
|
|
|
|
const onMapStep = step === "map" || step === "end"
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="fixed inset-0 z-50 flex flex-col bg-background text-foreground"
|
|
|
|
|
|
style={{ fontFamily: "var(--font-nunito), ui-sans-serif, system-ui, sans-serif" }}
|
|
|
|
|
|
role="dialog"
|
|
|
|
|
|
aria-modal="true"
|
|
|
|
|
|
aria-label={`Mål et slag, hull ${holeNumber}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* Header */}
|
|
|
|
|
|
<header className="flex shrink-0 items-start justify-between gap-3 border-b border-border px-4 pb-4 pt-[max(1rem,env(safe-area-inset-top))]">
|
|
|
|
|
|
<div className="flex items-start gap-2">
|
|
|
|
|
|
{step !== "start" ? (
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={goBack}
|
|
|
|
|
|
className="inline-flex min-h-11 items-center gap-1 rounded-xl px-2 text-base font-semibold text-muted-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
|
|
|
|
>
|
|
|
|
|
|
<ChevronLeft className="size-5 shrink-0" aria-hidden="true" />
|
|
|
|
|
|
Tilbake
|
|
|
|
|
|
</button>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
<div className="pt-1.5">
|
|
|
|
|
|
<h1 className="text-lg font-bold leading-tight text-balance">
|
|
|
|
|
|
{`Mål et slag — hull ${holeNumber}`}
|
|
|
|
|
|
</h1>
|
|
|
|
|
|
{existingShotCount > 0 ? (
|
|
|
|
|
|
<p className="mt-0.5 text-sm text-muted-foreground">
|
|
|
|
|
|
{`${existingShotCount} slag målt tidligere`}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={onCancel}
|
|
|
|
|
|
className="inline-flex min-h-11 items-center gap-1 rounded-xl px-3 text-base font-semibold text-muted-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
|
|
|
|
>
|
|
|
|
|
|
<X className="size-5 shrink-0" aria-hidden="true" />
|
|
|
|
|
|
Lukk
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Main */}
|
|
|
|
|
|
<main className={cn("flex-1", onMapStep ? "overflow-hidden" : "overflow-y-auto p-4")}>
|
|
|
|
|
|
{step === "start" ? (
|
|
|
|
|
|
<div className="mx-auto flex max-w-md flex-col gap-4 pt-2">
|
|
|
|
|
|
<p className="text-base text-muted-foreground text-pretty">
|
2026-08-08 21:38:10 +02:00
|
|
|
|
Velg hvor slaget startet.
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={useMyPosition}
|
|
|
|
|
|
disabled={startStatus === "loading"}
|
|
|
|
|
|
className="flex min-h-16 items-center gap-4 rounded-2xl border border-border bg-card p-5 text-left transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-60"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span className="flex size-11 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary">
|
|
|
|
|
|
<LocateFixed className="size-6" aria-hidden="true" />
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span className="flex flex-col">
|
|
|
|
|
|
<span className="text-base font-bold">Min posisjon nå</span>
|
|
|
|
|
|
<span className="text-sm text-muted-foreground">Bruk telefonens GPS</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setStartMethod("map_tap")
|
|
|
|
|
|
setStep("map")
|
|
|
|
|
|
}}
|
|
|
|
|
|
className="flex min-h-16 items-center gap-4 rounded-2xl border border-border bg-card p-5 text-left transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span className="flex size-11 shrink-0 items-center justify-center rounded-full bg-brand-orange/15 text-brand-orange">
|
|
|
|
|
|
<MapPin className="size-6" aria-hidden="true" />
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span className="flex flex-col">
|
|
|
|
|
|
<span className="text-base font-bold">Velg punkt på kart</span>
|
|
|
|
|
|
<span className="text-sm text-muted-foreground">Trykk på satellittkartet</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
|
|
{startStatus === "loading" ? (
|
|
|
|
|
|
<div className="flex items-center justify-center gap-3 pt-2">
|
|
|
|
|
|
<div className="size-8 animate-spin rounded-full border-4 border-primary/20 border-t-primary" />
|
|
|
|
|
|
<p className="text-base text-muted-foreground">Finner posisjonen din …</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
|
|
|
|
|
{startStatus === "error" ? (
|
|
|
|
|
|
<div className="flex flex-col gap-3 rounded-2xl border border-border bg-card p-4">
|
|
|
|
|
|
<p role="alert" className="text-base text-destructive text-pretty">
|
|
|
|
|
|
Fant ikke posisjonen din. Sjekk at posisjonstjenester er på, og prøv igjen.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={useMyPosition}
|
|
|
|
|
|
className="inline-flex min-h-11 items-center justify-center gap-2 rounded-xl bg-primary px-4 text-base font-bold text-primary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Crosshair className="size-5" aria-hidden="true" />
|
|
|
|
|
|
Prøv igjen
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
2026-08-10 07:00:11 +02:00
|
|
|
|
{/* method-argumentet i onConfirm ignoreres bevisst her -- alltid
|
|
|
|
|
|
"map_tap" på start-steget siden ingen referencePoint er satt. */}
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
{step === "map" ? <MapPointPicker onConfirm={(p) => {
|
|
|
|
|
|
setStartPoint(p)
|
|
|
|
|
|
setStep("end")
|
|
|
|
|
|
}} /> : null}
|
|
|
|
|
|
|
2026-08-10 07:00:11 +02:00
|
|
|
|
{/* Ball-steget viser NÅ alltid kartet (ADR-048-tillegg 2026-08-08,
|
|
|
|
|
|
brukerønske: "jeg skal se start og slutt på et satelittfoto...
|
|
|
|
|
|
mens jeg går opp mot ballen", "jeg ønsker å se lengden så langt
|
|
|
|
|
|
i sanntid"). Ingen egen valg-skjerm lenger -- MapPointPicker
|
|
|
|
|
|
selv viser BÅDE "Bekreft ballens posisjon" (trykket punkt) og
|
|
|
|
|
|
"Jeg er ved ballen nå" (nåværende sporede posisjon) i footeren
|
|
|
|
|
|
når referencePoint er satt, se den komponenten. */}
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
{step === "end" ? (
|
2026-08-08 21:38:10 +02:00
|
|
|
|
<MapPointPicker
|
|
|
|
|
|
referencePoint={startPoint ?? undefined}
|
|
|
|
|
|
referenceLabel="Utslag"
|
2026-08-10 07:00:11 +02:00
|
|
|
|
onConfirm={(p, method) => {
|
2026-08-08 21:38:10 +02:00
|
|
|
|
setEndPoint(p)
|
2026-08-10 07:00:11 +02:00
|
|
|
|
setEndMethod(method)
|
2026-08-08 21:38:10 +02:00
|
|
|
|
setStep("club")
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
{step === "club" ? (
|
|
|
|
|
|
<div className="mx-auto flex max-w-md flex-col gap-6 pt-2">
|
|
|
|
|
|
<div className="flex flex-col gap-1">
|
|
|
|
|
|
<h2 className="text-lg font-bold">Hvilken kølle brukte du?</h2>
|
|
|
|
|
|
<p className="text-base text-muted-foreground">Velg køllen for dette slaget.</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/* Reuses the shared ClubPicker (imported, not rebuilt). */}
|
|
|
|
|
|
<ClubPicker value={club} onChange={setClub} ownBagClubs={ownBagClubs} />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
|
|
|
|
|
{step === "result" ? (
|
|
|
|
|
|
<div className="mx-auto flex max-w-md flex-col gap-6 pt-2">
|
Fiks: kart-steget kollapset til 0px høyde (mapbox-gl.css CSS-krasj)
Produksjonsbug: "Kunne ikke laste kartet" for alle, bekreftet av bruker
etter oppfølgingsspørsmål ("alle tre" -- kart-valg, resultat-forhånds-
visning, delt bilde).
Rotårsak: mapbox-gl.css sin egen ".mapboxgl-map { position: relative }"
overstyrte Tailwind sin "absolute"-klasse på kart-beholderen (samme
klassenavn Mapbox GL JS legger til ved init, senere i CSS-cascaden).
Så snart position ikke lenger var absolute, mistet inset-0 all effekt
på størrelsen -- beholderen kollapset til height:0, kartet lastet helt
fint (style/tiles/events alle 200/204) men ble klippet vekk, usynlig.
Rettet ved å bytte til h-full w-full, som løser størrelsen via prosent-
arv uavhengig av hvilken position-verdi som vinner.
Kunne ikke fanges opp i tidligere scratch-tester siden Mapbox sin
URL-restriksjon alltid avviste localhost-scratch-opprinnelser før
kartet fikk lastet/rendret. Verifisert denne runden ved å overstyre
Referer-headeren for å simulere det ekte domenet.
Bygget i samme runde (ikke opprinnelig planlagt, brukerønske): en
client-side satellitt-forhåndsvisning i resultatsteget før lagring, med
det offentlige tokenet direkte som <img src> mot Mapbox Static Images
API.
Se CHANGELOG.md punkt 51 for full diagnose, inkl. en separat snubletråd
i mitt eget scratch-testverktøy (grep uten ^-anker matchet en
kommentarlinje) og en ekte service-worker-cache-fallgruve funnet
underveis.
2026-08-08 17:23:59 +02:00
|
|
|
|
{previewUrl ? (
|
|
|
|
|
|
// eslint-disable-next-line @next/next/no-img-element -- ekstern Mapbox-URL, ikke next/image-verdt
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={previewUrl || "/placeholder.svg"}
|
|
|
|
|
|
alt="Satellittutsnitt av slaget, med start- og sluttpunkt markert"
|
|
|
|
|
|
className="w-full rounded-2xl border border-border object-cover"
|
|
|
|
|
|
/>
|
|
|
|
|
|
) : null}
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
<div className="flex flex-col items-center gap-1 rounded-2xl border border-border bg-card p-6">
|
|
|
|
|
|
<span className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
|
|
|
|
|
|
Målt lengde
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span className="text-6xl font-extrabold tabular-nums leading-none">
|
|
|
|
|
|
{distance}
|
|
|
|
|
|
<span className="ml-1 text-3xl font-bold text-muted-foreground">m</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
{club ? (
|
|
|
|
|
|
<span className="mt-2 inline-flex items-center rounded-full bg-muted px-3 py-1 text-sm font-semibold text-foreground">
|
|
|
|
|
|
{club}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Private vs share segmented control */}
|
|
|
|
|
|
<div className="flex flex-col gap-3">
|
|
|
|
|
|
<span className="text-sm font-semibold text-muted-foreground">Deling</span>
|
|
|
|
|
|
<div
|
|
|
|
|
|
role="radiogroup"
|
|
|
|
|
|
aria-label="Deling av slaget"
|
|
|
|
|
|
className="grid grid-cols-2 gap-2 rounded-full bg-muted p-1"
|
|
|
|
|
|
>
|
|
|
|
|
|
{[
|
|
|
|
|
|
{ key: false, label: "Behold privat" },
|
|
|
|
|
|
{ key: true, label: "Del i feeden" },
|
|
|
|
|
|
].map((opt) => {
|
|
|
|
|
|
const selected = share === opt.key
|
|
|
|
|
|
return (
|
|
|
|
|
|
<button
|
|
|
|
|
|
key={String(opt.key)}
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
role="radio"
|
|
|
|
|
|
aria-checked={selected}
|
|
|
|
|
|
onClick={() => setShare(opt.key)}
|
|
|
|
|
|
className={cn(
|
|
|
|
|
|
"inline-flex min-h-11 items-center justify-center rounded-full px-4 text-base font-bold transition-colors",
|
|
|
|
|
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
|
|
|
|
selected
|
|
|
|
|
|
? "bg-primary text-primary-foreground"
|
|
|
|
|
|
: "text-muted-foreground hover:text-foreground",
|
|
|
|
|
|
)}
|
|
|
|
|
|
>
|
|
|
|
|
|
{opt.label}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
)
|
|
|
|
|
|
})}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{share ? (
|
|
|
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
|
<label htmlFor="share-text" className="text-sm font-semibold text-muted-foreground">
|
|
|
|
|
|
Innlegg
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<Textarea
|
|
|
|
|
|
id="share-text"
|
|
|
|
|
|
value={shareText}
|
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
|
shareEdited.current = true
|
|
|
|
|
|
setShareText(e.target.value)
|
|
|
|
|
|
}}
|
|
|
|
|
|
rows={3}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</div>
|
Fiks: slagmåling ga alltid 0m, delinger forsvant stille
Produksjonsbug rapportert av bruker rett etter forrige utrulling: "den
målte aldri mer enn 0 meter. Jeg så ingen bilder."
Rotårsak 1: "end"-steget (ballens posisjon) avfyrte GPS-målingen
automatisk idet steget ble aktivt, uten tid for brukeren til faktisk å
gå fra utslagsstedet til ballen -- start/slutt endte på samme sted,
samme øyeblikk. Fjernet auto-avfyringen, krever nå et eksplisitt "Jeg
er ved ballen nå"-trykk.
Rotårsak 2 (konsekvens av #1): en 0m-avstand avvist av backendens
distance_meters > 0-validering (422) gjorde at submitShot() bare lukket
arket stille, ingen feilmelding. Lagt til submitError/submitting-state,
parser både appens {detail:{message}} og FastAPI/Pydantic sin rå
{detail:[{msg}]}-valideringsform (bekreftet eksakt hvilken ved å
trigge en ekte 422), viser feilen i arket, holder det åpent ved feil.
Scratch-verifisert med navigator.geolocation midlertidig overstyrt
(ekte GPS-tillatelse permanent denied i CDP-automatiserte nettleser-
sesjoner): "Jeg er ved ballen nå" vises korrekt, et ekte gap ga
"130 m" (ikke 0) og delingen postet riktig, og en 0m-innsending viser nå
feilmeldingen i stedet for å lukke stille. Se CHANGELOG.md punkt 49.
2026-08-08 15:06:48 +02:00
|
|
|
|
|
|
|
|
|
|
{submitError ? (
|
|
|
|
|
|
<p role="alert" className="text-base text-destructive text-pretty">
|
|
|
|
|
|
{submitError}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
) : null}
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</main>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Footer — hidden on map step (MapPointPicker owns its own confirm bar)
|
|
|
|
|
|
and on the transient GPS steps. */}
|
|
|
|
|
|
{step === "club" || step === "result" ? (
|
|
|
|
|
|
<footer className="shrink-0 border-t border-border bg-background p-4 pb-[max(1rem,env(safe-area-inset-bottom))]">
|
|
|
|
|
|
{step === "club" ? (
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
disabled={!club.trim()}
|
|
|
|
|
|
onClick={() => setStep("result")}
|
|
|
|
|
|
className="inline-flex min-h-14 w-full items-center justify-center rounded-xl bg-primary px-6 text-lg font-bold text-primary-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
|
|
|
>
|
|
|
|
|
|
Neste
|
|
|
|
|
|
</button>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
Fiks: slagmåling ga alltid 0m, delinger forsvant stille
Produksjonsbug rapportert av bruker rett etter forrige utrulling: "den
målte aldri mer enn 0 meter. Jeg så ingen bilder."
Rotårsak 1: "end"-steget (ballens posisjon) avfyrte GPS-målingen
automatisk idet steget ble aktivt, uten tid for brukeren til faktisk å
gå fra utslagsstedet til ballen -- start/slutt endte på samme sted,
samme øyeblikk. Fjernet auto-avfyringen, krever nå et eksplisitt "Jeg
er ved ballen nå"-trykk.
Rotårsak 2 (konsekvens av #1): en 0m-avstand avvist av backendens
distance_meters > 0-validering (422) gjorde at submitShot() bare lukket
arket stille, ingen feilmelding. Lagt til submitError/submitting-state,
parser både appens {detail:{message}} og FastAPI/Pydantic sin rå
{detail:[{msg}]}-valideringsform (bekreftet eksakt hvilken ved å
trigge en ekte 422), viser feilen i arket, holder det åpent ved feil.
Scratch-verifisert med navigator.geolocation midlertidig overstyrt
(ekte GPS-tillatelse permanent denied i CDP-automatiserte nettleser-
sesjoner): "Jeg er ved ballen nå" vises korrekt, et ekte gap ga
"130 m" (ikke 0) og delingen postet riktig, og en 0m-innsending viser nå
feilmeldingen i stedet for å lukke stille. Se CHANGELOG.md punkt 49.
2026-08-08 15:06:48 +02:00
|
|
|
|
disabled={submitting}
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
onClick={confirmSubmit}
|
Fiks: slagmåling ga alltid 0m, delinger forsvant stille
Produksjonsbug rapportert av bruker rett etter forrige utrulling: "den
målte aldri mer enn 0 meter. Jeg så ingen bilder."
Rotårsak 1: "end"-steget (ballens posisjon) avfyrte GPS-målingen
automatisk idet steget ble aktivt, uten tid for brukeren til faktisk å
gå fra utslagsstedet til ballen -- start/slutt endte på samme sted,
samme øyeblikk. Fjernet auto-avfyringen, krever nå et eksplisitt "Jeg
er ved ballen nå"-trykk.
Rotårsak 2 (konsekvens av #1): en 0m-avstand avvist av backendens
distance_meters > 0-validering (422) gjorde at submitShot() bare lukket
arket stille, ingen feilmelding. Lagt til submitError/submitting-state,
parser både appens {detail:{message}} og FastAPI/Pydantic sin rå
{detail:[{msg}]}-valideringsform (bekreftet eksakt hvilken ved å
trigge en ekte 422), viser feilen i arket, holder det åpent ved feil.
Scratch-verifisert med navigator.geolocation midlertidig overstyrt
(ekte GPS-tillatelse permanent denied i CDP-automatiserte nettleser-
sesjoner): "Jeg er ved ballen nå" vises korrekt, et ekte gap ga
"130 m" (ikke 0) og delingen postet riktig, og en 0m-innsending viser nå
feilmeldingen i stedet for å lukke stille. Se CHANGELOG.md punkt 49.
2026-08-08 15:06:48 +02:00
|
|
|
|
className="inline-flex min-h-14 w-full items-center justify-center gap-2 rounded-xl bg-primary px-6 text-lg font-bold text-primary-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
>
|
Fiks: slagmåling ga alltid 0m, delinger forsvant stille
Produksjonsbug rapportert av bruker rett etter forrige utrulling: "den
målte aldri mer enn 0 meter. Jeg så ingen bilder."
Rotårsak 1: "end"-steget (ballens posisjon) avfyrte GPS-målingen
automatisk idet steget ble aktivt, uten tid for brukeren til faktisk å
gå fra utslagsstedet til ballen -- start/slutt endte på samme sted,
samme øyeblikk. Fjernet auto-avfyringen, krever nå et eksplisitt "Jeg
er ved ballen nå"-trykk.
Rotårsak 2 (konsekvens av #1): en 0m-avstand avvist av backendens
distance_meters > 0-validering (422) gjorde at submitShot() bare lukket
arket stille, ingen feilmelding. Lagt til submitError/submitting-state,
parser både appens {detail:{message}} og FastAPI/Pydantic sin rå
{detail:[{msg}]}-valideringsform (bekreftet eksakt hvilken ved å
trigge en ekte 422), viser feilen i arket, holder det åpent ved feil.
Scratch-verifisert med navigator.geolocation midlertidig overstyrt
(ekte GPS-tillatelse permanent denied i CDP-automatiserte nettleser-
sesjoner): "Jeg er ved ballen nå" vises korrekt, et ekte gap ga
"130 m" (ikke 0) og delingen postet riktig, og en 0m-innsending viser nå
feilmeldingen i stedet for å lukke stille. Se CHANGELOG.md punkt 49.
2026-08-08 15:06:48 +02:00
|
|
|
|
{submitting ? (
|
|
|
|
|
|
<div className="size-5 shrink-0 animate-spin rounded-full border-2 border-primary-foreground/30 border-t-primary-foreground" />
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<Check className="size-5 shrink-0" aria-hidden="true" />
|
|
|
|
|
|
)}
|
|
|
|
|
|
{submitting ? "Lagrer …" : "Lagre slag"}
|
Slag-for-slag GPS-avstandsmåling: entry point i scoring-veiviseren (ADR-048)
Første inngangspunkt av to planlagte: en "Mål et slag"-knapp i
ScoringWizard sitt detalj-steg, rett etter kølle-plukkeren for utslaget.
Komponentene (components/shot/shot-measurement-sheet.tsx,
map-point-picker.tsx) kommer fra en egen, teknisk V0-prompt (design-
tokens fra DESIGN_SYSTEM.md spesifisert som hard begrensning, siden
dette er et ark INNI en eksisterende Forest Green-skjerm, ikke en ny
frittstående side) -- meget tro mot spesifikasjonen: korrekt
next/dynamic({ssr:false})-lasting av kartsteget, ingen mapbox-gl-import
på GPS-only-stien, kartet mountes kun én gang per arkåpning.
components/ui/textarea.tsx (ny shadcn-primitiv) lagt til. Eksisterende,
lokale ClubPicker i round-detail.tsx trukket ut til
components/teecup/club-picker.tsx (ren utrekking, ingen atferdsendring)
slik at måle-arket kan gjenbruke den fremfor V0s egen plassholder-kopi.
Wiret mot ekte backend: POST .../holes/{n}/shots ved innsending, valgfri
etterfølgende POST .../shots/{id}/share ved deling, shot-telling hentet
og vist i selve knappen ("Mål et slag (N målt)").
Gjenstår: inngangspunkt to (alltid-synlig merkelapp på hull-kortet for
retroaktiv måling + lagformat-støtte), ekte Mapbox-tokens, og migrasjon
060_round_shot.sql mot ekte teecup_db (ingen av disse rørt ennå).
2026-08-08 12:37:30 +02:00
|
|
|
|
</button>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</footer>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default ShotMeasurementSheet
|