Handle 1 map only played in tournament without NaN

This commit is contained in:
Kalle
2026-08-26 17:38:20 +03:00
parent 8d27a15505
commit f952ca62af
3 changed files with 48 additions and 10 deletions

View File

@@ -18,7 +18,7 @@ import { modesShort } from "~/modules/in-game-lists/modes";
import { stageIds } from "~/modules/in-game-lists/stage-ids";
import type { ModeShort, StageId } from "~/modules/in-game-lists/types";
import invariant from "~/utils/invariant";
import { cutToNDecimalPlaces } from "~/utils/number";
import { cutToNDecimalPlaces, winPercentage } from "~/utils/number";
import type { SendouRouteHandle } from "~/utils/remix.server";
import {
loader,
@@ -277,12 +277,10 @@ function Players({
return (
<div className="stack md horizontal justify-center flex-wrap">
{players.map((player) => {
const setWinRate = Math.round(
(player.setWins / (player.setWins + player.setLosses)) * 100,
);
const mapWinRate = Math.round(
(player.mapWins / (player.mapWins + player.mapLosses)) * 100,
);
// a player only met on maps of a set someone else's team was fielded
// for has no set record to show a win rate of
const setWinRate = winPercentage(player.setWins, player.setLosses);
const mapWinRate = winPercentage(player.mapWins, player.mapLosses);
return (
<div key={player.user.id} className="stack">
<Link
@@ -294,11 +292,18 @@ function Players({
</Link>
<div
className={clsx("text-xs font-bold", {
"text-success": setWinRate >= 50,
"text-warning": setWinRate < 50,
"text-success":
typeof setWinRate === "number" && setWinRate >= 50,
"text-warning":
typeof setWinRate === "number" && setWinRate < 50,
})}
>
{setWinRate}% ({mapWinRate}%)
{typeof setWinRate === "number"
? `${Math.round(setWinRate)}% `
: null}
{typeof mapWinRate === "number"
? `(${Math.round(mapWinRate)}%)`
: null}
</div>
<div className="text-xs">
{player.setWins} ({player.mapWins}) {t("user:seasons.win.short")}

View File

@@ -78,3 +78,20 @@ export function safeNumberParse(value: string | null) {
const result = Number(trimmed);
return Number.isNaN(result) ? null : result;
}
/**
* Share of games won as a percentage, or `null` when no games were played.
* Callers decide how to round it and what to show in place of a missing rate.
*
* @example
* ```typescript
* winPercentage(3, 1); // returns 75
* winPercentage(0, 0); // returns null
* ```
*/
export function winPercentage(wins: number, losses: number) {
const played = wins + losses;
if (played === 0) return null;
return (wins / played) * 100;
}

View File

@@ -4,6 +4,7 @@ import {
cutToNDecimalPlaces,
roundToNDecimalPlaces,
safeNumberParse,
winPercentage,
} from "./number";
describe("roundToNDecimalPlaces()", () => {
@@ -75,3 +76,18 @@ describe("safeNumberParse()", () => {
expect(safeNumberParse(input)).toBe(expected);
});
});
describe("winPercentage()", () => {
test.each([
[3, 1, 75],
[1, 1, 50],
[0, 4, 0],
[4, 0, 100],
])("%d wins and %d losses is %d%%", (wins, losses, expected) => {
expect(winPercentage(wins, losses)).toBe(expected);
});
test("returns null when no games were played", () => {
expect(winPercentage(0, 0)).toBeNull();
});
});