diff --git a/frontend/src/ts/collections/quote-ratings.ts b/frontend/src/ts/collections/quote-ratings.ts new file mode 100644 index 000000000000..d7c6a6a96534 --- /dev/null +++ b/frontend/src/ts/collections/quote-ratings.ts @@ -0,0 +1,134 @@ +import { Language } from "@monkeytype/schemas/languages"; +import { QuoteRating } from "@monkeytype/schemas/quotes"; +import { + parseLoadSubsetOptions, + queryCollectionOptions, +} from "@tanstack/query-db-collection"; +import { createCollection, eq, useLiveQuery } from "@tanstack/solid-db"; +import { Accessor } from "solid-js"; +import { queryClient } from "../queries"; +import { baseKey } from "../queries/utils/keys"; +import Ape from "../ape"; +import { getSnapshot } from "../states/snapshot"; + +type QuoteUserRating = QuoteRating & { + userRating?: number; +}; + +const queryKeys = { + root: () => [...baseKey("quoteRatings", { isUserSpecific: true })], +}; + +export const quoteRatingsCollection = createCollection( + queryCollectionOptions({ + staleTime: Infinity, + queryKey: queryKeys.root(), + syncMode: "on-demand", // Enable predicate push-down + queryFn: async ({ meta }) => { + if (meta?.loadSubsetOptions === undefined) { + throw new Error("missing where clause in quoteRatingsCollection"); + } + const { where } = meta.loadSubsetOptions; + const parsed = parseLoadSubsetOptions({ where }); + + const language = parsed.filters.find((it) => it.field?.[0] === "language") + ?.value as Language; + const quoteId = parsed.filters.find((it) => it.field?.[0] === "quoteId") + ?.value as number; + + const response = await Ape.quotes.getRating({ + query: { language, quoteId }, + }); + if (response.status !== 200) { + throw new Error( + "Error fetching quote ratings:" + response.body.message, + ); + } + + const userRating = getSnapshot()?.quoteRatings?.[language]?.[quoteId]; + + const existingData: QuoteUserRating[] = + queryClient.getQueryData(queryKeys.root()) ?? []; + + if (response.body.data !== null) { + existingData.push({ ...response.body.data, userRating }); + } + + return existingData; + }, + onInsert: async ({ transaction }) => { + const newItems = transaction.mutations.map((it) => it.modified); + + quoteRatingsCollection.utils.writeBatch(() => { + newItems.forEach((item) => { + quoteRatingsCollection.utils.writeInsert(item); + }); + }); + + newItems.forEach(async (it) => { + if (it.userRating !== undefined) { + const response = await Ape.quotes.addRating({ + body: { + language: it.language, + quoteId: it.quoteId, + rating: it.userRating, + }, + }); + if (response.status !== 200) { + throw new Error( + "Cannot submit quote rating: " + response.body.message, + ); + } + } + }); + }, + onUpdate: async ({ transaction }) => { + const newItems = transaction.mutations.map((it) => it.modified); + + //TODO update rating average and total + quoteRatingsCollection.utils.writeBatch(() => { + newItems.forEach((item) => { + quoteRatingsCollection.utils.writeUpdate(item); + }); + }); + + newItems.forEach(async (it) => { + if (it.userRating !== undefined) { + const response = await Ape.quotes.addRating({ + body: { + language: it.language, + quoteId: it.quoteId, + rating: it.userRating, + }, + }); + if (response.status !== 200) { + throw new Error( + "Cannot submit quote rating: " + response.body.message, + ); + } + } + }); + }, + + queryClient, + getKey: (it) => it._id, + }), +); + +// oxlint-disable-next-line typescript/explicit-function-return-type +export function useQuoteRatingsLiveQuery( + filterAccessor: Accessor<{ + language: Language; + id: number; + } | null>, +) { + return useLiveQuery((q) => { + const filter = filterAccessor(); + if (filter === null) return undefined; + return q + .from({ r: quoteRatingsCollection }) + .where(({ r }) => eq(r.language, filter.language)) + .where(({ r }) => eq(r.quoteId, filter.id)) + .findOne(); + }); +} diff --git a/frontend/src/ts/commandline/lists/quote-favorites.ts b/frontend/src/ts/commandline/lists/quote-favorites.ts index ecfe6bf8876b..e4b24ca94b47 100644 --- a/frontend/src/ts/commandline/lists/quote-favorites.ts +++ b/frontend/src/ts/commandline/lists/quote-favorites.ts @@ -6,8 +6,8 @@ import { } from "../../states/notifications"; import { isAuthenticated } from "../../firebase"; import { showLoaderBar, hideLoaderBar } from "../../states/loader-bar"; -import * as TestWords from "../../test/test-words"; import { Command } from "../types"; +import { getCurrentQuote } from "../../states/test"; const commands: Command[] = [ { @@ -15,7 +15,7 @@ const commands: Command[] = [ display: "Add current quote to favorite", icon: "fa-heart", available: (): boolean => { - const quote = TestWords.currentQuote; + const quote = getCurrentQuote(); return ( isAuthenticated() && quote !== null && @@ -27,7 +27,7 @@ const commands: Command[] = [ try { showLoaderBar(); await QuotesController.setQuoteFavorite( - TestWords.currentQuote as Quote, + getCurrentQuote() as Quote, true, ); hideLoaderBar(); @@ -43,7 +43,7 @@ const commands: Command[] = [ display: "Remove current quote from favorite", icon: "fa-heart-broken", available: (): boolean => { - const quote = TestWords.currentQuote; + const quote = getCurrentQuote(); return ( isAuthenticated() && quote !== null && @@ -55,7 +55,7 @@ const commands: Command[] = [ try { showLoaderBar(); await QuotesController.setQuoteFavorite( - TestWords.currentQuote as Quote, + getCurrentQuote() as Quote, false, ); hideLoaderBar(); diff --git a/frontend/src/ts/components/core/DevTools.tsx b/frontend/src/ts/components/core/DevTools.tsx index 85eb49e91b86..9ccfc4b3de54 100644 --- a/frontend/src/ts/components/core/DevTools.tsx +++ b/frontend/src/ts/components/core/DevTools.tsx @@ -19,7 +19,7 @@ if (import.meta.env.DEV) { default: () => { onMount(() => { m.attachDevtoolsOverlay({ - defaultOpen: true, + defaultOpen: false, noPadding: true, }); }); diff --git a/frontend/src/ts/components/layout/footer/Footer.tsx b/frontend/src/ts/components/layout/footer/Footer.tsx index 12b2f0265924..b71918c160f6 100644 --- a/frontend/src/ts/components/layout/footer/Footer.tsx +++ b/frontend/src/ts/components/layout/footer/Footer.tsx @@ -1,8 +1,11 @@ import { JSXElement } from "solid-js"; +import { useQuoteRatingsLiveQuery } from "../../../collections/quote-ratings"; import { getFocus, getIsScreenshotting } from "../../../states/core"; import { showModal } from "../../../states/modals"; +import { getCurrentQuote } from "../../../states/test"; import { cn } from "../../../utils/cn"; +import AsyncContent from "../../common/AsyncContent"; import { Button } from "../../common/Button"; import { Keytips } from "./Keytips"; import { ThemeIndicator } from "./ThemeIndicator"; diff --git a/frontend/src/ts/components/layout/overlays/LoaderBar.tsx b/frontend/src/ts/components/layout/overlays/LoaderBar.tsx index 887453a83dc4..8efca540a763 100644 --- a/frontend/src/ts/components/layout/overlays/LoaderBar.tsx +++ b/frontend/src/ts/components/layout/overlays/LoaderBar.tsx @@ -2,6 +2,7 @@ import { JSX } from "solid-js"; import { useRefWithUtils } from "../../../hooks/useRefWithUtils"; import { useVisibilityAnimation } from "../../../hooks/useVisibilityAnimation"; +import { queryClient } from "../../../queries"; import { getLoaderBarSignal } from "../../../states/loader-bar"; import { applyReducedMotion } from "../../../utils/misc"; @@ -10,7 +11,8 @@ export function LoaderBar(): JSX.Element { useVisibilityAnimation({ element: loaderEl, - isVisible: () => getLoaderBarSignal()?.visible === true, + isVisible: () => + getLoaderBarSignal()?.visible === true || queryClient.isFetching() > 0, showAnimationOptions: { delay: applyReducedMotion(getLoaderBarSignal()?.instant ? 0 : 125), }, diff --git a/frontend/src/ts/components/modals/QuoteRateModal.tsx b/frontend/src/ts/components/modals/QuoteRateModal.tsx index 2e79b636f5f0..75fe24ea2929 100644 --- a/frontend/src/ts/components/modals/QuoteRateModal.tsx +++ b/frontend/src/ts/components/modals/QuoteRateModal.tsx @@ -1,7 +1,12 @@ +import { Language } from "@monkeytype/schemas/languages"; import { isSafeNumber } from "@monkeytype/util/numbers"; -import { JSXElement, createSignal, For } from "solid-js"; +import { JSXElement, createSignal, For, Accessor } from "solid-js"; import Ape from "../../ape"; +import { + quoteRatingsCollection, + useQuoteRatingsLiveQuery, +} from "../../collections/quote-ratings"; import * as DB from "../../db"; import { hideLoaderBar, showLoaderBar } from "../../states/loader-bar"; import { hideModalAndClearChain } from "../../states/modals"; @@ -13,48 +18,63 @@ import { import { currentQuote, quoteStats, - getQuoteStats, updateQuoteStats, getRatingAverage, } from "../../states/quote-rate"; +import { getCurrentQuote } from "../../states/test"; import { cn } from "../../utils/cn"; import { qs } from "../../utils/dom"; import { AnimatedModal } from "../common/AnimatedModal"; +import AsyncContent from "../common/AsyncContent"; import { Button } from "../common/Button"; import { Fa } from "../common/Fa"; import { Separator } from "../common/Separator"; export function QuoteRateModal(): JSXElement { - const [rating, setRating] = createSignal(0); - const [hoverRating, setHoverRating] = createSignal(0); + const quoteRatingQuery = useQuoteRatingsLiveQuery(getCurrentQuote); + const [rating, setRating] = createSignal(0); - const getLengthDesc = (): string => { - const quote = currentQuote(); - if (!quote) return "-"; - if (quote.group === 0) return "short"; - if (quote.group === 1) return "medium"; - if (quote.group === 2) return "long"; - if (quote.group === 3) return "thicc"; + const getLengthDesc = (group: number | undefined): string => { + if (group === undefined) return "-"; + if (group === 0) return "short"; + if (group === 1) return "medium"; + if (group === 2) return "long"; + if (group === 3) return "thicc"; return "-"; }; - const displayRating = (): number => hoverRating() || rating(); - const handleBeforeShow = (): void => { const quote = currentQuote(); if (!quote) return; setRating(0); - setHoverRating(0); - const snapshot = DB.getSnapshot(); - const alreadyRated = snapshot?.quoteRatings?.[quote.language]?.[quote.id]; - if (isSafeNumber(alreadyRated)) { - setRating(alreadyRated); + }; + + const submit2 = (options: { + _id: string | undefined; + language: Language; + quoteId: number; + userRating: number; + }): void => { + if (options._id === undefined) { + quoteRatingsCollection.insert({ + _id: "pending", //TODO upddate after insert + quoteId: options.quoteId, + language: options.language, + userRating: options.userRating, + totalRating: options.userRating, + average: options.userRating, + ratings: 1, + }); + } else { + quoteRatingsCollection.update( + options._id, + (old) => (old.userRating = options.userRating), + ); } - void getQuoteStats(quote); }; const submit = async (): Promise => { - if (rating() === 0) { + if (rating() === null) { showNoticeNotification("Please select a rating"); return; } @@ -134,77 +154,110 @@ export function QuoteRateModal(): JSXElement { beforeShow={handleBeforeShow} modalClass="max-w-[800px] overflow-visible" > -
- If you find a grammatical error or the quote has inappropriate language - - don{"'"}t give it a low rating! Please - report it instead. You can do so by closing this popup and clicking the{" "} - flag icon. -
- -
-
- {currentQuote()?.text ?? "-"} -
-
-
-
id
- {currentQuote()?.id ?? "-"} -
-
-
length
- {getLengthDesc()} -
-
-
source
- {currentQuote()?.source ?? "-"} -
-
-
- -
-
-
-
ratings
-
- {quoteStats()?.ratings?.toString() ?? "0"} + + {(quoteRating) => ( + <> +
+ If you find a grammatical error or the quote has inappropriate + language -{" "} + don{"'"}t give it a low rating!{" "} + Please report it instead. You can do so by closing this popup and + clicking the flag icon.
-
-
-
average
-
- {quoteStats()?.average?.toFixed(1) ?? "-"} + +
+
+ {currentQuote()?.text ?? "-"} +
+
+
+
id
+ {currentQuote()?.id ?? "-"} +
+
+
length
+ {getLengthDesc(currentQuote()?.group)} +
+
+
source
+ {currentQuote()?.source ?? "-"} +
+
-
-
-
your rating
-
- - {(star) => ( -
-
-
+ + )} + + + ); +} + +function Rating(props: { + currentRating: Accessor; + onChange: (newRating: number) => void; +}): JSXElement { + const [hoverRating, setHoverRating] = createSignal(0); + const displayRating = (): number => hoverRating() || props.currentRating(); + + return ( + + {(star) => (
- + )} + ); } diff --git a/frontend/src/ts/elements/last-10-average.ts b/frontend/src/ts/elements/last-10-average.ts index df296a69afdd..bf8c69190464 100644 --- a/frontend/src/ts/elements/last-10-average.ts +++ b/frontend/src/ts/elements/last-10-average.ts @@ -2,13 +2,13 @@ import * as DB from "../db"; import * as Misc from "../utils/misc"; import * as Numbers from "@monkeytype/util/numbers"; import { Config } from "../config/store"; -import * as TestWords from "../test/test-words"; +import { getCurrentQuote } from "../states/test"; let averageWPM = 0; let averageAcc = 0; export async function update(): Promise { - const mode2 = Misc.getMode2(Config, TestWords.currentQuote); + const mode2 = Misc.getMode2(Config, getCurrentQuote()); const [wpm, acc] = ( await DB.getUserAverage10( diff --git a/frontend/src/ts/elements/modes-notice.ts b/frontend/src/ts/elements/modes-notice.ts index 01dd9c152656..4b0b275d8a0f 100644 --- a/frontend/src/ts/elements/modes-notice.ts +++ b/frontend/src/ts/elements/modes-notice.ts @@ -12,7 +12,7 @@ import Format from "../singletons/format"; import { getActiveFunboxes, getActiveFunboxNames } from "../test/funbox/list"; import { escapeHTML, getMode2 } from "../utils/misc"; import { qsr } from "../utils/dom"; -import { getLoadedChallenge } from "../states/test"; +import { getCurrentQuote, getLoadedChallenge } from "../states/test"; configEvent.subscribe(({ key }) => { const configKeys: ConfigEventKey[] = [ @@ -202,7 +202,7 @@ export async function update(): Promise { if (!isAuthenticated()) { return; } - const mode2 = getMode2(Config, TestWords.currentQuote); + const mode2 = getMode2(Config, getCurrentQuote()); const pb = await DB.getLocalPB( Config.mode, mode2, diff --git a/frontend/src/ts/event-handlers/test.ts b/frontend/src/ts/event-handlers/test.ts index 108db58ee09c..0044152e3a8e 100644 --- a/frontend/src/ts/event-handlers/test.ts +++ b/frontend/src/ts/event-handlers/test.ts @@ -5,7 +5,6 @@ import * as DB from "../db"; import * as EditResultTagsModal from "../modals/edit-result-tags"; import * as MobileTestConfigModal from "../modals/mobile-test-config"; import * as CustomTestDurationModal from "../modals/custom-test-duration"; -import * as TestWords from "../test/test-words"; import { showNoticeNotification, showErrorNotification, @@ -20,6 +19,7 @@ import { ConfigKey } from "@monkeytype/schemas/configs"; import { ListsObjectKeys } from "../commandline/lists"; import { qs } from "../utils/dom"; import { showModal } from "../states/modals"; +import { getCurrentQuote } from "../states/test"; const testPage = qs(".pageTest"); @@ -76,19 +76,21 @@ testPage?.onChild("click", "#mobileTestConfigButton", () => { }); qs(".pageTest #rateQuoteButton")?.on("click", async () => { - if (TestWords.currentQuote === null) { + const currentQuote = getCurrentQuote(); + if (currentQuote === null) { showErrorNotification("Failed to show quote rating popup: no quote"); return; } - showQuoteRateModal(TestWords.currentQuote); + showQuoteRateModal(currentQuote); }); qs(".pageTest #reportQuoteButton")?.on("click", async () => { - if (TestWords.currentQuote === null) { + const currentQuote = getCurrentQuote(); + if (currentQuote === null) { showErrorNotification("Failed to show quote report popup: no quote"); return; } - showQuoteReportModal(TestWords.currentQuote?.id); + showQuoteReportModal(currentQuote?.id); }); testPage?.onChild("click", "#testConfig .quoteLength .textButton", (event) => { diff --git a/frontend/src/ts/modals/share-test-settings.ts b/frontend/src/ts/modals/share-test-settings.ts index 86d3324a9ca4..3ea33c58d722 100644 --- a/frontend/src/ts/modals/share-test-settings.ts +++ b/frontend/src/ts/modals/share-test-settings.ts @@ -1,5 +1,4 @@ import { Config } from "../config/store"; -import { currentQuote } from "../test/test-words"; import { getMode2 } from "../utils/misc"; import * as CustomText from "../test/custom-text"; import { compressToURI } from "lz-ts"; @@ -8,6 +7,7 @@ import { Difficulty, FunboxName } from "@monkeytype/schemas/configs"; import { Mode, Mode2 } from "@monkeytype/schemas/shared"; import { ElementWithUtils } from "../utils/dom"; import { CustomTextSettings } from "@monkeytype/schemas/results"; +import { getCurrentQuote } from "../states/test"; function getCheckboxValue(checkbox: string): boolean { return modal @@ -35,7 +35,7 @@ function updateURL(): void { const settingsMap = [ { key: "mode", getValue: () => Config.mode }, - { key: "mode2", getValue: () => getMode2(Config, currentQuote) }, + { key: "mode2", getValue: () => getMode2(Config, getCurrentQuote()) }, { key: "customText", getValue: () => CustomText.getData() }, { key: "punctuation", getValue: () => Config.punctuation }, { key: "numbers", getValue: () => Config.numbers }, diff --git a/frontend/src/ts/states/test.ts b/frontend/src/ts/states/test.ts index 1edc2ac0b853..ad92146f8441 100644 --- a/frontend/src/ts/states/test.ts +++ b/frontend/src/ts/states/test.ts @@ -1,5 +1,9 @@ import { Challenge } from "@monkeytype/schemas/challenges"; import { createSignal } from "solid-js"; +import { QuoteWithTextSplit } from "../controllers/quotes-controller"; export const [getLoadedChallenge, setLoadedChallenge] = createSignal(null); + +export const [getCurrentQuote, setCurrentQuote] = + createSignal(null); diff --git a/frontend/src/ts/test/pace-caret.ts b/frontend/src/ts/test/pace-caret.ts index d934c71c0264..b6ad81437886 100644 --- a/frontend/src/ts/test/pace-caret.ts +++ b/frontend/src/ts/test/pace-caret.ts @@ -7,6 +7,7 @@ import { configEvent } from "../events/config"; import { getActiveFunboxes } from "./funbox/list"; import { Caret } from "../elements/caret"; import { qsr } from "../utils/dom"; +import { getCurrentQuote } from "../states/test"; type Settings = { wpm: number; @@ -55,7 +56,7 @@ export function resetCaretPosition(): void { export async function init(): Promise { caret.hide(); - const mode2 = Misc.getMode2(Config, TestWords.currentQuote); + const mode2 = Misc.getMode2(Config, getCurrentQuote()); let wpm = 0; if (Config.paceCaret === "pb") { wpm = diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts index bf43b7f27262..bfc1a257772f 100644 --- a/frontend/src/ts/test/result.ts +++ b/frontend/src/ts/test/result.ts @@ -54,9 +54,9 @@ import { z } from "zod"; import * as TestState from "./test-state"; import { blurInputElement } from "../input/input-element"; import * as ConnectionState from "../legacy-states/connection"; -import { currentQuote } from "./test-words"; import { qs, qsa } from "../utils/dom"; import { getTheme } from "../states/theme"; +import { getCurrentQuote } from "../states/test"; let result: CompletedEvent; let minChartVal: number; @@ -1058,7 +1058,7 @@ export async function update( qs("main #result #rateQuoteButton")?.hide(); qs("main #result #reportQuoteButton")?.hide(); } else { - updateRateQuote(currentQuote); + updateRateQuote(getCurrentQuote()); qs("main #result #reportQuoteButton")?.show(); } qs("main #result .stats .dailyLeaderboard")?.hide(); diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 3ac6d4394b51..6807bf56118c 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -72,6 +72,7 @@ import { qs } from "../utils/dom"; import { setAccountButtonSpinner } from "../states/header"; import { Config } from "../config/store"; import { setQuoteLengthAll, toggleFunbox, setConfig } from "../config/setters"; +import { getCurrentQuote } from "../states/test"; let failReason = ""; export async function syncNotSignedInLastResult(uid: string): Promise { @@ -251,10 +252,11 @@ export function restart(options = {} as RestartOptions): void { } } + const currentQuote = getCurrentQuote(); if ( Config.mode === "quote" && - TestWords.currentQuote !== null && - Config.language.startsWith(TestWords.currentQuote.language) && + currentQuote !== null && + Config.language.startsWith(currentQuote.language) && Config.repeatQuotes === "typing" && (TestState.isActive || failReason !== "") ) { @@ -502,7 +504,7 @@ async function init(): Promise { mode: Config.mode, mode2: Misc.getMode2(Config, null), funbox: Config.funbox, - currentQuote: TestWords.currentQuote, + currentQuote: getCurrentQuote(), }); let wordsHaveTab = false; @@ -607,8 +609,7 @@ export function areAllTestWordsGenerated(): boolean { TestWords.words.length >= CustomText.getLimitValue() && CustomText.getLimitValue() !== 0) || (Config.mode === "quote" && - TestWords.words.length >= - (TestWords.currentQuote?.textSplit?.length ?? 0)) || + TestWords.words.length >= (getCurrentQuote()?.textSplit?.length ?? 0)) || (Config.mode === "custom" && CustomText.getLimitMode() === "section" && WordsGenerator.sectionIndex >= CustomText.getLimitValue() && @@ -817,7 +818,7 @@ function buildCompletedEvent( language = Strings.removeLanguageSize(Config.language); } - const quoteLength = TestWords.currentQuote?.group ?? -1; + const quoteLength = getCurrentQuote()?.group ?? -1; const completedEvent: Omit = { wpm: stats.wpm, @@ -831,7 +832,7 @@ function buildCompletedEvent( charTotal: stats.allChars, acc: stats.acc, mode: Config.mode, - mode2: Misc.getMode2(Config, TestWords.currentQuote), + mode2: Misc.getMode2(Config, getCurrentQuote()), quoteLength: quoteLength, punctuation: Config.punctuation, numbers: Config.numbers, @@ -1204,7 +1205,7 @@ export async function finish(difficultyFailed = false): Promise { afkDetected, TestState.isRepeated, tooShort, - TestWords.currentQuote, + getCurrentQuote(), dontSave, ); diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index 5bd1f63d7463..03e4612d3ba8 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -69,6 +69,7 @@ import { } from "../utils/dom"; import { getTheme } from "../states/theme"; import { skipBreakdownEvent } from "../states/header"; +import { getCurrentQuote } from "../states/test"; export const updateHintsPositionDebounced = Misc.debounceUntilResolved( updateHintsPosition, @@ -1136,7 +1137,7 @@ export async function scrollTape(noAnimation = false): Promise { } export function updatePremid(): void { - const mode2 = Misc.getMode2(Config, TestWords.currentQuote); + const mode2 = Misc.getMode2(Config, getCurrentQuote()); let fbtext = ""; if (Config.funbox.length > 0) { fbtext = " " + Config.funbox.join(" "); diff --git a/frontend/src/ts/test/test-words.ts b/frontend/src/ts/test/test-words.ts index 4b87130c9ea5..4f4112d4b246 100644 --- a/frontend/src/ts/test/test-words.ts +++ b/frontend/src/ts/test/test-words.ts @@ -1,4 +1,3 @@ -import { QuoteWithTextSplit } from "../controllers/quotes-controller"; import * as TestState from "./test-state"; class Words { @@ -60,11 +59,6 @@ export const words = new Words(); export let hasTab = false; export let hasNewline = false; export let hasNumbers = false; -export let currentQuote = null as QuoteWithTextSplit | null; - -export function setCurrentQuote(rq: QuoteWithTextSplit | null): void { - currentQuote = rq; -} export function setHasTab(tf: boolean): void { hasTab = tf; diff --git a/frontend/src/ts/test/timer-progress.ts b/frontend/src/ts/test/timer-progress.ts index e83d8754ebda..32f01f4c64c5 100644 --- a/frontend/src/ts/test/timer-progress.ts +++ b/frontend/src/ts/test/timer-progress.ts @@ -9,6 +9,7 @@ import { configEvent } from "../events/config"; import { applyReducedMotion } from "../utils/misc"; import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame"; import { animate } from "animejs"; +import { getCurrentQuote } from "../states/test"; const barEl = document.querySelector("#barTimerProgress .bar") as HTMLElement; const barOpacityEl = document.querySelector( @@ -206,7 +207,7 @@ export function update(): void { outof = CustomText.getLimitValue(); } if (Config.mode === "quote") { - outof = TestWords.currentQuote?.textSplit.length ?? 1; + outof = getCurrentQuote()?.textSplit.length ?? 1; } if (Config.timerStyle === "bar") { const percent = Math.floor( diff --git a/frontend/src/ts/test/words-generator.ts b/frontend/src/ts/test/words-generator.ts index 4302df510bfe..17c0e335ca21 100644 --- a/frontend/src/ts/test/words-generator.ts +++ b/frontend/src/ts/test/words-generator.ts @@ -6,7 +6,6 @@ import QuotesController, { Quote, QuoteWithTextSplit, } from "../controllers/quotes-controller"; -import * as TestWords from "./test-words"; import * as BritishEnglish from "./british-english"; import * as LazyMode from "./lazy-mode"; import * as EnglishPunctuation from "./english-punctuation"; @@ -28,6 +27,7 @@ import { WordGenError } from "../utils/word-gen-error"; import { showLoaderBar, hideLoaderBar } from "../states/loader-bar"; import { PolyglotWordset } from "./funbox/funbox-functions"; import { LanguageObject } from "@monkeytype/schemas/languages"; +import { getCurrentQuote, setCurrentQuote } from "../states/test"; //pin implementation const random = Math.random; @@ -377,8 +377,8 @@ async function applyBritishEnglishToWord( if (!Config.language.includes("english")) return word; if ( Config.mode === "quote" && - TestWords.currentQuote?.britishText !== undefined && - TestWords.currentQuote?.britishText !== "" + getCurrentQuote()?.britishText !== undefined && + getCurrentQuote()?.britishText !== "" ) { return word; } @@ -424,7 +424,7 @@ export function getLimit(): number { let limit = 100; - const currentQuote = TestWords.currentQuote; + const currentQuote = getCurrentQuote(); if (Config.mode === "quote" && currentQuote === null) { throw new WordGenError("Random quote is null"); @@ -503,7 +503,7 @@ async function getQuoteWordList( throw new WordGenError("Current wordset is null"); } - TestWords.setCurrentQuote(previousRandomQuote); + setCurrentQuote(previousRandomQuote); // need to re-reverse the words if the test is repeated // because it will be reversed again in the generateWords function @@ -579,17 +579,17 @@ async function getQuoteWordList( rq.textSplit = rq.text.split(" "); } - TestWords.setCurrentQuote(rq as QuoteWithTextSplit); + setCurrentQuote(rq as QuoteWithTextSplit); - if (TestWords.currentQuote === null) { + if (rq === null) { throw new WordGenError("Random quote is null"); } - if (TestWords.currentQuote.textSplit === undefined) { + if (rq.textSplit === undefined) { throw new WordGenError("Random quote textSplit is undefined"); } - return TestWords.currentQuote.textSplit; + return rq.textSplit; } let currentWordset: Wordset | null = null; @@ -613,8 +613,8 @@ export async function generateWords( if (!TestState.isRepeated) { previousGetNextWordReturns = []; } - previousRandomQuote = TestWords.currentQuote; - TestWords.setCurrentQuote(null); + previousRandomQuote = getCurrentQuote(); + setCurrentQuote(null); currentSection = []; sectionIndex = 0; sectionHistory = []; @@ -705,7 +705,7 @@ export async function generateWords( i++; } - const quote = TestWords.currentQuote; + const quote = getCurrentQuote(); if (Config.mode === "quote" && quote === null) { throw new WordGenError("Random quote is null");