refactor(types): leaderboard types

move to shared types (#4774)
add types to ape client (#4786)
This commit is contained in:
Miodec 2024-02-08 17:43:39 +01:00
parent b5465be75b
commit 15c697802d
9 changed files with 86 additions and 90 deletions

View file

@ -44,7 +44,7 @@ describe("LeaderboardsDal", () => {
"15",
"english",
0
)) as MonkeyTypes.LeaderboardEntry[];
)) as SharedTypes.LeaderboardEntry[];
//THEN
const lb = result.map((it) => _.omit(it, ["_id"]));
@ -70,7 +70,7 @@ describe("LeaderboardsDal", () => {
"60",
"english",
0
)) as MonkeyTypes.LeaderboardEntry[];
)) as SharedTypes.LeaderboardEntry[];
//THEN
const lb = result.map((it) => _.omit(it, ["_id"]));

View file

@ -12,12 +12,12 @@ export async function get(
language: string,
skip: number,
limit = 50
): Promise<MonkeyTypes.LeaderboardEntry[] | false> {
): Promise<SharedTypes.LeaderboardEntry[] | false> {
if (leaderboardUpdating[`${language}_${mode}_${mode2}`]) return false;
if (limit > 50 || limit <= 0) limit = 50;
if (skip < 0) skip = 0;
const preset = await db
.collection<MonkeyTypes.LeaderboardEntry>(
.collection<SharedTypes.LeaderboardEntry>(
`leaderboards.${language}.${mode}.${mode2}`
)
.find()
@ -31,7 +31,7 @@ export async function get(
interface GetRankResponse {
count: number;
rank: number | null;
entry: MonkeyTypes.LeaderboardEntry | null;
entry: SharedTypes.LeaderboardEntry | null;
}
export async function getRank(
@ -42,7 +42,7 @@ export async function getRank(
): Promise<GetRankResponse | false> {
if (leaderboardUpdating[`${language}_${mode}_${mode2}`]) return false;
const entry = await db
.collection<MonkeyTypes.LeaderboardEntry>(
.collection<SharedTypes.LeaderboardEntry>(
`leaderboards.${language}.${mode}.${mode2}`
)
.findOne({ uid });
@ -71,7 +71,7 @@ export async function update(
const start1 = performance.now();
const lb = db
.collection<MonkeyTypes.User>("users")
.aggregate<MonkeyTypes.LeaderboardEntry>(
.aggregate<SharedTypes.LeaderboardEntry>(
[
{
$match: {

View file

@ -9,14 +9,14 @@ const RECENT_AGE_MILLISECONDS = RECENT_AGE_MINUTES * 60 * 1000;
async function getTop10(
leaderboardTime: string
): Promise<MonkeyTypes.LeaderboardEntry[]> {
): Promise<SharedTypes.LeaderboardEntry[]> {
return (await LeaderboardsDAL.get(
"time",
leaderboardTime,
"english",
0,
10
)) as MonkeyTypes.LeaderboardEntry[]; //can do that because gettop10 will not be called during an update
)) as SharedTypes.LeaderboardEntry[]; //can do that because gettop10 will not be called during an update
}
async function updateLeaderboardAndNotifyChanges(

View file

@ -139,24 +139,6 @@ declare namespace MonkeyTypes {
personalBests: SharedTypes.PersonalBests;
}
interface LeaderboardEntry {
_id: ObjectId;
acc: number;
consistency: number;
difficulty: SharedTypes.Config.Difficulty;
lazyMode: boolean;
language: string;
punctuation: boolean;
raw: number;
wpm: number;
timestamp: number;
uid: string;
name: string;
rank: number;
badges?: Badge[];
badgeId?: number;
}
interface CustomTheme {
_id: ObjectId;
name: string;

View file

@ -1,24 +1,13 @@
const BASE_PATH = "/leaderboards";
interface LeaderboardQuery {
language: string;
mode: SharedTypes.Config.Mode;
mode2: string;
isDaily?: boolean;
daysBefore?: number;
}
interface LeadeboardQueryWithPagination extends LeaderboardQuery {
skip?: number;
limit?: number;
}
export default class Leaderboards {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async get(query: LeadeboardQueryWithPagination): Ape.EndpointResponse {
async get(
query: Ape.Leaderboards.QueryWithPagination
): Ape.EndpointResponse<Ape.Leaderboards.GetLeaderboard> {
const {
language,
mode,
@ -44,7 +33,9 @@ export default class Leaderboards {
return await this.httpClient.get(endpointPath, { searchQuery });
}
async getRank(query: LeaderboardQuery): Ape.EndpointResponse {
async getRank(
query: Ape.Leaderboards.Query
): Ape.EndpointResponse<Ape.Leaderboards.GetRank> {
const { language, mode, mode2, isDaily, daysBefore } = query;
const includeDaysBefore = (isDaily ?? false) && (daysBefore ?? 0) > 0;

View file

@ -0,0 +1,25 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
// for some reason when using the dot notaion, the types are not being recognized as used
declare namespace Ape.Leaderboards {
interface Query {
language: string;
mode: SharedTypes.Config.Mode;
mode2: string;
isDaily?: boolean;
daysBefore?: number;
}
interface QueryWithPagination extends Query {
skip?: number;
limit?: number;
}
type GetLeaderboard = SharedTypes.LeaderboardEntry[];
type GetRank = {
minWpm: number;
count: number;
rank: number | null;
entry: SharedTypes.LeaderboardEntry | null;
};
}

View file

@ -21,21 +21,14 @@ let showingYesterday = false;
type LbKey = "15" | "60";
let currentData: {
[key in LbKey]: MonkeyTypes.LeaderboardEntry[];
[key in LbKey]: SharedTypes.LeaderboardEntry[];
} = {
"15": [],
"60": [],
};
interface GetRankResponse {
minWpm: number;
count: number;
rank: number | null;
entry: MonkeyTypes.LeaderboardEntry | null;
}
let currentRank: {
[key in LbKey]: GetRankResponse | Record<string, never>;
[key in LbKey]: Ape.Leaderboards.GetRank | Record<string, never>;
} = {
"15": {},
"60": {},
@ -438,7 +431,7 @@ async function update(): Promise<void> {
const timeModes = ["15", "60"];
const leaderboardRequests = timeModes.map(async (mode2) => {
const lbDataRequests = timeModes.map(async (mode2) => {
return Ape.leaderboards.get({
language: currentLanguage,
mode: "time",
@ -447,8 +440,11 @@ async function update(): Promise<void> {
});
});
const lbRankRequests: Promise<
Ape.HttpClientResponse<Ape.Leaderboards.GetRank>
>[] = [];
if (Auth?.currentUser) {
leaderboardRequests.push(
lbRankRequests.push(
...timeModes.map(async (mode2) => {
return Ape.leaderboards.getRank({
language: currentLanguage,
@ -460,26 +456,28 @@ async function update(): Promise<void> {
);
}
const responses = await Promise.all(leaderboardRequests);
const responses = await Promise.all(lbDataRequests);
const rankResponses = await Promise.all(lbRankRequests);
const failedResponse = responses.find((response) => response.status !== 200);
if (failedResponse) {
const atLeastOneFailed =
responses.find((response) => response.status !== 200) ||
rankResponses.find((response) => response.status !== 200);
if (atLeastOneFailed) {
hideLoader("15");
hideLoader("60");
return Notifications.add(
"Failed to load leaderboards: " + failedResponse.message,
"Failed to load leaderboards: " + atLeastOneFailed.message,
-1
);
}
const [lb15Data, lb60Data, lb15Rank, lb60Rank] = responses.map(
(response) => response.data
);
const [lb15Data, lb60Data] = responses.map((response) => response.data);
const [lb15Rank, lb60Rank] = rankResponses.map((response) => response.data);
currentData["15"] = lb15Data;
currentData["60"] = lb60Data;
currentRank["15"] = lb15Rank;
currentRank["60"] = lb60Rank;
if (lb15Data !== undefined && lb15Data !== null) currentData["15"] = lb15Data;
if (lb60Data !== undefined && lb60Data !== null) currentData["60"] = lb60Data;
if (lb15Rank !== undefined && lb15Rank !== null) currentRank["15"] = lb15Rank;
if (lb60Rank !== undefined && lb60Rank !== null) currentRank["60"] = lb60Rank;
const leaderboardKeys: LbKey[] = ["15", "60"];
@ -535,9 +533,9 @@ async function requestMore(lb: LbKey, prepend = false): Promise<void> {
limit: limitVal,
...getDailyLeaderboardQuery(),
});
const data: MonkeyTypes.LeaderboardEntry[] = response.data;
const data = response.data;
if (response.status !== 200 || data.length === 0) {
if (response.status !== 200 || data === null || data.length === 0) {
hideLoader(lb);
requesting[lb] = false;
return;
@ -575,7 +573,7 @@ async function requestNew(lb: LbKey, skip: number): Promise<void> {
skip,
...getDailyLeaderboardQuery(),
});
const data: MonkeyTypes.LeaderboardEntry[] = response.data;
const data = response.data;
if (response.status === 503) {
Notifications.add(
@ -588,7 +586,7 @@ async function requestNew(lb: LbKey, skip: number): Promise<void> {
clearBody(lb);
currentData[lb] = [];
currentAvatars[lb] = [];
if (response.status !== 200 || data.length === 0) {
if (response.status !== 200 || data === null || data.length === 0) {
hideLoader(lb);
return;
}
@ -604,11 +602,14 @@ async function requestNew(lb: LbKey, skip: number): Promise<void> {
}
async function getAvatarUrls(
data: MonkeyTypes.LeaderboardEntry[]
data: Ape.Leaderboards.GetLeaderboard
): Promise<(string | null)[]> {
return Promise.allSettled(
data.map(async (entry) =>
Misc.getDiscordAvatarUrl(entry.discordId, entry.discordAvatar)
Misc.getDiscordAvatarUrl(
entry.discordId ?? undefined,
entry.discordAvatar ?? undefined
)
)
).then((promises) => {
return promises.map((promise) => {

View file

@ -200,29 +200,10 @@ declare namespace MonkeyTypes {
interface Leaderboards {
time: {
[key in 15 | 60]: LeaderboardEntry[];
[key in 15 | 60]: SharedTypes.LeaderboardEntry[];
};
}
interface LeaderboardEntry {
difficulty: string;
timestamp: number;
language: string;
wpm: number;
consistency: number | "-";
punctuation: boolean;
acc: number;
raw: number;
uid?: string;
name: string;
discordId?: string;
discordAvatar?: string;
badgeId?: number;
rank: number;
count?: number;
hidden?: boolean;
}
interface QuoteRatings {
[language: string]: {
[id: number]: number;

View file

@ -438,4 +438,20 @@ declare namespace SharedTypes {
name: string;
config: SharedTypes.ConfigPreset;
}
interface LeaderboardEntry {
_id: string;
wpm: number;
acc: number;
timestamp: number;
raw: number;
consistency: number | "-";
uid: string;
name: string;
discordId: string | null | undefined;
discordAvatar: string | null | undefined;
rank: number;
badgeId: number | null;
hidden?: boolean;
}
}