Fiks utslagsvalg i spillertabellen: select forsvinner aldri lenger
Funnet via brukers skjermopptak av forsøk på å endre én spillers utslag -- en ikke-tilordnet rad viste kun en død strek, ingen interaktiv kontroll, og et feilklikk på den tette avkrysningsboksen satt brukeren fast. Utslagsvelgeren vises nå alltid; å velge et utslag tilordner raden automatisk. Boks og select har også fått tydelig mer avstand for å redusere feilklikk.
This commit is contained in:
parent
24eda54d10
commit
724983fe03
2 changed files with 84 additions and 33 deletions
43
CHANGELOG.md
43
CHANGELOG.md
|
|
@ -13187,3 +13187,46 @@ Neste steg:
|
||||||
**Rullet ut 2026-08-19** -- bruker bekreftet. Ren frontend.
|
**Rullet ut 2026-08-19** -- bruker bekreftet. Ren frontend.
|
||||||
`docker compose build teecup_frontend && up -d`, rene logger,
|
`docker compose build teecup_frontend && up -d`, rene logger,
|
||||||
200 OK.
|
200 OK.
|
||||||
|
|
||||||
|
132. **Utslagsvalg i den nye spillertabellen -- reelt UX-hull, funnet via
|
||||||
|
video -- 2026-08-19.** Bruker lastet opp en skjermopptak: "Den viser
|
||||||
|
hvor vanskelig det er å velge utslag." Bilde-for-bilde-gjennomgang
|
||||||
|
(video konvertert til enkeltbilder med `ffmpeg`, installert lokalt
|
||||||
|
for anledningen) viste at bruker klikket presist på avkrysnings-
|
||||||
|
boksen til én rad (ville trolig bare endre utslaget hennes fra "55"
|
||||||
|
til "50"), som avkrysset raden helt av -- og satt deretter fast:
|
||||||
|
når en rad ikke er tilordnet runden viste cellen KUN en død strek
|
||||||
|
(`<span>—</span>`), ingen interaktiv kontroll. Eneste vei tilbake
|
||||||
|
var den 16px avkrysningsboksen, tett inntil selecten, lett å bomme
|
||||||
|
på. Bekreftet med et oppklaringsspørsmål til bruker (var det
|
||||||
|
"massetildel 55, overstyr noen til 50"-flyten som var problemet?)
|
||||||
|
-- bruker bekreftet at DET allerede fungerte (endre en allerede
|
||||||
|
avkrysset rads select direkte er upåvirket av denne bug'en), det
|
||||||
|
var spesifikt fastlåsingen etter et (feilaktig eller bevisst)
|
||||||
|
klikk på boksen som var hovedproblemet.
|
||||||
|
|
||||||
|
**Fiks** (`components/tournament-players-table.tsx`, `PlayerRow`
|
||||||
|
sin runde-celle): utslagsvelgeren vises nå ALLTID, aldri en død
|
||||||
|
strek. På en ikke-tilordnet rad vises den stiplet/nedtonet med
|
||||||
|
rundens standardutslag som forhåndsvalg -- å velge ET HVILKET SOM
|
||||||
|
HELST utslag der kaller `onToggleRound(..., true, teeId)` og
|
||||||
|
tilordner raden i samme handling, ingen egen boks-runde nødvendig.
|
||||||
|
Avkrysningsboksen er nå viklet i en egen `<label>` med større
|
||||||
|
klikkflate, og adskilt fra selecten med en synlig skillelinje
|
||||||
|
(`gap-1` + en 1px `bg-border`-strek) i stedet for kun `gap-1.5` --
|
||||||
|
reduserer sjansen for feilklikk mellom de to kontrollene.
|
||||||
|
|
||||||
|
**Verifisert i scratch** (mock-data, lokal `next dev` på port 3100,
|
||||||
|
IKKE mot kjørende `teecup_frontend`/`teecup_api` -- en midlertidig
|
||||||
|
forhåndsvisningsrute under `frontend/app/tmp-preview-tee-select-
|
||||||
|
x7q9/`, fjernet igjen etter verifisering): brukt Chrome DevTools MCP
|
||||||
|
til faktisk å klikke gjennom scenarioet. Bekreftet (1) massetildeling
|
||||||
|
fortsatt fungerer identisk, (2) å endre en allerede tilordnet rads
|
||||||
|
utslag direkte i selecten fungerer uendret, (3) den faktiske bug'en
|
||||||
|
er løst -- avkryssing av en rad beholder nå en fungerende select
|
||||||
|
(viser siste kjente utslag, stiplet stil), og å velge et utslag der
|
||||||
|
tilordner raden på nytt i ett klikk. Ingen konsollfeil. `tsc --noEmit`
|
||||||
|
rent, `vitest run` 55/55.
|
||||||
|
|
||||||
|
**Rullet ut 2026-08-19** -- bruker bekreftet. Ren frontend.
|
||||||
|
`docker compose build teecup_frontend && up -d`, rene logger, 200 OK.
|
||||||
|
|
|
||||||
|
|
@ -480,31 +480,44 @@ function PlayerRow({
|
||||||
const cell = cells[round.id]?.[player.participantId]
|
const cell = cells[round.id]?.[player.participantId]
|
||||||
const assigned = cell?.assigned ?? false
|
const assigned = cell?.assigned ?? false
|
||||||
const busy = busyRoundIds.includes(round.id)
|
const busy = busyRoundIds.includes(round.id)
|
||||||
|
const previewTeeId = cell?.teeId ?? defaultTees[round.id] ?? round.tees[0]?.id ?? ""
|
||||||
return (
|
return (
|
||||||
<td key={round.id} className={TD}>
|
<td key={round.id} className={TD}>
|
||||||
<div className="flex items-center gap-1.5 px-2">
|
<div className="flex items-center gap-1 px-2">
|
||||||
|
<label
|
||||||
|
className="flex shrink-0 cursor-pointer items-center py-2 pr-2"
|
||||||
|
title={assigned ? "Spiller runden" : "Spiller ikke runden"}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={assigned}
|
checked={assigned}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
aria-label={`${player.playerName} spiller ${round.label}`}
|
aria-label={`${player.playerName} spiller ${round.label}`}
|
||||||
title={assigned ? "Spiller runden" : "Spiller ikke runden"}
|
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const checked = e.target.checked
|
const checked = e.target.checked
|
||||||
const teeId = checked
|
const teeId = checked ? previewTeeId : cell?.teeId ?? previewTeeId
|
||||||
? defaultTees[round.id] ?? round.tees[0]?.id ?? ""
|
|
||||||
: cell?.teeId ?? round.tees[0]?.id ?? ""
|
|
||||||
onToggleRound(round.id, player.participantId, checked, teeId)
|
onToggleRound(round.id, player.participantId, checked, teeId)
|
||||||
}}
|
}}
|
||||||
className="size-4 shrink-0 rounded border-border text-primary outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
className="size-4 shrink-0 rounded border-border text-primary outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
{assigned ? (
|
</label>
|
||||||
|
<span aria-hidden="true" className="h-5 w-px shrink-0 bg-border" />
|
||||||
<select
|
<select
|
||||||
aria-label={`Utslag for ${player.playerName} i ${round.label}`}
|
aria-label={`Utslag for ${player.playerName} i ${round.label}`}
|
||||||
className="h-7 min-w-0 flex-1 rounded-md border border-border bg-background px-1.5 text-xs text-foreground outline-none transition-colors hover:border-primary/40 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
className={`h-7 min-w-0 flex-1 rounded-md border px-1.5 text-xs outline-none transition-colors hover:border-primary/40 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 ${
|
||||||
value={cell?.teeId ?? ""}
|
assigned
|
||||||
|
? "border-border bg-background text-foreground"
|
||||||
|
: "border-dashed border-border/70 bg-transparent text-muted-foreground"
|
||||||
|
}`}
|
||||||
|
value={previewTeeId}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
onChange={(e) => onChangeRoundTee(round.id, player.participantId, e.target.value)}
|
onChange={(e) => {
|
||||||
|
if (assigned) {
|
||||||
|
onChangeRoundTee(round.id, player.participantId, e.target.value)
|
||||||
|
} else {
|
||||||
|
onToggleRound(round.id, player.participantId, true, e.target.value)
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{round.tees.map((tee) => (
|
{round.tees.map((tee) => (
|
||||||
<option key={tee.id} value={tee.id}>
|
<option key={tee.id} value={tee.id}>
|
||||||
|
|
@ -512,11 +525,6 @@ function PlayerRow({
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
) : (
|
|
||||||
<span aria-hidden="true" className="flex-1 text-xs text-muted-foreground/60">
|
|
||||||
—
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue