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 mapboxgl from "mapbox-gl"
|
|
|
|
|
import "mapbox-gl/dist/mapbox-gl.css"
|
2026-08-10 07:00:11 +02:00
|
|
|
import { Crosshair, MapPin } from "lucide-react"
|
|
|
|
|
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
|
|
|
|
|
|
|
|
type LngLat = { lng: number; lat: number }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* MapPointPicker
|
|
|
|
|
*
|
2026-08-10 07:00:11 +02:00
|
|
|
* To ulike modi, styrt av `referencePoint`:
|
|
|
|
|
* - Start-steget (referencePoint IKKE satt): rendret kun når brukeren
|
|
|
|
|
* velger "Velg punkt på kart". Trykk-for-å-plassere en markør, ett
|
|
|
|
|
* engangs-GPS-oppslag kun for sentrering.
|
|
|
|
|
* - Ball-steget (referencePoint satt, ADR-048/049-tillegg): rendres
|
|
|
|
|
* ALLTID. Rent informativt kart (referansepunkt + løpende sporet
|
|
|
|
|
* posisjon + sanntidsavstand) -- IKKE trykkbart for å plassere ballen.
|
|
|
|
|
* Ballens posisjon bekreftes alltid med sporet GPS-posisjon
|
|
|
|
|
* ("Jeg er ved ballen nå"), aldri ved kart-trykk (brukerønske
|
|
|
|
|
* 2026-08-09: "bekreft ballens posisjon er unødvendig" -- fjernet
|
|
|
|
|
* trykk-alternativet som fantes en kort periode før dette).
|
|
|
|
|
*
|
|
|
|
|
* Alltid via next/dynamic(..., { ssr: false }) fra foreldre-komponenten.
|
|
|
|
|
* Mountes én gang per steg og forblir mountet til det steget forlates, så
|
|
|
|
|
* selve Mapbox-KARTET initialiseres nøyaktig én gang (empty-deps
|
|
|
|
|
* useEffect) — pans/zoom re-initialiserer det aldri. Dette holder
|
|
|
|
|
* Mapbox-kartlastninger (som faktureres) til én per steg-åpning.
|
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
|
|
|
*/
|
2026-08-08 21:38:10 +02:00
|
|
|
export function MapPointPicker({
|
|
|
|
|
onConfirm,
|
|
|
|
|
referencePoint,
|
|
|
|
|
referenceLabel = "Utslag",
|
|
|
|
|
}: {
|
2026-08-10 07:00:11 +02:00
|
|
|
/** method er "map_tap" ved trykk-bekreftelse (kun start-steget), "gps"
|
|
|
|
|
* ved "Jeg er ved ballen nå"-bekreftelse (kun ball-steget). */
|
|
|
|
|
onConfirm: (lngLat: LngLat, method: "gps" | "map_tap") => void
|
2026-08-08 21:38:10 +02:00
|
|
|
/**
|
2026-08-10 07:00:11 +02:00
|
|
|
* Satt KUN på ballposisjon-steget: et fast, ikke-flyttbart
|
|
|
|
|
* referansepunkt (utslagspunktet) vises på kartet, og kartet forsøker å
|
|
|
|
|
* vise BÅDE dette og brukerens nåværende posisjon i samme bilde --
|
|
|
|
|
* brukerønske: "slagpunktet må være en del av det jeg ser". Trigger
|
|
|
|
|
* samtidig løpende posisjonssporing (se lenger ned) -- ALDRI satt på
|
|
|
|
|
* start-steget, som fortsatt kun gjør ett engangs-oppslag.
|
2026-08-08 21:38:10 +02:00
|
|
|
*/
|
|
|
|
|
referencePoint?: LngLat
|
|
|
|
|
referenceLabel?: string
|
|
|
|
|
}) {
|
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 containerRef = useRef<HTMLDivElement | null>(null)
|
|
|
|
|
const mapRef = useRef<mapboxgl.Map | null>(null)
|
|
|
|
|
const markerRef = useRef<mapboxgl.Marker | null>(null)
|
2026-08-08 21:38:10 +02:00
|
|
|
const referenceMarkerRef = useRef<mapboxgl.Marker | null>(null)
|
2026-08-10 07:00:11 +02:00
|
|
|
const liveMarkerRef = useRef<mapboxgl.Marker | null>(null)
|
|
|
|
|
const watchIdRef = useRef<number | 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 [loaded, setLoaded] = useState(false)
|
|
|
|
|
const [point, setPoint] = useState<LngLat | null>(null)
|
|
|
|
|
const [error, setError] = useState<string | null>(null)
|
2026-08-10 07:00:11 +02:00
|
|
|
// Løpende posisjon + avstand-fra-referansepunkt-så-langt (ADR-048-tillegg
|
|
|
|
|
// 2026-08-08, brukerønske: "jeg ønsker å se lengden så langt i sanntid
|
|
|
|
|
// mens jeg nærmer meg ballen"). Kun i bruk når referencePoint er satt.
|
|
|
|
|
const [livePoint, setLivePoint] = useState<LngLat | null>(null)
|
|
|
|
|
const [liveDistance, setLiveDistance] = useState<number | 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
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const token = process.env.NEXT_PUBLIC_MAPBOX_TOKEN
|
|
|
|
|
const container = containerRef.current
|
|
|
|
|
if (!container) return
|
|
|
|
|
|
|
|
|
|
if (!token) {
|
2026-08-10 07:00:11 +02:00
|
|
|
setError("Kartet er ikke tilgjengelig akkurat nå.")
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-08 18:35:21 +02:00
|
|
|
let cancelled = false
|
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
|
|
|
|
2026-08-08 18:35:21 +02:00
|
|
|
// Reell bug funnet 2026-08-08: kartet sentrerte ALLTID på en hardkodet
|
|
|
|
|
// Oslo-koordinat -- en kommentar her hevdet "real app centers on
|
|
|
|
|
// last-known position", men den logikken fantes aldri, kun påstanden.
|
|
|
|
|
// Henter nå brukerens faktiske GPS-posisjon FØR kartet initialiseres
|
2026-08-10 07:00:11 +02:00
|
|
|
// (ett engangs-oppslag for selve sentreringen), med Oslo som fallback
|
|
|
|
|
// KUN hvis posisjon ikke kan hentes (avslått tillatelse, tidsavbrudd,
|
|
|
|
|
// ingen støtte).
|
2026-08-08 21:38:10 +02:00
|
|
|
// fitTo: satt når vi HAR en brukerposisjon OG et referansepunkt --
|
|
|
|
|
// kartet zoomer/panorerer da til å vise begge (padding rundt), i stedet
|
|
|
|
|
// for bare å sentrere på ett av dem, slik at referansepunktet garantert
|
|
|
|
|
// er synlig med det samme.
|
|
|
|
|
function initMap(center: [number, number], fitTo?: [[number, number], [number, number]]) {
|
2026-08-08 18:35:21 +02:00
|
|
|
if (cancelled || !container) return
|
|
|
|
|
mapboxgl.accessToken = token as string
|
|
|
|
|
const map = new mapboxgl.Map({
|
|
|
|
|
container,
|
|
|
|
|
style: "mapbox://styles/mapbox/satellite-v9",
|
|
|
|
|
center,
|
2026-08-08 21:38:10 +02:00
|
|
|
zoom: referencePoint ? 17 : 16,
|
2026-08-08 18:35:21 +02:00
|
|
|
attributionControl: false,
|
|
|
|
|
})
|
|
|
|
|
mapRef.current = map
|
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
|
|
|
|
2026-08-08 21:38:10 +02:00
|
|
|
map.on("load", () => {
|
|
|
|
|
setLoaded(true)
|
|
|
|
|
if (fitTo) {
|
|
|
|
|
const bounds = new mapboxgl.LngLatBounds(fitTo[0], fitTo[0])
|
|
|
|
|
bounds.extend(fitTo[1])
|
|
|
|
|
map.fitBounds(bounds, { padding: 80, maxZoom: 18, duration: 0 })
|
|
|
|
|
}
|
|
|
|
|
})
|
2026-08-08 18:35:21 +02:00
|
|
|
map.on("error", () => setError("Kunne ikke laste kartet."))
|
|
|
|
|
|
2026-08-08 21:38:10 +02:00
|
|
|
// Fast referansemarkør (utslagspunktet) -- kan ikke flyttes, kun til
|
|
|
|
|
// orientering. Egen farge (samme "pin-a"-oransje som brukes i
|
|
|
|
|
// delings-bildet) for å skille tydelig fra punktet som plasseres.
|
|
|
|
|
if (referencePoint) {
|
|
|
|
|
referenceMarkerRef.current = new mapboxgl.Marker({ color: "#ff5a1f" })
|
|
|
|
|
.setLngLat([referencePoint.lng, referencePoint.lat])
|
|
|
|
|
.addTo(map)
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-08 18:35:21 +02:00
|
|
|
// Tap to place/move a single draggable marker — never re-inits the map.
|
2026-08-10 07:00:11 +02:00
|
|
|
// KUN på start-steget (ingen referencePoint): brukerønske 2026-08-09,
|
|
|
|
|
// "bekreft ballens posisjon er unødvendig" -- ballens posisjon
|
|
|
|
|
// bekreftes nå ALLTID med sporet GPS-posisjon ("Jeg er ved ballen
|
|
|
|
|
// nå"), aldri ved å trykke på kartet. Kartet på ball-steget er dermed
|
|
|
|
|
// rent informativt (referansepunkt + sanntidsposisjon/-avstand), ikke
|
|
|
|
|
// interaktivt for plassering.
|
|
|
|
|
if (!referencePoint) {
|
|
|
|
|
map.on("click", (e) => {
|
|
|
|
|
const lngLat = { lng: e.lngLat.lng, lat: e.lngLat.lat }
|
|
|
|
|
if (!markerRef.current) {
|
|
|
|
|
const marker = new mapboxgl.Marker({ draggable: true, color: "#d2551a" })
|
|
|
|
|
.setLngLat(e.lngLat)
|
|
|
|
|
.addTo(map)
|
|
|
|
|
marker.on("dragend", () => {
|
|
|
|
|
const p = marker.getLngLat()
|
|
|
|
|
setPoint({ lng: p.lng, lat: p.lat })
|
|
|
|
|
})
|
|
|
|
|
markerRef.current = marker
|
|
|
|
|
} else {
|
|
|
|
|
markerRef.current.setLngLat(e.lngLat)
|
|
|
|
|
}
|
|
|
|
|
setPoint(lngLat)
|
|
|
|
|
})
|
|
|
|
|
}
|
2026-08-08 18:35:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const OSLO_FALLBACK: [number, number] = [10.7522, 59.9139]
|
2026-08-08 21:38:10 +02:00
|
|
|
const fallbackCenter: [number, number] = referencePoint
|
|
|
|
|
? [referencePoint.lng, referencePoint.lat]
|
|
|
|
|
: OSLO_FALLBACK
|
2026-08-08 18:35:21 +02:00
|
|
|
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
|
|
|
navigator.geolocation.getCurrentPosition(
|
2026-08-08 21:38:10 +02:00
|
|
|
(pos) => {
|
|
|
|
|
const here: [number, number] = [pos.coords.longitude, pos.coords.latitude]
|
|
|
|
|
if (referencePoint) {
|
|
|
|
|
initMap(here, [here, [referencePoint.lng, referencePoint.lat]])
|
|
|
|
|
} else {
|
|
|
|
|
initMap(here)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
() => initMap(fallbackCenter),
|
2026-08-08 18:35:21 +02:00
|
|
|
{ enableHighAccuracy: true, timeout: 8000 },
|
|
|
|
|
)
|
|
|
|
|
} else {
|
2026-08-08 21:38:10 +02:00
|
|
|
initMap(fallbackCenter)
|
2026-08-08 18:35:21 +02:00
|
|
|
}
|
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
|
|
|
|
2026-08-10 07:00:11 +02:00
|
|
|
// Løpende posisjonssporing -- KUN på ballposisjon-steget (referencePoint
|
|
|
|
|
// satt). Egen, bevisst unntak fra ADR-048s opprinnelige "ingen løpende
|
|
|
|
|
// watchPosition"-prinsipp (som gjaldt kostnadskontroll for KART-
|
|
|
|
|
// lastninger): watchPosition i seg selv koster ingenting hos Mapbox --
|
|
|
|
|
// det er ren nettleser-GPS, ikke et kartlastnings-kall -- og brukeren
|
|
|
|
|
// ba eksplisitt om sanntids-avstand mens de går mot ballen. Kartet
|
|
|
|
|
// forblir uansett kun ÉN instans (samme map-objekt gjenbrukes, aldri
|
|
|
|
|
// re-initialisert), kun MARKØRPOSISJONEN oppdateres løpende.
|
|
|
|
|
if (referencePoint && typeof navigator !== "undefined" && navigator.geolocation) {
|
|
|
|
|
watchIdRef.current = navigator.geolocation.watchPosition(
|
|
|
|
|
(pos) => {
|
|
|
|
|
if (cancelled) return
|
|
|
|
|
const p = { lng: pos.coords.longitude, lat: pos.coords.latitude }
|
|
|
|
|
setLivePoint(p)
|
|
|
|
|
setLiveDistance(haversineMeters(referencePoint, p))
|
|
|
|
|
if (mapRef.current) {
|
|
|
|
|
if (!liveMarkerRef.current) {
|
|
|
|
|
const el = document.createElement("div")
|
|
|
|
|
el.className = "size-4 rounded-full border-2 border-white bg-[#2b7fff] shadow-md"
|
|
|
|
|
liveMarkerRef.current = new mapboxgl.Marker({ element: el }).setLngLat([p.lng, p.lat]).addTo(mapRef.current)
|
|
|
|
|
} else {
|
|
|
|
|
liveMarkerRef.current.setLngLat([p.lng, p.lat])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
() => {
|
|
|
|
|
// Feil/avslått tillatelse underveis -- degraderer grasiøst, bruker
|
|
|
|
|
// kan fortsatt trykke selv ut ballens posisjon på kartet.
|
|
|
|
|
},
|
|
|
|
|
{ enableHighAccuracy: true, maximumAge: 1000 },
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
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 () => {
|
2026-08-08 18:35:21 +02:00
|
|
|
cancelled = true
|
2026-08-10 07:00:11 +02:00
|
|
|
if (watchIdRef.current !== null && typeof navigator !== "undefined" && navigator.geolocation) {
|
|
|
|
|
navigator.geolocation.clearWatch(watchIdRef.current)
|
|
|
|
|
}
|
|
|
|
|
liveMarkerRef.current?.remove()
|
|
|
|
|
liveMarkerRef.current = null
|
2026-08-08 21:38:10 +02:00
|
|
|
referenceMarkerRef.current?.remove()
|
|
|
|
|
referenceMarkerRef.current = 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
|
|
|
markerRef.current?.remove()
|
|
|
|
|
markerRef.current = null
|
2026-08-08 18:35:21 +02:00
|
|
|
mapRef.current?.remove()
|
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
|
|
|
mapRef.current = null
|
|
|
|
|
}
|
2026-08-08 21:38:10 +02:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- montert én gang per steg, se komponent-docstring
|
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="flex h-full flex-col">
|
|
|
|
|
<div className="relative flex-1">
|
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
|
|
|
{/* Map canvas host — kept mounted for the map's whole lifetime.
|
|
|
|
|
`h-full w-full`, IKKE `absolute inset-0`: mapbox-gl.css sin egen
|
|
|
|
|
`.mapboxgl-map { position: relative }`-regel overstyrer en
|
|
|
|
|
`absolute`-Tailwind-klasse her (samme klasse-navn, senere i
|
|
|
|
|
cascade siden mapbox-gl.css importeres i denne komponentfilen)
|
|
|
|
|
-- når posisjonen dermed blir `relative` i stedet for
|
|
|
|
|
`absolute`, mister `inset-0` all effekt på størrelsen (den
|
|
|
|
|
styrer kun posisjon/størrelse for absolutt/fixed-plasserte
|
|
|
|
|
elementer), og beholderen kollapser til 0 høyde uansett hvilken
|
|
|
|
|
posisjonsverdi som vinner kappløpet. `h-full`/`w-full` løser
|
|
|
|
|
størrelsen via prosent-arv i stedet, som fungerer likt for
|
|
|
|
|
både `relative` og `absolute`. Reell bug funnet 2026-08-08,
|
|
|
|
|
se CHANGELOG.md. */}
|
|
|
|
|
<div ref={containerRef} className="absolute inset-0 h-full w-full" aria-label="Satellittkart" role="application" />
|
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
|
|
|
|
|
|
|
|
{!loaded && !error ? (
|
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center bg-background">
|
|
|
|
|
<div className="flex flex-col items-center gap-4">
|
|
|
|
|
<div className="size-8 animate-spin rounded-full border-4 border-primary/20 border-t-primary" />
|
|
|
|
|
<p className="text-base text-muted-foreground">Laster kart …</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
|
|
|
{error ? (
|
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center p-6">
|
|
|
|
|
<p role="alert" className="max-w-sm text-center text-base text-destructive">
|
|
|
|
|
{error}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
|
|
|
|
|
2026-08-08 21:38:10 +02:00
|
|
|
{referencePoint ? (
|
|
|
|
|
<div className="pointer-events-none absolute left-4 top-4 flex items-center gap-2 rounded-full bg-card/95 px-3 py-1.5 text-xs font-semibold text-foreground shadow-md">
|
|
|
|
|
<span className="size-2.5 shrink-0 rounded-full" style={{ backgroundColor: "#ff5a1f" }} aria-hidden="true" />
|
|
|
|
|
{referenceLabel}
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
|
|
|
|
|
2026-08-10 07:00:11 +02:00
|
|
|
{/* Trykk-instruksjon KUN på start-steget -- ball-steget har ingen
|
|
|
|
|
trykk-handling lenger (se click-handler-kommentaren over). */}
|
|
|
|
|
{loaded && !point && !error && !referencePoint ? (
|
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="pointer-events-none absolute inset-x-0 top-4 flex justify-center px-4">
|
|
|
|
|
<p className="flex items-center gap-2 rounded-full bg-card/95 px-4 py-2 text-sm font-semibold text-foreground shadow-md">
|
|
|
|
|
<MapPin className="size-4 shrink-0" aria-hidden="true" />
|
2026-08-10 07:00:11 +02:00
|
|
|
Trykk på kartet for å plassere punktet
|
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>
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
2026-08-10 07:00:11 +02:00
|
|
|
|
|
|
|
|
{/* Sanntids-avstand så langt -- kun ball-steget. Brukerønske
|
|
|
|
|
2026-08-08: "jeg ønsker å se lengden så langt i sanntid mens
|
|
|
|
|
jeg nærmer meg ballen". */}
|
|
|
|
|
{referencePoint && liveDistance !== null ? (
|
|
|
|
|
<div className="pointer-events-none absolute inset-x-0 bottom-4 flex justify-center px-4">
|
|
|
|
|
<div className="flex flex-col items-center gap-0.5 rounded-2xl bg-card/95 px-5 py-2.5 shadow-md">
|
|
|
|
|
<span className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
|
|
|
Avstand så langt
|
|
|
|
|
</span>
|
|
|
|
|
<span className="text-3xl font-extrabold tabular-nums leading-none text-foreground">
|
|
|
|
|
{Math.round(liveDistance)}
|
|
|
|
|
<span className="ml-1 text-lg font-bold text-muted-foreground">m</span>
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : 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>
|
|
|
|
|
|
|
|
|
|
<div className="shrink-0 border-t border-border bg-background p-4 pb-[max(1rem,env(safe-area-inset-bottom))]">
|
2026-08-10 07:00:11 +02:00
|
|
|
{referencePoint ? (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
disabled={!livePoint}
|
|
|
|
|
onClick={() => livePoint && onConfirm(livePoint, "gps")}
|
|
|
|
|
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"
|
|
|
|
|
>
|
|
|
|
|
<Crosshair className="size-5 shrink-0" aria-hidden="true" />
|
|
|
|
|
Jeg er ved ballen nå
|
|
|
|
|
</button>
|
|
|
|
|
) : (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
disabled={!point}
|
|
|
|
|
onClick={() => point && onConfirm(point, "map_tap")}
|
|
|
|
|
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"
|
|
|
|
|
>
|
|
|
|
|
Bekreft punkt
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
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>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default MapPointPicker
|