mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
Affichage de la liste des salles
This commit is contained in:
parent
3c7e4c68e7
commit
a9743ad5d4
5 changed files with 276 additions and 122 deletions
6
client/src/Types/RoomType.tsx
Normal file
6
client/src/Types/RoomType.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export interface RoomType {
|
||||
_id: string;
|
||||
userId: string;
|
||||
title: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
|
@ -13,7 +13,6 @@ import GroupIcon from '@mui/icons-material/Group';
|
|||
import './manageRoom.css';
|
||||
import { ENV_VARIABLES } from 'src/constants';
|
||||
import { StudentType, Answer } from '../../../Types/StudentType';
|
||||
import { Button } from '@mui/material';
|
||||
import LoadingCircle from 'src/components/LoadingCircle/LoadingCircle';
|
||||
import { Refresh, Error } from '@mui/icons-material';
|
||||
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 ApiService from '../../../services/ApiService';
|
||||
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 navigate = useNavigate();
|
||||
|
|
@ -35,6 +45,45 @@ const ManageRoom: React.FC = () => {
|
|||
const [connectingError, setConnectingError] = useState<string>('');
|
||||
const [currentQuestion, setCurrentQuestion] = useState<QuestionType | undefined>(undefined);
|
||||
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(() => {
|
||||
if (quizId.id) {
|
||||
|
|
@ -193,70 +242,6 @@ const ManageRoom: React.FC = () => {
|
|||
|
||||
}, [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 = () => {
|
||||
if (!quizQuestions || !currentQuestion || !quiz?.content) return;
|
||||
|
||||
|
|
@ -454,7 +439,30 @@ const ManageRoom: React.FC = () => {
|
|||
</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>
|
||||
{/* the following breaks the css (if 'room' classes are nested) */}
|
||||
<div className=''>
|
||||
|
|
@ -534,7 +542,6 @@ const ManageRoom: React.FC = () => {
|
|||
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import axios, { AxiosError, AxiosResponse } from 'axios';
|
|||
|
||||
import { FolderType } from 'src/Types/FolderType';
|
||||
import { QuizType } from 'src/Types/QuizType';
|
||||
import { RoomType } from 'src/Types/RoomType';
|
||||
import { ENV_VARIABLES } from 'src/constants';
|
||||
|
||||
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 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
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -211,19 +211,16 @@ create = async (req, res, next) => {
|
|||
try {
|
||||
const { userId } = req.params;
|
||||
|
||||
// V<>rification que l'userId est valide
|
||||
if (!userId) {
|
||||
throw new AppError(MISSING_REQUIRED_PARAMETER);
|
||||
}
|
||||
|
||||
// R<>cup<75>rer les salles de l'utilisateur
|
||||
const rooms = await this.rooms.getUserRooms(userId);
|
||||
|
||||
if (!rooms || rooms.length === 0) {
|
||||
throw new AppError(ROOM_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Extraire uniquement les titres des salles
|
||||
const roomTitles = rooms.map(room => room.title);
|
||||
|
||||
return res.status(200).json({
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ const setupWebsocket = (io) => {
|
|||
totalConnections
|
||||
);
|
||||
|
||||
socket.on("create-room", (roomId) => {
|
||||
if (roomId) {
|
||||
const roomName = roomId;
|
||||
socket.on("create-room", (sentRoomName) => {
|
||||
if (sentRoomName) {
|
||||
const roomName = sentRoomName.toUpperCase();
|
||||
if (!io.sockets.adapter.rooms.get(roomName)) {
|
||||
socket.join(roomName);
|
||||
socket.emit("create-success", roomName);
|
||||
|
|
@ -41,7 +41,7 @@ const setupWebsocket = (io) => {
|
|||
socket.emit("create-failure");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("join-room", ({ enteredRoomName, username }) => {
|
||||
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 };
|
||||
|
|
|
|||
Loading…
Reference in a new issue