mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
[FEATURE] Ajout des rétroactions pour les questions à choix multiples et réponses courtes
Fixes #291
This commit is contained in:
parent
112062c0b2
commit
61a5cf1330
6 changed files with 168 additions and 50 deletions
|
|
@ -16,10 +16,11 @@ interface Props {
|
|||
const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = props;
|
||||
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
|
||||
const [isGoodAnswer, setisGoodAnswer] = useState<boolean>(false);
|
||||
|
||||
|
||||
let disableButton = false;
|
||||
if(handleOnSubmitAnswer === undefined){
|
||||
if (handleOnSubmitAnswer === undefined) {
|
||||
disableButton = true;
|
||||
}
|
||||
|
||||
|
|
@ -29,6 +30,15 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
|||
}
|
||||
}, [passedAnswer]);
|
||||
|
||||
useEffect(() => {
|
||||
checkAnswer();
|
||||
}, [answer]);
|
||||
|
||||
const checkAnswer = () => {
|
||||
const isCorrect = question.choices.some((choice) => choice.formattedText.text === answer as string);
|
||||
setisGoodAnswer(isCorrect);
|
||||
};
|
||||
|
||||
const handleOnClickAnswer = (choice: string) => {
|
||||
setAnswer(choice);
|
||||
};
|
||||
|
|
@ -36,7 +46,19 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
|||
const alphabet = alpha.map((x) => String.fromCharCode(x));
|
||||
return (
|
||||
|
||||
<div className="question-container">
|
||||
|
||||
<div className="question-wrapper">
|
||||
{showAnswer && (
|
||||
<div>
|
||||
<div className='question-feedback-validation'>
|
||||
{isGoodAnswer ? '✅ Correct! ' : '❌ Incorrect!'}
|
||||
</div>
|
||||
<div className="question-title">
|
||||
Question :
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)}
|
||||
<div className="question content">
|
||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
||||
</div>
|
||||
|
|
@ -51,8 +73,8 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
|||
className="button-wrapper"
|
||||
disabled={disableButton}
|
||||
onClick={() => !showAnswer && handleOnClickAnswer(choice.formattedText.text)}>
|
||||
{showAnswer? (<div> {(choice.isCorrect ? '✅' : '❌')}</div>)
|
||||
:``}
|
||||
{showAnswer ? (<div> {(choice.isCorrect ? '✅' : '❌')}</div>)
|
||||
: ``}
|
||||
<div className={`circle ${selected}`}>{alphabet[i]}</div>
|
||||
<div className={`answer-text ${selected}`}>
|
||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedText) }} />
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
|||
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } =
|
||||
props;
|
||||
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
|
||||
const [isGoodAnswer, setisGoodAnswer] = useState<boolean>(false);
|
||||
const correctAnswers = question.choices;
|
||||
let correctAnswer = '';
|
||||
|
||||
|
|
@ -27,6 +28,14 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
|||
}
|
||||
}, [passedAnswer]);
|
||||
|
||||
useEffect(() => {
|
||||
checkAnswer();
|
||||
}, [answer]);
|
||||
|
||||
const checkAnswer = () => {
|
||||
const isCorrect = correctAnswer === answer;
|
||||
setisGoodAnswer(isCorrect);
|
||||
};
|
||||
//const isSingleAnswer = correctAnswers.length === 1;
|
||||
|
||||
if (isSimpleNumericalAnswer(correctAnswers[0])) {
|
||||
|
|
@ -45,21 +54,40 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
|||
|
||||
return (
|
||||
<div className="question-wrapper">
|
||||
{showAnswer && (
|
||||
<div>
|
||||
<div className='question-feedback-validation'>
|
||||
{isGoodAnswer ? '✅ Correct! ' : '❌ Incorrect!'}
|
||||
</div>
|
||||
<div className="question-title">
|
||||
Question :
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
||||
</div>
|
||||
{showAnswer ? (
|
||||
<>
|
||||
<div className="correct-answer-text mb-2">
|
||||
<strong>La bonne réponse est: </strong>
|
||||
{correctAnswer}</div>
|
||||
<span>
|
||||
<strong>Votre réponse est: </strong>{answer.toString()}
|
||||
</span>
|
||||
<div className="correct-answer-text mb-1">
|
||||
<div>
|
||||
<div className="question-title">
|
||||
Réponse(s) accepté(es):
|
||||
</div>
|
||||
<div className="accepted-answers">
|
||||
{correctAnswer}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="question-title">
|
||||
Votre réponse est: </div>
|
||||
<div className="accepted-answers">{answer}</div>
|
||||
</div>
|
||||
</div>
|
||||
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
||||
</div>}
|
||||
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -17,34 +17,59 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
|||
|
||||
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = props;
|
||||
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
|
||||
const [isGoodAnswer, setisGoodAnswer] = useState<boolean>(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (passedAnswer !== undefined) {
|
||||
setAnswer(passedAnswer);
|
||||
}
|
||||
}, [passedAnswer]);
|
||||
console.log("Answer" , answer);
|
||||
|
||||
useEffect(() => {
|
||||
checkAnswer();
|
||||
}, [answer]);
|
||||
|
||||
const checkAnswer = () => {
|
||||
const isCorrect = question.choices.some((choice) => choice.text.toLowerCase() === (answer as String).toLowerCase());
|
||||
setisGoodAnswer(isCorrect);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<div className="question-wrapper">
|
||||
<div className="question content">
|
||||
{showAnswer && (
|
||||
<div>
|
||||
<div className='question-feedback-validation'>
|
||||
{isGoodAnswer ? '✅ Correct! ' : '❌ Incorrect!'}
|
||||
</div>
|
||||
<div className="question-title">
|
||||
Question :
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
||||
</div>
|
||||
{showAnswer ? (
|
||||
<>
|
||||
<div className="correct-answer-text mb-1">
|
||||
<span>
|
||||
<strong>La bonne réponse est: </strong>
|
||||
|
||||
<div>
|
||||
<div className="question-title">
|
||||
Réponse(s) accepté(es):
|
||||
</div>
|
||||
{question.choices.map((choice) => (
|
||||
<div key={choice.text} className="mb-1">
|
||||
<div key={choice.text} className="accepted-answers">
|
||||
{choice.text}
|
||||
</div>
|
||||
))}
|
||||
</span>
|
||||
<span>
|
||||
<strong>Votre réponse est: </strong>{answer}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div className="question-title">
|
||||
Votre réponse est: </div>
|
||||
<div className="accepted-answers">{answer}</div>
|
||||
</div>
|
||||
</div>
|
||||
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
||||
|
|
|
|||
|
|
@ -47,7 +47,19 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
|||
const selectedTrue = answer ? 'selected' : '';
|
||||
const selectedFalse = answer !== undefined && !answer ? 'selected' : '';
|
||||
return (
|
||||
<div className="question-container">
|
||||
<div className="question-wrapper">
|
||||
{showAnswer && (
|
||||
<div>
|
||||
<div className='question-feedback-validation'>
|
||||
{question.isTrue? '✅ Correct! ' : '❌ Incorrect!'}
|
||||
</div>
|
||||
<div className="question-title">
|
||||
Question :
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="question content">
|
||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
|
@ -22,7 +21,6 @@
|
|||
.question-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
|
@ -136,12 +134,12 @@
|
|||
/* height: 1em; */
|
||||
}
|
||||
|
||||
|
||||
.global-feedback {
|
||||
position: relative;
|
||||
padding: 0 1rem;
|
||||
background-color: hsl(43, 100%, 94%);
|
||||
color: hsl(43, 95%, 9%);
|
||||
margin-top: 2rem;
|
||||
border: hsl(36, 84%, 93%) 1px solid;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 2px 5px hsl(0, 0%, 74%);
|
||||
|
|
@ -169,3 +167,39 @@
|
|||
.choices-wrapper {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.correct-answer-text {
|
||||
text-align: left; /* Align text to the left */
|
||||
width: 100%; /* Ensure it takes the full width of its container */
|
||||
}
|
||||
|
||||
.accepted-answers {
|
||||
display: inline-block; /* Display elements side by side */
|
||||
border-radius: 6px; /* Add rounded corners */
|
||||
padding: 0.5rem; /* Add padding for spacing */
|
||||
margin: 0.5rem; /* Add margin for spacing between elements */
|
||||
background-color: hsl(0, 0%, 87%); /* Optional: Add a background color for emphasis */
|
||||
}
|
||||
.question-feedback-validation{
|
||||
font-size: 1.8rem; /* Increase the font size */
|
||||
font-weight: bold; /* Make the text bold */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
}
|
||||
.question-title{
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 1.5rem;
|
||||
width: 100%;
|
||||
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.question-content{
|
||||
margin-bottom: 1rem;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import QuestionComponent from '../QuestionsDisplay/QuestionDisplay';
|
|||
import '../../pages/Student/JoinRoom/joinRoom.css';
|
||||
import { QuestionType } from '../../Types/QuestionType';
|
||||
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
|
||||
import { Dialog, DialogContent, DialogActions, Button } from '@mui/material';
|
||||
import { Question } from 'gift-pegjs';
|
||||
import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService';
|
||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
||||
|
|
@ -94,7 +94,6 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
|||
open={isFeedbackDialogOpen}
|
||||
onClose={handleFeedbackDialogClose}
|
||||
>
|
||||
<DialogTitle>Rétroaction</DialogTitle>
|
||||
<DialogContent>
|
||||
<div style={{
|
||||
wordWrap: 'break-word',
|
||||
|
|
@ -102,8 +101,6 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
|||
maxHeight: '400px',
|
||||
overflowY: 'auto',
|
||||
}}>
|
||||
<div style={{ textAlign: 'left', fontWeight: 'bold', marginTop: '10px' }}
|
||||
>Question : </div>
|
||||
</div>
|
||||
|
||||
<QuestionComponent
|
||||
|
|
|
|||
Loading…
Reference in a new issue