diff --git a/frontend/components/tournament-players-table.tsx b/frontend/components/tournament-players-table.tsx index fc87fd9..1209165 100644 --- a/frontend/components/tournament-players-table.tsx +++ b/frontend/components/tournament-players-table.tsx @@ -1,7 +1,7 @@ "use client" import { useEffect, useMemo, useRef, useState } from "react" -import { ExternalLink, Loader2, Trash2, TriangleAlert } from "lucide-react" +import { ChevronDown, ChevronUp, ExternalLink, Loader2, Trash2, TriangleAlert } from "lucide-react" export type TournamentPlayerRow = { participantId: string @@ -90,6 +90,106 @@ function computeAge(birthDate: string): number | null { return age } +// ── Sortering (2026-08-20) ────────────────────────────────────────────── +// Kun disse syv kolonnene er sorterbare -- runde-kolonnene (deltar+utslag) +// og handlingskolonnen er det bevisst IKKE, se V0-prompten. +type SortKey = "name" | "hcp" | "className" | "statLevel" | "status" | "gender" | "age" +type SortDir = "asc" | "desc" +type SortState = { key: SortKey; dir: SortDir } | null + +const STAT_LEVEL_RANK: Record = { + strokes_only: 0, + strokes_and_putts: 1, + full: 2, +} +const STATUS_RANK: Record = { + active: 0, + dsq: 1, + rtd: 2, + dnf: 3, + dns: 4, +} +const GENDER_SORT_LABEL: Record<"m" | "f" | "x", string> = { f: "Kvinne", m: "Mann", x: "Annet" } + +// Sammenlignbar verdi per sorteringskolonne. Null sorteres alltid sist +// (håndtert i compareRows), uansett retning. +function sortValue(p: TournamentPlayerRow, key: SortKey, classNameById: Record): string | number | null { + switch (key) { + case "name": + return p.playerName.toLocaleLowerCase("nb") + case "hcp": + return p.handicapSnapshot + case "className": { + const name = p.classId ? classNameById[p.classId] : undefined + return name ? name.toLocaleLowerCase("nb") : null + } + case "statLevel": + return STAT_LEVEL_RANK[p.statLevel] + case "status": + return STATUS_RANK[p.status] + case "gender": + return p.gender ? GENDER_SORT_LABEL[p.gender].toLocaleLowerCase("nb") : null + case "age": + return p.birthDate ? computeAge(p.birthDate) : null + } +} + +function compareRows( + a: TournamentPlayerRow, + b: TournamentPlayerRow, + key: SortKey, + dir: SortDir, + classNameById: Record, +): number { + const av = sortValue(a, key, classNameById) + const bv = sortValue(b, key, classNameById) + if (av === null && bv === null) return 0 + if (av === null) return 1 + if (bv === null) return -1 + const res = typeof av === "number" && typeof bv === "number" ? av - bv : String(av).localeCompare(String(bv), "nb") + return dir === "asc" ? res : -res +} + +function SortableHeader({ + sortKey, + label, + sort, + onSort, + align, + sticky, +}: { + sortKey: SortKey + label: string + sort: SortState + onSort: (key: SortKey) => void + align?: "right" + sticky?: boolean +}) { + const active = sort?.key === sortKey + const dir = active ? sort.dir : null + const ariaSort = active ? (dir === "asc" ? "ascending" : "descending") : "none" + return ( + + + + ) +} + export function TournamentPlayersTable({ players, classes, @@ -122,6 +222,21 @@ export function TournamentPlayersTable({ setDefaultTees(next) }, [rounds]) + // Sortering: stigende -> synkende -> tilbake til opprinnelig rekkefølge. + const [sort, setSort] = useState(null) + const cycleSort = (key: SortKey) => { + setSort((prev) => { + if (!prev || prev.key !== key) return { key, dir: "asc" } + if (prev.dir === "asc") return { key, dir: "desc" } + return null + }) + } + const classNameById = useMemo(() => Object.fromEntries(classes.map((c) => [c.id, c.name])), [classes]) + const sortedPlayers = useMemo(() => { + if (!sort) return players + return [...players].sort((a, b) => compareRows(a, b, sort.key, sort.dir, classNameById)) + }, [players, sort, classNameById]) + return (
{errors.length > 0 && ( @@ -162,32 +277,15 @@ export function TournamentPlayersTable({ - - Spiller - - - Hcp - + + {showClassColumn && ( - - Klasse - + )} - - Statistikknivå - - - Status - - - Kjønn - - - Alder - + + + + {rounds.map((round) => { const busy = busyRoundIds.includes(round.id) const assignedCount = players.filter( @@ -246,7 +344,7 @@ export function TournamentPlayersTable({ - {players.map((player) => ( + {sortedPlayers.map((player) => (