Affichage de la liste des salles

This commit is contained in:
NouhailaAater 2025-02-20 00:19:32 -05:00
parent 3c7e4c68e7
commit a9743ad5d4
5 changed files with 276 additions and 122 deletions

View file

@ -0,0 +1,6 @@
export interface RoomType {
_id: string;
userId: string;
title: string;
created_at: string;
}

View file

@ -13,7 +13,6 @@ import GroupIcon from '@mui/icons-material/Group';
import './manageRoom.css'; import './manageRoom.css';
import { ENV_VARIABLES } from 'src/constants'; import { ENV_VARIABLES } from 'src/constants';
import { StudentType, Answer } from '../../../Types/StudentType'; import { StudentType, Answer } from '../../../Types/StudentType';
import { Button } from '@mui/material';
import LoadingCircle from 'src/components/LoadingCircle/LoadingCircle'; import LoadingCircle from 'src/components/LoadingCircle/LoadingCircle';
import { Refresh, Error } from '@mui/icons-material'; import { Refresh, Error } from '@mui/icons-material';
import StudentWaitPage from 'src/components/StudentWaitPage/StudentWaitPage'; import StudentWaitPage from 'src/components/StudentWaitPage/StudentWaitPage';
@ -22,6 +21,17 @@ 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 { RoomType } from 'src/Types/RoomType';
import {
IconButton,
Button,
Tooltip,
NativeSelect,
} from '@mui/material';
import {
Add
} from '@mui/icons-material';
const ManageRoom: React.FC = () => { const ManageRoom: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@ -35,6 +45,45 @@ 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 [rooms, setFolders] = useState<RoomType[]>([]);
const [selectedRoomId, setSelectedRoomId] = useState<string>('');
useEffect(() => {
const fetchData = async () => {
if (!ApiService.isLoggedIn()) {
navigate("/teacher/login");
return;
}
else {
const userFolders = await ApiService.getUserRooms();
setFolders(userFolders as RoomType[]);
}
};
fetchData();
}, []);
const handleSelectRoom = (event: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedRoomId(event.target.value);
};
const handleCreateRoom = async () => {
try {
const roomTitle = prompt('Titre de la salle');
if (roomTitle) {
await ApiService.createFolder(roomTitle);
const userFolders = await ApiService.getUserFolders();
setFolders(userFolders as RoomType[]);
const newlyCreatedFolder = userFolders[userFolders.length - 1] as RoomType;
setSelectedRoomId(newlyCreatedFolder._id);
}
} catch (error) {
console.error('Error creating folder:', error);
}
};
useEffect(() => { useEffect(() => {
if (quizId.id) { if (quizId.id) {
@ -193,70 +242,6 @@ const ManageRoom: React.FC = () => {
}, [socket, currentQuestion, quizQuestions]); }, [socket, currentQuestion, quizQuestions]);
// useEffect(() => {
// if (socket) {
// const submitAnswerHandler = (answerData: answerSubmissionType) => {
// const { answer, idQuestion, username } = answerData;
// console.log(`Received answer from ${username} for question ${idQuestion}: ${answer}`);
// // print the list of current student names
// console.log('Current students:');
// students.forEach((student) => {
// console.log(student.name);
// });
// // Update the students state using the functional form of setStudents
// setStudents((prevStudents) => {
// let foundStudent = false;
// const updatedStudents = prevStudents.map((student) => {
// if (student.id === username) {
// foundStudent = true;
// const updatedAnswers = student.answers.map((ans) => {
// const newAnswer: Answer = { answer, isCorrect: checkIfIsCorrect(answer, idQuestion, quizQuestions!), idQuestion };
// console.log(`Updating answer for ${student.name} for question ${idQuestion} to ${answer}`);
// return (ans.idQuestion === idQuestion ? { ...ans, newAnswer } : ans);
// }
// );
// return { ...student, answers: updatedAnswers };
// }
// return student;
// });
// if (!foundStudent) {
// console.log(`Student ${username} not found in the list of students in LiveResults`);
// }
// return updatedStudents;
// });
// // make a copy of the students array so we can update it
// // const updatedStudents = [...students];
// // 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
// // console.log(`Student ${idUser} not found in the list of students in LiveResults`);
// // return;
// // }
// // const isCorrect = checkIfIsCorrect(answer, idQuestion);
// // const newAnswer: Answer = { answer, isCorrect, idQuestion };
// // student.answers.push(newAnswer);
// // // print list of answers
// // console.log('Answers:');
// // student.answers.forEach((answer) => {
// // console.log(answer.answer);
// // });
// // setStudents(updatedStudents); // update the state
// };
// socket.on('submit-answer', submitAnswerHandler);
// return () => {
// socket.off('submit-answer');
// };
// }
// }, [socket]);
const nextQuestion = () => { const nextQuestion = () => {
if (!quizQuestions || !currentQuestion || !quiz?.content) return; if (!quizQuestions || !currentQuestion || !quiz?.content) return;
@ -454,7 +439,30 @@ const ManageRoom: React.FC = () => {
</div> </div>
<div className='dumb'></div> <div className='dumb'></div>
</div>
{/* bloc Room */}
<div className='room'>
<div className='select'>
<NativeSelect
id="select-room"
color="primary"
value={selectedRoomId}
onChange={handleSelectRoom}
>
<option value=""> Sélectionner une salle </option>
{rooms.map((room: RoomType) => (
<option value={room._id} key={room._id}> {room.title} </option>
))}
</NativeSelect>
</div>
<div className='actions'>
<Tooltip title="Ajouter room" placement="top">
<IconButton color="primary" onClick={handleCreateRoom}>
<Add />
</IconButton>
</Tooltip>
</div>
</div> </div>
{/* the following breaks the css (if 'room' classes are nested) */} {/* the following breaks the css (if 'room' classes are nested) */}
<div className=''> <div className=''>
@ -534,7 +542,6 @@ const ManageRoom: React.FC = () => {
)} )}
</div> </div>
</div> </div>
); );
}; };

View file

@ -2,6 +2,7 @@ import axios, { AxiosError, AxiosResponse } from 'axios';
import { FolderType } from 'src/Types/FolderType'; import { FolderType } from 'src/Types/FolderType';
import { QuizType } from 'src/Types/QuizType'; import { QuizType } from 'src/Types/QuizType';
import { RoomType } from 'src/Types/RoomType';
import { ENV_VARIABLES } from 'src/constants'; import { ENV_VARIABLES } from 'src/constants';
type ApiResponse = boolean | string; type ApiResponse = boolean | string;
@ -378,6 +379,171 @@ class ApiService {
} }
} }
//ROOM routes
public async getUserRooms(): Promise<RoomType[] | string> {
try {
const url: string = this.constructRequestUrl(`/room/getUserRooms`);
const headers = this.constructRequestHeaders();
const result: AxiosResponse = await axios.get(url, { headers: headers });
if (result.status !== 200) {
throw new Error(`L'obtention des salles utilisateur a échoué. Status: ${result.status}`);
}
return result.data.data.map((room: RoomType) => ({ _id: room._id, title: room.title }));
} catch (error) {
console.log("Error details: ", error);
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const data = err.response?.data as { error: string } | undefined;
const url = err.config?.url || 'URL inconnue';
return data?.error || `Erreur serveur inconnue lors de la requête (${url}).`;
}
return `Une erreur inattendue s'est produite.`
}
}
public async getRoomTitleByUserId(userId: string): Promise<string[] | string> {
try {
if (!userId) {
throw new Error(`L'ID utilisateur est requis.`);
}
const url: string = this.constructRequestUrl(`/room/getRoomTitleByUserId/${userId}`);
const headers = this.constructRequestHeaders();
const result: AxiosResponse = await axios.get(url, { headers });
if (result.status !== 200) {
throw new Error(`L'obtention des titres des salles a échoué. Status: ${result.status}`);
}
return result.data.titles;
} catch (error) {
console.log("Error details: ", error);
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const data = err.response?.data as { error: string } | undefined;
return data?.error || 'Erreur serveur inconnue lors de la requête.';
}
return `Une erreur inattendue s'est produite.`;
}
}
public async getRoomTitle(roomId: string): Promise<string | string> {
try {
if (!roomId) {
throw new Error(`L'ID de la salle est requis.`);
}
const url: string = this.constructRequestUrl(`/room/getRoomTitle/${roomId}`);
const headers = this.constructRequestHeaders();
const result: AxiosResponse = await axios.get(url, { headers });
if (result.status !== 200) {
throw new Error(`L'obtention du titre de la salle a échoué. Status: ${result.status}`);
}
return result.data.title;
} catch (error) {
console.log("Error details: ", error);
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const data = err.response?.data as { error: string } | undefined;
return data?.error || 'Erreur serveur inconnue lors de la requête.';
}
return `Une erreur inattendue s'est produite.`;
}
}
public async createRoom(title: string): Promise<string | string> {
try {
if (!title) {
throw new Error(`Le titre de la salle est requis.`);
}
const url: string = this.constructRequestUrl(`/room/create`);
const headers = this.constructRequestHeaders();
const body = { title };
const result: AxiosResponse = await axios.post(url, body, { headers });
if (result.status !== 200) {
throw new Error(`La création de la salle a échoué. Status: ${result.status}`);
}
return `Salle créée avec succès. ID de la salle: ${result.data.roomId}`;
} catch (error) {
console.log("Error details: ", error);
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const data = err.response?.data as { error: string } | undefined;
return data?.error || 'Erreur serveur inconnue lors de la création de la salle.';
}
return `Une erreur inattendue s'est produite.`;
}
}
public async deleteRoom(roomId: string): Promise<string | string> {
try {
if (!roomId) {
throw new Error(`L'ID de la salle est requis.`);
}
const url: string = this.constructRequestUrl(`/room/delete/${roomId}`);
const headers = this.constructRequestHeaders();
const result: AxiosResponse = await axios.delete(url, { headers });
if (result.status !== 200) {
throw new Error(`La suppression de la salle a échoué. Status: ${result.status}`);
}
return `Salle supprimée avec succès.`;
} catch (error) {
console.log("Error details: ", error);
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const data = err.response?.data as { error: string } | undefined;
return data?.error || 'Erreur serveur inconnue lors de la suppression de la salle.';
}
return `Une erreur inattendue s'est produite.`;
}
}
public async renameRoom(roomId: string, newTitle: string): Promise<string | string> {
try {
if (!roomId || !newTitle) {
throw new Error(`L'ID de la salle et le nouveau titre sont requis.`);
}
const url: string = this.constructRequestUrl(`/room/rename`);
const headers = this.constructRequestHeaders();
const body = { roomId, newTitle };
const result: AxiosResponse = await axios.put(url, body, { headers });
if (result.status !== 200) {
throw new Error(`La mise à jour du titre de la salle a échoué. Status: ${result.status}`);
}
return `Titre de la salle mis à jour avec succès.`;
} catch (error) {
console.log("Error details: ", error);
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const data = err.response?.data as { error: string } | undefined;
return data?.error || 'Erreur serveur inconnue lors de la mise à jour du titre.';
}
return `Une erreur inattendue s'est produite.`;
}
}
/** /**
* @returns true if successful * @returns true if successful
* @returns A error string if unsuccessful, * @returns A error string if unsuccessful,
@ -514,38 +680,6 @@ class ApiService {
} }
} }
public async createRoom(title: string): Promise<ApiResponse> {
try {
if (!title) {
throw new Error(`Le titre de la salle est requis.`);
}
const url: string = this.constructRequestUrl(`room/create`);
const headers = this.constructRequestHeaders();
const body = { title };
const result: AxiosResponse = await axios.post(url, body, { headers: headers });
if (result.status !== 200) {
throw new Error(`La création de la salle a échoué. Status: ${result.status}`);
}
// Return room ID from response data
return result.data.roomId;
} catch (error) {
console.log("Error details: ", error);
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const data = err.response?.data as { error: string } | undefined;
return data?.error || 'Erreur serveur inconnue lors de la création de la salle.';
}
return `Une erreur inattendue s'est produite lors de la création de la salle.`
}
}
// Quiz Routes // Quiz Routes
/** /**

View file

@ -211,19 +211,16 @@ create = async (req, res, next) => {
try { try {
const { userId } = req.params; const { userId } = req.params;
// V<>rification que l'userId est valide
if (!userId) { if (!userId) {
throw new AppError(MISSING_REQUIRED_PARAMETER); throw new AppError(MISSING_REQUIRED_PARAMETER);
} }
// R<>cup<75>rer les salles de l'utilisateur
const rooms = await this.rooms.getUserRooms(userId); const rooms = await this.rooms.getUserRooms(userId);
if (!rooms || rooms.length === 0) { if (!rooms || rooms.length === 0) {
throw new AppError(ROOM_NOT_FOUND); throw new AppError(ROOM_NOT_FOUND);
} }
// Extraire uniquement les titres des salles
const roomTitles = rooms.map(room => room.title); const roomTitles = rooms.map(room => room.title);
return res.status(200).json({ return res.status(200).json({

View file

@ -23,25 +23,25 @@ const setupWebsocket = (io) => {
totalConnections totalConnections
); );
socket.on("create-room", (roomId) => { socket.on("create-room", (sentRoomName) => {
if (roomId) { if (sentRoomName) {
const roomName = roomId; 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);
} else { } else {
socket.emit("create-failure"); socket.emit("create-failure");
} }
} else { } else {
const roomName = generateRoomName(); const roomName = generateRoomName();
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);
} else { } else {
socket.emit("create-failure"); socket.emit("create-failure");
}
} }
} });
});
socket.on("join-room", ({ enteredRoomName, username }) => { socket.on("join-room", ({ enteredRoomName, username }) => {
if (io.sockets.adapter.rooms.has(enteredRoomName)) { if (io.sockets.adapter.rooms.has(enteredRoomName)) {
@ -110,6 +110,16 @@ const setupWebsocket = (io) => {
}); });
}); });
const generateRoomName = (length = 6) => {
const characters = "0123456789";
let result = "";
for (let i = 0; i < length; i++) {
result += characters.charAt(
Math.floor(Math.random() * characters.length)
);
}
return result;
};
}; };
module.exports = { setupWebsocket }; module.exports = { setupWebsocket };