One StudentType that also has answers

This commit is contained in:
C. Fuhrman 2024-09-25 14:53:17 -04:00
parent fa4b6b5bd3
commit 91fa75131a
7 changed files with 85 additions and 93 deletions

View file

@ -8,5 +8,5 @@ export interface StudentType {
name: string;
id: string;
room?: string;
answers?: Answer[];
answers: Answer[];
}

View file

@ -1,15 +1,17 @@
//StudentType.test.tsx
import { StudentType } from "../../Types/StudentType";
import { StudentType, Answer } from "../../Types/StudentType";
const user : StudentType = {
name: 'Student',
id: '123'
id: '123',
answers: new Array<Answer>()
}
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.id).toBe('123');
expect(user.answers.length).toBe(0);
});
});

View file

@ -2,16 +2,17 @@
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import StudentWaitPage from '../../../components/StudentWaitPage/StudentWaitPage';
import { StudentType, Answer } from '../../../Types/StudentType';
describe('StudentWaitPage Component', () => {
const mockUsers = [
{ id: '1', name: 'User1' },
{ id: '2', name: 'User2' },
{ id: '3', name: 'User3' },
const mockUsers: StudentType[] = [
{ id: '1', name: 'User1', answers: new Array<Answer>() },
{ id: '2', name: 'User2', answers: new Array<Answer>() },
{ id: '3', name: 'User3', answers: new Array<Answer>() },
];
const mockProps = {
users: mockUsers,
students: mockUsers,
launchQuiz: jest.fn(),
roomName: 'Test Room',
setQuizMode: jest.fn(),

View file

@ -19,7 +19,7 @@ import {
TableHead,
TableRow
} from '@mui/material';
import { StudentType } from '../../Types/StudentType';
import { StudentType, Answer } from '../../Types/StudentType';
import { formatLatex } from '../GiftTemplate/templates/TextType';
interface LiveResultsProps {
@ -27,50 +27,53 @@ interface LiveResultsProps {
questions: QuestionType[];
showSelectedQuestion: (index: number) => void;
quizMode: 'teacher' | 'student';
students: StudentType[]
connectedStudents: StudentType[]
}
interface Answer {
answer: string | number | boolean;
isCorrect: boolean;
idQuestion: number;
}
// interface Answer {
// answer: string | number | boolean;
// isCorrect: boolean;
// idQuestion: number;
// }
interface StudentResult {
username: string;
idUser: string;
answers: Answer[];
}
// interface StudentResult {
// username: string;
// idUser: string;
// 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 [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;
useEffect(() => {
// Initialize the map with the current students
const newStudentResultsMap = new Map<string, StudentResult>();
// useEffect(() => {
// // Initialize the map with the current students
// const newStudentResultsMap = new Map<string, StudentResult>();
for (const student of students) {
newStudentResultsMap.set(student.id, { username: student.name, idUser: student.id, answers: [] });
}
// for (const student of students) {
// newStudentResultsMap.set(student.id, { username: student.name, idUser: student.id, answers: [] });
// }
setStudentResultsMap(newStudentResultsMap);
}, [])
// setStudentResultsMap(newStudentResultsMap);
// }, [])
// update when students change
// useEffect(() => {
// // studentResultsMap is inconsistent with students -- need to update
// for (const student of students as StudentType[]) {
// }
// }, [students])
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(() => {
if (socket) {
@ -84,35 +87,19 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
answer: string | number | boolean;
idQuestion: number;
}) => {
// Update the student results in the map with the answer
setStudentResultsMap((currentResults) => {
const studentResult = currentResults.get(idUser);
if (!studentResult) {
return currentResults;
}
// make a copy of the students array so we can update it
const updatedStudents = [...students];
const isCorrect = checkIfIsCorrect(answer, idQuestion);
studentResult.answers.push({ answer, isCorrect, idQuestion });
return new Map(currentResults).set(idUser, studentResult);
});
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
return;
}
// 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 }] }
// ];
// }
// });
const isCorrect = checkIfIsCorrect(answer, idQuestion);
const newAnswer: Answer = { answer, isCorrect, idQuestion };
student.answers.push(newAnswer);
setStudents(updatedStudents); // update the state
};
socket.on('submit-answer', submitAnswerHandler);
@ -122,7 +109,7 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
}
}, [socket]);
const getStudentGrade = (student: StudentResult): number => {
const getStudentGrade = (student: StudentType): number => {
if (student.answers.length === 0) {
return 0;
}
@ -148,24 +135,21 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
const classAverage: number = useMemo(() => {
let classTotal = 0;
const studentResults = Array.from(studentResultsMap.values());
studentResults.forEach((student) => {
students.forEach((student) => {
classTotal += getStudentGrade(student);
});
return classTotal / studentResults.length;
}, [studentResultsMap]);
return classTotal / students.length;
}, [students]);
const getCorrectAnswersPerQuestion = (index: number): number => {
return (
(Array.from(studentResultsMap.values()).filter((student) =>
(students.filter((student) =>
student.answers.some(
(answer) =>
parseInt(answer.idQuestion.toString()) === index + 1 && answer.isCorrect
)
).length / studentResultsMap.size) *
100
).length / students.length) * 100
);
};
@ -314,8 +298,8 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
</TableRow>
</TableHead>
<TableBody>
{Array.from(studentResultsMap.values()).map((student) => (
<TableRow key={student.idUser}>
{students.map((student) => (
<TableRow key={student.id}>
<TableCell
className="sticky-column"
sx={{
@ -325,7 +309,7 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
}}
>
<div className="text-base">
{showUsernames ? student.username : '******'}
{showUsernames ? student.name : '******'}
</div>
</TableCell>
{Array.from({ length: maxQuestions }, (_, index) => {
@ -396,7 +380,7 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
color: 'rgba(0, 0, 0)'
}}
>
{studentResultsMap.size > 0
{students.length > 0
? `${getCorrectAnswersPerQuestion(index).toFixed()} %`
: '-'}
</TableCell>
@ -412,7 +396,7 @@ const LiveResults: React.FC<LiveResultsProps> = ({ socket, questions, showSelect
color: 'rgba(0, 0, 0)'
}}
>
{studentResultsMap.size > 0 ? `${classAverage.toFixed()} %` : '-'}
{students.length > 0 ? `${classAverage.toFixed()} %` : '-'}
</TableCell>
</TableRow>
</TableFooter>

View file

@ -1,4 +1,4 @@
import { Button, Chip, Grid } from '@mui/material';
import { Box, Button, Chip } from '@mui/material';
import { StudentType } from '../../Types/StudentType';
import { PlayArrow } from '@mui/icons-material';
import LaunchQuizDialog from '../LaunchQuizDialog/LaunchQuizDialog';
@ -6,12 +6,12 @@ import { useState } from 'react';
import './studentWaitPage.css';
interface Props {
users: StudentType[];
students: StudentType[];
launchQuiz: () => 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);
return (
@ -30,15 +30,15 @@ const StudentWaitPage: React.FC<Props> = ({ users, launchQuiz, setQuizMode }) =>
<div className="students">
<Grid container spacing={3}>
<Box display="flex" flexWrap="wrap" gap={3}>
{users.map((user, index) => (
<Grid item key={user.name + index}>
<Chip label={user.name} sx={{ width: '100%' }} />
</Grid>
{students.map((student, index) => (
<Box key={student.name + index} >
<Chip label={student.name} sx={{ width: '100%' }} />
</Box>
))}
</Grid>
</Box>
</div>

View file

@ -74,7 +74,7 @@ const ManageRoom: React.FC = () => {
setSocket(null);
setQuizQuestions(undefined);
setCurrentQuestion(undefined);
setStudents([]);
setStudents(new Array<StudentType>());
setRoomName('');
}
};
@ -293,7 +293,7 @@ const ManageRoom: React.FC = () => {
socket={socket}
questions={quizQuestions}
showSelectedQuestion={showSelectedQuestion}
students={students}
connectedStudents={students}
></LiveResultsComponent>
</div>
@ -312,7 +312,7 @@ const ManageRoom: React.FC = () => {
) : (
<StudentWaitPage
users={students}
students={students}
launchQuiz={launchQuiz}
setQuizMode={setQuizMode}
/>

View file

@ -49,10 +49,15 @@ const setupWebsocket = (io) => {
io.sockets.adapter.rooms.get(enteredRoomName).size;
if (clientsInRoom <= MAX_USERS_PER_ROOM) {
const newStudent = {
id: socket.id,
name: username,
answers: [],
};
socket.join(enteredRoomName);
socket
.to(enteredRoomName)
.emit("user-joined", { name: username, id: socket.id });
.emit("user-joined", newStudent);
socket.emit("join-success");
} else {
socket.emit("join-failure", "La salle est remplie");