@@ -12,7 +12,7 @@ | |||||
font-size: 1.2rem; | font-size: 1.2rem; | ||||
font-weight: 700; | font-weight: 700; | ||||
color: white; | color: white; | ||||
background-color: var(--teal); | |||||
background-color: var(--red); | |||||
margin: 0 auto; | margin: 0 auto; | ||||
display: block; | display: block; | ||||
border: none; | border: none; | ||||
@@ -3,33 +3,100 @@ import styles from './Revise.module.scss'; | |||||
import { Question } from "./question/Question"; | import { Question } from "./question/Question"; | ||||
import { Summary } from "./summary/Summary"; | import { Summary } from "./summary/Summary"; | ||||
import { recollectionQuestions } from "../../services/recollectionquestions"; | |||||
import { MongoShelfWord } from "../../shared/models/shelf"; | |||||
interface WordWithShelfId extends MongoShelfWord { | |||||
shelfId: string | |||||
} | |||||
import { recollectionQuestions, updateRecollectionQuestion } from "../../services/recollectionquestions"; | |||||
import { MobileShelf } from "../../shared/models/shelf"; | |||||
import { MobileUser } from "../../shared/models/user"; | |||||
export const Revise: React.FC = () => { | export const Revise: React.FC = () => { | ||||
const [progressState, setProgressState] = useState<'INTRO' | 'QUESTION' | 'END'>('QUESTION'); | const [progressState, setProgressState] = useState<'INTRO' | 'QUESTION' | 'END'>('QUESTION'); | ||||
const [questions, setQuestions] = useState<Array<WordWithShelfId>>([]); | |||||
const [questions, setQuestions] = useState<Array<any>>([]); | |||||
const [answeredQuestions, setAnsweredQuestion] = useState<Array<{ | |||||
wordId: string, | |||||
hasRecalled: boolean | |||||
}>>([]); | |||||
const [currentQuestion, setCurrentQuestion] = useState<number>(0); | |||||
useEffect(() => { | useEffect(() => { | ||||
recollectionQuestions().then((response: any) => { | recollectionQuestions().then((response: any) => { | ||||
setQuestions(response.data); | |||||
let questions: Array<any> = response.data; | |||||
const curatedQuestions: Array<any> = []; | |||||
let allShelves: Array<MobileShelf> = []; | |||||
const userProfile: MobileUser = JSON.parse(localStorage.getItem('userProfile') || ""); | |||||
userProfile.categories.forEach(category => { | |||||
category.shelves?.forEach((shelf) => { | |||||
allShelves.push(shelf); | |||||
}); | |||||
}); | |||||
questions.forEach((question) => { | |||||
let index = allShelves.findIndex(shelf => shelf._id === question.shelfId); | |||||
if (index !== undefined) { | |||||
const word = allShelves[index].words?.find(word => word.word._id === question.word)?.word; | |||||
if (word !== undefined) { | |||||
curatedQuestions.push({ | |||||
...question, | |||||
word: word | |||||
}) | |||||
} | |||||
} | |||||
}); | |||||
setQuestions(curatedQuestions); | |||||
if (curatedQuestions.length === 0) { | |||||
setProgressState('END'); | |||||
} | |||||
}, (e) => { | }, (e) => { | ||||
window.alert("Failed to get questions"); | window.alert("Failed to get questions"); | ||||
console.log(e); | console.log(e); | ||||
}); | }); | ||||
}, []); | }, []); | ||||
return <section className={styles.revisePage}> | return <section className={styles.revisePage}> | ||||
{ progressState === 'QUESTION' && <div> | { progressState === 'QUESTION' && <div> | ||||
<Question /> | |||||
{ questions.map((question, index) => { | |||||
return currentQuestion === index && <Question key={index} totalQuestions={questions.length} questionNumber={currentQuestion} | |||||
word={question.word} | |||||
selectOption={(flag) => { | |||||
let temp = answeredQuestions; | |||||
temp.push({ | |||||
wordId: question.word._id, | |||||
hasRecalled: flag, | |||||
}); | |||||
setAnsweredQuestion(temp); | |||||
console.log(question) | |||||
setTimeout(() => { | |||||
if (currentQuestion < questions.length - 1) { | |||||
setCurrentQuestion(currentQuestion + 1); | |||||
} else { | |||||
setProgressState('END'); | |||||
} | |||||
updateRecollectionQuestion(question.shelfId, question.word._id, flag); | |||||
}, 200); | |||||
}} /> | |||||
}) } | |||||
<button className={styles.finishButton} onClick={() => setProgressState('END')}> | <button className={styles.finishButton} onClick={() => setProgressState('END')}> | ||||
Finish | |||||
Done | |||||
</button> | </button> | ||||
</div> } | </div> } | ||||
@@ -33,7 +33,7 @@ | |||||
p { | p { | ||||
font-size: 1.2rem; | font-size: 1.2rem; | ||||
font-weight: 500; | font-weight: 500; | ||||
color: var(--black); | |||||
color: var(--grey); | |||||
} | } | ||||
.checkmark { | .checkmark { | ||||
@@ -1,43 +1,33 @@ | |||||
import React from "react"; | |||||
import React, { useState } from "react"; | |||||
import styles from './Options.module.scss'; | import styles from './Options.module.scss'; | ||||
import { ReactComponent as CheckCircleIcon } from '../../../assets/icons/check.svg'; | import { ReactComponent as CheckCircleIcon } from '../../../assets/icons/check.svg'; | ||||
export const Options: React.FC = () => { | |||||
return <ul className={styles.optionsHolder}> | |||||
<li className={styles.active}> | |||||
<p> | |||||
Argentina & Leo Messi | |||||
</p> | |||||
<div className={styles.checkmark}> | |||||
<CheckCircleIcon /> | |||||
</div> | |||||
</li> | |||||
<li> | |||||
<p> | |||||
Brazil & Neymar | |||||
</p> | |||||
<div className={styles.checkmark}> | |||||
</div> | |||||
</li> | |||||
type OwnProps = { | |||||
options: Array<{ | |||||
text: string, | |||||
function:() => void, | |||||
}> | |||||
} | |||||
<li> | |||||
<p> | |||||
Chile & Sanchez | |||||
</p> | |||||
<div className={styles.checkmark}> | |||||
</div> | |||||
</li> | |||||
export const Options: React.FC<OwnProps> = (props) => { | |||||
const [selectedOption, setSelectedOption] = useState<{ | |||||
text: string, | |||||
function:() => void, | |||||
} | undefined>(); | |||||
<li> | |||||
<p> | |||||
Mexico & Chicharito | |||||
</p> | |||||
<div className={styles.checkmark}> | |||||
</div> | |||||
</li> | |||||
</ul>; | |||||
return <ul className={styles.optionsHolder}> | |||||
{ props.options.map((option, index) => { | |||||
return <li key={index} className={selectedOption === option ? styles.active : ''} onClick={() => { | |||||
option.function(); | |||||
setSelectedOption(option); | |||||
}}> | |||||
<p> | |||||
{ option.text } | |||||
</p> | |||||
{ selectedOption === option && <div className={styles.checkmark} > | |||||
<CheckCircleIcon /> | |||||
</div> } | |||||
</li> | |||||
}) } | |||||
</ul>; | |||||
} | } |
@@ -1,7 +1,7 @@ | |||||
$common-width: calc(100% - 4rem); | $common-width: calc(100% - 4rem); | ||||
.questionHolder { | .questionHolder { | ||||
height: calc(100vh - 8rem); | |||||
height: calc(100vh - 6rem); | |||||
padding-top: 2rem; | padding-top: 2rem; | ||||
overflow: auto; | overflow: auto; | ||||
} | } | ||||
@@ -76,4 +76,52 @@ $common-width: calc(100% - 4rem); | |||||
.answerTypes { | .answerTypes { | ||||
width: #{$common-width}; | width: #{$common-width}; | ||||
margin: 0 auto 2rem; | margin: 0 auto 2rem; | ||||
} | |||||
.meaning { | |||||
width: $common-width; | |||||
margin: 0 auto 2rem; | |||||
list-style: none; | |||||
position: relative; | |||||
&::before { | |||||
content: ''; | |||||
left: 0; | |||||
top: 0; | |||||
width: 100%; | |||||
height: 100%; | |||||
background-color: var(--lighter-grey); | |||||
position: absolute; | |||||
border-radius: 5px; | |||||
opacity: 0.95; | |||||
transition: opacity 0.5s; | |||||
} | |||||
&.unblock { | |||||
&::before { | |||||
opacity: 0; | |||||
} | |||||
} | |||||
li { | |||||
margin-bottom: 1rem; | |||||
} | |||||
p { | |||||
font-size: 14px; | |||||
color: var(--light-grey); | |||||
span { | |||||
vertical-align: middle; | |||||
} | |||||
} | |||||
} | |||||
.caption { | |||||
font-size: 14px; | |||||
color: var(--light-grey); | |||||
font-style: italic; | |||||
width: $common-width; | |||||
margin: 0 auto 2rem; | |||||
} | } |
@@ -1,22 +1,48 @@ | |||||
import React from "react"; | |||||
import React, { useState } from "react"; | |||||
import styles from './Question.module.scss'; | import styles from './Question.module.scss'; | ||||
import { ReactComponent as TimeIcon } from '../../../assets/icons/timer.svg'; | |||||
import { Options } from "../options/Options"; | import { Options } from "../options/Options"; | ||||
import { Word } from "../../../shared/models/word"; | |||||
type OwnProps = { | |||||
questionNumber: number, | |||||
totalQuestions: number, | |||||
word: Word, | |||||
selectOption: (hasRecalled: boolean) => void, | |||||
} | |||||
export const Question: React.FC<OwnProps> = (props) => { | |||||
const [isMeaningShown, setShowMeaning] = useState<boolean>(false); | |||||
export const Question: React.FC = () => { | |||||
return <section className={styles.questionHolder}> | return <section className={styles.questionHolder}> | ||||
<div className={styles.progressBarHolder}> | <div className={styles.progressBarHolder}> | ||||
<span className={styles.progressBar} style={{width: '60%'}}></span> | |||||
<span className={styles.text}> 30 </span> | |||||
<TimeIcon /> | |||||
<span className={styles.progressBar} style={{width: (props.questionNumber / props.totalQuestions * 100) + '%'}}></span> | |||||
{/* <span className={styles.text}> 30 </span> | |||||
<TimeIcon /> */} | |||||
</div> | </div> | ||||
<h3 className={styles.questionCount}> Question 10/<span>10</span> </h3> | |||||
<h3 className={styles.questionCount}> Question {props.questionNumber + 1} / <span> { props.totalQuestions } </span> </h3> | |||||
<h3 className={styles.question}> Do you recall this word? <br /> <strong> { props.word.name } </strong> </h3> | |||||
<ol className={styles.meaning + ' ' + (isMeaningShown ? styles.unblock : '')} | |||||
onClick={() => setShowMeaning(true)}> | |||||
{ props.word.grammaticalDetails.map((detail, index) => { | |||||
return <li key={index}> | |||||
<p> <span> - </span> { detail.description } </p> | |||||
</li> | |||||
}) } | |||||
</ol> | |||||
<h3 className={styles.question}> Who won Copa America 2021 and who was the Captian? </h3> | |||||
{ !isMeaningShown && <p className={styles.caption}> Tap on the blocked section to see the meaning </p> } | |||||
<section className={styles.answerTypes}> | <section className={styles.answerTypes}> | ||||
<Options /> | |||||
<Options options={[{ | |||||
text: 'Yes', | |||||
function: () => props.selectOption(true) | |||||
}, { | |||||
text: 'No', | |||||
function: () => props.selectOption(false) | |||||
}]} /> | |||||
</section> | </section> | ||||
</section> | </section> | ||||
} | } |