Skjul HCP på offentlig leaderboard for rene bruttoslagspill-turneringer

Bruker: "når det er brutto som er hovedkonkurransen trenger vi ikke se
hcp i leaderboarden" -- HCP er kun meningsfullt der den faktisk brukes
til slagfordeling (netto/stableford/Københavner/BBB), ikke ren brutto/
eclectic-gross. PublicTournamentInfo += scoring_method (manglet før),
leaderboard-raden skjuler nå HCP-teksten når turneringens scoring_method
er stroke_gross eller eclectic_gross. Verifisert mot ekte Klubbmesterskap
2026 (bekreftet stroke_gross) i scratch før utrulling.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erol Haagenrud 2026-08-21 20:20:22 +02:00
parent 3a9ae02841
commit dd974678fa
3 changed files with 26 additions and 7 deletions

View file

@ -135,6 +135,12 @@ class PublicTournamentInfo(BaseModel):
# individuell turnering, se ARCHITECTURE_DECISIONS.md/CHANGELOG.md # individuell turnering, se ARCHITECTURE_DECISIONS.md/CHANGELOG.md
# samme dag). # samme dag).
format_type: str format_type: str
# 2026-08-21: for offentlig visning av HCP på leaderboardet -- bruker:
# "når det er brutto som er hovedkonkurransen trenger vi ikke se hcp".
# HCP er kun meningsfullt der den faktisk brukes til slagfordeling
# (netto/stableford/Københavner/BBB), ikke ren bruttoslagspill/eclectic
# gross. `None` for lagturneringer (scoring_method er individuell-kun).
scoring_method: str | None
visibility: str visibility: str
description: str | None description: str | None
start_date: date | None start_date: date | None
@ -158,7 +164,7 @@ async def get_public_tournament(
row = await conn.fetchrow( row = await conn.fetchrow(
""" """
SELECT t.id::text, t.name, o.name AS organization_name, t.status::text, SELECT t.id::text, t.name, o.name AS organization_name, t.status::text,
t.format_type::text, t.visibility, t.description, t.hero_image_key, t.join_code, t.format_type::text, t.scoring_method, t.visibility, t.description, t.hero_image_key, t.join_code,
t.start_date, t.end_date, t.registration_deadline, t.start_date, t.end_date, t.registration_deadline,
t.registration_capacity, t.registration_capacity,
(SELECT count(*)::int FROM tournament_registration tr (SELECT count(*)::int FROM tournament_registration tr
@ -190,6 +196,7 @@ async def get_public_tournament(
organization_name=row["organization_name"], organization_name=row["organization_name"],
status=row["status"], status=row["status"],
format_type=row["format_type"], format_type=row["format_type"],
scoring_method=row["scoring_method"],
visibility=row["visibility"], visibility=row["visibility"],
description=row["description"], description=row["description"],
start_date=row["start_date"], start_date=row["start_date"],

View file

@ -64,7 +64,16 @@ type ApiLeaderboardEntry = {
type ApiHole = { hole_number: number; par: number; gross_strokes: number | null } type ApiHole = { hole_number: number; par: number; gross_strokes: number | null }
type ApiTournamentInfo = { name: string; format_type: string; status: string } type ApiTournamentInfo = { name: string; format_type: string; status: string; scoring_method: string | null }
// HCP er kun meningsfullt der den faktisk brukes til slagfordeling --
// ren bruttoslagspill (og brutto-eclectic) har ingen HCP-avhengighet.
// Bruker 2026-08-21: "når det er brutto som er hovedkonkurransen trenger
// vi ikke se hcp i leaderboarden".
const GROSS_ONLY_METHODS = new Set(["stroke_gross", "eclectic_gross"])
function shouldShowHcp(scoringMethod: string | null): boolean {
return scoringMethod != null && !GROSS_ONLY_METHODS.has(scoringMethod)
}
/* ------------------------------------------------------------------ * /* ------------------------------------------------------------------ *
* Visningstyper for hull-rutenettet (per runde, hentes lat ved utvidelse) * Visningstyper for hull-rutenettet (per runde, hentes lat ved utvidelse)
@ -265,10 +274,12 @@ function LeaderboardRow({
entry, entry,
organizationlessBase, organizationlessBase,
roundId, roundId,
showHcp,
}: { }: {
entry: ApiLeaderboardEntry entry: ApiLeaderboardEntry
organizationlessBase: string organizationlessBase: string
roundId: string | null roundId: string | null
showHcp: boolean
}) { }) {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [holes, setHoles] = useState<HoleResult[] | null>(null) const [holes, setHoles] = useState<HoleResult[] | null>(null)
@ -312,8 +323,8 @@ function LeaderboardRow({
Undertittelen (HCP/klasse, mindre viktig) beholder truncate. */} Undertittelen (HCP/klasse, mindre viktig) beholder truncate. */}
<span className="text-pretty text-[15px] font-bold leading-tight text-foreground">{entry.player_name}</span> <span className="text-pretty text-[15px] font-bold leading-tight text-foreground">{entry.player_name}</span>
<span className="truncate text-xs text-muted-foreground"> <span className="truncate text-xs text-muted-foreground">
{entry.handicap_index != null && `HCP ${entry.handicap_index.toFixed(1).replace(".", ",")}`} {showHcp && entry.handicap_index != null && `HCP ${entry.handicap_index.toFixed(1).replace(".", ",")}`}
{entry.handicap_index != null && entry.class_name ? " · " : ""} {showHcp && entry.handicap_index != null && entry.class_name ? " · " : ""}
{entry.class_name} {entry.class_name}
</span> </span>
</span> </span>
@ -496,6 +507,7 @@ export function PublicIndividualLive({ tournamentId, code }: { tournamentId: str
const hasCut = belowCut.length > 0 const hasCut = belowCut.length > 0
const isFinished = tournament?.status === "completed" || tournament?.status === "archived" const isFinished = tournament?.status === "completed" || tournament?.status === "archived"
const showHcp = shouldShowHcp(tournament?.scoring_method ?? null)
if (loading) { if (loading) {
return ( return (
@ -619,7 +631,7 @@ export function PublicIndividualLive({ tournamentId, code }: { tournamentId: str
) : ( ) : (
<ol className="divide-y divide-border overflow-hidden rounded-2xl border border-border bg-card shadow-md shadow-black/[0.06]"> <ol className="divide-y divide-border overflow-hidden rounded-2xl border border-border bg-card shadow-md shadow-black/[0.06]">
{advancing.map((e) => ( {advancing.map((e) => (
<LeaderboardRow key={e.tournament_participant_id} entry={e} organizationlessBase={base} roundId={selectedRoundId} /> <LeaderboardRow key={e.tournament_participant_id} entry={e} organizationlessBase={base} roundId={selectedRoundId} showHcp={showHcp} />
))} ))}
{hasCut && ( {hasCut && (
@ -633,7 +645,7 @@ export function PublicIndividualLive({ tournamentId, code }: { tournamentId: str
)} )}
{belowCut.map((e) => ( {belowCut.map((e) => (
<LeaderboardRow key={e.tournament_participant_id} entry={e} organizationlessBase={base} roundId={selectedRoundId} /> <LeaderboardRow key={e.tournament_participant_id} entry={e} organizationlessBase={base} roundId={selectedRoundId} showHcp={showHcp} />
))} ))}
</ol> </ol>
)} )}

File diff suppressed because one or more lines are too long