Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions frontend/src/ts/test/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import { LocalStorageWithSchema } from "../utils/local-storage-with-schema";
import { z } from "zod";
import * as TestState from "./test-state";
import { blurInputElement } from "../input/input-element";
import * as ConnectionState from "../states/connection";
import { currentQuote } from "./test-words";

let result: CompletedEvent;
let maxChartVal: number;
Expand Down Expand Up @@ -1006,6 +1008,11 @@ export async function update(
} else {
$("#result #watchVideoAdButton").removeClass("hidden");
}

if (!ConnectionState.get()) {
ConnectionState.showOfflineBanner();
}

updateWpmAndAcc();
updateConsistency();
updateTime();
Expand Down Expand Up @@ -1064,17 +1071,45 @@ export async function update(
} else {
$("main #result .stats").removeClass("hidden");
$("main #result .chart").removeClass("hidden");
// $("main #result #resultWordsHistory").removeClass("hidden");
if (!isAuthenticated()) {
$("main #result .loginTip").removeClass("hidden");
$("main #result #rateQuoteButton").addClass("hidden");
$("main #result #reportQuoteButton").addClass("hidden");
} else {
updateRateQuote(currentQuote);
$("main #result #reportQuoteButton").removeClass("hidden");
}
$("main #result .stats .dailyLeaderboard").addClass("hidden");
$("main #result #showWordHistoryButton").removeClass("hidden");
$("main #result #watchReplayButton").removeClass("hidden");
$("main #result #saveScreenshotButton").removeClass("hidden");
}

TestConfig.hide();
if (res.wpm === 0 && !difficultyFailed && res.testDuration >= 5) {
const roundedTime = Math.round(res.testDuration);

const messages = [
`Congratulations. You just wasted ${roundedTime} seconds of your life by typing nothing. Be proud of yourself.`,
`Bravo! You've managed to waste ${roundedTime} seconds and accomplish exactly zero. A true productivity icon.`,
`That was ${roundedTime} seconds of absolutely legendary idleness. History will remember this moment.`,
`Wow, ${roundedTime} seconds of typing... nothing. Bold. Mysterious. Completely useless.`,
`Thank you for those ${roundedTime} seconds of utter nothingness. The keyboard needed the break.`,
`A breathtaking display of inactivity. ${roundedTime} seconds of absolutely nothing. Powerful.`,
`You just gave ${roundedTime} seconds of your life to the void. And the void says thanks.`,
`Stunning. ${roundedTime} seconds of intense... whatever that wasn't. Keep it up, champ.`,
`Is it performance art? A protest? Or just ${roundedTime} seconds of glorious nothing? We may never know.`,
`You typed nothing for ${roundedTime} seconds. And in that moment, you became legend.`,
];

showConfetti();
Notifications.add(Arrays.randomElementFromArray(messages), 0, {
customTitle: "Nice",
duration: 15,
important: true,
});
}

TestConfig.hide();
Focus.set(false);

const canQuickRestart = canQuickRestartFn(
Expand Down
134 changes: 48 additions & 86 deletions frontend/src/ts/test/test-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,8 @@ export async function finish(difficultyFailed = false): Promise<void> {

const completedEvent = structuredClone(ce) as CompletedEvent;

TestStats.setLastResult(structuredClone(completedEvent));

///////// completed event ready

//afk check
Expand Down Expand Up @@ -1011,9 +1013,11 @@ export async function finish(difficultyFailed = false): Promise<void> {
dontSave = true;
} else if (afkDetected) {
Notifications.add("Test invalid - AFK detected", 0);
TestStats.setInvalid();
dontSave = true;
} else if (TestState.isRepeated) {
Notifications.add("Test invalid - repeated", 0);
TestStats.setInvalid();
dontSave = true;
} else if (
completedEvent.testDuration < 1 ||
Expand All @@ -1035,6 +1039,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
(Config.mode === "zen" && completedEvent.testDuration < 15)
) {
Notifications.add("Test invalid - too short", 0);
TestStats.setInvalid();
tooShort = true;
dontSave = true;
} else if (
Expand Down Expand Up @@ -1133,25 +1138,48 @@ export async function finish(difficultyFailed = false): Promise<void> {
);
Result.updateTodayTracker();

if (!isAuthenticated()) {
$(".pageTest #result #rateQuoteButton").addClass("hidden");
$(".pageTest #result #reportQuoteButton").addClass("hidden");
void AnalyticsController.log("testCompletedNoLogin");
if (!dontSave) notSignedInLastResult = completedEvent;
dontSave = true;
} else {
$(".pageTest #result #reportQuoteButton").removeClass("hidden");
}
let savingResultPromise: ReturnType<typeof saveResult> =
Promise.resolve(null);
const user = getAuthenticatedUser();
if (user !== null) {
// logged in
if (dontSave) {
void AnalyticsController.log("testCompletedInvalid");
} else {
TestStats.resetIncomplete();

$("#result .stats .dailyLeaderboard").addClass("hidden");
if (completedEvent.testDuration > 122) {
completedEvent.chartData = "toolong";
completedEvent.keySpacing = "toolong";
completedEvent.keyDuration = "toolong";
}

TestStats.setLastResult(structuredClone(completedEvent));
if (!completedEvent.bailedOut) {
const challenge = ChallengeContoller.verify(completedEvent);
if (challenge !== null) completedEvent.challenge = challenge;
}

if (!ConnectionState.get()) {
ConnectionState.showOfflineBanner();
completedEvent.uid = user.uid;
completedEvent.hash = objectHash(completedEvent);

savingResultPromise = saveResult(completedEvent, false);
void savingResultPromise.then((response) => {
if (response && response.status === 200) {
void AnalyticsController.log("testCompleted");
}
});
}
} else {
// logged out
void AnalyticsController.log("testCompletedNoLogin");
if (!dontSave) {
// if its valid save it for later
notSignedInLastResult = completedEvent;
}
dontSave = true;
}

await Result.update(
const resultUpdatePromise = Result.update(
completedEvent,
difficultyFailed,
failReason,
Expand All @@ -1162,78 +1190,13 @@ export async function finish(difficultyFailed = false): Promise<void> {
dontSave,
);

if (completedEvent.chartData !== "toolong") {
// @ts-expect-error TODO: check if this is needed
delete completedEvent.chartData.unsmoothedRaw;
}

if (completedEvent.testDuration > 122) {
completedEvent.chartData = "toolong";
completedEvent.keySpacing = "toolong";
completedEvent.keyDuration = "toolong";
}

if (
completedEvent.wpm === 0 &&
!difficultyFailed &&
completedEvent.testDuration >= 5
) {
const roundedTime = Math.round(completedEvent.testDuration);

const messages = [
`Congratulations. You just wasted ${roundedTime} seconds of your life by typing nothing. Be proud of yourself.`,
`Bravo! You've managed to waste ${roundedTime} seconds and accomplish exactly zero. A true productivity icon.`,
`That was ${roundedTime} seconds of absolutely legendary idleness. History will remember this moment.`,
`Wow, ${roundedTime} seconds of typing... nothing. Bold. Mysterious. Completely useless.`,
`Thank you for those ${roundedTime} seconds of utter nothingness. The keyboard needed the break.`,
`A breathtaking display of inactivity. ${roundedTime} seconds of absolutely nothing. Powerful.`,
`You just gave ${roundedTime} seconds of your life to the void. And the void says thanks.`,
`Stunning. ${roundedTime} seconds of intense... whatever that wasn't. Keep it up, champ.`,
`Is it performance art? A protest? Or just ${roundedTime} seconds of glorious nothing? We may never know.`,
`You typed nothing for ${roundedTime} seconds. And in that moment, you became legend.`,
];

Result.showConfetti();
Notifications.add(Arrays.randomElementFromArray(messages), 0, {
customTitle: "Nice",
duration: 15,
important: true,
});
}

if (dontSave) {
void AnalyticsController.log("testCompletedInvalid");
return;
}

// because of the dont save check above, we know the user is signed in
// we check here again so that typescript doesnt complain
const user = getAuthenticatedUser();
if (!user) {
return;
}

// user is logged in
TestStats.resetIncomplete();

completedEvent.uid = user.uid;

Result.updateRateQuote(TestWords.currentQuote);

if (!completedEvent.bailedOut) {
const challenge = ChallengeContoller.verify(completedEvent);
if (challenge !== null) completedEvent.challenge = challenge;
}

completedEvent.hash = objectHash(completedEvent);

await saveResult(completedEvent, false);
await Promise.all([savingResultPromise, resultUpdatePromise]);
}

async function saveResult(
completedEvent: CompletedEvent,
isRetrying: boolean,
): Promise<void> {
): Promise<null | Awaited<ReturnType<typeof Ape.results.add>>> {
AccountButton.loading(true);

if (!TestState.savingEnabled) {
Expand All @@ -1243,7 +1206,7 @@ async function saveResult(
important: true,
});
AccountButton.loading(false);
return;
return null;
}

if (!ConnectionState.get()) {
Expand All @@ -1258,7 +1221,7 @@ async function saveResult(
if (!isRetrying) {
retrySaving.completedEvent = completedEvent;
}
return;
return null;
}

const response = await Ape.results.add({ body: { result: completedEvent } });
Expand Down Expand Up @@ -1286,7 +1249,7 @@ async function saveResult(
"Looks like your result data is using an incorrect schema. Please refresh the page to download the new update. If the problem persists, please contact support.";
}
Notifications.add("Failed to save result", -1, { response });
return;
return response;
}

const data = response.body.data;
Expand Down Expand Up @@ -1327,8 +1290,6 @@ async function saveResult(
dataToSave.result = result;
}

void AnalyticsController.log("testCompleted");

if (data.isPb !== undefined && data.isPb) {
//new pb
const localPb = await DB.getLocalPB(
Expand Down Expand Up @@ -1377,6 +1338,7 @@ async function saveResult(
Notifications.add("Result saved", 1, { important: true });
}
DB.saveLocalResult(dataToSave);
return response;
}

export function fail(reason: string): void {
Expand Down
Loading