diff --git a/frontend/src/components/question/QuestionForm.tsx b/frontend/src/components/question/QuestionForm.tsx new file mode 100644 index 0000000..c276bbb --- /dev/null +++ b/frontend/src/components/question/QuestionForm.tsx @@ -0,0 +1,136 @@ +import type { QuizQuestion } from '../../model/quiz-question.ts' +import { type Accessor, type Component, createMemo, createSignal, For, Show } from 'solid-js' +import { preventDefault } from '../../helpers.ts' +import * as QuestionService from '../../services/QuizQuestionService.ts' +import { isMultipleAnswersCorrect, type MultipleAnswerResult } from '../../services/QuizQuestionService.ts' +import { transformObjectToArray } from '../../utils/transformObjectToArray.ts' +import { Explanation, QuestionExplanation } from './explanation/Explanation.tsx' +import { Feedback } from './feedback/Feedback.tsx' + +export const QuestionForm = ({ + id, + question, + answers, + explanations, + correctAnswers, + questionExplanation, +}: QuizQuestion) => { + const [selectedAnswer, setSelectedAnswer] = createSignal(null) + const [selectedAnswers, setSelectedAnswers] = createSignal<{ [key: string]: boolean } | Record>({}) + const [isAnswerCorrect, setIsAnswerCorrect] = createSignal(false) + //const [setExplanation] = createSignal('') + const [explanationIdx, setExplanationIdx] = createSignal(null) + const [answersRequiringFeedback, setAnswersRequiringFeedback] = createSignal([]) + + const [submitted, setSubmitted] = createSignal(false) + + const isMultiple = correctAnswers.length > 1 + + const submit = preventDefault(async () => { + const selectedAnswerIdx = selectedAnswer() + if (selectedAnswerIdx === null) return + QuestionService.isAnswerCorrect(id, selectedAnswerIdx).then(isCorrect => { + setSubmitted(true) + setIsAnswerCorrect(isCorrect) + //setExplanation(explanations[selectedAnswerIdx]) + setExplanationIdx(selectedAnswerIdx) + }) + }) + + const submitMultiple = preventDefault(async () => { + if (Object.keys(selectedAnswers()).length === 0) return + + const payload = transformObjectToArray(selectedAnswers()) + + isMultipleAnswersCorrect(id, payload).then((result: MultipleAnswerResult) => { + setSubmitted(true) + + setIsAnswerCorrect(result.questionAnsweredCorrectly) + setAnswersRequiringFeedback(result.answersRequiringFeedback) + }) + }) + + const selectAnswer = (answerIdx: number) => () => { + setSelectedAnswer(answerIdx) + } + + const handleCheckboxChange = (event: InputEvent) => { + const { name, checked } = event.target as HTMLInputElement + setSelectedAnswers(prevState => ({ + ...prevState, + [name]: checked, + })) + } + + type AnswerProps = { + answer: string // Adjust type based on the actual answer object + idx: number + explanation: string + isFeedbackRequired: Accessor + } + + const Answer: Component = ({ answer, idx, explanation, isFeedbackRequired }) => { + const answerId: string = `answer-${idx}` + + if (isMultiple) { + return ( +
  • + + +
  • + ) + } + + return ( +
  • + + +
  • + ) + } + + return ( +
    +

    {question}

    +
      + + {(answer, idx) => { + const isFeedbackRequired = createMemo(() => answersRequiringFeedback().some(id => id === idx())) + return ( + + ) + }} + +
    + + + + + ) +} diff --git a/frontend/src/components/question/explanation/Explanation.tsx b/frontend/src/components/question/explanation/Explanation.tsx new file mode 100644 index 0000000..a5fb80c --- /dev/null +++ b/frontend/src/components/question/explanation/Explanation.tsx @@ -0,0 +1,14 @@ +export const Explanation = (correct: boolean, explanation: string) => { + return ( + + {' '} + {correct ? 'Correct!' : 'Incorrect!'}
    + {'Explanation: '} + {explanation} +
    + ) +} + +export const QuestionExplanation = (questionExplanation: string) => ( +

    {questionExplanation}

    +) diff --git a/frontend/src/components/question/feedback/Feedback.tsx b/frontend/src/components/question/feedback/Feedback.tsx new file mode 100644 index 0000000..4b7b97f --- /dev/null +++ b/frontend/src/components/question/feedback/Feedback.tsx @@ -0,0 +1 @@ +export const Feedback = (correct: boolean) => diff --git a/frontend/src/components/question/questionForm.css b/frontend/src/components/question/questionForm.css new file mode 100644 index 0000000..fa282f7 --- /dev/null +++ b/frontend/src/components/question/questionForm.css @@ -0,0 +1,25 @@ +ul { + list-style-type: none; + padding: 0; + margin: 1em 0; + + li input[type="radio"] { + margin-right: 0.5em; + } +} + +.explanation { + color: dodgerblue; +} + +.greenSpan { + color: green; +} + +.redSpan { + color: red; +} + +.debugBorder { + border: 1px solid red; +} diff --git a/frontend/src/quiz.tsx b/frontend/src/quiz.tsx index 5dcff54..eff9c45 100644 --- a/frontend/src/quiz.tsx +++ b/frontend/src/quiz.tsx @@ -1,149 +1,11 @@ import './quiz.scss' -import { type Component, createSignal, For, onMount, Show, type Accessor, createMemo } from 'solid-js' +import { createSignal, onMount, Show } from 'solid-js' import { useParams } from '@solidjs/router' import type { QuizQuestion } from 'model/quiz-question.ts' -import { preventDefault } from 'helpers.ts' -import { transformObjectToArray } from './utils/transformObjectToArray.ts' -import { getQuestion, isMultipleAnswersCorrect, type MultipleAnswerResult } from './services/QuizQuestionService.ts' -import * as QuestionService from './services/QuizQuestionService.ts' - -const Feedback = (correct: boolean) => - -const Explanation = (correct: boolean, explanation: string) => { - return ( - - {' '} - {correct ? 'Correct!' : 'Incorrect!'}
    - {'Explanation: '} - {explanation} -
    - ) -} - -const QuestionExplanation = (questionExplanation: string) =>

    {questionExplanation}

    - -const Question = ({ id, question, answers, explanations, correctAnswers, questionExplanation }: QuizQuestion) => { - const [selectedAnswer, setSelectedAnswer] = createSignal(null) - const [selectedAnswers, setSelectedAnswers] = createSignal<{ [key: string]: boolean } | Record>({}) - const [isAnswerCorrect, setIsAnswerCorrect] = createSignal(false) - //const [setExplanation] = createSignal('') - const [explanationIdx, setExplanationIdx] = createSignal(null) - const [answersRequiringFeedback, setAnswersRequiringFeedback] = createSignal([]) - - const [submitted, setSubmitted] = createSignal(false) - - const isMultiple = correctAnswers.length > 1 - - const submit = preventDefault(async () => { - const selectedAnswerIdx = selectedAnswer() - if (selectedAnswerIdx === null) return - QuestionService.isAnswerCorrect(id, selectedAnswerIdx).then(isCorrect => { - setSubmitted(true) - setIsAnswerCorrect(isCorrect) - //setExplanation(explanations[selectedAnswerIdx]) - setExplanationIdx(selectedAnswerIdx) - }) - }) - - const submitMultiple = preventDefault(async () => { - if (Object.keys(selectedAnswers()).length === 0) return - - const payload = transformObjectToArray(selectedAnswers()) - - isMultipleAnswersCorrect(id, payload).then((result: MultipleAnswerResult) => { - setSubmitted(true) - - setIsAnswerCorrect(result.questionAnsweredCorrectly) - setAnswersRequiringFeedback(result.answersRequiringFeedback) - }) - }) - - const selectAnswer = (answerIdx: number) => () => { - setSelectedAnswer(answerIdx) - } - - const handleCheckboxChange = (event: InputEvent) => { - const { name, checked } = event.target as HTMLInputElement - setSelectedAnswers(prevState => ({ - ...prevState, - [name]: checked, - })) - } - - type AnswerProps = { - answer: string // Adjust type based on the actual answer object - idx: number - explanation: string - isFeedbackRequired: Accessor - } - - const Answer: Component = ({ answer, idx, explanation, isFeedbackRequired }) => { - const answerId: string = `answer-${idx}` - - if (isMultiple) { - return ( -
  • - - -
  • - ) - } - - return ( -
  • - - -
  • - ) - } - - return ( -
    -

    {question}

    -
      - - {(answer, idx) => { - const isFeedbackRequired = createMemo(() => answersRequiringFeedback().some(id => id === idx())) - return ( - - ) - }} - -
    - - - - - ) -} +import { getQuestion } from './services/QuizQuestionService.ts' +import { QuestionForm } from './components/question/QuestionForm.tsx' export const Quiz = () => { const params = useParams() @@ -153,5 +15,5 @@ export const Quiz = () => { onMount(async () => setQuizQuestion(await getQuestion(questionId))) - return + return }