import { useState, useEffect, useRef } from "react"; import "./VerseValidator.css"; import { StringDiff } from "react-string-diff"; import { containsKorean, jamoSubstringMatch } from './utils'; const STATE = { INCORRECT: 0, PARTIAL: 1, CORRECT: 2, }; // function to render and handle logic of each of the cells const VerseValidator = ( { element: { pack, title, chapterTitle, reference, verse }, toHideReference, liveValidation, clearKey, t, index, onShowAnswer }) => { // useful use of destructuring here const [inputReference, setReference] = useState('') const [referenceBool, setReferenceBool] = useState(STATE.INCORRECT) const [inputChapterTitle, setChapterTitle] = useState('') const [chapterTitleBool, setChapterTitleBool] = useState(STATE.INCORRECT) const [inputTitle, setTitle] = useState('') const [titleBool, setTitleBool] = useState(STATE.INCORRECT) const [inputVerse, setVerse] = useState('') const [verseBool, setVerseBool] = useState(STATE.INCORRECT) const [hintBool, setHintBool] = useState(false) const [diffBool, setDiffBool] = 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 const handleReset = () => { setReference(''); setReferenceBool(STATE.INCORRECT); setChapterTitle(''); setChapterTitleBool(STATE.INCORRECT); setTitle(''); setTitleBool(STATE.INCORRECT); setVerse(''); setVerseBool(STATE.INCORRECT); setDiffBool(false); // optionally hide answer again setHintBool(false); // Reset hint counts setReferenceHintCount(0); setTitleHintCount(0); setChapterTitleHintCount(0); setVerseHintCount(0); }; // Handle the start of composition const handleCompositionStart = () => { setIsComposing(true); }; function resultChecker(string1, string2, liveValidation) { var result = STATE.INCORRECT; // init // contains korean if (containsKorean(string1)) { if (string1 === string2) { result = STATE.CORRECT; } else if (liveValidation && jamoSubstringMatch(string2, string1) & string1 !== "") { result = STATE.PARTIAL; } else { result = STATE.INCORRECT; } } else { // does not contain korean if (string1 === string2) { result = STATE.CORRECT; } else if (liveValidation && string2.startsWith(string1) & string1 !== "") { result = STATE.PARTIAL; } else { result = STATE.INCORRECT; } } return result; } // function to check correctness of reference input const validateReference = (value) => { const string1 = String(value) .replace(/\s+/g, "") .toLowerCase() .normalize("NFC"); const string2 = String(reference) .replace(/\s+/g, "") .toLowerCase() .normalize("NFC"); const result = resultChecker(string1, string2, liveValidation); setReferenceBool(result); }; const referenceClassName = `reference-box${ referenceBool === STATE.CORRECT ? " correct" : referenceBool === STATE.PARTIAL ? " partial" : " incorrect" }`; {/* function to check correctness of title input */} const validateTitle = (value) => { let string1 = value; let string2 = title; string1 = String(string1) .replace(/[\p{P}\p{S}]/gu, "") // Removes punctuation and symbols .replace(/\s+/g, "") // Removes all whitespace .toLowerCase() .normalize("NFC"); // Normalizes to NFC form string2 = String(string2) .replace(/[\p{P}\p{S}]/gu, "") .replace(/\s+/g, "") .toLowerCase() .normalize("NFC"); const result = resultChecker(string1, string2, liveValidation); setTitleBool(result); }; const titleClassName = `chapter-title-box${ titleBool=== STATE.CORRECT ? " correct" : titleBool === STATE.PARTIAL ? " partial" : " incorrect" }`; {/* function to check correctness of chapter title input */} const validateChapterTitle = (value) => { let string1 = value; let string2 = chapterTitle; string1 = String(string1) .replace(/[\p{P}\p{S}]/gu, "") .replace(/\s+/g, "") .toLowerCase() .normalize("NFC"); string2 = String(string2) .replace(/[\p{P}\p{S}]/gu, "") .replace(/\s+/g, "") .toLowerCase() .normalize("NFC"); const result = resultChecker(string1, string2, liveValidation); setChapterTitleBool(result); }; const chapterTitleClassName = `title-box${ chapterTitleBool=== STATE.CORRECT ? " correct" : chapterTitleBool === STATE.PARTIAL ? " partial" : " incorrect" }`; // check verse input const validateVerse = (value) => { let string1 = value; let string2 = verse; string1 = String(string1) .replace(/[\p{P}\p{S}]/gu, "") .replace(/\s+/g, "") .toLowerCase() .normalize("NFC"); string2 = String(string2) .replace(/[\p{P}\p{S}]/gu, "") .replace(/\s+/g, "") .toLowerCase() .normalize("NFC"); const result = resultChecker(string1, string2, liveValidation); setVerseBool(result); }; const verseClassName = `verse-box${ verseBool === STATE.CORRECT ? " correct" : verseBool === STATE.PARTIAL ? " partial" : " incorrect" }`; const DiffViewerStrict = ({oldValue, newValue}) => { const string1 = String(oldValue) .toLowerCase() .normalize("NFC"); const string2 = String(newValue) .toLowerCase() .normalize("NFC"); let diffStyle = { added: { backgroundColor: 'var(--background-color-added)' }, removed: { backgroundColor: 'var(--background-color-removed)' }, default: {} }; return () } return (

Verse {index}

{/* toggle hiding reference */} {toHideReference ? (