Skip to content

Commit 8fd2e5e

Browse files
authored
Merge pull request #357 from ets-cfuhrman-pfe/Minh-Khoi-Le/hide-feedback
Hide feedback and correct answers in teacher mode quiz
2 parents 2ec36f1 + 1106535 commit 8fd2e5e

9 files changed

Lines changed: 460 additions & 61 deletions

File tree

client/src/__tests__/pages/Student/TeacherModeQuiz/TeacherModeQuizV2.test.tsx

Lines changed: 372 additions & 29 deletions
Large diffs are not rendered by default.

client/src/components/QuestionsDisplay/MultipleChoiceQuestionDisplay/MultipleChoiceQuestionDisplayV2.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ interface PropsV2 {
1616
disabled?: boolean;
1717
students?: StudentType[];
1818
showStatistics?: boolean;
19+
hideAnswerFeedback?: boolean;
1920
}
2021

2122
const MultipleChoiceQuestionDisplayV2: React.FC<PropsV2> = (props) => {
22-
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer, buttonText = 'Répondre', disabled = false, students = [], showStatistics = false } = props;
23+
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer, buttonText = 'Répondre', disabled = false, students = [], showStatistics = false, hideAnswerFeedback = false } = props;
2324
// console.log('MultipleChoiceQuestionDisplayV2: passedAnswer', JSON.stringify(passedAnswer));
2425

2526
const [answer, setAnswer] = useState<AnswerType>(() => {
@@ -46,7 +47,8 @@ const MultipleChoiceQuestionDisplayV2: React.FC<PropsV2> = (props) => {
4647
// Prevent validation styling from showing immediately on question change
4748
// For teacher view (no handleOnSubmitAnswer), show validation when showAnswer is true
4849
// For student view, only show validation after they've submitted an answer
49-
const shouldShowValidation = showAnswer && (handleOnSubmitAnswer === undefined || answer.length > 0);
50+
// In teacher mode rhythm, hide validation when hideAnswerFeedback is true
51+
const shouldShowValidation = showAnswer && !hideAnswerFeedback && (handleOnSubmitAnswer === undefined || answer.length > 0);
5052

5153
const handleOnClickAnswer = (choice: string) => {
5254
setAnswer((prevAnswer) => {
@@ -96,8 +98,8 @@ const MultipleChoiceQuestionDisplayV2: React.FC<PropsV2> = (props) => {
9698
? (choice.isCorrect ? 'bg-success text-white' : 'bg-danger text-white')
9799
: (selected ? 'bg-primary text-white choice-button-selected' : 'bg-light text-dark')
98100
} ${shouldShowValidation && selected ? 'choice-button-validated-selected' : ''}`}
99-
disabled={disableButton || disabled}
100-
onClick={() => !shouldShowValidation && !disabled && handleOnClickAnswer(choice.formattedText.text)}
101+
disabled={disableButton || disabled || (showAnswer && hideAnswerFeedback)}
102+
onClick={() => !shouldShowValidation && !disabled && !(showAnswer && hideAnswerFeedback) && handleOnClickAnswer(choice.formattedText.text)}
101103
>
102104
<div className="d-flex align-items-center w-100">
103105
<div
@@ -125,7 +127,7 @@ const MultipleChoiceQuestionDisplayV2: React.FC<PropsV2> = (props) => {
125127
)}
126128
</div>
127129
</Button>
128-
{choice.formattedFeedback && showAnswer && (
130+
{choice.formattedFeedback && showAnswer && !hideAnswerFeedback && (
129131
<div className="mt-2">
130132
<div className="alert alert-info small">
131133
<div
@@ -160,7 +162,7 @@ const MultipleChoiceQuestionDisplayV2: React.FC<PropsV2> = (props) => {
160162

161163
{/* Global feedback - always reserve space */}
162164
<div className="d-flex flex-column">
163-
{question.formattedGlobalFeedback && showAnswer && (
165+
{question.formattedGlobalFeedback && showAnswer && !hideAnswerFeedback && (
164166
<div className="global-feedback">
165167
<div
166168
dangerouslySetInnerHTML={{

client/src/components/QuestionsDisplay/NumericalQuestionDisplay/NumericalQuestionDisplayV2.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@ import { isSimpleNumericalAnswer, isRangeNumericalAnswer, isHighLowNumericalAnsw
77
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
88
import ValidatedTextField from '../../ValidatedTextField/ValidatedTextField';
99

10+
const noop = () => {};
11+
1012
interface PropsV2 {
1113
question: NumericalQuestion;
1214
handleOnSubmitAnswer?: (answer: AnswerType) => void;
1315
showAnswer?: boolean;
1416
passedAnswer?: AnswerType;
1517
buttonText?: string;
1618
disabled?: boolean;
19+
hideAnswerFeedback?: boolean;
1720
}
1821

1922
const NumericalQuestionDisplayV2: React.FC<PropsV2> = (props) => {
20-
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer, buttonText = 'Répondre', disabled = false } = props;
23+
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer, buttonText = 'Répondre', disabled = false, hideAnswerFeedback = false } = props;
2124
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || []);
2225
const correctAnswers = question.choices;
2326
let correctAnswer = '';
@@ -47,7 +50,7 @@ const NumericalQuestionDisplayV2: React.FC<PropsV2> = (props) => {
4750
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
4851
</div>
4952

50-
{showAnswer ? (
53+
{showAnswer && !hideAnswerFeedback ? (
5154
<div className="mb-4">
5255
{answer && answer.length > 0 && answer[0] !== undefined && answer[0] !== null ? (
5356
(() => {
@@ -85,6 +88,26 @@ const NumericalQuestionDisplayV2: React.FC<PropsV2> = (props) => {
8588
</div>
8689
)}
8790
</div>
91+
) : showAnswer && hideAnswerFeedback ? (
92+
// Show the input field disabled when hideAnswerFeedback is true
93+
<div className="mb-4">
94+
<div className="row">
95+
<div className="col-md-8">
96+
<ValidatedTextField
97+
fieldPath="number.decimal"
98+
initialValue={answer[0]?.toString() || ''}
99+
onValueChange={noop} // No-op function since it's disabled
100+
type="number"
101+
id={question.formattedStem.text}
102+
name={question.formattedStem.text}
103+
disabled={true}
104+
aria-label="number-input"
105+
fullWidth
106+
label="Votre réponse (nombre)"
107+
/>
108+
</div>
109+
</div>
110+
</div>
88111
) : (
89112
<div className="mb-4">
90113
<div className="row">
@@ -126,7 +149,7 @@ const NumericalQuestionDisplayV2: React.FC<PropsV2> = (props) => {
126149

127150
{/* Global feedback - always reserve space */}
128151
<div className="d-flex flex-column" >
129-
{question.formattedGlobalFeedback && showAnswer && (
152+
{question.formattedGlobalFeedback && showAnswer && !hideAnswerFeedback && (
130153
<div className="global-feedback">
131154
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
132155
</div>

client/src/components/QuestionsDisplay/QuestionDisplayV2.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface QuestionV2Props {
1717
disabled?: boolean;
1818
students?: StudentType[];
1919
showStatistics?: boolean;
20+
hideAnswerFeedback?: boolean;
2021
}
2122

2223
const QuestionDisplayV2: React.FC<QuestionV2Props> = ({
@@ -28,6 +29,7 @@ const QuestionDisplayV2: React.FC<QuestionV2Props> = ({
2829
disabled = false,
2930
students = [],
3031
showStatistics = false,
32+
hideAnswerFeedback = false,
3133
}) => {
3234
let questionTypeComponent = null;
3335
switch (question?.type) {
@@ -42,6 +44,7 @@ const QuestionDisplayV2: React.FC<QuestionV2Props> = ({
4244
disabled={disabled}
4345
students={students}
4446
showStatistics={showStatistics}
47+
hideAnswerFeedback={hideAnswerFeedback}
4548
/>
4649
);
4750
break;
@@ -56,6 +59,7 @@ const QuestionDisplayV2: React.FC<QuestionV2Props> = ({
5659
disabled={disabled}
5760
students={students}
5861
showStatistics={showStatistics}
62+
hideAnswerFeedback={hideAnswerFeedback}
5963
/>
6064
);
6165
break;
@@ -69,6 +73,7 @@ const QuestionDisplayV2: React.FC<QuestionV2Props> = ({
6973
passedAnswer={answer}
7074
buttonText={buttonText}
7175
disabled={disabled}
76+
hideAnswerFeedback={hideAnswerFeedback}
7277
/>
7378
);
7479
}
@@ -82,6 +87,7 @@ const QuestionDisplayV2: React.FC<QuestionV2Props> = ({
8287
passedAnswer={answer}
8388
buttonText={buttonText}
8489
disabled={disabled}
90+
hideAnswerFeedback={hideAnswerFeedback}
8591
/>
8692
);
8793
break;

client/src/components/QuestionsDisplay/ShortAnswerQuestionDisplay/ShortAnswerQuestionDisplayV2.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@ import { ShortAnswerQuestion } from 'gift-pegjs';
66
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
77
import ValidatedTextField from '../../ValidatedTextField/ValidatedTextField';
88

9+
const noop = () => {};
10+
911
interface PropsV2 {
1012
question: ShortAnswerQuestion;
1113
handleOnSubmitAnswer?: (answer: AnswerType) => void;
1214
showAnswer?: boolean;
1315
passedAnswer?: AnswerType;
1416
buttonText?: string;
1517
disabled?: boolean;
18+
hideAnswerFeedback?: boolean;
1619
}
1720

1821
const ShortAnswerQuestionDisplayV2: React.FC<PropsV2> = (props) => {
19-
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer, buttonText = 'Répondre', disabled = false } = props;
22+
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer, buttonText = 'Répondre', disabled = false, hideAnswerFeedback = false } = props;
2023
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || []);
2124

2225
useEffect(() => {
@@ -32,7 +35,7 @@ const ShortAnswerQuestionDisplayV2: React.FC<PropsV2> = (props) => {
3235
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
3336
</div>
3437

35-
{showAnswer ? (
38+
{showAnswer && !hideAnswerFeedback ? (
3639
<div className="mb-4">
3740
{answer && answer.length > 0 && answer[0] ? (
3841
(() => {
@@ -61,6 +64,26 @@ const ShortAnswerQuestionDisplayV2: React.FC<PropsV2> = (props) => {
6164
</div>
6265
)}
6366
</div>
67+
) : showAnswer && hideAnswerFeedback ? (
68+
// Show the input field disabled when hideAnswerFeedback is true
69+
<div className="mb-4">
70+
<div className="row">
71+
<div className="col-md-8">
72+
<ValidatedTextField
73+
fieldPath="text.short"
74+
initialValue={answer[0] || ''}
75+
onValueChange={noop} // No-op function since it's disabled
76+
type="text"
77+
id={question.formattedStem.text}
78+
name={question.formattedStem.text}
79+
disabled={true}
80+
aria-label="short-answer-input"
81+
fullWidth
82+
label="Votre réponse"
83+
/>
84+
</div>
85+
</div>
86+
</div>
6487
) : (
6588
<div className="mb-4">
6689
<div className="row">
@@ -101,7 +124,7 @@ const ShortAnswerQuestionDisplayV2: React.FC<PropsV2> = (props) => {
101124

102125
{/* Global feedback - always reserve space */}
103126
<div className="d-flex flex-column">
104-
{question.formattedGlobalFeedback && showAnswer && (
127+
{question.formattedGlobalFeedback && showAnswer && !hideAnswerFeedback && (
105128
<div className="global-feedback">
106129
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
107130
</div>

client/src/components/QuestionsDisplay/TrueFalseQuestionDisplay/TrueFalseQuestionDisplayV2.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ interface PropsV2 {
1616
disabled?: boolean;
1717
students?: StudentType[];
1818
showStatistics?: boolean;
19+
hideAnswerFeedback?: boolean;
1920
}
2021

2122
const TrueFalseQuestionDisplayV2: React.FC<PropsV2> = (props) => {
22-
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer, buttonText = 'Répondre', disabled = false, students = [], showStatistics = false } = props;
23+
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer, buttonText = 'Répondre', disabled = false, students = [], showStatistics = false, hideAnswerFeedback = false } = props;
2324

2425
const [answer, setAnswer] = useState<boolean | undefined>(() => {
2526
if (passedAnswer && (passedAnswer[0] === true || passedAnswer[0] === false)) {
@@ -48,7 +49,8 @@ const TrueFalseQuestionDisplayV2: React.FC<PropsV2> = (props) => {
4849
// Prevent validation styling from showing immediately on question change
4950
// For teacher view (no handleOnSubmitAnswer), show validation when showAnswer is true
5051
// For student view, only show validation after they've submitted an answer
51-
const shouldShowValidation = showAnswer && (handleOnSubmitAnswer === undefined || answer !== undefined);
52+
// In teacher mode rhythm, hide validation when hideAnswerFeedback is true
53+
const shouldShowValidation = showAnswer && !hideAnswerFeedback && (handleOnSubmitAnswer === undefined || answer !== undefined);
5254
const selectedTrue = answer === true ? 'selected' : '';
5355
const selectedFalse = answer === false ? 'selected' : '';
5456

@@ -79,8 +81,8 @@ const TrueFalseQuestionDisplayV2: React.FC<PropsV2> = (props) => {
7981
<div className="col-md-6">
8082
<Button
8183
className={`w-100 p-3 text-start choice-button ${trueColorClass} ${trueValidationClass}`}
82-
onClick={() => !shouldShowValidation && !disabled && handleOnClickAnswer(true)}
83-
disabled={disableButton || disabled}
84+
onClick={() => !shouldShowValidation && !disabled && !(showAnswer && hideAnswerFeedback) && handleOnClickAnswer(true)}
85+
disabled={disableButton || disabled || (showAnswer && hideAnswerFeedback)}
8486
variant="outlined"
8587
>
8688
<div className="d-flex align-items-center">
@@ -96,7 +98,7 @@ const TrueFalseQuestionDisplayV2: React.FC<PropsV2> = (props) => {
9698
)}
9799
</div>
98100
</Button>
99-
{showAnswer && answer && question.trueFormattedFeedback && (
101+
{showAnswer && answer && question.trueFormattedFeedback && !hideAnswerFeedback && (
100102
<div className="true-feedback">
101103
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.trueFormattedFeedback) }} />
102104
</div>
@@ -106,8 +108,8 @@ const TrueFalseQuestionDisplayV2: React.FC<PropsV2> = (props) => {
106108
<div className="col-md-6">
107109
<Button
108110
className={`w-100 p-3 text-start choice-button ${falseColorClass} ${falseValidationClass}`}
109-
onClick={() => !shouldShowValidation && !disabled && handleOnClickAnswer(false)}
110-
disabled={disableButton || disabled}
111+
onClick={() => !shouldShowValidation && !disabled && !(showAnswer && hideAnswerFeedback) && handleOnClickAnswer(false)}
112+
disabled={disableButton || disabled || (showAnswer && hideAnswerFeedback)}
111113
variant="outlined"
112114
>
113115
<div className="d-flex align-items-center">
@@ -123,7 +125,7 @@ const TrueFalseQuestionDisplayV2: React.FC<PropsV2> = (props) => {
123125
)}
124126
</div>
125127
</Button>
126-
{showAnswer && !answer && question.falseFormattedFeedback && (
128+
{showAnswer && !answer && question.falseFormattedFeedback && !hideAnswerFeedback && (
127129
<div className="false-feedback">
128130
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.falseFormattedFeedback) }} />
129131
</div>
@@ -151,7 +153,7 @@ const TrueFalseQuestionDisplayV2: React.FC<PropsV2> = (props) => {
151153

152154
{/* Global feedback - always reserve space */}
153155
<div className="d-flex flex-column">
154-
{question.formattedGlobalFeedback && showAnswer && (
156+
{question.formattedGlobalFeedback && showAnswer && !hideAnswerFeedback && (
155157
<div className="global-feedback">
156158
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
157159
</div>

client/src/components/StudentModeQuiz/StudentModeQuizV2.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ const StudentModeQuizV2: React.FC<StudentModeQuizV2Props> = ({
6767
};
6868

6969
// Compute if answer is submitted for current question
70-
const isAnswerSubmitted = answers[Number(questionInfos.question.id) - 1]?.answer !== undefined;
70+
const answerSubmission = answers[Number(questionInfos.question.id) - 1];
71+
const isAnswerSubmitted = answerSubmission?.answer !== undefined && answerSubmission?.roomName !== undefined;
7172

7273
// Create a student object for the current student
7374
const currentStudent: StudentType = {

client/src/components/TeacherModeQuiz/TeacherModeQuizV2.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,14 @@ const TeacherModeQuizV2: React.FC<TeacherModeQuizV2Props> = ({
4040

4141
// arrive here the first time after waiting for next question
4242
useEffect(() => {
43-
const oldAnswer = answers[Number(questionInfos.question.id) -1 ]?.answer;
43+
setIsAnswerSubmitted(false); // Reset to prevent flash
44+
const answerSubmission = answers[Number(questionInfos.question.id) - 1];
45+
const oldAnswer = answerSubmission?.answer;
4446
setAnswer(oldAnswer);
45-
// Reset validation state when question changes to prevent flash
46-
setIsAnswerSubmitted(false);
47+
// Set answer submission state based on whether answer exists and is not just an empty object
48+
setIsAnswerSubmitted(oldAnswer !== undefined && answerSubmission?.roomName !== undefined);
4749
}, [questionInfos?.question, answers]);
4850

49-
// handle answer submission state
50-
useEffect(() => {
51-
setIsAnswerSubmitted(answer !== undefined);
52-
}, [answer]);
53-
5451
const handleOnSubmitAnswer = (answer: AnswerType) => {
5552
if (shouldShowResults) {
5653
// Quiz is completed, show results instead of submitting
@@ -60,13 +57,14 @@ const TeacherModeQuizV2: React.FC<TeacherModeQuizV2Props> = ({
6057
const idQuestion = Number(questionInfos.question.id) || -1;
6158
submitAnswer(answer, idQuestion);
6259
setAnswer(answer);
60+
setIsAnswerSubmitted(true);
6361
}
6462
};
6563

6664
// Check if student has answered all questions
6765
const hasAnsweredAllQuestions = questions && questions.length > 0 &&
6866
answers.length === questions.length &&
69-
answers.every(answer => answer?.answer !== undefined);
67+
answers.every(answer => answer?.answer !== undefined && answer?.roomName !== undefined);
7068

7169
// Check if we should show results (quiz completed or all questions answered)
7270
const shouldShowResults = hasAnsweredAllQuestions || quizCompleted;
@@ -155,6 +153,7 @@ const TeacherModeQuizV2: React.FC<TeacherModeQuizV2Props> = ({
155153
showAnswer={isAnswerSubmitted}
156154
answer={answer}
157155
buttonText={buttonText}
156+
hideAnswerFeedback={true}
158157
/>
159158
</div>
160159
</div>

0 commit comments

Comments
 (0)