From df617db28ba31001c0608fc907c157533f566478 Mon Sep 17 00:00:00 2001 From: JubaAzul <118773284+JubaAzul@users.noreply.github.com> Date: Fri, 7 Feb 2025 12:47:33 -0500 Subject: [PATCH] Refactoriser la classe LiveResult Fixes #236 --- .../components/LiveResults/LiveResults.tsx | 389 +----------------- .../LiveResults/LiveResultsTable.tsx | 215 ++++++++++ 2 files changed, 224 insertions(+), 380 deletions(-) create mode 100644 client/src/components/LiveResults/LiveResultsTable.tsx diff --git a/client/src/components/LiveResults/LiveResults.tsx b/client/src/components/LiveResults/LiveResults.tsx index 6bcd7ce..a230630 100644 --- a/client/src/components/LiveResults/LiveResults.tsx +++ b/client/src/components/LiveResults/LiveResults.tsx @@ -1,26 +1,16 @@ // LiveResults.tsx -import React, { useMemo, useState } from 'react'; +import React, { useState } from 'react'; import { Socket } from 'socket.io-client'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faCheck, faCircleXmark } from '@fortawesome/free-solid-svg-icons'; import { QuestionType } from '../../Types/QuestionType'; import './liveResult.css'; import { FormControlLabel, FormGroup, - Paper, Switch, - Table, - TableBody, - TableCell, - TableContainer, - TableFooter, - TableHead, - TableRow } from '@mui/material'; import { StudentType } from '../../Types/StudentType'; -import { formatLatex } from '../GiftTemplate/templates/TextTypeTemplate'; +import LiveResultsTable from './LiveResultsTable'; interface LiveResultsProps { socket: Socket | null; @@ -30,239 +20,11 @@ interface LiveResultsProps { students: StudentType[] } -// interface Answer { -// answer: string | number | boolean; -// isCorrect: boolean; -// idQuestion: number; -// } - -// interface StudentResult { -// username: string; -// idUser: string; -// answers: Answer[]; -// } const LiveResults: React.FC = ({ questions, showSelectedQuestion, students }) => { const [showUsernames, setShowUsernames] = useState(false); const [showCorrectAnswers, setShowCorrectAnswers] = useState(false); - // const [students, setStudents] = useState(initialStudents); - // const [studentResultsMap, setStudentResultsMap] = useState>(new Map()); - const maxQuestions = questions.length; - - // useEffect(() => { - // // Initialize the map with the current students - // const newStudentResultsMap = new Map(); - - // for (const student of students) { - // newStudentResultsMap.set(student.id, { username: student.name, idUser: student.id, answers: [] }); - // } - - // setStudentResultsMap(newStudentResultsMap); - // }, []) - - // update when students change - // useEffect(() => { - // // studentResultsMap is inconsistent with students -- need to update - - // for (const student of students as StudentType[]) { - // } - - // }, [students]) - - // useEffect(() => { - // if (socket) { - // const submitAnswerHandler = ({ - // idUser, - // answer, - // idQuestion - // }: { - // idUser: string; - // username: string; - // answer: string | number | boolean; - // idQuestion: number; - // }) => { - // console.log(`Received answer from ${idUser} for question ${idQuestion}: ${answer}`); - - // // print the list of current student names - // console.log('Current students:'); - // students.forEach((student) => { - // console.log(student.name); - // }); - - // // Update the students state using the functional form of setStudents - // setStudents((prevStudents) => { - // let foundStudent = false; - // const updatedStudents = prevStudents.map((student) => { - // if (student.id === idUser) { - // foundStudent = true; - // const updatedAnswers = student.answers.map((ans) => { - // const newAnswer: Answer = { answer, isCorrect: checkIfIsCorrect(answer, idQuestion), idQuestion }; - // console.log(`Updating answer for ${student.name} for question ${idQuestion} to ${answer}`); - // return (ans.idQuestion === idQuestion ? { ...ans, newAnswer } : ans); - // } - // ); - // return { ...student, answers: updatedAnswers }; - // } - // return student; - // }); - // if (!foundStudent) { - // console.log(`Student ${idUser} not found in the list of students in LiveResults`); - // } - // return updatedStudents; - // }); - - - // // make a copy of the students array so we can update it - // // const updatedStudents = [...students]; - - // // const student = updatedStudents.find((student) => student.id === idUser); - // // if (!student) { - // // // this is a bad thing if an answer was submitted but the student isn't in the list - // // console.log(`Student ${idUser} not found in the list of students in LiveResults`); - // // return; - // // } - - // // const isCorrect = checkIfIsCorrect(answer, idQuestion); - // // const newAnswer: Answer = { answer, isCorrect, idQuestion }; - // // student.answers.push(newAnswer); - // // // print list of answers - // // console.log('Answers:'); - // // student.answers.forEach((answer) => { - // // console.log(answer.answer); - // // }); - // // setStudents(updatedStudents); // update the state - // }; - - // socket.on('submit-answer', submitAnswerHandler); - // return () => { - // socket.off('submit-answer'); - // }; - // } - // }, [socket]); - - const getStudentGrade = (student: StudentType): number => { - if (student.answers.length === 0) { - return 0; - } - - const uniqueQuestions = new Set(); - let correctAnswers = 0; - - for (const answer of student.answers) { - const { idQuestion, isCorrect } = answer; - - if (!uniqueQuestions.has(idQuestion)) { - uniqueQuestions.add(idQuestion); - - if (isCorrect) { - correctAnswers++; - } - } - } - - return (correctAnswers / questions.length) * 100; - }; - - const classAverage: number = useMemo(() => { - let classTotal = 0; - - students.forEach((student) => { - classTotal += getStudentGrade(student); - }); - - return classTotal / students.length; - }, [students]); - - const getCorrectAnswersPerQuestion = (index: number): number => { - return ( - (students.filter((student) => - student.answers.some( - (answer) => - parseInt(answer.idQuestion.toString()) === index + 1 && answer.isCorrect - ) - ).length / students.length) * 100 - ); - }; - - // (studentResults.filter((student) => - // student.answers.some( - // (answer) => - // parseInt(answer.idQuestion.toString()) === index + 1 && answer.isCorrect - // ) - // ).length / - // studentResults.length) * - // 100 - // ); - // }; - - // function checkIfIsCorrect(answer: string | number | boolean, idQuestion: number): boolean { - // const questionInfo = questions.find((q) => - // q.question.id ? q.question.id === idQuestion.toString() : false - // ) as QuestionType | undefined; - - // const answerText = answer.toString(); - // if (questionInfo) { - // const question = questionInfo.question as GIFTQuestion; - // if (question.type === 'TF') { - // return ( - // (question.isTrue && answerText == 'true') || - // (!question.isTrue && answerText == 'false') - // ); - // } else if (question.type === 'MC') { - // return question.choices.some( - // (choice) => choice.isCorrect && choice.text.text === answerText - // ); - // } else if (question.type === 'Numerical') { - // if (question.choices && !Array.isArray(question.choices)) { - // if ( - // question.choices.type === 'high-low' && - // question.choices.numberHigh && - // question.choices.numberLow - // ) { - // const answerNumber = parseFloat(answerText); - // if (!isNaN(answerNumber)) { - // return ( - // answerNumber <= question.choices.numberHigh && - // answerNumber >= question.choices.numberLow - // ); - // } - // } - // } - // if (question.choices && Array.isArray(question.choices)) { - // if ( - // question.choices[0].text.type === 'range' && - // question.choices[0].text.number && - // question.choices[0].text.range - // ) { - // const answerNumber = parseFloat(answerText); - // const range = question.choices[0].text.range; - // const correctAnswer = question.choices[0].text.number; - // if (!isNaN(answerNumber)) { - // return ( - // answerNumber <= correctAnswer + range && - // answerNumber >= correctAnswer - range - // ); - // } - // } - // if ( - // question.choices[0].text.type === 'simple' && - // question.choices[0].text.number - // ) { - // const answerNumber = parseFloat(answerText); - // if (!isNaN(answerNumber)) { - // return answerNumber === question.choices[0].text.number; - // } - // } - // } - // } else if (question.type === 'Short') { - // return question.choices.some( - // (choice) => choice.text.text.toUpperCase() === answerText.toUpperCase() - // ); - // } - // } - // return false; - // } return (
@@ -295,146 +57,13 @@ const LiveResults: React.FC = ({ questions, showSelectedQuesti
- - - - - -
Nom d'utilisateur
-
- {Array.from({ length: maxQuestions }, (_, index) => ( - showSelectedQuestion(index)} - > -
{`Q${index + 1}`}
-
- ))} - -
% réussite
-
-
-
- - {students.map((student) => ( - - -
- {showUsernames ? student.name : '******'} -
-
- {Array.from({ length: maxQuestions }, (_, index) => { - const answer = student.answers.find( - (answer) => parseInt(answer.idQuestion.toString()) === index + 1 - ); - const answerText = answer ? answer.answer.toString() : ''; - const isCorrect = answer ? answer.isCorrect : false; - - return ( - - {showCorrectAnswers ? ( -
{formatLatex(answerText)}
- ) : isCorrect ? ( - - ) : ( - answerText !== '' && ( - - ) - )} -
- ); - })} - - {getStudentGrade(student).toFixed()} % - -
- ))} -
- - - -
% réussite
-
- {Array.from({ length: maxQuestions }, (_, index) => ( - - {students.length > 0 - ? `${getCorrectAnswersPerQuestion(index).toFixed()} %` - : '-'} - - ))} - - {students.length > 0 ? `${classAverage.toFixed()} %` : '-'} - -
-
-
-
+
); diff --git a/client/src/components/LiveResults/LiveResultsTable.tsx b/client/src/components/LiveResults/LiveResultsTable.tsx new file mode 100644 index 0000000..bb81b80 --- /dev/null +++ b/client/src/components/LiveResults/LiveResultsTable.tsx @@ -0,0 +1,215 @@ +import React, { useMemo } from 'react'; +import { Paper, Table, TableBody, TableCell, TableContainer, TableFooter, TableHead, TableRow } from '@mui/material'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCheck, faCircleXmark } from '@fortawesome/free-solid-svg-icons'; +import { StudentType } from 'src/Types/StudentType'; +import { QuestionType } from '../../Types/QuestionType'; +import { FormattedTextTemplate } from '../GiftTemplate/templates/TextTypeTemplate'; + +interface LiveResultsTableProps { + students: StudentType[]; + questions: QuestionType[]; + showCorrectAnswers: boolean; + showSelectedQuestion: (index: number) => void; + showUsernames: boolean; +} + +const LiveResultsTable: React.FC = ({ + questions, + students, + showCorrectAnswers, + showSelectedQuestion, + showUsernames +}) => { + + const maxQuestions = questions.length; + + const getStudentGrade = (student: StudentType): number => { + if (student.answers.length === 0) { + return 0; + } + + const uniqueQuestions = new Set(); + let correctAnswers = 0; + + for (const answer of student.answers) { + const { idQuestion, isCorrect } = answer; + + if (!uniqueQuestions.has(idQuestion)) { + uniqueQuestions.add(idQuestion); + + if (isCorrect) { + correctAnswers++; + } + } + } + + return (correctAnswers / questions.length) * 100; + }; + + const classAverage: number = useMemo(() => { + let classTotal = 0; + + students.forEach((student) => { + classTotal += getStudentGrade(student); + }); + + return classTotal / students.length; + }, [students]); + + const getCorrectAnswersPerQuestion = (index: number): number => { + return ( + (students.filter((student) => + student.answers.some( + (answer) => + parseInt(answer.idQuestion.toString()) === index + 1 && answer.isCorrect + ) + ).length / students.length) * 100 + ); + }; + + return ( + + + + + +
Nom d'utilisateur
+
+ {Array.from({ length: maxQuestions }, (_, index) => ( + showSelectedQuestion(index)} + > +
{`Q${index + 1}`}
+
+ ))} + +
% réussite
+
+
+
+ + {students.map((student) => ( + + +
+ {showUsernames ? student.name : '******'} +
+
+ {Array.from({ length: maxQuestions }, (_, index) => { + const answer = student.answers.find( + (answer) => parseInt(answer.idQuestion.toString()) === index + 1 + ); + const answerText = answer ? answer.answer.toString() : ''; + const isCorrect = answer ? answer.isCorrect : false; + + return ( + + {showCorrectAnswers ? ( +
+ ) : isCorrect ? ( + + ) : ( + answerText !== '' && ( + + ) + )} +
+ ); + })} + + {getStudentGrade(student).toFixed()} % + +
+ ))} +
+ + + +
% réussite
+
+ {Array.from({ length: maxQuestions }, (_, index) => ( + + {students.length > 0 + ? `${getCorrectAnswersPerQuestion(index).toFixed()} %` + : '-'} + + ))} + + {students.length > 0 ? `${classAverage.toFixed()} %` : '-'} + +
+
+
+
+ ); +}; + +export default LiveResultsTable; \ No newline at end of file