Nom de la salle doiit être un majuscule

Supprimer des créations de socket/salle superflues
Suppression (nettoyage) des salles et socket plus robuste
diminue le bazaar de useEffect (!)
This commit is contained in:
C. Fuhrman 2025-02-27 15:49:09 -05:00
parent 38e366a7de
commit 70d6d1bc56
8 changed files with 170 additions and 164 deletions

View file

@ -13,7 +13,6 @@ import Register from './pages/Teacher/Register/Register';
import ResetPassword from './pages/Teacher/ResetPassword/ResetPassword'; import ResetPassword from './pages/Teacher/ResetPassword/ResetPassword';
import ManageRoom from './pages/Teacher/ManageRoom/ManageRoom'; import ManageRoom from './pages/Teacher/ManageRoom/ManageRoom';
import QuizForm from './pages/Teacher/EditorQuiz/EditorQuiz'; import QuizForm from './pages/Teacher/EditorQuiz/EditorQuiz';
import { RoomProvider } from './pages/Teacher/ManageRoom/RoomContext';
// Pages espace étudiant // Pages espace étudiant
import JoinRoom from './pages/Student/JoinRoom/JoinRoom'; import JoinRoom from './pages/Student/JoinRoom/JoinRoom';
@ -34,8 +33,6 @@ const isLoggedIn = () => {
function App() { function App() {
return ( return (
<RoomProvider>
{' '}
<div className="content"> <div className="content">
<Header isLoggedIn={isLoggedIn} handleLogout={handleLogout} /> <Header isLoggedIn={isLoggedIn} handleLogout={handleLogout} />
@ -64,7 +61,6 @@ function App() {
</div> </div>
<Footer /> <Footer />
</div> </div>
</RoomProvider>
); );
} }

View file

@ -98,7 +98,7 @@ describe('ManageRoom', () => {
expect(screen.getByText('Test Quiz')).toBeInTheDocument(); expect(screen.getByText('Test Quiz')).toBeInTheDocument();
const roomHeader = document.querySelector('h1'); const roomHeader = document.querySelector('h1');
expect(roomHeader).toHaveTextContent('Salle : Test Room'); expect(roomHeader).toHaveTextContent('Salle : TEST ROOM');
expect(screen.getByText('0/60')).toBeInTheDocument(); expect(screen.getByText('0/60')).toBeInTheDocument();
expect(screen.getByText('Question 1/2')).toBeInTheDocument(); expect(screen.getByText('Question 1/2')).toBeInTheDocument();

View file

@ -37,18 +37,19 @@ const JoinRoom: React.FC = () => {
console.log(`JoinRoom: handleCreateSocket: ${ENV_VARIABLES.VITE_BACKEND_SOCKET_URL}`); console.log(`JoinRoom: handleCreateSocket: ${ENV_VARIABLES.VITE_BACKEND_SOCKET_URL}`);
const socket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_SOCKET_URL); const socket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_SOCKET_URL);
socket.on('join-success', () => { socket.on('join-success', (roomJoinedName) => {
setIsWaitingForTeacher(true); setIsWaitingForTeacher(true);
setIsConnecting(false); setIsConnecting(false);
console.log('Successfully joined the room.'); console.log(`on(join-success): Successfully joined the room ${roomJoinedName}`);
}); });
socket.on('next-question', (question: QuestionType) => { socket.on('next-question', (question: QuestionType) => {
console.log('on(next-question): Received next-question:', question);
setQuizMode('teacher'); setQuizMode('teacher');
setIsWaitingForTeacher(false); setIsWaitingForTeacher(false);
setQuestion(question); setQuestion(question);
}); });
socket.on('launch-student-mode', (questions: QuestionType[]) => { socket.on('launch-student-mode', (questions: QuestionType[]) => {
console.log('Received launch-student-mode:', questions); console.log('on(launch-student-mode): Received launch-student-mode:', questions);
setQuizMode('student'); setQuizMode('student');
setIsWaitingForTeacher(false); setIsWaitingForTeacher(false);
@ -168,7 +169,7 @@ const JoinRoom: React.FC = () => {
label="Nom de la salle" label="Nom de la salle"
variant="outlined" variant="outlined"
value={roomName} value={roomName}
onChange={(e) => setRoomName(e.target.value)} onChange={(e) => setRoomName(e.target.value.toUpperCase())}
placeholder="Nom de la salle" placeholder="Nom de la salle"
sx={{ marginBottom: '1rem' }} sx={{ marginBottom: '1rem' }}
fullWidth fullWidth

View file

@ -13,7 +13,7 @@ import './dashboard.css';
import ImportModal from 'src/components/ImportModal/ImportModal'; import ImportModal from 'src/components/ImportModal/ImportModal';
//import axios from 'axios'; //import axios from 'axios';
import { RoomType } from 'src/Types/RoomType'; import { RoomType } from 'src/Types/RoomType';
import { useRooms } from '../ManageRoom/RoomContext'; // import { useRooms } from '../ManageRoom/RoomContext';
import { import {
Dialog, Dialog,
DialogActions, DialogActions,
@ -62,7 +62,8 @@ const Dashboard: React.FC = () => {
const [rooms, setRooms] = useState<RoomType[]>([]); const [rooms, setRooms] = useState<RoomType[]>([]);
const [openAddRoomDialog, setOpenAddRoomDialog] = useState(false); const [openAddRoomDialog, setOpenAddRoomDialog] = useState(false);
const [newRoomTitle, setNewRoomTitle] = useState(''); const [newRoomTitle, setNewRoomTitle] = useState('');
const { selectedRoom, selectRoom, createRoom } = useRooms(); // const { selectedRoom, selectRoom, createRoom } = useRooms();
const [selectedRoom, selectRoom] = useState<RoomType>(); // menu
const [errorMessage, setErrorMessage] = useState(''); const [errorMessage, setErrorMessage] = useState('');
const [showErrorDialog, setShowErrorDialog] = useState(false); const [showErrorDialog, setShowErrorDialog] = useState(false);
@ -96,7 +97,7 @@ const Dashboard: React.FC = () => {
setRooms(userRooms as RoomType[]); setRooms(userRooms as RoomType[]);
// select the first room if it exists // select the first room if it exists
if (userRooms instanceof Array && userRooms.length > 0) { if (userRooms instanceof Array && userRooms.length > 0) {
selectRoom(userRooms[0]._id); selectRoom(userRooms[0]);
} }
const userFolders = await ApiService.getUserFolders(); const userFolders = await ApiService.getUserFolders();
@ -111,11 +112,32 @@ const Dashboard: React.FC = () => {
if (event.target.value === 'add-room') { if (event.target.value === 'add-room') {
setOpenAddRoomDialog(true); setOpenAddRoomDialog(true);
} else { } else {
selectRoom(event.target.value); selectRoomByName(event.target.value);
} }
}; };
const handleSubmitCreateRoom = async () => { // Créer une salle
const createRoom = async (title: string) => {
// Créer la salle et récupérer l'objet complet
const newRoom = await ApiService.createRoom(title);
// Mettre à jour la liste des salles
const updatedRooms = await ApiService.getUserRooms();
setRooms(updatedRooms as RoomType[]);
// Sélectionner la nouvelle salle avec son ID
selectRoomByName(newRoom); // Utiliser l'ID de l'objet retourné
};
// Sélectionner une salle
const selectRoomByName = (roomId: string) => {
const room = rooms.find(r => r._id === roomId);
selectRoom(room);
localStorage.setItem('selectedRoomId', roomId);
};
const handleCreateRoom = async () => {
if (newRoomTitle.trim()) { if (newRoomTitle.trim()) {
try { try {
await createRoom(newRoomTitle); await createRoom(newRoomTitle);
@ -432,7 +454,7 @@ const Dashboard: React.FC = () => {
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={() => setOpenAddRoomDialog(false)}>Annuler</Button> <Button onClick={() => setOpenAddRoomDialog(false)}>Annuler</Button>
<Button onClick={handleSubmitCreateRoom}>Créer</Button> <Button onClick={handleCreateRoom}>Créer</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
<Dialog open={showErrorDialog} onClose={() => setShowErrorDialog(false)}> <Dialog open={showErrorDialog} onClose={() => setShowErrorDialog(false)}>
@ -491,6 +513,7 @@ const Dashboard: React.FC = () => {
</Tooltip> </Tooltip>
<Tooltip title="Renommer dossier" placement="top"> <Tooltip title="Renommer dossier" placement="top">
<div>
<IconButton <IconButton
color="primary" color="primary"
onClick={handleRenameFolder} onClick={handleRenameFolder}
@ -499,9 +522,11 @@ const Dashboard: React.FC = () => {
{' '} {' '}
<Edit />{' '} <Edit />{' '}
</IconButton> </IconButton>
</div>
</Tooltip> </Tooltip>
<Tooltip title="Dupliquer dossier" placement="top"> <Tooltip title="Dupliquer dossier" placement="top">
<div>
<IconButton <IconButton
color="primary" color="primary"
onClick={handleDuplicateFolder} onClick={handleDuplicateFolder}
@ -510,9 +535,11 @@ const Dashboard: React.FC = () => {
{' '} {' '}
<FolderCopy />{' '} <FolderCopy />{' '}
</IconButton> </IconButton>
</div>
</Tooltip> </Tooltip>
<Tooltip title="Supprimer dossier" placement="top"> <Tooltip title="Supprimer dossier" placement="top">
<div>
<IconButton <IconButton
aria-label="delete" aria-label="delete"
color="primary" color="primary"
@ -522,6 +549,7 @@ const Dashboard: React.FC = () => {
{' '} {' '}
<DeleteOutline />{' '} <DeleteOutline />{' '}
</IconButton> </IconButton>
</div>
</Tooltip> </Tooltip>
</div> </div>
</div> </div>
@ -554,15 +582,17 @@ const Dashboard: React.FC = () => {
<div className="quiz" key={quiz._id}> <div className="quiz" key={quiz._id}>
<div className="title"> <div className="title">
<Tooltip title="Lancer quiz" placement="top"> <Tooltip title="Lancer quiz" placement="top">
<Button <div>
variant="outlined" <Button
onClick={() => handleLancerQuiz(quiz)} variant="outlined"
disabled={!validateQuiz(quiz.content)} onClick={() => handleLancerQuiz(quiz)}
> disabled={!validateQuiz(quiz.content)}
{`${quiz.title} (${quiz.content.length} question${ >
quiz.content.length > 1 ? 's' : '' {`${quiz.title} (${quiz.content.length} question${
})`} quiz.content.length > 1 ? 's' : ''
</Button> })`}
</Button>
</div>
</Tooltip> </Tooltip>
</div> </div>

View file

@ -23,9 +23,7 @@ import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
import QuestionDisplay from 'src/components/QuestionsDisplay/QuestionDisplay'; import QuestionDisplay from 'src/components/QuestionsDisplay/QuestionDisplay';
import ApiService from '../../../services/ApiService'; import ApiService from '../../../services/ApiService';
import { QuestionType } from 'src/Types/QuestionType'; import { QuestionType } from 'src/Types/QuestionType';
import { useRooms } from '../ManageRoom/RoomContext';
import { Button } from '@mui/material'; import { Button } from '@mui/material';
// import { use } from 'marked';
const ManageRoom: React.FC = () => { const ManageRoom: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@ -38,39 +36,38 @@ const ManageRoom: React.FC = () => {
const [connectingError, setConnectingError] = useState<string>(''); const [connectingError, setConnectingError] = useState<string>('');
const [currentQuestion, setCurrentQuestion] = useState<QuestionType | undefined>(undefined); const [currentQuestion, setCurrentQuestion] = useState<QuestionType | undefined>(undefined);
const [quizStarted, setQuizStarted] = useState(false); const [quizStarted, setQuizStarted] = useState(false);
const { selectedRoom } = useRooms(); const [formattedRoomName, setFormattedRoomName] = useState("");
useEffect(() => { useEffect(() => {
// verify that roomName argument is not null const verifyLogin = async () => {
if (!roomName || !quizId) {
window.alert(
`Une erreur est survenue.\n La salle ou le quiz n'a pas été spécifié.\nVeuillez réessayer plus tard.`
);
console.error('Room or Quiz not found for name:', roomName);
navigate('/teacher/dashboard');
}
}, [roomName, navigate]);
useEffect(() => {
if (selectedRoom && !socket) {
createWebSocketRoom();
}
}, [selectedRoom]);
useEffect(() => {
const fetchData = async () => {
if (!ApiService.isLoggedIn()) { if (!ApiService.isLoggedIn()) {
navigate('/teacher/login'); navigate('/teacher/login');
return; return;
} }
}; };
fetchData(); verifyLogin();
}, []); }, []);
useEffect(() => {
if (!roomName || !quizId) {
window.alert(
`Une erreur est survenue.\n La salle ou le quiz n'a pas été spécifié.\nVeuillez réessayer plus tard.`
);
console.error(`Room "${roomName}" or Quiz "${quizId}" not found.`);
navigate('/teacher/dashboard');
}
if (roomName && !socket) {
createWebSocketRoom();
}
return () => {
disconnectWebSocket();
};
}, [roomName, navigate]);
useEffect(() => { useEffect(() => {
if (quizId) { if (quizId) {
const fetchquiz = async () => { const fetchQuiz = async () => {
const quiz = await ApiService.getQuiz(quizId); const quiz = await ApiService.getQuiz(quizId);
if (!quiz) { if (!quiz) {
@ -83,18 +80,9 @@ const ManageRoom: React.FC = () => {
} }
setQuiz(quiz as QuizType); setQuiz(quiz as QuizType);
if (!socket) {
console.log(`no socket in ManageRoom, creating one.`);
createWebSocketRoom();
}
// return () => {
// webSocketService.disconnect();
// };
}; };
fetchquiz(); fetchQuiz();
} else { } else {
window.alert( window.alert(
`Une erreur est survenue.\n Le quiz ${quizId} n'a pas été trouvé\nVeuillez réessayer plus tard` `Une erreur est survenue.\n Le quiz ${quizId} n'a pas été trouvé\nVeuillez réessayer plus tard`
@ -107,7 +95,7 @@ const ManageRoom: React.FC = () => {
const disconnectWebSocket = () => { const disconnectWebSocket = () => {
if (socket) { if (socket) {
webSocketService.endQuiz(roomName); webSocketService.endQuiz(formattedRoomName);
webSocketService.disconnect(); webSocketService.disconnect();
setSocket(null); setSocket(null);
setQuizQuestions(undefined); setQuizQuestions(undefined);
@ -117,16 +105,12 @@ const ManageRoom: React.FC = () => {
}; };
const createWebSocketRoom = () => { const createWebSocketRoom = () => {
console.log('Creating WebSocket room...');
if (!selectedRoom) {
setConnectingError('Veuillez sélectionner une salle.');
return;
}
const socket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_SOCKET_URL); const socket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_SOCKET_URL);
const roomNameUpper = roomName.toUpperCase();
setFormattedRoomName(roomNameUpper);
console.log(`Creating WebSocket room named ${roomNameUpper}`);
socket.on('connect', () => { socket.on('connect', () => {
webSocketService.createRoom(selectedRoom.title); webSocketService.createRoom(roomNameUpper);
}); });
socket.on('connect_error', (error) => { socket.on('connect_error', (error) => {
@ -134,20 +118,22 @@ const ManageRoom: React.FC = () => {
console.error('ManageRoom: WebSocket connection error:', error); console.error('ManageRoom: WebSocket connection error:', error);
}); });
socket.on('create-success', (roomName: string) => { socket.on('create-success', (createdRoomName: string) => {
console.log(`Room created: ${roomName}`); console.log(`Room created: ${createdRoomName}`);
// setRoomName(roomName);
}); });
socket.on('user-joined', (student: StudentType) => { socket.on('user-joined', (student: StudentType) => {
console.log(`Student joined: name = ${student.name}, id = ${student.id}`); console.log(`Student joined: name = ${student.name}, id = ${student.id}, quizMode = ${quizMode}, quizStarted = ${quizStarted}`);
setStudents((prevStudents) => [...prevStudents, student]); setStudents((prevStudents) => [...prevStudents, student]);
// only send nextQuestion if the quiz has started
if (!quizStarted) return;
if (quizMode === 'teacher') { if (quizMode === 'teacher') {
webSocketService.nextQuestion(roomName, currentQuestion); webSocketService.nextQuestion(formattedRoomName, currentQuestion);
} else if (quizMode === 'student') { } else if (quizMode === 'student') {
webSocketService.launchStudentModeQuiz(roomName, quizQuestions); webSocketService.launchStudentModeQuiz(formattedRoomName, quizQuestions);
} }
}); });
socket.on('join-failure', (message) => { socket.on('join-failure', (message) => {
@ -164,22 +150,9 @@ const ManageRoom: React.FC = () => {
}; };
useEffect(() => { useEffect(() => {
// This is here to make sure the correct value is sent when user join
if (socket) {
console.log(`Listening for user-joined in room ${roomName}`);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
socket.on('user-joined', (_student: StudentType) => {
if (quizMode === 'teacher') {
webSocketService.nextQuestion(roomName, currentQuestion);
} else if (quizMode === 'student') {
webSocketService.launchStudentModeQuiz(roomName, quizQuestions);
}
});
}
if (socket) { if (socket) {
// handle the case where user submits an answer console.log(`Listening for submit-answer-room in room ${formattedRoomName}`);
console.log(`Listening for submit-answer-room in room ${roomName}`);
socket.on('submit-answer-room', (answerData: AnswerReceptionFromBackendType) => { socket.on('submit-answer-room', (answerData: AnswerReceptionFromBackendType) => {
const { answer, idQuestion, idUser, username } = answerData; const { answer, idQuestion, idUser, username } = answerData;
console.log( console.log(
@ -192,7 +165,6 @@ const ManageRoom: React.FC = () => {
// Update the students state using the functional form of setStudents // Update the students state using the functional form of setStudents
setStudents((prevStudents) => { setStudents((prevStudents) => {
// print the list of current student names
console.log('Current students:'); console.log('Current students:');
prevStudents.forEach((student) => { prevStudents.forEach((student) => {
console.log(student.name); console.log(student.name);
@ -208,7 +180,6 @@ const ManageRoom: React.FC = () => {
); );
let updatedAnswers: Answer[] = []; let updatedAnswers: Answer[] = [];
if (existingAnswer) { if (existingAnswer) {
// Update the existing answer
updatedAnswers = student.answers.map((ans) => { updatedAnswers = student.answers.map((ans) => {
console.log(`Comparing ${ans.idQuestion} to ${idQuestion}`); console.log(`Comparing ${ans.idQuestion} to ${idQuestion}`);
return ans.idQuestion === idQuestion return ans.idQuestion === idQuestion
@ -224,7 +195,6 @@ const ManageRoom: React.FC = () => {
: ans; : ans;
}); });
} else { } else {
// Add a new answer
const newAnswer = { const newAnswer = {
idQuestion, idQuestion,
answer, answer,
@ -254,7 +224,7 @@ const ManageRoom: React.FC = () => {
if (nextQuestionIndex === undefined || nextQuestionIndex > quizQuestions.length - 1) return; if (nextQuestionIndex === undefined || nextQuestionIndex > quizQuestions.length - 1) return;
setCurrentQuestion(quizQuestions[nextQuestionIndex]); setCurrentQuestion(quizQuestions[nextQuestionIndex]);
webSocketService.nextQuestion(roomName, quizQuestions[nextQuestionIndex]); webSocketService.nextQuestion(formattedRoomName, quizQuestions[nextQuestionIndex]);
}; };
const previousQuestion = () => { const previousQuestion = () => {
@ -264,7 +234,7 @@ const ManageRoom: React.FC = () => {
if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return; if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return;
setCurrentQuestion(quizQuestions[prevQuestionIndex]); setCurrentQuestion(quizQuestions[prevQuestionIndex]);
webSocketService.nextQuestion(roomName, quizQuestions[prevQuestionIndex]); webSocketService.nextQuestion(formattedRoomName, quizQuestions[prevQuestionIndex]);
}; };
const initializeQuizQuestion = () => { const initializeQuizQuestion = () => {
@ -292,7 +262,7 @@ const ManageRoom: React.FC = () => {
} }
setCurrentQuestion(quizQuestions[0]); setCurrentQuestion(quizQuestions[0]);
webSocketService.nextQuestion(roomName, quizQuestions[0]); webSocketService.nextQuestion(formattedRoomName, quizQuestions[0]);
}; };
const launchStudentMode = () => { const launchStudentMode = () => {
@ -304,14 +274,14 @@ const ManageRoom: React.FC = () => {
return; return;
} }
setQuizQuestions(quizQuestions); setQuizQuestions(quizQuestions);
webSocketService.launchStudentModeQuiz(roomName, quizQuestions); webSocketService.launchStudentModeQuiz(formattedRoomName, quizQuestions);
}; };
const launchQuiz = () => { const launchQuiz = () => {
if (!socket || !roomName || !quiz?.content || quiz?.content.length === 0) { if (!socket || !formattedRoomName || !quiz?.content || quiz?.content.length === 0) {
// TODO: This error happens when token expires! Need to handle it properly // TODO: This error happens when token expires! Need to handle it properly
console.log( console.log(
`Error launching quiz. socket: ${socket}, roomName: ${roomName}, quiz: ${quiz}` `Error launching quiz. socket: ${socket}, roomName: ${formattedRoomName}, quiz: ${quiz}`
); );
setQuizStarted(true); setQuizStarted(true);
@ -332,7 +302,7 @@ const ManageRoom: React.FC = () => {
setCurrentQuestion(quizQuestions[questionIndex]); setCurrentQuestion(quizQuestions[questionIndex]);
if (quizMode === 'teacher') { if (quizMode === 'teacher') {
webSocketService.nextQuestion(roomName, quizQuestions[questionIndex]); webSocketService.nextQuestion(formattedRoomName, quizQuestions[questionIndex]);
} }
} }
}; };
@ -399,7 +369,7 @@ const ManageRoom: React.FC = () => {
return false; return false;
} }
if (!roomName) { if (!formattedRoomName) {
return ( return (
<div className="center"> <div className="center">
{!connectingError ? ( {!connectingError ? (
@ -423,7 +393,7 @@ const ManageRoom: React.FC = () => {
return ( return (
<div className="room"> <div className="room">
<h1>Salle : {roomName}</h1> <h1>Salle : {formattedRoomName}</h1>
<div className="roomHeader"> <div className="roomHeader">
<DisconnectButton <DisconnectButton
onReturn={handleReturn} onReturn={handleReturn}
@ -440,10 +410,10 @@ const ManageRoom: React.FC = () => {
width: '100%' width: '100%'
}} }}
> >
{quizStarted && ( {(
<div <div
className="userCount subtitle smallText" className="userCount subtitle smallText"
style={{ display: 'flex', alignItems: 'center' }} style={{ display: "flex", justifyContent: "flex-end" }}
> >
<GroupIcon style={{ marginRight: '5px' }} /> <GroupIcon style={{ marginRight: '5px' }} />
{students.length}/60 {students.length}/60

View file

@ -51,13 +51,26 @@ class WebSocketService {
} }
} }
// deleteRoom(roomName: string) {
// console.log('WebsocketService: deleteRoom', roomName);
// if (this.socket) {
// console.log('WebsocketService: emit: delete-room', roomName);
// this.socket.emit('delete-room', roomName);
// }
// }
nextQuestion(roomName: string, question: unknown) { nextQuestion(roomName: string, question: unknown) {
console.log('WebsocketService: nextQuestion', roomName, question);
if (!question) {
throw new Error('WebsocketService: nextQuestion: question is null');
}
if (this.socket) { if (this.socket) {
this.socket.emit('next-question', { roomName, question }); this.socket.emit('next-question', { roomName, question });
} }
} }
launchStudentModeQuiz(roomName: string, questions: unknown) { launchStudentModeQuiz(roomName: string, questions: unknown) {
console.log('WebsocketService: launchStudentModeQuiz', roomName, questions, this.socket);
if (this.socket) { if (this.socket) {
this.socket.emit('launch-student-mode', { roomName, questions }); this.socket.emit('launch-student-mode', { roomName, questions });
} }
@ -75,21 +88,9 @@ class WebSocketService {
} }
} }
submitAnswer(answerData: AnswerSubmissionToBackendType submitAnswer(answerData: AnswerSubmissionToBackendType) {
// roomName: string,
// answer: string | number | boolean,
// username: string,
// idQuestion: string
) {
if (this.socket) { if (this.socket) {
this.socket?.emit('submit-answer', this.socket?.emit('submit-answer', answerData
// {
// answer: answer,
// roomName: roomName,
// username: username,
// idQuestion: idQuestion
// }
answerData
); );
} }
} }

View file

@ -60,45 +60,42 @@ describe("websocket server", () => {
}); });
test("should create a room", (done) => { test("should create a room", (done) => {
teacherSocket.emit("create-room", "room1");
teacherSocket.on("create-success", (roomName) => { teacherSocket.on("create-success", (roomName) => {
expect(roomName).toBe("ROOM1"); expect(roomName).toBe("ROOM1");
done(); done();
}); });
teacherSocket.emit("create-room", "room1");
}); });
test("should not create a room if it already exists", (done) => { test("should not create a room if it already exists", (done) => {
teacherSocket.emit("create-room", "room1");
teacherSocket.on("create-failure", () => { teacherSocket.on("create-failure", () => {
done(); done();
}); });
teacherSocket.emit("create-room", "room1");
}); });
test("should join a room", (done) => { test("should join a room", (done) => {
studentSocket.emit("join-room", { studentSocket.on("join-success", (roomName) => {
enteredRoomName: "ROOM1", expect(roomName).toBe("ROOM1");
username: "student1",
});
studentSocket.on("join-success", () => {
done(); done();
}); });
studentSocket.emit("join-room", {
enteredRoomName: "room1",
username: "student1",
});
}); });
test("should not join a room if it does not exist", (done) => { test("should not join a room if it does not exist", (done) => {
studentSocket.on("join-failure", () => {
done();
});
studentSocket.emit("join-room", { studentSocket.emit("join-room", {
enteredRoomName: "ROOM2", enteredRoomName: "ROOM2",
username: "student1", username: "student1",
}); });
studentSocket.on("join-failure", () => {
done();
});
}); });
test("should launch student mode", (done) => { test("should launch student mode", (done) => {
teacherSocket.emit("launch-student-mode", {
roomName: "ROOM1",
questions: [{ question: "question1" }, { question: "question2" }],
});
studentSocket.on("launch-student-mode", (questions) => { studentSocket.on("launch-student-mode", (questions) => {
expect(questions).toEqual([ expect(questions).toEqual([
{ question: "question1" }, { question: "question1" },
@ -106,26 +103,24 @@ describe("websocket server", () => {
]); ]);
done(); done();
}); });
teacherSocket.emit("launch-student-mode", {
roomName: "ROOM1",
questions: [{ question: "question1" }, { question: "question2" }],
});
}); });
test("should send next question", (done) => { test("should send next question", (done) => {
teacherSocket.emit("next-question", {
roomName: "ROOM1",
question: { question: "question2" },
});
studentSocket.on("next-question", (question) => { studentSocket.on("next-question", (question) => {
expect(question).toEqual({ question: "question2" }); expect(question).toEqual({ question: "question2" });
done(); done();
}); });
teacherSocket.emit("next-question", {
roomName: "ROOM1",
question: { question: "question2" },
});
}); });
test("should send answer", (done) => { test("should send answer", (done) => {
studentSocket.emit("submit-answer", {
roomName: "ROOM1",
username: "student1",
answer: "answer1",
idQuestion: 1,
});
teacherSocket.on("submit-answer-room", (answer) => { teacherSocket.on("submit-answer-room", (answer) => {
expect(answer).toEqual({ expect(answer).toEqual({
idUser: studentSocket.id, idUser: studentSocket.id,
@ -135,32 +130,38 @@ describe("websocket server", () => {
}); });
done(); done();
}); });
studentSocket.emit("submit-answer", {
roomName: "ROOM1",
username: "student1",
answer: "answer1",
idQuestion: 1,
});
}); });
test("should not join a room if no room name is provided", (done) => { test("should not join a room if no room name is provided", (done) => {
studentSocket.on("join-failure", () => {
done();
});
studentSocket.emit("join-room", { studentSocket.emit("join-room", {
enteredRoomName: "", enteredRoomName: "",
username: "student1", username: "student1",
}); });
studentSocket.on("join-failure", () => {
done();
});
}); });
test("should not join a room if the username is not provided", (done) => { test("should not join a room if the username is not provided", (done) => {
studentSocket.emit("join-room", { enteredRoomName: "ROOM2", username: "" });
studentSocket.on("join-failure", () => { studentSocket.on("join-failure", () => {
done(); done();
}); });
studentSocket.emit("join-room", { enteredRoomName: "ROOM2", username: "" });
}); });
test("should end quiz", (done) => { test("should end quiz", (done) => {
teacherSocket.emit("end-quiz", {
roomName: "ROOM1",
});
studentSocket.on("end-quiz", () => { studentSocket.on("end-quiz", () => {
done(); done();
}); });
teacherSocket.emit("end-quiz", {
roomName: "ROOM1",
});
}); });
test("should disconnect", (done) => { test("should disconnect", (done) => {

View file

@ -6,7 +6,7 @@ const setupWebsocket = (io) => {
io.on("connection", (socket) => { io.on("connection", (socket) => {
if (totalConnections >= MAX_TOTAL_CONNECTIONS) { if (totalConnections >= MAX_TOTAL_CONNECTIONS) {
console.log("Connection limit reached. Disconnecting client."); console.log("socket.js: Connection limit reached. Disconnecting client.");
socket.emit( socket.emit(
"join-failure", "join-failure",
"Le nombre maximum de connexions a été atteint" "Le nombre maximum de connexions a été atteint"
@ -17,46 +17,46 @@ const setupWebsocket = (io) => {
totalConnections++; totalConnections++;
console.log( console.log(
"A user connected:", "socket.js: A user connected:",
socket.id, socket.id,
"| Total connections:", "| Total connections:",
totalConnections totalConnections
); );
socket.on("create-room", (sentRoomName) => { socket.on("create-room", (sentRoomName) => {
console.log(`Demande de création de salle avec le nom : ${sentRoomName}`); console.log(`socket.js: Demande de création de salle avec le nom : ${sentRoomName}`);
if (sentRoomName) { if (sentRoomName) {
const roomName = sentRoomName.toUpperCase(); const roomName = sentRoomName.toUpperCase();
if (!io.sockets.adapter.rooms.get(roomName)) { if (!io.sockets.adapter.rooms.get(roomName)) {
socket.join(roomName); socket.join(roomName);
socket.emit("create-success", roomName); socket.emit("create-success", roomName);
console.log(`Salle créée avec succès : ${roomName}`); console.log(`socket.js: Salle créée avec succès : ${roomName}`);
} else { } else {
socket.emit("create-failure", `La salle ${roomName} existe déjà.`); socket.emit("create-failure", `La salle ${roomName} existe déjà.`);
console.log(`Échec de création : ${roomName} existe déjà`); console.log(`socket.js: Échec de création : ${roomName} existe déjà`);
} }
} }
console.log( reportSalles();
"Salles existantes après la tentative de création : ",
Array.from(io.sockets.adapter.rooms.keys())
);
}); });
function reportSalles() {
console.log("socket.js: Salles existantes :", Array.from(io.sockets.adapter.rooms.keys()));
}
socket.on("join-room", ({ enteredRoomName, username }) => { socket.on("join-room", ({ enteredRoomName, username }) => {
const roomToCheck = enteredRoomName.toUpperCase(); const roomToCheck = enteredRoomName.toUpperCase();
console.log( console.log(
`Requête de connexion : salle="${roomToCheck}", utilisateur="${username}"` `socket.js: Requête de connexion : salle="${roomToCheck}", utilisateur="${username}"`
);
console.log(
"Salles existantes :",
Array.from(io.sockets.adapter.rooms.keys())
); );
reportSalles();
if (io.sockets.adapter.rooms.has(roomToCheck)) { if (io.sockets.adapter.rooms.has(roomToCheck)) {
console.log("socket.js: La salle existe");
const clientsInRoom = io.sockets.adapter.rooms.get(roomToCheck).size; const clientsInRoom = io.sockets.adapter.rooms.get(roomToCheck).size;
if (clientsInRoom <= MAX_USERS_PER_ROOM) { if (clientsInRoom <= MAX_USERS_PER_ROOM) {
console.log("socket.js: La salle n'est pas pleine avec ", clientsInRoom, " utilisateurs");
const newStudent = { const newStudent = {
id: socket.id, id: socket.id,
name: username, name: username,
@ -64,17 +64,20 @@ const setupWebsocket = (io) => {
}; };
socket.join(roomToCheck); socket.join(roomToCheck);
socket.to(roomToCheck).emit("user-joined", newStudent); socket.to(roomToCheck).emit("user-joined", newStudent);
socket.emit("join-success"); socket.emit("join-success", roomToCheck);
} else { } else {
console.log("socket.js: La salle est pleine avec ", clientsInRoom, " utilisateurs");
socket.emit("join-failure", "La salle est remplie"); socket.emit("join-failure", "La salle est remplie");
} }
} else { } else {
console.log("socket.js: La salle n'existe pas");
socket.emit("join-failure", "Le nom de la salle n'existe pas"); socket.emit("join-failure", "Le nom de la salle n'existe pas");
} }
}); });
socket.on("next-question", ({ roomName, question }) => { socket.on("next-question", ({ roomName, question }) => {
// console.log("next-question", roomName, question); console.log("socket.js: next-question", roomName, question);
console.log("socket.js: rediffusion de la question", question);
socket.to(roomName).emit("next-question", question); socket.to(roomName).emit("next-question", question);
}); });
@ -83,21 +86,25 @@ const setupWebsocket = (io) => {
}); });
socket.on("end-quiz", ({ roomName }) => { socket.on("end-quiz", ({ roomName }) => {
console.log("socket.js: end-quiz", roomName);
socket.to(roomName).emit("end-quiz"); socket.to(roomName).emit("end-quiz");
io.sockets.adapter.rooms.delete(roomName);
reportSalles();
}); });
socket.on("message", (data) => { socket.on("message", (data) => {
console.log("Received message from", socket.id, ":", data); console.log("socket.js: Received message from", socket.id, ":", data);
}); });
socket.on("disconnect", () => { socket.on("disconnect", () => {
totalConnections--; totalConnections--;
console.log( console.log(
"A user disconnected:", "socket.js: A user disconnected:",
socket.id, socket.id,
"| Total connections:", "| Total connections:",
totalConnections totalConnections
); );
reportSalles();
for (const [room] of io.sockets.adapter.rooms) { for (const [room] of io.sockets.adapter.rooms) {
if (room !== socket.id) { if (room !== socket.id) {