[BUG] Dans un quiz au rythme de l'étudiant, l'enseignant ne peut plus masquer les questions

Fixes #295
This commit is contained in:
JubaAzul 2025-03-18 18:11:25 -04:00
parent 112062c0b2
commit e4ae70896a
3 changed files with 141 additions and 55 deletions

View file

@ -293,4 +293,66 @@ describe('ManageRoom', () => {
expect(screen.queryByText('Student 1')).not.toBeInTheDocument(); expect(screen.queryByText('Student 1')).not.toBeInTheDocument();
}); });
}); });
test('initializes isQuestionShown based on quizMode', async() => {
render(<MemoryRouter>
<ManageRoom />
</MemoryRouter>);
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(<MemoryRouter>
<ManageRoom />
</MemoryRouter>);
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();
});
}); });

View file

@ -39,6 +39,7 @@ const ManageRoom: React.FC = () => {
const [quizStarted, setQuizStarted] = useState<boolean>(false); const [quizStarted, setQuizStarted] = useState<boolean>(false);
const [formattedRoomName, setFormattedRoomName] = useState(""); const [formattedRoomName, setFormattedRoomName] = useState("");
const [newlyConnectedUser, setNewlyConnectedUser] = useState<StudentType | null>(null); const [newlyConnectedUser, setNewlyConnectedUser] = useState<StudentType | null>(null);
const [isQuestionShown, setIsQuestionShown] = useState<boolean>(quizMode === 'student' ? false : true);
// Handle the newly connected user in useEffect, because it needs state info // Handle the newly connected user in useEffect, because it needs state info
// not available in the socket.on() callback // not available in the socket.on() callback
@ -71,6 +72,10 @@ const ManageRoom: React.FC = () => {
} }
}, [newlyConnectedUser]); }, [newlyConnectedUser]);
useEffect(() => {
setIsQuestionShown(quizMode === 'student' ? false : true);
}, [quizMode]);
useEffect(() => { useEffect(() => {
const verifyLogin = async () => { const verifyLogin = async () => {
if (!ApiService.isLoggedIn()) { if (!ApiService.isLoggedIn()) {
@ -258,10 +263,12 @@ 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: formattedRoomName, webSocketService.nextQuestion({
roomName: formattedRoomName,
questions: quizQuestions, questions: quizQuestions,
questionIndex: nextQuestionIndex, questionIndex: nextQuestionIndex,
isLaunch: false}); isLaunch: false
});
}; };
const previousQuestion = () => { const previousQuestion = () => {
@ -271,7 +278,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: formattedRoomName, questions: quizQuestions, questionIndex: prevQuestionIndex, isLaunch: false}); webSocketService.nextQuestion({ roomName: formattedRoomName, questions: quizQuestions, questionIndex: prevQuestionIndex, isLaunch: false });
}; };
const initializeQuizQuestion = () => { const initializeQuizQuestion = () => {
@ -299,7 +306,7 @@ const ManageRoom: React.FC = () => {
} }
setCurrentQuestion(quizQuestions[0]); 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 = () => { const launchStudentMode = () => {
@ -336,9 +343,11 @@ const ManageRoom: React.FC = () => {
if (quiz?.content && quizQuestions) { if (quiz?.content && quizQuestions) {
setCurrentQuestion(quizQuestions[questionIndex]); setCurrentQuestion(quizQuestions[questionIndex]);
if (quizMode === 'teacher') { 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 = () => { const handleReturn = () => {
@ -460,15 +469,29 @@ const ManageRoom: React.FC = () => {
{/* the following breaks the css (if 'room' classes are nested) */} {/* the following breaks the css (if 'room' classes are nested) */}
<div className=""> <div className="">
{quizQuestions ? ( {quizQuestions ? (
<div style={{ display: 'flex', flexDirection: 'column' }}> <div style={{ display: 'flex', flexDirection: 'column' }}>
<div className="title center-h-align mb-2">{quiz?.title}</div> <div className="title center-h-align mb-2">{quiz?.title}</div>
{!isNaN(Number(currentQuestion?.question.id)) && ( {(quizMode === 'student' && isQuestionShown) && (
<div className='close-button-wrapper'>
<Button
className="close-button"
onClick={() => {
setIsQuestionShown(false);
}} >
</Button>
</div>
)}
{!isNaN(Number(currentQuestion?.question.id))
&& isQuestionShown && (
<strong className="number of questions"> <strong className="number of questions">
Question {Number(currentQuestion?.question.id)}/ Question {Number(currentQuestion?.question.id)}/
{quizQuestions?.length} {quizQuestions?.length}
</strong> </strong>
)} )
}
{quizMode === 'teacher' && ( {quizMode === 'teacher' && (
<div className="mb-1"> <div className="mb-1">
@ -483,7 +506,7 @@ const ManageRoom: React.FC = () => {
<div className="mb-2 flex-column-wrapper"> <div className="mb-2 flex-column-wrapper">
<div className="preview-and-result-container"> <div className="preview-and-result-container">
{currentQuestion && ( {currentQuestion && isQuestionShown && (
<QuestionDisplay <QuestionDisplay
showAnswer={false} showAnswer={false}
question={currentQuestion?.question as Question} question={currentQuestion?.question as Question}

View file

@ -37,10 +37,11 @@
/* align-items: center; */ /* align-items: center; */
} }
.close-button-wrapper{
display: flex;
justify-content: flex-end;
margin-right: 1rem;
}
/* .create-room-container { /* .create-room-container {
display: flex; display: flex;