2024-03-29 20:08:34 -04:00
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
|
|
|
import { Socket } from 'socket.io-client';
|
2025-01-25 02:02:18 -05:00
|
|
|
import { ParsedGIFTQuestion, BaseQuestion, parse, Question } from 'gift-pegjs';
|
|
|
|
|
import { isSimpleNumericalAnswer, isRangeNumericalAnswer, isHighLowNumericalAnswer } from "gift-pegjs/typeGuards";
|
2025-01-16 12:37:07 -05:00
|
|
|
import LiveResultsComponent from 'src/components/LiveResults/LiveResults';
|
2024-09-26 00:34:30 -04:00
|
|
|
import webSocketService, { AnswerReceptionFromBackendType } from '../../../services/WebsocketService';
|
2024-03-29 20:08:34 -04:00
|
|
|
import { QuizType } from '../../../Types/QuizType';
|
2025-01-23 20:12:47 -05:00
|
|
|
import GroupIcon from '@mui/icons-material/Group';
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
import './manageRoom.css';
|
2025-01-10 15:46:17 -05:00
|
|
|
import { ENV_VARIABLES } from 'src/constants';
|
2024-09-26 00:34:30 -04:00
|
|
|
import { StudentType, Answer } from '../../../Types/StudentType';
|
2024-03-29 20:08:34 -04:00
|
|
|
import { Button } from '@mui/material';
|
2025-01-16 12:37:07 -05:00
|
|
|
import LoadingCircle from 'src/components/LoadingCircle/LoadingCircle';
|
2024-03-29 20:08:34 -04:00
|
|
|
import { Refresh, Error } from '@mui/icons-material';
|
2025-01-16 12:37:07 -05:00
|
|
|
import StudentWaitPage from 'src/components/StudentWaitPage/StudentWaitPage';
|
|
|
|
|
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
2025-01-25 02:02:18 -05:00
|
|
|
import QuestionDisplay from 'src/components/QuestionsDisplay/QuestionDisplay';
|
2024-03-29 20:08:34 -04:00
|
|
|
import ApiService from '../../../services/ApiService';
|
2025-01-25 02:02:18 -05:00
|
|
|
import { QuestionType } from 'src/Types/QuestionType';
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
const ManageRoom: React.FC = () => {
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const [socket, setSocket] = useState<Socket | null>(null);
|
2024-09-25 13:05:36 -04:00
|
|
|
const [students, setStudents] = useState<StudentType[]>([]);
|
2024-03-29 20:08:34 -04:00
|
|
|
const quizId = useParams<{ id: string }>();
|
|
|
|
|
const [quizQuestions, setQuizQuestions] = useState<QuestionType[] | undefined>();
|
|
|
|
|
const [quiz, setQuiz] = useState<QuizType | null>(null);
|
|
|
|
|
const [quizMode, setQuizMode] = useState<'teacher' | 'student'>('teacher');
|
|
|
|
|
const [connectingError, setConnectingError] = useState<string>('');
|
|
|
|
|
const [currentQuestion, setCurrentQuestion] = useState<QuestionType | undefined>(undefined);
|
2025-01-23 20:12:47 -05:00
|
|
|
const [quizStarted, setQuizStarted] = useState(false);
|
2025-02-09 16:10:25 -05:00
|
|
|
const [isSocketConnected, setIsSocketConnected] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (quizId.id) {
|
|
|
|
|
const fetchquiz = async () => {
|
2025-02-09 16:10:25 -05:00
|
|
|
try {
|
|
|
|
|
const quiz = await ApiService.getQuiz(quizId.id as string);
|
|
|
|
|
|
|
|
|
|
if (!quiz) {
|
|
|
|
|
window.alert(`Une erreur est survenue.\n Le quiz ${quizId.id} n'a pas été trouvé\nVeuillez réessayer plus tard`)
|
|
|
|
|
console.error('Quiz not found for id:', quizId.id);
|
|
|
|
|
navigate('/teacher/dashboard');
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
if ((quiz as QuizType).roomId) {
|
|
|
|
|
setQuiz(quiz as QuizType);
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
if (!socket) {
|
|
|
|
|
console.log('Initializing WebSocket connection...');
|
|
|
|
|
initializeWebSocketConnection((quiz as QuizType).roomId);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
console.error('Quiz data is not valid, roomId is missing.');
|
|
|
|
|
navigate('/teacher/dashboard');
|
|
|
|
|
}
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Failed to load quiz:', error);
|
|
|
|
|
setConnectingError('Erreur de chargement du quiz');
|
|
|
|
|
navigate('/teacher/dashboard');
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fetchquiz();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
window.alert(`Une erreur est survenue.\n Le quiz ${quizId.id} n'a pas été trouvé\nVeuillez réessayer plus tard`)
|
|
|
|
|
console.error('Quiz not found for id:', quizId.id);
|
|
|
|
|
navigate('/teacher/dashboard');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}, [quizId]);
|
|
|
|
|
|
|
|
|
|
const disconnectWebSocket = () => {
|
2025-02-09 16:10:25 -05:00
|
|
|
if (socket && quiz) {
|
|
|
|
|
webSocketService.endQuiz(quiz.roomId);
|
2024-03-29 20:08:34 -04:00
|
|
|
webSocketService.disconnect();
|
|
|
|
|
setSocket(null);
|
|
|
|
|
setQuizQuestions(undefined);
|
|
|
|
|
setCurrentQuestion(undefined);
|
2024-09-25 14:53:17 -04:00
|
|
|
setStudents(new Array<StudentType>());
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
|
|
|
|
|
const initializeWebSocketConnection = (roomId: string) => {
|
|
|
|
|
console.log('Initializing WebSocket for room:', roomId);
|
2025-02-07 19:36:11 -05:00
|
|
|
const socket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_SOCKET_URL);
|
2025-02-09 16:10:25 -05:00
|
|
|
console.log('Socket connection status:', webSocketService.isConnected());
|
2024-09-26 00:34:30 -04:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
socket.on('connect', () => {
|
2025-02-09 16:10:25 -05:00
|
|
|
console.log('WebSocket connected, joining room:', roomId);
|
|
|
|
|
setIsSocketConnected(true);
|
|
|
|
|
webSocketService.joinRoom(roomId, 'Teacher');
|
2024-03-29 20:08:34 -04:00
|
|
|
});
|
2025-02-09 16:10:25 -05:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
socket.on('connect_error', (error) => {
|
|
|
|
|
setConnectingError('Erreur lors de la connexion... Veuillez réessayer');
|
2025-02-09 16:10:25 -05:00
|
|
|
console.error('Connection error:', error);
|
2024-03-29 20:08:34 -04:00
|
|
|
});
|
2025-02-09 16:10:25 -05:00
|
|
|
|
2024-09-25 13:05:36 -04:00
|
|
|
socket.on('user-joined', (student: StudentType) => {
|
2024-09-25 16:31:38 -04:00
|
|
|
console.log(`Student joined: name = ${student.name}, id = ${student.id}`);
|
2024-09-26 00:34:30 -04:00
|
|
|
|
2024-09-25 11:17:06 -04:00
|
|
|
setStudents((prevStudents) => [...prevStudents, student]);
|
2024-04-09 10:10:17 -04:00
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
if (quiz && socket.connected) {
|
|
|
|
|
if (quizMode === 'teacher') {
|
|
|
|
|
webSocketService.nextQuestion(quiz.roomId, currentQuestion);
|
|
|
|
|
} else if (quizMode === 'student') {
|
|
|
|
|
webSocketService.launchStudentModeQuiz(quiz.roomId, quizQuestions);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
console.error("Quiz data is not available or Socket is not connected.");
|
2024-04-09 10:10:17 -04:00
|
|
|
}
|
|
|
|
|
});
|
2025-02-09 16:10:25 -05:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
socket.on('join-failure', (message) => {
|
|
|
|
|
setConnectingError(message);
|
|
|
|
|
setSocket(null);
|
2025-02-09 16:10:25 -05:00
|
|
|
setIsSocketConnected(false);
|
2024-03-29 20:08:34 -04:00
|
|
|
});
|
2025-02-09 16:10:25 -05:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
socket.on('user-disconnected', (userId: string) => {
|
2024-09-25 16:31:38 -04:00
|
|
|
console.log(`Student left: id = ${userId}`);
|
2024-09-25 11:17:06 -04:00
|
|
|
setStudents((prevUsers) => prevUsers.filter((user) => user.id !== userId));
|
2024-03-29 20:08:34 -04:00
|
|
|
});
|
2025-02-09 16:10:25 -05:00
|
|
|
socket.on('disconnect', () => {
|
|
|
|
|
console.log('WebSocket disconnected');
|
|
|
|
|
setIsSocketConnected(false);
|
|
|
|
|
});
|
2024-03-29 20:08:34 -04:00
|
|
|
setSocket(socket);
|
|
|
|
|
};
|
|
|
|
|
|
2024-04-06 19:25:30 -04:00
|
|
|
useEffect(() => {
|
|
|
|
|
// This is here to make sure the correct value is sent when user join
|
2025-02-09 16:10:25 -05:00
|
|
|
if (socket && quiz?.roomId) {
|
|
|
|
|
console.log(`Listening for user-joined in room ${quiz.roomId}`);
|
2025-02-07 19:36:11 -05:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
2024-09-25 13:05:36 -04:00
|
|
|
socket.on('user-joined', (_student: StudentType) => {
|
2024-04-06 19:25:30 -04:00
|
|
|
if (quizMode === 'teacher') {
|
2025-02-09 16:10:25 -05:00
|
|
|
webSocketService.nextQuestion(quiz.roomId, currentQuestion);
|
|
|
|
|
|
2024-04-06 19:25:30 -04:00
|
|
|
} else if (quizMode === 'student') {
|
2025-02-09 16:10:25 -05:00
|
|
|
webSocketService.launchStudentModeQuiz(quiz.roomId, quizQuestions);
|
2024-04-06 19:25:30 -04:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2024-09-26 00:34:30 -04:00
|
|
|
if (socket) {
|
|
|
|
|
// handle the case where user submits an answer
|
2025-02-09 16:10:25 -05:00
|
|
|
console.log(`Listening for submit-answer-room in room ${quiz?.roomId}`);
|
2024-09-26 00:34:30 -04:00
|
|
|
socket.on('submit-answer-room', (answerData: AnswerReceptionFromBackendType) => {
|
|
|
|
|
const { answer, idQuestion, idUser, username } = answerData;
|
|
|
|
|
console.log(`Received answer from ${username} for question ${idQuestion}: ${answer}`);
|
|
|
|
|
if (!quizQuestions) {
|
|
|
|
|
console.log('Quiz questions not found (cannot update answers without them).');
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-01-23 20:12:47 -05:00
|
|
|
|
2024-09-26 00:34:30 -04:00
|
|
|
// Update the students state using the functional form of setStudents
|
|
|
|
|
setStudents((prevStudents) => {
|
|
|
|
|
// print the list of current student names
|
|
|
|
|
console.log('Current students:');
|
|
|
|
|
prevStudents.forEach((student) => {
|
|
|
|
|
console.log(student.name);
|
|
|
|
|
});
|
2025-01-23 20:12:47 -05:00
|
|
|
|
2024-09-26 00:34:30 -04:00
|
|
|
let foundStudent = false;
|
|
|
|
|
const updatedStudents = prevStudents.map((student) => {
|
|
|
|
|
console.log(`Comparing ${student.id} to ${idUser}`);
|
|
|
|
|
if (student.id === idUser) {
|
|
|
|
|
foundStudent = true;
|
|
|
|
|
const existingAnswer = student.answers.find((ans) => ans.idQuestion === idQuestion);
|
|
|
|
|
let updatedAnswers: Answer[] = [];
|
|
|
|
|
if (existingAnswer) {
|
|
|
|
|
// Update the existing answer
|
|
|
|
|
updatedAnswers = student.answers.map((ans) => {
|
|
|
|
|
console.log(`Comparing ${ans.idQuestion} to ${idQuestion}`);
|
|
|
|
|
return (ans.idQuestion === idQuestion ? { ...ans, answer, isCorrect: checkIfIsCorrect(answer, idQuestion, quizQuestions!) } : ans);
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
// Add a new answer
|
|
|
|
|
const newAnswer = { idQuestion, answer, isCorrect: checkIfIsCorrect(answer, idQuestion, quizQuestions!) };
|
|
|
|
|
updatedAnswers = [...student.answers, newAnswer];
|
|
|
|
|
}
|
|
|
|
|
return { ...student, answers: updatedAnswers };
|
2025-01-23 20:12:47 -05:00
|
|
|
}
|
2024-09-26 00:34:30 -04:00
|
|
|
return student;
|
|
|
|
|
});
|
|
|
|
|
if (!foundStudent) {
|
|
|
|
|
console.log(`Student ${username} not found in the list.`);
|
|
|
|
|
}
|
|
|
|
|
return updatedStudents;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
setSocket(socket);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}, [socket, currentQuestion, quizQuestions]);
|
|
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
const nextQuestion = () => {
|
|
|
|
|
if (!quizQuestions || !currentQuestion || !quiz?.content) return;
|
|
|
|
|
|
|
|
|
|
const nextQuestionIndex = Number(currentQuestion?.question.id);
|
|
|
|
|
|
|
|
|
|
if (nextQuestionIndex === undefined || nextQuestionIndex > quizQuestions.length - 1) return;
|
|
|
|
|
|
|
|
|
|
setCurrentQuestion(quizQuestions[nextQuestionIndex]);
|
2025-02-09 16:10:25 -05:00
|
|
|
webSocketService.nextQuestion(quiz.roomId, quizQuestions[nextQuestionIndex]);
|
2024-03-29 20:08:34 -04:00
|
|
|
};
|
|
|
|
|
|
2025-01-22 15:28:45 -05:00
|
|
|
const previousQuestion = () => {
|
|
|
|
|
if (!quizQuestions || !currentQuestion || !quiz?.content) return;
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2025-01-22 15:28:45 -05:00
|
|
|
const prevQuestionIndex = Number(currentQuestion?.question.id) - 2; // -2 because question.id starts at index 1
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2025-01-22 15:28:45 -05:00
|
|
|
if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return;
|
|
|
|
|
setCurrentQuestion(quizQuestions[prevQuestionIndex]);
|
2025-02-09 16:10:25 -05:00
|
|
|
webSocketService.nextQuestion(quiz.roomId, quizQuestions[prevQuestionIndex]);
|
2025-01-22 15:28:45 -05:00
|
|
|
};
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
const initializeQuizQuestion = () => {
|
|
|
|
|
const quizQuestionArray = quiz?.content;
|
|
|
|
|
if (!quizQuestionArray) return null;
|
|
|
|
|
const parsedQuestions = [] as QuestionType[];
|
|
|
|
|
|
|
|
|
|
quizQuestionArray.forEach((question, index) => {
|
2025-01-25 02:02:18 -05:00
|
|
|
parsedQuestions.push({ question: parse(question)[0] as BaseQuestion });
|
2024-03-29 20:08:34 -04:00
|
|
|
parsedQuestions[index].question.id = (index + 1).toString();
|
|
|
|
|
});
|
|
|
|
|
if (parsedQuestions.length === 0) return null;
|
|
|
|
|
|
|
|
|
|
setQuizQuestions(parsedQuestions);
|
|
|
|
|
return parsedQuestions;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const launchTeacherMode = () => {
|
|
|
|
|
const quizQuestions = initializeQuizQuestion();
|
2025-02-09 16:10:25 -05:00
|
|
|
if (quizQuestions && quiz?.roomId) {
|
|
|
|
|
setCurrentQuestion(quizQuestions[0]);
|
|
|
|
|
webSocketService.nextQuestion(quiz.roomId, quizQuestions[0]);
|
2024-09-26 00:34:30 -04:00
|
|
|
}
|
2024-03-29 20:08:34 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const launchStudentMode = () => {
|
|
|
|
|
const quizQuestions = initializeQuizQuestion();
|
2025-02-09 16:10:25 -05:00
|
|
|
if (quizQuestions && quiz?.roomId) {
|
|
|
|
|
setQuizQuestions(quizQuestions);
|
|
|
|
|
webSocketService.launchStudentModeQuiz(quiz.roomId, quizQuestions);
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-03-29 20:08:34 -04:00
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
const launchQuiz = async () => {
|
|
|
|
|
if (!isSocketConnected) {
|
|
|
|
|
console.log("Waiting for socket connection...");
|
|
|
|
|
window.alert("En attente de la connexion au serveur... Veuillez réessayer dans quelques secondes.");
|
2024-03-29 20:08:34 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
if (!quiz?.roomId) {
|
|
|
|
|
console.error("Room ID is missing.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-01-23 20:12:47 -05:00
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
if (!quiz?.content || quiz.content.length === 0) {
|
|
|
|
|
console.error("Quiz content is missing or empty.");
|
2024-03-29 20:08:34 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2025-02-09 16:10:25 -05:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
switch (quizMode) {
|
|
|
|
|
case 'student':
|
2025-01-23 20:12:47 -05:00
|
|
|
setQuizStarted(true);
|
2024-03-29 20:08:34 -04:00
|
|
|
return launchStudentMode();
|
|
|
|
|
case 'teacher':
|
2025-01-23 20:12:47 -05:00
|
|
|
setQuizStarted(true);
|
2024-03-29 20:08:34 -04:00
|
|
|
return launchTeacherMode();
|
2025-02-09 16:10:25 -05:00
|
|
|
default:
|
|
|
|
|
console.error("Invalid quiz mode.");
|
|
|
|
|
return;
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const showSelectedQuestion = (questionIndex: number) => {
|
|
|
|
|
if (quiz?.content && quizQuestions) {
|
|
|
|
|
setCurrentQuestion(quizQuestions[questionIndex]);
|
2024-09-26 00:34:30 -04:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
if (quizMode === 'teacher') {
|
2025-02-09 16:10:25 -05:00
|
|
|
webSocketService.nextQuestion(quiz.roomId, quizQuestions[questionIndex]);
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleReturn = () => {
|
|
|
|
|
disconnectWebSocket();
|
|
|
|
|
navigate('/teacher/dashboard');
|
|
|
|
|
};
|
|
|
|
|
|
2024-09-26 00:34:30 -04:00
|
|
|
function checkIfIsCorrect(answer: string | number | boolean, idQuestion: number, questions: QuestionType[]): boolean {
|
|
|
|
|
const questionInfo = questions.find((q) =>
|
|
|
|
|
q.question.id ? q.question.id === idQuestion.toString() : false
|
|
|
|
|
) as QuestionType | undefined;
|
|
|
|
|
|
|
|
|
|
const answerText = answer.toString();
|
|
|
|
|
if (questionInfo) {
|
2025-01-25 02:02:18 -05:00
|
|
|
const question = questionInfo.question as ParsedGIFTQuestion;
|
2024-09-26 00:34:30 -04:00
|
|
|
if (question.type === 'TF') {
|
|
|
|
|
return (
|
|
|
|
|
(question.isTrue && answerText == 'true') ||
|
|
|
|
|
(!question.isTrue && answerText == 'false')
|
|
|
|
|
);
|
|
|
|
|
} else if (question.type === 'MC') {
|
|
|
|
|
return question.choices.some(
|
2025-01-25 02:02:18 -05:00
|
|
|
(choice) => choice.isCorrect && choice.formattedText.text === answerText
|
2024-09-26 00:34:30 -04:00
|
|
|
);
|
|
|
|
|
} else if (question.type === 'Numerical') {
|
2025-01-25 02:02:18 -05:00
|
|
|
if (isHighLowNumericalAnswer(question.choices[0])) {
|
|
|
|
|
const choice = question.choices[0];
|
|
|
|
|
const answerNumber = parseFloat(answerText);
|
|
|
|
|
if (!isNaN(answerNumber)) {
|
|
|
|
|
return (
|
|
|
|
|
answerNumber <= choice.numberHigh &&
|
|
|
|
|
answerNumber >= choice.numberLow
|
|
|
|
|
);
|
2024-09-26 00:34:30 -04:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-25 02:02:18 -05:00
|
|
|
if (isRangeNumericalAnswer(question.choices[0])) {
|
|
|
|
|
const answerNumber = parseFloat(answerText);
|
|
|
|
|
const range = question.choices[0].range;
|
|
|
|
|
const correctAnswer = question.choices[0].number;
|
|
|
|
|
if (!isNaN(answerNumber)) {
|
|
|
|
|
return (
|
|
|
|
|
answerNumber <= correctAnswer + range &&
|
|
|
|
|
answerNumber >= correctAnswer - range
|
|
|
|
|
);
|
2024-09-26 00:34:30 -04:00
|
|
|
}
|
2025-01-25 02:02:18 -05:00
|
|
|
}
|
|
|
|
|
if (isSimpleNumericalAnswer(question.choices[0])) {
|
|
|
|
|
const answerNumber = parseFloat(answerText);
|
|
|
|
|
if (!isNaN(answerNumber)) {
|
|
|
|
|
return answerNumber === question.choices[0].number;
|
2024-09-26 00:34:30 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (question.type === 'Short') {
|
|
|
|
|
return question.choices.some(
|
2025-01-25 02:02:18 -05:00
|
|
|
(choice) => choice.text.toUpperCase() === answerText.toUpperCase()
|
2024-09-26 00:34:30 -04:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
if (!quiz || !quiz?.roomId) {
|
2024-03-29 20:08:34 -04:00
|
|
|
return (
|
|
|
|
|
<div className="center">
|
|
|
|
|
{!connectingError ? (
|
2025-02-09 16:10:25 -05:00
|
|
|
<LoadingCircle text="Chargement du quiz..." />
|
2024-03-29 20:08:34 -04:00
|
|
|
) : (
|
|
|
|
|
<div className="center-v-align">
|
|
|
|
|
<Error sx={{ padding: 0 }} />
|
|
|
|
|
<div className="text-base">{connectingError}</div>
|
|
|
|
|
<Button
|
|
|
|
|
variant="contained"
|
|
|
|
|
startIcon={<Refresh />}
|
2025-02-09 16:10:25 -05:00
|
|
|
onClick={() => {
|
|
|
|
|
if (quiz?.roomId) {
|
|
|
|
|
initializeWebSocketConnection(quiz.roomId);
|
|
|
|
|
} else {
|
|
|
|
|
console.error("Room ID is not available");
|
|
|
|
|
}
|
|
|
|
|
}}
|
2024-03-29 20:08:34 -04:00
|
|
|
>
|
|
|
|
|
Reconnecter
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className='room'>
|
|
|
|
|
<div className='roomHeader'>
|
|
|
|
|
|
|
|
|
|
<DisconnectButton
|
|
|
|
|
onReturn={handleReturn}
|
|
|
|
|
askConfirm
|
|
|
|
|
message={`Êtes-vous sûr de vouloir quitter?`} />
|
|
|
|
|
|
2025-01-23 20:12:47 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div className='headerContent' style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' }}>
|
|
|
|
|
<div style={{ flex: 1, display: 'flex', justifyContent: 'center' }}>
|
2025-02-09 16:10:25 -05:00
|
|
|
<div className='title'>Salle: {quiz?.roomId}</div>
|
2025-01-23 20:12:47 -05:00
|
|
|
</div>
|
|
|
|
|
{quizStarted && (
|
|
|
|
|
<div className='userCount subtitle smallText' style={{ display: 'flex', alignItems: 'center' }}>
|
|
|
|
|
<GroupIcon style={{ marginRight: '5px' }} />
|
|
|
|
|
{students.length}/60
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2024-03-29 20:08:34 -04:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className='dumb'></div>
|
|
|
|
|
|
|
|
|
|
</div>
|
2024-09-26 00:34:30 -04:00
|
|
|
{/* the following breaks the css (if 'room' classes are nested) */}
|
2024-09-24 09:49:15 -04:00
|
|
|
<div className=''>
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
{quizQuestions ? (
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
|
|
|
<div className="title center-h-align mb-2">{quiz?.title}</div>
|
2025-01-23 20:23:15 -05:00
|
|
|
{!isNaN(Number(currentQuestion?.question.id)) && (
|
|
|
|
|
<strong className='number of questions'>
|
|
|
|
|
Question {Number(currentQuestion?.question.id)}/{quizQuestions?.length}
|
|
|
|
|
</strong>
|
|
|
|
|
)}
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
{quizMode === 'teacher' && (
|
|
|
|
|
|
|
|
|
|
<div className="mb-1">
|
2025-01-21 15:35:07 -05:00
|
|
|
{/* <QuestionNavigation
|
2024-03-29 20:08:34 -04:00
|
|
|
currentQuestionId={Number(currentQuestion?.question.id)}
|
|
|
|
|
questionsLength={quizQuestions?.length}
|
|
|
|
|
previousQuestion={previousQuestion}
|
|
|
|
|
nextQuestion={nextQuestion}
|
2025-01-21 15:35:07 -05:00
|
|
|
/> */}
|
2024-03-29 20:08:34 -04:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<div className="mb-2 flex-column-wrapper">
|
|
|
|
|
<div className="preview-and-result-container">
|
|
|
|
|
|
|
|
|
|
{currentQuestion && (
|
2025-01-23 22:38:22 -05:00
|
|
|
<QuestionDisplay
|
2024-03-29 20:08:34 -04:00
|
|
|
showAnswer={false}
|
2025-01-25 02:02:18 -05:00
|
|
|
question={currentQuestion?.question as Question}
|
2024-03-29 20:08:34 -04:00
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<LiveResultsComponent
|
|
|
|
|
quizMode={quizMode}
|
|
|
|
|
socket={socket}
|
|
|
|
|
questions={quizQuestions}
|
|
|
|
|
showSelectedQuestion={showSelectedQuestion}
|
2024-09-26 00:34:30 -04:00
|
|
|
students={students}
|
2024-03-29 20:08:34 -04:00
|
|
|
></LiveResultsComponent>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{quizMode === 'teacher' && (
|
2025-01-23 20:12:47 -05:00
|
|
|
<div className="questionNavigationButtons" style={{ display: 'flex', justifyContent: 'center' }}>
|
|
|
|
|
<div className="previousQuestionButton">
|
|
|
|
|
<Button onClick={previousQuestion}
|
|
|
|
|
variant="contained"
|
|
|
|
|
disabled={Number(currentQuestion?.question.id) <= 1}>
|
|
|
|
|
Question précédente
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="nextQuestionButton">
|
|
|
|
|
<Button onClick={nextQuestion}
|
|
|
|
|
variant="contained"
|
|
|
|
|
disabled={Number(currentQuestion?.question.id) >= quizQuestions.length}
|
|
|
|
|
>
|
|
|
|
|
Prochaine question
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>)}
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
) : (
|
|
|
|
|
|
2024-09-25 13:20:09 -04:00
|
|
|
<StudentWaitPage
|
2024-09-25 14:53:17 -04:00
|
|
|
students={students}
|
2024-03-29 20:08:34 -04:00
|
|
|
launchQuiz={launchQuiz}
|
|
|
|
|
setQuizMode={setQuizMode}
|
2025-02-09 16:10:25 -05:00
|
|
|
isSocketConnected={isSocketConnected}
|
2024-03-29 20:08:34 -04:00
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-09 16:10:25 -05:00
|
|
|
export default ManageRoom;
|