import type { MatchmakerLogSource } from "@/lib/matchmaker-log-source"; import { DEFAULT_LEDGER_PAGE_SIZE } from "@/lib/ledger-table-view"; export type AdminDashboardTab = | "dashboard" | "players" | "matches" | "matchmaker" | "ledger" | "analysis" | "logs"; export type DashboardUrlQuery = { tab: AdminDashboardTab; highlightId: string | null; participantRaw: string | null; editId?: number | null; saveError?: boolean; /** Ledger: failed system supply action */ supplyError?: boolean; /** When tab is matchmaker: `raw` selects matchmaker.log; omit or processed → history.log */ matchmakerSource?: MatchmakerLogSource | null; /** Ledger tab: UTC date-only bounds (`lfrom` / `lto` query params). */ ledgerFrom?: string | null; ledgerTo?: string | null; ledgerPage?: number | null; /** Ledger rows per page (`lsize`); omitted from URL when equal to default. */ ledgerPageSize?: number | null; ledgerSort?: string | null; ledgerOrder?: "asc" | "desc" | null; /** Analysis tab: UTC date-only bounds (`afrom` / `ato`). */ analysisFrom?: string | null; analysisTo?: string | null; /** Analysis tab: comma-separated player ids (`aplayers`). */ analysisPlayers?: string | null; /** Matches tab: local date-only bounds (`mfrom` / `mto`) + tz offset minutes (`mtz`). */ matchesFrom?: string | null; matchesTo?: string | null; matchesTzOffsetMinutes?: number | null; }; /** Build `/?…` for dashboard tabs, filters, and optional edit / error flags. */ export function buildDashboardHref(q: DashboardUrlQuery): string { const p = new URLSearchParams(); if (q.tab === "matches") p.set("tab", "matches"); else if (q.tab === "players") p.set("tab", "players"); else if (q.tab === "matchmaker") p.set("tab", "matchmaker"); else if (q.tab === "ledger") p.set("tab", "ledger"); else if (q.tab === "analysis") p.set("tab", "analysis"); else if (q.tab === "logs") p.set("tab", "logs"); if (q.highlightId) p.set("highlight", q.highlightId); if (q.participantRaw) p.set("participant", q.participantRaw); if (q.tab === "matchmaker" && q.matchmakerSource === "raw") { p.set("mklog", "raw"); } if (q.tab === "ledger") { if (q.ledgerFrom) p.set("lfrom", q.ledgerFrom); if (q.ledgerTo) p.set("lto", q.ledgerTo); if ( q.ledgerPage != null && Number.isFinite(q.ledgerPage) && Math.trunc(q.ledgerPage) > 1 ) { p.set("lpage", String(Math.trunc(q.ledgerPage))); } if (q.ledgerSort) p.set("lsort", q.ledgerSort); if (q.ledgerOrder) p.set("lorder", q.ledgerOrder); if ( q.ledgerPageSize != null && Number.isFinite(q.ledgerPageSize) && Math.trunc(q.ledgerPageSize) !== DEFAULT_LEDGER_PAGE_SIZE ) { p.set("lsize", String(Math.trunc(q.ledgerPageSize))); } } if (q.tab === "analysis") { if (q.analysisFrom) p.set("afrom", q.analysisFrom); if (q.analysisTo) p.set("ato", q.analysisTo); if (q.analysisPlayers) p.set("aplayers", q.analysisPlayers); } if (q.tab === "matches") { if (q.matchesFrom) p.set("mfrom", q.matchesFrom); if (q.matchesTo) p.set("mto", q.matchesTo); if ( q.matchesTzOffsetMinutes != null && Number.isFinite(q.matchesTzOffsetMinutes) ) { p.set("mtz", String(Math.trunc(q.matchesTzOffsetMinutes))); } } if (q.editId != null && Number.isFinite(q.editId)) { p.set("edit", String(q.editId)); } if (q.saveError) p.set("saveError", "1"); if (q.supplyError) p.set("supplyErr", "1"); const s = p.toString(); return s ? `/?${s}` : "/"; }