+
+
-
+
downloadTxtFile(quiz)}
- >
+ >
+ {' '}
+ {' '}
+
handleEditQuiz(quiz)}
- >
+ >
+ {' '}
+ {' '}
+
handleDuplicateQuiz(quiz)}
- >
+ >
+ {' '}
+ {' '}
+
@@ -507,14 +567,20 @@ const Dashboard: React.FC = () => {
aria-label="delete"
color="primary"
onClick={() => handleRemoveQuiz(quiz)}
- >
+ >
+ {' '}
+ {' '}
+
handleShareQuiz(quiz)}
- >
+ >
+ {' '}
+ {' '}
+
@@ -529,7 +595,6 @@ const Dashboard: React.FC = () => {
handleOnImport={handleOnImport}
selectedFolder={selectedFolderId}
/>
-
);
};
@@ -542,4 +607,3 @@ function addFolderTitleToQuizzes(folderQuizzes: string | QuizType[], folderName:
console.log(`quiz: ${quiz.title} folder: ${quiz.folderName}`);
});
}
-
diff --git a/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx b/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx
index 556fa55..0619377 100644
--- a/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx
+++ b/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx
@@ -23,13 +23,11 @@ import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
import QuestionDisplay from 'src/components/QuestionsDisplay/QuestionDisplay';
import ApiService from '../../../services/ApiService';
import { QuestionType } from 'src/Types/QuestionType';
-import { RoomType } from 'src/Types/RoomType';
-import { Button, NativeSelect } from '@mui/material';
-import { Dialog, DialogActions, DialogContent, DialogTitle, TextField } from '@mui/material';
+import { useRooms } from '../ManageRoom/RoomContext';
+import { Button } from '@mui/material';
const ManageRoom: React.FC = () => {
const navigate = useNavigate();
- const [roomName, setRoomName] = useState
('');
const [socket, setSocket] = useState(null);
const [students, setStudents] = useState([]);
const quizId = useParams<{ id: string }>();
@@ -39,11 +37,9 @@ const ManageRoom: React.FC = () => {
const [connectingError, setConnectingError] = useState('');
const [currentQuestion, setCurrentQuestion] = useState(undefined);
const [quizStarted, setQuizStarted] = useState(false);
- const [rooms, setRooms] = useState([]);
- const [selectedRoomId, setSelectedRoomId] = useState('');
- const [openDialog, setOpenDialog] = useState(false);
- const [newRoomTitle, setNewRoomTitle] = useState('');
- const [isRoomSelectionVisible, setIsRoomSelectionVisible] = useState(true);
+ const { selectedRoom } = useRooms();
+ const roomName = selectedRoom?.title || '';
+
useEffect(() => {
const fetchData = async () => {
@@ -51,54 +47,11 @@ const ManageRoom: React.FC = () => {
navigate('/teacher/login');
return;
}
-
- const userRooms = await ApiService.getUserRooms();
- setRooms(userRooms as RoomType[]);
};
fetchData();
}, []);
- const handleSelectRoom = (event: React.ChangeEvent) => {
- const roomId = event.target.value;
- setSelectedRoomId(roomId);
-
- const selectedRoom = rooms.find((room) => room._id === roomId);
- setRoomName(selectedRoom?.title || '');
- };
-
- useEffect(() => {
- if (rooms.length > 0 && !selectedRoomId) {
- setSelectedRoomId(rooms[0]._id);
- }
- }, [rooms]);
-
- const handleDialogClose = () => {
- setOpenDialog(false);
- };
-
- const handleCreateRoom = async () => {
- setOpenDialog(true);
- };
- const handleSubmitRoom = async () => {
- try {
- if (newRoomTitle.trim()) {
- const createdRoom = await ApiService.createRoom(newRoomTitle);
-
- const updatedRooms = await ApiService.getUserRooms();
- setRooms(updatedRooms as RoomType[]);
-
- if (createdRoom) {
- setSelectedRoomId(createdRoom);
- }
- setOpenDialog(false);
- setNewRoomTitle('');
- }
- } catch (error) {
- console.error('Error creating Room::', error);
- }
- };
-
useEffect(() => {
if (quizId.id) {
const fetchquiz = async () => {
@@ -136,25 +89,6 @@ const ManageRoom: React.FC = () => {
}
}, [quizId]);
- useEffect(() => {
- if (rooms.length > 0 && !selectedRoomId) {
- setSelectedRoomId(rooms[0].title);
- }
- }, [rooms]);
-
- useEffect(() => {
- if (!newRoomTitle && !selectedRoomId) {
- setConnectingError('Aucun nom de salle sélectionné ou créé.');
- }
- }, [newRoomTitle, selectedRoomId]);
-
- useEffect(() => {
- if (selectedRoomId && selectedRoomId.trim() !== '') {
- console.log(`Sélection d'une nouvelle salle: ${selectedRoomId}`);
- createWebSocketRoom();
- }
- }, [selectedRoomId]);
-
const disconnectWebSocket = () => {
if (socket) {
webSocketService.endQuiz(roomName);
@@ -163,162 +97,117 @@ const ManageRoom: React.FC = () => {
setQuizQuestions(undefined);
setCurrentQuestion(undefined);
setStudents(new Array());
- setRoomName('');
}
};
const createWebSocketRoom = () => {
console.log('Creating WebSocket room...');
- setConnectingError('');
-
- const handleRoomCreation = (socket: Socket, roomToCreate?: string) => {
- socket.on('connect', () => {
- if (roomToCreate) {
- webSocketService.createRoom(roomToCreate);
- } else {
- socket.emit("create-room");
- }
- });
-
- socket.on('create-success', (createdRoomName: string) => {
- console.log('Salle créée/jointe:', createdRoomName);
- setRoomName(createdRoomName);
- });
-
- socket.on('create-failure', (errorMessage: string) => {
- setConnectingError(errorMessage);
- console.error('Erreur création salle:', errorMessage);
- });
- socket.on('user-joined', (student: StudentType) => {
- console.log(`Student joined: name = ${student.name}, id = ${student.id}`);
-
- setStudents((prevStudents) => [...prevStudents, student]);
-
- if (quizMode === 'teacher') {
- webSocketService.nextQuestion(roomName, currentQuestion);
- } else if (quizMode === 'student') {
- webSocketService.launchStudentModeQuiz(roomName, quizQuestions);
- }
- });
+ if (!selectedRoom) {
+ setConnectingError('Aucune salle sélectionnée.');
+ return;
+ }
- socket.on('join-failure', (message) => {
- setConnectingError(message);
- setSocket(null);
- });
+ const socket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_SOCKET_URL);
+ socket.on('connect', () => {
+ webSocketService.createRoom(selectedRoom.title);
+ });
+
+ socket.on('connect_error', (error) => {
+ setConnectingError('Erreur lors de la connexion... Veuillez réessayer');
+ console.error('ManageRoom: WebSocket connection error:', error);
+ });
+
+ socket.on('user-joined', (student: StudentType) => {
+ console.log(`Student joined: name = ${student.name}, id = ${student.id}`);
- socket.on('user-disconnected', (userId: string) => {
- console.log(`Student left: id = ${userId}`);
- setStudents((prevUsers) => prevUsers.filter((user) => user.id !== userId));
- });
+ setStudents((prevStudents) => [...prevStudents, student]);
+
+ if (quizMode === 'teacher') {
+ webSocketService.nextQuestion(roomName, currentQuestion);
+ } else if (quizMode === 'student') {
+ webSocketService.launchStudentModeQuiz(roomName, quizQuestions);
+ }
+ });
+ socket.on('join-failure', (message) => {
+ setConnectingError(message);
+ setSocket(null);
+ });
+
+ socket.on('user-disconnected', (userId: string) => {
+ console.log(`Student left: id = ${userId}`);
+ setStudents((prevUsers) => prevUsers.filter((user) => user.id !== userId));
+ });
+
+ setSocket(socket);
};
-
- if (rooms.length === 0) {
- console.log('Tentative de création de salle automatique...');
- const newSocket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_SOCKET_URL);
- handleRoomCreation(newSocket);
- setSocket(newSocket);
- } else {
- const targetRoom = rooms.find((room) => room._id === selectedRoomId) || rooms[0];
- if (!targetRoom) {
- setConnectingError('Aucune salle disponible');
- return;
+
+ 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);
+ }
+ });
}
- console.log('Utilisation de la salle:', targetRoom.title);
- const newSocket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_SOCKET_URL);
- handleRoomCreation(newSocket, targetRoom.title);
- setSocket(newSocket);
- }
- socket?.on('connect_error', (error) => {
- setConnectingError('Erreur de connexion au serveur...');
- console.error('Connection error:', error);
- });
- };
-
- 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) {
- // handle the case where user submits an answer
- console.log(`Listening for submit-answer-room in room ${roomName}`);
- 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;
- }
-
- // 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);
- });
-
- 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 };
- }
- return student;
- });
- if (!foundStudent) {
- console.log(`Student ${username} not found in the list.`);
+ if (socket) {
+ // handle the case where user submits an answer
+ console.log(`Listening for submit-answer-room in room ${roomName}`);
+ 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;
}
- return updatedStudents;
+
+ // 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);
+ });
+
+ 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 };
+ }
+ return student;
+ });
+ if (!foundStudent) {
+ console.log(`Student ${username} not found in the list.`);
+ }
+ return updatedStudents;
+ });
});
- });
- setSocket(socket);
- }
- }, [socket, currentQuestion, quizQuestions]);
+ setSocket(socket);
+ }
+
+ }, [socket, currentQuestion, quizQuestions]);
const nextQuestion = () => {
if (!quizQuestions || !currentQuestion || !quiz?.content) return;
@@ -497,6 +386,7 @@ const ManageRoom: React.FC = () => {
return (
+
Salle : {roomName}
{
width: '100%'
}}
>
-
{quizStarted && (
- {isRoomSelectionVisible && (
-
-
-
-
- {rooms.map((room: RoomType) => (
-
- ))}
-
-
-
-
-
-
-
- {/* Dialog pour créer une salle */}
-
-
- )}
+
{/* the following breaks the css (if 'room' classes are nested) */}
@@ -669,7 +494,6 @@ const ManageRoom: React.FC = () => {
students={students}
launchQuiz={launchQuiz}
setQuizMode={setQuizMode}
- setIsRoomSelectionVisible={setIsRoomSelectionVisible}
/>
)}
diff --git a/client/src/pages/Teacher/ManageRoom/RoomContext.tsx b/client/src/pages/Teacher/ManageRoom/RoomContext.tsx
new file mode 100644
index 0000000..545400c
--- /dev/null
+++ b/client/src/pages/Teacher/ManageRoom/RoomContext.tsx
@@ -0,0 +1,53 @@
+import { createContext, useContext, useState, useEffect } from 'react';
+import ApiService from '../../../services/ApiService';
+import { RoomType } from 'src/Types/RoomType';
+import React from "react";
+
+type RoomContextType = {
+ rooms: RoomType[];
+ selectedRoom: RoomType | null;
+ selectRoom: (roomId: string) => void;
+ createRoom: (title: string) => Promise;
+};
+
+const RoomContext = createContext(undefined);
+
+export const RoomProvider = ({ children }: { children: React.ReactNode }) => {
+ const [rooms, setRooms] = useState([]);
+ const [selectedRoom, setSelectedRoom] = useState(null);
+
+ useEffect(() => {
+ const loadRooms = async () => {
+ const userRooms = await ApiService.getUserRooms();
+ setRooms(userRooms as RoomType[]);
+ };
+ loadRooms();
+ }, []);
+
+ // Sélectionner une salle
+ const selectRoom = (roomId: string) => {
+ const room = rooms.find(r => r._id === roomId) || null;
+ setSelectedRoom(room);
+ localStorage.setItem('selectedRoomId', roomId);
+ };
+
+ // Créer une salle
+ const createRoom = async (title: string) => {
+ const newRoomId = await ApiService.createRoom(title);
+ const updatedRooms = await ApiService.getUserRooms();
+ setRooms(updatedRooms as RoomType[]);
+ selectRoom(newRoomId);
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useRooms = () => {
+ const context = useContext(RoomContext);
+ if (!context) throw new Error('useRooms must be used within a RoomProvider');
+ return context;
+};
\ No newline at end of file