diff --git a/package.json b/package.json index a957a9c..127ae3b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lingdocs/pashto-inflector", - "version": "1.9.0", + "version": "1.9.1", "author": "lingdocs.com", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "homepage": "https://verbs.lingdocs.com", diff --git a/src/App.css b/src/App.css index d3f9d76..2b03d02 100644 --- a/src/App.css +++ b/src/App.css @@ -10,7 +10,21 @@ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; } - + +.answer-feedback { + transition: opacity 0.3s ease-in; + opacity: 0.8; + position: fixed; + top: 50%; + left: 50%; + z-index: 99999999; + transform: translate(-50%, -50%); +} + +.hide { + opacity: 0; +} + :root { --secondary: #00c1fc; --primary: #ffda54; diff --git a/src/components/vp-explorer/TensePicker.tsx b/src/components/vp-explorer/TensePicker.tsx index fa191a8..fa11cc6 100644 --- a/src/components/vp-explorer/TensePicker.tsx +++ b/src/components/vp-explorer/TensePicker.tsx @@ -68,10 +68,11 @@ export function getRandomTense(type: "basic" | "modal" | "perfect", o?: T.Perfec return tns; } -function TensePicker({ onChange, vps, mode }: { +function TensePicker({ onChange, vps, mode, locked }: { vps: T.VPSelectionState, onChange: (p: T.VPSelectionState) => void, mode: "charts" | "phrases" | "quiz", + locked: boolean, }) { function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) { const value = o?.value ? o.value : undefined; @@ -179,7 +180,7 @@ function TensePicker({ onChange, vps, mode }: { options={tOptions} {...zIndexProps} /> - {vps.verb &&
+ {vps.verb && !locked &&
diff --git a/src/components/vp-explorer/VPExplorer.tsx b/src/components/vp-explorer/VPExplorer.tsx index 5d2d125..2b6233e 100644 --- a/src/components/vp-explorer/VPExplorer.tsx +++ b/src/components/vp-explorer/VPExplorer.tsx @@ -16,10 +16,13 @@ import { randomSubjObj } from "../../library"; import shuffleArray from "../../lib/shuffle-array"; import InlinePs from "../InlinePs"; import { psStringEquals } from "../../lib/p-text-helpers"; +import classNames from "classnames"; +import { randFromArray } from "../../lib/misc-helpers"; // import { useReward } from 'react-rewards'; const kingEmoji = "👑"; const servantEmoji = "🙇‍♂️"; +const correctEmoji = ["✅", '🤓', "✅", '😊', "🌹", "✅", "✅", "🕺", "💃", '🥳', "👏", "✅", "💯", "😎", "✅", "👍"]; // TODO: Drill Down text display options @@ -34,6 +37,8 @@ const servantEmoji = "🙇‍♂️"; // TODO: error handling on error with rendering etc +const checkDuration = 400; + type QuizState = { answer: { ps: T.SingleOrLengthOpts; @@ -62,18 +67,26 @@ export function VPExplorer(props: { ); const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">("phrases", "verbExplorerMode"); const [quizState, setQuizState] = useState(undefined); + const [showCheck, setShowCheck] = useState(false); + const [currentCorrectEmoji, setCurrentCorrectEmoji] = useState(randFromArray(correctEmoji)); // const { reward } = useReward('rewardId', "emoji", { // emoji: ['🤓', '😊', '🥳', "👏", "💯", "😎", "👍"], // lifetime: 50, // elementCount: 10, // elementSize: 30, // }); + useEffect(() => { + if (mode === "quiz") { + handleResetQuiz(); + } + // eslint-disable-next-line + }, []); useEffect(() => { setVps(o => { if (mode === "quiz") { - return getRandomVPSelection("both")( - makeVPSelectionState(props.verb, o) - ); + const { VPS, qs } = makeQuizState(vps); + setQuizState(qs); + return VPS; } return makeVPSelectionState(props.verb, o); }); @@ -130,8 +143,17 @@ export function VPExplorer(props: { function checkQuizAnswer(a: T.PsString) { if (!quizState) return; if (isInAnswer(a, quizState.answer)) { - // reward(); - handleResetQuiz(); + setShowCheck(true); + setTimeout(() => { + handleResetQuiz(); + }, checkDuration / 2); + setTimeout(() => { + setShowCheck(false); + }, checkDuration); + // this sucks, have to do this so the emoji doesn't change in the middle of animation + setTimeout(() => { + setCurrentCorrectEmoji(randFromArray(correctEmoji)); + }, checkDuration * 2); } else { setQuizState({ ...quizState, @@ -219,6 +241,7 @@ export function VPExplorer(props: { vps={vps} onChange={quizLock(setVps)} mode={mode} + locked={!!(mode === "quiz" && quizState)} />
@@ -228,10 +251,15 @@ export function VPExplorer(props: { {(vps.verb && (mode === "charts")) && } {(mode === "quiz" && quizState) &&
+
+ {currentCorrectEmoji} +
{quizState.result === "waiting" ? <>
Choose a correct answer:
- {quizState.options.map(o =>
-
checkQuizAnswer(o)}> + {quizState.options.map(o =>
+
{ + checkQuizAnswer(o); + }}> {o}
)} @@ -248,9 +276,6 @@ export function VPExplorer(props: {
}
} - {mode === "quiz" &&
- {/* spacer for blank space while quizzing */} -
} } @@ -398,7 +423,7 @@ function getRandomVPSelection(mix: MixType = "both") { }; return { subject: s, - verb: mix === "both" ? randomizeTense(v, false) : v, + verb: randomizeTense(v, true), }; }; }; diff --git a/src/lib/misc-helpers.ts b/src/lib/misc-helpers.ts index 2c539cf..2b480f9 100644 --- a/src/lib/misc-helpers.ts +++ b/src/lib/misc-helpers.ts @@ -152,6 +152,12 @@ export function randomNumber(minInclusive: number, maxExclusive: number): number return Math.floor(Math.random() * (maxExclusive - minInclusive) + minInclusive); } +export function randFromArray(arr: M[]): M { + return arr[ + Math.floor(Math.random()*arr.length) + ]; +} + // TODO: deprecate this because we have it in np-tools? /** * Sees if a possiblePerson (for subject/object) is possible, given the other person