Changed questions display

This commit is contained in:
KenChanA 2025-03-16 21:25:21 -04:00
parent 99c6432105
commit 8db658e7a0
10 changed files with 122 additions and 77 deletions

View file

@ -19,6 +19,7 @@
"@mui/material": "^6.4.6", "@mui/material": "^6.4.6",
"@types/uuid": "^9.0.7", "@types/uuid": "^9.0.7",
"axios": "^1.8.1", "axios": "^1.8.1",
"bootstrap": "^5.3.3",
"dompurify": "^3.2.3", "dompurify": "^3.2.3",
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"gift-pegjs": "^2.0.0-beta.1", "gift-pegjs": "^2.0.0-beta.1",
@ -5536,6 +5537,24 @@
"devOptional": true, "devOptional": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/bootstrap": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"peerDependencies": {
"@popperjs/core": "^2.11.8"
}
},
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",

View file

@ -23,6 +23,7 @@
"@mui/material": "^6.4.6", "@mui/material": "^6.4.6",
"@types/uuid": "^9.0.7", "@types/uuid": "^9.0.7",
"axios": "^1.8.1", "axios": "^1.8.1",
"bootstrap": "^5.3.3",
"dompurify": "^3.2.3", "dompurify": "^3.2.3",
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"gift-pegjs": "^2.0.0-beta.1", "gift-pegjs": "^2.0.0-beta.1",

View file

@ -1,4 +1,4 @@
import React from "react"; import React, { useState } from "react";
import { TableCell, TableHead, TableRow } from "@mui/material"; import { TableCell, TableHead, TableRow } from "@mui/material";
interface LiveResultsHeaderProps { interface LiveResultsHeaderProps {
@ -10,6 +10,12 @@ const LiveResultsTableHeader: React.FC<LiveResultsHeaderProps> = ({
maxQuestions, maxQuestions,
showSelectedQuestion, showSelectedQuestion,
}) => { }) => {
const [selectedQuestionIndex, setSelectedQuestionIndex] = useState<number | null>(null);
const handleQuestionClick = (index: number) => {
setSelectedQuestionIndex(index);
showSelectedQuestion(index);
};
return ( return (
<TableHead> <TableHead>
@ -25,9 +31,10 @@ const LiveResultsTableHeader: React.FC<LiveResultsHeaderProps> = ({
cursor: 'pointer', cursor: 'pointer',
borderStyle: 'solid', borderStyle: 'solid',
borderWidth: 1, borderWidth: 1,
borderColor: 'rgba(224, 224, 224, 1)' borderColor: 'rgba(224, 224, 224, 1)',
backgroundColor: selectedQuestionIndex === index ? '#dedede' : 'transparent'
}} }}
onClick={() => showSelectedQuestion(index)} onClick={() => handleQuestionClick(index)}
> >
<div className="text-base text-bold blue">{`Q${index + 1}`}</div> <div className="text-base text-bold blue">{`Q${index + 1}`}</div>
</TableCell> </TableCell>

View file

@ -67,7 +67,7 @@ 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-container" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div className="question content"> <div className="question content">
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
@ -76,7 +76,7 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
{question.choices.map((choice, i) => { {question.choices.map((choice, i) => {
const selected = answer === choice.formattedText.text ? 'selected' : ''; const selected = answer === choice.formattedText.text ? 'selected' : '';
const rateStyle = showCorrectAnswers ? { const rateStyle = showCorrectAnswers ? {
backgroundImage: `linear-gradient(to right, ${choice.isCorrect ? 'lightgreen' : 'lightcoral'} ${pickRates[i]}%, transparent ${pickRates[i]}%)`, backgroundImage: `linear-gradient(to right, ${choice.isCorrect ? 'royalblue' : 'orange'} ${pickRates[i]}%, transparent ${pickRates[i]}%)`,
color: 'black' color: 'black'
} : {}; } : {};
return ( return (
@ -114,12 +114,7 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedFeedback) }} />
</div> </div>
)} )}
{showCorrectAnswers && <div>{choice.isCorrect ? '✅' : '❌'}</div>} {showCorrectAnswers && <div className="pick-rate">{choice.isCorrect ? '✅' : '❌'} {pickRates[i].toFixed(1)}%</div>}
{showCorrectAnswers && (
<div className="pick-rate">
{pickRates[i].toFixed(1)}%
</div>
)}
</Button> </Button>
</div> </div>
); );

View file

@ -26,6 +26,10 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false); const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0); const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0);
const [submissionCounts, setSubmissionCounts] = useState({
correctSubmissions: 0,
totalSubmissions: 0
});
const toggleShowCorrectAnswers = () => { const toggleShowCorrectAnswers = () => {
setShowCorrectAnswers(!showCorrectAnswers); setShowCorrectAnswers(!showCorrectAnswers);
@ -42,7 +46,7 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
const calculateCorrectAnswerRate = () => { const calculateCorrectAnswerRate = () => {
if (!students || students.length === 0) { if (!students || students.length === 0) {
setCorrectAnswerRate(0); // Safeguard against undefined or empty student array setSubmissionCounts({ correctSubmissions: 0, totalSubmissions: 0 });
return; return;
} }
@ -52,6 +56,12 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
ans.idQuestion === Number(question.id) && ans.isCorrect ans.idQuestion === Number(question.id) && ans.isCorrect
) )
).length; ).length;
setSubmissionCounts({
correctSubmissions,
totalSubmissions
});
setCorrectAnswerRate((correctSubmissions / totalSubmissions) * 100); setCorrectAnswerRate((correctSubmissions / totalSubmissions) * 100);
}; };
@ -139,7 +149,7 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
visibility: showCorrectAnswers ? 'visible' : 'hidden' visibility: showCorrectAnswers ? 'visible' : 'hidden'
}}> }}>
<div> <div>
Taux de réponse correcte: Taux de réponse correcte: {submissionCounts.correctSubmissions}/{submissionCounts.totalSubmissions}
</div> </div>
<div className="progress-bar-container"> <div className="progress-bar-container">
<div className="progress-bar-fill" style={{ width: `${correctAnswerRate}%` }}></div> <div className="progress-bar-fill" style={{ width: `${correctAnswerRate}%` }}></div>

View file

@ -24,7 +24,7 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
handleOnSubmitAnswer, handleOnSubmitAnswer,
showAnswer, showAnswer,
students, students,
isDisplayOnly = false isDisplayOnly = false,
answer, answer,
}) => { }) => {
// const isMobile = useCheckMobileScreen(); // const isMobile = useCheckMobileScreen();

View file

@ -20,6 +20,10 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || ''); const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false); const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0); const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0);
const [submissionCounts, setSubmissionCounts] = useState({
correctSubmissions: 0,
totalSubmissions: 0
});
const toggleShowCorrectAnswers = () => { const toggleShowCorrectAnswers = () => {
setShowCorrectAnswers(!showCorrectAnswers); setShowCorrectAnswers(!showCorrectAnswers);
@ -39,7 +43,7 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
const calculateCorrectAnswerRate = () => { const calculateCorrectAnswerRate = () => {
if (!students || students.length === 0) { if (!students || students.length === 0) {
setCorrectAnswerRate(0); // Safeguard against undefined or empty student array setSubmissionCounts({ correctSubmissions: 0, totalSubmissions: 0 });
return; return;
} }
@ -49,12 +53,18 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
ans.idQuestion === Number(question.id) && ans.isCorrect ans.idQuestion === Number(question.id) && ans.isCorrect
) )
).length; ).length;
setSubmissionCounts({
correctSubmissions,
totalSubmissions
});
setCorrectAnswerRate((correctSubmissions / totalSubmissions) * 100); setCorrectAnswerRate((correctSubmissions / totalSubmissions) * 100);
}; };
return ( return (
<div className="question-wrapper"> <div className="question-wrapper">
<div className="question content"> <div>
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
</div> </div>
{showAnswer ? ( {showAnswer ? (
@ -122,7 +132,7 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
visibility: showCorrectAnswers ? 'visible' : 'hidden' visibility: showCorrectAnswers ? 'visible' : 'hidden'
}}> }}>
<div> <div>
Taux de réponse correcte: Taux de réponse correcte: {submissionCounts.correctSubmissions}/{submissionCounts.totalSubmissions}
</div> </div>
<div className="progress-bar-container"> <div className="progress-bar-container">
<div className="progress-bar-fill" style={{ width: `${correctAnswerRate}%` }}></div> <div className="progress-bar-fill" style={{ width: `${correctAnswerRate}%` }}></div>

View file

@ -32,7 +32,6 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
}; };
useEffect(() => { useEffect(() => {
console.log("passedAnswer", passedAnswer);
if (passedAnswer === true || passedAnswer === false) { if (passedAnswer === true || passedAnswer === false) {
setAnswer(passedAnswer); setAnswer(passedAnswer);
} else { } else {
@ -96,15 +95,14 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
<div className={`circle ${selectedTrue}`}>V</div> <div className={`circle ${selectedTrue}`}>V</div>
<div className={`answer-text ${selectedTrue}`} <div className={`answer-text ${selectedTrue}`}
style={showCorrectAnswers ? { style={showCorrectAnswers ? {
backgroundImage: `linear-gradient(to right, ${question.isTrue ? 'lightgreen' : 'lightcoral'} ${pickRates.trueRate}%, transparent ${pickRates.trueRate}%)` backgroundImage: `linear-gradient(to right, ${question.isTrue ? 'royalblue' : 'orange'} ${pickRates.trueRate}%, transparent ${pickRates.trueRate}%)`
} : {}} } : {}}
> >
Vrai Vrai
</div> </div>
{showCorrectAnswers && ( {showCorrectAnswers && (
<> <>
<div>{question.isTrue ? '✅' : '❌'}</div> <div className="pick-rate">{question.isTrue ? '✅' : '❌'} {pickRates.trueRate.toFixed(1)}%</div>
<div className="pick-rate">{pickRates.trueRate.toFixed(1)}%</div>
</> </>
)} )}
@ -125,7 +123,7 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
<div <div
className={`answer-text ${selectedFalse}`} className={`answer-text ${selectedFalse}`}
style={showCorrectAnswers ? { style={showCorrectAnswers ? {
backgroundImage: `linear-gradient(to right, ${!question.isTrue ? 'lightgreen' : 'lightcoral'} ${pickRates.falseRate}%, transparent ${pickRates.falseRate}%)`, backgroundImage: `linear-gradient(to right, ${!question.isTrue ? 'royalblue' : 'orange'} ${pickRates.falseRate}%, transparent ${pickRates.falseRate}%)`,
} : {}} } : {}}
> >
Faux Faux
@ -133,8 +131,7 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
{showCorrectAnswers && ( {showCorrectAnswers && (
<> <>
<div>{!question.isTrue ? '✅' : '❌'}</div> <div className="pick-rate">{!question.isTrue ? '✅' : '❌'} {pickRates.falseRate.toFixed(1)}%</div>
<div className="pick-rate">{pickRates.falseRate.toFixed(1)}%</div>
</> </>
)} )}

View file

@ -182,7 +182,7 @@
.progress-bar-fill { .progress-bar-fill {
height: 100%; height: 100%;
background-color: lightgreen; background-color: royalblue;
width: 0%; width: 0%;
transition: width 0.6s ease; transition: width 0.6s ease;
} }
@ -196,3 +196,8 @@
color: Black; color: Black;
} }
.pick-rate{
color: rgba(0,0,0,1);
min-width: 70px;
}

View file

@ -6,6 +6,7 @@ import { BrowserRouter } from 'react-router-dom';
import { ThemeProvider, createTheme } from '@mui/material'; import { ThemeProvider, createTheme } from '@mui/material';
import '@fortawesome/fontawesome-free/css/all.min.css'; import '@fortawesome/fontawesome-free/css/all.min.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import './cssReset.css'; import './cssReset.css';
import './index.css'; import './index.css';