mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
One StudentType that also has answers
This commit is contained in:
parent
fa4b6b5bd3
commit
91fa75131a
7 changed files with 85 additions and 93 deletions
|
|
@ -8,5 +8,5 @@ export interface StudentType {
|
||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
room?: string;
|
room?: string;
|
||||||
answers?: Answer[];
|
answers: Answer[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
//StudentType.test.tsx
|
//StudentType.test.tsx
|
||||||
import { StudentType } from "../../Types/StudentType";
|
import { StudentType, Answer } from "../../Types/StudentType";
|
||||||
|
|
||||||
const user : StudentType = {
|
const user : StudentType = {
|
||||||
name: 'Student',
|
name: 'Student',
|
||||||
id: '123'
|
id: '123',
|
||||||
|
answers: new Array<Answer>()
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('StudentType', () => {
|
describe('StudentType', () => {
|
||||||
test('creates a student with name and id', () => {
|
test('creates a student with name, id and answers', () => {
|
||||||
|
|
||||||
expect(user.name).toBe('Student');
|
expect(user.name).toBe('Student');
|
||||||
expect(user.id).toBe('123');
|
expect(user.id).toBe('123');
|
||||||
|
expect(user.answers.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,17 @@
|
||||||
import { render, screen, fireEvent } from '@testing-library/react';
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom';
|
||||||
import StudentWaitPage from '../../../components/StudentWaitPage/StudentWaitPage';
|
import StudentWaitPage from '../../../components/StudentWaitPage/StudentWaitPage';
|
||||||
|
import { StudentType, Answer } from '../../../Types/StudentType';
|
||||||
|
|
||||||
describe('StudentWaitPage Component', () => {
|
describe('StudentWaitPage Component', () => {
|
||||||
const mockUsers = [
|
const mockUsers: StudentType[] = [
|
||||||
{ id: '1', name: 'User1' },
|
{ id: '1', name: 'User1', answers: new Array<Answer>() },
|
||||||
{ id: '2', name: 'User2' },
|
{ id: '2', name: 'User2', answers: new Array<Answer>() },
|
||||||
{ id: '3', name: 'User3' },
|
{ id: '3', name: 'User3', answers: new Array<Answer>() },
|
||||||
];
|
];
|
||||||
|
|
||||||
const mockProps = {
|
const mockProps = {
|
||||||
users: mockUsers,
|
students: mockUsers,
|
||||||
launchQuiz: jest.fn(),
|
launchQuiz: jest.fn(),
|
||||||
roomName: 'Test Room',
|
roomName: 'Test Room',
|
||||||
setQuizMode: jest.fn(),
|
setQuizMode: jest.fn(),
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import {
|
||||||
TableHead,
|
TableHead,
|
||||||
TableRow
|
TableRow
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { StudentType } from '../../Types/StudentType';
|
import { StudentType, Answer } from '../../Types/StudentType';
|
||||||
import { formatLatex } from '../GiftTemplate/templates/TextType';
|
import { formatLatex } from '../GiftTemplate/templates/TextType';
|
||||||
|
|
||||||
interface LiveResultsProps {
|
interface LiveResultsProps {
|
||||||
|
|
@ -27,50 +27,53 @@ interface LiveResultsProps {
|
||||||
questions: QuestionType[];
|
questions: QuestionType[];
|
||||||
showSelectedQuestion: (index: number) => void;
|
showSelectedQuestion: (index: number) => void;
|
||||||
quizMode: 'teacher' | 'student';
|
quizMode: 'teacher' | 'student';
|
||||||
students: StudentType[]
|
connectedStudents: StudentType[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Answer {
|
// interface Answer {
|
||||||
answer: string | number | boolean;
|
// answer: string | number | boolean;
|
||||||
isCorrect: boolean;
|
// isCorrect: boolean;
|
||||||
idQuestion: number;
|
// idQuestion: number;
|
||||||
}
|
// }
|
||||||
|
|
||||||
interface StudentResult {
|
// interface StudentResult {
|
||||||
username: string;
|
// username: string;
|
||||||
idUser: string;
|
// idUser: string;
|
||||||
answers: Answer[];
|
// answers: Answer[];
|
||||||
}
|
// }
|
||||||
|
|
||||||
const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelectedQuestion, students }) => {
|
const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelectedQuestion, connectedStudents }) => {
|
||||||
const [showUsernames, setShowUsernames] = useState<boolean>(false);
|
const [showUsernames, setShowUsernames] = useState<boolean>(false);
|
||||||
const [showCorrectAnswers, setShowCorrectAnswers] = useState<boolean>(false);
|
const [showCorrectAnswers, setShowCorrectAnswers] = useState<boolean>(false);
|
||||||
const [studentResultsMap, setStudentResultsMap] = useState<Map<string, StudentResult>>(new Map());
|
const [students, setStudents] = useState<StudentType[]>(connectedStudents);
|
||||||
|
// const [studentResultsMap, setStudentResultsMap] = useState<Map<string, StudentResult>>(new Map());
|
||||||
|
|
||||||
const maxQuestions = questions.length;
|
const maxQuestions = questions.length;
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
// Initialize the map with the current students
|
// // Initialize the map with the current students
|
||||||
const newStudentResultsMap = new Map<string, StudentResult>();
|
// const newStudentResultsMap = new Map<string, StudentResult>();
|
||||||
|
|
||||||
for (const student of students) {
|
// for (const student of students) {
|
||||||
newStudentResultsMap.set(student.id, { username: student.name, idUser: student.id, answers: [] });
|
// newStudentResultsMap.set(student.id, { username: student.name, idUser: student.id, answers: [] });
|
||||||
}
|
// }
|
||||||
|
|
||||||
setStudentResultsMap(newStudentResultsMap);
|
// setStudentResultsMap(newStudentResultsMap);
|
||||||
}, [])
|
// }, [])
|
||||||
|
|
||||||
// update when students change
|
// update when students change
|
||||||
|
// useEffect(() => {
|
||||||
|
// // studentResultsMap is inconsistent with students -- need to update
|
||||||
|
|
||||||
|
// for (const student of students as StudentType[]) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }, [students])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// studentResultsMap is inconsistent with students -- need to update
|
// Update the students state when the initialStudents prop changes
|
||||||
|
setStudents(connectedStudents);
|
||||||
|
}, [connectedStudents]);
|
||||||
|
|
||||||
for (const student of students as StudentType[]) {
|
|
||||||
if (!studentResultsMap.has(student.id)) {
|
|
||||||
studentResultsMap.set(student.id, { username: student.name, idUser: student.id, answers: [] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [students])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket) {
|
if (socket) {
|
||||||
|
|
@ -84,35 +87,19 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
|
||||||
answer: string | number | boolean;
|
answer: string | number | boolean;
|
||||||
idQuestion: number;
|
idQuestion: number;
|
||||||
}) => {
|
}) => {
|
||||||
// Update the student results in the map with the answer
|
// make a copy of the students array so we can update it
|
||||||
setStudentResultsMap((currentResults) => {
|
const updatedStudents = [...students];
|
||||||
const studentResult = currentResults.get(idUser);
|
|
||||||
if (!studentResult) {
|
const student = updatedStudents.find((student) => student.id === idUser);
|
||||||
return currentResults;
|
if (!student) {
|
||||||
|
// this is a bad thing if an answer was submitted but the student isn't in the list
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCorrect = checkIfIsCorrect(answer, idQuestion);
|
const isCorrect = checkIfIsCorrect(answer, idQuestion);
|
||||||
studentResult.answers.push({ answer, isCorrect, idQuestion });
|
const newAnswer: Answer = { answer, isCorrect, idQuestion };
|
||||||
return new Map(currentResults).set(idUser, studentResult);
|
student.answers.push(newAnswer);
|
||||||
});
|
setStudents(updatedStudents); // update the state
|
||||||
|
|
||||||
|
|
||||||
// setStudentResults((currentResults) => {
|
|
||||||
// const userIndex = currentResults.findIndex(
|
|
||||||
// (result) => result.idUser === idUser
|
|
||||||
// );
|
|
||||||
// const isCorrect = checkIfIsCorrect(answer, idQuestion);
|
|
||||||
// if (userIndex !== -1) {
|
|
||||||
// const newResults = [...currentResults];
|
|
||||||
// newResults[userIndex].answers.push({ answer, isCorrect, idQuestion });
|
|
||||||
// return newResults;
|
|
||||||
// } else {
|
|
||||||
// return [
|
|
||||||
// ...currentResults,
|
|
||||||
// { idUser, username, answers: [{ answer, isCorrect, idQuestion }] }
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.on('submit-answer', submitAnswerHandler);
|
socket.on('submit-answer', submitAnswerHandler);
|
||||||
|
|
@ -122,7 +109,7 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
|
||||||
}
|
}
|
||||||
}, [socket]);
|
}, [socket]);
|
||||||
|
|
||||||
const getStudentGrade = (student: StudentResult): number => {
|
const getStudentGrade = (student: StudentType): number => {
|
||||||
if (student.answers.length === 0) {
|
if (student.answers.length === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -148,24 +135,21 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
|
||||||
const classAverage: number = useMemo(() => {
|
const classAverage: number = useMemo(() => {
|
||||||
let classTotal = 0;
|
let classTotal = 0;
|
||||||
|
|
||||||
const studentResults = Array.from(studentResultsMap.values());
|
students.forEach((student) => {
|
||||||
|
|
||||||
studentResults.forEach((student) => {
|
|
||||||
classTotal += getStudentGrade(student);
|
classTotal += getStudentGrade(student);
|
||||||
});
|
});
|
||||||
|
|
||||||
return classTotal / studentResults.length;
|
return classTotal / students.length;
|
||||||
}, [studentResultsMap]);
|
}, [students]);
|
||||||
|
|
||||||
const getCorrectAnswersPerQuestion = (index: number): number => {
|
const getCorrectAnswersPerQuestion = (index: number): number => {
|
||||||
return (
|
return (
|
||||||
(Array.from(studentResultsMap.values()).filter((student) =>
|
(students.filter((student) =>
|
||||||
student.answers.some(
|
student.answers.some(
|
||||||
(answer) =>
|
(answer) =>
|
||||||
parseInt(answer.idQuestion.toString()) === index + 1 && answer.isCorrect
|
parseInt(answer.idQuestion.toString()) === index + 1 && answer.isCorrect
|
||||||
)
|
)
|
||||||
).length / studentResultsMap.size) *
|
).length / students.length) * 100
|
||||||
100
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -314,8 +298,8 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{Array.from(studentResultsMap.values()).map((student) => (
|
{students.map((student) => (
|
||||||
<TableRow key={student.idUser}>
|
<TableRow key={student.id}>
|
||||||
<TableCell
|
<TableCell
|
||||||
className="sticky-column"
|
className="sticky-column"
|
||||||
sx={{
|
sx={{
|
||||||
|
|
@ -325,7 +309,7 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="text-base">
|
<div className="text-base">
|
||||||
{showUsernames ? student.username : '******'}
|
{showUsernames ? student.name : '******'}
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
{Array.from({ length: maxQuestions }, (_, index) => {
|
{Array.from({ length: maxQuestions }, (_, index) => {
|
||||||
|
|
@ -396,7 +380,7 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
|
||||||
color: 'rgba(0, 0, 0)'
|
color: 'rgba(0, 0, 0)'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{studentResultsMap.size > 0
|
{students.length > 0
|
||||||
? `${getCorrectAnswersPerQuestion(index).toFixed()} %`
|
? `${getCorrectAnswersPerQuestion(index).toFixed()} %`
|
||||||
: '-'}
|
: '-'}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
@ -412,7 +396,7 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
|
||||||
color: 'rgba(0, 0, 0)'
|
color: 'rgba(0, 0, 0)'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{studentResultsMap.size > 0 ? `${classAverage.toFixed()} %` : '-'}
|
{students.length > 0 ? `${classAverage.toFixed()} %` : '-'}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableFooter>
|
</TableFooter>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button, Chip, Grid } from '@mui/material';
|
import { Box, Button, Chip } from '@mui/material';
|
||||||
import { StudentType } from '../../Types/StudentType';
|
import { StudentType } from '../../Types/StudentType';
|
||||||
import { PlayArrow } from '@mui/icons-material';
|
import { PlayArrow } from '@mui/icons-material';
|
||||||
import LaunchQuizDialog from '../LaunchQuizDialog/LaunchQuizDialog';
|
import LaunchQuizDialog from '../LaunchQuizDialog/LaunchQuizDialog';
|
||||||
|
|
@ -6,12 +6,12 @@ import { useState } from 'react';
|
||||||
import './studentWaitPage.css';
|
import './studentWaitPage.css';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
users: StudentType[];
|
students: StudentType[];
|
||||||
launchQuiz: () => void;
|
launchQuiz: () => void;
|
||||||
setQuizMode: (mode: 'student' | 'teacher') => void;
|
setQuizMode: (mode: 'student' | 'teacher') => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StudentWaitPage: React.FC<Props> = ({ users, launchQuiz, setQuizMode }) => {
|
const StudentWaitPage: React.FC<Props> = ({ students, launchQuiz, setQuizMode }) => {
|
||||||
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false);
|
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -30,15 +30,15 @@ const StudentWaitPage: React.FC<Props> = ({ users, launchQuiz, setQuizMode }) =>
|
||||||
|
|
||||||
<div className="students">
|
<div className="students">
|
||||||
|
|
||||||
<Grid container spacing={3}>
|
<Box display="flex" flexWrap="wrap" gap={3}>
|
||||||
|
|
||||||
{users.map((user, index) => (
|
{students.map((student, index) => (
|
||||||
<Grid item key={user.name + index}>
|
<Box key={student.name + index} >
|
||||||
<Chip label={user.name} sx={{ width: '100%' }} />
|
<Chip label={student.name} sx={{ width: '100%' }} />
|
||||||
</Grid>
|
</Box>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
</Grid>
|
</Box>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ const ManageRoom: React.FC = () => {
|
||||||
setSocket(null);
|
setSocket(null);
|
||||||
setQuizQuestions(undefined);
|
setQuizQuestions(undefined);
|
||||||
setCurrentQuestion(undefined);
|
setCurrentQuestion(undefined);
|
||||||
setStudents([]);
|
setStudents(new Array<StudentType>());
|
||||||
setRoomName('');
|
setRoomName('');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -293,7 +293,7 @@ const ManageRoom: React.FC = () => {
|
||||||
socket={socket}
|
socket={socket}
|
||||||
questions={quizQuestions}
|
questions={quizQuestions}
|
||||||
showSelectedQuestion={showSelectedQuestion}
|
showSelectedQuestion={showSelectedQuestion}
|
||||||
students={students}
|
connectedStudents={students}
|
||||||
></LiveResultsComponent>
|
></LiveResultsComponent>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -312,7 +312,7 @@ const ManageRoom: React.FC = () => {
|
||||||
) : (
|
) : (
|
||||||
|
|
||||||
<StudentWaitPage
|
<StudentWaitPage
|
||||||
users={students}
|
students={students}
|
||||||
launchQuiz={launchQuiz}
|
launchQuiz={launchQuiz}
|
||||||
setQuizMode={setQuizMode}
|
setQuizMode={setQuizMode}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -49,10 +49,15 @@ const setupWebsocket = (io) => {
|
||||||
io.sockets.adapter.rooms.get(enteredRoomName).size;
|
io.sockets.adapter.rooms.get(enteredRoomName).size;
|
||||||
|
|
||||||
if (clientsInRoom <= MAX_USERS_PER_ROOM) {
|
if (clientsInRoom <= MAX_USERS_PER_ROOM) {
|
||||||
|
const newStudent = {
|
||||||
|
id: socket.id,
|
||||||
|
name: username,
|
||||||
|
answers: [],
|
||||||
|
};
|
||||||
socket.join(enteredRoomName);
|
socket.join(enteredRoomName);
|
||||||
socket
|
socket
|
||||||
.to(enteredRoomName)
|
.to(enteredRoomName)
|
||||||
.emit("user-joined", { name: username, id: socket.id });
|
.emit("user-joined", newStudent);
|
||||||
socket.emit("join-success");
|
socket.emit("join-success");
|
||||||
} else {
|
} else {
|
||||||
socket.emit("join-failure", "La salle est remplie");
|
socket.emit("join-failure", "La salle est remplie");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue