Skip to content

Commit e529f1e

Browse files
authored
fix(navigation): level up animation showing wrong level (@Miodec) (monkeytypegame#6946)
Introduced in monkeytypegame#6865, caused by account button reacting to the `snapshotUpdate` triggered by `addXp` function. Fixed by merging result related snapshot functions into one and adding a `noDispatchEvent` param to `setSnapshot` and using it in the new function and `addXp`. This works because result and alerts panel both call the `XPBar.update` directly to animate the xp gain.
1 parent f9a9463 commit e529f1e

File tree

3 files changed

+88
-78
lines changed

3 files changed

+88
-78
lines changed

frontend/src/ts/db.ts

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ export function getSnapshot(): Snapshot | undefined {
4949
return dbSnapshot;
5050
}
5151

52-
export function setSnapshot(newSnapshot: Snapshot | undefined): void {
52+
export function setSnapshot(
53+
newSnapshot: Snapshot | undefined,
54+
options?: { dispatchEvent?: boolean }
55+
): void {
5356
const originalBanned = dbSnapshot?.banned;
5457
const originalVerified = dbSnapshot?.verified;
5558
const lbOptOut = dbSnapshot?.lbOptOut;
@@ -71,7 +74,9 @@ export function setSnapshot(newSnapshot: Snapshot | undefined): void {
7174
dbSnapshot.lbOptOut = lbOptOut;
7275
}
7376

74-
AuthEvent.dispatch({ type: "snapshotUpdated", data: { isInitial: false } });
77+
if (options?.dispatchEvent !== false) {
78+
AuthEvent.dispatch({ type: "snapshotUpdated", data: { isInitial: false } });
79+
}
7580
}
7681

7782
export async function initSnapshot(): Promise<Snapshot | false> {
@@ -629,7 +634,7 @@ export async function getLocalPB<M extends Mode>(
629634
);
630635
}
631636

632-
export async function saveLocalPB<M extends Mode>(
637+
function saveLocalPB<M extends Mode>(
633638
mode: M,
634639
mode2: Mode2<M>,
635640
punctuation: boolean,
@@ -641,7 +646,7 @@ export async function saveLocalPB<M extends Mode>(
641646
acc: number,
642647
raw: number,
643648
consistency: number
644-
): Promise<void> {
649+
): void {
645650
if (mode === "quote") return;
646651
if (!dbSnapshot) return;
647652
function cont(): void {
@@ -922,38 +927,76 @@ export async function resetConfig(): Promise<void> {
922927
}
923928
}
924929

925-
export function saveLocalResult(result: SnapshotResult<Mode>): void {
930+
export type SaveLocalResultData = {
931+
xp?: number;
932+
streak?: number;
933+
result?: SnapshotResult<Mode>;
934+
isPb?: boolean;
935+
};
936+
937+
export function saveLocalResult(data: SaveLocalResultData): void {
926938
const snapshot = getSnapshot();
927939
if (!snapshot) return;
928940

929-
if (snapshot?.results !== undefined) {
930-
snapshot.results.unshift(result);
941+
if (data.result !== undefined) {
942+
if (snapshot?.results !== undefined) {
943+
snapshot.results.unshift(data.result);
944+
}
945+
if (snapshot.testActivity !== undefined) {
946+
snapshot.testActivity.increment(new Date(data.result.timestamp));
947+
}
948+
if (snapshot.typingStats === undefined) {
949+
snapshot.typingStats = {
950+
timeTyping: 0,
951+
startedTests: 0,
952+
completedTests: 0,
953+
};
931954

932-
setSnapshot(snapshot);
933-
}
955+
const time =
956+
data.result.testDuration +
957+
data.result.incompleteTestSeconds -
958+
data.result.afkDuration;
934959

935-
if (snapshot.testActivity !== undefined) {
936-
snapshot.testActivity.increment(new Date(result.timestamp));
937-
setSnapshot(snapshot);
960+
snapshot.typingStats.timeTyping += time;
961+
snapshot.typingStats.startedTests += data.result.restartCount + 1;
962+
snapshot.typingStats.completedTests += 1;
963+
}
964+
965+
if (data.isPb) {
966+
saveLocalPB(
967+
data.result.mode,
968+
data.result.mode2,
969+
data.result.punctuation,
970+
data.result.numbers,
971+
data.result.language,
972+
data.result.difficulty,
973+
data.result.lazyMode,
974+
data.result.wpm,
975+
data.result.acc,
976+
data.result.rawWpm,
977+
data.result.consistency
978+
);
979+
}
938980
}
939-
}
940981

941-
export function updateLocalStats(started: number, time: number): void {
942-
const snapshot = getSnapshot();
943-
if (!snapshot) return;
944-
if (snapshot.typingStats === undefined) {
945-
snapshot.typingStats = {
946-
timeTyping: 0,
947-
startedTests: 0,
948-
completedTests: 0,
949-
};
982+
if (data.xp !== undefined) {
983+
if (snapshot.xp === undefined) {
984+
snapshot.xp = 0;
985+
}
986+
snapshot.xp += data.xp;
950987
}
951988

952-
snapshot.typingStats.timeTyping += time;
953-
snapshot.typingStats.startedTests += started;
954-
snapshot.typingStats.completedTests += 1;
989+
if (data.streak !== undefined) {
990+
snapshot.streak = data.streak;
955991

956-
setSnapshot(snapshot);
992+
if (snapshot.streak > snapshot.maxStreak) {
993+
snapshot.maxStreak = snapshot.streak;
994+
}
995+
}
996+
997+
setSnapshot(snapshot, {
998+
dispatchEvent: false,
999+
});
9571000
}
9581001

9591002
export function addXp(xp: number): void {
@@ -964,7 +1007,9 @@ export function addXp(xp: number): void {
9641007
snapshot.xp = 0;
9651008
}
9661009
snapshot.xp += xp;
967-
setSnapshot(snapshot);
1010+
setSnapshot(snapshot, {
1011+
dispatchEvent: false,
1012+
});
9681013
}
9691014

9701015
export function updateInboxUnreadSize(newSize: number): void {
@@ -988,19 +1033,6 @@ export function addBadge(badge: Badge): void {
9881033
setSnapshot(snapshot);
9891034
}
9901035

991-
export function setStreak(streak: number): void {
992-
const snapshot = getSnapshot();
993-
if (!snapshot) return;
994-
995-
snapshot.streak = streak;
996-
997-
if (snapshot.streak > snapshot.maxStreak) {
998-
snapshot.maxStreak = snapshot.streak;
999-
}
1000-
1001-
setSnapshot(snapshot);
1002-
}
1003-
10041036
export async function getTestActivityCalendar(
10051037
yearString: string
10061038
): Promise<TestActivityCalendar | undefined> {

frontend/src/ts/test/test-logic.ts

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,8 @@ async function saveResult(
12881288
);
12891289
$("#result .stats .tags .editTagsButton").removeClass("invisible");
12901290

1291+
const dataToSave: DB.SaveLocalResultData = {};
1292+
12911293
if (data.xp !== undefined) {
12921294
const snapxp = DB.getSnapshot()?.xp ?? 0;
12931295

@@ -1296,11 +1298,11 @@ async function saveResult(
12961298
data.xp,
12971299
TestUI.resultVisible ? data.xpBreakdown : undefined
12981300
);
1299-
DB.addXp(data.xp);
1301+
dataToSave.xp = data.xp;
13001302
}
13011303

13021304
if (data.streak !== undefined) {
1303-
DB.setStreak(data.streak);
1305+
dataToSave.streak = data.streak;
13041306
}
13051307

13061308
if (data.insertedId !== undefined) {
@@ -1314,13 +1316,7 @@ async function saveResult(
13141316
if (data.isPb !== undefined && data.isPb) {
13151317
result.isPb = true;
13161318
}
1317-
DB.saveLocalResult(result);
1318-
DB.updateLocalStats(
1319-
completedEvent.incompleteTests.length + 1,
1320-
completedEvent.testDuration +
1321-
completedEvent.incompleteTestSeconds -
1322-
completedEvent.afkDuration
1323-
);
1319+
dataToSave.result = result;
13241320
}
13251321

13261322
void AnalyticsController.log("testCompleted");
@@ -1343,34 +1339,11 @@ async function saveResult(
13431339
}
13441340
Result.showCrown("normal");
13451341

1346-
await DB.saveLocalPB(
1347-
completedEvent.mode,
1348-
completedEvent.mode2,
1349-
completedEvent.punctuation,
1350-
completedEvent.numbers,
1351-
completedEvent.language,
1352-
completedEvent.difficulty,
1353-
completedEvent.lazyMode,
1354-
completedEvent.wpm,
1355-
completedEvent.acc,
1356-
completedEvent.rawWpm,
1357-
completedEvent.consistency
1358-
);
1342+
dataToSave.isPb = true;
13591343
} else {
13601344
Result.showErrorCrownIfNeeded();
13611345
}
13621346

1363-
// if (response.data.dailyLeaderboardRank) {
1364-
// Notifications.add(
1365-
// `New ${completedEvent.language} ${completedEvent.mode} ${completedEvent.mode2} rank: ` +
1366-
// Misc.getPositionString(response.data.dailyLeaderboardRank),
1367-
// 1,
1368-
// 10,
1369-
// "Daily Leaderboard",
1370-
// "list-ol"
1371-
// );
1372-
// }
1373-
13741347
if (data.dailyLeaderboardRank === undefined) {
13751348
$("#result .stats .dailyLeaderboard").addClass("hidden");
13761349
} else {
@@ -1396,6 +1369,7 @@ async function saveResult(
13961369
if (isRetrying) {
13971370
Notifications.add("Result saved", 1, { important: true });
13981371
}
1372+
DB.saveLocalResult(dataToSave);
13991373
}
14001374

14011375
export function fail(reason: string): void {

frontend/src/ts/utils/results.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,19 @@ export async function syncNotSignedInLastResult(uid: string): Promise<void> {
2727
const result = structuredClone(
2828
notSignedInLastResult
2929
) as unknown as SnapshotResult<Mode>;
30+
31+
const dataToSave: DB.SaveLocalResultData = {
32+
xp: response.body.data.xp,
33+
streak: response.body.data.streak,
34+
result,
35+
isPb: response.body.data.isPb,
36+
};
37+
3038
result._id = response.body.data.insertedId;
3139
if (response.body.data.isPb) {
3240
result.isPb = true;
3341
}
34-
DB.saveLocalResult(result);
35-
DB.updateLocalStats(
36-
1,
37-
result.testDuration + result.incompleteTestSeconds - result.afkDuration
38-
);
42+
DB.saveLocalResult(dataToSave);
3943
TestLogic.clearNotSignedInResult();
4044
Notifications.add(
4145
`Last test result saved ${response.body.data.isPb ? `(new pb!)` : ""}`,

0 commit comments

Comments
 (0)