From a325598d70b81f7d99eafe3d5adb4da794f35e91 Mon Sep 17 00:00:00 2001 From: d471061c Date: Fri, 4 Aug 2023 09:25:53 +0300 Subject: [PATCH] fix exercise validation in quizzes --- services/quizzes/src/components/AnswerExercise.tsx | 7 +++++++ services/quizzes/src/components/ExerciseEditor.tsx | 1 + .../quizzes/src/components/widget/ClosedEndedQuestion.tsx | 4 ++-- services/quizzes/src/components/widget/Matrix/Matrix.tsx | 7 +------ .../src/contexts/QuizzesExerciseServiceContext.tsx | 2 +- .../quizzes/src/contexts/QuizzesUserItemAnswerContext.tsx | 2 +- shared-module/src/contexts/ExerciseServiceContext.tsx | 6 +++++- .../useExerciseServiceOutputState.tsx | 8 ++++++-- 8 files changed, 24 insertions(+), 13 deletions(-) diff --git a/services/quizzes/src/components/AnswerExercise.tsx b/services/quizzes/src/components/AnswerExercise.tsx index 76c38b846e2c..4ec82e1b4fb7 100644 --- a/services/quizzes/src/components/AnswerExercise.tsx +++ b/services/quizzes/src/components/AnswerExercise.tsx @@ -37,6 +37,13 @@ const Exercise: React.FC> = ({ outputState: userAnswer, port: port, _rawSetOutputState: setUserAnswer, + validate: (previousState) => { + if (!previousState) { + return false + } + const validities = previousState.itemAnswers.map((item) => item.valid) + return validities.every(Boolean) + }, }} > > = ({ port, priv outputState, port: port, _rawSetOutputState: setOutputState, + validate: () => true, }} > diff --git a/services/quizzes/src/components/widget/ClosedEndedQuestion.tsx b/services/quizzes/src/components/widget/ClosedEndedQuestion.tsx index 783bd51a425c..cce77fdbee24 100644 --- a/services/quizzes/src/components/widget/ClosedEndedQuestion.tsx +++ b/services/quizzes/src/components/widget/ClosedEndedQuestion.tsx @@ -24,13 +24,13 @@ const ClosedEndedQuestion: React.FC< quizItemId: quizItem.id, type: "closed-ended-question", textData: newValue, - valid: true, + valid: newValue.length > 0, }) return } if (!quizItem.formatRegex) { - return setQuizItemAnswerState({ ...quizItemAnswerState, textData: newValue, valid: true }) + return setQuizItemAnswerState({ ...quizItemAnswerState, textData: newValue, valid: false }) } const newValueIsValid = newValue diff --git a/services/quizzes/src/components/widget/Matrix/Matrix.tsx b/services/quizzes/src/components/widget/Matrix/Matrix.tsx index 3e809ea99ba4..f9f601455405 100644 --- a/services/quizzes/src/components/widget/Matrix/Matrix.tsx +++ b/services/quizzes/src/components/widget/Matrix/Matrix.tsx @@ -76,9 +76,6 @@ const Matrix: React.FunctionComponent< handleSizeChange(matrixVariable) }, [handleSizeChange, matrixVariable]) - if (!quizItemAnswerState) { - return
- } const handleOptionSelect = (text: string, column: number, row: number) => { const newMatrix = matrixVariable.map((rowArray, rowIndex) => { return rowArray.map((cell, columnIndex) => { @@ -148,9 +145,7 @@ const Matrix: React.FunctionComponent< cellText={cellText} handleOptionSelect={handleOptionSelect} matrixSize={matrixActiveSize} - > - {" "} - + > ) } })} diff --git a/services/quizzes/src/contexts/QuizzesExerciseServiceContext.tsx b/services/quizzes/src/contexts/QuizzesExerciseServiceContext.tsx index 5eea64b6bf2d..32760eada2c6 100644 --- a/services/quizzes/src/contexts/QuizzesExerciseServiceContext.tsx +++ b/services/quizzes/src/contexts/QuizzesExerciseServiceContext.tsx @@ -1,6 +1,6 @@ import { PrivateSpecQuiz } from "../../types/quizTypes/privateSpec" import { createExerciseServiceContext } from "../shared-module/contexts/ExerciseServiceContext" -const QuizzesExerciseServiceContext = createExerciseServiceContext() +const QuizzesExerciseServiceContext = createExerciseServiceContext(() => false) export default QuizzesExerciseServiceContext diff --git a/services/quizzes/src/contexts/QuizzesUserItemAnswerContext.tsx b/services/quizzes/src/contexts/QuizzesUserItemAnswerContext.tsx index de458213aa4f..f8b8091f261a 100644 --- a/services/quizzes/src/contexts/QuizzesUserItemAnswerContext.tsx +++ b/services/quizzes/src/contexts/QuizzesUserItemAnswerContext.tsx @@ -1,6 +1,6 @@ import { UserAnswer } from "../../types/quizTypes/answer" import { createExerciseServiceContext } from "../shared-module/contexts/ExerciseServiceContext" -const QuizzesUserItemAnswerContext = createExerciseServiceContext() +const QuizzesUserItemAnswerContext = createExerciseServiceContext(() => false) export default QuizzesUserItemAnswerContext diff --git a/shared-module/src/contexts/ExerciseServiceContext.tsx b/shared-module/src/contexts/ExerciseServiceContext.tsx index f902d42bc88b..6536d4c97c29 100644 --- a/shared-module/src/contexts/ExerciseServiceContext.tsx +++ b/shared-module/src/contexts/ExerciseServiceContext.tsx @@ -3,16 +3,20 @@ import React from "react" interface ExerciseServiceContextProps { outputState: T | null port: MessagePort | null + validate: (newState: T | null) => boolean _rawSetOutputState: (newValue: T | null) => void } -export const createExerciseServiceContext = () => { +export const createExerciseServiceContext = ( + validate: (newState: OutputType | null) => boolean, +) => { return React.createContext>({ outputState: null, port: null, _rawSetOutputState: () => { /* NOP */ }, + validate, }) } diff --git a/shared-module/src/hooks/exerciseServiceHooks/useExerciseServiceOutputState.tsx b/shared-module/src/hooks/exerciseServiceHooks/useExerciseServiceOutputState.tsx index 460e8ff0f76d..b8ddfea9731f 100644 --- a/shared-module/src/hooks/exerciseServiceHooks/useExerciseServiceOutputState.tsx +++ b/shared-module/src/hooks/exerciseServiceHooks/useExerciseServiceOutputState.tsx @@ -15,13 +15,17 @@ const useExerciseServiceOutputState = ( context: ExerciseServiceContextType, selector: (arg: OutputType | null) => SelectorReturnType | null, ): UseExerciseServiceOutputStateReturn => { - const { outputState, port, _rawSetOutputState } = useContext(context) + const { outputState, port, _rawSetOutputState, validate } = useContext(context) const updateState = (func: UpdateFunction) => { if (!port) { return } + if (!validate) { + return + } + const nextState = produce(outputState, (draft) => { const selected = selector(draft as OutputType) // Selected is a draft too because it is a subset of the draft variable @@ -32,7 +36,7 @@ const useExerciseServiceOutputState = ( data: nextState, // eslint-disable-next-line i18next/no-literal-string message: "current-state", - valid: true, + valid: validate(nextState), } port.postMessage(message) _rawSetOutputState(nextState)