aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMiodec <[email protected]>2024-08-05 14:28:31 +0200
committerMiodec <[email protected]>2024-08-05 14:28:31 +0200
commit7306cf8a9fc74a942385b0e4ad6f92a6c77ef889 (patch)
treebbe26f8a4a13f1789c2d6ab8f39941a2656fcd8d
parentddebf57454b5bfe1270d0af2c3a0c20c39b64487 (diff)
downloadmonkeytype-7306cf8a9fc74a942385b0e4ad6f92a6c77ef889.tar.gz
monkeytype-7306cf8a9fc74a942385b0e4ad6f92a6c77ef889.zip
feat: last signed out result modal
the website will now show the last signed out result and ask the user if they want to save or discard it (instead of always saving)
-rw-r--r--frontend/src/html/popups.html38
-rw-r--r--frontend/src/styles/popups.scss39
-rw-r--r--frontend/src/ts/controllers/account-controller.ts17
-rw-r--r--frontend/src/ts/modals/last-signed-out-result.ts147
4 files changed, 227 insertions, 14 deletions
diff --git a/frontend/src/html/popups.html b/frontend/src/html/popups.html
index 0622dffb8..e5dabb7a7 100644
--- a/frontend/src/html/popups.html
+++ b/frontend/src/html/popups.html
@@ -4,6 +4,44 @@
</div>
</dialog>
+<dialog id="lastSignedOutResult" class="modalWrapper hidden">
+ <div class="modal">
+ <div class="title">Last signed out result</div>
+ <div class="question">Would you like to save it?</div>
+ <div class="divider"></div>
+ <div class="result">
+ <div class="group wpm">
+ <div class="sub">wpm</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group acc">
+ <div class="sub">accuracy</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group raw">
+ <div class="sub">raw</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group con">
+ <div class="sub">consistency</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group chardata">
+ <div class="sub">characters</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group testType">
+ <div class="sub">test type</div>
+ <div class="val">-</div>
+ </div>
+ </div>
+ <div class="buttons">
+ <button class="save">save</button>
+ <button class="discard">discard</button>
+ </div>
+ </div>
+</dialog>
+
<dialog id="devOptionsModal" class="modalWrapper hidden">
<div class="modal">
<div class="title">Dev options</div>
diff --git a/frontend/src/styles/popups.scss b/frontend/src/styles/popups.scss
index 734d15b7f..1c9d4848f 100644
--- a/frontend/src/styles/popups.scss
+++ b/frontend/src/styles/popups.scss
@@ -635,6 +635,45 @@ body.darkMode {
}
}
+#lastSignedOutResult {
+ .modal {
+ max-width: 600px;
+
+ .buttons {
+ display: flex;
+ flex-direction: row-reverse;
+ gap: 0.5rem;
+ button {
+ flex-grow: 1;
+ }
+ }
+ .result {
+ display: grid;
+ gap: 0.5rem;
+ grid-template-columns: 1fr 1fr;
+ }
+ .divider {
+ background: var(--sub-alt-color);
+ width: 100%;
+ height: 0.25rem;
+ border-radius: var(--roundness);
+ }
+ .group {
+ .sub {
+ font-size: 0.75em;
+ color: var(--sub-color);
+ }
+ &.testType {
+ grid-column: 1;
+ }
+ &.wpm,
+ &.acc {
+ font-size: 2em;
+ }
+ }
+ }
+}
+
#devOptionsModal {
.modal {
max-width: 400px;
diff --git a/frontend/src/ts/controllers/account-controller.ts b/frontend/src/ts/controllers/account-controller.ts
index 44c3c2326..89c6794d0 100644
--- a/frontend/src/ts/controllers/account-controller.ts
+++ b/frontend/src/ts/controllers/account-controller.ts
@@ -15,6 +15,7 @@ import * as LoginPage from "../pages/login";
import * as ResultFilters from "../elements/account/result-filters";
import * as TagController from "./tag-controller";
import * as RegisterCaptchaModal from "../modals/register-captcha";
+import * as LastSignedOutResultModal from "../modals/last-signed-out-result";
import * as URLHandler from "../utils/url-handler";
import * as Account from "../pages/account";
import * as Alerts from "../elements/alerts";
@@ -45,8 +46,6 @@ import * as ConnectionState from "../states/connection";
import { navigate } from "./route-controller";
import { getHtmlByUserFlags } from "./user-flag-controller";
-let signedOutThisSession = false;
-
export const gmailProvider = new GoogleAuthProvider();
export const githubProvider = new GithubAuthProvider();
@@ -209,18 +208,9 @@ export async function loadUser(user: UserType): Promise<void> {
// showFavouriteThemesAtTheTop();
- if (TestLogic.notSignedInLastResult !== null && !signedOutThisSession) {
+ if (TestLogic.notSignedInLastResult !== null) {
TestLogic.setNotSignedInUid(user.uid);
-
- const response = await Ape.results.save(TestLogic.notSignedInLastResult);
-
- if (response.status !== 200) {
- Notifications.add("Failed to save last result: " + response.message, -1);
- return;
- }
-
- TestLogic.clearNotSignedInResult();
- Notifications.add("Last test result saved", 1);
+ LastSignedOutResultModal.show();
}
}
@@ -647,7 +637,6 @@ $("header .signInOut").on("click", () => {
}
if (isAuthenticated()) {
signOut();
- signedOutThisSession = true;
} else {
navigate("/login");
}
diff --git a/frontend/src/ts/modals/last-signed-out-result.ts b/frontend/src/ts/modals/last-signed-out-result.ts
new file mode 100644
index 000000000..fe399323e
--- /dev/null
+++ b/frontend/src/ts/modals/last-signed-out-result.ts
@@ -0,0 +1,147 @@
+import AnimatedModal from "../utils/animated-modal";
+import Ape from "../ape";
+import * as TestLogic from "../test/test-logic";
+import * as Notifications from "../elements/notifications";
+import { CompletedEvent } from "@monkeytype/shared-types";
+
+function reset(): void {
+ (modal.getModal().querySelector(".result") as HTMLElement).innerHTML = `
+ <div class="group wpm">
+ <div class="sub">wpm</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group acc">
+ <div class="sub">accuracy</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group raw">
+ <div class="sub">raw</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group con">
+ <div class="sub">consistency</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group chardata">
+ <div class="sub">characters</div>
+ <div class="val">-</div>
+ </div>
+ <div class="group testType">
+ <div class="sub">test type</div>
+ <div class="val">-</div>
+ </div>`;
+}
+
+function fillData(): void {
+ //safe because we check if it exists before showing the modal
+ const r = TestLogic.notSignedInLastResult as CompletedEvent;
+
+ // const r: CompletedEvent = {
+ // wpm: 100,
+ // acc: 100,
+ // rawWpm: 100,
+ // consistency: 100,
+ // mode: "time",
+ // mode2: "60",
+ // numbers: true,
+ // punctuation: true,
+ // difficulty: "master",
+ // language: "english",
+ // blindMode: true,
+ // lazyMode: true,
+ // funbox: "read_ahead",
+ // tags: ["asdf", "sdfsdf"],
+ // charStats: [10, 10, 10, 10],
+ // };
+
+ fillGroup("wpm", r.wpm);
+ fillGroup("acc", r.acc + "%");
+ fillGroup("raw", r.rawWpm);
+ fillGroup("con", r.consistency + "%");
+ fillGroup("chardata", r.charStats.join("/"));
+
+ let tt = r.mode + " " + r.mode2;
+
+ tt += "<br>" + r.language;
+
+ if (r.numbers) tt += "<br>numbers";
+ if (r.punctuation) tt += "<br>punctuation";
+ if (r.blindMode) tt += "<br>blind";
+ if (r.lazyMode) tt += "<br>lazy";
+ if (r.funbox !== "none") {
+ tt += "<br>" + r.funbox.replace(/_/g, " ").replace(/#/g, ", ");
+ }
+ if (r.difficulty !== "normal") tt += "<br>" + r.difficulty;
+ if (r.tags.length > 0) tt += "<br>" + r.tags.length + " tags";
+
+ fillGroup("testType", tt, true);
+}
+
+function fillGroup(
+ groupClass: string,
+ text: string | number,
+ html = false
+): void {
+ if (html) {
+ $(modal.getModal()).find(`.group.${groupClass} .val`).html(`${text}`);
+ } else {
+ $(modal.getModal()).find(`.group.${groupClass} .val`).text(text);
+ }
+}
+
+export function show(): void {
+ if (!TestLogic.notSignedInLastResult) {
+ Notifications.add(
+ "Failed to show last signed out result modal: no last result",
+ -1
+ );
+ return;
+ }
+ reset();
+ void modal.show({
+ beforeAnimation: async (): Promise<void> => {
+ fillData();
+ },
+ });
+}
+
+function hide(): void {
+ void modal.hide();
+}
+
+async function saveLastResult(): Promise<void> {
+ //safe because we check if it exists before showing the modal
+ const response = await Ape.results.save(
+ TestLogic.notSignedInLastResult as CompletedEvent
+ );
+ if (response.status !== 200) {
+ Notifications.add("Failed to save last result: " + response.message, -1);
+ return;
+ }
+
+ TestLogic.clearNotSignedInResult();
+ Notifications.add(
+ `Last test result saved ${response.data?.isPb ? `(new pb!)` : ""}`,
+ 1
+ );
+}
+
+const modal = new AnimatedModal({
+ dialogId: "lastSignedOutResult",
+ setup: async (modalEl): Promise<void> => {
+ modalEl
+ .querySelector("button.save")
+ ?.addEventListener("click", async (e) => {
+ void saveLastResult();
+ hide();
+ });
+ modalEl.querySelector("button.discard")?.addEventListener("click", (e) => {
+ TestLogic.clearNotSignedInResult();
+ Notifications.add("Last test result discarded", 0);
+ hide();
+ });
+ },
+ customWrapperClickHandler: (): void => {
+ //do nothing
+ },
+});