From 40b4a963da67182d1ddc489f57dea627ec5fc455 Mon Sep 17 00:00:00 2001
From: lingdocs <71590811+lingdocs@users.noreply.github.com>
Date: Sat, 9 Apr 2022 22:31:55 +0500
Subject: [PATCH] added verb basic quiz feature
---
package.json | 2 +-
src/App.tsx | 1 +
src/components/np-picker/NPPicker.tsx | 5 +-
src/components/vp-explorer/TensePicker.tsx | 2 +-
src/components/vp-explorer/VPDisplay.tsx | 6 +-
src/components/vp-explorer/VPExplorer.tsx | 94 ++++++++++++++++++++--
src/lib/dictionary-models.js | 1 +
src/lib/np-tools.ts | 2 +-
src/lib/useStickyState.ts | 11 +--
9 files changed, 102 insertions(+), 22 deletions(-)
diff --git a/package.json b/package.json
index c416714..a2e5ec4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@lingdocs/pashto-inflector",
- "version": "1.8.4",
+ "version": "1.8.5",
"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.tsx b/src/App.tsx
index 3646c66..1acd745 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -33,6 +33,7 @@ const verbTypes: VerbType[] = [
"stative compound",
"dynamic compound",
];
+
const nouns = nounsAdjs.filter(isNounEntry);
const transitivities: T.Transitivity[] = [
diff --git a/src/components/np-picker/NPPicker.tsx b/src/components/np-picker/NPPicker.tsx
index c0c999d..9e5b439 100644
--- a/src/components/np-picker/NPPicker.tsx
+++ b/src/components/np-picker/NPPicker.tsx
@@ -18,6 +18,7 @@ function NPPicker(props: {
counterPart: T.NPSelection | T.VerbObject | undefined,
asObject?: boolean,
opts: T.TextOptions,
+ cantClear?: boolean,
} & ({
nouns: (s: string) => T.NounEntry[],
verbs: (s: string) => T.VerbEntry[],
@@ -52,7 +53,9 @@ function NPPicker(props: {
}
}
const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement;
- const clearButton = ;
+ const clearButton = !props.cantClear
+ ?
+ :
;
return
{!npType &&
{/*
diff --git a/src/components/vp-explorer/TensePicker.tsx b/src/components/vp-explorer/TensePicker.tsx
index ff1f17a..efb4ab6 100644
--- a/src/components/vp-explorer/TensePicker.tsx
+++ b/src/components/vp-explorer/TensePicker.tsx
@@ -58,7 +58,7 @@ const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense
function TensePicker({ onChange, verb, mode }: {
verb: T.VerbSelection | undefined,
onChange: (p: T.VerbSelection | undefined) => void,
- mode: "charts" | "phrases",
+ mode: "charts" | "phrases" | "quiz",
}) {
function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) {
const value = o?.value ? o.value : undefined;
diff --git a/src/components/vp-explorer/VPDisplay.tsx b/src/components/vp-explorer/VPDisplay.tsx
index 85d2954..90f97bb 100644
--- a/src/components/vp-explorer/VPDisplay.tsx
+++ b/src/components/vp-explorer/VPDisplay.tsx
@@ -1,13 +1,13 @@
-import { useState } from "react";
import { renderVP, compileVP } from "../../lib/phrase-building/index";
import * as T from "../../types";
import InlinePs from "../InlinePs";
import AbbreviationFormSelector from "./AbbreviationFormSelector";
import { isPastTense } from "../../lib/phrase-building/vp-tools";
+import { useStickyState } from "../../library";
function VPDisplay({ VP, opts }: { VP: T.VPSelection, opts: T.TextOptions }) {
- const [form, setForm] = useState
({ removeKing: false, shrinkServant: false });
- const [OSV, setOSV] = useState(false);
+ const [form, setForm] = useStickyState({ removeKing: false, shrinkServant: false }, "abbreviationForm");
+ const [OSV, setOSV] = useStickyState(false, "includeOSV");
const result = compileVP(renderVP(VP), { ...form, OSV });
return
{VP.verb.transitivity === "transitive" &&
diff --git a/src/components/vp-explorer/VPExplorer.tsx b/src/components/vp-explorer/VPExplorer.tsx
index 5555144..7e015a7 100644
--- a/src/components/vp-explorer/VPExplorer.tsx
+++ b/src/components/vp-explorer/VPExplorer.tsx
@@ -11,7 +11,8 @@ import * as T from "../../types";
import ChartDisplay from "./ChartDisplay";
import useStickyState from "../../lib/useStickyState";
import { makeVerbSelection } from "./verb-selection";
-import { useEffect } from "react";
+import { useEffect, useState } from "react";
+import { randomSubjObj } from "../../library";
const kingEmoji = "👑";
const servantEmoji = "🙇♂️";
@@ -41,7 +42,8 @@ export function VPExplorer(props: {
getVerbByTs: (ts: number) => T.VerbEntry | undefined,
})) {
const [subject, setSubject] = useStickyState
(undefined, "subjectNPSelection");
- const [mode, setMode] = useStickyState<"charts" | "phrases">("phrases", "verbExplorerMode");
+ const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">("phrases", "verbExplorerMode");
+ const [showAnswer, setShowAnswer] = useState(false);
const passedVerb = props.verb;
const [verb, setVerb] = useStickyState(
passedVerb
@@ -57,6 +59,28 @@ export function VPExplorer(props: {
}
// eslint-disable-next-line
}, [passedVerb]);
+ function handleChangeMode(m: "charts" | "phrases" | "quiz") {
+ if (m === "quiz") {
+ handleResetQuiz();
+ }
+ setMode(m);
+ }
+ function handleSetVerb(v: T.VerbSelection | undefined) {
+ if (v?.verb.entry.ts !== verb?.verb.entry.ts) {
+ handleResetQuiz();
+ }
+ setVerb(v);
+ }
+ function handleResetQuiz() {
+ if (!verb) {
+ alert("Choose a verb to quiz");
+ return;
+ }
+ const { S, V } = setRandomQuizState(subject, verb);
+ setShowAnswer(false);
+ setSubject(S);
+ setVerb(V);
+ }
function handleSubjectChange(subject: T.NPSelection | undefined, skipPronounConflictCheck?: boolean) {
if (!skipPronounConflictCheck && hasPronounConflict(subject, verb?.object)) {
alert("That combination of pronouns is not allowed");
@@ -94,17 +118,18 @@ export function VPExplorer(props: {
verb={verb}
subject={subject}
changeSubject={(s) => handleSubjectChange(s, true)}
- onChange={setVerb}
+ onChange={handleSetVerb}
opts={props.opts}
/>
-
+
{(verb && (typeof verb.object === "object") && (verb.isCompound !== "dynamic") && (mode !== "charts")) &&
@@ -131,6 +156,7 @@ export function VPExplorer(props: {
counterPart={verb ? verb.object : undefined}
onChange={handleSubjectChange}
opts={props.opts}
+ cantClear={mode === "quiz"}
/>
{verb && (verb.object !== "none") &&
@@ -152,21 +178,32 @@ export function VPExplorer(props: {
counterPart={subject}
onChange={handleObjectChange}
opts={props.opts}
+ cantClear={mode === "quiz"}
/>}
}
>}
- {(verbPhrase && (mode === "phrases")) &&
+ {(verb && (mode === "quiz")) &&
+
+
}
+ {(verbPhrase && ((mode === "phrases") || (mode === "quiz" && showAnswer))) &&
}
- {(verb && (mode === "charts")) &&
}
+ {(verb && (mode === "charts")) &&
}
}
@@ -211,4 +248,45 @@ function switchSubjObj({ subject, verb }: SOClump): SOClump {
object: subject,
}
};
+}
+
+function setRandomQuizState(subject: T.NPSelection | undefined, verb: T.VerbSelection): {
+ S: T.NPSelection,
+ V: T.VerbSelection,
+} {
+ const oldSubj = (subject?.type === "pronoun")
+ ? subject.person
+ : undefined;
+ const oldObj = (typeof verb?.object === "object" && verb.object.type === "pronoun")
+ ? verb.object.person
+ : undefined;
+ const { subj, obj } = randomSubjObj(
+ oldSubj !== undefined ? { subj: oldSubj, obj: oldObj } : undefined
+ );
+ const randSubj: T.PronounSelection = subject?.type === "pronoun" ? {
+ ...subject,
+ person: subj,
+ } : {
+ type: "pronoun",
+ distance: "far",
+ person: subj,
+ };
+ const randObj: T.PronounSelection = typeof verb?.object === "object" && verb.object.type === "pronoun" ? {
+ ...verb.object,
+ person: obj,
+ } : {
+ type: "pronoun",
+ distance: "far",
+ person: obj,
+ };
+ return {
+ // TODO: Randomize the near/far ??
+ S: randSubj,
+ V: {
+ ...verb,
+ object: (typeof verb.object === "object" || verb.object === undefined)
+ ? randObj
+ : verb.object,
+ },
+ }
}
\ No newline at end of file
diff --git a/src/lib/dictionary-models.js b/src/lib/dictionary-models.js
index 5801f46..cec16a9 100644
--- a/src/lib/dictionary-models.js
+++ b/src/lib/dictionary-models.js
@@ -1,3 +1,4 @@
+// eslint-disable-next-line
'use strict'; // code generated by pbf v3.2.1
// DictionaryInfo ========================================
diff --git a/src/lib/np-tools.ts b/src/lib/np-tools.ts
index 94fc803..57ed9e4 100644
--- a/src/lib/np-tools.ts
+++ b/src/lib/np-tools.ts
@@ -50,7 +50,7 @@ export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
);
}
-export function randomSubjObj(old?: { subj: T.Person, obj: T.Person }): { subj: T.Person, obj: T.Person } {
+export function randomSubjObj(old?: { subj: T.Person, obj?: T.Person }): { subj: T.Person, obj: T.Person } {
let subj = 0;
let obj = 0;
do {
diff --git a/src/lib/useStickyState.ts b/src/lib/useStickyState.ts
index ce824e3..6e86a04 100644
--- a/src/lib/useStickyState.ts
+++ b/src/lib/useStickyState.ts
@@ -8,12 +8,9 @@ import { useEffect, useState } from "react";
* @param key a key for saving the state in locolStorage
* @returns
*/
-export default function useStickyState(
- defaultValue: T | ((old: T | undefined) => T),
- key: string
-): [
- value: T,
- setValue: React.Dispatch>,
+export default function useStickyState(defaultValue: T | ((old: T | undefined) => T), key: string): [
+ value: T,
+ setValue: React.Dispatch>,
] {
const [value, setValue] = useState(() => {
const v = window.localStorage.getItem(key);
@@ -30,7 +27,7 @@ export default function useStickyState