Fixed bootstrap format, added toggle button

This commit is contained in:
KenChanA 2025-04-01 00:29:56 -04:00
parent 198eb786fc
commit b9d79fceac
6 changed files with 215 additions and 250 deletions

View file

@ -14,18 +14,22 @@ interface Props {
passedAnswer?: AnswerType; passedAnswer?: AnswerType;
students?: StudentType[]; students?: StudentType[];
isDisplayOnly?: boolean; isDisplayOnly?: boolean;
showResults?: boolean;
} }
const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => { const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
const { question, showAnswer, handleOnSubmitAnswer, students, isDisplayOnly, passedAnswer } = props; const { question, showAnswer, handleOnSubmitAnswer, students, showResults, passedAnswer } = props;
const [answer, setAnswer] = useState<AnswerType>(() => { const [answer, setAnswer] = useState<AnswerType>(() => {
if (passedAnswer && passedAnswer.length > 0) { if (passedAnswer && passedAnswer.length > 0) {
return passedAnswer; return passedAnswer;
} }
return []; return [];
}); });
const [pickRates, setPickRates] = useState<{ percentages: number[], counts: number[], totalCount: number }>({ percentages: [], counts: [], totalCount: 0 }); const [pickRates, setPickRates] = useState<{ percentages: number[], counts: number[], totalCount: number }>({
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false); percentages: [],
counts: [],
totalCount: 0
});
let disableButton = false; let disableButton = false;
if (handleOnSubmitAnswer === undefined) { if (handleOnSubmitAnswer === undefined) {
@ -52,10 +56,6 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
} }
}); });
}; };
const toggleShowCorrectAnswers = () => {
setShowCorrectAnswers(!showCorrectAnswers);
};
const calculatePickRates = () => { const calculatePickRates = () => {
if (!students || students.length === 0) { if (!students || students.length === 0) {
@ -88,11 +88,12 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
setAnswer([]); setAnswer([]);
calculatePickRates(); calculatePickRates();
} }
}, [passedAnswer, students, question.id, showCorrectAnswers]); }, [passedAnswer, students, question.id]);
const alpha = Array.from(Array(26)).map((_e, i) => i + 65); const alpha = Array.from(Array(26)).map((_e, i) => i + 65);
const alphabet = alpha.map((x) => String.fromCharCode(x)); const alphabet = alpha.map((x) => String.fromCharCode(x));
return ( return (
<div className="container"> <div className="container">
<div className="row justify-content-center"> <div className="row justify-content-center">
@ -103,7 +104,7 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
<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.includes(choice.formattedText.text) ? 'selected' : ''; const selected = answer.includes(choice.formattedText.text) ? 'selected' : '';
const rateStyle = showCorrectAnswers ? { const rateStyle = showResults ? {
backgroundImage: `linear-gradient(to right, ${choice.isCorrect ? 'lightgreen' : 'lightcoral'} ${pickRates.percentages[i]}%, transparent ${pickRates.percentages[i]}%)`, backgroundImage: `linear-gradient(to right, ${choice.isCorrect ? 'lightgreen' : 'lightcoral'} ${pickRates.percentages[i]}%, transparent ${pickRates.percentages[i]}%)`,
color: 'black' color: 'black'
} : {}; } : {};
@ -134,7 +135,12 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
/> />
</div> </div>
)} )}
{showCorrectAnswers && <div className="pick-rate">{choice.isCorrect ? '✅' : '❌'} {`${pickRates.counts[i]}/${pickRates.totalCount} (${pickRates.percentages[i].toFixed(1)}%)`}</div>} {showResults && pickRates.percentages.length > i && (
<div className="pick-rate">
{choice.isCorrect ? '✅' : '❌'}
{`${pickRates.counts[i]}/${pickRates.totalCount} (${pickRates.percentages[i].toFixed(1)}%)`}
</div>
)}
</Button> </Button>
</div> </div>
); );
@ -162,17 +168,6 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
</Button> </Button>
)} )}
</div> </div>
{isDisplayOnly && (
<div className="col-auto d-flex align-items-center justify-content-end">
<Button
variant="outlined"
onClick={toggleShowCorrectAnswers}
color="primary"
>
{showCorrectAnswers ? "Masquer les résultats" : "Afficher les résultats"}
</Button>
</div>
)}
</div> </div>
</div> </div>
); );

View file

@ -14,35 +14,29 @@ interface Props {
showAnswer?: boolean; showAnswer?: boolean;
passedAnswer?: AnswerType; passedAnswer?: AnswerType;
students?: StudentType[]; students?: StudentType[];
isDisplayOnly?: boolean; showResults?: boolean;
} }
const NumericalQuestionDisplay: React.FC<Props> = (props) => { const NumericalQuestionDisplay: React.FC<Props> = (props) => {
const { question, showAnswer, handleOnSubmitAnswer, students, passedAnswer, isDisplayOnly } = const { question, showAnswer, handleOnSubmitAnswer, students, showResults, passedAnswer } =
props; props;
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || []); const [answer, setAnswer] = useState<AnswerType>(passedAnswer || []);
const correctAnswers = question.choices; const correctAnswers = question.choices;
let correctAnswer = ''; let correctAnswer = '';
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0); const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0);
const [submissionCounts, setSubmissionCounts] = useState({ const [submissionCounts, setSubmissionCounts] = useState({
correctSubmissions: 0, correctSubmissions: 0,
totalSubmissions: 0 totalSubmissions: 0
}); });
const toggleShowCorrectAnswers = () => {
setShowCorrectAnswers(!showCorrectAnswers);
};
useEffect(() => { useEffect(() => {
if (passedAnswer !== null && passedAnswer !== undefined) { if (passedAnswer !== null && passedAnswer !== undefined) {
setAnswer(passedAnswer); setAnswer(passedAnswer);
} }
if (showCorrectAnswers && students) { if (showResults && students) {
calculateCorrectAnswerRate(); calculateCorrectAnswerRate();
} }
}, [passedAnswer, showCorrectAnswers, students]); }, [passedAnswer, showResults, students]);
const calculateCorrectAnswerRate = () => { const calculateCorrectAnswerRate = () => {
if (!students || students.length === 0) { if (!students || students.length === 0) {
@ -82,85 +76,78 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
} }
return ( return (
<div className="question-wrapper"> <>
<div> <div className="container question-wrapper">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} /> <div className="row justify-content-center">
</div> <div className="col-auto">
{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>
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div>}
</>
) : (
<>
<div className="answer-wrapper mb-1">
<TextField
type="number"
id={question.formattedStem.text}
name={question.formattedStem.text}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setAnswer([e.target.valueAsNumber]);
}}
inputProps={{ 'data-testid': 'number-input' }}
/>
</div>
{question.formattedGlobalFeedback && showAnswer && (
<div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div>
)}
{handleOnSubmitAnswer && (
<Button
variant="contained"
onClick={() =>
answer !== undefined &&
handleOnSubmitAnswer &&
handleOnSubmitAnswer(answer)
}
disabled={answer === undefined || answer === null || isNaN(answer[0] as number)}
>
Répondre
</Button>
)}
</>
)}
{isDisplayOnly && (
<>
<div style={{ marginTop: '10px' }}>
<Button
variant="outlined"
onClick={toggleShowCorrectAnswers}
color="primary"
>
{showCorrectAnswers ? "Masquer les résultats" : "Afficher les résultats"}
</Button>
</div>
<div style={{
visibility: showCorrectAnswers ? 'visible' : 'hidden'
}}>
<div> <div>
Taux de réponse correcte: {submissionCounts.correctSubmissions}/{submissionCounts.totalSubmissions} <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
<div className="progress-bar-container"> {showAnswer ? (
<div className="progress-bar-fill" style={{ width: `${correctAnswerRate}%` }}></div> <>
<div className="progress-bar-text"> <div className="correct-answer-text mb-2">
{correctAnswerRate.toFixed(1)}% <strong>La bonne réponse est: </strong>
{correctAnswer}</div>
<span>
<strong>Votre réponse est: </strong>{answer.toString()}
</span>
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div>}
</>
) : (
<>
<div className="answer-wrapper mb-1">
<TextField
type="number"
id={question.formattedStem.text}
name={question.formattedStem.text}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setAnswer([e.target.valueAsNumber]);
}}
inputProps={{ 'data-testid': 'number-input' }}
/>
</div>
{question.formattedGlobalFeedback && showAnswer && (
<div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div>
)}
{handleOnSubmitAnswer && (
<div className="col-auto d-flex flex-column align-items-center">
<Button
variant="contained"
onClick={() =>
answer !== undefined &&
handleOnSubmitAnswer &&
handleOnSubmitAnswer(answer)
}
disabled={answer === undefined || answer === null || isNaN(answer[0] as number)}
>
Répondre
</Button>
</div>
)}
</>
)}
</div>
{showResults && (
<div className="col-auto">
<div>
Taux de réponse correcte: {submissionCounts.correctSubmissions}/{submissionCounts.totalSubmissions}
</div>
<div className="progress-bar-container">
<div className="progress-bar-fill" style={{ width: `${correctAnswerRate}%` }}></div>
<div className="progress-bar-text">
{correctAnswerRate.toFixed(1)}%
</div>
</div> </div>
</div> </div>
</div> )}
</> </div>
)} </div>
</div> </>
); );
}; };

View file

@ -15,7 +15,7 @@ interface QuestionProps {
handleOnSubmitAnswer?: (answer: AnswerType) => void; handleOnSubmitAnswer?: (answer: AnswerType) => void;
showAnswer?: boolean; showAnswer?: boolean;
students?: StudentType[]; students?: StudentType[];
isDisplayOnly?: boolean; showResults?: boolean;
answer?: AnswerType; answer?: AnswerType;
} }
@ -24,7 +24,7 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
handleOnSubmitAnswer, handleOnSubmitAnswer,
showAnswer, showAnswer,
students, students,
isDisplayOnly = false, showResults,
answer, answer,
}) => { }) => {
// const isMobile = useCheckMobileScreen(); // const isMobile = useCheckMobileScreen();
@ -41,7 +41,7 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
handleOnSubmitAnswer={handleOnSubmitAnswer} handleOnSubmitAnswer={handleOnSubmitAnswer}
showAnswer={showAnswer} showAnswer={showAnswer}
students={students} students={students}
isDisplayOnly={isDisplayOnly} showResults={showResults}
passedAnswer={answer} passedAnswer={answer}
/> />
); );
@ -54,7 +54,7 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
handleOnSubmitAnswer={handleOnSubmitAnswer} handleOnSubmitAnswer={handleOnSubmitAnswer}
showAnswer={showAnswer} showAnswer={showAnswer}
students={students} students={students}
isDisplayOnly={isDisplayOnly} showResults={showResults}
passedAnswer={answer} passedAnswer={answer}
/> />
); );
@ -68,7 +68,7 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
showAnswer={showAnswer} showAnswer={showAnswer}
passedAnswer={answer} passedAnswer={answer}
students={students} students={students}
isDisplayOnly={isDisplayOnly} showResults={showResults}
/> />
); );
} }
@ -80,7 +80,7 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
handleOnSubmitAnswer={handleOnSubmitAnswer} handleOnSubmitAnswer={handleOnSubmitAnswer}
showAnswer={showAnswer} showAnswer={showAnswer}
students={students} students={students}
isDisplayOnly={isDisplayOnly} showResults={showResults}
passedAnswer={answer} passedAnswer={answer}
/> />
); );

View file

@ -12,33 +12,28 @@ interface Props {
showAnswer?: boolean; showAnswer?: boolean;
passedAnswer?: AnswerType; passedAnswer?: AnswerType;
students?: StudentType[]; students?: StudentType[];
isDisplayOnly?: boolean; showResults?: boolean;
} }
const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => { const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
const { question, showAnswer, handleOnSubmitAnswer, students, passedAnswer, isDisplayOnly } = props; const { question, showAnswer, handleOnSubmitAnswer, students, showResults, passedAnswer } = props;
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || []); const [answer, setAnswer] = useState<AnswerType>(passedAnswer || []);
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0); const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0);
const [submissionCounts, setSubmissionCounts] = useState({ const [submissionCounts, setSubmissionCounts] = useState({
correctSubmissions: 0, correctSubmissions: 0,
totalSubmissions: 0 totalSubmissions: 0
}); });
const toggleShowCorrectAnswers = () => {
setShowCorrectAnswers(!showCorrectAnswers);
};
useEffect(() => { useEffect(() => {
if (passedAnswer !== undefined) { if (passedAnswer !== undefined) {
setAnswer(passedAnswer); setAnswer(passedAnswer);
} }
if (showCorrectAnswers && students) { if (showResults && students) {
calculateCorrectAnswerRate(); calculateCorrectAnswerRate();
} }
}, [passedAnswer, showCorrectAnswers, students, answer]); }, [passedAnswer, showResults, students, answer]);
console.log("Answer", answer); console.log("Answer", answer);
const calculateCorrectAnswerRate = () => { const calculateCorrectAnswerRate = () => {
@ -67,7 +62,9 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
<div className="container question-wrapper"> <div className="container question-wrapper">
<div className="row justify-content-center"> <div className="row justify-content-center">
<div className="col-auto"> <div className="col-auto">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} /> <div>
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div>
{showAnswer ? ( {showAnswer ? (
<> <>
<div className="correct-answer-text mb-1"> <div className="correct-answer-text mb-1">
@ -104,7 +101,7 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
/> />
</div> </div>
{handleOnSubmitAnswer && ( {handleOnSubmitAnswer && (
<div className="col-auto d-flex flex-column align-items-center"> <div className="">
<Button <Button
variant="contained" variant="contained"
onClick={() => onClick={() =>
@ -121,33 +118,19 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
</> </>
)} )}
</div> </div>
{isDisplayOnly && ( {showResults && (
<> <div className="col-auto">
<div className="col-auto d-flex flex-column align-items-center"> <div>
<Button Taux de réponse correcte: {submissionCounts.correctSubmissions}/{submissionCounts.totalSubmissions}
style={{ marginTop: '10px' }}
variant="outlined"
onClick={toggleShowCorrectAnswers}
color="primary"
>
{showCorrectAnswers ? "Masquer les résultats" : "Afficher les résultats"}
</Button>
{showCorrectAnswers && (
<div>
<div>
Taux de réponse correcte: {submissionCounts.correctSubmissions}/{submissionCounts.totalSubmissions}
</div>
<div className="progress-bar-container">
<div className="progress-bar-fill" style={{ width: `${correctAnswerRate}%` }}></div>
<div className="progress-bar-text">
{correctAnswerRate.toFixed(1)}%
</div>
</div>
</div>
)}
</div> </div>
</> <div className="progress-bar-container">
)} <div className="progress-bar-fill" style={{ width: `${correctAnswerRate}%` }}></div>
<div className="progress-bar-text">
{correctAnswerRate.toFixed(1)}%
</div>
</div>
</div>
)}
</div> </div>
</div> </div>
</> </>

View file

@ -13,11 +13,11 @@ interface Props {
showAnswer?: boolean; showAnswer?: boolean;
passedAnswer?: AnswerType; passedAnswer?: AnswerType;
students?: StudentType[]; students?: StudentType[];
isDisplayOnly?: boolean; showResults?: boolean;
} }
const TrueFalseQuestionDisplay: React.FC<Props> = (props) => { const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
const { question, showAnswer, handleOnSubmitAnswer, students, passedAnswer, isDisplayOnly } = props; const { question, showAnswer, handleOnSubmitAnswer, students, passedAnswer, showResults } = props;
const [pickRates, setPickRates] = useState<{ trueRate: number, falseRate: number, trueCount: number, falseCount: number, totalCount: number }>({ const [pickRates, setPickRates] = useState<{ trueRate: number, falseRate: number, trueCount: number, falseCount: number, totalCount: number }>({
trueRate: 0, trueRate: 0,
falseRate: 0, falseRate: 0,
@ -25,7 +25,6 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
falseCount: 0, falseCount: 0,
totalCount: 0 totalCount: 0
}); });
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
const [answer, setAnswer] = useState<boolean | undefined>(() => { const [answer, setAnswer] = useState<boolean | undefined>(() => {
@ -61,10 +60,6 @@ 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' : '';
const toggleShowCorrectAnswers = () => {
setShowCorrectAnswers(!showCorrectAnswers);
};
// Calcul le pick rate de chaque réponse // Calcul le pick rate de chaque réponse
const calculatePickRates = () => { const calculatePickRates = () => {
if (!students) { if (!students) {
@ -75,12 +70,14 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
const totalAnswers = students.length; const totalAnswers = students.length;
const trueAnswers = students.filter(student => const trueAnswers = students.filter(student =>
student.answers.some(ans => student.answers.some(ans =>
ans.idQuestion === Number(question.id) && ans.answer === true ans.idQuestion === Number(question.id) && ans.answer.some(a => a === true)
)).length; )
).length;
const falseAnswers = students.filter(student => const falseAnswers = students.filter(student =>
student.answers.some(ans => student.answers.some(ans =>
ans.idQuestion === Number(question.id) && ans.answer === false ans.idQuestion === Number(question.id) && ans.answer.some(a => a === false)
)).length; )
).length;
setPickRates({ setPickRates({
trueRate: (trueAnswers / totalAnswers) * 100, trueRate: (trueAnswers / totalAnswers) * 100,
@ -92,99 +89,91 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
}; };
return ( return (
<div className="question-container"> <div className="container">
<div className="question content"> <div className="row justify-content-center">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} /> <div className="col-auto question-container">
</div> <div className="question content">
<div className="choices-wrapper mb-1"> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
<Button
className="button-wrapper"
onClick={() => !showAnswer && handleOnClickAnswer(true)}
fullWidth
disabled={disableButton}
>
{showAnswer ? (<div> {(question.isTrue ? '✅' : '❌')}</div>) : ``}
<div className={`circle ${selectedTrue}`}>V</div>
<div className={`answer-text ${selectedTrue}`}
style={showCorrectAnswers ? {
backgroundImage: `linear-gradient(to right, ${question.isTrue ? 'royalblue' : 'orange'} ${pickRates.trueRate}%, transparent ${pickRates.trueRate}%)`
} : {}}
>
Vrai
</div> </div>
{showCorrectAnswers && ( <div className="choices-wrapper mb-1">
<> <Button
<div className="pick-rate">{question.isTrue ? '✅' : '❌'} {pickRates.trueCount}/{pickRates.totalCount} ({pickRates.trueRate.toFixed(1)}%)</div> className="button-wrapper"
</> onClick={() => !showAnswer && handleOnClickAnswer(true)}
)} fullWidth
disabled={disableButton}
>
{showAnswer ? (<div> {(question.isTrue ? '✅' : '❌')}</div>) : ``}
<div className={`circle ${selectedTrue}`}>V</div>
<div className={`answer-text ${selectedTrue}`}
style={showResults ? {
backgroundImage: `linear-gradient(to right, ${question.isTrue ? 'lightgreen' : 'lightcoral'} ${pickRates.trueRate}%, transparent ${pickRates.trueRate}%)`
} : {}}
>
Vrai
</div>
{showResults && (
<>
<div className="pick-rate">{question.isTrue ? '✅' : '❌'} {pickRates.trueCount}/{pickRates.totalCount} ({pickRates.trueRate.toFixed(1)}%)</div>
</>
)}
{showAnswer && answer && question.trueFormattedFeedback && ( {showAnswer && answer && question.trueFormattedFeedback && (
<div className="true-feedback mb-2"> <div className="true-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.trueFormattedFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.trueFormattedFeedback) }} />
</div>
)}
</Button>
<Button
className={`button-wrapper ${selectedFalse}`}
onClick={() => !showResults && handleOnClickAnswer(false)}
fullWidth
disabled={disableButton}
>
{showAnswer ? (<div> {(!question.isTrue ? '✅' : '❌')}</div>) : ``}
<div className={`circle ${selectedFalse}`}>F</div>
<div
className={`answer-text ${selectedFalse}`}
style={showResults ? {
backgroundImage: `linear-gradient(to right, ${!question.isTrue ? 'lightgreen' : 'lightcoral'} ${pickRates.falseRate}%, transparent ${pickRates.falseRate}%)`,
} : {}}
>
Faux
</div>
{showResults && (
<>
<div className="pick-rate">{!question.isTrue ? '✅' : '❌'} {pickRates.falseCount}/{pickRates.totalCount} ({pickRates.falseRate.toFixed(1)}%)</div>
</>
)}
{showAnswer && !answer && question.falseFormattedFeedback && (
<div className="false-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.falseFormattedFeedback) }} />
</div>
)}
</Button>
</div>
{question.formattedGlobalFeedback && showAnswer && (
<div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div> </div>
)} )}
</Button> {!showAnswer && handleOnSubmitAnswer && (
<Button <Button
className={`button-wrapper ${selectedFalse}`} variant="contained"
onClick={() => !showCorrectAnswers && handleOnClickAnswer(false)} onClick={() =>
fullWidth answer !== undefined && handleOnSubmitAnswer && handleOnSubmitAnswer([answer])
disabled={disableButton} }
disabled={answer === undefined}
> >
{showAnswer ? (<div> {(!question.isTrue ? '✅' : '❌')}</div>) : ``} Répondre
<div className={`circle ${selectedFalse}`}>F</div> </Button>
<div
className={`answer-text ${selectedFalse}`}
style={showCorrectAnswers ? {
backgroundImage: `linear-gradient(to right, ${!question.isTrue ? 'royalblue' : 'orange'} ${pickRates.falseRate}%, transparent ${pickRates.falseRate}%)`,
} : {}}
>
Faux
</div>
{showCorrectAnswers && (
<>
<div className="pick-rate">{!question.isTrue ? '✅' : '❌'} {pickRates.falseCount}/{pickRates.totalCount} ({pickRates.falseRate.toFixed(1)}%)</div>
</>
)} )}
</div>
{showAnswer && !answer && question.falseFormattedFeedback && (
<div className="false-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.falseFormattedFeedback) }} />
</div>
)}
</Button>
</div> </div>
{question.formattedGlobalFeedback && showAnswer && (
<div className="global-feedback mb-2">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
</div>
)}
{!showAnswer && handleOnSubmitAnswer && (
<Button
variant="contained"
onClick={() =>
answer !== undefined && handleOnSubmitAnswer && handleOnSubmitAnswer([answer])
}
disabled={answer === undefined}
>
Répondre
</Button>
)}
{isDisplayOnly && (
<div>
<Button
variant="outlined"
onClick={toggleShowCorrectAnswers}
color="primary"
>
{showCorrectAnswers ? "Masquer les résultats" : "Afficher les résultats"}
</Button>
</div>
)}
</div> </div>
); );
}; };

View file

@ -18,7 +18,7 @@ import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
import QuestionDisplay from 'src/components/QuestionsDisplay/QuestionDisplay'; import QuestionDisplay from 'src/components/QuestionsDisplay/QuestionDisplay';
import ApiService from '../../../services/ApiService'; import ApiService from '../../../services/ApiService';
import { QuestionType } from 'src/Types/QuestionType'; import { QuestionType } from 'src/Types/QuestionType';
import { Button } from '@mui/material'; import { Button, FormControlLabel, Switch } from '@mui/material';
import { checkIfIsCorrect } from './useRooms'; import { checkIfIsCorrect } from './useRooms';
const ManageRoom: React.FC = () => { const ManageRoom: React.FC = () => {
@ -34,6 +34,7 @@ const ManageRoom: React.FC = () => {
const [quizStarted, setQuizStarted] = useState<boolean>(false); const [quizStarted, setQuizStarted] = useState<boolean>(false);
const [formattedRoomName, setFormattedRoomName] = useState(""); const [formattedRoomName, setFormattedRoomName] = useState("");
const [newlyConnectedUser, setNewlyConnectedUser] = useState<StudentType | null>(null); const [newlyConnectedUser, setNewlyConnectedUser] = useState<StudentType | null>(null);
const [showResults, setShowResults] = useState<boolean>(false);
// Handle the newly connected user in useEffect, because it needs state info // Handle the newly connected user in useEffect, because it needs state info
// not available in the socket.on() callback // not available in the socket.on() callback
@ -407,7 +408,17 @@ const ManageRoom: React.FC = () => {
{quizQuestions?.length} {quizQuestions?.length}
</strong> </strong>
)} )}
<FormControlLabel
label={<div className="text-sm">Afficher les résultats</div>}
control={
<Switch
value={showResults}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setShowResults(e.target.checked)
}
/>
}
/>
{quizMode === 'teacher' && ( {quizMode === 'teacher' && (
<div className="mb-1"> <div className="mb-1">
{/* <QuestionNavigation {/* <QuestionNavigation
@ -426,7 +437,7 @@ const ManageRoom: React.FC = () => {
showAnswer={false} showAnswer={false}
question={currentQuestion?.question as Question} question={currentQuestion?.question as Question}
students={students} students={students}
isDisplayOnly={true} showResults={showResults}
/> />
)} )}