mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
parent
e61c855492
commit
6d714d1d77
12 changed files with 502 additions and 487 deletions
|
|
@ -13,6 +13,7 @@ import ResetPassword from './pages/AuthManager/providers/SimpleLogin/ResetPasswo
|
||||||
import ManageRoom from './pages/Teacher/ManageRoom/ManageRoom';
|
import ManageRoom from './pages/Teacher/ManageRoom/ManageRoom';
|
||||||
import QuizForm from './pages/Teacher/EditorQuiz/EditorQuiz';
|
import QuizForm from './pages/Teacher/EditorQuiz/EditorQuiz';
|
||||||
|
|
||||||
|
|
||||||
// Pages espace étudiant
|
// Pages espace étudiant
|
||||||
import JoinRoom from './pages/Student/JoinRoom/JoinRoom';
|
import JoinRoom from './pages/Student/JoinRoom/JoinRoom';
|
||||||
|
|
||||||
|
|
@ -25,6 +26,7 @@ import Footer from './components/Footer/Footer';
|
||||||
|
|
||||||
import ApiService from './services/ApiService';
|
import ApiService from './services/ApiService';
|
||||||
import OAuthCallback from './pages/AuthManager/callback/AuthCallback';
|
import OAuthCallback from './pages/AuthManager/callback/AuthCallback';
|
||||||
|
import { QuizProvider } from './pages/Student/JoinRoom/QuizProvider';
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn());
|
const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn());
|
||||||
|
|
@ -78,13 +80,13 @@ const App: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/teacher/manage-room/:quizId/:roomName"
|
path="/teacher/manage-room/:quizId/:roomName"
|
||||||
element={isTeacherAuthenticated ? <ManageRoom /> : <Navigate to="/login" />}
|
element={isTeacherAuthenticated ? <QuizProvider><ManageRoom /></QuizProvider> : <Navigate to="/login" />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Pages espace étudiant */}
|
{/* Pages espace étudiant */}
|
||||||
<Route
|
<Route
|
||||||
path="/student/join-room"
|
path="/student/join-room"
|
||||||
element={( !isRoomRequireAuthentication || isAuthenticated ) ? <JoinRoom /> : <Navigate to="/login" />}
|
element={( !isRoomRequireAuthentication || isAuthenticated ) ? <QuizProvider><JoinRoom /></QuizProvider> : <Navigate to="/login" />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Pages authentification */}
|
{/* Pages authentification */}
|
||||||
|
|
|
||||||
|
|
@ -5,55 +5,52 @@ import { Button } from '@mui/material';
|
||||||
import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
|
import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
|
||||||
import { MultipleChoiceQuestion } from 'gift-pegjs';
|
import { MultipleChoiceQuestion } from 'gift-pegjs';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
||||||
|
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
import { QuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
|
||||||
interface Props {
|
const MultipleChoiceQuestionDisplay: React.FC = () => {
|
||||||
question: MultipleChoiceQuestion;
|
const { questions, index, answer, submitAnswer } = useQuizContext();
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
console.log('MultipleChoiceQuestionDisplay: passedAnswer', JSON.stringify(answer));
|
||||||
showAnswer?: boolean;
|
|
||||||
passedAnswer?: AnswerType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
const question = questions[Number(index)].question as MultipleChoiceQuestion;
|
||||||
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = props;
|
|
||||||
console.log('MultipleChoiceQuestionDisplay: passedAnswer', JSON.stringify(passedAnswer));
|
|
||||||
|
|
||||||
const [answer, setAnswer] = useState<AnswerType>(() => {
|
const [actualAnswer, setActualAnswer] = useState<AnswerType>(() => {
|
||||||
if (passedAnswer && passedAnswer.length > 0) {
|
if (answer && answer.length > 0) {
|
||||||
return passedAnswer;
|
return answer;
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
let disableButton = false;
|
let disableButton = false;
|
||||||
if (handleOnSubmitAnswer === undefined) {
|
if (submitAnswer === undefined) {
|
||||||
disableButton = true;
|
disableButton = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('MultipleChoiceQuestionDisplay: passedAnswer', JSON.stringify(passedAnswer));
|
console.log('MultipleChoiceQuestionDisplay: passedAnswer', JSON.stringify(answer));
|
||||||
if (passedAnswer !== undefined) {
|
if (answer !== undefined) {
|
||||||
setAnswer(passedAnswer);
|
setActualAnswer(answer);
|
||||||
} else {
|
} else {
|
||||||
setAnswer([]);
|
setActualAnswer([]);
|
||||||
}
|
}
|
||||||
}, [passedAnswer, question.id]);
|
}, [answer, index]);
|
||||||
|
|
||||||
const handleOnClickAnswer = (choice: string) => {
|
const handleOnClickAnswer = (choice: string) => {
|
||||||
setAnswer((prevAnswer) => {
|
setActualAnswer((answer) => {
|
||||||
console.log(`handleOnClickAnswer -- setAnswer(): prevAnswer: ${prevAnswer}, choice: ${choice}`);
|
console.log(`handleOnClickAnswer -- setAnswer(): prevAnswer: ${answer}, choice: ${choice}`);
|
||||||
const correctAnswersCount = question.choices.filter((c) => c.isCorrect).length;
|
const correctAnswersCount = question.choices.filter((c) => c.isCorrect).length;
|
||||||
|
|
||||||
if (correctAnswersCount === 1) {
|
if (correctAnswersCount === 1) {
|
||||||
// If only one correct answer, replace the current selection
|
// If only one correct answer, replace the current selection
|
||||||
return prevAnswer.includes(choice) ? [] : [choice];
|
return answer.includes(choice) ? [] : [choice];
|
||||||
} else {
|
} else {
|
||||||
// Allow multiple selections if there are multiple correct answers
|
// Allow multiple selections if there are multiple correct answers
|
||||||
if (prevAnswer.includes(choice)) {
|
if (answer.includes(choice)) {
|
||||||
// Remove the choice if it's already selected
|
// Remove the choice if it's already selected
|
||||||
return prevAnswer.filter((selected) => selected !== choice);
|
return answer.filter((selected) => selected !== choice);
|
||||||
} else {
|
} else {
|
||||||
// Add the choice if it's not already selected
|
// Add the choice if it's not already selected
|
||||||
return [...prevAnswer, choice];
|
return [...answer, choice];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -63,14 +60,16 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
const alphabet = alpha.map((x) => String.fromCharCode(x));
|
const alphabet = alpha.map((x) => String.fromCharCode(x));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<QuizContext.Consumer>
|
||||||
|
{({ showAnswer }) => (
|
||||||
<div className="question-container">
|
<div className="question-container">
|
||||||
<div className="question content">
|
<div className="question content">
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
||||||
</div>
|
</div>
|
||||||
<div className="choices-wrapper mb-1">
|
<div className="choices-wrapper mb-1">
|
||||||
{question.choices.map((choice, i) => {
|
{question.choices.map((choice, i) => {
|
||||||
console.log(`answer: ${answer}, choice: ${choice.formattedText.text}`);
|
console.log(`answer: ${actualAnswer}, choice: ${choice.formattedText.text}`);
|
||||||
const selected = answer.includes(choice.formattedText.text) ? 'selected' : '';
|
const selected = actualAnswer.includes(choice.formattedText.text) ? 'selected' : '';
|
||||||
return (
|
return (
|
||||||
<div key={choice.formattedText.text + i} className="choice-container">
|
<div key={choice.formattedText.text + i} className="choice-container">
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -115,11 +114,11 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!showAnswer && handleOnSubmitAnswer && (
|
{!showAnswer && submitAnswer && (
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
answer.length > 0 && handleOnSubmitAnswer && handleOnSubmitAnswer(answer)
|
actualAnswer.length > 0 && submitAnswer && submitAnswer(actualAnswer)
|
||||||
}
|
}
|
||||||
disabled={answer.length === 0}
|
disabled={answer.length === 0}
|
||||||
>
|
>
|
||||||
|
|
@ -127,6 +126,8 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</QuizContext.Consumer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,26 +6,23 @@ import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemp
|
||||||
import { NumericalQuestion, SimpleNumericalAnswer, RangeNumericalAnswer, HighLowNumericalAnswer } from 'gift-pegjs';
|
import { NumericalQuestion, SimpleNumericalAnswer, RangeNumericalAnswer, HighLowNumericalAnswer } from 'gift-pegjs';
|
||||||
import { isSimpleNumericalAnswer, isRangeNumericalAnswer, isHighLowNumericalAnswer, isMultipleNumericalAnswer } from 'gift-pegjs/typeGuards';
|
import { isSimpleNumericalAnswer, isRangeNumericalAnswer, isHighLowNumericalAnswer, isMultipleNumericalAnswer } from 'gift-pegjs/typeGuards';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
||||||
|
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
import { QuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
|
||||||
interface Props {
|
const NumericalQuestionDisplay: React.FC = () => {
|
||||||
question: NumericalQuestion;
|
const { questions, index, answer, submitAnswer } = useQuizContext();
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
|
||||||
showAnswer?: boolean;
|
|
||||||
passedAnswer?: AnswerType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
const question = questions[Number(index)].question as NumericalQuestion;
|
||||||
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } =
|
|
||||||
props;
|
const [actualAnswer, setActualAnswer] = useState<AnswerType>(answer || []);
|
||||||
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || []);
|
|
||||||
const correctAnswers = question.choices;
|
const correctAnswers = question.choices;
|
||||||
let correctAnswer = '';
|
let correctAnswer = '';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (passedAnswer !== null && passedAnswer !== undefined) {
|
if (answer !== null && answer !== undefined) {
|
||||||
setAnswer(passedAnswer);
|
setActualAnswer(answer);
|
||||||
}
|
}
|
||||||
}, [passedAnswer]);
|
}, [answer]);
|
||||||
|
|
||||||
//const isSingleAnswer = correctAnswers.length === 1;
|
//const isSingleAnswer = correctAnswers.length === 1;
|
||||||
|
|
||||||
|
|
@ -44,6 +41,8 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<QuizContext.Consumer>
|
||||||
|
{({ showAnswer }) => (
|
||||||
<div className="question-wrapper">
|
<div className="question-wrapper">
|
||||||
<div>
|
<div>
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
||||||
|
|
@ -54,7 +53,7 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
<strong>La bonne réponse est: </strong>
|
<strong>La bonne réponse est: </strong>
|
||||||
{correctAnswer}</div>
|
{correctAnswer}</div>
|
||||||
<span>
|
<span>
|
||||||
<strong>Votre réponse est: </strong>{answer.toString()}
|
<strong>Votre réponse est: </strong>{actualAnswer.toString()}
|
||||||
</span>
|
</span>
|
||||||
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
||||||
|
|
@ -69,7 +68,7 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
id={question.formattedStem.text}
|
id={question.formattedStem.text}
|
||||||
name={question.formattedStem.text}
|
name={question.formattedStem.text}
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setAnswer([e.target.valueAsNumber]);
|
setActualAnswer([e.target.valueAsNumber]);
|
||||||
}}
|
}}
|
||||||
inputProps={{ 'data-testid': 'number-input' }}
|
inputProps={{ 'data-testid': 'number-input' }}
|
||||||
/>
|
/>
|
||||||
|
|
@ -79,22 +78,25 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{handleOnSubmitAnswer && (
|
{submitAnswer && (
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
answer !== undefined &&
|
actualAnswer !== undefined &&
|
||||||
handleOnSubmitAnswer &&
|
submitAnswer &&
|
||||||
handleOnSubmitAnswer(answer)
|
submitAnswer(actualAnswer)
|
||||||
}
|
}
|
||||||
disabled={answer === undefined || answer === null || isNaN(answer[0] as number)}
|
disabled={actualAnswer === undefined || actualAnswer === null || isNaN(actualAnswer[0] as number)}
|
||||||
>
|
>
|
||||||
Répondre
|
Répondre
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</QuizContext.Consumer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,20 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Question } from 'gift-pegjs';
|
import { Question } from 'gift-pegjs';
|
||||||
|
|
||||||
import TrueFalseQuestionDisplay from './TrueFalseQuestionDisplay/TrueFalseQuestionDisplay';
|
import TrueFalseQuestionDisplay from './TrueFalseQuestionDisplay/TrueFalseQuestionDisplay';
|
||||||
import MultipleChoiceQuestionDisplay from './MultipleChoiceQuestionDisplay/MultipleChoiceQuestionDisplay';
|
import MultipleChoiceQuestionDisplay from './MultipleChoiceQuestionDisplay/MultipleChoiceQuestionDisplay';
|
||||||
import NumericalQuestionDisplay from './NumericalQuestionDisplay/NumericalQuestionDisplay';
|
import NumericalQuestionDisplay from './NumericalQuestionDisplay/NumericalQuestionDisplay';
|
||||||
import ShortAnswerQuestionDisplay from './ShortAnswerQuestionDisplay/ShortAnswerQuestionDisplay';
|
import ShortAnswerQuestionDisplay from './ShortAnswerQuestionDisplay/ShortAnswerQuestionDisplay';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
// import useCheckMobileScreen from '../../services/useCheckMobileScreen';
|
|
||||||
|
|
||||||
interface QuestionProps {
|
|
||||||
question: Question;
|
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
|
||||||
showAnswer?: boolean;
|
|
||||||
answer?: AnswerType;
|
|
||||||
|
|
||||||
}
|
|
||||||
const QuestionDisplay: React.FC<QuestionProps> = ({
|
|
||||||
question,
|
|
||||||
handleOnSubmitAnswer,
|
|
||||||
showAnswer,
|
|
||||||
answer,
|
|
||||||
}) => {
|
|
||||||
// const isMobile = useCheckMobileScreen();
|
|
||||||
// const imgWidth = useMemo(() => {
|
|
||||||
// return isMobile ? '100%' : '20%';
|
|
||||||
// }, [isMobile]);
|
|
||||||
|
|
||||||
|
const QuestionDisplay: React.FC = () => {
|
||||||
|
const { questions, index } = useQuizContext();
|
||||||
|
const question = questions[Number(index)].question as Question;
|
||||||
let questionTypeComponent = null;
|
let questionTypeComponent = null;
|
||||||
|
|
||||||
switch (question?.type) {
|
switch (question?.type) {
|
||||||
case 'TF':
|
case 'TF':
|
||||||
questionTypeComponent = (
|
questionTypeComponent = (
|
||||||
<TrueFalseQuestionDisplay
|
<TrueFalseQuestionDisplay
|
||||||
question={question}
|
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
|
||||||
// showAnswer={showAnswer}
|
|
||||||
passedAnswer={answer}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
@ -42,10 +22,6 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
|
||||||
|
|
||||||
questionTypeComponent = (
|
questionTypeComponent = (
|
||||||
<MultipleChoiceQuestionDisplay
|
<MultipleChoiceQuestionDisplay
|
||||||
question={question}
|
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
|
||||||
showAnswer={showAnswer}
|
|
||||||
passedAnswer={answer}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
@ -53,11 +29,6 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
|
||||||
if (question.choices) {
|
if (question.choices) {
|
||||||
questionTypeComponent = (
|
questionTypeComponent = (
|
||||||
<NumericalQuestionDisplay
|
<NumericalQuestionDisplay
|
||||||
question={question}
|
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
|
||||||
showAnswer={showAnswer}
|
|
||||||
passedAnswer={answer}
|
|
||||||
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -65,10 +36,6 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
|
||||||
case 'Short':
|
case 'Short':
|
||||||
questionTypeComponent = (
|
questionTypeComponent = (
|
||||||
<ShortAnswerQuestionDisplay
|
<ShortAnswerQuestionDisplay
|
||||||
question={question}
|
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
|
||||||
showAnswer={showAnswer}
|
|
||||||
passedAnswer={answer}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -4,28 +4,26 @@ import { Button, TextField } from '@mui/material';
|
||||||
import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
|
import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
|
||||||
import { ShortAnswerQuestion } from 'gift-pegjs';
|
import { ShortAnswerQuestion } from 'gift-pegjs';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
||||||
|
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
import { QuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
|
||||||
interface Props {
|
|
||||||
question: ShortAnswerQuestion;
|
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
|
||||||
showAnswer?: boolean;
|
|
||||||
passedAnswer?: AnswerType;
|
|
||||||
|
|
||||||
}
|
const ShortAnswerQuestionDisplay: React.FC = () => {
|
||||||
|
|
||||||
const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
const { questions, index, answer, submitAnswer } = useQuizContext();
|
||||||
|
const [actualAnswer, setActualAnswer] = useState<AnswerType>(answer || []);
|
||||||
const { question, showAnswer, handleOnSubmitAnswer, passedAnswer } = props;
|
const question = questions[Number(index)].question as ShortAnswerQuestion;
|
||||||
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (passedAnswer !== undefined) {
|
if (answer !== undefined) {
|
||||||
setAnswer(passedAnswer);
|
setActualAnswer(answer);
|
||||||
}
|
}
|
||||||
}, [passedAnswer]);
|
}, [answer]);
|
||||||
console.log("Answer" , answer);
|
console.log("Answer", actualAnswer);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<QuizContext.Consumer>
|
||||||
|
{({ showAnswer }) => (
|
||||||
<div className="question-wrapper">
|
<div className="question-wrapper">
|
||||||
<div className="question content">
|
<div className="question content">
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
||||||
|
|
@ -43,7 +41,7 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<strong>Votre réponse est: </strong>{answer}
|
<strong>Votre réponse est: </strong>{actualAnswer}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
||||||
|
|
@ -58,21 +56,21 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
id={question.formattedStem.text}
|
id={question.formattedStem.text}
|
||||||
name={question.formattedStem.text}
|
name={question.formattedStem.text}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setAnswer([e.target.value]);
|
setActualAnswer([e.target.value]);
|
||||||
}}
|
}}
|
||||||
disabled={showAnswer}
|
disabled={showAnswer}
|
||||||
aria-label="short-answer-input"
|
aria-label="short-answer-input"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{handleOnSubmitAnswer && (
|
{submitAnswer && (
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
answer !== undefined &&
|
actualAnswer !== undefined &&
|
||||||
handleOnSubmitAnswer &&
|
submitAnswer &&
|
||||||
handleOnSubmitAnswer(answer)
|
submitAnswer(actualAnswer)
|
||||||
}
|
}
|
||||||
disabled={answer === null || answer === undefined || answer.length === 0}
|
disabled={actualAnswer === null || actualAnswer === undefined || actualAnswer.length === 0}
|
||||||
>
|
>
|
||||||
Répondre
|
Répondre
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -80,6 +78,8 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</QuizContext.Consumer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,51 +4,43 @@ import '../questionStyle.css';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import { TrueFalseQuestion } from 'gift-pegjs';
|
import { TrueFalseQuestion } from 'gift-pegjs';
|
||||||
import { FormattedTextTemplate } from 'src/components/GiftTemplate/templates/TextTypeTemplate';
|
import { FormattedTextTemplate } from 'src/components/GiftTemplate/templates/TextTypeTemplate';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
import { QuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
import { QuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
|
||||||
interface Props {
|
|
||||||
question: TrueFalseQuestion;
|
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
|
||||||
// showAnswer?: boolean;
|
|
||||||
passedAnswer?: AnswerType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
const TrueFalseQuestionDisplay: React.FC = () => {
|
||||||
const { question,
|
|
||||||
// showAnswer,
|
|
||||||
handleOnSubmitAnswer, passedAnswer } =
|
|
||||||
props;
|
|
||||||
|
|
||||||
const [answer, setAnswer] = useState<boolean | undefined>(() => {
|
const { questions, index, answer, submitAnswer } = useQuizContext();
|
||||||
if (passedAnswer && (passedAnswer[0] === true || passedAnswer[0] === false)) {
|
|
||||||
return passedAnswer[0];
|
const question = questions[Number(index)].question as TrueFalseQuestion;
|
||||||
|
|
||||||
|
const [actualAnswer, setActualAnswer] = useState<boolean | undefined>(() => {
|
||||||
|
if (answer && (answer[0] === true || answer[0] === false)) {
|
||||||
|
return answer[0];
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
let disableButton = false;
|
let disableButton = false;
|
||||||
if (handleOnSubmitAnswer === undefined) {
|
if (submitAnswer === undefined) {
|
||||||
disableButton = true;
|
disableButton = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("passedAnswer", passedAnswer);
|
console.log("passedAnswer", answer);
|
||||||
if (passedAnswer && (passedAnswer[0] === true || passedAnswer[0] === false)) {
|
if (answer && (answer[0] === true || answer[0] === false)) {
|
||||||
setAnswer(passedAnswer[0]);
|
setActualAnswer(answer[0]);
|
||||||
} else {
|
} else {
|
||||||
setAnswer(undefined);
|
setActualAnswer(undefined);
|
||||||
}
|
}
|
||||||
}, [passedAnswer, question.id]);
|
}, [answer, index]);
|
||||||
|
|
||||||
const handleOnClickAnswer = (choice: boolean) => {
|
const handleOnClickAnswer = (choice: boolean) => {
|
||||||
setAnswer(choice);
|
setActualAnswer(choice);
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedTrue = answer ? 'selected' : '';
|
const selectedTrue = actualAnswer ? 'selected' : '';
|
||||||
const selectedFalse = answer !== undefined && !answer ? 'selected' : '';
|
const selectedFalse = actualAnswer !== undefined && !actualAnswer ? 'selected' : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QuizContext.Consumer>
|
<QuizContext.Consumer>
|
||||||
|
|
@ -76,7 +68,7 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
<div className={`circle ${selectedTrue}`}>V</div>
|
<div className={`circle ${selectedTrue}`}>V</div>
|
||||||
<div className={`answer-text ${selectedTrue}`}>Vrai</div>
|
<div className={`answer-text ${selectedTrue}`}>Vrai</div>
|
||||||
|
|
||||||
{showAnswer && answer && question.trueFormattedFeedback && (
|
{showAnswer && actualAnswer && question.trueFormattedFeedback && (
|
||||||
<div className="true-feedback mb-2">
|
<div className="true-feedback mb-2">
|
||||||
<div
|
<div
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
|
|
@ -102,7 +94,7 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
<div className={`circle ${selectedFalse}`}>F</div>
|
<div className={`circle ${selectedFalse}`}>F</div>
|
||||||
<div className={`answer-text ${selectedFalse}`}>Faux</div>
|
<div className={`answer-text ${selectedFalse}`}>Faux</div>
|
||||||
|
|
||||||
{showAnswer && !answer && question.falseFormattedFeedback && (
|
{showAnswer && !actualAnswer && question.falseFormattedFeedback && (
|
||||||
<div className="false-feedback mb-2">
|
<div className="false-feedback mb-2">
|
||||||
<div
|
<div
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
|
|
@ -126,15 +118,15 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!showAnswer && handleOnSubmitAnswer && (
|
{!showAnswer && submitAnswer && (
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
answer !== undefined &&
|
actualAnswer !== undefined &&
|
||||||
handleOnSubmitAnswer &&
|
submitAnswer &&
|
||||||
handleOnSubmitAnswer([answer])
|
submitAnswer([actualAnswer])
|
||||||
}
|
}
|
||||||
disabled={answer === undefined}
|
disabled={actualAnswer === undefined}
|
||||||
>
|
>
|
||||||
Répondre
|
Répondre
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,16 @@
|
||||||
// StudentModeQuiz.tsx
|
// StudentModeQuiz.tsx
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import QuestionComponent from '../QuestionsDisplay/QuestionDisplay';
|
import QuestionDisplay from '../QuestionsDisplay/QuestionDisplay';
|
||||||
import '../../pages/Student/JoinRoom/joinRoom.css';
|
import '../../pages/Student/JoinRoom/joinRoom.css';
|
||||||
import { QuestionType } from '../../Types/QuestionType';
|
import { QuestionType } from '../../Types/QuestionType';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
||||||
import { Question } from 'gift-pegjs';
|
|
||||||
import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService';
|
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
|
||||||
interface StudentModeQuizProps {
|
const StudentModeQuiz: React.FC = () => {
|
||||||
questions: QuestionType[];
|
const { questions, answers, setIsQuestionSent, disconnectWebSocket, setShowAnswer } = useQuizContext(); // Access setShowAnswer from context
|
||||||
answers: AnswerSubmissionToBackendType[];
|
|
||||||
submitAnswer: (_answer: AnswerType, _idQuestion: number) => void;
|
|
||||||
disconnectWebSocket: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
|
|
||||||
questions,
|
|
||||||
answers,
|
|
||||||
submitAnswer,
|
|
||||||
disconnectWebSocket
|
|
||||||
}) => {
|
|
||||||
const { setShowAnswer } = useQuizContext(); // Access setShowAnswer from context
|
|
||||||
|
|
||||||
const [questionInfos, setQuestion] = useState<QuestionType>(questions[0]);
|
const [questionInfos, setQuestion] = useState<QuestionType>(questions[0]);
|
||||||
const [isAnswerSubmitted, setIsAnswerSubmitted] = useState(false);
|
|
||||||
|
|
||||||
const previousQuestion = () => {
|
const previousQuestion = () => {
|
||||||
setQuestion(questions[Number(questionInfos.question?.id) - 2]);
|
setQuestion(questions[Number(questionInfos.question?.id) - 2]);
|
||||||
|
|
@ -35,7 +19,7 @@ const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const savedAnswer = answers[Number(questionInfos.question.id) - 1]?.answer;
|
const savedAnswer = answers[Number(questionInfos.question.id) - 1]?.answer;
|
||||||
console.log(`StudentModeQuiz: useEffect: savedAnswer: ${savedAnswer}`);
|
console.log(`StudentModeQuiz: useEffect: savedAnswer: ${savedAnswer}`);
|
||||||
setIsAnswerSubmitted(savedAnswer !== undefined);
|
setIsQuestionSent(savedAnswer !== undefined);
|
||||||
setShowAnswer(savedAnswer !== undefined); // Update showAnswer in context
|
setShowAnswer(savedAnswer !== undefined); // Update showAnswer in context
|
||||||
}, [questionInfos.question, answers, setShowAnswer]);
|
}, [questionInfos.question, answers, setShowAnswer]);
|
||||||
|
|
||||||
|
|
@ -43,13 +27,6 @@ const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
|
||||||
setQuestion(questions[Number(questionInfos.question?.id)]);
|
setQuestion(questions[Number(questionInfos.question?.id)]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnSubmitAnswer = (answer: AnswerType) => {
|
|
||||||
const idQuestion = Number(questionInfos.question.id) || -1;
|
|
||||||
submitAnswer(answer, idQuestion);
|
|
||||||
setIsAnswerSubmitted(true);
|
|
||||||
setShowAnswer(true); // Update showAnswer in context when an answer is submitted
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="room">
|
<div className="room">
|
||||||
<div className="roomHeader">
|
<div className="roomHeader">
|
||||||
|
|
@ -63,12 +40,7 @@ const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
|
||||||
</div>
|
</div>
|
||||||
<div className="overflow-auto">
|
<div className="overflow-auto">
|
||||||
<div className="question-component-container">
|
<div className="question-component-container">
|
||||||
<QuestionComponent
|
<QuestionDisplay/>
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
|
||||||
question={questionInfos.question as Question}
|
|
||||||
showAnswer={isAnswerSubmitted} // Local state for showing answers
|
|
||||||
answer={answers[Number(questionInfos.question.id) - 1]?.answer}
|
|
||||||
/>
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: '1rem' }}>
|
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: '1rem' }}>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -1,69 +1,55 @@
|
||||||
// TeacherModeQuiz.tsx
|
// TeacherModeQuiz.tsx
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import QuestionComponent from '../QuestionsDisplay/QuestionDisplay';
|
import QuestionDisplay from '../QuestionsDisplay/QuestionDisplay';
|
||||||
import '../../pages/Student/JoinRoom/joinRoom.css';
|
import '../../pages/Student/JoinRoom/joinRoom.css';
|
||||||
import { QuestionType } from '../../Types/QuestionType';
|
|
||||||
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
||||||
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
|
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
|
||||||
import { Question } from 'gift-pegjs';
|
|
||||||
import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService';
|
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
// import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
interface TeacherModeQuizProps {
|
|
||||||
questionInfos: QuestionType;
|
|
||||||
answers: AnswerSubmissionToBackendType[];
|
|
||||||
submitAnswer: (_answer: AnswerType, _idQuestion: number) => void;
|
|
||||||
disconnectWebSocket: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
const TeacherModeQuiz: React.FC = () => {
|
||||||
questionInfos,
|
const {
|
||||||
|
questions,
|
||||||
answers,
|
answers,
|
||||||
submitAnswer,
|
setShowAnswer,
|
||||||
disconnectWebSocket
|
disconnectWebSocket,
|
||||||
}) => {
|
index,
|
||||||
const { setShowAnswer } = useQuizContext(); // Access setShowAnswer from context
|
isQuestionSent,
|
||||||
|
setIsQuestionSent,
|
||||||
|
answer,
|
||||||
|
setAnswer,
|
||||||
|
} = useQuizContext();
|
||||||
|
|
||||||
const [isAnswerSubmitted, setIsAnswerSubmitted] = useState(false);
|
const [isAnswerSubmitted, setIsAnswerSubmitted] = useState(false);
|
||||||
const [isFeedbackDialogOpen, setIsFeedbackDialogOpen] = useState(false);
|
|
||||||
const [answer, setAnswer] = useState<AnswerType>();
|
|
||||||
|
|
||||||
|
|
||||||
// arrive here the first time after waiting for next question
|
// arrive here the first time after waiting for next question
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log(`QuestionDisplay: questions: ${JSON.stringify(questions)}`);
|
||||||
|
|
||||||
console.log(`TeacherModeQuiz: useEffect: answers: ${JSON.stringify(answers)}`);
|
console.log(`TeacherModeQuiz: useEffect: answers: ${JSON.stringify(answers)}`);
|
||||||
console.log(`TeacherModeQuiz: useEffect: questionInfos.question.id: ${questionInfos.question.id} answer: ${answer}`);
|
console.log(`TeacherModeQuiz: useEffect: questionInfos.question.id: ${index} answer: ${answer}`);
|
||||||
const oldAnswer = answers[Number(questionInfos.question.id) -1 ]?.answer;
|
const oldAnswer = answers[Number(index) -1 ]?.answer;
|
||||||
console.log(`TeacherModeQuiz: useEffect: oldAnswer: ${oldAnswer}`);
|
console.log(`TeacherModeQuiz: useEffect: oldAnswer: ${oldAnswer}`);
|
||||||
setAnswer(oldAnswer);
|
setAnswer(oldAnswer);
|
||||||
setShowAnswer(false);
|
setShowAnswer(false);
|
||||||
setIsFeedbackDialogOpen(false);
|
setIsQuestionSent(false);
|
||||||
}, [questionInfos.question, answers]);
|
}, [questions[Number(index)].question, answers]);
|
||||||
|
|
||||||
// handle showing the feedback dialog
|
// handle showing the feedback dialog
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(`TeacherModeQuiz: useEffect: answer: ${answer}`);
|
console.log(`TeacherModeQuiz: useEffect: answer: ${answer}`);
|
||||||
setIsAnswerSubmitted(answer !== undefined);
|
setIsAnswerSubmitted(answer !== undefined);
|
||||||
setIsFeedbackDialogOpen(answer !== undefined);
|
setIsQuestionSent(answer !== undefined);
|
||||||
}, [answer]);
|
}, [answer]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(`TeacherModeQuiz: useEffect: isAnswerSubmitted: ${isAnswerSubmitted}`);
|
console.log(`TeacherModeQuiz: useEffect: isAnswerSubmitted: ${isAnswerSubmitted}`);
|
||||||
setIsFeedbackDialogOpen(isAnswerSubmitted);
|
setIsQuestionSent(isAnswerSubmitted);
|
||||||
setShowAnswer(isAnswerSubmitted);
|
setShowAnswer(isAnswerSubmitted);
|
||||||
}, [isAnswerSubmitted]);
|
}, [isAnswerSubmitted]);
|
||||||
|
|
||||||
const handleOnSubmitAnswer = (answer: AnswerType) => {
|
|
||||||
const idQuestion = Number(questionInfos.question.id) || -1;
|
|
||||||
submitAnswer(answer, idQuestion);
|
|
||||||
setAnswer(answer);
|
|
||||||
setIsFeedbackDialogOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFeedbackDialogClose = () => {
|
const handleFeedbackDialogClose = () => {
|
||||||
setIsFeedbackDialogOpen(false);
|
setIsQuestionSent(false);
|
||||||
setIsAnswerSubmitted(true);
|
setIsAnswerSubmitted(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -76,7 +62,7 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
||||||
message={`Êtes-vous sûr de vouloir quitter?`} />
|
message={`Êtes-vous sûr de vouloir quitter?`} />
|
||||||
|
|
||||||
<div className='centerTitle'>
|
<div className='centerTitle'>
|
||||||
<div className='title'>Question {questionInfos.question.id}</div>
|
<div className='title'>Question {index}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='dumb'></div>
|
<div className='dumb'></div>
|
||||||
|
|
@ -88,15 +74,11 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
||||||
En attente pour la prochaine question...
|
En attente pour la prochaine question...
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<QuestionComponent
|
<QuestionDisplay/>
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
|
||||||
question={questionInfos.question as Question}
|
|
||||||
answer={answer}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
open={isFeedbackDialogOpen}
|
open={isQuestionSent}
|
||||||
onClose={handleFeedbackDialogClose}
|
onClose={handleFeedbackDialogClose}
|
||||||
>
|
>
|
||||||
<DialogTitle>Rétroaction</DialogTitle>
|
<DialogTitle>Rétroaction</DialogTitle>
|
||||||
|
|
@ -111,12 +93,8 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
||||||
>Question : </div>
|
>Question : </div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<QuestionComponent
|
<QuestionDisplay
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
//showAnswer={true}
|
||||||
question={questionInfos.question as Question}
|
|
||||||
showAnswer={true}
|
|
||||||
answer={answer}
|
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|
|
||||||
|
|
@ -15,23 +15,38 @@ import LoadingButton from '@mui/lab/LoadingButton';
|
||||||
|
|
||||||
import LoginContainer from 'src/components/LoginContainer/LoginContainer'
|
import LoginContainer from 'src/components/LoginContainer/LoginContainer'
|
||||||
|
|
||||||
import ApiService from '../../../services/ApiService'
|
import { useQuizContext } from './QuizContext';
|
||||||
import { QuizProvider } from './QuizProvider';
|
|
||||||
|
|
||||||
export type AnswerType = Array<string | number | boolean>;
|
export type AnswerType = Array<string | number | boolean>;
|
||||||
|
|
||||||
const JoinRoom: React.FC = () => {
|
const JoinRoom: React.FC = () => {
|
||||||
const [roomName, setRoomName] = useState('');
|
const {
|
||||||
const [username, setUsername] = useState(ApiService.getUsername());
|
setQuestions,
|
||||||
|
setAnswers,
|
||||||
|
questions,
|
||||||
|
username,
|
||||||
|
setUsername,
|
||||||
|
setDisconnectWebSocket,
|
||||||
|
roomName,
|
||||||
|
setRoomName,
|
||||||
|
index,
|
||||||
|
updateIndex,
|
||||||
|
|
||||||
|
} = useQuizContext();
|
||||||
|
|
||||||
const [socket, setSocket] = useState<Socket | null>(null);
|
const [socket, setSocket] = useState<Socket | null>(null);
|
||||||
const [isWaitingForTeacher, setIsWaitingForTeacher] = useState(false);
|
const [isWaitingForTeacher, setIsWaitingForTeacher] = useState(false);
|
||||||
const [question, setQuestion] = useState<QuestionType>();
|
|
||||||
const [quizMode, setQuizMode] = useState<string>();
|
const [quizMode, setQuizMode] = useState<string>();
|
||||||
const [questions, setQuestions] = useState<QuestionType[]>([]);
|
|
||||||
const [answers, setAnswers] = useState<AnswerSubmissionToBackendType[]>([]);
|
|
||||||
const [connectionError, setConnectionError] = useState<string>('');
|
const [connectionError, setConnectionError] = useState<string>('');
|
||||||
const [isConnecting, setIsConnecting] = useState<boolean>(false);
|
const [isConnecting, setIsConnecting] = useState<boolean>(false);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Set the disconnectWebSocket function in the context
|
||||||
|
setDisconnectWebSocket(() => disconnect);
|
||||||
|
}, [socket]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleCreateSocket();
|
handleCreateSocket();
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -42,6 +57,7 @@ const JoinRoom: React.FC = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(`JoinRoom: useEffect: questions: ${JSON.stringify(questions)}`);
|
console.log(`JoinRoom: useEffect: questions: ${JSON.stringify(questions)}`);
|
||||||
setAnswers(questions ? Array(questions.length).fill({} as AnswerSubmissionToBackendType) : []);
|
setAnswers(questions ? Array(questions.length).fill({} as AnswerSubmissionToBackendType) : []);
|
||||||
|
console.log(`JoinRoom: useEffect: answers: ${JSON.stringify(questions)}`);
|
||||||
}, [questions]);
|
}, [questions]);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -58,13 +74,13 @@ const JoinRoom: React.FC = () => {
|
||||||
console.log('JoinRoom: on(next-question): Received next-question:', question);
|
console.log('JoinRoom: on(next-question): Received next-question:', question);
|
||||||
setQuizMode('teacher');
|
setQuizMode('teacher');
|
||||||
setIsWaitingForTeacher(false);
|
setIsWaitingForTeacher(false);
|
||||||
setQuestion(question);
|
updateIndex(Number(question.question.id));
|
||||||
});
|
});
|
||||||
socket.on('launch-teacher-mode', (questions: QuestionType[]) => {
|
socket.on('launch-teacher-mode', (questions: QuestionType[]) => {
|
||||||
console.log('on(launch-teacher-mode): Received launch-teacher-mode:', questions);
|
console.log('on(launch-teacher-mode): Received launch-teacher-mode:', questions);
|
||||||
setQuizMode('teacher');
|
setQuizMode('teacher');
|
||||||
setIsWaitingForTeacher(true);
|
setIsWaitingForTeacher(true);
|
||||||
setQuestions([]); // clear out from last time (in case quiz is repeated)
|
updateIndex(null);
|
||||||
setQuestions(questions);
|
setQuestions(questions);
|
||||||
// wait for next-question
|
// wait for next-question
|
||||||
});
|
});
|
||||||
|
|
@ -75,7 +91,7 @@ const JoinRoom: React.FC = () => {
|
||||||
setIsWaitingForTeacher(false);
|
setIsWaitingForTeacher(false);
|
||||||
setQuestions([]); // clear out from last time (in case quiz is repeated)
|
setQuestions([]); // clear out from last time (in case quiz is repeated)
|
||||||
setQuestions(questions);
|
setQuestions(questions);
|
||||||
setQuestion(questions[0]);
|
updateIndex(0);
|
||||||
});
|
});
|
||||||
socket.on('end-quiz', () => {
|
socket.on('end-quiz', () => {
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
@ -105,7 +121,7 @@ const JoinRoom: React.FC = () => {
|
||||||
// localStorage.clear();
|
// localStorage.clear();
|
||||||
webSocketService.disconnect();
|
webSocketService.disconnect();
|
||||||
setSocket(null);
|
setSocket(null);
|
||||||
setQuestion(undefined);
|
updateIndex(null);
|
||||||
setIsWaitingForTeacher(false);
|
setIsWaitingForTeacher(false);
|
||||||
setQuizMode('');
|
setQuizMode('');
|
||||||
setRoomName('');
|
setRoomName('');
|
||||||
|
|
@ -127,25 +143,6 @@ const JoinRoom: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnSubmitAnswer = (answer: AnswerType, idQuestion: number) => {
|
|
||||||
console.info(`JoinRoom: handleOnSubmitAnswer: answer: ${answer}, idQuestion: ${idQuestion}`);
|
|
||||||
const answerData: AnswerSubmissionToBackendType = {
|
|
||||||
roomName: roomName,
|
|
||||||
answer: answer,
|
|
||||||
username: username,
|
|
||||||
idQuestion: idQuestion
|
|
||||||
};
|
|
||||||
// localStorage.setItem(`Answer${idQuestion}`, JSON.stringify(answer));
|
|
||||||
setAnswers((prevAnswers) => {
|
|
||||||
console.log(`JoinRoom: handleOnSubmitAnswer: prevAnswers: ${JSON.stringify(prevAnswers)}`);
|
|
||||||
const newAnswers = [...prevAnswers]; // Create a copy of the previous answers array
|
|
||||||
newAnswers[idQuestion - 1] = answerData; // Update the specific answer
|
|
||||||
return newAnswers; // Return the new array
|
|
||||||
});
|
|
||||||
console.log(`JoinRoom: handleOnSubmitAnswer: answers: ${JSON.stringify(answers)}`);
|
|
||||||
webSocketService.submitAnswer(answerData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleReturnKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleReturnKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === 'Enter' && username && roomName) {
|
if (e.key === 'Enter' && username && roomName) {
|
||||||
handleSocket();
|
handleSocket();
|
||||||
|
|
@ -176,28 +173,16 @@ const JoinRoom: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (quizMode) {
|
switch (quizMode) {
|
||||||
|
|
||||||
|
|
||||||
case 'student':
|
case 'student':
|
||||||
return (
|
return (
|
||||||
<QuizProvider>
|
<StudentModeQuiz />
|
||||||
<StudentModeQuiz
|
|
||||||
questions={questions}
|
|
||||||
answers={answers}
|
|
||||||
submitAnswer={handleOnSubmitAnswer}
|
|
||||||
disconnectWebSocket={disconnect}
|
|
||||||
/>
|
|
||||||
</QuizProvider>
|
|
||||||
);
|
);
|
||||||
case 'teacher':
|
case 'teacher':
|
||||||
return (
|
return (
|
||||||
question && (
|
index != null && (
|
||||||
<QuizProvider>
|
<TeacherModeQuiz />
|
||||||
<TeacherModeQuiz
|
|
||||||
questionInfos={question}
|
|
||||||
answers={answers}
|
|
||||||
submitAnswer={handleOnSubmitAnswer}
|
|
||||||
disconnectWebSocket={disconnect}
|
|
||||||
/>
|
|
||||||
</QuizProvider>
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,49 @@
|
||||||
import React, { Dispatch, SetStateAction, useContext } from 'react';
|
import React, { Dispatch, SetStateAction, useContext } from 'react';
|
||||||
|
import { QuestionType } from '../../../Types/QuestionType';
|
||||||
|
import { AnswerSubmissionToBackendType } from '../../../services/WebsocketService';
|
||||||
|
import { AnswerType } from './JoinRoom';
|
||||||
|
|
||||||
export const QuizContext = React.createContext<{
|
export const QuizContext = React.createContext<{
|
||||||
showAnswer: boolean;
|
showAnswer: boolean;
|
||||||
setShowAnswer: Dispatch<SetStateAction<boolean>>;
|
setShowAnswer: Dispatch<SetStateAction<boolean>>;
|
||||||
|
questions: QuestionType[];
|
||||||
|
setQuestions: Dispatch<SetStateAction<QuestionType[]>>;
|
||||||
|
answers: AnswerSubmissionToBackendType[];
|
||||||
|
setAnswers: Dispatch<SetStateAction<AnswerSubmissionToBackendType[]>>;
|
||||||
|
answer : AnswerType;
|
||||||
|
setAnswer: Dispatch<SetStateAction<AnswerType>>;
|
||||||
|
index: number | null; // Add index to the context
|
||||||
|
updateIndex: (questionId: number | null) => void; // Add a function to update the index
|
||||||
|
submitAnswer: (answer: AnswerType, idQuestion?: number) => void; // Updated submitAnswer signature
|
||||||
|
isQuestionSent: boolean;
|
||||||
|
setIsQuestionSent: Dispatch<SetStateAction<boolean>>;
|
||||||
|
roomName: string;
|
||||||
|
setRoomName: Dispatch<SetStateAction<string>>;
|
||||||
|
username: string; // Username of the user
|
||||||
|
setUsername: Dispatch<SetStateAction<string>>; // Setter for username
|
||||||
|
disconnectWebSocket: () => void; // Function to disconnect the WebSocket
|
||||||
|
setDisconnectWebSocket: Dispatch<SetStateAction<() => void>>; // Setter for disconnectWebSocket
|
||||||
|
|
||||||
}>({
|
}>({
|
||||||
showAnswer: false,
|
showAnswer: false,
|
||||||
setShowAnswer: () => {},
|
setShowAnswer: () => {},
|
||||||
|
questions: [],
|
||||||
|
setQuestions: () => {},
|
||||||
|
answers: [],
|
||||||
|
setAnswers: () => {},
|
||||||
|
answer: [], // Default value for answer
|
||||||
|
setAnswer: () => {}, // Default no-op function
|
||||||
|
index: null, // Default value for index
|
||||||
|
updateIndex: () => {}, // Default no-op function
|
||||||
|
submitAnswer: () => {}, // Default no-op function
|
||||||
|
isQuestionSent: false,
|
||||||
|
setIsQuestionSent: () => {},
|
||||||
|
username: '', // Default value for username
|
||||||
|
setUsername: () => {}, // Default no-op function
|
||||||
|
roomName: '', // Default value for roomName
|
||||||
|
setRoomName: () => {}, // Default no-op function
|
||||||
|
disconnectWebSocket: () => {}, // Default no-op function
|
||||||
|
setDisconnectWebSocket: () => {}, // Default no-op function
|
||||||
});
|
});
|
||||||
|
|
||||||
export const useQuizContext = () => {
|
export const useQuizContext = () => {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,95 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { QuizContext } from './QuizContext';
|
import { QuizContext } from './QuizContext';
|
||||||
|
import { QuestionType } from '../../../Types/QuestionType';
|
||||||
|
import { AnswerSubmissionToBackendType } from '../../../services/WebsocketService';
|
||||||
|
import { AnswerType } from './JoinRoom';
|
||||||
|
import webSocketService from '../../../services/WebsocketService';
|
||||||
|
import ApiService from '../../../services/ApiService'
|
||||||
|
|
||||||
|
|
||||||
export const QuizProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
export const QuizProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
|
|
||||||
// State for showing answers
|
// State for showing answers
|
||||||
const [showAnswer, setShowAnswer] = useState(false);
|
const [showAnswer, setShowAnswer] = useState(false);
|
||||||
|
|
||||||
console.log('QuizProvider: showAnswer:', showAnswer);
|
// State for managing the list of questions
|
||||||
|
const [questions, setQuestions] = useState<QuestionType[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
// State for managing the list of answers
|
||||||
console.log('QuizProvider: showAnswer:', showAnswer);
|
const [answers, setAnswers] = useState<AnswerSubmissionToBackendType[]>([]);
|
||||||
}, [showAnswer]);
|
|
||||||
|
// Calculate the index based on the current question's ID
|
||||||
|
const [index, setIndex] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const [answer, setAnswer] = useState<AnswerType>([]); // Initialize answer as an empty array
|
||||||
|
|
||||||
|
const [isQuestionSent, setIsQuestionSent] = useState(false);
|
||||||
|
|
||||||
|
const [username, setUsername] = useState<string>(ApiService.getUsername());
|
||||||
|
|
||||||
|
const [roomName, setRoomName] = useState<string>(''); // Add roomName state
|
||||||
|
|
||||||
|
const [disconnectWebSocket, setDisconnectWebSocket] = useState<() => void>(() => () => {});
|
||||||
|
|
||||||
|
|
||||||
|
const updateIndex = (questionId: number | null) => {
|
||||||
|
const questionIndex = questions.findIndex((q) => q.question.id === String(questionId));
|
||||||
|
setIndex(questionIndex >= 0 ? questionIndex : null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to handle answer submission
|
||||||
|
const submitAnswer = (answer: AnswerType, idQuestion?: number) => {
|
||||||
|
if (!idQuestion) {
|
||||||
|
setAnswer(answer);
|
||||||
|
setIsQuestionSent(true);
|
||||||
|
console.log('index',index);
|
||||||
|
} else {
|
||||||
|
console.info(`QuizProvider: submitAnswer: answer: ${answer}, idQuestion: ${idQuestion}`);
|
||||||
|
const answerData: AnswerSubmissionToBackendType = {
|
||||||
|
roomName: roomName,
|
||||||
|
answer: answer,
|
||||||
|
username: username,
|
||||||
|
idQuestion: idQuestion,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update the answers state
|
||||||
|
setAnswers((prevAnswers) => {
|
||||||
|
const newAnswers = [...prevAnswers]; // Create a copy of the previous answers array
|
||||||
|
newAnswers[idQuestion - 1] = answerData; // Update the specific answer
|
||||||
|
return newAnswers; // Return the new array
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`QuizProvider: submitAnswer: answers: ${JSON.stringify(answers)}`);
|
||||||
|
|
||||||
|
// Submit the answer to the WebSocket service
|
||||||
|
webSocketService.submitAnswer(answerData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QuizContext.Provider value={{ showAnswer, setShowAnswer }}>
|
<QuizContext.Provider
|
||||||
|
value={{
|
||||||
|
showAnswer,
|
||||||
|
setShowAnswer,
|
||||||
|
questions,
|
||||||
|
setQuestions,
|
||||||
|
answers,
|
||||||
|
setAnswers,
|
||||||
|
answer,
|
||||||
|
setAnswer,
|
||||||
|
index, // Expose the index in the context
|
||||||
|
updateIndex, // Expose a function to update the index
|
||||||
|
submitAnswer, // Expose submitAnswer in the context
|
||||||
|
isQuestionSent,
|
||||||
|
setIsQuestionSent,
|
||||||
|
username,
|
||||||
|
setUsername,
|
||||||
|
roomName,
|
||||||
|
setRoomName,
|
||||||
|
disconnectWebSocket,
|
||||||
|
setDisconnectWebSocket,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</QuizContext.Provider>
|
</QuizContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import { BaseQuestion, parse, Question } from 'gift-pegjs';
|
import { BaseQuestion, parse /*Question*/ } from 'gift-pegjs';
|
||||||
import LiveResultsComponent from 'src/components/LiveResults/LiveResults';
|
import LiveResultsComponent from 'src/components/LiveResults/LiveResults';
|
||||||
import webSocketService, {
|
import webSocketService, {
|
||||||
AnswerReceptionFromBackendType
|
AnswerReceptionFromBackendType
|
||||||
|
|
@ -20,17 +20,24 @@ import ApiService from '../../../services/ApiService';
|
||||||
import { QuestionType } from 'src/Types/QuestionType';
|
import { QuestionType } from 'src/Types/QuestionType';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import { checkIfIsCorrect } from './useRooms';
|
import { checkIfIsCorrect } from './useRooms';
|
||||||
|
import { useQuizContext } from 'src/pages/Student/JoinRoom/QuizContext';
|
||||||
|
|
||||||
const ManageRoom: React.FC = () => {
|
const ManageRoom: React.FC = () => {
|
||||||
|
const {
|
||||||
|
questions,
|
||||||
|
setQuestions,
|
||||||
|
index,
|
||||||
|
updateIndex,
|
||||||
|
} = useQuizContext();
|
||||||
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [socket, setSocket] = useState<Socket | null>(null);
|
const [socket, setSocket] = useState<Socket | null>(null);
|
||||||
const [students, setStudents] = useState<StudentType[]>([]);
|
const [students, setStudents] = useState<StudentType[]>([]);
|
||||||
const { quizId = '', roomName = '' } = useParams<{ quizId: string, roomName: string }>();
|
const { quizId = '', roomName = '' } = useParams<{ quizId: string, roomName: string }>();
|
||||||
const [quizQuestions, setQuizQuestions] = useState<QuestionType[] | undefined>();
|
|
||||||
const [quiz, setQuiz] = useState<QuizType | null>(null);
|
const [quiz, setQuiz] = useState<QuizType | null>(null);
|
||||||
const [quizMode, setQuizMode] = useState<'teacher' | 'student'>('teacher');
|
const [quizMode, setQuizMode] = useState<'teacher' | 'student'>('teacher');
|
||||||
const [connectingError, setConnectingError] = useState<string>('');
|
const [connectingError, setConnectingError] = useState<string>('');
|
||||||
const [currentQuestion, setCurrentQuestion] = useState<QuestionType | undefined>(undefined);
|
|
||||||
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);
|
||||||
|
|
@ -51,12 +58,12 @@ const ManageRoom: React.FC = () => {
|
||||||
if (quizMode === 'teacher') {
|
if (quizMode === 'teacher') {
|
||||||
webSocketService.nextQuestion({
|
webSocketService.nextQuestion({
|
||||||
roomName: formattedRoomName,
|
roomName: formattedRoomName,
|
||||||
questions: quizQuestions,
|
questions: questions,
|
||||||
questionIndex: Number(currentQuestion?.question.id) - 1,
|
questionIndex: Number(index),
|
||||||
isLaunch: true // started late
|
isLaunch: true // started late
|
||||||
});
|
});
|
||||||
} else if (quizMode === 'student') {
|
} else if (quizMode === 'student') {
|
||||||
webSocketService.launchStudentModeQuiz(formattedRoomName, quizQuestions);
|
webSocketService.launchStudentModeQuiz(formattedRoomName, questions);
|
||||||
} else {
|
} else {
|
||||||
console.error('Invalid quiz mode:', quizMode);
|
console.error('Invalid quiz mode:', quizMode);
|
||||||
}
|
}
|
||||||
|
|
@ -126,8 +133,8 @@ const ManageRoom: React.FC = () => {
|
||||||
webSocketService.endQuiz(formattedRoomName);
|
webSocketService.endQuiz(formattedRoomName);
|
||||||
webSocketService.disconnect();
|
webSocketService.disconnect();
|
||||||
setSocket(null);
|
setSocket(null);
|
||||||
setQuizQuestions(undefined);
|
setQuestions([]);
|
||||||
setCurrentQuestion(undefined);
|
updateIndex(null);
|
||||||
setStudents(new Array<StudentType>());
|
setStudents(new Array<StudentType>());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -187,7 +194,7 @@ const ManageRoom: React.FC = () => {
|
||||||
console.log(
|
console.log(
|
||||||
`Received answer from ${username} for question ${idQuestion}: ${answer}`
|
`Received answer from ${username} for question ${idQuestion}: ${answer}`
|
||||||
);
|
);
|
||||||
if (!quizQuestions) {
|
if (!questions) {
|
||||||
console.log('Quiz questions not found (cannot update answers without them).');
|
console.log('Quiz questions not found (cannot update answers without them).');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +225,7 @@ const ManageRoom: React.FC = () => {
|
||||||
isCorrect: checkIfIsCorrect(
|
isCorrect: checkIfIsCorrect(
|
||||||
answer,
|
answer,
|
||||||
idQuestion,
|
idQuestion,
|
||||||
quizQuestions!
|
questions!
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
: ans;
|
: ans;
|
||||||
|
|
@ -227,7 +234,7 @@ const ManageRoom: React.FC = () => {
|
||||||
const newAnswer = {
|
const newAnswer = {
|
||||||
idQuestion,
|
idQuestion,
|
||||||
answer,
|
answer,
|
||||||
isCorrect: checkIfIsCorrect(answer, idQuestion, quizQuestions!)
|
isCorrect: checkIfIsCorrect(answer, idQuestion, questions!)
|
||||||
};
|
};
|
||||||
updatedAnswers = [...student.answers, newAnswer];
|
updatedAnswers = [...student.answers, newAnswer];
|
||||||
}
|
}
|
||||||
|
|
@ -243,30 +250,30 @@ const ManageRoom: React.FC = () => {
|
||||||
});
|
});
|
||||||
setSocket(socket);
|
setSocket(socket);
|
||||||
}
|
}
|
||||||
}, [socket, currentQuestion, quizQuestions]);
|
}, [socket, index, questions]);
|
||||||
|
|
||||||
const nextQuestion = () => {
|
const nextQuestion = () => {
|
||||||
if (!quizQuestions || !currentQuestion || !quiz?.content) return;
|
if (!questions || !index || !quiz?.content) return;
|
||||||
|
|
||||||
const nextQuestionIndex = Number(currentQuestion?.question.id);
|
const nextQuestionIndex = index;
|
||||||
|
|
||||||
if (nextQuestionIndex === undefined || nextQuestionIndex > quizQuestions.length - 1) return;
|
if (nextQuestionIndex === undefined || nextQuestionIndex > questions.length - 1) return;
|
||||||
|
|
||||||
setCurrentQuestion(quizQuestions[nextQuestionIndex]);
|
updateIndex(nextQuestionIndex);
|
||||||
webSocketService.nextQuestion({roomName: formattedRoomName,
|
webSocketService.nextQuestion({roomName: formattedRoomName,
|
||||||
questions: quizQuestions,
|
questions: questions,
|
||||||
questionIndex: nextQuestionIndex,
|
questionIndex: nextQuestionIndex,
|
||||||
isLaunch: false});
|
isLaunch: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
const previousQuestion = () => {
|
const previousQuestion = () => {
|
||||||
if (!quizQuestions || !currentQuestion || !quiz?.content) return;
|
if (!questions || !index || !quiz?.content) return;
|
||||||
|
|
||||||
const prevQuestionIndex = Number(currentQuestion?.question.id) - 2; // -2 because question.id starts at index 1
|
const prevQuestionIndex = index - 1; // -2 because question.id starts at index 1
|
||||||
|
|
||||||
if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return;
|
if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return;
|
||||||
setCurrentQuestion(quizQuestions[prevQuestionIndex]);
|
updateIndex(prevQuestionIndex);
|
||||||
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex: prevQuestionIndex, isLaunch: false});
|
webSocketService.nextQuestion({roomName: formattedRoomName, questions: questions, questionIndex: prevQuestionIndex, isLaunch: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeQuizQuestion = () => {
|
const initializeQuizQuestion = () => {
|
||||||
|
|
@ -280,33 +287,33 @@ const ManageRoom: React.FC = () => {
|
||||||
});
|
});
|
||||||
if (parsedQuestions.length === 0) return null;
|
if (parsedQuestions.length === 0) return null;
|
||||||
|
|
||||||
setQuizQuestions(parsedQuestions);
|
setQuestions(parsedQuestions);
|
||||||
return parsedQuestions;
|
return parsedQuestions;
|
||||||
};
|
};
|
||||||
|
|
||||||
const launchTeacherMode = () => {
|
const launchTeacherMode = () => {
|
||||||
const quizQuestions = initializeQuizQuestion();
|
const questions = initializeQuizQuestion();
|
||||||
console.log('launchTeacherMode - quizQuestions:', quizQuestions);
|
console.log('launchTeacherMode - quizQuestions:', questions);
|
||||||
|
|
||||||
if (!quizQuestions) {
|
if (!questions) {
|
||||||
console.log('Error launching quiz (launchTeacherMode). No questions found.');
|
console.log('Error launching quiz (launchTeacherMode). No questions found.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentQuestion(quizQuestions[0]);
|
updateIndex(0);
|
||||||
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex: 0, isLaunch: true});
|
webSocketService.nextQuestion({roomName: formattedRoomName, questions: questions, questionIndex: 0, isLaunch: true});
|
||||||
};
|
};
|
||||||
|
|
||||||
const launchStudentMode = () => {
|
const launchStudentMode = () => {
|
||||||
const quizQuestions = initializeQuizQuestion();
|
const questions = initializeQuizQuestion();
|
||||||
console.log('launchStudentMode - quizQuestions:', quizQuestions);
|
console.log('launchStudentMode - quizQuestions:', questions);
|
||||||
|
|
||||||
if (!quizQuestions) {
|
if (!questions) {
|
||||||
console.log('Error launching quiz (launchStudentMode). No questions found.');
|
console.log('Error launching quiz (launchStudentMode). No questions found.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setQuizQuestions(quizQuestions);
|
setQuestions(questions);
|
||||||
webSocketService.launchStudentModeQuiz(formattedRoomName, quizQuestions);
|
webSocketService.launchStudentModeQuiz(formattedRoomName, questions);
|
||||||
};
|
};
|
||||||
|
|
||||||
const launchQuiz = () => {
|
const launchQuiz = () => {
|
||||||
|
|
@ -328,10 +335,10 @@ const ManageRoom: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const showSelectedQuestion = (questionIndex: number) => {
|
const showSelectedQuestion = (questionIndex: number) => {
|
||||||
if (quiz?.content && quizQuestions) {
|
if (quiz?.content && questions) {
|
||||||
setCurrentQuestion(quizQuestions[questionIndex]);
|
updateIndex(questionIndex);
|
||||||
if (quizMode === 'teacher') {
|
if (quizMode === 'teacher') {
|
||||||
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex, isLaunch: false});
|
webSocketService.nextQuestion({roomName: formattedRoomName, questions: questions, questionIndex, isLaunch: false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -398,13 +405,13 @@ 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 ? (
|
{questions.length > 0 ? (
|
||||||
<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)) && (
|
{index && (
|
||||||
<strong className="number of questions">
|
<strong className="number of questions">
|
||||||
Question {Number(currentQuestion?.question.id)}/
|
Question {index+1}/
|
||||||
{quizQuestions?.length}
|
{questions?.length}
|
||||||
</strong>
|
</strong>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -421,18 +428,14 @@ 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 && (
|
{index && (
|
||||||
<QuestionDisplay
|
<QuestionDisplay/>
|
||||||
showAnswer={false}
|
|
||||||
question={currentQuestion?.question as Question}
|
|
||||||
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<LiveResultsComponent
|
<LiveResultsComponent
|
||||||
quizMode={quizMode}
|
quizMode={quizMode}
|
||||||
socket={socket}
|
socket={socket}
|
||||||
questions={quizQuestions}
|
questions={questions}
|
||||||
showSelectedQuestion={showSelectedQuestion}
|
showSelectedQuestion={showSelectedQuestion}
|
||||||
students={students}
|
students={students}
|
||||||
></LiveResultsComponent>
|
></LiveResultsComponent>
|
||||||
|
|
@ -448,7 +451,7 @@ const ManageRoom: React.FC = () => {
|
||||||
<Button
|
<Button
|
||||||
onClick={previousQuestion}
|
onClick={previousQuestion}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
disabled={Number(currentQuestion?.question.id) <= 1}
|
disabled={index !== null && index <= 1}
|
||||||
>
|
>
|
||||||
Question précédente
|
Question précédente
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -458,8 +461,8 @@ const ManageRoom: React.FC = () => {
|
||||||
onClick={nextQuestion}
|
onClick={nextQuestion}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
disabled={
|
disabled={
|
||||||
Number(currentQuestion?.question.id) >=
|
index !== null &&
|
||||||
quizQuestions.length
|
index >= questions.length
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Prochaine question
|
Prochaine question
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue