TypeScript FrontEnd: Add Account Files (#2494)

* add account files, config, and db, fix other files, and make lint script work on cmd

* fuck operating systems

* remove project from eslint

* Merging and fixing some bugs

* fixed result ordering

* fixed quote filter stopping all results

* fixed words filter not working

* corrected type

* Update commandline-lists.ts

* Update types.d.ts

* removing explicit tag types

* mfing prettier

* small changes

* stuff

* fixes

* fix cannot read properties of undefined

* another check just to be safe

* okay that works

Co-authored-by: Miodec <bartnikjack@gmail.com>
This commit is contained in:
Ferotiq 2022-02-19 10:44:27 -06:00 committed by GitHub
parent c3825ab54e
commit 71cdce20e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1377 additions and 955 deletions

View file

@ -2,7 +2,6 @@ name: Bug report
description: Create a report to help us improve
labels: [bug]
body:
- type: markdown
attributes:
value: |
@ -10,8 +9,7 @@ body:
```
Thanks for taking the time to fill out this bug! If you need real-time help, join us on Discord: discord.gg/monkeytype
```
- type: checkboxes
attributes:
label: Did you clear cache before opening an issue?
@ -19,7 +17,7 @@ body:
options:
- label: I have cleared my cache
required: true
- type: checkboxes
attributes:
label: Is there an existing issue for this?
@ -27,7 +25,7 @@ body:
options:
- label: I have searched the existing issues
required: true
- type: markdown
attributes:
value: |
@ -35,35 +33,35 @@ body:
```
Below fields are very important to quickly track down the issue, so please take the time to carefully check when the issue happens and when it does not.
```
- type: dropdown
attributes:
label: Does the issue happen when logged in?
options: ["Yes", "No", "N/A"]
validations:
required: true
- type: dropdown
attributes:
label: Does the issue happen when logged out?
options: ["Yes", "No"]
validations:
required: true
- type: dropdown
attributes:
label: Does the issue happen in incognito mode when logged in?
options: ["Yes", "No", "N/A"]
validations:
required: true
- type: dropdown
attributes:
label: Does the issue happen in incognito mode when logged out?
options: ["Yes", "No"]
validations:
required: true
- type: textarea
attributes:
label: Account information
@ -128,4 +126,3 @@ body:
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false

View file

@ -1,5 +1,14 @@
{
"tabWidth": 2,
"useTabs": false,
"htmlWhitespaceSensitivity": "ignore"
"htmlWhitespaceSensitivity": "ignore",
"endOfLine": "lf",
"overrides": [
{
"files": ["*.ts"],
"options": {
"parser": "typescript"
}
}
]
}

View file

@ -1,33 +1,37 @@
import * as DB from "../db";
import * as Misc from "../misc";
export function clear() {
export function clear(): void {
$(".pageAccount .globalTimeTyping .val").text(`-`);
$(".pageAccount .globalTestsStarted .val").text(`-`);
$(".pageAccount .globalTestsCompleted .val").text(`-`);
}
export function update() {
if (DB.getSnapshot().globalStats.time != undefined) {
export function update(): void {
const snapshot = DB.getSnapshot();
if (snapshot.globalStats !== undefined) {
// let th = Math.floor(DB.getSnapshot().globalStats.time / 3600);
// let tm = Math.floor((DB.getSnapshot().globalStats.time % 3600) / 60);
// let ts = Math.floor((DB.getSnapshot().globalStats.time % 3600) % 60);
$(".pageAccount .globalTimeTyping .val").text(
Misc.secondsToString(
Math.round(DB.getSnapshot().globalStats.time),
Math.round(snapshot.globalStats.time as number),
true,
true
)
);
}
if (DB.getSnapshot().globalStats.started != undefined) {
if (snapshot.globalStats !== undefined) {
$(".pageAccount .globalTestsStarted .val").text(
DB.getSnapshot().globalStats.started
snapshot.globalStats.started as number
);
}
if (DB.getSnapshot().globalStats.completed != undefined) {
if (snapshot.globalStats !== undefined) {
$(".pageAccount .globalTestsCompleted .val").text(
DB.getSnapshot().globalStats.completed
snapshot.globalStats.completed as number
);
}
}

View file

@ -1,23 +1,23 @@
import * as ChartController from "../controllers/chart-controller";
import Config from "../config";
export function updatePosition(x, y) {
export function updatePosition(x: number, y: number): void {
$(".pageAccount .miniResultChartWrapper").css({ top: y, left: x });
}
export function show() {
export function show(): void {
$(".pageAccount .miniResultChartWrapper").stop(true, true).fadeIn(125);
$(".pageAccount .miniResultChartBg").stop(true, true).fadeIn(125);
}
function hide() {
function hide(): void {
$(".pageAccount .miniResultChartWrapper").stop(true, true).fadeOut(125);
$(".pageAccount .miniResultChartBg").stop(true, true).fadeOut(125);
}
export function updateData(data) {
export function updateData(data: MonkeyTypes.ChartData): void {
// let data = filteredResults[filteredId].chartData;
let labels = [];
const labels = [];
for (let i = 1; i <= data.wpm.length; i++) {
labels.push(i.toString());
}
@ -28,22 +28,22 @@ export function updateData(data) {
ChartController.miniResult.updateColors();
let maxChartVal = Math.max(...[Math.max(...data.wpm), Math.max(...data.raw)]);
let minChartVal = Math.min(...[Math.min(...data.wpm), Math.min(...data.raw)]);
ChartController.miniResult.options.scales.yAxes[0].ticks.max = Math.round(
maxChartVal
const maxChartVal = Math.max(
...[Math.max(...data.wpm), Math.max(...data.raw)]
);
ChartController.miniResult.options.scales.yAxes[1].ticks.max = Math.round(
maxChartVal
const minChartVal = Math.min(
...[Math.min(...data.wpm), Math.min(...data.raw)]
);
ChartController.miniResult.options.scales.yAxes[0].ticks.max =
Math.round(maxChartVal);
ChartController.miniResult.options.scales.yAxes[1].ticks.max =
Math.round(maxChartVal);
if (!Config.startGraphsAtZero) {
ChartController.miniResult.options.scales.yAxes[0].ticks.min = Math.round(
minChartVal
);
ChartController.miniResult.options.scales.yAxes[1].ticks.min = Math.round(
minChartVal
);
ChartController.miniResult.options.scales.yAxes[0].ticks.min =
Math.round(minChartVal);
ChartController.miniResult.options.scales.yAxes[1].ticks.min =
Math.round(minChartVal);
} else {
ChartController.miniResult.options.scales.yAxes[0].ticks.min = 0;
ChartController.miniResult.options.scales.yAxes[1].ticks.min = 0;
@ -52,6 +52,6 @@ export function updateData(data) {
ChartController.miniResult.update({ duration: 0 });
}
$(document).on("click", ".pageAccount .miniResultChartBg", (event) => {
$(document).on("click", ".pageAccount .miniResultChartBg", () => {
hide();
});

View file

@ -2,7 +2,7 @@ import * as DB from "../db";
import Config from "../config";
import * as Misc from "../misc";
export function update() {
export function update(): void {
$(".pageAccount .timePbTable tbody").html(`
<tr>
<td>15</td>
@ -75,10 +75,11 @@ export function update() {
}
const pb = DB.getSnapshot().personalBests;
if (pb === undefined) return;
let pbData;
let text;
let dateText = `-<br><span class="sub">-</span>`;
let multiplier = Config.alwaysShowCPM ? 5 : 1;
const multiplier = Config.alwaysShowCPM ? 5 : 1;
text = "";
try {

View file

@ -3,7 +3,7 @@ import * as DB from "../db";
import Config from "../config";
import * as Notifications from "../elements/notifications";
export let defaultResultFilters = {
export const defaultResultFilters: MonkeyTypes.ResultFilters = {
difficulty: {
normal: true,
expert: true,
@ -62,15 +62,15 @@ export let defaultResultFilters = {
export let filters = defaultResultFilters;
function save() {
function save(): void {
window.localStorage.setItem("resultFilters", JSON.stringify(filters));
}
export function load() {
export function load(): void {
// let newTags = $.cookie("activeTags");
console.log("loading filters");
try {
let newResultFilters = window.localStorage.getItem("resultFilters");
const newResultFilters = window.localStorage.getItem("resultFilters");
if (
newResultFilters != undefined &&
newResultFilters !== "" &&
@ -84,7 +84,9 @@ export function load() {
// save();
}
let newTags = {};
const newTags: {
[tag: string]: boolean;
} = { none: false };
Object.keys(defaultResultFilters.tags).forEach((tag) => {
if (filters.tags[tag] !== undefined) {
@ -104,11 +106,13 @@ export function load() {
}
}
export function getFilters() {
export function getFilters(): MonkeyTypes.ResultFilters {
return filters;
}
export function getGroup(group) {
export function getGroup<G extends MonkeyTypes.Group>(
group: G
): MonkeyTypes.ResultFilters[G] {
return filters[group];
}
@ -116,7 +120,10 @@ export function getGroup(group) {
// filters[group][filter] = value;
// }
export function getFilter(group, filter) {
export function getFilter<G extends MonkeyTypes.Group>(
group: G,
filter: MonkeyTypes.Filter<G>
): MonkeyTypes.ResultFilters[G][MonkeyTypes.Filter<G>] {
return filters[group][filter];
}
@ -124,30 +131,42 @@ export function getFilter(group, filter) {
// filters[group][filter] = !filters[group][filter];
// }
export function loadTags(tags) {
export function loadTags(tags: MonkeyTypes.Tag[]): void {
console.log("loading tags");
tags.forEach((tag) => {
defaultResultFilters.tags[tag._id] = true;
});
}
export function reset() {
export function reset(): void {
filters = defaultResultFilters;
save();
}
export function updateActive() {
let aboveChartDisplay = {};
Object.keys(getFilters()).forEach((group) => {
type AboveChartDisplay = MonkeyTypes.PartialRecord<
MonkeyTypes.Group,
{ all: boolean; array?: string[] }
>;
export function updateActive(): void {
const aboveChartDisplay: AboveChartDisplay = {};
(Object.keys(getFilters()) as MonkeyTypes.Group[]).forEach((group) => {
aboveChartDisplay[group] = {
all: true,
array: [],
};
Object.keys(getGroup(group)).forEach((filter) => {
(
Object.keys(getGroup(group)) as MonkeyTypes.Filter<typeof group>[]
).forEach((filter) => {
const groupAboveChartDisplay = aboveChartDisplay[group];
if (groupAboveChartDisplay === undefined) return;
if (getFilter(group, filter)) {
aboveChartDisplay[group].array.push(filter);
groupAboveChartDisplay["array"]?.push(filter);
} else {
aboveChartDisplay[group].all = false;
if (groupAboveChartDisplay["all"] !== undefined)
groupAboveChartDisplay["all"] = false;
}
let buttonEl;
if (group === "date") {
@ -167,7 +186,7 @@ export function updateActive() {
});
});
function addText(group) {
function addText(group: MonkeyTypes.Group): string {
let ret = "";
ret += "<div class='group'>";
if (group == "difficulty") {
@ -200,21 +219,23 @@ export function updateActive() {
} else if (group == "funbox") {
ret += `<span aria-label="Funbox" data-balloon-pos="up"><i class="fas fa-fw fa-gamepad"></i>`;
}
if (aboveChartDisplay[group].all) {
if (aboveChartDisplay[group]?.all) {
ret += "all";
} else {
if (group === "tags") {
ret += aboveChartDisplay.tags.array
.map((id) => {
ret += aboveChartDisplay.tags?.array
?.map((id) => {
if (id == "none") return id;
let name = DB.getSnapshot().tags.filter((t) => t._id == id)[0];
const snapshot = DB.getSnapshot();
const name = snapshot.tags?.filter((t) => t._id == id)[0];
if (name !== undefined) {
return DB.getSnapshot().tags.filter((t) => t._id == id)[0].name;
return snapshot.tags?.filter((t) => t._id == id)[0].name;
}
return name;
})
.join(", ");
} else {
ret += aboveChartDisplay[group].array.join(", ").replace(/_/g, " ");
ret += aboveChartDisplay[group]?.array?.join(", ").replace(/_/g, " ");
}
}
ret += "</span></div>";
@ -232,13 +253,13 @@ export function updateActive() {
chartString += `<div class="spacer"></div>`;
//time
if (aboveChartDisplay.mode.array.includes("time")) {
if (aboveChartDisplay.mode?.array?.includes("time")) {
chartString += addText("time");
chartString += `<div class="spacer"></div>`;
}
//words
if (aboveChartDisplay.mode.array.includes("words")) {
if (aboveChartDisplay.mode?.array?.includes("words")) {
chartString += addText("words");
chartString += `<div class="spacer"></div>`;
}
@ -271,14 +292,21 @@ export function updateActive() {
}, 0);
}
export function toggle(group, filter) {
export function toggle<G extends MonkeyTypes.Group>(
group: G,
filter: MonkeyTypes.Filter<G>
): void {
try {
if (group === "date") {
Object.keys(getGroup("date")).forEach((date) => {
filters["date"][date] = false;
});
(Object.keys(getGroup("date")) as MonkeyTypes.Filter<"date">[]).forEach(
(date) => {
filters["date"][date] = false;
}
);
}
filters[group][filter] = !filters[group][filter];
filters[group][filter] = !filters[group][
filter
] as unknown as MonkeyTypes.ResultFilters[G][keyof MonkeyTypes.ResultFilters[G]];
save();
} catch (e) {
Notifications.add(
@ -292,18 +320,21 @@ export function toggle(group, filter) {
}
}
export function updateTags() {
export function updateTags(): void {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).empty();
if (DB.getSnapshot().tags.length > 0) {
const snapshot = DB.getSnapshot();
if (snapshot.tags?.length || 0 > 0) {
$(".pageAccount .content .filterButtons .buttonsAndTitle.tags").removeClass(
"hidden"
);
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).append(`<div class="button" filter="none">no tag</div>`);
DB.getSnapshot().tags.forEach((tag) => {
snapshot.tags?.forEach((tag) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).append(`<div class="button" filter="${tag._id}">${tag.name}</div>`);
@ -318,32 +349,49 @@ export function updateTags() {
$(
".pageAccount .filterButtons .buttonsAndTitle .buttons, .pageAccount .group.topFilters .buttonsAndTitle.testDate .buttons"
).click(".button", (e) => {
const filter = $(e.target).attr("filter");
const group = $(e.target).parents(".buttons").attr("group");
const group = $(e.target)
.parents(".buttons")
.attr("group") as MonkeyTypes.Group;
const filter = $(e.target).attr("filter") as MonkeyTypes.Filter<typeof group>;
if ($(e.target).hasClass("allFilters")) {
Object.keys(getFilters()).forEach((group) => {
Object.keys(getGroup(group)).forEach((filter) => {
(Object.keys(getFilters()) as MonkeyTypes.Group[]).forEach((group) => {
(
Object.keys(getGroup(group)) as MonkeyTypes.Filter<typeof group>[]
).forEach((filter) => {
if (group === "date") {
// TODO figure out why "filter" is never
// @ts-ignore
filters[group][filter] = false;
} else {
} else if (filters[group] !== undefined) {
// @ts-ignore
filters[group][filter] = true;
}
});
});
filters["date"]["all"] = true;
} else if ($(e.target).hasClass("noFilters")) {
Object.keys(getFilters()).forEach((group) => {
(Object.keys(getFilters()) as MonkeyTypes.Group[]).forEach((group) => {
if (group !== "date") {
Object.keys(getGroup(group)).forEach((filter) => {
(
Object.keys(getGroup(group)) as MonkeyTypes.Filter<typeof group>[]
).forEach((filter) => {
// TODO figure out why "filter" is never
// @ts-ignore
filters[group][filter] = false;
});
}
});
} else if ($(e.target).hasClass("button")) {
if (e.shiftKey) {
Object.keys(getGroup(group)).forEach((filter) => {
(
Object.keys(getGroup(group)) as MonkeyTypes.Filter<typeof group>[]
).forEach((filter) => {
// TODO figure out why "filter" is never
// @ts-ignore
filters[group][filter] = false;
});
// TODO figure out why "filter" is never
// @ts-ignore
filters[group][filter] = true;
} else {
toggle(group, filter);
@ -354,12 +402,18 @@ $(
save();
});
$(".pageAccount .topFilters .button.allFilters").click((e) => {
Object.keys(getFilters()).forEach((group) => {
Object.keys(getGroup(group)).forEach((filter) => {
$(".pageAccount .topFilters .button.allFilters").click(() => {
(Object.keys(getFilters()) as MonkeyTypes.Group[]).forEach((group) => {
(
Object.keys(getGroup(group)) as MonkeyTypes.Filter<typeof group>[]
).forEach((filter) => {
if (group === "date") {
// TODO figure out why "filter" is never
// @ts-ignore
filters[group][filter] = false;
} else {
// TODO figure out why "filter" is never
// @ts-ignore
filters[group][filter] = true;
}
});
@ -369,9 +423,13 @@ $(".pageAccount .topFilters .button.allFilters").click((e) => {
save();
});
$(".pageAccount .topFilters .button.currentConfigFilter").click((e) => {
Object.keys(getFilters()).forEach((group) => {
Object.keys(getGroup(group)).forEach((filter) => {
$(".pageAccount .topFilters .button.currentConfigFilter").click(() => {
(Object.keys(getFilters()) as MonkeyTypes.Group[]).forEach((group) => {
(
Object.keys(getGroup(group)) as MonkeyTypes.Filter<typeof group>[]
).forEach((filter) => {
// TODO figure out why "filter" is never
// @ts-ignore
filters[group][filter] = false;
});
});
@ -379,11 +437,22 @@ $(".pageAccount .topFilters .button.currentConfigFilter").click((e) => {
filters["difficulty"][Config.difficulty] = true;
filters["mode"][Config.mode] = true;
if (Config.mode === "time") {
filters["time"][Config.time] = true;
if ([15, 30, 60, 120].includes(Config.time)) {
const configTime = Config.time as MonkeyTypes.DefaultTimeModes;
filters["time"][configTime] = true;
}
} else if (Config.mode === "words") {
filters["words"][Config.words] = true;
if ([10, 25, 50, 100, 200].includes(Config.words)) {
const configWords = Config.words as MonkeyTypes.DefaultWordsModes;
filters["words"][configWords] = true;
}
} else if (Config.mode === "quote") {
Object.keys(getGroup("quoteLength")).forEach((ql) => {
(
Object.keys(
getGroup("quoteLength")
) as MonkeyTypes.Filter<"quoteLength">[]
).forEach((ql) => {
// TODO figure out how to fix this
filters["quoteLength"][ql] = true;
});
}
@ -410,7 +479,8 @@ $(".pageAccount .topFilters .button.currentConfigFilter").click((e) => {
}
filters["tags"]["none"] = true;
DB.getSnapshot().tags.forEach((tag) => {
DB.getSnapshot().tags?.forEach((tag) => {
if (tag.active === true) {
filters["tags"]["none"] = false;
filters["tags"][tag._id] = true;
@ -422,7 +492,7 @@ $(".pageAccount .topFilters .button.currentConfigFilter").click((e) => {
save();
});
$(".pageAccount .topFilters .button.toggleAdvancedFilters").click((e) => {
$(".pageAccount .topFilters .button.toggleAdvancedFilters").click(() => {
$(".pageAccount .filterButtons").slideToggle(250);
$(".pageAccount .topFilters .button.toggleAdvancedFilters").toggleClass(
"active"

View file

@ -1,4 +1,4 @@
export function show() {
export function show(): void {
// $(".signOut").removeClass("hidden").css("opacity", 1);
$(".signOut")
.stop(true, true)
@ -18,7 +18,7 @@ export function show() {
);
}
export function hide() {
export function hide(): void {
$(".signOut")
.stop(true, true)
.css({

View file

@ -79,10 +79,10 @@ export async function getDataAndInit() {
LoadingPage.updateBar(45);
}
LoadingPage.updateText("Applying settings...");
let snap = DB.getSnapshot();
$("#menu .icon-button.account .text").text(snap.name);
const snapshot = DB.getSnapshot();
$("#menu .icon-button.account .text").text(snapshot.name);
ResultFilters.loadTags(DB.getSnapshot().tags);
ResultFilters.loadTags(snapshot.tags);
Promise.all([Misc.getLanguageList(), Misc.getFunboxList()]).then((values) => {
let languages = values[0];
@ -98,12 +98,12 @@ export async function getDataAndInit() {
});
let user = firebase.auth().currentUser;
if (snap.name == undefined) {
if (snapshot.name == undefined) {
//verify username
if (Misc.isUsernameValid(user.name)) {
//valid, just update
snap.name = user.name;
DB.setSnapshot(snap);
snapshot.name = user.name;
DB.setSnapshot(snapshot);
DB.updateName(user.uid, user.name);
} else {
//invalid, get new
@ -134,7 +134,8 @@ export async function getDataAndInit() {
if (response?.status == 200) {
nameGood = true;
Notifications.add("Name updated", 1);
DB.getSnapshot().name = name;
snapshot.name = name;
DB.setSnapshot(snapshot);
$("#menu .icon-button.account .text").text(name);
}
}
@ -145,11 +146,11 @@ export async function getDataAndInit() {
if (Config.localStorageConfig === null) {
console.log("no local config, applying db");
AccountButton.loading(false);
UpdateConfig.apply(DB.getSnapshot().config);
UpdateConfig.apply(snapshot.config);
Settings.update();
UpdateConfig.saveToLocalStorage(true);
TestLogic.restart(false, true);
} else if (DB.getSnapshot().config !== undefined) {
} else if (snapshot.config !== undefined) {
//loading db config, keep for now
let configsDifferent = false;
Object.keys(Config).forEach((key) => {
@ -158,22 +159,18 @@ export async function getDataAndInit() {
if (key !== "resultFilters") {
if (Array.isArray(Config[key])) {
Config[key].forEach((arrval, index) => {
if (arrval != DB.getSnapshot().config[key][index]) {
if (arrval != snapshot.config[key][index]) {
configsDifferent = true;
console.log(
`.config is different: ${arrval} != ${
DB.getSnapshot().config[key][index]
}`
`.config is different: ${arrval} != ${snapshot.config[key][index]}`
);
}
});
} else {
if (Config[key] != DB.getSnapshot().config[key]) {
if (Config[key] != snapshot.config[key]) {
configsDifferent = true;
console.log(
`..config is different ${key}: ${Config[key]} != ${
DB.getSnapshot().config[key]
}`
`..config is different ${key}: ${Config[key]} != ${snapshot.config[key]}`
);
}
}
@ -188,7 +185,7 @@ export async function getDataAndInit() {
if (configsDifferent) {
console.log("configs are different, applying config from db");
AccountButton.loading(false);
UpdateConfig.apply(DB.getSnapshot().config);
UpdateConfig.apply(snapshot.config);
Settings.update();
UpdateConfig.saveToLocalStorage(true);
if (ActivePage.get() == "test") {
@ -444,7 +441,11 @@ export async function signInWithGoogle() {
})
.then((result) => {
if (result.status === 200) {
DB.getSnapshot().results.push(TestLogic.notSignedInLastResult);
const snapshot = DB.getSnapshot();
snapshot.results.push(TestLogic.notSignedInLastResult);
DB.setSnapshot(snapshot);
}
});
// PageController.change("account");
@ -659,7 +660,11 @@ async function signUp() {
})
.then((result) => {
if (result.status === 200) {
DB.getSnapshot().results.push(TestLogic.notSignedInLastResult);
const snapshot = DB.getSnapshot();
snapshot.results.push(TestLogic.notSignedInLastResult);
DB.setSnapshot(snapshot);
}
});
PageController.change("account");

View file

@ -523,8 +523,9 @@ function handleChar(char, charIndex) {
}
}
let activeWordTopBeforeJump = document.querySelector("#words .word.active")
.offsetTop;
let activeWordTopBeforeJump = document.querySelector(
"#words .word.active"
).offsetTop;
TestUI.updateWordElement();
if (!Config.hideExtraLetters) {

View file

@ -22,19 +22,31 @@ export function saveActiveToLocalStorage() {
}
export function clear(nosave = false) {
DB.getSnapshot().tags.forEach((tag) => {
const snapshot = DB.getSnapshot();
snapshot.tags = snapshot.tags.map((tag) => {
tag.active = false;
return tag;
});
DB.setSnapshot(snapshot);
ModesNotice.update();
if (!nosave) saveActiveToLocalStorage();
}
export function set(tagid, state, nosave = false) {
DB.getSnapshot().tags.forEach((tag) => {
const snapshot = DB.getSnapshot();
snapshot.tags = snapshot.tags.map((tag) => {
if (tag._id === tagid) {
tag.active = state;
}
return tag;
});
DB.setSnapshot(snapshot);
ModesNotice.update();
if (!nosave) saveActiveToLocalStorage();
}

View file

@ -27,7 +27,11 @@ export async function verify(user) {
Notifications.add(response.data.message);
} else {
Notifications.add("Accounts linked", 1);
DB.getSnapshot().discordId = response.data.did;
const snapshot = DB.getSnapshot();
snapshot.discordId = response.data.did;
DB.setSnapshot(snapshot);
Settings.updateDiscordSection();
}
}

View file

@ -3,20 +3,22 @@ import * as Notifications from "./elements/notifications";
import axiosInstance from "./axios-instance";
import * as LoadingPage from "./pages/loading";
let dbSnapshot = null;
let dbSnapshot: MonkeyTypes.Snapshot;
export function updateName(uid, name) {
export function updateName(uid: string, name: string): void {
//TODO update
axiosInstance.patch("/user/name", {
name,
});
name = uid; // this is just so that typescript is happy; Remove once this function is updated.
}
export function getSnapshot() {
export function getSnapshot(): MonkeyTypes.Snapshot {
return dbSnapshot;
}
export function setSnapshot(newSnapshot) {
export function setSnapshot(newSnapshot: MonkeyTypes.Snapshot): void {
try {
delete newSnapshot.banned;
} catch {}
@ -26,11 +28,19 @@ export function setSnapshot(newSnapshot) {
dbSnapshot = newSnapshot;
}
export async function initSnapshot() {
export async function initSnapshot(): Promise<
MonkeyTypes.Snapshot | number | boolean
> {
//send api request with token that returns tags, presets, and data needed for snap
let defaultSnap = {
const defaultSnap: MonkeyTypes.Snapshot = {
results: undefined,
personalBests: {},
personalBests: {
time: {},
words: {},
zen: { zen: [] },
quote: { custom: [] },
custom: { custom: [] },
},
name: undefined,
presets: [],
tags: [],
@ -38,7 +48,7 @@ export async function initSnapshot() {
banned: undefined,
verified: undefined,
emailVerified: undefined,
lbMemory: {},
lbMemory: { time: { 15: { english: 0 }, 60: { english: 0 } } },
globalStats: {
time: 0,
started: 0,
@ -47,7 +57,7 @@ export async function initSnapshot() {
quoteRatings: undefined,
quoteMod: false,
};
let snap = defaultSnap;
const snap = defaultSnap;
try {
if (firebase.auth().currentUser == null) return false;
// if (ActivePage.get() == "loading") {
@ -56,16 +66,16 @@ export async function initSnapshot() {
// LoadingPage.updateBar(16);
// }
// LoadingPage.updateText("Downloading user...");
let promises = await Promise.all([
const promises = await Promise.all([
axiosInstance.get("/user"),
axiosInstance.get("/config"),
axiosInstance.get("/user/tags"),
axiosInstance.get("/presets"),
]);
let userData = promises[0].data;
let configData = promises[1].data;
let tagsData = promises[2].data;
let presetsData = promises[3].data;
const userData = promises[0].data;
const configData = promises[1].data;
const tagsData = promises[2].data;
const presetsData = promises[3].data;
snap.name = userData.name;
snap.personalBests = userData.personalBests;
@ -84,7 +94,7 @@ export async function initSnapshot() {
if (userData.lbMemory?.time15 || userData.lbMemory?.time60) {
//old memory format
snap.lbMemory = {};
snap.lbMemory = {} as MonkeyTypes.LeaderboardMemory;
} else if (userData.lbMemory) {
snap.lbMemory = userData.lbMemory;
}
@ -104,7 +114,7 @@ export async function initSnapshot() {
// }
// LoadingPage.updateText("Downloading tags...");
snap.tags = tagsData;
snap.tags = snap.tags.sort((a, b) => {
snap.tags = snap.tags?.sort((a, b) => {
if (a.name > b.name) {
return 1;
} else if (a.name < b.name) {
@ -120,7 +130,7 @@ export async function initSnapshot() {
// }
// LoadingPage.updateText("Downloading presets...");
snap.presets = presetsData;
snap.presets = snap.presets.sort((a, b) => {
snap.presets = snap.presets?.sort((a, b) => {
if (a.name > b.name) {
return 1;
} else if (a.name < b.name) {
@ -138,8 +148,8 @@ export async function initSnapshot() {
}
}
export async function getUserResults() {
let user = firebase.auth().currentUser;
export async function getUserResults(): Promise<boolean> {
const user = firebase.auth().currentUser;
if (user == null) return false;
if (dbSnapshot === null) return false;
if (dbSnapshot.results !== undefined) {
@ -148,8 +158,11 @@ export async function getUserResults() {
try {
LoadingPage.updateText("Downloading results...");
LoadingPage.updateBar(90);
let results = await axiosInstance.get("/results");
results.data.forEach((result) => {
const resultsData = await axiosInstance.get("/results");
let results = resultsData.data as MonkeyTypes.Result<MonkeyTypes.Mode>[];
results.forEach((result) => {
if (result.bailedOut === undefined) result.bailedOut = false;
if (result.blindMode === undefined) result.blindMode = false;
if (result.lazyMode === undefined) result.lazyMode = false;
@ -160,12 +173,10 @@ export async function getUserResults() {
if (result.numbers === undefined) result.numbers = false;
if (result.punctuation === undefined) result.punctuation = false;
});
results.data = results.data.sort((a, b) => {
return a.timestamp < b.timestamp;
});
dbSnapshot.results = results.data;
results = results.sort((a, b) => b.timestamp - a.timestamp);
dbSnapshot.results = results;
return true;
} catch (e) {
} catch (e: any) {
Notifications.add("Error getting results: " + e.message, -1);
return false;
}
@ -208,17 +219,18 @@ export async function getUserResults() {
*/
}
export async function getUserHighestWpm(
mode,
mode2,
punctuation,
language,
difficulty,
lazyMode
) {
function cont() {
export async function getUserHighestWpm<M extends MonkeyTypes.Mode>(
mode: M,
mode2: MonkeyTypes.Mode2<M>,
punctuation: boolean,
language: string,
difficulty: MonkeyTypes.Difficulty,
lazyMode: boolean
): Promise<number> {
function cont(): number {
let topWpm = 0;
dbSnapshot.results.forEach((result) => {
dbSnapshot.results?.forEach((result) => {
if (
result.mode == mode &&
result.mode2 == mode2 &&
@ -236,25 +248,22 @@ export async function getUserHighestWpm(
return topWpm;
}
let retval;
if (dbSnapshot == null || dbSnapshot.results === undefined) {
retval = 0;
} else {
retval = cont();
}
const retval =
dbSnapshot === null || dbSnapshot.results === undefined ? 0 : cont();
return retval;
}
export async function getUserAverageWpm10(
mode,
mode2,
punctuation,
language,
difficulty,
lazyMode
) {
function cont() {
let activeTagIds = [];
export async function getUserAverageWpm10<M extends MonkeyTypes.Mode>(
mode: M,
mode2: MonkeyTypes.Mode2<M>,
punctuation: boolean,
language: string,
difficulty: MonkeyTypes.Difficulty,
lazyMode: boolean
): Promise<number> {
function cont(): number {
const activeTagIds: string[] = [];
getSnapshot()?.tags?.forEach((tag) => {
if (tag.active === true) {
activeTagIds.push(tag._id);
@ -266,7 +275,7 @@ export async function getUserAverageWpm10(
let last10Wpm = 0;
let last10Count = 0;
// You have to use every so you can break out of the loop
dbSnapshot.results.every((result) => {
dbSnapshot.results?.every((result) => {
if (
result.mode == mode &&
result.punctuation == punctuation &&
@ -311,34 +320,35 @@ export async function getUserAverageWpm10(
return Math.round(wpmSum / count);
}
let retval = 0;
const retval =
dbSnapshot === null || (await getUserResults()) === false ? 0 : cont();
if (dbSnapshot == null) return retval;
let dbSnapshotValid = await getUserResults();
if (dbSnapshotValid === false) {
return retval;
}
retval = cont();
return retval;
}
export async function getLocalPB(
mode,
mode2,
punctuation,
language,
difficulty,
lazyMode,
funbox
) {
export async function getLocalPB<M extends MonkeyTypes.Mode>(
mode: M,
mode2: MonkeyTypes.Mode2<M>,
punctuation: boolean,
language: string,
difficulty: MonkeyTypes.Difficulty,
lazyMode: boolean,
funbox: string
): Promise<number> {
if (funbox !== "none" && funbox !== "plus_one" && funbox !== "plus_two") {
return 0;
}
function cont() {
function cont(): number {
let ret = 0;
try {
dbSnapshot.personalBests[mode][mode2].forEach((pb) => {
if (!dbSnapshot.personalBests) return ret;
(
dbSnapshot.personalBests[mode][
mode2
] as unknown as MonkeyTypes.PersonalBest[]
).forEach((pb) => {
if (
pb.punctuation == punctuation &&
pb.difficulty == difficulty &&
@ -349,43 +359,61 @@ export async function getLocalPB(
ret = pb.wpm;
}
});
return ret;
} catch (e) {
return ret;
}
}
let retval;
if (dbSnapshot == null) {
retval = 0;
} else {
retval = cont();
}
const retval = dbSnapshot === null ? 0 : cont();
return retval;
}
export async function saveLocalPB(
mode,
mode2,
punctuation,
language,
difficulty,
lazyMode,
wpm,
acc,
raw,
consistency
) {
export async function saveLocalPB<M extends MonkeyTypes.Mode>(
mode: M,
mode2: MonkeyTypes.Mode2<M>,
punctuation: boolean,
language: string,
difficulty: MonkeyTypes.Difficulty,
lazyMode: boolean,
wpm: number,
acc: number,
raw: number,
consistency: number
): Promise<void> {
if (mode == "quote") return;
function cont() {
function cont(): void {
let found = false;
if (dbSnapshot.personalBests === undefined) dbSnapshot.personalBests = {};
if (dbSnapshot.personalBests[mode] === undefined)
dbSnapshot.personalBests[mode] = {};
if (dbSnapshot.personalBests[mode][mode2] === undefined)
dbSnapshot.personalBests[mode][mode2] = [];
if (dbSnapshot.personalBests === undefined)
dbSnapshot.personalBests = {
time: {},
words: {},
zen: { zen: [] },
quote: { custom: [] },
custom: { custom: [] },
};
dbSnapshot.personalBests[mode][mode2].forEach((pb) => {
if (dbSnapshot.personalBests[mode] === undefined) {
if (mode === "zen") {
dbSnapshot.personalBests["zen"] = { zen: [] };
} else {
dbSnapshot.personalBests[mode as Exclude<typeof mode, "zen">] = {
custom: [],
};
}
}
if (dbSnapshot.personalBests[mode][mode2] === undefined)
dbSnapshot.personalBests[mode][mode2] =
[] as unknown as MonkeyTypes.PersonalBests[M][keyof MonkeyTypes.PersonalBests[M]];
(
dbSnapshot.personalBests[mode][
mode2
] as unknown as MonkeyTypes.PersonalBest[]
).forEach((pb) => {
if (
pb.punctuation == punctuation &&
pb.difficulty == difficulty &&
@ -404,7 +432,11 @@ export async function saveLocalPB(
});
if (!found) {
//nothing found
dbSnapshot.personalBests[mode][mode2].push({
(
dbSnapshot.personalBests[mode][
mode2
] as unknown as MonkeyTypes.PersonalBest[]
).push({
language: language,
difficulty: difficulty,
lazyMode: lazyMode,
@ -423,20 +455,39 @@ export async function saveLocalPB(
}
}
export async function getLocalTagPB(
tagId,
mode,
mode2,
punctuation,
language,
difficulty,
lazyMode
) {
function cont() {
export async function getLocalTagPB<M extends MonkeyTypes.Mode>(
tagId: string,
mode: M,
mode2: MonkeyTypes.Mode2<M>,
punctuation: boolean,
language: string,
difficulty: MonkeyTypes.Difficulty,
lazyMode: boolean
): Promise<number> {
function cont(): number {
let ret = 0;
let filteredtag = dbSnapshot.tags.filter((t) => t._id === tagId)[0];
const filteredtag = (getSnapshot().tags ?? []).filter(
(t) => t._id === tagId
)[0];
if (filteredtag === undefined) return ret;
if (filteredtag.personalBests === undefined) {
filteredtag.personalBests = {
time: {},
words: {},
zen: { zen: [] },
quote: { custom: [] },
custom: { custom: [] },
};
}
try {
filteredtag.personalBests[mode][mode2].forEach((pb) => {
const personalBests = (filteredtag.personalBests[mode][mode2] ??
[]) as MonkeyTypes.PersonalBest[];
personalBests.forEach((pb) => {
if (
pb.punctuation == punctuation &&
pb.difficulty == difficulty &&
@ -453,37 +504,51 @@ export async function getLocalTagPB(
return ret;
}
let retval;
if (dbSnapshot == null) {
retval = 0;
} else {
retval = cont();
}
const retval = dbSnapshot === null ? 0 : cont();
return retval;
}
export async function saveLocalTagPB(
tagId,
mode,
mode2,
punctuation,
language,
difficulty,
lazyMode,
wpm,
acc,
raw,
consistency
) {
export async function saveLocalTagPB<M extends MonkeyTypes.Mode>(
tagId: string,
mode: M,
mode2: MonkeyTypes.Mode2<M>,
punctuation: boolean,
language: string,
difficulty: MonkeyTypes.Difficulty,
lazyMode: boolean,
wpm: number,
acc: number,
raw: number,
consistency: number
): Promise<number | undefined> {
if (mode == "quote") return;
function cont() {
let filteredtag = dbSnapshot.tags.filter((t) => t._id === tagId)[0];
function cont(): void {
const filteredtag = dbSnapshot.tags?.filter(
(t) => t._id === tagId
)[0] as MonkeyTypes.Tag;
if (!filteredtag.personalBests) {
filteredtag.personalBests = {
time: {},
words: {},
zen: { zen: [] },
quote: { custom: [] },
custom: { custom: [] },
};
}
try {
let found = false;
if (filteredtag.personalBests[mode][mode2] === undefined) {
filteredtag.personalBests[mode][mode2] = [];
filteredtag.personalBests[mode][mode2] =
[] as unknown as MonkeyTypes.PersonalBests[M][keyof MonkeyTypes.PersonalBests[M]];
}
filteredtag.personalBests[mode][mode2].forEach((pb) => {
(
filteredtag.personalBests[mode][
mode2
] as unknown as MonkeyTypes.PersonalBest[]
).forEach((pb) => {
if (
pb.punctuation == punctuation &&
pb.difficulty == difficulty &&
@ -502,7 +567,11 @@ export async function saveLocalTagPB(
});
if (!found) {
//nothing found
filteredtag.personalBests[mode][mode2].push({
(
filteredtag.personalBests[mode][
mode2
] as unknown as MonkeyTypes.PersonalBest[]
).push({
language: language,
difficulty: difficulty,
lazyMode: lazyMode,
@ -516,8 +585,20 @@ export async function saveLocalTagPB(
}
} catch (e) {
//that mode or mode2 is not found
filteredtag.personalBests = {};
filteredtag.personalBests[mode] = {};
filteredtag.personalBests = {
time: {},
words: {},
zen: { zen: [] },
quote: { custom: [] },
custom: { custom: [] },
};
if (mode === "zen") {
filteredtag.personalBests["zen"] = { zen: [] };
} else {
filteredtag.personalBests[mode as Exclude<typeof mode, "zen">] = {
custom: [],
};
}
filteredtag.personalBests[mode][mode2] = [
{
language: language,
@ -530,42 +611,63 @@ export async function saveLocalTagPB(
timestamp: Date.now(),
consistency: consistency,
},
];
] as unknown as MonkeyTypes.PersonalBests[M][keyof MonkeyTypes.PersonalBests[M]];
}
}
if (dbSnapshot != null) {
cont();
}
return;
}
export function updateLbMemory(mode, mode2, language, rank, api = false) {
export function updateLbMemory<M extends MonkeyTypes.Mode>(
mode: M,
mode2: MonkeyTypes.Mode2<M>,
language: string,
rank: number,
api = false
): void {
//could dbSnapshot just be used here instead of getSnapshot()
if (dbSnapshot.lbMemory === undefined) dbSnapshot.lbMemory = {};
if (dbSnapshot.lbMemory[mode] === undefined) dbSnapshot.lbMemory[mode] = {};
if (dbSnapshot.lbMemory[mode][mode2] === undefined)
dbSnapshot.lbMemory[mode][mode2] = {};
let current = dbSnapshot.lbMemory[mode][mode2][language];
dbSnapshot.lbMemory[mode][mode2][language] = rank;
if (api && current != rank) {
axiosInstance.patch("/user/leaderboardMemory", {
mode,
mode2,
language,
rank,
});
if (mode === "time") {
const timeMode = mode as "time",
timeMode2 = mode2 as 15 | 60;
const snapshot = getSnapshot();
if (snapshot.lbMemory === undefined)
snapshot.lbMemory = { time: { 15: { english: 0 }, 60: { english: 0 } } };
if (snapshot.lbMemory[timeMode] === undefined)
snapshot.lbMemory[timeMode] = {
15: { english: 0 },
60: { english: 0 },
};
if (snapshot.lbMemory[timeMode][timeMode2] === undefined)
snapshot.lbMemory[timeMode][timeMode2] = {};
const current = snapshot.lbMemory[timeMode][timeMode2][language];
snapshot.lbMemory[timeMode][timeMode2][language] = rank;
if (api && current != rank) {
axiosInstance.patch("/user/leaderboardMemory", {
mode,
mode2,
language,
rank,
});
}
setSnapshot(snapshot);
}
}
export async function saveConfig(config) {
export async function saveConfig(config: MonkeyTypes.Config): Promise<void> {
if (firebase.auth().currentUser !== null) {
AccountButton.loading(true);
try {
await axiosInstance.post("/config/save", { config });
} catch (e) {
} catch (e: any) {
AccountButton.loading(false);
let msg = e?.response?.data?.message ?? e.message;
const msg = e?.response?.data?.message ?? e.message;
Notifications.add("Failed to save config: " + msg, -1);
return;
}
@ -573,30 +675,41 @@ export async function saveConfig(config) {
}
}
export function saveLocalResult(result) {
if (getSnapshot() !== null && getSnapshot().results !== undefined) {
getSnapshot().results.unshift(result);
export function saveLocalResult(
result: MonkeyTypes.Result<MonkeyTypes.Mode>
): void {
const snapshot = getSnapshot();
if (snapshot !== null && snapshot.results !== undefined) {
snapshot.results.unshift(result);
setSnapshot(snapshot);
}
}
export function updateLocalStats(stats) {
if (getSnapshot() !== null) {
if (getSnapshot().globalStats.time == undefined) {
getSnapshot().globalStats.time = stats.time;
export function updateLocalStats(stats: MonkeyTypes.Stats): void {
const snapshot = getSnapshot();
if (snapshot.globalStats === undefined)
snapshot.globalStats = {} as MonkeyTypes.Stats;
if (snapshot !== null && snapshot.globalStats !== undefined) {
if (snapshot.globalStats.time == undefined) {
snapshot.globalStats.time = stats.time;
} else {
getSnapshot().globalStats.time += stats.time;
snapshot.globalStats.time += stats.time;
}
if (getSnapshot().globalStats.started == undefined) {
getSnapshot().globalStats.started = stats.started;
if (snapshot.globalStats.started == undefined) {
snapshot.globalStats.started = stats.started;
} else {
getSnapshot().globalStats.started += stats.started;
snapshot.globalStats.started += stats.started;
}
if (getSnapshot().globalStats.completed == undefined) {
getSnapshot().globalStats.completed = 1;
if (snapshot.globalStats.completed == undefined) {
snapshot.globalStats.completed = 1;
} else {
getSnapshot().globalStats.completed += 1;
snapshot.globalStats.completed += 1;
}
}
setSnapshot(snapshot);
}
// export async function DB.getLocalTagPB(tagId) {
@ -613,10 +726,8 @@ export function updateLocalStats(stats) {
// }
// }
// let retval;
// if (dbSnapshot != null) {
// retval = cont();
// }
// const retval = dbSnapshot !== null ? cont() : undefined;
// return retval;
// }

View file

@ -212,7 +212,7 @@ const commandsTags: MonkeyTypes.CommandsGroup = {
};
export function updateTagCommands(): void {
if (DB.getSnapshot()?.tags?.length > 0) {
if (DB.getSnapshot()?.tags?.length ?? 0 > 0) {
commandsTags.list = [];
commandsTags.list.push({
@ -220,15 +220,21 @@ export function updateTagCommands(): void {
display: `Clear tags`,
icon: "fa-times",
exec: (): void => {
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag) => {
const snapshot = DB.getSnapshot();
snapshot.tags = snapshot.tags?.map((tag) => {
tag.active = false;
return tag;
});
DB.setSnapshot(snapshot);
ModesNotice.update();
TagController.saveActiveToLocalStorage();
},
});
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((tag) => {
let dis = tag.name;
if (tag.active === true) {
@ -283,10 +289,12 @@ const commandsPresets: MonkeyTypes.CommandsGroup = {
};
export function updatePresetCommands(): void {
if (DB.getSnapshot()?.presets?.length > 0) {
const snapshot = DB.getSnapshot();
if (snapshot.presets !== undefined && snapshot.presets.length > 0) {
commandsPresets.list = [];
DB.getSnapshot().presets.forEach((preset: MonkeyTypes.Preset) => {
snapshot.presets.forEach((preset: MonkeyTypes.Preset) => {
const dis = preset.name;
commandsPresets.list.push({
@ -1655,7 +1663,7 @@ const commandsTimerColor: MonkeyTypes.CommandsGroup = {
display: "black",
configValue: "black",
exec: (): void => {
UpdateConfig.setTimerColor("bar");
UpdateConfig.setTimerColor("black");
},
},
{
@ -1740,7 +1748,7 @@ const commandsTimerOpacity: MonkeyTypes.CommandsGroup = {
display: ".25",
configValue: 0.25,
exec: (): void => {
UpdateConfig.setTimerOpacity(0.25);
UpdateConfig.setTimerOpacity("0.25");
},
},
{
@ -1748,7 +1756,7 @@ const commandsTimerOpacity: MonkeyTypes.CommandsGroup = {
display: ".5",
configValue: 0.5,
exec: (): void => {
UpdateConfig.setTimerOpacity(0.5);
UpdateConfig.setTimerOpacity("0.5");
},
},
{
@ -1756,7 +1764,7 @@ const commandsTimerOpacity: MonkeyTypes.CommandsGroup = {
display: ".75",
configValue: 0.75,
exec: (): void => {
UpdateConfig.setTimerOpacity(0.75);
UpdateConfig.setTimerOpacity("0.75");
},
},
{
@ -1764,7 +1772,7 @@ const commandsTimerOpacity: MonkeyTypes.CommandsGroup = {
display: "1",
configValue: 1,
exec: (): void => {
UpdateConfig.setTimerOpacity(1);
UpdateConfig.setTimerOpacity("1");
},
},
],
@ -1780,7 +1788,7 @@ const commandsWordCount: MonkeyTypes.CommandsGroup = {
configValue: 10,
exec: (): void => {
UpdateConfig.setMode("words");
UpdateConfig.setWordCount("10");
UpdateConfig.setWordCount(10);
TestLogic.restart();
},
},
@ -1790,7 +1798,7 @@ const commandsWordCount: MonkeyTypes.CommandsGroup = {
configValue: 25,
exec: (): void => {
UpdateConfig.setMode("words");
UpdateConfig.setWordCount("25");
UpdateConfig.setWordCount(25);
TestLogic.restart();
},
},
@ -1800,7 +1808,7 @@ const commandsWordCount: MonkeyTypes.CommandsGroup = {
configValue: 50,
exec: (): void => {
UpdateConfig.setMode("words");
UpdateConfig.setWordCount("50");
UpdateConfig.setWordCount(50);
TestLogic.restart();
},
},
@ -1810,7 +1818,7 @@ const commandsWordCount: MonkeyTypes.CommandsGroup = {
configValue: 100,
exec: (): void => {
UpdateConfig.setMode("words");
UpdateConfig.setWordCount("100");
UpdateConfig.setWordCount(100);
TestLogic.restart();
},
},
@ -1820,7 +1828,7 @@ const commandsWordCount: MonkeyTypes.CommandsGroup = {
configValue: 200,
exec: (): void => {
UpdateConfig.setMode("words");
UpdateConfig.setWordCount("200");
UpdateConfig.setWordCount(200);
TestLogic.restart();
},
},
@ -2057,7 +2065,7 @@ const commandsTimeConfig: MonkeyTypes.CommandsGroup = {
configValue: 15,
exec: (): void => {
UpdateConfig.setMode("time");
UpdateConfig.setTimeConfig("15");
UpdateConfig.setTimeConfig(15);
TestLogic.restart();
},
},
@ -2067,7 +2075,7 @@ const commandsTimeConfig: MonkeyTypes.CommandsGroup = {
configValue: 30,
exec: (): void => {
UpdateConfig.setMode("time");
UpdateConfig.setTimeConfig("30");
UpdateConfig.setTimeConfig(30);
TestLogic.restart();
},
},
@ -2077,7 +2085,7 @@ const commandsTimeConfig: MonkeyTypes.CommandsGroup = {
configValue: 60,
exec: (): void => {
UpdateConfig.setMode("time");
UpdateConfig.setTimeConfig("60");
UpdateConfig.setTimeConfig(60);
TestLogic.restart();
},
},
@ -2087,7 +2095,7 @@ const commandsTimeConfig: MonkeyTypes.CommandsGroup = {
configValue: 120,
exec: (): void => {
UpdateConfig.setMode("time");
UpdateConfig.setTimeConfig("120");
UpdateConfig.setTimeConfig(120);
TestLogic.restart();
},
},

View file

@ -320,7 +320,7 @@ function useSingleListCommandLine(sshow = true): void {
// } else if (Config.singleListCommandLine == "on") {
CommandlineLists.setCurrent([allCommands]);
// }
if (Config.singleListCommandLine != "off")
if (Config.singleListCommandLine != "manual")
$("#commandLine").addClass("allCommands");
if (sshow) show();
}

View file

@ -117,17 +117,16 @@ $(".section.customBackgroundFilter .opacity input").on("input", () => {
});
$(".section.customBackgroundFilter .save.button").click(() => {
const arr: number[] = [];
Object.keys(filters).forEach((filterKey) => {
arr.push(filters[filterKey as keyof typeof filters].value);
});
const arr = Object.keys(filters).map(
(filterKey) => filters[filterKey as keyof typeof filters].value
) as MonkeyTypes.CustomBackgroundFilter;
UpdateConfig.setCustomBackgroundFilter(arr, false);
Notifications.add("Custom background filters saved", 1);
});
ConfigEvent.subscribe((eventKey, eventValue) => {
if (eventKey === "customBackgroundFilter") {
loadConfig(((eventValue as unknown) as any[]).map((ev) => parseFloat(ev)));
loadConfig((eventValue as unknown as any[]).map((ev) => parseFloat(ev)));
apply();
}
});

View file

@ -70,9 +70,9 @@ function updateTimerElement(): void {
function startTimer(): void {
updateTimerElement();
updateTimer = (setInterval(() => {
updateTimer = setInterval(() => {
updateTimerElement();
}, 1000) as unknown) as number;
}, 1000) as unknown as number;
}
function showLoader(lb: number): void {
@ -152,7 +152,7 @@ function checkLbMemory(lb: LbKey): void {
side = "right";
}
const memory = DB.getSnapshot()?.lbMemory?.time?.[lb]?.english;
const memory = DB.getSnapshot()?.lbMemory?.time?.[lb]?.["english"];
if (memory && currentRank[lb]) {
const difference = memory - currentRank[lb].rank;

View file

@ -169,7 +169,7 @@ export function update(): void {
let tagsString = "";
try {
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((tag) => {
if (tag.active === true) {
tagsString += tag.name + ", ";
}

View file

@ -212,7 +212,7 @@ export async function addPower(good = true, extra = false): Promise<void> {
`translate(${shake[0]}px, ${shake[1]}px)`
);
if (ctx.resetTimeOut) clearTimeout(ctx.resetTimeOut);
ctx.resetTimeOut = (setTimeout(reset, 2000) as unknown) as number;
ctx.resetTimeOut = setTimeout(reset, 2000) as unknown as number;
}
// Sparks

View file

@ -6,21 +6,24 @@ export function getuid(): void {
console.error("Only share this uid with Miodec and nobody else!");
}
function hexToHSL(
hex: string
): { hue: number; sat: number; lgt: number; string: string } {
function hexToHSL(hex: string): {
hue: number;
sat: number;
lgt: number;
string: string;
} {
// Convert hex to RGB first
let r: number;
let g: number;
let b: number;
if (hex.length == 4) {
r = (("0x" + hex[1] + hex[1]) as unknown) as number;
g = (("0x" + hex[2] + hex[2]) as unknown) as number;
b = (("0x" + hex[3] + hex[3]) as unknown) as number;
r = ("0x" + hex[1] + hex[1]) as unknown as number;
g = ("0x" + hex[2] + hex[2]) as unknown as number;
b = ("0x" + hex[3] + hex[3]) as unknown as number;
} else if (hex.length == 7) {
r = (("0x" + hex[1] + hex[2]) as unknown) as number;
g = (("0x" + hex[3] + hex[4]) as unknown) as number;
b = (("0x" + hex[5] + hex[6]) as unknown) as number;
r = ("0x" + hex[1] + hex[2]) as unknown as number;
g = ("0x" + hex[3] + hex[4]) as unknown as number;
b = ("0x" + hex[5] + hex[6]) as unknown as number;
} else {
r = 0x00;
g = 0x00;

View file

@ -1,12 +1,12 @@
type SubscribeFunction = (key: string, value?: string, value2?: string) => void;
type SubscribeFunction<V, V2> = (key: string, value?: V, value2?: V2) => void;
const subscribers: SubscribeFunction[] = [];
const subscribers: SubscribeFunction<any, any>[] = [];
export function subscribe(fn: SubscribeFunction): void {
export function subscribe(fn: SubscribeFunction<any, any>): void {
subscribers.push(fn);
}
export function dispatch(key: string, value: string, value2: string): void {
export function dispatch<V, V2>(key: string, value?: V, value2?: V2): void {
subscribers.forEach((fn) => {
try {
fn(key, value, value2);

View file

@ -23,7 +23,7 @@ export function toggleFilterDebug(): void {
}
}
let filteredResults: MonkeyTypes.Result[] = [];
let filteredResults: MonkeyTypes.Result<MonkeyTypes.Mode>[] = [];
let visibleTableLines = 0;
function loadMoreLines(lineIndex?: number): void {
@ -102,7 +102,7 @@ function loadMoreLines(lineIndex?: number): void {
if (result.tags !== undefined && result.tags.length > 0) {
result.tags.forEach((tag) => {
DB.getSnapshot().tags.forEach((snaptag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((snaptag) => {
if (tag === snaptag._id) {
tagNames += snaptag.name + ", ";
}
@ -258,323 +258,332 @@ export function update(): void {
filteredResults = [];
$(".pageAccount .history table tbody").empty();
DB.getSnapshot().results.forEach((result: MonkeyTypes.Result) => {
// totalSeconds += tt;
DB.getSnapshot().results?.forEach(
(result: MonkeyTypes.Result<MonkeyTypes.Mode>) => {
// totalSeconds += tt;
//apply filters
try {
let resdiff = result.difficulty;
if (resdiff == undefined) {
resdiff = "normal";
}
if (!ResultFilters.getFilter("difficulty", resdiff)) {
if (filterDebug)
console.log(`skipping result due to difficulty filter`, result);
return;
}
if (!ResultFilters.getFilter("mode", result.mode)) {
if (filterDebug)
console.log(`skipping result due to mode filter`, result);
return;
}
if (result.mode == "time") {
let timefilter = "custom";
if ([15, 30, 60, 120].includes(parseInt(result.mode2 as string))) {
timefilter = result.mode2.toString();
//apply filters
try {
let resdiff = result.difficulty;
if (resdiff == undefined) {
resdiff = "normal";
}
if (!ResultFilters.getFilter("time", timefilter)) {
if (!ResultFilters.getFilter("difficulty", resdiff)) {
if (filterDebug)
console.log(`skipping result due to time filter`, result);
console.log(`skipping result due to difficulty filter`, result);
return;
}
} else if (result.mode == "words") {
let wordfilter = "custom";
if (
[10, 25, 50, 100, 200].includes(parseInt(result.mode2 as string))
) {
wordfilter = result.mode2.toString();
}
if (!ResultFilters.getFilter("words", wordfilter)) {
if (!ResultFilters.getFilter("mode", result.mode)) {
if (filterDebug)
console.log(`skipping result due to word filter`, result);
console.log(`skipping result due to mode filter`, result);
return;
}
}
if (result.quoteLength != null) {
let filter = null;
if (result.quoteLength === 0) {
filter = "short";
} else if (result.quoteLength === 1) {
filter = "medium";
} else if (result.quoteLength === 2) {
filter = "long";
} else if (result.quoteLength === 3) {
filter = "thicc";
}
if (
filter !== null &&
!ResultFilters.getFilter("quoteLength", filter)
) {
if (filterDebug)
console.log(`skipping result due to quoteLength filter`, result);
return;
}
}
let langFilter = ResultFilters.getFilter(
"language",
result.language ?? "english"
);
if (
result.language === "english_expanded" &&
ResultFilters.getFilter("language", "english_1k")
) {
langFilter = true;
}
if (!langFilter) {
if (filterDebug)
console.log(`skipping result due to language filter`, result);
return;
}
let puncfilter = "off";
if (result.punctuation) {
puncfilter = "on";
}
if (!ResultFilters.getFilter("punctuation", puncfilter)) {
if (filterDebug)
console.log(`skipping result due to punctuation filter`, result);
return;
}
let numfilter = "off";
if (result.numbers) {
numfilter = "on";
}
if (!ResultFilters.getFilter("numbers", numfilter)) {
if (filterDebug)
console.log(`skipping result due to numbers filter`, result);
return;
}
if (result.funbox === "none" || result.funbox === undefined) {
if (!ResultFilters.getFilter("funbox", "none")) {
if (filterDebug)
console.log(`skipping result due to funbox filter`, result);
return;
}
} else {
if (!ResultFilters.getFilter("funbox", result.funbox)) {
if (filterDebug)
console.log(`skipping result due to funbox filter`, result);
return;
}
}
let tagHide = true;
if (result.tags === undefined || result.tags.length === 0) {
//no tags, show when no tag is enabled
if (DB.getSnapshot().tags.length > 0) {
if (ResultFilters.getFilter("tags", "none")) tagHide = false;
} else {
tagHide = false;
}
} else {
//tags exist
const validTags: string[] = DB.getSnapshot().tags.map(
(t: MonkeyTypes.Tag) => t._id
);
result.tags.forEach((tag) => {
//check if i even need to check tags anymore
if (!tagHide) return;
//check if tag is valid
if (validTags.includes(tag)) {
//tag valid, check if filter is on
if (ResultFilters.getFilter("tags", tag)) tagHide = false;
} else {
//tag not found in valid tags, meaning probably deleted
if (ResultFilters.getFilter("tags", "none")) tagHide = false;
if (result.mode == "time") {
let timefilter: MonkeyTypes.Mode2Custom<"time"> = "custom";
if ([15, 30, 60, 120].includes(parseInt(result.mode2 as string))) {
timefilter = result.mode2;
}
});
if (!ResultFilters.getFilter("time", timefilter)) {
if (filterDebug)
console.log(`skipping result due to time filter`, result);
return;
}
} else if (result.mode == "words") {
let wordfilter: MonkeyTypes.Mode2Custom<"words"> = "custom";
if (
[10, 25, 50, 100, 200].includes(parseInt(result.mode2 as string))
) {
wordfilter = result.mode2;
}
if (!ResultFilters.getFilter("words", wordfilter)) {
if (filterDebug)
console.log(`skipping result due to word filter`, result);
return;
}
}
if (result.quoteLength != null) {
let filter: MonkeyTypes.QuoteModes | undefined = undefined;
if (result.quoteLength === 0) {
filter = "short";
} else if (result.quoteLength === 1) {
filter = "medium";
} else if (result.quoteLength === 2) {
filter = "long";
} else if (result.quoteLength === 3) {
filter = "thicc";
}
if (
filter !== undefined &&
!ResultFilters.getFilter("quoteLength", filter)
) {
if (filterDebug)
console.log(
`skipping result due to quoteLength filter`,
result
);
return;
}
}
let langFilter = ResultFilters.getFilter(
"language",
result.language ?? "english"
);
if (
result.language === "english_expanded" &&
ResultFilters.getFilter("language", "english_1k")
) {
langFilter = true;
}
if (!langFilter) {
if (filterDebug)
console.log(`skipping result due to language filter`, result);
return;
}
let puncfilter: MonkeyTypes.Filter<"punctuation"> = "off";
if (result.punctuation) {
puncfilter = "on";
}
if (!ResultFilters.getFilter("punctuation", puncfilter)) {
if (filterDebug)
console.log(`skipping result due to punctuation filter`, result);
return;
}
let numfilter: MonkeyTypes.Filter<"numbers"> = "off";
if (result.numbers) {
numfilter = "on";
}
if (!ResultFilters.getFilter("numbers", numfilter)) {
if (filterDebug)
console.log(`skipping result due to numbers filter`, result);
return;
}
if (result.funbox === "none" || result.funbox === undefined) {
if (!ResultFilters.getFilter("funbox", "none")) {
if (filterDebug)
console.log(`skipping result due to funbox filter`, result);
return;
}
} else {
if (!ResultFilters.getFilter("funbox", result.funbox)) {
if (filterDebug)
console.log(`skipping result due to funbox filter`, result);
return;
}
}
let tagHide = true;
if (result.tags === undefined || result.tags.length === 0) {
//no tags, show when no tag is enabled
if (DB.getSnapshot().tags?.length || 0 > 0) {
if (ResultFilters.getFilter("tags", "none")) tagHide = false;
} else {
tagHide = false;
}
} else {
//tags exist
const validTags = DB.getSnapshot().tags?.map((t) => t._id);
if (validTags === undefined) return;
result.tags.forEach((tag) => {
//check if i even need to check tags anymore
if (!tagHide) return;
//check if tag is valid
if (validTags?.includes(tag)) {
//tag valid, check if filter is on
if (ResultFilters.getFilter("tags", tag)) tagHide = false;
} else {
//tag not found in valid tags, meaning probably deleted
if (ResultFilters.getFilter("tags", "none")) tagHide = false;
}
});
}
if (tagHide) {
if (filterDebug)
console.log(`skipping result due to tag filter`, result);
return;
}
const timeSinceTest = Math.abs(result.timestamp - Date.now()) / 1000;
let datehide = true;
if (
ResultFilters.getFilter("date", "all") ||
(ResultFilters.getFilter("date", "last_day") &&
timeSinceTest <= 86400) ||
(ResultFilters.getFilter("date", "last_week") &&
timeSinceTest <= 604800) ||
(ResultFilters.getFilter("date", "last_month") &&
timeSinceTest <= 2592000) ||
(ResultFilters.getFilter("date", "last_3months") &&
timeSinceTest <= 7776000)
) {
datehide = false;
}
if (datehide) {
if (filterDebug)
console.log(`skipping result due to date filter`, result);
return;
}
filteredResults.push(result);
} catch (e) {
Notifications.add(
"Something went wrong when filtering. Resetting filters.",
0
);
console.log(result);
console.error(e);
ResultFilters.reset();
ResultFilters.updateActive();
update();
}
//filters done
//=======================================
if (tagHide) {
if (filterDebug)
console.log(`skipping result due to tag filter`, result);
return;
}
const resultDate = new Date(result.timestamp);
resultDate.setSeconds(0);
resultDate.setMinutes(0);
resultDate.setHours(0);
resultDate.setMilliseconds(0);
const resultTimestamp = resultDate.getTime();
const timeSinceTest = Math.abs(result.timestamp - Date.now()) / 1000;
let datehide = true;
if (
ResultFilters.getFilter("date", "all") ||
(ResultFilters.getFilter("date", "last_day") &&
timeSinceTest <= 86400) ||
(ResultFilters.getFilter("date", "last_week") &&
timeSinceTest <= 604800) ||
(ResultFilters.getFilter("date", "last_month") &&
timeSinceTest <= 2592000) ||
(ResultFilters.getFilter("date", "last_3months") &&
timeSinceTest <= 7776000)
) {
datehide = false;
}
if (datehide) {
if (filterDebug)
console.log(`skipping result due to date filter`, result);
return;
}
filteredResults.push(result);
} catch (e) {
Notifications.add(
"Something went wrong when filtering. Resetting filters.",
0
);
console.log(result);
console.error(e);
ResultFilters.reset();
ResultFilters.updateActive();
update();
}
//filters done
//=======================================
const resultDate = new Date(result.timestamp);
resultDate.setSeconds(0);
resultDate.setMinutes(0);
resultDate.setHours(0);
resultDate.setMilliseconds(0);
const resultTimestamp = resultDate.getTime();
if (Object.keys(activityChartData).includes(String(resultTimestamp))) {
activityChartData[resultTimestamp].amount++;
activityChartData[resultTimestamp].time +=
result.testDuration +
result.incompleteTestSeconds -
(result.afkDuration ?? 0);
activityChartData[resultTimestamp].totalWpm += result.wpm;
} else {
activityChartData[resultTimestamp] = {
amount: 1,
time:
if (Object.keys(activityChartData).includes(String(resultTimestamp))) {
activityChartData[resultTimestamp].amount++;
activityChartData[resultTimestamp].time +=
result.testDuration +
result.incompleteTestSeconds -
(result.afkDuration ?? 0),
totalWpm: result.wpm,
};
}
let tt = 0;
if (
result.testDuration == undefined &&
result.mode2 !== "custom" &&
result.mode2 !== "zen"
) {
//test finished before testDuration field was introduced - estimate
if (result.mode == "time") {
tt = result.mode2;
} else if (result.mode == "words") {
tt = (result.mode2 / result.wpm) * 60;
(result.afkDuration ?? 0);
activityChartData[resultTimestamp].totalWpm += result.wpm;
} else {
activityChartData[resultTimestamp] = {
amount: 1,
time:
result.testDuration +
result.incompleteTestSeconds -
(result.afkDuration ?? 0),
totalWpm: result.wpm,
};
}
} else {
tt = result.testDuration;
}
if (result.incompleteTestSeconds != undefined) {
tt += result.incompleteTestSeconds;
} else if (result.restartCount != undefined && result.restartCount > 0) {
tt += (tt / 4) * result.restartCount;
}
// if (result.incompleteTestSeconds != undefined) {
// tt += result.incompleteTestSeconds;
// } else if (result.restartCount != undefined && result.restartCount > 0) {
// tt += (tt / 4) * result.restartCount;
// }
totalSecondsFiltered += tt;
if (last10 < 10) {
last10++;
wpmLast10total += result.wpm;
totalAcc10 += result.acc;
result.consistency !== undefined
? (totalCons10 += result.consistency)
: 0;
}
testCount++;
if (result.consistency !== undefined) {
consCount++;
totalCons += result.consistency;
if (result.consistency > topCons) {
topCons = result.consistency;
let tt = 0;
if (
result.testDuration == undefined &&
result.mode2 !== "custom" &&
result.mode2 !== "zen"
) {
//test finished before testDuration field was introduced - estimate
if (result.mode == "time") {
tt = result.mode2;
} else if (result.mode == "words") {
tt = (result.mode2 / result.wpm) * 60;
}
} else {
tt = result.testDuration;
}
}
if (result.rawWpm != null) {
if (rawWpm.last10Count < 10) {
rawWpm.last10Count++;
rawWpm.last10Total += result.rawWpm;
if (result.incompleteTestSeconds != undefined) {
tt += result.incompleteTestSeconds;
} else if (
result.restartCount != undefined &&
result.restartCount > 0
) {
tt += (tt / 4) * result.restartCount;
}
rawWpm.total += result.rawWpm;
rawWpm.count++;
if (result.rawWpm > rawWpm.max) {
rawWpm.max = result.rawWpm;
// if (result.incompleteTestSeconds != undefined) {
// tt += result.incompleteTestSeconds;
// } else if (result.restartCount != undefined && result.restartCount > 0) {
// tt += (tt / 4) * result.restartCount;
// }
totalSecondsFiltered += tt;
if (last10 < 10) {
last10++;
wpmLast10total += result.wpm;
totalAcc10 += result.acc;
result.consistency !== undefined
? (totalCons10 += result.consistency)
: 0;
}
testCount++;
if (result.consistency !== undefined) {
consCount++;
totalCons += result.consistency;
if (result.consistency > topCons) {
topCons = result.consistency;
}
}
if (result.rawWpm != null) {
if (rawWpm.last10Count < 10) {
rawWpm.last10Count++;
rawWpm.last10Total += result.rawWpm;
}
rawWpm.total += result.rawWpm;
rawWpm.count++;
if (result.rawWpm > rawWpm.max) {
rawWpm.max = result.rawWpm;
}
}
if (result.acc > topAcc) {
topAcc = result.acc;
}
totalAcc += result.acc;
if (result.restartCount != undefined) {
testRestarts += result.restartCount;
}
chartData.push({
x: result.timestamp,
y: Config.alwaysShowCPM ? Misc.roundTo2(result.wpm * 5) : result.wpm,
acc: result.acc,
mode: result.mode,
mode2: result.mode2,
punctuation: result.punctuation as boolean,
language: result.language,
timestamp: result.timestamp,
difficulty: result.difficulty,
raw: Config.alwaysShowCPM
? Misc.roundTo2(result.rawWpm * 5)
: result.rawWpm,
});
wpmChartData.push(result.wpm);
accChartData.push({
x: result.timestamp,
y: 100 - result.acc,
});
if (result.wpm > topWpm) {
const puncsctring = result.punctuation ? ",<br>with punctuation" : "";
const numbsctring = result.numbers
? ",<br> " + (result.punctuation ? "&" : "") + "with numbers"
: "";
topWpm = result.wpm;
if (result.mode == "custom") topMode = result.mode;
else
topMode =
result.mode + " " + result.mode2 + puncsctring + numbsctring;
}
totalWpm += result.wpm;
}
if (result.acc > topAcc) {
topAcc = result.acc;
}
totalAcc += result.acc;
if (result.restartCount != undefined) {
testRestarts += result.restartCount;
}
chartData.push({
x: result.timestamp,
y: Config.alwaysShowCPM ? Misc.roundTo2(result.wpm * 5) : result.wpm,
acc: result.acc,
mode: result.mode,
mode2: result.mode2,
punctuation: result.punctuation as boolean,
language: result.language,
timestamp: result.timestamp,
difficulty: result.difficulty,
raw: Config.alwaysShowCPM
? Misc.roundTo2(result.rawWpm * 5)
: result.rawWpm,
});
wpmChartData.push(result.wpm);
accChartData.push({
x: result.timestamp,
y: 100 - result.acc,
});
if (result.wpm > topWpm) {
const puncsctring = result.punctuation ? ",<br>with punctuation" : "";
const numbsctring = result.numbers
? ",<br> " + (result.punctuation ? "&" : "") + "with numbers"
: "";
topWpm = result.wpm;
if (result.mode == "custom") topMode = result.mode;
else
topMode =
result.mode + " " + result.mode2 + puncsctring + numbsctring;
}
totalWpm += result.wpm;
});
);
if (Config.alwaysShowCPM) {
$(".pageAccount .group.history table thead tr td:nth-child(2)").text(
@ -630,8 +639,10 @@ export function update(): void {
"Average Wpm";
}
ChartController.accountActivity.data.datasets[0].data = activityChartData_time;
ChartController.accountActivity.data.datasets[1].data = activityChartData_avgWpm;
ChartController.accountActivity.data.datasets[0].data =
activityChartData_time;
ChartController.accountActivity.data.datasets[1].data =
activityChartData_avgWpm;
if (Config.alwaysShowCPM) {
ChartController.accountHistory.options.scales.yAxes[0].scaleLabel.labelString =
@ -653,9 +664,8 @@ export function update(): void {
Math.floor(maxWpmChartVal) + (10 - (Math.floor(maxWpmChartVal) % 10));
if (!Config.startGraphsAtZero) {
ChartController.accountHistory.options.scales.yAxes[0].ticks.min = Math.floor(
minWpmChartVal
);
ChartController.accountHistory.options.scales.yAxes[0].ticks.min =
Math.floor(minWpmChartVal);
} else {
ChartController.accountHistory.options.scales.yAxes[0].ticks.min = 0;
}
@ -963,7 +973,9 @@ $(document).on("click", ".pageAccount .miniResultChartButton", (event) => {
console.log("updating");
const filteredId = $(event.currentTarget).attr("filteredResultsId");
if (filteredId === undefined) return;
MiniResultChart.updateData(filteredResults[parseInt(filteredId)].chartData);
MiniResultChart.updateData(
filteredResults[parseInt(filteredId)].chartData as MonkeyTypes.ChartData
);
MiniResultChart.show();
MiniResultChart.updatePosition(
event.pageX - ($(".pageAccount .miniResultChartWrapper").outerWidth() ?? 0),

View file

@ -587,7 +587,7 @@ function setActiveFunboxButton(): void {
function refreshTagsSettingsSection(): void {
if (firebase.auth().currentUser !== null && DB.getSnapshot() !== null) {
const tagsEl = $(".pageSettings .section.tags .tagsList").empty();
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((tag) => {
// let tagPbString = "No PB found";
// if (tag.pb != undefined && tag.pb > 0) {
// tagPbString = `PB: ${tag.pb}`;
@ -622,7 +622,7 @@ function refreshTagsSettingsSection(): void {
function refreshPresetsSettingsSection(): void {
if (firebase.auth().currentUser !== null && DB.getSnapshot() !== null) {
const presetsEl = $(".pageSettings .section.presets .presetsList").empty();
DB.getSnapshot().presets.forEach((preset: MonkeyTypes.Preset) => {
DB.getSnapshot().presets?.forEach((preset: MonkeyTypes.Preset) => {
presetsEl.append(`
<div class="buttons preset" id="${preset._id}">
<div class="button presetButton">
@ -904,7 +904,7 @@ $(".pageSettings .section.customBackgroundSize .inputAndButton .save").on(
UpdateConfig.setCustomBackground(
$(
".pageSettings .section.customBackgroundSize .inputAndButton input"
).val()
).val() as string
);
}
);
@ -915,7 +915,7 @@ $(".pageSettings .section.customBackgroundSize .inputAndButton input").keypress(
UpdateConfig.setCustomBackground(
$(
".pageSettings .section.customBackgroundSize .inputAndButton input"
).val()
).val() as string
);
}
}
@ -925,7 +925,9 @@ $(".pageSettings .section.customLayoutfluid .inputAndButton .save").on(
"click",
() => {
UpdateConfig.setCustomLayoutfluid(
$(".pageSettings .section.customLayoutfluid .inputAndButton input").val()
$(
".pageSettings .section.customLayoutfluid .inputAndButton input"
).val() as MonkeyTypes.CustomLayoutFluidSpaces
);
Notifications.add("Custom layoutfluid saved", 1);
}
@ -937,7 +939,7 @@ $(".pageSettings .section.customLayoutfluid .inputAndButton .input").keypress(
UpdateConfig.setCustomLayoutfluid(
$(
".pageSettings .section.customLayoutfluid .inputAndButton input"
).val()
).val() as MonkeyTypes.CustomLayoutFluidSpaces
);
Notifications.add("Custom layoutfluid saved", 1);
}

View file

@ -102,7 +102,7 @@ function apply(): void {
const val = parseInput($("#customTestDurationPopup input").val() as string);
if (val !== null && !isNaN(val) && val >= 0) {
UpdateConfig.setTimeConfig(val);
UpdateConfig.setTimeConfig(val as MonkeyTypes.TimeModes);
ManualRestart.set();
TestLogic.restart();
if (val >= 1800) {

View file

@ -36,7 +36,7 @@ function apply(): void {
const val = parseInt($("#customWordAmountPopup input").val() as string);
if (val !== null && !isNaN(val) && val >= 0) {
UpdateConfig.setWordCount(val);
UpdateConfig.setWordCount(val as MonkeyTypes.WordsModes);
ManualRestart.set();
TestLogic.restart();
if (val > 2000) {

View file

@ -79,11 +79,11 @@ async function apply(): Promise<void> {
);
// TODO fix this sometime
let configChanges: ConfigChanges = (null as unknown) as ConfigChanges;
let configChanges: ConfigChanges = null as unknown as ConfigChanges;
if ((updateConfig && action === "edit") || action === "add") {
configChanges = Config.getConfigChanges() as ConfigChanges;
const activeTagIds: string[] = [];
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((tag) => {
if (tag.active) {
activeTagIds.push(tag._id);
}
@ -112,7 +112,7 @@ async function apply(): Promise<void> {
Notifications.add(response.data.message);
} else {
Notifications.add("Preset added", 1, 2);
DB.getSnapshot().presets.push({
DB.getSnapshot().presets?.push({
name: inputVal,
config: configChanges,
_id: response.data.insertedId,
@ -140,12 +140,15 @@ async function apply(): Promise<void> {
Notifications.add(response.data.message);
} else {
Notifications.add("Preset updated", 1);
const preset: MonkeyTypes.Snapshot = DB.getSnapshot().presets.filter(
const preset = DB.getSnapshot().presets?.filter(
(preset: MonkeyTypes.Preset) => preset._id == presetid
)[0];
preset.name = inputVal;
if (updateConfig === true) preset.config = configChanges;
Settings.update();
if (preset !== undefined) {
preset.name = inputVal;
if (updateConfig === true) preset.config = configChanges;
Settings.update();
}
}
} else if (action === "remove") {
Loader.show();
@ -166,10 +169,10 @@ async function apply(): Promise<void> {
Notifications.add(response.data.message);
} else {
Notifications.add("Preset removed", 1);
DB.getSnapshot().presets.forEach(
DB.getSnapshot().presets?.forEach(
(preset: MonkeyTypes.Preset, index: number) => {
if (preset._id === presetid) {
DB.getSnapshot().presets.splice(index, 1);
DB.getSnapshot().presets?.splice(index, 1);
}
}
);

View file

@ -91,7 +91,7 @@ async function apply(): Promise<void> {
Notifications.add(response.data.message);
} else {
Notifications.add("Tag added", 1);
DB.getSnapshot().tags.push({
DB.getSnapshot().tags?.push({
name: response.data.name,
_id: response.data._id,
});
@ -119,7 +119,7 @@ async function apply(): Promise<void> {
Notifications.add(response.data.message);
} else {
Notifications.add("Tag updated", 1);
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((tag) => {
if (tag._id === tagid) {
tag.name = inputVal;
}
@ -145,9 +145,9 @@ async function apply(): Promise<void> {
Notifications.add(response.data.message);
} else {
Notifications.add("Tag removed", 1);
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag, index: number) => {
DB.getSnapshot().tags?.forEach((tag, index: number) => {
if (tag._id === tagid) {
DB.getSnapshot().tags.splice(index, 1);
DB.getSnapshot().tags?.splice(index, 1);
}
});
ResultTagsPopup.updateButtons();
@ -171,9 +171,15 @@ async function apply(): Promise<void> {
Notifications.add(response.data.message);
} else {
Notifications.add("Tag PB cleared", 1);
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((tag) => {
if (tag._id === tagid) {
tag.personalBests = {};
tag.personalBests = {
time: {},
words: {},
custom: { custom: [] },
zen: { zen: [] },
quote: { custom: [] },
};
}
});
ResultTagsPopup.updateButtons();

View file

@ -95,23 +95,27 @@ $("#top .mobileConfig").click(() => {
el.find(".wordsGroup .button").on("click", (e) => {
const wrd = $(e.currentTarget).attr("words");
if (wrd == "custom") {
hidePopup();
CustomWordAmountPopup.show();
} else {
UpdateConfig.setWordCount(wrd);
} else if (wrd !== undefined) {
const wrdNum = parseInt(wrd);
UpdateConfig.setWordCount(wrdNum);
ManualRestart.set();
TestLogic.restart();
}
});
el.find(".timeGroup .button").on("click", (e) => {
const mode = $(e.currentTarget).attr("time");
if (mode == "custom") {
const time = $(e.currentTarget).attr("time");
if (time == "custom") {
hidePopup();
CustomTestDurationPopup.show();
} else {
UpdateConfig.setTimeConfig(mode);
} else if (time !== undefined) {
const timeNum = parseInt(time);
UpdateConfig.setTimeConfig(timeNum);
ManualRestart.set();
TestLogic.restart();
}
@ -128,7 +132,11 @@ el.find(".quoteGroup .button").on("click", (e) => {
if (len == -1) {
len = [0, 1, 2, 3];
}
UpdateConfig.setQuoteLength(len, false, e.shiftKey);
UpdateConfig.setQuoteLength(
len as MonkeyTypes.QuoteLength | MonkeyTypes.QuoteLengthArray,
false,
e.shiftKey
);
ManualRestart.set();
TestLogic.restart();
}
@ -154,7 +162,7 @@ el.find(".numbers").on("click", () => {
el.find(".modeGroup .button").on("click", (e) => {
if ($(e.currentTarget).hasClass("active")) return;
const mode = $(e.currentTarget).attr("mode");
UpdateConfig.setMode(mode);
UpdateConfig.setMode(mode as MonkeyTypes.Mode);
ManualRestart.set();
TestLogic.restart();
});

View file

@ -1,47 +1,42 @@
import * as DB from "../db";
function update(mode: string): void {
interface PersonalBest extends MonkeyTypes.PersonalBest {
mode2: MonkeyTypes.Mode2<MonkeyTypes.Mode>;
}
function update(mode: MonkeyTypes.Mode): void {
$("#pbTablesPopup table tbody").empty();
$($("#pbTablesPopup table thead tr td")[0]).text(mode);
type PersonalBests = {
[key: string]: PersonalBest[];
};
const snapshot = DB.getSnapshot();
type PersonalBest = {
acc: number;
consistency: number;
difficulty: MonkeyTypes.Difficulty;
lazyMode: boolean;
language: string;
punctuation: boolean;
raw: number;
wpm: number;
timestamp: number;
mode2?: string;
};
const allmode2 = (
snapshot.personalBests === undefined
? undefined
: snapshot.personalBests[mode]
) as { [quote: string]: PersonalBest[] } | undefined;
const allmode2: PersonalBests = DB.getSnapshot().personalBests[mode];
if (!allmode2) return;
if (allmode2 === undefined) return;
const list: PersonalBest[] = [];
Object.keys(allmode2).forEach(function (key) {
let pbs = allmode2[key];
pbs = pbs.sort(function (a, b) {
return b.wpm - a.wpm;
// if (a.difficulty === b.difficulty) {
// return (a.language < b.language ? -1 : 1);
// }
// return (a.difficulty < b.difficulty ? -1 : 1)
});
pbs.forEach(function (pb) {
pb.mode2 = key;
list.push(pb);
});
});
(Object.keys(allmode2) as MonkeyTypes.Mode2<MonkeyTypes.Mode>[]).forEach(
function (key) {
let pbs = allmode2[key];
pbs = pbs.sort(function (a, b) {
return b.wpm - a.wpm;
// if (a.difficulty === b.difficulty) {
// return (a.language < b.language ? -1 : 1);
// }
// return (a.difficulty < b.difficulty ? -1 : 1)
});
pbs.forEach(function (pb) {
pb.mode2 = key;
list.push(pb);
});
}
);
let mode2memory: string;
let mode2memory: MonkeyTypes.Mode2<MonkeyTypes.Mode>;
list.forEach((pb) => {
let dateText = `-<br><span class="sub">-</span>`;
@ -74,11 +69,11 @@ function update(mode: string): void {
<td>${dateText}</td>
</tr>
`);
mode2memory = pb.mode2 as string;
mode2memory = pb.mode2 as never;
});
}
function show(mode: string): void {
function show(mode: MonkeyTypes.Mode): void {
if ($("#pbTablesPopupWrapper").hasClass("hidden")) {
update(mode);

View file

@ -15,12 +15,6 @@ type QuoteStats = {
language: string;
};
type QuoteRatings = {
[language: string]: {
[id: string]: number;
};
};
let quoteStats: QuoteStats | null | Record<string, never> = null;
let currentQuote: MonkeyTypes.Quote | null = null;
@ -111,9 +105,13 @@ export function show(quote: MonkeyTypes.Quote, shouldReset = true): void {
currentQuote = quote;
rating = 0;
const alreadyRated = DB.getSnapshot().quoteRatings?.[
currentQuote.language
]?.[currentQuote.id];
const snapshot = DB.getSnapshot();
if (snapshot.quoteRatings === undefined) return;
const alreadyRated =
snapshot.quoteRatings[currentQuote.language][currentQuote.id];
if (alreadyRated) {
rating = alreadyRated;
}
@ -174,7 +172,10 @@ async function submit(): Promise<void> {
if (response.status !== 200) {
Notifications.add(response.data.message);
} else {
let quoteRatings: QuoteRatings = DB.getSnapshot().quoteRatings;
let quoteRatings = DB.getSnapshot().quoteRatings;
if (quoteRatings === undefined) return;
if (quoteRatings?.[currentQuote.language]?.[currentQuote.id]) {
const oldRating = quoteRatings[currentQuote.language][currentQuote.id];
const diff = rating - oldRating;
@ -243,5 +244,5 @@ $("#quoteRatePopup .submitButton").click(() => {
$(".pageTest #rateQuoteButton").click(async () => {
// TODO remove this when done with TestWords
show((TestWords.randomQuote as unknown) as MonkeyTypes.Quote);
show(TestWords.randomQuote as unknown as MonkeyTypes.Quote);
});

View file

@ -146,7 +146,7 @@ export function apply(val: number): boolean {
}
let ret;
if (val !== null && !isNaN(val) && val >= 0) {
UpdateConfig.setQuoteLength(-2, false);
UpdateConfig.setQuoteLength(-2 as MonkeyTypes.QuoteLength, false);
selectedId = val;
ManualRestart.set();
ret = true;

View file

@ -32,7 +32,7 @@ function hide(): void {
export function updateButtons(): void {
$("#resultEditTagsPanel .buttons").empty();
DB.getSnapshot().tags.forEach((tag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((tag) => {
$("#resultEditTagsPanel .buttons").append(
`<div class="button tag" tagid="${tag._id}">${tag.name}</div>`
);
@ -52,7 +52,7 @@ function updateActiveButtons(active: string[]): void {
}
$(document).on("click", ".pageAccount .group.history #resultEditTags", (f) => {
if (DB.getSnapshot().tags.length > 0) {
if (DB.getSnapshot().tags?.length || 0 > 0) {
const resultid = $(f.target).parents("span").attr("resultid") as string;
const tags = $(f.target).parents("span").attr("tags") as string;
$("#resultEditTagsPanel").attr("resultid", resultid);
@ -97,17 +97,19 @@ $("#resultEditTagsPanel .confirmButton").click(() => {
Notifications.add(response.data.message);
} else {
Notifications.add("Tags updated.", 1, 2);
DB.getSnapshot().results.forEach((result: MonkeyTypes.Result) => {
if (result._id === resultid) {
result.tags = newtags;
DB.getSnapshot().results?.forEach(
(result: MonkeyTypes.Result<MonkeyTypes.Mode>) => {
if (result._id === resultid) {
result.tags = newtags;
}
}
});
);
let tagNames = "";
if (newtags.length > 0) {
newtags.forEach((tag) => {
DB.getSnapshot().tags.forEach((snaptag: MonkeyTypes.Tag) => {
DB.getSnapshot().tags?.forEach((snaptag) => {
if (tag === snaptag._id) {
tagNames += snaptag.name + ", ";
}

View file

@ -578,10 +578,16 @@ list["clearTagPb"] = new SimplePopup(
.then((res) => {
Loader.hide();
if (res.data.resultCode === 1) {
const tag = DB.getSnapshot().tags.filter(
(t: MonkeyTypes.Tag) => t._id === tagid
)[0];
tag.pb = 0;
const tag = DB.getSnapshot().tags?.filter((t) => t._id === tagid)[0];
if (tag === undefined) return;
tag.personalBests = {
time: {},
words: {},
zen: { zen: [] },
quote: { custom: [] },
custom: { custom: [] },
};
$(
`.pageSettings .section.tags .tagsList .tag[id="${tagid}"] .clearPbButton`
).attr("aria-label", "No PB found");
@ -665,7 +671,13 @@ list["resetPersonalBests"] = new SimplePopup(
Notifications.add(response.data.message);
} else {
Notifications.add("Personal bests have been reset", 1);
DB.getSnapshot().personalBests = {};
DB.getSnapshot().personalBests = {
time: {},
words: {},
zen: { zen: [] },
quote: { custom: [] },
custom: { custom: [] },
};
}
} catch (e) {
Loader.hide();

View file

@ -9,7 +9,7 @@ export default class SettingsGroup {
public updateCallback?: () => any;
constructor(
configName: string,
configFunction: () => any,
configFunction: (...values: any[]) => any,
mode: string,
setCallback?: () => any,
updateCallback?: () => any

View file

@ -212,7 +212,7 @@ $(document).on(
$(document).on("click", ".pageSettings .section.themes .theme.button", (e) => {
const theme = $(e.currentTarget).attr("theme");
if (!$(e.target).hasClass("favButton")) {
if (!$(e.target).hasClass("favButton") && theme !== undefined) {
UpdateConfig.setTheme(theme);
updateActiveButton();
}

View file

@ -7,12 +7,10 @@ export function update(burst: number): void {
if (Config.blindMode) {
number = 0;
}
(document.querySelector(
"#miniTimerAndLiveWpm .burst"
) as Element).innerHTML = number.toString();
(document.querySelector(
"#liveBurst"
) as Element).innerHTML = number.toString();
(document.querySelector("#miniTimerAndLiveWpm .burst") as Element).innerHTML =
number.toString();
(document.querySelector("#liveBurst") as Element).innerHTML =
number.toString();
}
export function show(): void {

View file

@ -35,9 +35,8 @@ async function updateGraph() {
}
ChartController.result.updateColors();
ChartController.result.data.labels = labels;
ChartController.result.options.scales.yAxes[0].scaleLabel.labelString = Config.alwaysShowCPM
? "Character per Minute"
: "Words per Minute";
ChartController.result.options.scales.yAxes[0].scaleLabel.labelString =
Config.alwaysShowCPM ? "Character per Minute" : "Words per Minute";
let chartData1 = Config.alwaysShowCPM
? TestInput.wpmHistory.map((a) => a * 5)
: TestInput.wpmHistory;
@ -156,12 +155,10 @@ export async function updateGraphPBLine() {
) {
maxChartVal = parseFloat(chartlpb) + 20;
}
ChartController.result.options.scales.yAxes[0].ticks.max = Math.round(
maxChartVal
);
ChartController.result.options.scales.yAxes[1].ticks.max = Math.round(
maxChartVal
);
ChartController.result.options.scales.yAxes[0].ticks.max =
Math.round(maxChartVal);
ChartController.result.options.scales.yAxes[1].ticks.max =
Math.round(maxChartVal);
ChartController.result.update({ duration: 0 });
}
@ -548,9 +545,8 @@ function updateOther(
export function updateRateQuote(randomQuote) {
if (Config.mode === "quote") {
let userqr = DB.getSnapshot().quoteRatings?.[randomQuote.language]?.[
randomQuote.id
];
let userqr =
DB.getSnapshot().quoteRatings?.[randomQuote.language]?.[randomQuote.id];
if (userqr) {
$(".pageTest #result #rateQuoteButton .icon")
.removeClass("far")

View file

@ -57,7 +57,7 @@ class Words {
}
export const words = new Words();
export let hasTab = false;
export let randomQuote = (null as unknown) as MonkeyTypes.Quote;
export let randomQuote = null as unknown as MonkeyTypes.Quote;
export function setRandomQuote(rq: MonkeyTypes.Quote): void {
randomQuote = rq;

View file

@ -7,17 +7,17 @@ declare namespace MonkeyTypes {
type Mode2<M extends Mode> = keyof PersonalBests[M];
type Mode2Custom<M extends Mode> = Mode2<M> | "custom";
type LanguageGroup = { name: string; languages: string[] };
// type Mode2 = 10 | 15 | 25 | 30 | 50 | 60 | 100 | 120 | 200 | "zen" | "custom";
type WordsModes = number;
type NoncustomWordsModes = 10 | 25 | 50 | 100 | 200;
type TimeModes = number;
type WordsModes = NoncustomWordsModes | CustomModes;
type DefaultWordsModes = 10 | 25 | 50 | 100;
type NoncustomTimeModes = 15 | 30 | 60 | 120;
type TimeModes = NoncustomTimeModes | CustomModes;
type DefaultTimeModes = 15 | 30 | 60 | 120;
type QuoteModes = "short" | "medium" | "long" | "thicc";
@ -40,7 +40,7 @@ declare namespace MonkeyTypes {
type TimerStyle = "bar" | "text" | "mini";
type RandomTheme = "off" | "on" | "favorite" | "light" | "dark";
type RandomTheme = "off" | "on" | "fav" | "light" | "dark";
type TimerColor = "black" | "sub" | "text" | "main";
@ -61,15 +61,17 @@ declare namespace MonkeyTypes {
type SingleListCommandLine = "manual" | "on";
type PlaySoundOnClick =
| "off"
| "click"
| "beep"
| "pop"
| "nk_creams"
| "typewriter"
| "osu"
| "hitmarker";
/*
off = off
1 = click
2 = beep
3 = pop
4 = nk creams
5 = typewriter
6 = osu
7 = hitmarker
*/
type PlaySoundOnClick = "off" | "1" | "2" | "3" | "4" | "5" | "6" | "7";
type SoundVolume = "0.1" | "0.5" | "1.0";
@ -83,7 +85,7 @@ declare namespace MonkeyTypes {
type HighlightMode = "off" | "letter" | "word";
type EnableAds = "off" | "on" | "sellout";
type EnableAds = "off" | "on" | "max";
type MinimumAccuracy = "off" | "custom";
@ -95,12 +97,27 @@ declare namespace MonkeyTypes {
type CustomBackgroundFilter = [0 | 1, 0 | 1, 0 | 1, 0 | 1, 0 | 1];
type MonkeyPowerLevel = "off" | "mellow" | "high" | "ultra" | "over_9000";
/*
off = off
1 = mellow
2 = high
3 = ultra
4 = over 9000
*/
type MonkeyPowerLevel = "off" | "1" | "2" | "3" | "4";
type MinimumBurst = "off" | "fixed" | "flex";
type FunboxObjectType = "script" | "style";
type IndicateTypos = "off" | "below" | "replace";
type CustomLayoutFluid = `${string}#${string}#${string}`;
type CustomLayoutFluidSpaces =
| CustomLayoutFluid
| `${string} ${string} ${string}`;
interface FunboxObject {
name: string;
type: FunboxObjectType;
@ -137,22 +154,22 @@ declare namespace MonkeyTypes {
interface PersonalBests {
time: {
[key: number]: PersonalBest[];
custom: PersonalBest[];
};
words: {
[key: number]: PersonalBest[];
custom: PersonalBest[];
};
quote: { [quote: string]: PersonalBest[] };
custom: { custom: PersonalBest[] };
zen: PersonalBest[];
zen: {
zen: PersonalBest[];
};
}
interface Tag {
_id: string;
name: string;
personalBests: PersonalBests | Record<string, never>;
active: boolean;
personalBests?: PersonalBests;
active?: boolean;
}
interface Stats {
@ -172,7 +189,7 @@ declare namespace MonkeyTypes {
sd: number;
}
interface Result {
interface Result<M extends Mode> {
_id: string;
wpm: number;
rawWpm: number;
@ -180,8 +197,8 @@ declare namespace MonkeyTypes {
correctChars?: number; // --------------
incorrectChars?: number; // legacy results
acc: number;
mode: Mode;
mode2: number | "custom" | "zen";
mode: M;
mode2: Mode2<M>;
quoteLength: number;
timestamp: number;
restartCount: number;
@ -235,7 +252,7 @@ declare namespace MonkeyTypes {
layout: string;
funbox: string;
confidenceMode: ConfidenceMode;
indicateTypos: boolean;
indicateTypos: IndicateTypos;
timerStyle: TimerStyle;
colorfulMode: boolean;
randomTheme: RandomTheme;
@ -282,7 +299,7 @@ declare namespace MonkeyTypes {
customBackground: string;
customBackgroundSize: CustomBackgroundSize;
customBackgroundFilter: CustomBackgroundFilter;
customLayoutfluid: string;
customLayoutfluid: CustomLayoutFluid;
monkeyPowerLevel: MonkeyPowerLevel;
minBurst: MinimumBurst;
minBurstCustomSpeed: number;
@ -295,6 +312,14 @@ declare namespace MonkeyTypes {
wordCount: WordsModes;
}
interface LeaderboardMemory {
time: {
[key in 15 | 60]: {
[language: string]: number;
};
};
}
interface Leaderboards {
time: {
[key in 15 | 60]: LeaderboardEntry[];
@ -319,24 +344,34 @@ declare namespace MonkeyTypes {
hidden?: boolean;
}
interface QuoteRatings {
[language: string]: {
[id: string | number]: any; // TODO find this
};
}
interface Snapshot {
banned?: boolean;
emailVerified?: boolean;
quoteRatings?: object; // TODO find structure of quoteRatings
results?: Result[];
quoteRatings?: QuoteRatings;
results?: Result<Mode>[];
verified?: boolean;
personalBests?: PersonalBests;
name?: string;
presets?: Preset[];
tags?: Tag[];
favouriteThemes?: string[];
lbMemory?: Leaderboards;
lbMemory?: LeaderboardMemory;
globalStats?: Stats;
quoteMod?: boolean;
discordId?: string;
config?: Config;
}
type PartialRecord<K extends keyof any, T> = {
[P in K]?: T;
};
interface ResultFilters {
difficulty: {
normal: boolean;

16
package-lock.json generated
View file

@ -22,8 +22,8 @@
"eslint-plugin-promise": "5.1.0",
"eslint-plugin-require-path-exists": "1.1.9",
"husky": "4.3.0",
"jsonschema": "^1.4.0",
"prettier": "2.1.2",
"jsonschema": "1.4.0",
"prettier": "2.5.1",
"pretty-quick": "3.1.0"
},
"engines": {
@ -4515,9 +4515,9 @@
}
},
"node_modules/prettier": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz",
"integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
@ -9301,9 +9301,9 @@
"dev": true
},
"prettier": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz",
"integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true
},
"pretty-quick": {

View file

@ -36,8 +36,8 @@
"eslint-plugin-promise": "5.1.0",
"eslint-plugin-require-path-exists": "1.1.9",
"husky": "4.3.0",
"jsonschema": "^1.4.0",
"prettier": "2.1.2",
"jsonschema": "1.4.0",
"prettier": "2.5.1",
"pretty-quick": "3.1.0"
},
"husky": {