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)
This commit is contained in:
Miodec 2024-08-05 14:28:31 +02:00
parent ddebf57454
commit 7306cf8a9f
4 changed files with 227 additions and 14 deletions

View file

@ -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>

View file

@ -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;

View file

@ -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");
}

View file

@ -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
},
});