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.
|
||||
`docker compose build teecup_frontend && up -d`, rene logger,
|
||||
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,43 +480,51 @@ function PlayerRow({
|
|||
const cell = cells[round.id]?.[player.participantId]
|
||||
const assigned = cell?.assigned ?? false
|
||||
const busy = busyRoundIds.includes(round.id)
|
||||
const previewTeeId = cell?.teeId ?? defaultTees[round.id] ?? round.tees[0]?.id ?? ""
|
||||
return (
|
||||
<td key={round.id} className={TD}>
|
||||
<div className="flex items-center gap-1.5 px-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={assigned}
|
||||
disabled={busy}
|
||||
aria-label={`${player.playerName} spiller ${round.label}`}
|
||||
<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"}
|
||||
onChange={(e) => {
|
||||
const checked = e.target.checked
|
||||
const teeId = checked
|
||||
? defaultTees[round.id] ?? round.tees[0]?.id ?? ""
|
||||
: cell?.teeId ?? round.tees[0]?.id ?? ""
|
||||
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"
|
||||
/>
|
||||
{assigned ? (
|
||||
<select
|
||||
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"
|
||||
value={cell?.teeId ?? ""}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={assigned}
|
||||
disabled={busy}
|
||||
onChange={(e) => onChangeRoundTee(round.id, player.participantId, e.target.value)}
|
||||
>
|
||||
{round.tees.map((tee) => (
|
||||
<option key={tee.id} value={tee.id}>
|
||||
{tee.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
<span aria-hidden="true" className="flex-1 text-xs text-muted-foreground/60">
|
||||
—
|
||||
</span>
|
||||
)}
|
||||
aria-label={`${player.playerName} spiller ${round.label}`}
|
||||
onChange={(e) => {
|
||||
const checked = e.target.checked
|
||||
const teeId = checked ? previewTeeId : cell?.teeId ?? previewTeeId
|
||||
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"
|
||||
/>
|
||||
</label>
|
||||
<span aria-hidden="true" className="h-5 w-px shrink-0 bg-border" />
|
||||
<select
|
||||
aria-label={`Utslag for ${player.playerName} i ${round.label}`}
|
||||
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 ${
|
||||
assigned
|
||||
? "border-border bg-background text-foreground"
|
||||
: "border-dashed border-border/70 bg-transparent text-muted-foreground"
|
||||
}`}
|
||||
value={previewTeeId}
|
||||
disabled={busy}
|
||||
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) => (
|
||||
<option key={tee.id} value={tee.id}>
|
||||
{tee.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue