feat: added live validation toggle

This commit is contained in:
Richard Wong 2026-01-10 13:00:27 +08:00
parent 7abc197742
commit d0fc6664f2
4 changed files with 55 additions and 32 deletions

View File

@ -10,8 +10,10 @@
"set_shuffle": "Set Shuffle:",
"note_set_shuffle": "(Otherwise cards will appear in sequential order)",
"hide_reference": "Set Hide Reference:",
"note_hide_reference": "(If you also want to test the verse reference)",
"pick_pack": "Pick Your Packs:",
"note_hide_reference": "Check this box to hide the verse reference and test your memory on the reference as well.",
"live_validation": "Enable live validation",
"note_live_validation": "Check this box to enable live validation feedback as you type. Uncheck to only show correctness upon completion.",
"pick_pack": "Pick your pack(s)",
"shuffle_card": "Shuffle Cards:",
"verses": "Verses:"
},

View File

@ -10,8 +10,10 @@
"set_shuffle": "무작위 설정:",
"note_set_shuffle": "(Otherwise cards will appear in sequential order)",
"hide_reference": "Set Hide Reference:",
"note_hide_reference": "(If you also want to test the verse reference)",
"pick_pack": "Pick Your Packs:",
"note_hide_reference": "Check this box to hide the verse reference and test your memory on the reference as well.",
"live_validation": "Enable live validation",
"note_live_validation": "Check this box to enable live validation feedback as you type. Uncheck to only show correctness upon completion.",
"pick_pack": "Pick your pack(s)",
"shuffle_card": "Shuffle Cards:",
"verses": "Verses:"
},

View File

@ -15,7 +15,7 @@ import { useTranslation } from 'react-i18next';
import logo from './assets/droplet.svg';
import { Suspense } from "react";
const GenerateTestList = ({ VerseData, packs, testCount, toShuffle, toHideReference, translate}) => {
const GenerateTestList = ({ VerseData, packs, testCount, toShuffle, toHideReference, liveValidation, translate}) => {
let testList = packs.reduce(
// grab all elements included checked in "packs"
(accumulator, currentValue) => accumulator.concat(VerseData[currentValue]),
@ -26,18 +26,20 @@ const GenerateTestList = ({ VerseData, packs, testCount, toShuffle, toHideRefere
<ArrayTester
array={testList}
toHideReference={toHideReference}
liveValidation={liveValidation}
translate={translate}
/>
)
}
const ArrayTester = ({ array, toHideReference, translate}) => {
const ArrayTester = ({ array, toHideReference, liveValidation, translate}) => {
const list = array.map((element, index) => (
// key needs to be unique; chose 3 elements that will separate all elements
<VerseValidator
key={element.pack + element.title + element.reference}
element={element}
toHideReference={toHideReference}
liveValidation={liveValidation}
t={translate} // this passes the t i18 object to the function
index={index + 1}
/>
@ -201,6 +203,14 @@ function Page() {
setHideReference(!toHideReference);
};
// state for liveValidation
const [liveValidation, setLiveValidation] = useState(true);
// Function to handle checkbox change
const handleLiveValidationCheckboxChange = () => {
// Toggle the state when the checkbox is changed
setLiveValidation(!liveValidation);
};
@ -262,6 +272,21 @@ function Page() {
<p></p>}
</div>
{!(toReview) ?
<>
<h2>
{t('main.live_validation')}
<input
type="checkbox"
checked={liveValidation}
onChange={handleLiveValidationCheckboxChange}
/>
</h2>
<p>{t('main.note_live_validation')}</p>
</> :
<p></p>
}
<h2>{t('main.pick_pack')}</h2>
<CheckboxWidget
@ -296,6 +321,7 @@ function Page() {
testCount={testCount}
toShuffle={toShuffle}
toHideReference={toHideReference}
liveValidation={liveValidation}
translate={t}
/>
}

View File

@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import "./VerseValidator.css";
import { StringDiff } from "react-string-diff";
import { containsKorean, jamoSubstringMatch } from './utils';
@ -12,8 +12,7 @@ const STATE = {
// function to render and handle logic of each of the cells
const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse } , toHideReference, t, index}) => { // useful use of destructuring here
const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse } , toHideReference, liveValidation, t, index}) => { // useful use of destructuring here
const [inputReference, setReference] = useState('')
const [referenceBool, setReferenceBool] = useState(STATE.INCORRECT)
const [inputChapterTitle, setChapterTitle] = useState('')
@ -26,6 +25,15 @@ const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse
const[diffBool, setDiffBool] = useState(false)
const [isComposing, setIsComposing] = useState(false);
useEffect(() => {
// Re-run validation for all fields when liveValidation changes
// Using current input values to re-evaluate their state
validateReference(inputReference);
validateChapterTitle(inputChapterTitle);
validateTitle(inputTitle);
validateVerse(inputVerse);
}, [liveValidation]); // Dependency array: re-run effect when liveValidation changes
// handle reset
const handleReset = () => {
setReference('');
@ -46,13 +54,13 @@ const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse
setIsComposing(true);
};
function resultChecker(string1, string2) {
function resultChecker(string1, string2, liveValidation) {
var result = STATE.INCORRECT; // init
// contains korean
if (containsKorean(string1)) {
if (string1 === string2) {
result = STATE.CORRECT;
} else if (jamoSubstringMatch(string2, string1) & string1 !== "") {
} else if (liveValidation && jamoSubstringMatch(string2, string1) & string1 !== "") {
result = STATE.PARTIAL;
} else {
result = STATE.INCORRECT;
@ -60,7 +68,7 @@ const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse
} else { // does not contain korean
if (string1 === string2) {
result = STATE.CORRECT;
} else if (string2.startsWith(string1) & string1 !== "") {
} else if (liveValidation && string2.startsWith(string1) & string1 !== "") {
result = STATE.PARTIAL;
} else {
result = STATE.INCORRECT;
@ -81,7 +89,7 @@ const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse
.toLowerCase()
.normalize("NFC");
const result = resultChecker(string1, string2);
const result = resultChecker(string1, string2, liveValidation);
setReferenceBool(result);
};
@ -109,7 +117,7 @@ const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse
.toLowerCase()
.normalize("NFC");
const result = resultChecker(string1, string2);
const result = resultChecker(string1, string2, liveValidation);
setTitleBool(result);
};
@ -140,7 +148,7 @@ const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse
.toLowerCase()
.normalize("NFC");
const result = resultChecker(string1, string2);
const result = resultChecker(string1, string2, liveValidation);
setChapterTitleBool(result);
};
@ -167,7 +175,7 @@ const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse
.toLowerCase()
.normalize("NFC");
const result = resultChecker(string1, string2);
const result = resultChecker(string1, string2, liveValidation);
setVerseBool(result);
};
@ -179,21 +187,6 @@ const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse
}`;
// const DiffViewer = ({oldValue, newValue}) => {
// const string1 = String(oldValue)
// .replace(/[\p{P}\p{S}]/gu, "")
// .toLowerCase()
// .normalize("NFC");
// const string2 = String(newValue)
// .replace(/[\p{P}\p{S}]/gu, "")
// .toLowerCase()
// .normalize("NFC");
// return (<StringDiff oldValue={string1} newValue={string2} diffMethod="diffWords" />)
// }
const DiffViewerStrict = ({oldValue, newValue}) => {
const string1 = String(oldValue)
.toLowerCase()