This commit is contained in:
Juba.M 2025-03-20 17:14:35 -04:00 committed by GitHub
commit c65fea8399
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 363 additions and 114 deletions

View file

@ -1,44 +1,21 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import { NumericalQuestion, parse, ParsedGIFTQuestion } from 'gift-pegjs'; import { render, screen, fireEvent } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom'; import { parse, NumericalQuestion } from 'gift-pegjs';
import React from 'react';
import NumericalQuestionDisplay from 'src/components/QuestionsDisplay/NumericalQuestionDisplay/NumericalQuestionDisplay'; import NumericalQuestionDisplay from 'src/components/QuestionsDisplay/NumericalQuestionDisplay/NumericalQuestionDisplay';
const questions = parse( describe('NumericalQuestionDisplay Component', () => {
`
::Sample Question 1:: Question stem
{
#5..10
}`
) as ParsedGIFTQuestion[];
const question = questions[0] as NumericalQuestion;
describe('NumericalQuestion parse', () => {
const q = questions[0];
it('The question is Numerical', () => {
expect(q.type).toBe('Numerical');
});
});
describe('NumericalQuestion Component', () => {
const mockHandleOnSubmitAnswer = jest.fn(); const mockHandleOnSubmitAnswer = jest.fn();
const question =
parse('::Sample Numerical Question:: What is 2+2? {#4}')[0] as NumericalQuestion;
const sampleProps = { const sampleProps = {
question: question,
handleOnSubmitAnswer: mockHandleOnSubmitAnswer, handleOnSubmitAnswer: mockHandleOnSubmitAnswer,
showAnswer: false showAnswer: false
}; };
beforeEach(() => { beforeEach(() => {
render( render(<NumericalQuestionDisplay question={question} {...sampleProps} />);
<MemoryRouter>
<NumericalQuestionDisplay
{...sampleProps}
/>
</MemoryRouter>);
}); });
it('renders correctly', () => { it('renders correctly', () => {
@ -55,13 +32,13 @@ describe('NumericalQuestion Component', () => {
expect(inputElement.value).toBe('7'); expect(inputElement.value).toBe('7');
}); });
it('Submit button should be disable if nothing is entered', () => { it('Submit button should be disabled if nothing is entered', () => {
const submitButton = screen.getByText('Répondre'); const submitButton = screen.getByText('Répondre');
expect(submitButton).toBeDisabled(); expect(submitButton).toBeDisabled();
}); });
it('not submited answer if nothing is entered', () => { it('does not submit answer if nothing is entered', () => {
const submitButton = screen.getByText('Répondre'); const submitButton = screen.getByText('Répondre');
fireEvent.click(submitButton); fireEvent.click(submitButton);
@ -79,4 +56,52 @@ describe('NumericalQuestion Component', () => {
expect(mockHandleOnSubmitAnswer).toHaveBeenCalledWith(7); expect(mockHandleOnSubmitAnswer).toHaveBeenCalledWith(7);
}); });
});
it('renders correctly with the correct answer shown', () => {
render(<NumericalQuestionDisplay question={question} {...sampleProps} showAnswer={true} passedAnswer={4} />);
expect(screen.getByText('Réponse(s) accepté(es):')).toBeInTheDocument();
expect(screen.getAllByText('4')).toHaveLength(2);
});
it('handles input change and checks if the answer is correct', () => {
const inputElement = screen.getByTestId('number-input') as HTMLInputElement;
fireEvent.change(inputElement, { target: { value: '4' } });
expect(inputElement.value).toBe('4');
const submitButton = screen.getByText('Répondre');
fireEvent.click(submitButton);
expect(mockHandleOnSubmitAnswer).toHaveBeenCalledWith(4);
});
it('submits the correct answer', () => {
const inputElement = screen.getByTestId('number-input') as HTMLInputElement;
fireEvent.change(inputElement, { target: { value: '4' } });
const submitButton = screen.getByText('Répondre');
fireEvent.click(submitButton);
expect(mockHandleOnSubmitAnswer).toHaveBeenCalledWith(4);
});
it('submits an incorrect answer', () => {
const inputElement = screen.getByTestId('number-input') as HTMLInputElement;
fireEvent.change(inputElement, { target: { value: '5' } });
const submitButton = screen.getByText('Répondre');
fireEvent.click(submitButton);
expect(mockHandleOnSubmitAnswer).toHaveBeenCalledWith(5);
});
it('displays feedback when the answer is shown', () => {
render(<NumericalQuestionDisplay question={question} {...sampleProps} showAnswer={true} passedAnswer={5} />);
expect(screen.getByText('❌ Incorrect!')).toBeInTheDocument();
expect(screen.getByText('Réponse(s) accepté(es):')).toBeInTheDocument();
expect(screen.getByText('5')).toBeInTheDocument();
});
});

View file

@ -1,7 +1,7 @@
import React from 'react';
import { render, screen, fireEvent, within } from '@testing-library/react';
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import { render, screen, fireEvent } from '@testing-library/react';
import { parse, ShortAnswerQuestion } from 'gift-pegjs'; import { parse, ShortAnswerQuestion } from 'gift-pegjs';
import React from 'react';
import ShortAnswerQuestionDisplay from 'src/components/QuestionsDisplay/ShortAnswerQuestionDisplay/ShortAnswerQuestionDisplay'; import ShortAnswerQuestionDisplay from 'src/components/QuestionsDisplay/ShortAnswerQuestionDisplay/ShortAnswerQuestionDisplay';
describe('ShortAnswerQuestion Component', () => { describe('ShortAnswerQuestion Component', () => {
@ -20,28 +20,26 @@ describe('ShortAnswerQuestion Component', () => {
it('renders correctly', () => { it('renders correctly', () => {
expect(screen.getByText(question.formattedStem.text)).toBeInTheDocument(); expect(screen.getByText(question.formattedStem.text)).toBeInTheDocument();
const container = screen.getByLabelText('short-answer-input'); const inputElement = screen.getByRole('textbox') as HTMLInputElement;
const inputElement = within(container).getByRole('textbox') as HTMLInputElement;
expect(inputElement).toBeInTheDocument(); expect(inputElement).toBeInTheDocument();
expect(screen.getByText('Répondre')).toBeInTheDocument(); expect(screen.getByText('Répondre')).toBeInTheDocument();
}); });
it('handles input change correctly', () => { it('handles input change correctly', () => {
const container = screen.getByLabelText('short-answer-input'); const inputElement = screen.getByRole('textbox') as HTMLInputElement;
const inputElement = within(container).getByRole('textbox') as HTMLInputElement;
fireEvent.change(inputElement, { target: { value: 'User Input' } }); fireEvent.change(inputElement, { target: { value: 'User Input' } });
expect(inputElement.value).toBe('User Input'); expect(inputElement.value).toBe('User Input');
}); });
it('Submit button should be disable if nothing is entered', () => { it('Submit button should be disabled if nothing is entered', () => {
const submitButton = screen.getByText('Répondre'); const submitButton = screen.getByText('Répondre');
expect(submitButton).toBeDisabled(); expect(submitButton).toBeDisabled();
}); });
it('not submitted answer if nothing is entered', () => { it('does not submit answer if nothing is entered', () => {
const submitButton = screen.getByText('Répondre'); const submitButton = screen.getByText('Répondre');
fireEvent.click(submitButton); fireEvent.click(submitButton);
@ -49,17 +47,51 @@ describe('ShortAnswerQuestion Component', () => {
expect(mockHandleSubmitAnswer).not.toHaveBeenCalled(); expect(mockHandleSubmitAnswer).not.toHaveBeenCalled();
}); });
it('submits answer correctly', () => { it('renders correctly with the correct answer shown', () => {
const container = screen.getByLabelText('short-answer-input'); render(<ShortAnswerQuestionDisplay question={question} {...sampleProps} showAnswer={true} passedAnswer="Correct Answer" />);
const inputElement = within(container).getByRole('textbox') as HTMLInputElement; expect(screen.getByText('Réponse(s) accepté(es):')).toBeInTheDocument();
expect(screen.getByText('Correct Answer')).toBeInTheDocument();
});
it('handles input change and checks if the answer is correct', () => {
const inputElement = screen.getByRole('textbox') as HTMLInputElement;
fireEvent.change(inputElement, { target: { value: 'Correct Answer' } });
expect(inputElement.value).toBe('Correct Answer');
// const inputElement = screen.getByRole('textbox', { name: 'short-answer-input'}) as HTMLInputElement;
const submitButton = screen.getByText('Répondre'); const submitButton = screen.getByText('Répondre');
fireEvent.change(inputElement, { target: { value: 'User Input' } });
fireEvent.click(submitButton); fireEvent.click(submitButton);
expect(mockHandleSubmitAnswer).toHaveBeenCalledWith('User Input'); expect(mockHandleSubmitAnswer).toHaveBeenCalledWith('Correct Answer');
}); });
});
it('submits the correct answer', () => {
const inputElement = screen.getByRole('textbox') as HTMLInputElement;
fireEvent.change(inputElement, { target: { value: 'Correct Answer' } });
const submitButton = screen.getByText('Répondre');
fireEvent.click(submitButton);
expect(mockHandleSubmitAnswer).toHaveBeenCalledWith('Correct Answer');
});
it('submits an incorrect answer', () => {
const inputElement = screen.getByRole('textbox') as HTMLInputElement;
fireEvent.change(inputElement, { target: { value: 'Incorrect Answer' } });
const submitButton = screen.getByText('Répondre');
fireEvent.click(submitButton);
expect(mockHandleSubmitAnswer).toHaveBeenCalledWith('Incorrect Answer');
});
it('displays feedback when the answer is shown', () => {
render(<ShortAnswerQuestionDisplay question={question} {...sampleProps} showAnswer={true} passedAnswer="Incorrect Answer" />);
expect(screen.getByText('❌ Incorrect!')).toBeInTheDocument();
expect(screen.getByText('Réponse(s) accepté(es):')).toBeInTheDocument();
expect(screen.getByText('Incorrect Answer')).toBeInTheDocument();
});
});

View file

@ -66,6 +66,18 @@ describe('TeacherModeQuiz', () => {
expect(mockSubmitAnswer).toHaveBeenCalledWith('Option A', 1); expect(mockSubmitAnswer).toHaveBeenCalledWith('Option A', 1);
}); });
test('handles shows feedback for answered question', () => {
act(() => {
fireEvent.click(screen.getByText('Option B'));
});
act(() => {
fireEvent.click(screen.getByText('Répondre'));
});
expect(mockSubmitAnswer).toHaveBeenCalledWith('Option B', 1)
expect(screen.getByText('❌ Incorrect!')).toBeInTheDocument();
});
test('handles shows feedback for an already answered question', () => { test('handles shows feedback for an already answered question', () => {
// Answer the first question // Answer the first question
act(() => { act(() => {
@ -106,7 +118,7 @@ describe('TeacherModeQuiz', () => {
}); });
// Check if the feedback dialog is shown again // Check if the feedback dialog is shown again
expect(screen.getByText('Rétroaction')).toBeInTheDocument(); expect(screen.getByText('❌ Incorrect!')).toBeInTheDocument();
}); });
test('handles disconnect button click', () => { test('handles disconnect button click', () => {

View file

@ -16,19 +16,29 @@ interface Props {
const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => { const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = props; const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = props;
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || ''); const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
const [isGoodAnswer, setisGoodAnswer] = useState<boolean>(false);
let disableButton = false; let disableButton = false;
if(handleOnSubmitAnswer === undefined){ if (handleOnSubmitAnswer === undefined) {
disableButton = true; disableButton = true;
} }
useEffect(() => { useEffect(() => {
if (passedAnswer !== undefined) { if (passedAnswer !== undefined) {
setAnswer(passedAnswer); setAnswer(passedAnswer);
} }
}, [passedAnswer]); }, [passedAnswer]);
useEffect(() => {
checkAnswer();
}, [answer]);
const checkAnswer = () => {
const isCorrect = question.choices.some((choice) => choice.isCorrect && choice.formattedText.text === answer as string);
setisGoodAnswer(isCorrect);
};
const handleOnClickAnswer = (choice: string) => { const handleOnClickAnswer = (choice: string) => {
setAnswer(choice); setAnswer(choice);
}; };
@ -36,12 +46,24 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
const alphabet = alpha.map((x) => String.fromCharCode(x)); const alphabet = alpha.map((x) => String.fromCharCode(x));
return ( 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 className="question content">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
<div className="choices-wrapper mb-1"> <div className="choices-wrapper mb-1">
{question.choices.map((choice, i) => { {question.choices.map((choice, i) => {
const selected = answer === choice.formattedText.text ? 'selected' : ''; const selected = answer === choice.formattedText.text ? 'selected' : '';
return ( return (
@ -51,17 +73,17 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
className="button-wrapper" className="button-wrapper"
disabled={disableButton} disabled={disableButton}
onClick={() => !showAnswer && handleOnClickAnswer(choice.formattedText.text)}> 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={`circle ${selected}`}>{alphabet[i]}</div>
<div className={`answer-text ${selected}`}> <div className={`answer-text ${selected}`}>
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedText) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedText) }} />
</div> </div>
{choice.formattedFeedback && showAnswer && ( {choice.formattedFeedback && showAnswer && (
<div className="feedback-container mb-1 mt-1/2"> <div className="feedback-container mb-1 mt-1/2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedFeedback) }} />
</div> </div>
)} )}
</Button> </Button>
</div> </div>
@ -70,22 +92,24 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
</div> </div>
{question.formattedGlobalFeedback && showAnswer && ( {question.formattedGlobalFeedback && showAnswer && (
<div className="global-feedback mb-2"> <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div> </div>
)} )}
{!showAnswer && handleOnSubmitAnswer && ( {!showAnswer && handleOnSubmitAnswer && (
<div className="submit-button-container">
<Button <Button
variant="contained" className='submit-button'
variant="contained"
onClick={() => onClick={() =>
answer !== "" && handleOnSubmitAnswer && handleOnSubmitAnswer(answer) answer !== "" && handleOnSubmitAnswer && handleOnSubmitAnswer(answer)
} }
disabled={answer === '' || answer === null} disabled={answer === '' || answer === null}
> >
Répondre Répondre
</Button> </Button>
</div>
)} )}
</div> </div>
); );

View file

@ -18,7 +18,13 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } =
props; props;
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || ''); const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
const [isGoodAnswer, setisGoodAnswer] = useState<boolean>(false);
const [isMultpleAnswer, setIsMultpleAnswer] = useState<boolean>(false);
const correctAnswers = question.choices; const correctAnswers = question.choices;
const correctAnswersList: number[] = [];
const correctAnswersPhrases: string[] = [];
let correctAnswer = ''; let correctAnswer = '';
useEffect(() => { useEffect(() => {
@ -27,6 +33,34 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
} }
}, [passedAnswer]); }, [passedAnswer]);
useEffect(() => {
checkAnswer();
}, [answer]);
const checkAnswer = () => {
if(isMultpleAnswer) {
correctAnswers.forEach((answers) => {
if(isSimpleNumericalAnswer(answers) && answer === answers.number) {
setisGoodAnswer(true);
} else if(isRangeNumericalAnswer(answers) && answer as number >= answers.number - answers.range && answer as number <= answers.number + answers.range) {
setisGoodAnswer(true);
} else if(isHighLowNumericalAnswer(answers) && answer as number >= answers.numberLow && answer as number <= answers.numberHigh) {
setisGoodAnswer(true);
}
}
)
;
} else {
if(isSimpleNumericalAnswer(answers) && answer === answers.number) {
setisGoodAnswer(true);
} else if(isRangeNumericalAnswer(answers) && answer as number >= answers.number - answers.range && answer as number <= answers.number + answers.range) {
setisGoodAnswer(true);
} else if(isHighLowNumericalAnswer(answers) && answer as number >= answers.numberLow && answer as number <= answers.numberHigh) {
setisGoodAnswer(true);
}
};
};
//const isSingleAnswer = correctAnswers.length === 1; //const isSingleAnswer = correctAnswers.length === 1;
if (isSimpleNumericalAnswer(correctAnswers[0])) { if (isSimpleNumericalAnswer(correctAnswers[0])) {
@ -38,28 +72,57 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
const choice = correctAnswers[0] as HighLowNumericalAnswer; const choice = correctAnswers[0] as HighLowNumericalAnswer;
correctAnswer = `Entre ${choice.numberLow} et ${choice.numberHigh}`; correctAnswer = `Entre ${choice.numberLow} et ${choice.numberHigh}`;
} else if (isMultipleNumericalAnswer(correctAnswers[0])) { } else if (isMultipleNumericalAnswer(correctAnswers[0])) {
correctAnswer = `MultipleNumericalAnswer is not supported yet`; setIsMultpleAnswer(true);
} else { correctAnswers.forEach((answers) => {
if(isSimpleNumericalAnswer(answers)) {
correctAnswersPhrases.push(`${(answers as SimpleNumericalAnswer).number}`);
} else if(isRangeNumericalAnswer(answers)) {
correctAnswersPhrases.push(`Entre ${answers.number - answers.range} et ${answers.number + answers.range}`);
} else if(isHighLowNumericalAnswer(answers)) {
correctAnswersPhrases.push(`Entre ${answers.numberLow} et ${answers.numberHigh}`);
}
});
}
else {
throw new Error('Unknown numerical answer type'); throw new Error('Unknown numerical answer type');
} }
return ( return (
<div className="question-wrapper"> <div className="question-wrapper">
{showAnswer && (
<div>
<div className='question-feedback-validation'>
{isGoodAnswer ? '✅ Correct! ' : '❌ Incorrect!'}
</div>
<div className="question-title">
Question :
</div>
</div>
)}
<div> <div>
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
{showAnswer ? ( {showAnswer ? (
<> <>
<div className="correct-answer-text mb-2"> <div className="correct-answer-text mb-1">
<strong>La bonne réponse est: </strong> <div>
{correctAnswer}</div> <div className="question-title">
<span> Réponse(s) accepté(es):
<strong>Votre réponse est: </strong>{answer.toString()} </div>
</span> <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"> {question.formattedGlobalFeedback && <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div>} </div>}
</> </>
) : ( ) : (
<> <>
@ -80,7 +143,9 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
</div> </div>
)} )}
{handleOnSubmitAnswer && ( {handleOnSubmitAnswer && (
<div className="submit-button-container">
<Button <Button
className='submit-button'
variant="contained" variant="contained"
onClick={() => onClick={() =>
answer !== undefined && answer !== undefined &&
@ -91,6 +156,7 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
> >
Répondre Répondre
</Button> </Button>
</div>
)} )}
</> </>
)} )}

View file

@ -17,34 +17,59 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = props; const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = props;
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || ''); const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
const [isGoodAnswer, setisGoodAnswer] = useState<boolean>(false);
useEffect(() => { useEffect(() => {
if (passedAnswer !== undefined) { if (passedAnswer !== undefined) {
setAnswer(passedAnswer); setAnswer(passedAnswer);
} }
}, [passedAnswer]); }, [passedAnswer]);
console.log("Answer" , answer);
useEffect(() => {
checkAnswer();
}, [answer]);
const checkAnswer = () => {
const isCorrect = question.choices.some((choice) => String(choice.text).toLowerCase() === String(answer).toLowerCase());
setisGoodAnswer(isCorrect);
};
return ( return (
<div className="question-wrapper"> <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 dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
{showAnswer ? ( {showAnswer ? (
<> <>
<div className="correct-answer-text mb-1"> <div className="correct-answer-text mb-1">
<span> <div>
<strong>La bonne réponse est: </strong> <div className="question-title">
Réponse(s) accepté(es):
{question.choices.map((choice) => (
<div key={choice.text} className="mb-1">
{choice.text}
</div> </div>
))} {question.choices.map((choice) => (
</span> <div key={choice.text} className="accepted-answers">
<span> {choice.text}
<strong>Votre réponse est: </strong>{answer} </div>
</span> ))}
</div>
<div>
<div className="question-title">
Votre réponse est: </div>
<div className="accepted-answers">{answer}</div>
</div>
</div> </div>
{question.formattedGlobalFeedback && <div className="global-feedback mb-2"> {question.formattedGlobalFeedback && <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
@ -65,7 +90,9 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
/> />
</div> </div>
{handleOnSubmitAnswer && ( {handleOnSubmitAnswer && (
<div className="submit-button-container">
<Button <Button
className='submit-button'
variant="contained" variant="contained"
onClick={() => onClick={() =>
answer !== undefined && answer !== undefined &&
@ -76,6 +103,7 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
> >
Répondre Répondre
</Button> </Button>
</div>
)} )}
</> </>
)} )}

View file

@ -47,7 +47,19 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
const selectedTrue = answer ? 'selected' : ''; const selectedTrue = answer ? 'selected' : '';
const selectedFalse = answer !== undefined && !answer ? 'selected' : ''; const selectedFalse = answer !== undefined && !answer ? 'selected' : '';
return ( return (
<div className="question-container"> <div className="question-wrapper">
{showAnswer && (
<div>
<div className='question-feedback-validation'>
{answer === question.isTrue ? '✅ Correct! ' : '❌ Incorrect!'}
</div>
<div className="question-title">
Question :
</div>
</div>
)}
<div className="question content"> <div className="question content">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
@ -92,7 +104,9 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
</div> </div>
)} )}
{!showAnswer && handleOnSubmitAnswer && ( {!showAnswer && handleOnSubmitAnswer && (
<div className="submit-button-container">
<Button <Button
className='submit-button'
variant="contained" variant="contained"
onClick={() => onClick={() =>
answer !== undefined && handleOnSubmitAnswer && handleOnSubmitAnswer(answer) answer !== undefined && handleOnSubmitAnswer && handleOnSubmitAnswer(answer)
@ -102,6 +116,7 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
> >
Répondre Répondre
</Button> </Button>
</div>
)} )}
</div> </div>
); );

View file

@ -2,7 +2,6 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center;
width: 100%; width: 100%;
} }
@ -22,8 +21,6 @@
.question-wrapper { .question-wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
justify-content: center;
} }
.question-wrapper .katex { .question-wrapper .katex {
@ -31,7 +28,8 @@
} }
.katex * { .katex * {
font-family: 'KaTeX_Main' /* to display characters like \neq properly */ font-family: 'KaTeX_Main'
/* to display characters like \neq properly */
} }
.circle { .circle {
@ -97,15 +95,11 @@
} }
.answer-positive-weight { .answer-positive-weight {
background-color: hsl( background-color: hsl(120, 100%, 90%);
120, 100%, 90%
);
} }
.answer-zero-or-less-weight { .answer-zero-or-less-weight {
background-color: hsl( background-color: hsl(0, 100%, 90%);
0, 100%, 90%
);
} }
.answer-text.selected { .answer-text.selected {
@ -119,7 +113,8 @@
} }
.feedback-container { .feedback-container {
display: inline-block !important; /* override the parent */ display: inline-block !important;
/* override the parent */
align-items: center; align-items: center;
margin-left: 1.1rem; margin-left: 1.1rem;
position: relative; position: relative;
@ -136,12 +131,12 @@
/* height: 1em; */ /* height: 1em; */
} }
.global-feedback { .global-feedback {
position: relative; position: relative;
padding: 0 1rem; padding: 0 1rem;
background-color: hsl(43, 100%, 94%); background-color: hsl(43, 100%, 94%);
color: hsl(43, 95%, 9%); color: hsl(43, 95%, 9%);
margin-top: 2rem;
border: hsl(36, 84%, 93%) 1px solid; border: hsl(36, 84%, 93%) 1px solid;
border-radius: 6px; border-radius: 6px;
box-shadow: 0px 2px 5px hsl(0, 0%, 74%); box-shadow: 0px 2px 5px hsl(0, 0%, 74%);
@ -156,6 +151,7 @@
border-radius: 6px; border-radius: 6px;
box-shadow: 0px 2px 5px hsl(0, 0%, 74%); box-shadow: 0px 2px 5px hsl(0, 0%, 74%);
} }
.false-feedback { .false-feedback {
position: relative; position: relative;
padding: 0 1rem; padding: 0 1rem;
@ -169,3 +165,57 @@
.choices-wrapper { .choices-wrapper {
width: 90%; 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;
}
.submit-button {
width: min-content;
margin-left: 19rem;}
.submit-button-container{
display: flex;
justify-content: center;
margin-top: 1rem;
}

View file

@ -60,7 +60,7 @@ const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
<div > <div >
<b>Question {questionInfos.question.id}/{questions.length}</b> <b>Question {questionInfos.question.id}/{questions.length}</b>
</div> </div>
<div className="overflow-auto"> <div className="overflow-auto" style={{ width: '50%', alignItems: 'center', justifyContent: 'center', margin: 'auto' }}>
<div className="question-component-container"> <div className="question-component-container">
<div className="mb-5"> <div className="mb-5">
{/* <QuestionNavigation {/* <QuestionNavigation

View file

@ -4,7 +4,7 @@ import QuestionComponent from '../QuestionsDisplay/QuestionDisplay';
import '../../pages/Student/JoinRoom/joinRoom.css'; import '../../pages/Student/JoinRoom/joinRoom.css';
import { QuestionType } from '../../Types/QuestionType'; import { QuestionType } from '../../Types/QuestionType';
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton'; 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 { Question } from 'gift-pegjs';
import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService'; import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService';
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom'; import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
@ -94,7 +94,6 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
open={isFeedbackDialogOpen} open={isFeedbackDialogOpen}
onClose={handleFeedbackDialogClose} onClose={handleFeedbackDialogClose}
> >
<DialogTitle>Rétroaction</DialogTitle>
<DialogContent> <DialogContent>
<div style={{ <div style={{
wordWrap: 'break-word', wordWrap: 'break-word',
@ -102,8 +101,6 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
maxHeight: '400px', maxHeight: '400px',
overflowY: 'auto', overflowY: 'auto',
}}> }}>
<div style={{ textAlign: 'left', fontWeight: 'bold', marginTop: '10px' }}
>Question : </div>
</div> </div>
<QuestionComponent <QuestionComponent