From e4ae70896afd7eb6caf6ed240b1eff76afd35061 Mon Sep 17 00:00:00 2001 From: JubaAzul <118773284+JubaAzul@users.noreply.github.com> Date: Tue, 18 Mar 2025 18:11:25 -0400 Subject: [PATCH] =?UTF-8?q?[BUG]=20Dans=20un=20quiz=20au=20rythme=20de=20l?= =?UTF-8?q?'=C3=A9tudiant,=20l'enseignant=20ne=20peut=20plus=20masquer=20l?= =?UTF-8?q?es=20questions=20Fixes=20#295?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/ManageRoom/ManageRoom.test.tsx | 110 ++++++++++++++---- .../pages/Teacher/ManageRoom/ManageRoom.tsx | 77 +++++++----- .../pages/Teacher/ManageRoom/manageRoom.css | 9 +- 3 files changed, 141 insertions(+), 55 deletions(-) diff --git a/client/src/__tests__/pages/ManageRoom/ManageRoom.test.tsx b/client/src/__tests__/pages/ManageRoom/ManageRoom.test.tsx index 142f1f3..2d0259e 100644 --- a/client/src/__tests__/pages/ManageRoom/ManageRoom.test.tsx +++ b/client/src/__tests__/pages/ManageRoom/ManageRoom.test.tsx @@ -75,36 +75,36 @@ describe('ManageRoom', () => { ); }); - + await act(async () => { const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1]; createSuccessCallback('Test Room'); }); - + await waitFor(() => { expect(ApiService.getQuiz).toHaveBeenCalledWith('test-quiz-id'); }); - + const launchButton = screen.getByText('Lancer'); fireEvent.click(launchButton); - + const rythmeButton = screen.getByText('Rythme du professeur'); fireEvent.click(rythmeButton); - + const secondLaunchButton = screen.getAllByText('Lancer'); fireEvent.click(secondLaunchButton[1]); - + await waitFor(() => { expect(screen.getByText('Test Quiz')).toBeInTheDocument(); - + const roomHeader = document.querySelector('h1'); expect(roomHeader).toHaveTextContent('Salle : TEST ROOM'); - + expect(screen.getByText('0/60')).toBeInTheDocument(); expect(screen.getByText('Question 1/2')).toBeInTheDocument(); }); }); - + test('handles create-success event', async () => { await act(async () => { render( @@ -171,30 +171,30 @@ describe('ManageRoom', () => { ); }); - + await act(async () => { const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1]; createSuccessCallback('Test Room'); }); - + fireEvent.click(screen.getByText('Lancer')); fireEvent.click(screen.getByText('Rythme du professeur')); fireEvent.click(screen.getAllByText('Lancer')[1]); - + await waitFor(() => { screen.debug(); }); - + const nextQuestionButton = await screen.findByRole('button', { name: /Prochaine question/i }); expect(nextQuestionButton).toBeInTheDocument(); - + fireEvent.click(nextQuestionButton); - + await waitFor(() => { expect(screen.getByText('Question 2/2')).toBeInTheDocument(); }); }); - + test('handles disconnect', async () => { await act(async () => { render( @@ -230,37 +230,37 @@ describe('ManageRoom', () => { ); }); - + await act(async () => { const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1]; createSuccessCallback('test-room-name'); }); - + const launchButton = screen.getByText('Lancer'); fireEvent.click(launchButton); - + const rythmeButton = screen.getByText('Rythme du professeur'); fireEvent.click(rythmeButton); - + const secondLaunchButton = screen.getAllByText('Lancer'); fireEvent.click(secondLaunchButton[1]); - + await act(async () => { const userJoinedCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'user-joined')[1]; userJoinedCallback(mockStudents[0]); }); - + await act(async () => { const submitAnswerCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'submit-answer-room')[1]; submitAnswerCallback(mockAnswerData); }); - + await waitFor(() => { expect(consoleSpy).toHaveBeenCalledWith( 'Received answer from Student 1 for question 1: Answer1' ); }); - + consoleSpy.mockRestore(); }); @@ -293,4 +293,66 @@ describe('ManageRoom', () => { expect(screen.queryByText('Student 1')).not.toBeInTheDocument(); }); }); + test('initializes isQuestionShown based on quizMode', async() => { + render( + + ); + + await act(async () => { + const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1]; + createSuccessCallback('Test Room'); + }); + + await waitFor(() => { + expect(ApiService.getQuiz).toHaveBeenCalledWith('test-quiz-id'); + }); + const launchButton = screen.getByText('Lancer'); + fireEvent.click(launchButton); + + const rythmeButton = screen.getByText(`Rythme de l'étudiant`); + fireEvent.click(rythmeButton); + + const secondLaunchButton = screen.getAllByText('Lancer'); + fireEvent.click(secondLaunchButton[1]); + + expect(screen.queryByText('Question')).not.toBeInTheDocument(); + }); + + test('renders the close button when quizMode is student and isQuestionShown is true', async() => { + render( + + ); + + await act(async () => { + const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1]; + createSuccessCallback('Test Room'); + }); + + await waitFor(() => { + expect(ApiService.getQuiz).toHaveBeenCalledWith('test-quiz-id'); + }); + + const launchButton = screen.getByText('Lancer'); + fireEvent.click(launchButton); + + const rythmeButton = screen.getByText(`Rythme de l'étudiant`); + fireEvent.click(rythmeButton); + + const secondLaunchButton = screen.getAllByText('Lancer'); + fireEvent.click(secondLaunchButton[1]); + + const tableHeader = screen.getByText('Q1'); + fireEvent.click(tableHeader); + + const closeButton = screen.getByRole('button', { name: /✖/i }); + expect(closeButton).toBeInTheDocument(); + expect(screen.getByText(/Question 1\//i)).toBeInTheDocument(); + + fireEvent.click(closeButton); + + expect(screen.queryByRole('button', { name: /✖/i })).not.toBeInTheDocument(); + expect(screen.queryByText(/Question 1\//i)).not.toBeInTheDocument(); + + }); + }); diff --git a/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx b/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx index 01d9c27..67af4a3 100644 --- a/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx +++ b/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx @@ -30,7 +30,7 @@ const ManageRoom: React.FC = () => { const navigate = useNavigate(); const [socket, setSocket] = useState(null); const [students, setStudents] = useState([]); - const { quizId = '', roomName = '' } = useParams<{ quizId: string, roomName: string }>(); + const { quizId = '', roomName = '' } = useParams<{ quizId: string, roomName: string }>(); const [quizQuestions, setQuizQuestions] = useState(); const [quiz, setQuiz] = useState(null); const [quizMode, setQuizMode] = useState<'teacher' | 'student'>('teacher'); @@ -39,6 +39,7 @@ const ManageRoom: React.FC = () => { const [quizStarted, setQuizStarted] = useState(false); const [formattedRoomName, setFormattedRoomName] = useState(""); const [newlyConnectedUser, setNewlyConnectedUser] = useState(null); + const [isQuestionShown, setIsQuestionShown] = useState(quizMode === 'student' ? false : true); // Handle the newly connected user in useEffect, because it needs state info // not available in the socket.on() callback @@ -46,13 +47,13 @@ const ManageRoom: React.FC = () => { if (newlyConnectedUser) { console.log(`Handling newly connected user: ${newlyConnectedUser.name}`); setStudents((prevStudents) => [...prevStudents, newlyConnectedUser]); - + // only send nextQuestion if the quiz has started if (!quizStarted) { console.log(`!quizStarted: returning.... `); return; } - + if (quizMode === 'teacher') { webSocketService.nextQuestion({ roomName: formattedRoomName, @@ -65,12 +66,16 @@ const ManageRoom: React.FC = () => { } else { console.error('Invalid quiz mode:', quizMode); } - + // Reset the newly connected user state setNewlyConnectedUser(null); } }, [newlyConnectedUser]); + useEffect(() => { + setIsQuestionShown(quizMode === 'student' ? false : true); + }, [quizMode]); + useEffect(() => { const verifyLogin = async () => { if (!ApiService.isLoggedIn()) { @@ -96,7 +101,7 @@ const ManageRoom: React.FC = () => { return () => { disconnectWebSocket(); }; - }, [roomName, navigate]); + }, [roomName, navigate]); useEffect(() => { if (quizId) { @@ -218,14 +223,14 @@ const ManageRoom: React.FC = () => { console.log(`Comparing ${ans.idQuestion} to ${idQuestion}`); return ans.idQuestion === idQuestion ? { - ...ans, - answer, - isCorrect: checkIfIsCorrect( - answer, - idQuestion, - quizQuestions! - ) - } + ...ans, + answer, + isCorrect: checkIfIsCorrect( + answer, + idQuestion, + quizQuestions! + ) + } : ans; }); } else { @@ -258,10 +263,12 @@ const ManageRoom: React.FC = () => { if (nextQuestionIndex === undefined || nextQuestionIndex > quizQuestions.length - 1) return; setCurrentQuestion(quizQuestions[nextQuestionIndex]); - webSocketService.nextQuestion({roomName: formattedRoomName, - questions: quizQuestions, - questionIndex: nextQuestionIndex, - isLaunch: false}); + webSocketService.nextQuestion({ + roomName: formattedRoomName, + questions: quizQuestions, + questionIndex: nextQuestionIndex, + isLaunch: false + }); }; const previousQuestion = () => { @@ -271,7 +278,7 @@ const ManageRoom: React.FC = () => { if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return; setCurrentQuestion(quizQuestions[prevQuestionIndex]); - webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex: prevQuestionIndex, isLaunch: false}); + webSocketService.nextQuestion({ roomName: formattedRoomName, questions: quizQuestions, questionIndex: prevQuestionIndex, isLaunch: false }); }; const initializeQuizQuestion = () => { @@ -299,7 +306,7 @@ const ManageRoom: React.FC = () => { } setCurrentQuestion(quizQuestions[0]); - webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex: 0, isLaunch: true}); + webSocketService.nextQuestion({ roomName: formattedRoomName, questions: quizQuestions, questionIndex: 0, isLaunch: true }); }; const launchStudentMode = () => { @@ -336,9 +343,11 @@ const ManageRoom: React.FC = () => { if (quiz?.content && quizQuestions) { setCurrentQuestion(quizQuestions[questionIndex]); if (quizMode === 'teacher') { - webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex, isLaunch: false}); + webSocketService.nextQuestion({ roomName: formattedRoomName, questions: quizQuestions, questionIndex, isLaunch: false }); } + setIsQuestionShown(true); } + }; const handleReturn = () => { @@ -460,15 +469,29 @@ const ManageRoom: React.FC = () => { {/* the following breaks the css (if 'room' classes are nested) */}
+ {quizQuestions ? (
{quiz?.title}
- {!isNaN(Number(currentQuestion?.question.id)) && ( - - Question {Number(currentQuestion?.question.id)}/ - {quizQuestions?.length} - + {(quizMode === 'student' && isQuestionShown) && ( +
+ +
)} + {!isNaN(Number(currentQuestion?.question.id)) + && isQuestionShown && ( + + Question {Number(currentQuestion?.question.id)}/ + {quizQuestions?.length} + + ) + } {quizMode === 'teacher' && (
@@ -483,11 +506,11 @@ const ManageRoom: React.FC = () => {
- {currentQuestion && ( + {currentQuestion && isQuestionShown && ( )} diff --git a/client/src/pages/Teacher/ManageRoom/manageRoom.css b/client/src/pages/Teacher/ManageRoom/manageRoom.css index ad870a9..9246099 100644 --- a/client/src/pages/Teacher/ManageRoom/manageRoom.css +++ b/client/src/pages/Teacher/ManageRoom/manageRoom.css @@ -37,10 +37,11 @@ /* align-items: center; */ } - - - - +.close-button-wrapper{ + display: flex; + justify-content: flex-end; + margin-right: 1rem; +} /* .create-room-container { display: flex;