all ts errors

This commit is contained in:
Miodec 2025-02-14 20:39:57 +01:00
parent 86dcef01e2
commit 9e3f601b58
18 changed files with 389 additions and 1417 deletions

View file

@ -1,3 +1,5 @@
import * as TribeTypes from "../tribe/types";
export class InputSuggestions {
private inputElement: JQuery<HTMLElement>;
private suggestionsElement: JQuery<HTMLElement> | undefined;
@ -36,7 +38,7 @@ export class InputSuggestions {
this.inputElement.on("input", () => {
const inputVal = this.inputElement.val() as string;
const split = inputVal.split(" ");
const last = split[split.length - 1];
const last = split[split.length - 1] as string;
const search = last.slice(this.prefix.length);
if (
@ -91,9 +93,9 @@ export class InputSuggestions {
const suggestionsElement = document.createElement("div");
suggestionsElement.classList.add("inputSuggestions");
if (this.position === "top") {
this.inputElement[0].before(suggestionsElement);
this.inputElement[0]?.before(suggestionsElement);
} else {
this.inputElement[0].after(suggestionsElement);
this.inputElement[0]?.after(suggestionsElement);
}
this.suggestionsElement = $(suggestionsElement);
this.selectedIndex = 0;
@ -139,17 +141,19 @@ export class InputSuggestions {
}
for (const searchString of this.foundKeys) {
const suggestion = this.data[searchString];
const suggestion = this.data[
searchString
] as TribeTypes.InputSuggestionEntry;
const el = `
<div class="suggestion ${
added === this.selectedIndex ? "selected" : ""
}" data-search-string="${searchString}" data-id="${added}">
${
suggestion.imageIcon
suggestion.imageIcon !== undefined
? `<div class="icon"><img src="${suggestion.imageIcon}" /></div>`
: suggestion.faIcon
: suggestion.faIcon !== undefined
? `<div class="icon"><i class="fas fa-fw ${suggestion.faIcon}"></i></div>`
: suggestion.textIcon
: suggestion.textIcon !== undefined
? `<div class="icon"><span>${suggestion.textIcon}</span></div>`
: ""
}
@ -172,20 +176,20 @@ export class InputSuggestions {
if (!this.suggestionsElement) return;
if (this.position === "top") {
this.suggestionsElement.css({
left: this.inputElement[0].offsetLeft + "px",
width: this.inputElement[0].offsetWidth + "px",
left: this.inputElement[0]?.offsetLeft + "px",
width: this.inputElement[0]?.offsetWidth + "px",
top:
this.inputElement[0].offsetTop -
this.suggestionsElement[0].offsetHeight +
(this.inputElement[0]?.offsetTop ?? 0) -
(this.suggestionsElement[0]?.offsetHeight ?? 0) +
"px",
});
} else {
this.suggestionsElement.css({
left: this.inputElement[0].offsetLeft + "px",
width: this.inputElement[0].offsetWidth + "px",
left: this.inputElement[0]?.offsetLeft + "px",
width: this.inputElement[0]?.offsetWidth + "px",
top:
this.inputElement[0].offsetTop +
this.inputElement[0].offsetHeight +
(this.inputElement[0]?.offsetTop ?? 0) +
(this.inputElement[0]?.offsetHeight ?? 0) +
"px",
});
}
@ -215,9 +219,9 @@ export class InputSuggestions {
applySelection(): void {
if (!this.suggestionsElement) return;
if (this.selectedIndex === undefined) return;
if (!this.suggestionsElement) return;
if (this.suggestionsElement === undefined) return;
const toInsert = this.foundKeys[this.selectedIndex];
if (!toInsert) return;
if (toInsert === undefined) return;
const currentVal = this.inputElement.val() as string;
const split = currentVal.split(" ");

View file

@ -56,6 +56,7 @@ import * as TribeDelta from "../tribe/tribe-delta";
import * as Random from "../utils/random";
import * as TribeState from "../tribe/tribe-state";
import * as Tribe from "../tribe/tribe";
import * as TribeTypes from "../tribe/types";
export const glarsesMode = false;

View file

@ -1,13 +1,15 @@
import * as TestWords from "../test/test-words";
import * as TestUI from "../test/test-ui";
import Config from "../config";
import { convertRemToPixels } from "../utils/misc";
import * as SlowTimer from "../states/slow-timer";
import { getRoom } from "./tribe-state";
import tribeSocket from "./tribe-socket";
import * as LineJumpEvent from "../observables/line-jump-event";
import * as ThemeColors from "../elements/theme-colors";
import * as ConfigEvent from "../observables/config-event";
import * as TestState from "../test/test-state";
import { convertRemToPixels } from "../utils/numbers";
import * as TribeTypes from "./types";
const carets: { [key: string]: TribeCaret } = {};
@ -28,7 +30,8 @@ export class TribeCaret {
public spawn(): void {
if (this.element) {
return this.destroy();
this.destroy();
return;
}
//create element and store
const element = document.createElement("div");
@ -80,7 +83,8 @@ export class TribeCaret {
public animate(animationDuration: number): void {
if (!this.element) {
this.spawn();
return this.animate(125);
this.animate(125);
return;
}
// if ($("#paceCaret").hasClass("hidden")) {
// $("#paceCaret").removeClass("hidden");
@ -106,7 +110,7 @@ export class TribeCaret {
try {
const newIndex =
animationWordIndex -
(TestWords.words.currentIndex - TestUI.currentWordElementIndex);
(TestState.activeWordIndex - TestUI.activeWordElementIndex);
currentWord = <HTMLElement>(
document.querySelectorAll("#words .word")[newIndex]
);
@ -129,6 +133,7 @@ export class TribeCaret {
currentLetterWidth === undefined ||
caretWidth === undefined
) {
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw ``;
}
@ -149,7 +154,7 @@ export class TribeCaret {
this.element.addClass("hidden");
}
const currentTop = this.element[0].offsetTop;
const currentTop = this.element[0]?.offsetTop;
if (newTop !== undefined) {
const smoothlinescroll = $("#words .smoothScroller").height() ?? 0;
@ -230,7 +235,7 @@ export class TribeCaret {
}
}
async changeColor(color: keyof MonkeyTypes.ThemeColors): Promise<void> {
async changeColor(color: ThemeColors.ColorName): Promise<void> {
if (!this.element) return;
const colorHex = await ThemeColors.get(color);
this.element.css({
@ -261,7 +266,7 @@ export function init(): void {
if (!room) return;
for (const socketId of Object.keys(room.users)) {
if (socketId === tribeSocket.getId()) continue;
if (room.users[socketId].isTyping !== true) continue;
if (room.users[socketId]?.isTyping !== true) continue;
const name = room.users[socketId].name;
@ -273,11 +278,9 @@ export function updateAndAnimate(
data: Record<string, TribeTypes.UserProgress>
): void {
for (const socketId of Object.keys(data)) {
const d = data[socketId] as TribeTypes.UserProgress;
if (!carets[socketId]) continue;
carets[socketId].updatePosition(
data[socketId].wordIndex,
data[socketId].letterIndex
);
carets[socketId].updatePosition(d.wordIndex, d.letterIndex);
carets[socketId].animate(getRoom()?.updateRate ?? 500);
}
}
@ -285,29 +288,31 @@ export function updateAndAnimate(
export function destroy(socketId: string): void {
if (carets[socketId]) {
carets[socketId].destroy();
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete carets[socketId];
}
}
export function changeColor(
socketId: string,
color: keyof MonkeyTypes.ThemeColors
color: ThemeColors.ColorName
): void {
if (carets[socketId]) {
carets[socketId].changeColor(color);
void carets[socketId].changeColor(color);
}
}
export function destroyAll(): void {
for (const socketId of Object.keys(carets)) {
carets[socketId].destroy();
carets[socketId]?.destroy();
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete carets[socketId];
}
}
export function lineJump(offset: number, withAnimation: boolean): void {
for (const socketId of Object.keys(carets)) {
carets[socketId].lineJump(offset, withAnimation);
carets[socketId]?.lineJump(offset, withAnimation);
}
}
@ -328,7 +333,7 @@ ConfigEvent.subscribe((key, value, _nosave, previousValue) => {
(value === "on" && previousValue === "noNames")
) {
for (const socketId of Object.keys(carets)) {
carets[socketId].setNameVisibility(Config.tribeCarets === "on");
carets[socketId]?.setNameVisibility(Config.tribeCarets === "on");
}
}
});

View file

@ -2,8 +2,9 @@ import { Chart, ChartConfiguration } from "chart.js";
import * as TribeState from "./tribe-state";
import * as ThemeColors from "../elements/theme-colors";
import * as Notifications from "../elements/notifications";
import { createErrorMessage, smooth } from "../utils/misc";
import { createErrorMessage } from "../utils/misc";
import tribeSocket from "./tribe-socket";
import { smooth } from "../utils/arrays";
const charts: Record<string, Chart> = {};
@ -42,12 +43,12 @@ const settings: ChartConfiguration = {
pointStyle: "crossRot",
pointRadius: function (context): 0 | 2 {
const index = context.dataIndex;
const value = context.dataset.data[index] ?? 0;
const value = (context.dataset.data[index] ?? 0) as number;
return value <= 0 ? 0 : 2;
},
pointHoverRadius: function (context): 0 | 3 {
const index = context.dataIndex;
const value = context.dataset.data[index] ?? 0;
const value = (context.dataset.data[index] ?? 0) as number;
return value <= 0 ? 0 : 3;
},
},
@ -257,8 +258,9 @@ async function fillData(chart: Chart, userId: string): Promise<void> {
const labels: number[] = [];
const room = TribeState.getRoom();
if (!room) return;
const result = room.users[userId].result;
const result = room.users[userId]?.result;
if (!result) return;
for (let i = 1; i <= result.chartData.wpm.length; i++) {
labels.push(i);
}
@ -271,20 +273,27 @@ async function fillData(chart: Chart, userId: string): Promise<void> {
const smoothedRawData = smooth(result.chartData.raw, 1);
chart.data.labels = labels;
//@ts-expect-error
chart.data.datasets[0].data = result.chartData.wpm;
//@ts-expect-error
chart.data.datasets[1].data = smoothedRawData;
//@ts-expect-error
chart.data.datasets[2].data = result.chartData.err;
// chart.options.scales["wpm"].ticks.max = Math.round(chartmaxval);
// chart.options.scales["raw"].ticks.max = Math.round(chartmaxval);
if (userId == tribeSocket.getId()) {
//@ts-expect-error
chart.data.datasets[0].borderColor = await ThemeColors.get("main");
// chart.data.datasets[0].backgroundColor = await ThemeColors.get("main");
} else {
//@ts-expect-error
chart.data.datasets[0].borderColor = await ThemeColors.get("text");
// chart.data.datasets[0].backgroundColor = await ThemeColors.get("text");
}
//@ts-expect-error
chart.data.datasets[1].borderColor = await ThemeColors.get("sub");
// chart.data.datasets[1].backgroundColor = await ThemeColors.get("sub");
@ -303,10 +312,7 @@ export async function drawChart(userId: string): Promise<void> {
return;
}
const chart = new Chart(
element,
$.extend(true, {}, settings) as ChartConfiguration
);
const chart = new Chart(element, $.extend(true, {}, settings));
await fillData(chart, userId);
@ -329,7 +335,7 @@ export async function drawAllCharts(): Promise<void> {
if (!room) return;
const list = Object.keys(room.users);
for (let i = 0; i < list.length; i++) {
const userId = list[i];
const userId = list[i] as string;
if (!charts[userId]) {
await drawChart(userId);
}
@ -343,7 +349,7 @@ export async function updateChartMaxValues(): Promise<void> {
let maxRaw = 0;
for (const userId of Object.keys(room.users)) {
const result = room.users[userId].result;
const result = room.users[userId]?.result;
if (!result) continue;
const maxUserWpm = Math.max(maxWpm, Math.max(...result.chartData.wpm));
const maxUserRaw = Math.max(maxRaw, Math.max(...result.chartData.raw));
@ -358,7 +364,7 @@ export async function updateChartMaxValues(): Promise<void> {
const list = Object.keys(room.users);
for (let i = 0; i < list.length; i++) {
const userId = list[i];
const userId = list[i] as string;
if (charts[userId]) {
const scales = charts[userId].options.scales;
if (scales?.["wpm"]) {
@ -370,7 +376,7 @@ export async function updateChartMaxValues(): Promise<void> {
scales["raw"].min = 0;
}
const result = room.users[userId].result;
const result = room.users[userId]?.result;
if (result && scales?.["errors"]) {
scales["errors"].max = Math.max(...result.chartData.err) + 1;
scales["errors"].min = 0;
@ -380,15 +386,16 @@ export async function updateChartMaxValues(): Promise<void> {
// Math.round(chartmaxval);
// charts[userId].options.scales.yAxes[1].ticks.max =
// Math.round(chartmaxval);
await charts[userId].update();
charts[userId].update();
}
}
}
export function destroyAllCharts(): void {
Object.keys(charts).forEach((userId) => {
charts[userId].clear();
charts[userId].destroy();
charts[userId]?.clear();
charts[userId]?.destroy();
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete charts[userId];
});
}

View file

@ -4,6 +4,8 @@ import * as Misc from "../utils/misc";
import * as TestUI from "../test/test-ui";
import tribeSocket from "./tribe-socket";
import { InputSuggestions } from "../elements/input-suggestions";
import { getEmojiList } from "../utils/json-data";
import * as TribeTypes from "./types";
let lastMessageTimestamp = 0;
let shouldScrollChat = true;
@ -63,7 +65,7 @@ export function isAnyChatSuggestionVisible(): boolean {
);
}
Misc.getEmojiList().then((emojis) => {
void getEmojiList().then((emojis) => {
const dataToSet: Record<string, TribeTypes.InputSuggestionEntry> = {};
for (const emoji of emojis) {
if (emoji.type === "emoji") {
@ -112,7 +114,12 @@ export function reset(where: "both" | "lobby" | "result" = "both"): void {
export function fill(where: "both" | "lobby" | "result"): void {
for (const message of chatHistory) {
displayMessage(message.isSystem, message.socketId, message.message, where);
void displayMessage(
message.isSystem,
message.socketId,
message.message,
where
);
}
}
@ -140,8 +147,10 @@ function sendChattingUpdate(bool: boolean): void {
// }
export function scrollChat(): void {
const chatEl = $(".pageTribe .lobby .chat .messages")[0];
const chatEl2 = $(".pageTest #result #tribeResultBottom .chat .messages")[0];
const chatEl = $(".pageTribe .lobby .chat .messages")[0] as HTMLElement;
const chatEl2 = $(
".pageTest #result #tribeResultBottom .chat .messages"
)[0] as HTMLElement;
if (shouldScrollChat) {
chatEl.scrollTop = chatEl.scrollHeight;
@ -162,18 +171,23 @@ export function updateIsTyping(): void {
const names: string[] = [];
for (const userId of Object.keys(room.users)) {
if (room.users[userId].isChatting && userId !== tribeSocket.getId()) {
names.push(room.users[userId].name);
const user = room.users[userId] as TribeTypes.User;
if (user.isChatting && userId !== tribeSocket.getId()) {
names.push(user.name);
}
}
if (names.length > 0) {
for (let i = 0; i < names.length; i++) {
if (i === 0) {
string += `<span class="who">${Misc.escapeHTML(names[i])}</span>`;
string += `<span class="who">${Misc.escapeHTML(names[i] ?? "")}</span>`;
} else if (i === names.length - 1) {
string += ` and <span class="who">${Misc.escapeHTML(names[i])}</span>`;
string += ` and <span class="who">${Misc.escapeHTML(
names[i] ?? ""
)}</span>`;
} else {
string += `, <span class="who">${Misc.escapeHTML(names[i])}</span>`;
string += `, <span class="who">${Misc.escapeHTML(
names[i] ?? ""
)}</span>`;
}
}
if (names.length == 1) {
@ -194,12 +208,12 @@ async function insertImageEmoji(text: string): Promise<string> {
let big = "";
if (textSplit.length === 1) big = "big";
for (let i = 0; i < textSplit.length; i++) {
if (/&#58;.+&#58;/g.test(textSplit[i])) {
const emoji = await Misc.getEmojiList();
if (/&#58;.+&#58;/g.test(textSplit[i] as string)) {
const emoji = await getEmojiList();
const result = emoji.filter(
(e) =>
Misc.escapeHTML(e.from).toLowerCase() ==
textSplit[i].replace(/&#58;/g, "").toLowerCase()
textSplit[i]?.replace(/&#58;/g, "").toLowerCase()
);
if (result[0] !== undefined) {
if (result[0].type === "image") {
@ -230,7 +244,7 @@ export function appendMessage(
chatHistory.splice(0, chatHistory.length - 100);
}
displayMessage(isSystem, socketId, message);
void displayMessage(isSystem, socketId, message);
}
export async function displayMessage(
@ -241,9 +255,10 @@ export async function displayMessage(
): Promise<void> {
let cls = "message";
let author = "";
const fromName = socketId
? TribeState.getRoom()?.users[socketId]?.name
: undefined;
const fromName =
socketId !== undefined
? TribeState.getRoom()?.users[socketId]?.name
: undefined;
if (isSystem) {
cls = "systemMessage";
} else {
@ -367,9 +382,9 @@ $(".pageTest #result #tribeResultBottom .chat .input input").on(
$(".pageTribe .lobby .chat .messages").on("scroll", (_e) => {
const el = $(".pageTribe .lobby .chat .messages")[0];
const scrollHeight = el.scrollHeight as number;
const scrollTop = el.scrollTop as number;
const height = el.clientHeight as number;
const scrollHeight = el?.scrollHeight as number;
const scrollTop = el?.scrollTop as number;
const height = el?.clientHeight as number;
if (height + scrollTop < scrollHeight - 20) {
shouldScrollChat = false;
} else {
@ -379,9 +394,9 @@ $(".pageTribe .lobby .chat .messages").on("scroll", (_e) => {
$(".pageTest #result #tribeResultBottom .chat .messages").on("scroll", (_e) => {
const el = $(".pageTest #result #tribeResultBottom .chat .messages")[0];
const scrollHeight = el.scrollHeight as number;
const scrollTop = el.scrollTop as number;
const height = el.clientHeight as number;
const scrollHeight = el?.scrollHeight as number;
const scrollTop = el?.scrollTop as number;
const height = el?.clientHeight as number;
if (height + scrollTop < scrollHeight - 20) {
shouldScrollChat = false;
} else {

View file

@ -1,11 +1,17 @@
import Config, * as UpdateConfig from "../config";
import * as Funbox from "../test/funbox/funbox";
// import * as Notifications from "./notifications";
import * as CustomText from "../test/custom-text";
// import * as CustomText from "../test/custom-text";
import * as TribeConfigSyncEvent from "../observables/tribe-config-sync-event";
import * as TribeButtons from "./tribe-buttons";
import * as TribeState from "../tribe/tribe-state";
import tribeSocket from "./tribe-socket";
import * as TribeTypes from "./types";
import { Difficulty, Mode } from "@monkeytype/contracts/schemas/shared";
import {
QuoteLength,
StopOnError,
} from "@monkeytype/contracts/schemas/configs";
export function getArray(config: TribeTypes.RoomConfig): string[] {
const ret: string[] = [];
@ -42,10 +48,10 @@ export function getArray(config: TribeTypes.RoomConfig): string[] {
if (config["difficulty"] !== "normal") ret.push(config["difficulty"]);
// if(config['language'] !== "english")
ret.push(config["language"]);
if (config["punctuation"] !== false) ret.push("punctuation");
if (config["numbers"] !== false) ret.push("numbers");
if (config["punctuation"]) ret.push("punctuation");
if (config["numbers"]) ret.push("numbers");
if (config["funbox"] !== "none") ret.push(config["funbox"]);
if (config["lazyMode"] !== false) ret.push("lazy mode");
if (config["lazyMode"]) ret.push("lazy mode");
if (config["stopOnError"] !== "off") {
ret.push("stop on " + config["stopOnError"] == "word" ? "word" : "letter");
}
@ -59,42 +65,30 @@ export function getArray(config: TribeTypes.RoomConfig): string[] {
}
export function apply(config: TribeTypes.RoomConfig): void {
UpdateConfig.setMode(config.mode as MonkeyTypes.Mode, true, true);
UpdateConfig.setMode(config.mode as Mode, true, true);
if (config.mode === "time") {
UpdateConfig.setTimeConfig(config.mode2 as number, true, true);
} else if (config.mode === "words") {
UpdateConfig.setWordCount(config.mode2 as number, true, true);
} else if (config.mode === "quote") {
UpdateConfig.setQuoteLength(
config.mode2 as MonkeyTypes.QuoteLength,
true,
true,
true
);
UpdateConfig.setQuoteLength(config.mode2 as QuoteLength, true, true, true);
} else if (config.mode === "custom") {
CustomText.setText(config.customText.text, true);
CustomText.setIsWordRandom(config.customText.isWordRandom, true);
CustomText.setIsTimeRandom(config.customText.isTimeRandom, true);
CustomText.setTime(config.customText.time, true);
CustomText.setWord(config.customText.word, true);
//todo fix
// CustomText.setText(config.customText.text, true);
// CustomText.setIsWordRandom(config.customText.isWordRandom, true);
// CustomText.setIsTimeRandom(config.customText.isTimeRandom, true);
// CustomText.setTime(config.customText.time, true);
// CustomText.setWord(config.customText.word, true);
}
UpdateConfig.setDifficulty(
config.difficulty as MonkeyTypes.Difficulty,
true,
true
);
UpdateConfig.setDifficulty(config.difficulty as Difficulty, true, true);
UpdateConfig.setLanguage(config.language, true, true);
UpdateConfig.setPunctuation(config.punctuation, true, true);
UpdateConfig.setNumbers(config.numbers, true, true);
Funbox.setFunbox(config.funbox, true);
UpdateConfig.setLazyMode(config.lazyMode, true, true);
UpdateConfig.setStopOnError(
config.stopOnError as MonkeyTypes.StopOnError,
true,
true
);
UpdateConfig.setStopOnError(config.stopOnError as StopOnError, true, true);
if (config.minWpm !== "off") {
UpdateConfig.setMinWpmCustomSpeed(config.minWpm as number, true, true);
UpdateConfig.setMinWpmCustomSpeed(config.minWpm, true, true);
UpdateConfig.setMinWpm("custom", true, true);
} else {
UpdateConfig.setMinWpm("off", true, true);
@ -163,13 +157,14 @@ function sync(): void {
minAcc: Config.minAcc === "custom" ? Config.minAccCustom : "off",
minBurst:
Config.minBurst === "fixed" ? Config.minBurstCustomSpeed : "off",
customText: {
text: CustomText.text,
isWordRandom: CustomText.isWordRandom,
isTimeRandom: CustomText.isTimeRandom,
word: CustomText.word,
time: CustomText.time,
},
//todo fix
// customText: {
// text: CustomText.text,
// isWordRandom: CustomText.isWordRandom,
// isTimeRandom: CustomText.isTimeRandom,
// word: CustomText.word,
// time: CustomText.time,
// },
isInfiniteTest:
(Config.mode == "time" || Config.mode == "words") && mode2 == "0",
});

View file

@ -4,6 +4,7 @@ import * as SlowTimer from "../states/slow-timer";
import tribeSocket from "./tribe-socket";
import { FinalPositions } from "./tribe-socket/routes/room";
import { getOrdinalNumberString } from "@monkeytype/util/numbers";
import * as TribeTypes from "./types";
const initialised: Record<string, boolean | object> = {};

View file

@ -1,11 +1,17 @@
import { Mode } from "@monkeytype/contracts/schemas/shared";
import Socket from "../socket";
import { QuoteLength } from "@monkeytype/contracts/schemas/configs";
import * as TribeTypes from "../../types";
type GetPublicRoomsResponse = {
status?: string;
rooms?: TribeTypes.Room[];
};
async function getPublicRooms(
_page: number,
search: string
): Promise<TribeSocket.GetPublicRoomsResponse> {
): Promise<GetPublicRoomsResponse> {
return new Promise((resolve) => {
Socket.emit(
"room_get_public_rooms",
@ -13,22 +19,27 @@ async function getPublicRooms(
page: 0,
search: search,
},
(e: TribeSocket.GetPublicRoomsResponse) => {
(e: GetPublicRoomsResponse) => {
resolve(e);
}
);
});
}
type JoinRoomResponse = {
status?: string;
room?: TribeTypes.Room;
};
async function join(
roomId: string,
fromBrowser: boolean
): Promise<TribeSocket.JoinRoomResponse> {
): Promise<JoinRoomResponse> {
return new Promise((resolve) => {
Socket.emit(
"room_join",
{ roomId, fromBrowser },
(res: TribeSocket.JoinRoomResponse) => {
(res: JoinRoomResponse) => {
resolve(res);
}
);

View file

@ -1,4 +1,10 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
import Socket from "../socket";
import * as TribeTypes from "../../types";
async function versionCheck(
expectedVersion: string
@ -104,7 +110,9 @@ function connect(callback: () => void): void {
});
}
function disconnect(callback: (reason: string, details?: any) => void): void {
function disconnect(
callback: (reason: string, details?: unknown) => void
): void {
Socket.on("disconnect", callback);
}

View file

@ -3,10 +3,7 @@ declare namespace TribeSocket {
status?: string;
rooms?: TribeTypes.Room[];
}
interface JoinRoomResponse {
status?: string;
room?: TribeTypes.Room;
}
interface VersionCheckResponse {
status: string;
version: string;

View file

@ -1,4 +1,5 @@
import TribeSocket from "./tribe-socket";
import * as TribeTypes from "./types";
let state = -1;

View file

@ -1,4 +1,5 @@
import tribeSocket from "./tribe-socket";
import * as TribeTypes from "./types";
export let inQueueNumbers = [0, 0, 0, 0];

View file

@ -1,6 +1,7 @@
import * as TribeState from "./tribe-state";
import * as TribeUserSettingsPopup from "../popups/tribe-user-settings-popup";
import tribeSocket from "./tribe-socket";
import { User } from "./types";
export function reset(page?: string): void {
if (page === undefined) {
@ -16,7 +17,7 @@ export function reset(page?: string): void {
export function update(page?: string): void {
const room = TribeState.getRoom();
if (!room) return;
if (!page) {
if (page === undefined) {
update("lobby");
update("result");
return;
@ -28,8 +29,8 @@ export function update(page?: string): void {
usersArray.push(room.users[userId]);
}
const sortedUsers = usersArray.sort(
(a, b) => (b.points ?? 0) - (a.points ?? 0)
);
(a, b) => (b?.points ?? 0) - (a?.points ?? 0)
) as User[];
sortedUsers.forEach((user) => {
let icons = "";
if (user.isTyping && !user.isFinished) {

View file

@ -28,7 +28,9 @@ import * as TestWords from "../test/test-words";
import * as TestStats from "../test/test-stats";
import * as TestInput from "../test/test-input";
import * as TribeCarets from "./tribe-carets";
import * as TribeTypes from "./types";
import { navigate } from "../controllers/route-controller";
import { ColorName } from "../elements/theme-colors";
const defaultName = "Guest";
let name = "Guest";
@ -111,7 +113,7 @@ function updateState(newState: number): void {
} else if (state === 21) {
TribeResults.hideTimer();
TribeResults.updateTimerText("Time left for everyone to get ready");
if (TribeState.getAutoReady() === true) {
if (TribeState.getAutoReady()) {
TribeSocket.out.room.readyUpdate();
}
} else if (state === 22) {
@ -137,7 +139,7 @@ export async function init(): Promise<void> {
//todo remove, only for dev
const lstribename = window.localStorage.getItem("tribeName");
if (lstribename) {
if (lstribename !== undefined && lstribename !== null) {
name = lstribename;
TribeSocket.updateName(lstribename);
}
@ -164,17 +166,17 @@ export function joinRoom(roomId: string, fromBrowser = false): void {
return;
}
TribeSocket.out.room.join(roomId, fromBrowser).then((response) => {
void TribeSocket.out.room.join(roomId, fromBrowser).then((response) => {
if (response.room) {
TribeState.setRoom(response.room);
updateState(response.room.state);
TribePageLobby.init();
TribePages.change("lobby");
void TribePages.change("lobby");
TribeSound.play("join");
TribeChat.updateSuggestionData();
// history.replaceState(null, "", `/tribe/${roomId}`);
} else {
TribePages.change("menu");
void TribePages.change("menu");
history.replaceState("/tribe", "", "/tribe");
}
});
@ -218,14 +220,14 @@ async function connect(): Promise<void> {
UpdateConfig.setTimerStyle("mini", true);
TribePageMenu.enableButtons();
updateState(1);
if (autoJoin) {
if (autoJoin !== undefined) {
TribePagePreloader.updateText(`Joining room ${autoJoin}`);
TribePagePreloader.updateSubtext("Please wait...");
setTimeout(() => {
joinRoom(autoJoin as string);
}, 500);
} else {
TribePages.change("menu");
void TribePages.change("menu");
}
}
@ -236,10 +238,13 @@ function checkIfEveryoneIsReady(): void {
if (Object.keys(room.users).length <= 1) return;
let everyoneReady = true;
Object.keys(room.users).forEach((userId) => {
if (room && (room.users[userId].isLeader || room.users[userId].isAfk)) {
if (
room !== undefined &&
(room.users[userId]?.isLeader || room.users[userId]?.isAfk)
) {
return;
}
if (room && !room.users[userId].isReady) {
if (room !== undefined && !room.users[userId]?.isReady) {
everyoneReady = false;
}
});
@ -253,12 +258,12 @@ function checkIfEveryoneIsReady(): void {
}
TribeSocket.in.system.connect(() => {
connect();
void connect();
});
$(".tribechangename").on("click", () => {
const name = prompt("Name");
if (name) {
if (name !== "" && name !== null) {
window.localStorage.setItem("tribeName", name); //todo remove, only for dev
TribeSocket.out.user.setName(name, true);
}
@ -273,6 +278,7 @@ TribeSocket.in.system.disconnect((reason, details) => {
const roomId = TribeState.getRoom()?.id;
if (!$(".pageTribe").hasClass("active")) {
Notifications.add(
//@ts-ignore
`Disconnected: ${details?.["description"]} (${reason})`,
-1,
{
@ -281,14 +287,15 @@ TribeSocket.in.system.disconnect((reason, details) => {
);
}
TribeState.setRoom(undefined);
TribePages.change("preloader");
void TribePages.change("preloader");
TribePagePreloader.updateIcon("times");
TribePagePreloader.updateText(`Disconnected`);
//@ts-ignore
TribePagePreloader.updateSubtext(`${details?.["description"]} (${reason})`);
TribePagePreloader.showReconnectButton();
reset();
if (roomId) {
void reset();
if (roomId !== undefined) {
autoJoin = roomId;
}
});
@ -301,12 +308,12 @@ TribeSocket.in.system.connectFailed((err) => {
customTitle: "Tribe",
});
}
TribePages.change("preloader");
void TribePages.change("preloader");
TribePagePreloader.updateIcon("times");
TribePagePreloader.updateText("Connection failed");
TribePagePreloader.updateSubtext(err.message);
TribePagePreloader.showReconnectButton();
reset();
void reset();
});
TribeSocket.in.system.connectError((err) => {
@ -317,12 +324,12 @@ TribeSocket.in.system.connectError((err) => {
customTitle: "Tribe",
});
}
TribePages.change("preloader");
void TribePages.change("preloader");
TribePagePreloader.updateIcon("times");
TribePagePreloader.updateText(`Connection error`);
TribePagePreloader.updateSubtext(err.message);
TribePagePreloader.showReconnectButton();
reset();
void reset();
});
TribeSocket.in.system.reconnect((attempt) => {
@ -347,7 +354,7 @@ TribeSocket.in.room.joined((data) => {
TribeState.setRoom(data.room);
updateState(data.room.state);
TribePageLobby.init();
TribePages.change("lobby");
void TribePages.change("lobby");
TribeSound.play("join");
TribeChat.updateSuggestionData();
// history.replaceState(null, "", `/tribe/${e.room.id}`);
@ -368,6 +375,7 @@ TribeSocket.in.room.playerJoined((data) => {
TribeSocket.in.room.playerLeft((data) => {
const room = TribeState.getRoom();
if (room?.users) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete room.users[data.userId];
room.size = Object.keys(room.users).length;
TribeUserList.update();
@ -392,8 +400,8 @@ TribeSocket.in.room.left(() => {
}
TribeCarets.destroyAll();
TribeSound.play("leave");
TribePages.change("menu").then(() => {
reset();
void TribePages.change("menu").then(() => {
void reset();
});
TribeChat.updateIsTyping();
name = defaultName;
@ -416,7 +424,7 @@ TribeSocket.in.room.nameChanged((data) => {
TribeSocket.in.room.userIsReady((data) => {
const room = TribeState.getRoom();
if (!room) return;
room.users[data.userId].isReady = true;
(room.users[data.userId] as TribeTypes.User).isReady = true;
TribeUserList.update();
TribeButtons.update();
checkIfEveryoneIsReady();
@ -425,7 +433,9 @@ TribeSocket.in.room.userIsReady((data) => {
TribeSocket.in.room.userAfkUpdate((data) => {
const room = TribeState.getRoom();
if (!room) return;
room.users[data.userId].isAfk = data.isAfk;
const user = room.users[data.userId];
if (!user) return;
user.isAfk = data.isAfk;
TribeUserList.update();
TribeButtons.update();
});
@ -433,12 +443,15 @@ TribeSocket.in.room.userAfkUpdate((data) => {
TribeSocket.in.room.leaderChanged((data) => {
const room = TribeState.getRoom();
if (!room) return;
const user = room.users[data.userId];
if (!user) return;
for (const userId of Object.keys(room.users)) {
delete room.users[userId].isLeader;
delete room.users[userId]?.isLeader;
}
room.users[data.userId].isLeader = true;
room.users[data.userId].isAfk = false;
room.users[data.userId].isReady = false;
user.isLeader = true;
user.isAfk = false;
user.isReady = false;
TribeUserList.update();
TribeButtons.update();
TribePageLobby.updateVisibility();
@ -448,7 +461,9 @@ TribeSocket.in.room.leaderChanged((data) => {
TribeSocket.in.room.chattingChanged((data) => {
const room = TribeState.getRoom();
if (!room) return;
room.users[data.userId].isChatting = data.isChatting;
const user = room.users[data.userId];
if (!user) return;
user.isChatting = data.isChatting;
TribeChat.updateIsTyping();
});
@ -546,14 +561,15 @@ TribeSocket.in.room.usersUpdate((data) => {
let isChattingChanged = false;
for (const [userId, user] of Object.entries(data)) {
const roomUser = room.users[userId] as TribeTypes.User;
if (user.isTyping !== undefined) {
room.users[userId].isTyping = user.isTyping;
roomUser.isTyping = user.isTyping;
}
if (user.isAfk !== undefined) room.users[userId].isAfk = user.isAfk;
if (user.isReady !== undefined) room.users[userId].isReady = user.isReady;
if (user.isAfk !== undefined) roomUser.isAfk = user.isAfk;
if (user.isReady !== undefined) roomUser.isReady = user.isReady;
if (user.isChatting !== undefined) {
isChattingChanged = true;
room.users[userId].isChatting = user.isChatting;
roomUser.isChatting = user.isChatting;
}
}
TribeUserList.update("lobby");
@ -588,7 +604,7 @@ TribeSocket.in.room.progressUpdate((data) => {
if (
TribeState.getState() >= 10 &&
TribeState.getState() <= 21 &&
TestState.isActive === true
TestState.isActive
) {
const wpmAndRaw = TestStats.calculateWpmAndRaw();
const acc = Math.floor(TestStats.calculateAccuracy());
@ -610,7 +626,7 @@ TribeSocket.in.room.progressUpdate((data) => {
}
const wordsProgress = Math.floor(
(TestWords.words.currentIndex / outof) * 100
(TestState.activeWordIndex / outof) * 100
);
progress = wordsProgress + globalWordProgress;
@ -625,15 +641,16 @@ TribeSocket.in.room.progressUpdate((data) => {
raw: wpmAndRaw.raw,
acc,
progress,
wordIndex: TestWords.words.currentIndex,
wordIndex: TestState.activeWordIndex,
letterIndex: inputLen - 1,
afk: TestInput.afkHistory[TestInput.afkHistory.length - 1],
afk: TestInput.afkHistory[TestInput.afkHistory.length - 1] ?? false,
});
}
TribeCarets.updateAndAnimate(data.users);
for (const [userId, userProgress] of Object.entries(data.users)) {
if (room.users[userId] === undefined) continue;
room.users[userId].progress = userProgress;
if (userId == TribeSocket.getId()) {
TribeDelta.update();
@ -657,9 +674,11 @@ TribeSocket.in.room.progressUpdate((data) => {
TribeSocket.in.room.userResult((data) => {
const room = TribeState.getRoom();
if (!room) return;
room.users[data.userId].result = data.result;
room.users[data.userId].isFinished = true;
room.users[data.userId].isTyping = false;
const user = room.users[data.userId];
if (!user) return;
user.result = data.result;
user.isFinished = true;
user.isTyping = false;
const resolve = data.result?.resolve;
if (
resolve === undefined ||
@ -673,13 +692,13 @@ TribeSocket.in.room.userResult((data) => {
let color = undefined;
if (resolve?.failed === true) {
color = "colorfulError" as keyof MonkeyTypes.ThemeColors;
color = "colorfulError" as ColorName;
}
if (color) TribeCarets.changeColor(data.userId, color);
TribeBars.fadeUser("test", data.userId, color);
TribeBars.fadeUser("tribe", data.userId, color);
if (room.config.isInfiniteTest === false) {
if (!room.config.isInfiniteTest) {
TribeResults.fadeUser("result", data.userId);
}
if (resolve?.afk) {
@ -704,7 +723,7 @@ TribeSocket.in.room.userResult((data) => {
await TribeChartController.drawChart(data.userId);
}
if (TribeState.getState() >= 21) {
TribeChartController.updateChartMaxValues();
void TribeChartController.updateChartMaxValues();
}
}, 250);
}
@ -761,14 +780,19 @@ TribeSocket.in.room.finalPositions((data) => {
TribeResults.updateMiniCrowns("result", data.miniCrowns);
for (const userArray of Object.values(data.positions)) {
for (const user of userArray) {
room.users[user.id].points = user.newPointsTotal;
const u = room.users[user.id] as TribeTypes.User;
u.points = user.newPointsTotal;
}
}
TribeUserList.update();
let localGlow = false;
for (const winner of data.positions["1"]) {
const positions = data.positions["1"];
if (!positions) return;
for (const winner of positions) {
if (winner.id === TribeSocket.getId()) {
localGlow = true;
}
@ -786,7 +810,7 @@ TribeSocket.in.room.finalPositions((data) => {
TribeResults.showCrown("result", winner.id, isGlowing);
}
if (data.positions[1].some((u) => u.id === TribeSocket.getId())) {
if (positions.some((u) => u.id === TribeSocket.getId())) {
TribeSound.play("finish_win");
if (localGlow) {
TribeSound.play("glow");
@ -803,7 +827,7 @@ $(`.pageTribe .tribePage.lobby .lobbyButtons .startTestButton,
$(".pageTribe .tribePage.preloader .reconnectButton").on("click", () => {
TribePagePreloader.hideReconnectButton();
init();
void init();
});
window.addEventListener("beforeunload", () => {

View file

@ -0,0 +1,134 @@
import { ChartData } from "@monkeytype/contracts/schemas/results";
export type SystemStats = {
pingStart: number;
stats: [
number, // online users
rooms: {
mm: [number, number, number, number];
custom: [number, number];
},
queueLengths: [number, number, number, number],
version: string
];
};
export type InputSuggestionEntry = {
display: string;
imageIcon?: string;
faIcon?: string;
textIcon?: string;
};
export type Result = {
wpm: number;
raw: number;
acc: number;
consistency: number;
testDuration: number;
charStats: number[];
chartData: ChartData;
resolve: ResultResolve;
};
export type ResultResolve = {
login?: boolean;
saved?: boolean;
failed?: boolean;
afk?: boolean;
repeated?: boolean;
failedReason?: string;
valid?: boolean;
tooShort?: boolean;
saveFailedMessage?: string;
isPb?: boolean;
bailedOut?: boolean;
};
export type RoomJoin = {
room: Room;
};
export type Room = {
id: string;
state: number;
users: {
[socketId: string]: User;
};
size: number;
updateRate: number;
isPrivate: boolean;
name: string;
config: RoomConfig;
maxRaw: number;
maxWpm: number;
minRaw: number;
minWpm: number;
seed: number;
};
export type RoomConfig = {
mode: string;
mode2: string | number | number[];
difficulty: string;
language: string;
punctuation: boolean;
numbers: boolean;
funbox: string;
lazyMode: boolean;
stopOnError: string;
minWpm: number | "off";
minAcc: number | "off";
minBurst: number | "off";
//todo fix
// customText: {
// text: string[];
// isWordRandom: boolean;
// isTimeRandom: boolean;
// time: number;
// word: number;
// };
isInfiniteTest: boolean;
};
export type UserProgressOut = {
wpm: number;
raw: number;
acc: number;
progress: number;
wordIndex: number;
letterIndex: number;
afk: boolean;
};
export type UserProgress = {
wpm: number;
raw: number;
acc: number;
progress: number;
wpmProgress: number;
wordIndex: number;
letterIndex: number;
afk: boolean;
};
export type User = {
id: string;
isLeader?: boolean;
name: string;
isReady?: boolean;
result?: Result;
progress?: UserProgress;
isFinished?: boolean;
isTyping?: boolean;
isAfk?: boolean;
isChatting?: boolean;
points?: number;
};
export type MiniCrowns = {
raw: string[];
wpm: string[];
acc: string[];
consistency: string[];
};

View file

@ -1,133 +0,0 @@
declare namespace TribeTypes {
interface SystemStats {
pingStart: number;
stats: [
number, // online users
rooms: {
mm: [number, number, number, number];
custom: [number, number];
},
queueLengths: [number, number, number, number],
version: string
];
}
interface InputSuggestionEntry {
display: string;
imageIcon?: string;
faIcon?: string;
textIcon?: string;
}
interface Result {
wpm: number;
raw: number;
acc: number;
consistency: number;
testDuration: number;
charStats: number[];
chartData: MonkeyTypes.ChartData;
resolve: ResultResolve;
}
interface ResultResolve {
login?: boolean;
saved?: boolean;
failed?: boolean;
afk?: boolean;
repeated?: boolean;
failedReason?: string;
valid?: boolean;
tooShort?: boolean;
saveFailedMessage?: string;
isPb?: boolean;
bailedOut?: boolean;
}
interface RoomJoin {
room: Room;
}
interface Room {
id: string;
state: number;
users: {
[socketId: string]: User;
};
size: number;
updateRate: number;
isPrivate: boolean;
name: string;
config: RoomConfig;
maxRaw: number;
maxWpm: number;
minRaw: number;
minWpm: number;
seed: number;
}
interface RoomConfig {
mode: string;
mode2: string | number | number[];
difficulty: string;
language: string;
punctuation: boolean;
numbers: boolean;
funbox: string;
lazyMode: boolean;
stopOnError: string;
minWpm: number | "off";
minAcc: number | "off";
minBurst: number | "off";
customText: {
text: string[];
isWordRandom: boolean;
isTimeRandom: boolean;
time: number;
word: number;
};
isInfiniteTest: boolean;
}
interface UserProgressOut {
wpm: number;
raw: number;
acc: number;
progress: number;
wordIndex: number;
letterIndex: number;
afk: boolean;
}
interface UserProgress {
wpm: number;
raw: number;
acc: number;
progress: number;
wpmProgress: number;
wordIndex: number;
letterIndex: number;
afk: boolean;
}
interface User {
id: string;
isLeader?: boolean;
name: string;
isReady?: boolean;
result?: Result;
progress?: UserProgress;
isFinished?: boolean;
isTyping?: boolean;
isAfk?: boolean;
isChatting?: boolean;
points?: number;
}
interface MiniCrowns {
raw: string[];
wpm: string[];
acc: string[];
consistency: string[];
}
}

View file

@ -434,3 +434,18 @@ export async function getReleasesFromGitHub(): Promise<GithubRelease[]> {
"https://api.github.com/repos/monkeytypegame/monkeytype/releases?per_page=5"
);
}
export type Emoji = {
type: "image" | "emoji";
from: string;
to: string;
};
export async function getEmojiList(): Promise<Emoji[]> {
try {
const data = await cachedFetchJson<Emoji[]>("/./emoji/_list.json");
return data;
} catch (e) {
throw new Error("Emoji list JSON fetch failed");
}
}

File diff suppressed because it is too large Load diff