2024-03-29 20:08:34 -04:00
|
|
|
// LiveResults.tsx
|
|
|
|
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
|
|
|
import { Socket } from 'socket.io-client';
|
|
|
|
|
import { GIFTQuestion } from 'gift-pegjs';
|
|
|
|
|
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,
|
|
|
|
|
TableFooter,
|
|
|
|
|
TableHead,
|
|
|
|
|
TableRow
|
|
|
|
|
} from '@mui/material';
|
2024-09-25 14:53:17 -04:00
|
|
|
import { StudentType, Answer } from '../../Types/StudentType';
|
2024-09-23 15:55:37 -04:00
|
|
|
import { formatLatex } from '../GiftTemplate/templates/TextType';
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
interface LiveResultsProps {
|
|
|
|
|
socket: Socket | null;
|
|
|
|
|
questions: QuestionType[];
|
|
|
|
|
showSelectedQuestion: (index: number) => void;
|
|
|
|
|
quizMode: 'teacher' | 'student';
|
2024-09-25 14:53:17 -04:00
|
|
|
connectedStudents: StudentType[]
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
// interface Answer {
|
|
|
|
|
// answer: string | number | boolean;
|
|
|
|
|
// isCorrect: boolean;
|
|
|
|
|
// idQuestion: number;
|
|
|
|
|
// }
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
// interface StudentResult {
|
|
|
|
|
// username: string;
|
|
|
|
|
// idUser: string;
|
|
|
|
|
// answers: Answer[];
|
|
|
|
|
// }
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelectedQuestion, connectedStudents }) => {
|
2024-03-29 20:08:34 -04:00
|
|
|
const [showUsernames, setShowUsernames] = useState<boolean>(false);
|
|
|
|
|
const [showCorrectAnswers, setShowCorrectAnswers] = useState<boolean>(false);
|
2024-09-25 14:53:17 -04:00
|
|
|
const [students, setStudents] = useState<StudentType[]>(connectedStudents);
|
|
|
|
|
// const [studentResultsMap, setStudentResultsMap] = useState<Map<string, StudentResult>>(new Map());
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
const maxQuestions = questions.length;
|
|
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
// useEffect(() => {
|
|
|
|
|
// // Initialize the map with the current students
|
|
|
|
|
// const newStudentResultsMap = new Map<string, StudentResult>();
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
// for (const student of students) {
|
|
|
|
|
// newStudentResultsMap.set(student.id, { username: student.name, idUser: student.id, answers: [] });
|
|
|
|
|
// }
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
// setStudentResultsMap(newStudentResultsMap);
|
|
|
|
|
// }, [])
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2024-09-25 11:17:06 -04:00
|
|
|
// update when students change
|
2024-09-25 14:53:17 -04:00
|
|
|
// useEffect(() => {
|
|
|
|
|
// // studentResultsMap is inconsistent with students -- need to update
|
2024-09-25 11:17:06 -04:00
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
// for (const student of students as StudentType[]) {
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// }, [students])
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
// Update the students state when the initialStudents prop changes
|
|
|
|
|
setStudents(connectedStudents);
|
2024-09-25 16:31:38 -04:00
|
|
|
console.log(`useEffect: connectedStudents: ${JSON.stringify(connectedStudents)}`);
|
2024-09-25 14:53:17 -04:00
|
|
|
}, [connectedStudents]);
|
2024-09-25 11:17:06 -04:00
|
|
|
|
|
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (socket) {
|
|
|
|
|
const submitAnswerHandler = ({
|
|
|
|
|
idUser,
|
|
|
|
|
answer,
|
|
|
|
|
idQuestion
|
|
|
|
|
}: {
|
|
|
|
|
idUser: string;
|
|
|
|
|
username: string;
|
|
|
|
|
answer: string | number | boolean;
|
|
|
|
|
idQuestion: number;
|
|
|
|
|
}) => {
|
2024-09-25 16:31:38 -04:00
|
|
|
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;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
// make a copy of the students array so we can update it
|
2024-09-25 16:31:38 -04:00
|
|
|
// 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
|
2024-03-29 20:08:34 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
socket.on('submit-answer', submitAnswerHandler);
|
|
|
|
|
return () => {
|
|
|
|
|
socket.off('submit-answer');
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}, [socket]);
|
|
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
const getStudentGrade = (student: StudentType): number => {
|
2024-03-29 20:08:34 -04:00
|
|
|
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;
|
2024-09-25 11:17:06 -04:00
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
students.forEach((student) => {
|
2024-03-29 20:08:34 -04:00
|
|
|
classTotal += getStudentGrade(student);
|
|
|
|
|
});
|
|
|
|
|
|
2024-09-25 14:53:17 -04:00
|
|
|
return classTotal / students.length;
|
|
|
|
|
}, [students]);
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
const getCorrectAnswersPerQuestion = (index: number): number => {
|
|
|
|
|
return (
|
2024-09-25 14:53:17 -04:00
|
|
|
(students.filter((student) =>
|
2024-03-29 20:08:34 -04:00
|
|
|
student.answers.some(
|
|
|
|
|
(answer) =>
|
|
|
|
|
parseInt(answer.idQuestion.toString()) === index + 1 && answer.isCorrect
|
|
|
|
|
)
|
2024-09-25 14:53:17 -04:00
|
|
|
).length / students.length) * 100
|
2024-03-29 20:08:34 -04:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2024-09-25 11:17:06 -04:00
|
|
|
// (studentResults.filter((student) =>
|
|
|
|
|
// student.answers.some(
|
|
|
|
|
// (answer) =>
|
|
|
|
|
// parseInt(answer.idQuestion.toString()) === index + 1 && answer.isCorrect
|
|
|
|
|
// )
|
|
|
|
|
// ).length /
|
|
|
|
|
// studentResults.length) *
|
|
|
|
|
// 100
|
|
|
|
|
// );
|
|
|
|
|
// };
|
|
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
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 (
|
|
|
|
|
<div>
|
|
|
|
|
<div className="action-bar mb-1">
|
|
|
|
|
<div className="text-2xl text-bold">Résultats du quiz</div>
|
|
|
|
|
<FormGroup row>
|
|
|
|
|
<FormControlLabel
|
|
|
|
|
label={<div className="text-sm">Afficher les noms</div>}
|
|
|
|
|
control={
|
|
|
|
|
<Switch
|
|
|
|
|
value={showUsernames}
|
|
|
|
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
|
|
|
setShowUsernames(e.target.checked)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
<FormControlLabel
|
|
|
|
|
label={<div className="text-sm">Afficher les réponses</div>}
|
|
|
|
|
control={
|
|
|
|
|
<Switch
|
|
|
|
|
value={showCorrectAnswers}
|
|
|
|
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
|
|
|
setShowCorrectAnswers(e.target.checked)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</FormGroup>
|
|
|
|
|
</div>
|
|
|
|
|
|
2024-09-24 09:49:15 -04:00
|
|
|
<div className="table-container">
|
|
|
|
|
<Table size="small" component={Paper}>
|
2024-03-29 20:08:34 -04:00
|
|
|
<TableHead>
|
|
|
|
|
<TableRow>
|
2024-09-24 09:49:15 -04:00
|
|
|
<TableCell className="sticky-column">
|
2024-03-29 20:08:34 -04:00
|
|
|
<div className="text-base text-bold">Nom d'utilisateur</div>
|
|
|
|
|
</TableCell>
|
|
|
|
|
{Array.from({ length: maxQuestions }, (_, index) => (
|
|
|
|
|
<TableCell
|
|
|
|
|
key={index}
|
|
|
|
|
sx={{
|
|
|
|
|
textAlign: 'center',
|
2024-09-24 09:49:15 -04:00
|
|
|
cursor: 'pointer',
|
2024-03-29 20:08:34 -04:00
|
|
|
borderStyle: 'solid',
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: 'rgba(224, 224, 224, 1)'
|
|
|
|
|
}}
|
|
|
|
|
onClick={() => showSelectedQuestion(index)}
|
|
|
|
|
>
|
|
|
|
|
<div className="text-base text-bold blue">{`Q${index + 1}`}</div>
|
|
|
|
|
</TableCell>
|
|
|
|
|
))}
|
|
|
|
|
<TableCell
|
2024-09-24 09:49:15 -04:00
|
|
|
className="sticky-header"
|
2024-03-29 20:08:34 -04:00
|
|
|
sx={{
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
borderStyle: 'solid',
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: 'rgba(224, 224, 224, 1)'
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div className="text-base text-bold">% réussite</div>
|
|
|
|
|
</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
</TableHead>
|
|
|
|
|
<TableBody>
|
2024-09-25 14:53:17 -04:00
|
|
|
{students.map((student) => (
|
|
|
|
|
<TableRow key={student.id}>
|
2024-03-29 20:08:34 -04:00
|
|
|
<TableCell
|
2024-09-24 09:49:15 -04:00
|
|
|
className="sticky-column"
|
2024-03-29 20:08:34 -04:00
|
|
|
sx={{
|
|
|
|
|
borderStyle: 'solid',
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: 'rgba(224, 224, 224, 1)'
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div className="text-base">
|
2024-09-25 14:53:17 -04:00
|
|
|
{showUsernames ? student.name : '******'}
|
2024-03-29 20:08:34 -04:00
|
|
|
</div>
|
|
|
|
|
</TableCell>
|
|
|
|
|
{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;
|
2024-09-23 15:55:37 -04:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
return (
|
|
|
|
|
<TableCell
|
|
|
|
|
key={index}
|
|
|
|
|
sx={{
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
borderStyle: 'solid',
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: 'rgba(224, 224, 224, 1)'
|
|
|
|
|
}}
|
|
|
|
|
className={
|
|
|
|
|
answerText === ''
|
|
|
|
|
? ''
|
|
|
|
|
: isCorrect
|
|
|
|
|
? 'correct-answer'
|
|
|
|
|
: 'incorrect-answer'
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{showCorrectAnswers ? (
|
2024-09-23 15:55:37 -04:00
|
|
|
<div>{formatLatex(answerText)}</div>
|
2024-03-29 20:08:34 -04:00
|
|
|
) : isCorrect ? (
|
|
|
|
|
<FontAwesomeIcon icon={faCheck} />
|
|
|
|
|
) : (
|
|
|
|
|
answerText !== '' && (
|
|
|
|
|
<FontAwesomeIcon icon={faCircleXmark} />
|
|
|
|
|
)
|
|
|
|
|
)}
|
|
|
|
|
</TableCell>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
<TableCell
|
|
|
|
|
sx={{
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
borderStyle: 'solid',
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: 'rgba(224, 224, 224, 1)',
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
color: 'rgba(0, 0, 0)'
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{getStudentGrade(student).toFixed()} %
|
|
|
|
|
</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
))}
|
|
|
|
|
</TableBody>
|
|
|
|
|
<TableFooter>
|
|
|
|
|
<TableRow sx={{ backgroundColor: '#d3d3d34f' }}>
|
2024-09-24 09:49:15 -04:00
|
|
|
<TableCell className="sticky-column" sx={{ color: 'black' }}>
|
2024-03-29 20:08:34 -04:00
|
|
|
<div className="text-base text-bold">% réussite</div>
|
|
|
|
|
</TableCell>
|
|
|
|
|
{Array.from({ length: maxQuestions }, (_, index) => (
|
|
|
|
|
<TableCell
|
|
|
|
|
key={index}
|
|
|
|
|
sx={{
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
borderStyle: 'solid',
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: 'rgba(224, 224, 224, 1)',
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
color: 'rgba(0, 0, 0)'
|
|
|
|
|
}}
|
|
|
|
|
>
|
2024-09-25 14:53:17 -04:00
|
|
|
{students.length > 0
|
2024-03-29 20:08:34 -04:00
|
|
|
? `${getCorrectAnswersPerQuestion(index).toFixed()} %`
|
|
|
|
|
: '-'}
|
|
|
|
|
</TableCell>
|
|
|
|
|
))}
|
|
|
|
|
<TableCell
|
|
|
|
|
sx={{
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
borderStyle: 'solid',
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
borderColor: 'rgba(224, 224, 224, 1)',
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
fontSize: '1rem',
|
|
|
|
|
color: 'rgba(0, 0, 0)'
|
|
|
|
|
}}
|
|
|
|
|
>
|
2024-09-25 14:53:17 -04:00
|
|
|
{students.length > 0 ? `${classAverage.toFixed()} %` : '-'}
|
2024-03-29 20:08:34 -04:00
|
|
|
</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
</TableFooter>
|
|
|
|
|
</Table>
|
|
|
|
|
</div>
|
2024-09-24 09:49:15 -04:00
|
|
|
</div>
|
2024-03-29 20:08:34 -04:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default LiveResults;
|