From db6ba08c1af7af4b2595e1eef7c72e8abcfd4b91 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Tue, 21 Sep 2021 12:45:09 -0400 Subject: [PATCH] proper caching and sending of test results --- src/games/GameCore.tsx | 34 +++++++++++++++------ src/games/games.tsx | 49 ++++++++++++++---------------- src/games/sub-cores/GenderGame.tsx | 4 +-- src/lib/game-results.ts | 40 ++++++++++++++++++++++++ src/user-context.tsx | 4 +++ 5 files changed, 92 insertions(+), 39 deletions(-) create mode 100644 src/lib/game-results.ts diff --git a/src/games/GameCore.tsx b/src/games/GameCore.tsx index f95c278..aa85b14 100644 --- a/src/games/GameCore.tsx +++ b/src/games/GameCore.tsx @@ -7,10 +7,13 @@ import "./timer.css"; import { getPercentageDone, } from "../lib/game-utils"; +import { + saveResult, + postSavedResults, +} from "../lib/game-results"; import { AT, getTimestamp, - postTestResults, } from "@lingdocs/lingdocs-main"; import { Types as T, @@ -27,7 +30,7 @@ function GameCore({ questions, Display, timeLimit, Instructions, studyLink, i }) { // TODO: report pass with id to user info const rewardRef = useRef(null); - const { user, pullUser } = useUser(); + const { user, pullUser, setUser } = useUser(); const [finish, setFinish] = useState(null); const [current, setCurrent] = useState | undefined>(undefined); const [questionBox, setQuestionBox] = useState>(questions()); @@ -47,6 +50,24 @@ function GameCore({ questions, Display, timeLimit, Instructions, studyLink, i if (next.done) handleFinish(); else setCurrent(next.value); } + function handleResult(result: AT.TestResult) { + // add the test to the user object + if (!user) return; + setUser((u) => { + // pure type safety with the prevUser + if (!u) return u; + return { + ...u, + tests: [...u.tests, result], + }; + }); + // save the test result in local storage + saveResult(result, user.userId); + // try to post the result + postSavedResults(user.userId).then((r) => { + if (r === "sent") pullUser(); + }).catch(console.error); + } function handleFinish() { setFinish("pass"); rewardRef.current?.rewardMe(); @@ -56,14 +77,7 @@ function GameCore({ questions, Display, timeLimit, Instructions, studyLink, i time: getTimestamp(), id, }; - console.log("will post result", JSON.stringify(result)); - // TODO: Check not showing up - should show up immediately whether online or not - postTestResults([result]) - .then((res) => { - if (res.ok) { - pullUser(); - } - }).catch(console.error); + handleResult(result); } function handleQuit() { setFinish(null); diff --git a/src/games/games.tsx b/src/games/games.tsx index 48066ec..6c094c0 100644 --- a/src/games/games.tsx +++ b/src/games/games.tsx @@ -2,39 +2,34 @@ import React from "react"; import GenderGame from "./sub-cores/GenderGame"; import UnisexNounGame from "./sub-cores/UnisexNounGame"; -const unisexNounsId = "unisex-nouns-1"; -const nounGender1Id = "gender-nouns-1"; -const nounGender2Id = "gender-nouns-2"; - -export const unisexNounGame: GameRecord = { - title: "Changing genders on unisex nouns", - id: unisexNounsId, - Game: function() { - // TODO: Why won't this.id word here??! - return ; - }, +function makeGameRecord(title: string, id: string, game: (id: string) => (() => JSX.Element)): GameRecord { + return { + title, + id, + Game: game(id), + } } -export const nounGenderGame1: GameRecord = { - title: "Identify Noun Genders - Level 1", - id: nounGender1Id, - Game: function() { - return ; - }, -} - -export const nounGenderGame2: GameRecord = { - title: "Identify Noun Genders - Level 1", - id: nounGender2Id, - Game: function() { - return ; - }, -} +export const nounGenderGame1 = makeGameRecord( + "Identify Noun Genders - Level 1", + "gender-nouns-1", + (id) => () => , +); +export const nounGenderGame2 = makeGameRecord( + "Identify Noun Genders - Level 2", + "gender-nouns-2", + (id) => () => , +); +export const unisexNounGame = makeGameRecord( + "Changing genders on unisex nouns", + "unisex-nouns-1", + (id) => () => , +); const games: GameRecord[] = [ - unisexNounGame, nounGenderGame1, nounGenderGame2, + unisexNounGame, ]; export default games; diff --git a/src/games/sub-cores/GenderGame.tsx b/src/games/sub-cores/GenderGame.tsx index 6872414..fe8ff4d 100644 --- a/src/games/sub-cores/GenderGame.tsx +++ b/src/games/sub-cores/GenderGame.tsx @@ -48,7 +48,7 @@ const exceptions: Record = { } // consonantFem: words.filter((w) => w.category === "consonant-fem"), -const amount = 40; +const amount = 35; export default function({level, id}: { level: 1 | 2, id: string}) { function* questions () { @@ -105,7 +105,7 @@ export default function({level, id}: { level: 1 | 2, id: string}) { questions={questions} id={id} Display={Display} - timeLimit={level === 1 ? 65 : 85} + timeLimit={level === 1 ? 50 : 70} Instructions={Instructions} /> }; diff --git a/src/lib/game-results.ts b/src/lib/game-results.ts new file mode 100644 index 0000000..34c964c --- /dev/null +++ b/src/lib/game-results.ts @@ -0,0 +1,40 @@ +import { + AT, + postTestResults, +} from "@lingdocs/lingdocs-main"; + +const fullKey = (uid: AT.UUID) => `test-results-${uid}`; + +export async function postSavedResults(uid: AT.UUID): Promise<"sent" | "unsent" | "none"> { + const key = fullKey(uid); + const results = getSavedResults(key); + if (results.length === 0) return "none"; + // if the result posting was successful, delete the result from local storage + // and pull the user + try { + const res = await postTestResults(results) + if (res.ok) { + deleteTestResults(res.tests, key); + return "sent"; + } + } catch(e) { + console.error(e); + } + return "unsent"; +} + +export function saveResult(result: AT.TestResult, uid: AT.UUID) { + const key = fullKey(uid); + const results = getSavedResults(key); + localStorage.setItem(key, JSON.stringify([...results, result])); +} + +function getSavedResults(key: string): AT.TestResult[] { + return JSON.parse(localStorage.getItem(key) || "[]") as AT.TestResult[]; +} + +function deleteTestResults(results: AT.TestResult[], key: string) { + const r = getSavedResults(key); + const left = r.filter((rs) => !results.some(x => x.time === rs.time)); + localStorage.setItem(key, JSON.stringify(left)); +} \ No newline at end of file diff --git a/src/user-context.tsx b/src/user-context.tsx index 1012032..a9111d0 100644 --- a/src/user-context.tsx +++ b/src/user-context.tsx @@ -6,6 +6,7 @@ import { userObjIsEqual, } from "@lingdocs/lingdocs-main"; import { CronJob } from "cron"; +import { postSavedResults } from "./lib/game-results"; const UserContext = createContext< { @@ -35,6 +36,9 @@ function UserProvider({ children }: any) { const checkUserCronJob = new CronJob("1/30 * * * * *", () => { pullUser(); + if (value) { + postSavedResults(value.userId); + } }); useEffect(() => {