Skip to content

Commit

Permalink
Tried to mock backend with simple Promise simulation.
Browse files Browse the repository at this point in the history
  • Loading branch information
sklykov committed Aug 27, 2024
1 parent 05f15f0 commit 11a4750
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 50 deletions.
2 changes: 1 addition & 1 deletion lang_quiz_react/src/components/QuizSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function QuizSection({quizState, setQuizState, userInfo}) {
// Returning the quiz game field and the button for ending it
return (
<section>
<QuizManager userInfo={userInfo} quizType={quizState.quizType} />
<QuizManager userInfo={userInfo} quizState={quizState} />
<StartQuiz quizState={quizState} setQuizState={setQuizState} />
</section>
);
Expand Down
43 changes: 36 additions & 7 deletions lang_quiz_react/src/components/quiz_data/Nouns.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,46 @@ const nouns_data = [
{"noun_id": 8, noun: "Abbruch", en_noun: "cancellation", article: "der", right_answers: 0, learnt: false},
{"noun_id": 9, noun: "Gepäck", en_noun: "luggage, baggage", article: "das", right_answers: 0, learnt: false},
{"noun_id": 10, noun: "Zweifel", en_noun: "doubt", article: "der", right_answers: 0, learnt: false},
{"noun_id": 11, noun: "Hintergrund", en_noun: "experience", article: "der", right_answers: 0, learnt: false}
{"noun_id": 11, noun: "Hintergrund", en_noun: "experience", article: "der", right_answers: 0, learnt: false},
{"noun_id": 12, noun: "Angebot", en_noun: "offer", article: "das", right_answers: 0, learnt: false}
]

function getNounsSlice(n_words, userCredentials) {
// function returning Promise with the sliced data from the array above
export function getNounsSlice(n_words, userCredentials, learntNouns) {
let response = new Promise((resolve, reject) => {
const n_nouns = nouns_data.length;
if ((n_words <= n_nouns) && (userCredentials.user === "demo") ) {

let n_nouns = nouns_data.length; let initialData = nouns_data.slice();
// Filter out the already learnt nouns from the initial array with words
let nounsFiltered = false;
if (learntNouns.length > 0) {
for (let learntNoun of learntNouns) {
let indexEl = initialData.indexOf(learntNoun); // find the learnt noun
if (indexEl > -1) {
initialData.splice(indexEl, 1); // remove the learnt noun
if (!nounsFiltered) nounsFiltered = true;
}
}
}
if (nounsFiltered) {
n_nouns = initialData.length;
}
// Select random slice of words for returning, set resolve and reject answers
let responseTime = Math.round(Math.random()*100) + 20; // random ms response time from the specified range
// console.log("Expected response time:", responseTime);
if ((n_words <= n_nouns) && (userCredentials.user === "demo")) {
let nounsSlice = [];
// Randomly select and return the slice of
for (let i=0; i < n_words; i++) {
let iRandom = Math.floor(Math.random()*initialData.length);
nounsSlice.push(initialData[iRandom]); initialData.splice(iRandom, 1);
}
setTimeout(resolve(nounsSlice), responseTime); // send the found slice with nouns
} else {

if (n_words > n_nouns) {
setTimeout(reject("# of requested words is larger than the remained not learnt nouns"), responseTime);
} else {
setTimeout(reject("User not found"), responseTime);
}
}
});
return response;
}
}
110 changes: 78 additions & 32 deletions lang_quiz_react/src/components/quiz_types/NounArticleQuiz.jsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,105 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import styles from './NounArticleQuiz.module.css';
import { getNounsSlice } from '../quiz_data/Nouns';

let variants = ["der", "die", "das"]; // 3 base articles - fixed answer variants

// Fetch the information for setting up the quiz
function fetchUserData(userCredentials) {
// console.log("Logged in:", userCredentials);
let data = null;

if (userCredentials.user === "demo") {
data = {
noun: "Heimat", article: "die",
};
}
return data;
}

// Shuffle array function from the https://javascript.info/task/shuffle (Fisher-Yates shuffle algorithm)
// This function is used for shuffle the 3 variants of articles
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}

// Component function
// Component function for the preparing quiz question about the article of the noun
export default function NounArticleQuiz({userInfo}) {
let quizLength = 5; // number of words for fetching and asking during the quiz

let quizData = fetchUserData(userInfo);
const [quizGoing, setQuizState] = useState(true);
const [currentQuestion, setCurrentQuestion] = useState(null);
const [indexQuestion, setCurrentIndexQuestion] = useState(0);
const [fetchingData, setFetchingData] = useState(false);
const [quizNouns, setQuizNouns] = useState([]);
const [errorMessage, setErrorMessage] = useState("");

useEffect(() => {
// Definition of the function for retrieving data from the simulated backend
async function retrieveData() {
setFetchingData(true);
console.log("Start Retrieving data...");
try {
setQuizNouns(await getNounsSlice(quizLength, userInfo, []));
} catch (error) {
setQuizNouns([]); setErrorMessage(String(error));
}
setFetchingData(false);
console.log("Stop Retrieving data.");
}
retrieveData();
}, [quizLength, userInfo]);

// below - set the first question
useEffect(() => {
if (quizNouns.length > 0) {
setCurrentQuestion(quizNouns[0]); setCurrentIndexQuestion((prevIndex) => prevIndex + 1);
}}, [quizNouns]);

useEffect(() => {shuffle(variants)}, [quizData.noun]); // shuffle the array if noun has been changed
useEffect(() => {shuffle(variants)}, [currentQuestion]); // shuffle the array if noun has been changed

// Handle click on the variant of an answer
function handleVariantSelection(e) {
if (e.target.innerText === quizData.article) {
if (e.target.innerText === currentQuestion.article) {
console.log("Right answer!");
} else {
console.log("Wrong answer!");
}
if (indexQuestion < quizLength) {
setCurrentQuestion(quizNouns[indexQuestion]);
setCurrentIndexQuestion((prevIndex) => prevIndex + 1);
} else {
setQuizState(false);
}
}

// JSX forming
if (quizData !== null) {
return (
return(
<>
{quizGoing && fetchingData && <div> Waiting for data coming from the backend ... </div>}
{quizGoing && !fetchingData && currentQuestion !== null && (
<div className={styles.quizBox}>
<div lang="de"> Select proper article for: <span className={styles.noun}>{quizData.noun}</span> </div>
<ul className={styles.variantsBox}>
{variants.map(variant => {
// Note that always the HTML tags should be always returned to be rendered and displayed
return (<li lang="de" key={variant} className={styles.variant} onClick={handleVariantSelection}>{variant}</li>);
})}
</ul>
</div>
);
} else {
return <div> User Not Found, cannot set up Quiz... </div>
}
<div lang="de"> Select proper article for: <span className={styles.noun}>{currentQuestion.noun}</span> </div>
<ul className={styles.variantsBox}>
{variants.map(variant => {
// Note that always the HTML tags should be always returned to be rendered and displayed
return (<li lang="de" key={variant} className={styles.variant} onClick={handleVariantSelection}>{variant}</li>);
})}
</ul>
</div>
)}
{!quizGoing && !fetchingData && currentQuestion === null && <div> Rejected with the message: {errorMessage} </div>}
{!quizGoing && <div> Quiz finished. </div>}
</>
);

// if (quizGoing && !fetchingData && currentQuestion !== null) {
// return (
// <div className={styles.quizBox}>
// <div lang="de"> Select proper article for: <span className={styles.noun}>{currentQuestion.noun}</span> </div>
// <ul className={styles.variantsBox}>
// {variants.map(variant => {
// // Note that always the HTML tags should be always returned to be rendered and displayed
// return (<li lang="de" key={variant} className={styles.variant} onClick={handleVariantSelection}>{variant}</li>);
// })}
// </ul>
// </div>
// );
// } else if (quizGoing && fetchingData) {
// return <div> Waiting for data coming from the backend ... </div>;
// } else if (quizGoing && !fetchingData && currentQuestion === null) {
// return <div> Rejected with the message: {errorMessage} </div>;
// } else if (!quizGoing) {
// return <div> Quiz finished. </div>;
// }
}
22 changes: 12 additions & 10 deletions lang_quiz_react/src/components/quiz_types/QuizManager.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import NounArticleQuiz from "./NounArticleQuiz";

export default function QuizManager({ userInfo, quizType }) {
export default function QuizManager({ userInfo, quizState }) {

return (
<div>
{quizType === "Article for Noun" ? (
<NounArticleQuiz userInfo={userInfo}/>
) : (
<div> Flipping Cards Quiz Placeholder </div>
)}
</div>
);
if (quizState.started) {
return (
<div>
{quizState.quizType === "Article for Noun" ? (
<NounArticleQuiz userInfo={userInfo}/>
) : (
<div> Flipping Cards Quiz Placeholder </div>
)}
</div>
);
}
}

0 comments on commit 11a4750

Please sign in to comment.