Compare commits
No commits in common. "41d6eed467f013cb244bf74006c83c6324e0295b" and "97ebbb29b7210cfde651b7af7a4dd426faf42271" have entirely different histories.
41d6eed467
...
97ebbb29b7
|
|
@ -10,13 +10,10 @@
|
||||||
"set_shuffle": "Set Shuffle:",
|
"set_shuffle": "Set Shuffle:",
|
||||||
"note_set_shuffle": "(Otherwise cards will appear in sequential order)",
|
"note_set_shuffle": "(Otherwise cards will appear in sequential order)",
|
||||||
"hide_reference": "Set Hide Reference:",
|
"hide_reference": "Set Hide Reference:",
|
||||||
"note_hide_reference": "Check this box to hide the verse reference and test your memory on the reference as well.",
|
"note_hide_reference": "(If you also want to test the verse reference)",
|
||||||
"live_validation": "Enable live validation",
|
"pick_pack": "Pick Your Packs:",
|
||||||
"note_live_validation": "Check this box to enable live validation feedback as you type. Uncheck to only show correctness upon completion.",
|
"shuffle_card": "Shuffle Cards:",
|
||||||
"pick_pack": "Pick your pack(s)",
|
"verses": "Verses:"
|
||||||
"tools": "Tools:",
|
|
||||||
"verses": "Verses:",
|
|
||||||
"problem_verses_session": "Statistics (This Session):"
|
|
||||||
},
|
},
|
||||||
"verse_validator": {
|
"verse_validator": {
|
||||||
"input_reference": "Input Verse Reference:",
|
"input_reference": "Input Verse Reference:",
|
||||||
|
|
@ -93,11 +90,7 @@
|
||||||
{ "value": "dep-6-part-b", "label": "Why should we witness?" },
|
{ "value": "dep-6-part-b", "label": "Why should we witness?" },
|
||||||
{ "value": "dep-6-part-c", "label": "How do we witness?" },
|
{ "value": "dep-6-part-c", "label": "How do we witness?" },
|
||||||
{ "value": "dep-6-part-d", "label": "Examples of witness" },
|
{ "value": "dep-6-part-d", "label": "Examples of witness" },
|
||||||
{ "value": "dep-6-part-e", "label": "Bridge Illustration (Creation story)" },
|
{ "value": "dep-6-part-e", "label": "Bridge Illustration" }
|
||||||
{ "value": "dep-6-part-f", "label": "Bridge Illustration (Man's condition)" },
|
|
||||||
{ "value": "dep-6-part-g", "label": "Bridge Illustration (Salvation not by ourselves)" },
|
|
||||||
{ "value": "dep-6-part-h", "label": "Bridge Illustration (God's solution)" },
|
|
||||||
{ "value": "dep-6-part-i", "label": "Bridge Illustration (Man must)" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,10 @@
|
||||||
"set_shuffle": "무작위 설정:",
|
"set_shuffle": "무작위 설정:",
|
||||||
"note_set_shuffle": "(Otherwise cards will appear in sequential order)",
|
"note_set_shuffle": "(Otherwise cards will appear in sequential order)",
|
||||||
"hide_reference": "Set Hide Reference:",
|
"hide_reference": "Set Hide Reference:",
|
||||||
"note_hide_reference": "Check this box to hide the verse reference and test your memory on the reference as well.",
|
"note_hide_reference": "(If you also want to test the verse reference)",
|
||||||
"live_validation": "Enable live validation",
|
"pick_pack": "Pick Your Packs:",
|
||||||
"note_live_validation": "Check this box to enable live validation feedback as you type. Uncheck to only show correctness upon completion.",
|
"shuffle_card": "Shuffle Cards:",
|
||||||
"pick_pack": "Pick your pack(s)",
|
"verses": "Verses:"
|
||||||
"tools": "Tools:",
|
|
||||||
"verses": "Verses:",
|
|
||||||
"problem_verses_session": "Statistics (This Session):"
|
|
||||||
},
|
},
|
||||||
"verse_validator": {
|
"verse_validator": {
|
||||||
"input_reference": "Input Verse Reference: ",
|
"input_reference": "Input Verse Reference: ",
|
||||||
|
|
|
||||||
|
|
@ -28,20 +28,3 @@
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-bar {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px; /* Adjust as needed */
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lang-bar {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px; /* Adjust as needed */
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Implemented features:
|
||||||
- create checklist from keys
|
- create checklist from keys
|
||||||
*/
|
*/
|
||||||
import fullVerseData from "./assets/verse.json" // the actual verse json data file
|
import fullVerseData from "./assets/verse.json" // the actual verse json data file
|
||||||
import { useState, useEffect, useMemo, useCallback } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import CheckboxTree from 'react-checkbox-tree';
|
import CheckboxTree from 'react-checkbox-tree';
|
||||||
import 'react-checkbox-tree/lib/react-checkbox-tree.css';
|
import 'react-checkbox-tree/lib/react-checkbox-tree.css';
|
||||||
import _ from 'underscore';
|
import _ from 'underscore';
|
||||||
|
|
@ -15,24 +15,50 @@ import { useTranslation } from 'react-i18next';
|
||||||
import logo from './assets/droplet.svg';
|
import logo from './assets/droplet.svg';
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
|
|
||||||
|
const GenerateTestList = ({ VerseData, packs, testCount, toShuffle, toHideReference, translate}) => {
|
||||||
|
let testList = packs.reduce(
|
||||||
|
// grab all elements included checked in "packs"
|
||||||
|
(accumulator, currentValue) => accumulator.concat(VerseData[currentValue]),
|
||||||
|
new Array()
|
||||||
|
);
|
||||||
|
testList = toShuffle ? _.sample(testList, testCount) : _.first(testList, testCount);
|
||||||
|
return (
|
||||||
|
<ArrayTester
|
||||||
|
array={testList}
|
||||||
|
toHideReference={toHideReference}
|
||||||
|
translate={translate}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const ArrayTester = ({ array, toHideReference, liveValidation, clearKey, translate, onShowAnswer}) => {
|
const ArrayTester = ({ array, toHideReference, translate}) => {
|
||||||
const list = array.map((element, index) => (
|
const list = array.map((element, index) => (
|
||||||
// key needs to be unique; chose 3 elements that will separate all elements
|
// key needs to be unique; chose 3 elements that will separate all elements
|
||||||
<VerseValidator
|
<VerseValidator
|
||||||
key={element.pack + element.title + element.reference}
|
key={element.pack + element.title + element.reference}
|
||||||
element={element}
|
element={element}
|
||||||
toHideReference={toHideReference}
|
toHideReference={toHideReference}
|
||||||
liveValidation={liveValidation}
|
|
||||||
clearKey={clearKey} // Pass clearKey down
|
|
||||||
t={translate} // this passes the t i18 object to the function
|
t={translate} // this passes the t i18 object to the function
|
||||||
index={index + 1}
|
index={index + 1}
|
||||||
onShowAnswer={onShowAnswer}
|
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GenerateReviewList = ({ VerseData, packs, testCount, toShuffle, translate}) => {
|
||||||
|
let testList = packs.reduce(
|
||||||
|
// grab all elements included checked in "packs"
|
||||||
|
(accumulator, currentValue) => accumulator.concat(VerseData[currentValue]),
|
||||||
|
new Array()
|
||||||
|
);
|
||||||
|
testList = toShuffle ? _.sample(testList, testCount) : _.first(testList, testCount);
|
||||||
|
return (
|
||||||
|
<ArrayPrinter
|
||||||
|
array={testList}
|
||||||
|
translate={translate}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const ArrayPrinter = ({ array, translate}) => {
|
const ArrayPrinter = ({ array, translate}) => {
|
||||||
const list = array.map((element, index) => (
|
const list = array.map((element, index) => (
|
||||||
|
|
@ -48,6 +74,7 @@ const ArrayPrinter = ({ array, translate}) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const CheckboxWidget = ({nodes, checked, expanded, setChecked, setExpanded}) => {
|
const CheckboxWidget = ({nodes, checked, expanded, setChecked, setExpanded}) => {
|
||||||
return (
|
return (
|
||||||
<div className="CheckboxTree">
|
<div className="CheckboxTree">
|
||||||
|
|
@ -84,34 +111,16 @@ const loadCustomData = (language) => {
|
||||||
function Page() {
|
function Page() {
|
||||||
|
|
||||||
// refresh button for refresh
|
// refresh button for refresh
|
||||||
const RefreshButton = ({ onClick, disabled }) => {
|
const RefreshButton = ({ onClick }) => {
|
||||||
return <button onClick={onClick} disabled={disabled}>Shuffle</button>;
|
return <button onClick={onClick}>Shuffle</button>;
|
||||||
};
|
};
|
||||||
// refresh variables where incrementing state forces refresh
|
// refresh variables where incrementing state forces refresh
|
||||||
const [shuffleKey, setShuffleKey] = useState(0);
|
const [refreshKey, setRefreshKey] = useState(0);
|
||||||
const handleShuffle = () => {
|
const handleRefresh = () => {
|
||||||
// Increment the key to force a re-render
|
// Increment the key to force a re-render
|
||||||
setShuffleKey(shuffleKey => shuffleKey + 1);
|
setRefreshKey(refreshKey => refreshKey + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// New state for clearing all inputs
|
|
||||||
const [clearKey, setClearKey] = useState(0);
|
|
||||||
const handleClearAll = () => {
|
|
||||||
setClearKey(clearKey => clearKey + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// New state for tracking problem verses within the session
|
|
||||||
const [sessionProblemVerses, setSessionProblemVerses] = useState({});
|
|
||||||
|
|
||||||
// Callback for when 'Show Answer' is clicked in VerseValidator
|
|
||||||
const handleShowAnswer = useCallback((verseIdentifier) => {
|
|
||||||
const key = `${verseIdentifier.pack}|${verseIdentifier.reference}`;
|
|
||||||
setSessionProblemVerses(prev => ({
|
|
||||||
...prev,
|
|
||||||
[key]: (prev[key] || 0) + 1
|
|
||||||
}));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// setup i18 for function
|
// setup i18 for function
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
|
||||||
|
|
@ -192,31 +201,6 @@ function Page() {
|
||||||
setHideReference(!toHideReference);
|
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate testList using cached state that depends only on shuffle-dependent variables
|
|
||||||
// this fixes the bug where changing other state causes a re-shuffle
|
|
||||||
const testList = useMemo(() => {
|
|
||||||
if (!VerseData || checked.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
let list = checked.reduce(
|
|
||||||
(accumulator, currentValue) => accumulator.concat(VerseData[currentValue]),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
return toShuffle ? _.sample(list, testCount) : _.first(list, testCount);
|
|
||||||
}, [VerseData, checked, testCount, toShuffle, shuffleKey]);
|
|
||||||
|
|
||||||
// Reset session problem verses when the testList changes (new session)
|
|
||||||
useEffect(() => {
|
|
||||||
setSessionProblemVerses({});
|
|
||||||
}, [testList]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -224,12 +208,8 @@ function Page() {
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<h1>{t('main.title')}</h1>
|
<h1>{t('main.title')}</h1>
|
||||||
<h2>{t('main.pick_lang')}</h2>
|
<h2>{t('main.pick_lang')}</h2>
|
||||||
|
<button type="button" onClick={() => changeLanguage('en')}>English</button>
|
||||||
<div className="lang-bar">
|
<button type="button" onClick={() => changeLanguage('kn')}>Korean</button>
|
||||||
<button type="button" onClick={() => changeLanguage('en')}>English</button>
|
|
||||||
<button type="button" onClick={() => changeLanguage('kn')}>Korean</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>{t('main.pick_num_verses')}</h2>
|
<h2>{t('main.pick_num_verses')}</h2>
|
||||||
<label className="test-count-box-label" htmlFor="testCountBox">
|
<label className="test-count-box-label" htmlFor="testCountBox">
|
||||||
{t('main.num_verses_tested')}
|
{t('main.num_verses_tested')}
|
||||||
|
|
@ -266,30 +246,20 @@ function Page() {
|
||||||
</h2>
|
</h2>
|
||||||
<p>{t('main.note_set_shuffle')}</p>
|
<p>{t('main.note_set_shuffle')}</p>
|
||||||
|
|
||||||
<div className={(toShuffle || toReview) ? 'setting-disabled' : ''}>
|
<div>
|
||||||
<h2>
|
{!(toShuffle || toReview) ?
|
||||||
{t('main.hide_reference')}
|
<>
|
||||||
<input
|
<h2>
|
||||||
type="checkbox"
|
{t('main.hide_reference')}
|
||||||
checked={toHideReference}
|
<input
|
||||||
onChange={handleHideReferenceCheckboxChange}
|
type="checkbox"
|
||||||
disabled={toShuffle || toReview}
|
checked={toHideReference}
|
||||||
/>
|
onChange={handleHideReferenceCheckboxChange}
|
||||||
</h2>
|
/>
|
||||||
<p>{t('main.note_hide_reference')}</p>
|
</h2>
|
||||||
</div>
|
<p>{t('main.note_hide_reference')}</p>
|
||||||
|
</>:
|
||||||
<div className={toReview ? 'setting-disabled' : ''}>
|
<p></p>}
|
||||||
<h2>
|
|
||||||
{t('main.live_validation')}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={liveValidation}
|
|
||||||
onChange={handleLiveValidationCheckboxChange}
|
|
||||||
disabled={toReview}
|
|
||||||
/>
|
|
||||||
</h2>
|
|
||||||
<p>{t('main.note_live_validation')}</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -302,43 +272,34 @@ function Page() {
|
||||||
setExpanded={setExpanded}
|
setExpanded={setExpanded}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>{t('main.tools')}</h2>
|
<div key={refreshKey}>
|
||||||
<div className="tool-bar">
|
{toShuffle ?
|
||||||
<RefreshButton onClick={handleShuffle} disabled={!toShuffle} />
|
<>
|
||||||
<button onClick={handleClearAll}>Clear All</button>
|
<h2>{t('main.shuffle_card')}</h2>
|
||||||
|
<RefreshButton onClick={handleRefresh} />
|
||||||
|
</>:
|
||||||
|
<p></p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1>{t('main.verses')}</h1>
|
<h1>{t('main.verses')}</h1>
|
||||||
{toReview ?
|
{toReview ?
|
||||||
<ArrayPrinter
|
<GenerateReviewList
|
||||||
array={testList}
|
VerseData={VerseData}
|
||||||
|
packs={checked}
|
||||||
|
testCount={testCount}
|
||||||
|
toShuffle={toShuffle}
|
||||||
translate={t}
|
translate={t}
|
||||||
/> :
|
/> :
|
||||||
<ArrayTester
|
<GenerateTestList
|
||||||
array={testList}
|
VerseData={VerseData}
|
||||||
|
packs={checked}
|
||||||
|
testCount={testCount}
|
||||||
|
toShuffle={toShuffle}
|
||||||
toHideReference={toHideReference}
|
toHideReference={toHideReference}
|
||||||
liveValidation={liveValidation}
|
|
||||||
clearKey={clearKey} // Pass clearKey down
|
|
||||||
translate={t}
|
translate={t}
|
||||||
onShowAnswer={handleShowAnswer}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
{Object.keys(sessionProblemVerses).length > 0 && (
|
|
||||||
<div className="session-problem-verses">
|
|
||||||
<h2>{t('main.problem_verses_session')}</h2>
|
|
||||||
<ul>
|
|
||||||
{Object.entries(sessionProblemVerses)
|
|
||||||
.sort(([, countA], [, countB]) => countB - countA) // Sort by count in descending order
|
|
||||||
.map(([key, count]) => {
|
|
||||||
// Assuming key format is "pack:reference"
|
|
||||||
const [pack, reference] = key.split('|');
|
|
||||||
return <li key={key}>{reference} (Shown Answer: {count} time{count > 1 ? 's' : ''})</li>;
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<p><x-small> Built on: {VITE_BUILD_DATE} </x-small></p>
|
<p><x-small> Built on: {VITE_BUILD_DATE} </x-small></p>
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.verse-validator-button-box {
|
.answer-button-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useEffect, useRef } from "react";
|
import { useState } from "react";
|
||||||
import "./VerseValidator.css";
|
import "./VerseValidator.css";
|
||||||
import { StringDiff } from "react-string-diff";
|
import { StringDiff } from "react-string-diff";
|
||||||
import { containsKorean, jamoSubstringMatch } from './utils';
|
import { containsKorean, jamoSubstringMatch } from './utils';
|
||||||
|
|
@ -9,18 +9,11 @@ const STATE = {
|
||||||
CORRECT: 2,
|
CORRECT: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// function to render and handle logic of each of the cells
|
// function to render and handle logic of each of the cells
|
||||||
const VerseValidator = (
|
const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse } , toHideReference, t, index}) => { // useful use of destructuring here
|
||||||
{ element:
|
|
||||||
{ pack, title, chapterTitle, reference, verse },
|
|
||||||
toHideReference,
|
|
||||||
liveValidation,
|
|
||||||
clearKey,
|
|
||||||
t,
|
|
||||||
index,
|
|
||||||
onShowAnswer
|
|
||||||
}) => { // useful use of destructuring here
|
|
||||||
const [inputReference, setReference] = useState('')
|
const [inputReference, setReference] = useState('')
|
||||||
const [referenceBool, setReferenceBool] = useState(STATE.INCORRECT)
|
const [referenceBool, setReferenceBool] = useState(STATE.INCORRECT)
|
||||||
const [inputChapterTitle, setChapterTitle] = useState('')
|
const [inputChapterTitle, setChapterTitle] = useState('')
|
||||||
|
|
@ -29,33 +22,9 @@ const VerseValidator = (
|
||||||
const [titleBool, setTitleBool] = useState(STATE.INCORRECT)
|
const [titleBool, setTitleBool] = useState(STATE.INCORRECT)
|
||||||
const [inputVerse, setVerse] = useState('')
|
const [inputVerse, setVerse] = useState('')
|
||||||
const [verseBool, setVerseBool] = useState(STATE.INCORRECT)
|
const [verseBool, setVerseBool] = useState(STATE.INCORRECT)
|
||||||
const [hintBool, setHintBool] = useState(false)
|
const[hintBool, setHintBool] = useState(false)
|
||||||
const [diffBool, setDiffBool] = useState(false)
|
const[diffBool, setDiffBool] = useState(false)
|
||||||
const [isComposing, setIsComposing] = useState(false);
|
const [isComposing, setIsComposing] = useState(false);
|
||||||
const isInitialMount = useRef(true);
|
|
||||||
|
|
||||||
// State for hint word counts
|
|
||||||
const [referenceHintCount, setReferenceHintCount] = useState(0);
|
|
||||||
const [titleHintCount, setTitleHintCount] = useState(0);
|
|
||||||
const [chapterTitleHintCount, setChapterTitleHintCount] = useState(0);
|
|
||||||
const [verseHintCount, setVerseHintCount] = useState(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isInitialMount.current) {
|
|
||||||
isInitialMount.current = false;
|
|
||||||
} else {
|
|
||||||
handleReset();
|
|
||||||
}
|
|
||||||
}, [clearKey]);
|
|
||||||
|
|
||||||
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
|
// handle reset
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
|
|
@ -68,12 +37,6 @@ const VerseValidator = (
|
||||||
setVerse('');
|
setVerse('');
|
||||||
setVerseBool(STATE.INCORRECT);
|
setVerseBool(STATE.INCORRECT);
|
||||||
setDiffBool(false); // optionally hide answer again
|
setDiffBool(false); // optionally hide answer again
|
||||||
setHintBool(false);
|
|
||||||
// Reset hint counts
|
|
||||||
setReferenceHintCount(0);
|
|
||||||
setTitleHintCount(0);
|
|
||||||
setChapterTitleHintCount(0);
|
|
||||||
setVerseHintCount(0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -83,13 +46,13 @@ const VerseValidator = (
|
||||||
setIsComposing(true);
|
setIsComposing(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
function resultChecker(string1, string2, liveValidation) {
|
function resultChecker(string1, string2) {
|
||||||
var result = STATE.INCORRECT; // init
|
var result = STATE.INCORRECT; // init
|
||||||
// contains korean
|
// contains korean
|
||||||
if (containsKorean(string1)) {
|
if (containsKorean(string1)) {
|
||||||
if (string1 === string2) {
|
if (string1 === string2) {
|
||||||
result = STATE.CORRECT;
|
result = STATE.CORRECT;
|
||||||
} else if (liveValidation && jamoSubstringMatch(string2, string1) & string1 !== "") {
|
} else if (jamoSubstringMatch(string2, string1) & string1 !== "") {
|
||||||
result = STATE.PARTIAL;
|
result = STATE.PARTIAL;
|
||||||
} else {
|
} else {
|
||||||
result = STATE.INCORRECT;
|
result = STATE.INCORRECT;
|
||||||
|
|
@ -97,7 +60,7 @@ const VerseValidator = (
|
||||||
} else { // does not contain korean
|
} else { // does not contain korean
|
||||||
if (string1 === string2) {
|
if (string1 === string2) {
|
||||||
result = STATE.CORRECT;
|
result = STATE.CORRECT;
|
||||||
} else if (liveValidation && string2.startsWith(string1) & string1 !== "") {
|
} else if (string2.startsWith(string1) & string1 !== "") {
|
||||||
result = STATE.PARTIAL;
|
result = STATE.PARTIAL;
|
||||||
} else {
|
} else {
|
||||||
result = STATE.INCORRECT;
|
result = STATE.INCORRECT;
|
||||||
|
|
@ -118,7 +81,7 @@ const VerseValidator = (
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.normalize("NFC");
|
.normalize("NFC");
|
||||||
|
|
||||||
const result = resultChecker(string1, string2, liveValidation);
|
const result = resultChecker(string1, string2);
|
||||||
|
|
||||||
setReferenceBool(result);
|
setReferenceBool(result);
|
||||||
};
|
};
|
||||||
|
|
@ -146,7 +109,7 @@ const VerseValidator = (
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.normalize("NFC");
|
.normalize("NFC");
|
||||||
|
|
||||||
const result = resultChecker(string1, string2, liveValidation);
|
const result = resultChecker(string1, string2);
|
||||||
setTitleBool(result);
|
setTitleBool(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -177,7 +140,7 @@ const VerseValidator = (
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.normalize("NFC");
|
.normalize("NFC");
|
||||||
|
|
||||||
const result = resultChecker(string1, string2, liveValidation);
|
const result = resultChecker(string1, string2);
|
||||||
|
|
||||||
setChapterTitleBool(result);
|
setChapterTitleBool(result);
|
||||||
};
|
};
|
||||||
|
|
@ -204,7 +167,7 @@ const VerseValidator = (
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.normalize("NFC");
|
.normalize("NFC");
|
||||||
|
|
||||||
const result = resultChecker(string1, string2, liveValidation);
|
const result = resultChecker(string1, string2);
|
||||||
|
|
||||||
setVerseBool(result);
|
setVerseBool(result);
|
||||||
};
|
};
|
||||||
|
|
@ -216,6 +179,21 @@ const VerseValidator = (
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
|
||||||
|
// 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 DiffViewerStrict = ({oldValue, newValue}) => {
|
||||||
const string1 = String(oldValue)
|
const string1 = String(oldValue)
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
|
|
@ -279,19 +257,6 @@ const VerseValidator = (
|
||||||
validateReference(value);
|
validateReference(value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{hintBool && (
|
|
||||||
<div className="hint-area">
|
|
||||||
<p className="hint-text">
|
|
||||||
Hint: {reference.split(' ').slice(0, referenceHintCount).join(' ')}
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
onClick={() => setReferenceHintCount(prev => prev + 1)}
|
|
||||||
disabled={referenceHintCount >= reference.split(' ').length}
|
|
||||||
>
|
|
||||||
Next Word
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<h2>
|
<h2>
|
||||||
|
|
@ -325,122 +290,70 @@ const VerseValidator = (
|
||||||
setChapterTitle(value);
|
setChapterTitle(value);
|
||||||
validateChapterTitle(value);
|
validateChapterTitle(value);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
{hintBool && (
|
|
||||||
<div className="hint-area">
|
|
||||||
<p className="hint-text">
|
|
||||||
Hint: {chapterTitle.split(' ').slice(0, chapterTitleHintCount).join(' ')}
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
onClick={() => setChapterTitleHintCount(prev => prev + 1)}
|
|
||||||
disabled={chapterTitleHintCount >= chapterTitle.split(' ').length}
|
|
||||||
>
|
|
||||||
Next Word
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* input box for title */}
|
{/* input box for title */}
|
||||||
<div>
|
<label className="title-box-label">
|
||||||
<label className="title-box-label">
|
{t('verse_validator.input_title')}
|
||||||
{t('verse_validator.input_title')}
|
</label>
|
||||||
</label>
|
<textarea
|
||||||
<textarea
|
className={titleClassName}
|
||||||
className={titleClassName}
|
type="text"
|
||||||
type="text"
|
id="titleBox"
|
||||||
id="titleBox"
|
name="titleBox"
|
||||||
name="titleBox"
|
value={inputTitle}
|
||||||
value={inputTitle}
|
onInput={(event) => {
|
||||||
onInput={(event) => {
|
const value = event.target.value;
|
||||||
const value = event.target.value;
|
setTitle(value);
|
||||||
setTitle(value);
|
if (!isComposing) {
|
||||||
if (!isComposing) {
|
|
||||||
validateTitle(value);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onCompositionStart={handleCompositionStart}
|
|
||||||
onCompositionEnd={(event) => {
|
|
||||||
const value = event.target.value;
|
|
||||||
setIsComposing(false);
|
|
||||||
setTitle(value);
|
|
||||||
validateTitle(value);
|
validateTitle(value);
|
||||||
}}
|
}
|
||||||
/>
|
}}
|
||||||
{hintBool && (
|
onCompositionStart={handleCompositionStart}
|
||||||
<div className="hint-area">
|
onCompositionEnd={(event) => {
|
||||||
<p className="hint-text">
|
const value = event.target.value;
|
||||||
Hint: {title.split(' ').slice(0, titleHintCount).join(' ')}
|
setIsComposing(false);
|
||||||
</p>
|
setTitle(value);
|
||||||
<button
|
validateTitle(value);
|
||||||
onClick={() => setTitleHintCount(prev => prev + 1)}
|
}}
|
||||||
disabled={titleHintCount >= title.split(' ').length}
|
|
||||||
>
|
/>
|
||||||
Next Word
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* input box for verse */}
|
{/* input box for verse */}
|
||||||
<div>
|
<label className="verse-box-label">
|
||||||
<label className="verse-box-label">
|
{t('verse_validator.input_verse')}
|
||||||
{t('verse_validator.input_verse')}
|
</label>
|
||||||
</label>
|
<textarea
|
||||||
<textarea
|
className={verseClassName}
|
||||||
className={verseClassName}
|
type="text"
|
||||||
type="text"
|
id="verseBox"
|
||||||
id="verseBox"
|
name="verseBox"
|
||||||
name="verseBox"
|
value={inputVerse}
|
||||||
value={inputVerse}
|
onInput={(event) => {
|
||||||
onInput={(event) => {
|
const value = event.target.value;
|
||||||
const value = event.target.value;
|
setVerse(value);
|
||||||
setVerse(value);
|
if (!isComposing) {
|
||||||
if (!isComposing) {
|
|
||||||
validateVerse(value);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onCompositionStart={handleCompositionStart}
|
|
||||||
onCompositionEnd={(event) => {
|
|
||||||
const value = event.target.value;
|
|
||||||
setIsComposing(false);
|
|
||||||
setVerse(value);
|
|
||||||
validateVerse(value);
|
validateVerse(value);
|
||||||
}}
|
}
|
||||||
/>
|
}}
|
||||||
{hintBool && (
|
onCompositionStart={handleCompositionStart}
|
||||||
<div className="hint-area">
|
onCompositionEnd={(event) => {
|
||||||
<p className="hint-text">
|
const value = event.target.value;
|
||||||
Hint: {verse.split(' ').slice(0, verseHintCount).join(' ')}
|
setIsComposing(false);
|
||||||
</p>
|
setVerse(value);
|
||||||
<button
|
validateVerse(value);
|
||||||
onClick={() => setVerseHintCount(prev => prev + 1)}
|
}}
|
||||||
disabled={verseHintCount >= verse.split(' ').length}
|
|
||||||
>
|
|
||||||
Next Word
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* buttons to toggle per-block functionality*/}
|
|
||||||
<div className="verse-validator-button-box">
|
/>
|
||||||
{/* hint button*/}
|
|
||||||
<button onClick={() => setHintBool(!hintBool)}>
|
{/* button to toggle show answer*/}
|
||||||
{hintBool ? 'Hide Hints' : 'Show Hints'}
|
<div className="answer-button-box">
|
||||||
</button>
|
{/* <button onClick={() => setHintBool(!hintBool)}>Show Answer:</button> */}
|
||||||
{/* show answer button*/}
|
<button onClick={() => setDiffBool(!diffBool)}>Show Answer:</button>
|
||||||
<button onClick={() => {
|
|
||||||
// Toggle the diff display
|
|
||||||
setDiffBool(prev => !prev);
|
|
||||||
// If it's being turned ON, and onShowAnswer is provided, call it.
|
|
||||||
// We only want to count when the user explicitly reveals the answer.
|
|
||||||
if (!diffBool && onShowAnswer) {
|
|
||||||
onShowAnswer({ pack, title, reference });
|
|
||||||
}
|
|
||||||
}}>Show Answer</button>
|
|
||||||
{/* reset button*/}
|
|
||||||
<button onClick={handleReset}>Reset</button>
|
<button onClick={handleReset}>Reset</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1722,9 +1722,7 @@
|
||||||
"title": "Separated from God by our sin",
|
"title": "Separated from God by our sin",
|
||||||
"reference": "Isaiah 59:1-2",
|
"reference": "Isaiah 59:1-2",
|
||||||
"verse": "Surely the arm of the LORD is not too short to save, nor his ear too dull to hear. But your iniquities have separated you from your God; your sins have hidden his face from you, so that he will not hear."
|
"verse": "Surely the arm of the LORD is not too short to save, nor his ear too dull to hear. But your iniquities have separated you from your God; your sins have hidden his face from you, so that he will not hear."
|
||||||
}
|
},
|
||||||
],
|
|
||||||
"dep-6-part-f": [
|
|
||||||
{
|
{
|
||||||
"pack": "DEP6",
|
"pack": "DEP6",
|
||||||
"chapterTitle": "Bridge Illustration",
|
"chapterTitle": "Bridge Illustration",
|
||||||
|
|
@ -1766,9 +1764,7 @@
|
||||||
"title": "Man's condition - Eternal death",
|
"title": "Man's condition - Eternal death",
|
||||||
"reference": "Revelation 21:8",
|
"reference": "Revelation 21:8",
|
||||||
"verse": "But the cowardly, the unbelieving, the vile, the murderers, the sexually immoral, those who practice magic arts, the idolaters and all liars - their place will be in the fiery lake of burning sulfur. This is the second death.\""
|
"verse": "But the cowardly, the unbelieving, the vile, the murderers, the sexually immoral, those who practice magic arts, the idolaters and all liars - their place will be in the fiery lake of burning sulfur. This is the second death.\""
|
||||||
}
|
},
|
||||||
],
|
|
||||||
"dep-6-part-g": [
|
|
||||||
{
|
{
|
||||||
"pack": "DEP6",
|
"pack": "DEP6",
|
||||||
"chapterTitle": "Bridge Illustration",
|
"chapterTitle": "Bridge Illustration",
|
||||||
|
|
@ -1838,9 +1834,7 @@
|
||||||
"title": "Salvation not by ourselves - The flesh counts for nothing",
|
"title": "Salvation not by ourselves - The flesh counts for nothing",
|
||||||
"reference": "John 6:63",
|
"reference": "John 6:63",
|
||||||
"verse": "The Spirit gives life, the flesh counts for nothing. The words I have spoken to you are spirit and they are life."
|
"verse": "The Spirit gives life, the flesh counts for nothing. The words I have spoken to you are spirit and they are life."
|
||||||
}
|
},
|
||||||
],
|
|
||||||
"dep-6-part-h": [
|
|
||||||
{
|
{
|
||||||
"pack": "DEP6",
|
"pack": "DEP6",
|
||||||
"chapterTitle": "Bridge Illustration",
|
"chapterTitle": "Bridge Illustration",
|
||||||
|
|
@ -1875,9 +1869,7 @@
|
||||||
"title": "God's solution - Forgiving us all our sins",
|
"title": "God's solution - Forgiving us all our sins",
|
||||||
"reference": "Colossians 2:13",
|
"reference": "Colossians 2:13",
|
||||||
"verse": "When you were dead in your sins and in the uncircumcision of your sinful nature, God made you alive with Christ. He forgave us all our sins."
|
"verse": "When you were dead in your sins and in the uncircumcision of your sinful nature, God made you alive with Christ. He forgave us all our sins."
|
||||||
}
|
},
|
||||||
],
|
|
||||||
"dep-6-part-i": [
|
|
||||||
{
|
{
|
||||||
"pack": "DEP6",
|
"pack": "DEP6",
|
||||||
"chapterTitle": "Bridge Illustration",
|
"chapterTitle": "Bridge Illustration",
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,11 @@ i18n
|
||||||
// for all options read: https://www.i18next.com/overview/configuration-options
|
// for all options read: https://www.i18next.com/overview/configuration-options
|
||||||
.init({
|
.init({
|
||||||
fallbackLng: 'en',
|
fallbackLng: 'en',
|
||||||
supportedLngs: ['en', 'kn'],
|
|
||||||
detection: { // adds some caching
|
detection: { // adds some caching
|
||||||
order: ['querystring', 'cookie', 'navigator', 'htmlTag', 'path', 'subdomain'],
|
order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag', 'path', 'subdomain'],
|
||||||
caches: ['cookie'], // Removed 'localStorage' to address Vivaldi mobile issue, kept 'cookie'
|
caches: ['localStorage', 'cookie'],
|
||||||
load: 'languageOnly'
|
|
||||||
},
|
},
|
||||||
debug: false,
|
debug: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default i18n;
|
export default i18n;
|
||||||
Loading…
Reference in New Issue