Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use selected typing speed unit on personal best popup (fehmer) #5070

Merged
merged 13 commits into from
Feb 19, 2024
201 changes: 201 additions & 0 deletions frontend/__tests__/utils/format.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import { Formatting } from "../../src/ts/utils/format";
import * as MockConfig from "../../src/ts/config";
import DefaultConfig from "../../src/ts/constants/default-config";

describe("format.ts", () => {
afterEach(() => {
jest.resetAllMocks();
});
describe("typingsSpeed", () => {
it("should format with typing speed and decimalPlaces from configuration", () => {
//wpm, no decimals
const wpmNoDecimals = getInstance({
typingSpeedUnit: "wpm",
alwaysShowDecimalPlaces: false,
});
expect(wpmNoDecimals.typingSpeed(12.5)).toEqual("13");
expect(wpmNoDecimals.typingSpeed(0)).toEqual("0");

//cpm, no decimals
const cpmNoDecimals = getInstance({
typingSpeedUnit: "cpm",
alwaysShowDecimalPlaces: false,
});
expect(cpmNoDecimals.typingSpeed(12.5)).toEqual("63");
expect(cpmNoDecimals.typingSpeed(0)).toEqual("0");

//wpm, with decimals
const wpmWithDecimals = getInstance({
typingSpeedUnit: "wpm",
alwaysShowDecimalPlaces: true,
});
expect(wpmWithDecimals.typingSpeed(12.5)).toEqual("12.50");
expect(wpmWithDecimals.typingSpeed(0)).toEqual("0.00");

//cpm, with decimals
const cpmWithDecimals = getInstance({
typingSpeedUnit: "cpm",
alwaysShowDecimalPlaces: true,
});
expect(cpmWithDecimals.typingSpeed(12.5)).toEqual("62.50");
expect(cpmWithDecimals.typingSpeed(0)).toEqual("0.00");
});

it("should format with fallback", () => {
//default fallback
const format = getInstance();
expect(format.typingSpeed(null)).toEqual("-");
expect(format.typingSpeed(undefined)).toEqual("-");

//provided fallback
expect(format.typingSpeed(null, { fallback: "none" })).toEqual("none");
expect(format.typingSpeed(null, { fallback: "" })).toEqual("");
expect(format.typingSpeed(undefined, { fallback: "none" })).toEqual(
"none"
);

expect(format.typingSpeed(undefined, { fallback: "" })).toEqual("");
expect(format.typingSpeed(undefined, { fallback: undefined })).toEqual(
""
);
});

it("should format with decimals", () => {
//force with decimals
const wpmNoDecimals = getInstance({
typingSpeedUnit: "wpm",
alwaysShowDecimalPlaces: false,
});
expect(
wpmNoDecimals.typingSpeed(100, { showDecimalPlaces: true })
).toEqual("100.00");
//force without decimals
const wpmWithDecimals = getInstance({
typingSpeedUnit: "wpm",
alwaysShowDecimalPlaces: true,
});
expect(
wpmWithDecimals.typingSpeed(100, { showDecimalPlaces: false })
).toEqual("100");
});

it("should format with suffix", () => {
const format = getInstance({
typingSpeedUnit: "wpm",
alwaysShowDecimalPlaces: false,
});
expect(format.typingSpeed(100, { suffix: " raw" })).toEqual("100 raw");
expect(format.typingSpeed(100, { suffix: undefined })).toEqual("100");
expect(format.typingSpeed(0, { suffix: " raw" })).toEqual("0 raw");
expect(format.typingSpeed(null, { suffix: " raw" })).toEqual("-");
expect(format.typingSpeed(undefined, { suffix: " raw" })).toEqual("-");
});
});
describe("percentage", () => {
it("should format with decimalPlaces from configuration", () => {
//no decimals
const noDecimals = getInstance({ alwaysShowDecimalPlaces: false });
expect(noDecimals.percentage(12.5)).toEqual("13%");
expect(noDecimals.percentage(0)).toEqual("0%");

//with decimals
const withDecimals = getInstance({ alwaysShowDecimalPlaces: true });
expect(withDecimals.percentage(12.5)).toEqual("12.50%");
expect(withDecimals.percentage(0)).toEqual("0.00%");
});

it("should format with fallback", () => {
//default fallback
const format = getInstance();
expect(format.percentage(null)).toEqual("-");
expect(format.percentage(undefined)).toEqual("-");

//provided fallback
expect(format.percentage(null, { fallback: "none" })).toEqual("none");
expect(format.percentage(null, { fallback: "" })).toEqual("");
expect(format.percentage(undefined, { fallback: "none" })).toEqual(
"none"
);

expect(format.percentage(undefined, { fallback: "" })).toEqual("");
expect(format.percentage(undefined, { fallback: undefined })).toEqual("");
});

it("should format with decimals", () => {
//force with decimals
const noDecimals = getInstance({ alwaysShowDecimalPlaces: false });
expect(noDecimals.percentage(100, { showDecimalPlaces: true })).toEqual(
"100.00%"
);
//force without decimals
const withDecimals = getInstance({ alwaysShowDecimalPlaces: true });
expect(
withDecimals.percentage(100, { showDecimalPlaces: false })
).toEqual("100%");
});

it("should format with suffix", () => {
const format = getInstance({ alwaysShowDecimalPlaces: false });
expect(format.percentage(100, { suffix: " raw" })).toEqual("100% raw");
expect(format.percentage(100, { suffix: undefined })).toEqual("100%");
expect(format.percentage(0, { suffix: " raw" })).toEqual("0% raw");
expect(format.percentage(null, { suffix: " raw" })).toEqual("-");
expect(format.percentage(undefined, { suffix: " raw" })).toEqual("-");
});
});
describe("decimals", () => {
it("should format with decimalPlaces from configuration", () => {
//no decimals
const noDecimals = getInstance({ alwaysShowDecimalPlaces: false });
expect(noDecimals.decimals(12.5)).toEqual("13");
expect(noDecimals.decimals(0)).toEqual("0");

//with decimals
const withDecimals = getInstance({ alwaysShowDecimalPlaces: true });
expect(withDecimals.decimals(12.5)).toEqual("12.50");
expect(withDecimals.decimals(0)).toEqual("0.00");
});

it("should format with fallback", () => {
//default fallback
const format = getInstance();
expect(format.decimals(null)).toEqual("-");
expect(format.decimals(undefined)).toEqual("-");

//provided fallback
expect(format.decimals(null, { fallback: "none" })).toEqual("none");
expect(format.decimals(null, { fallback: "" })).toEqual("");
expect(format.decimals(undefined, { fallback: "none" })).toEqual("none");

expect(format.decimals(undefined, { fallback: "" })).toEqual("");
expect(format.decimals(undefined, { fallback: undefined })).toEqual("");
});

it("should format with decimals", () => {
//force with decimals
const noDecimals = getInstance({ alwaysShowDecimalPlaces: false });
expect(noDecimals.decimals(100, { showDecimalPlaces: true })).toEqual(
"100.00"
);
//force without decimals
const withDecimals = getInstance({ alwaysShowDecimalPlaces: true });
expect(withDecimals.decimals(100, { showDecimalPlaces: false })).toEqual(
"100"
);
});

it("should format with suffix", () => {
const format = getInstance({ alwaysShowDecimalPlaces: false });
expect(format.decimals(100, { suffix: " raw" })).toEqual("100 raw");
expect(format.decimals(100, { suffix: undefined })).toEqual("100");
expect(format.decimals(0, { suffix: " raw" })).toEqual("0 raw");
expect(format.decimals(null, { suffix: " raw" })).toEqual("-");
expect(format.decimals(undefined, { suffix: " raw" })).toEqual("-");
});
});
});

function getInstance(config?: Partial<SharedTypes.Config>): Formatting {
const target: SharedTypes.Config = { ...DefaultConfig, ...config };
return new Formatting(target);
}
70 changes: 17 additions & 53 deletions frontend/src/ts/account/pb-tables.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Config from "../config";
import format from "date-fns/format";
import * as Misc from "../utils/misc";
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
import dateFormat from "date-fns/format";
import Format from "../utils/format";

function clearTables(isProfile: boolean): void {
const source = isProfile ? "Profile" : "Account";
Expand Down Expand Up @@ -140,70 +139,35 @@ function buildPbHtml(
let dateText = "";
const modeString = `${mode2} ${mode === "time" ? "seconds" : "words"}`;
const speedUnit = Config.typingSpeedUnit;
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
try {
const pbData = (pbs[mode][mode2] ?? []).sort((a, b) => b.wpm - a.wpm)[0];

if (pbData === undefined) throw new Error("No PB data found");

const date = new Date(pbData.timestamp);
if (pbData.timestamp) {
dateText = format(date, "dd MMM yyyy");
dateText = dateFormat(date, "dd MMM yyyy");
}

let speedString: number | string = typingSpeedUnit.fromWpm(pbData.wpm);
if (Config.alwaysShowDecimalPlaces) {
speedString = Misc.roundTo2(speedString).toFixed(2);
} else {
speedString = Math.round(speedString);
}
speedString += ` ${speedUnit}`;

let rawString: number | string = typingSpeedUnit.fromWpm(pbData.raw);
if (Config.alwaysShowDecimalPlaces) {
rawString = Misc.roundTo2(rawString).toFixed(2);
} else {
rawString = Math.round(rawString);
}
rawString += ` raw`;

let accString: number | string = pbData.acc;
if (accString === undefined) {
accString = "-";
} else {
if (Config.alwaysShowDecimalPlaces) {
accString = Misc.roundTo2(accString).toFixed(2);
} else {
accString = Math.floor(accString);
}
}
accString += ` acc`;

let conString: number | string = pbData.consistency;
if (conString === undefined) {
conString = "-";
} else {
if (Config.alwaysShowDecimalPlaces) {
conString = Misc.roundTo2(conString).toFixed(2);
} else {
conString = Math.round(conString);
}
}
conString += ` con`;

retval = `<div class="quick">
<div class="test">${modeString}</div>
<div class="wpm">${Math.round(typingSpeedUnit.fromWpm(pbData.wpm))}</div>
<div class="acc">${
pbData.acc === undefined ? "-" : Math.floor(pbData.acc) + "%"
}</div>
<div class="wpm">${Format.typingSpeed(pbData.wpm, {
showDecimalPlaces: false,
})}</div>
<div class="acc">${Format.percentage(pbData.acc, {
showDecimalPlaces: false,
})}</div>
</div>
<div class="fullTest">
<div>${modeString}</div>
<div>${speedString}</div>
<div>${rawString}</div>
<div>${accString}</div>
<div>${conString}</div>
<div>${Format.typingSpeed(pbData.wpm, {
suffix: ` ${speedUnit}`,
})}</div>
<div>${Format.typingSpeed(pbData.raw, { suffix: " raw" })}</div>
<div>${Format.percentage(pbData.acc, { suffix: " acc" })}</div>
<div>${Format.percentage(pbData.consistency, {
suffix: " con",
})}</div>
<div>${dateText}</div>
</div>`;
} catch (e) {
Expand Down
41 changes: 25 additions & 16 deletions frontend/src/ts/elements/leaderboards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Ape from "../ape";
import * as DB from "../db";
import Config from "../config";
import * as Misc from "../utils/misc";
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
import * as Notifications from "./notifications";
import format from "date-fns/format";
import { isAuthenticated } from "../firebase";
Expand All @@ -11,6 +10,7 @@ import { getHTMLById as getBadgeHTMLbyId } from "../controllers/badge-controller
import * as ConnectionState from "../states/connection";
import * as Skeleton from "../popups/skeleton";
import { debounce } from "throttle-debounce";
import Format from "../utils/format";
import SlimSelect from "slim-select";

const wrapperId = "leaderboardsWrapper";
Expand Down Expand Up @@ -165,7 +165,6 @@ function updateFooter(lb: LbKey): void {
return;
}

const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
if (DB.getSnapshot()?.lbOptOut === true) {
$(`#leaderboardsWrapper table.${side} tfoot`).html(`
<tr>
Expand Down Expand Up @@ -211,12 +210,18 @@ function updateFooter(lb: LbKey): void {
<tr>
<td>${lbRank.rank}</td>
<td><span class="top">You</span>${toppercent ? toppercent : ""}</td>
<td class="alignRight">${typingSpeedUnit.fromWpm(entry.wpm).toFixed(2)}<br>
<div class="sub">${entry.acc.toFixed(2)}%</div></td>
<td class="alignRight">${typingSpeedUnit.fromWpm(entry.raw).toFixed(2)}<br>
<div class="sub">${
entry.consistency === undefined ? "-" : entry.consistency.toFixed(2) + "%"
}</div></td>
<td class="alignRight">${Format.typingSpeed(entry.wpm, {
showDecimalPlaces: true,
})}<br>
<div class="sub">${Format.percentage(entry.acc, {
showDecimalPlaces: true,
})}%</div></td>
<td class="alignRight">${Format.typingSpeed(entry.raw, {
showDecimalPlaces: true,
})}<br>
<div class="sub">${Format.percentage(entry.consistency, {
showDecimalPlaces: true,
})}</div></td>
<td class="alignRight">${format(date, "dd MMM yyyy")}<br>
<div class='sub'>${format(date, "HH:mm")}</div></td>
</tr>
Expand Down Expand Up @@ -296,8 +301,6 @@ async function fillTable(lb: LbKey): Promise<void> {
"<tr><td colspan='7'>No results found</td></tr>"
);
}

const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
const loggedInUserName = DB.getSnapshot()?.name;

let html = "";
Expand Down Expand Up @@ -336,12 +339,18 @@ async function fillTable(lb: LbKey): Promise<void> {
${entry.badgeId ? getBadgeHTMLbyId(entry.badgeId) : ""}
</div>
</td>
<td class="alignRight">${typingSpeedUnit.fromWpm(entry.wpm).toFixed(2)}<br>
<div class="sub">${entry.acc.toFixed(2)}%</div></td>
<td class="alignRight">${typingSpeedUnit.fromWpm(entry.raw).toFixed(2)}<br>
<div class="sub">${
entry.consistency === undefined ? "-" : entry.consistency.toFixed(2) + "%"
}</div></td>
<td class="alignRight">${Format.typingSpeed(entry.wpm, {
showDecimalPlaces: true,
})}<br>
<div class="sub">${Format.percentage(entry.acc, {
showDecimalPlaces: true,
})}</div></td>
<td class="alignRight">${Format.typingSpeed(entry.raw, {
showDecimalPlaces: true,
})}<br>
<div class="sub">${Format.percentage(entry.consistency, {
showDecimalPlaces: true,
})}</div></td>
<td class="alignRight">${format(date, "dd MMM yyyy")}<br>
<div class='sub'>${format(date, "HH:mm")}</div></td>
</tr>
Expand Down
Loading
Loading