From 3b93f86524a125bf545a28062be18b964e4f83d3 Mon Sep 17 00:00:00 2001 From: Yi Xhan Date: Fri, 14 Nov 2025 13:38:40 -0500 Subject: [PATCH 1/6] can't submit training without answering all questions, might change display of error and account for other errors --- client/src/pages/maker/take_quiz/QuizTaker.tsx | 17 ++++++++++------- server/src/resolvers/trainingModuleResolver.ts | 6 ++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/client/src/pages/maker/take_quiz/QuizTaker.tsx b/client/src/pages/maker/take_quiz/QuizTaker.tsx index 8edcc6f9..69b9b561 100644 --- a/client/src/pages/maker/take_quiz/QuizTaker.tsx +++ b/client/src/pages/maker/take_quiz/QuizTaker.tsx @@ -72,10 +72,7 @@ export default function QuizTaker({ module }: QuizTakerProps) { const [answerSheet, setAnswerSheet] = useImmer(initialAnswerSheet); - const [submitModule, result] = useMutation(SUBMIT_MODULE, { - variables: { moduleID: module.id, answerSheet }, - refetchQueries: [{ query: GET_CURRENT_USER }, { query: GET_TRAINING_MODULES }], - }); + const [submitModule, result] = useMutation(SUBMIT_MODULE); const selectMultipleChoiceOption = (itemID: string, optionID: string) => { setAnswerSheet((draft) => { @@ -130,9 +127,15 @@ export default function QuizTaker({ module }: QuizTakerProps) { const navigate = useNavigate(); const submitAndViewResults = async () => { - await submitModule(); - navigate(`results`); - trainingSubmissionAnimation(); + await submitModule({ + variables: { moduleID: module.id, answerSheet }, + refetchQueries: [{ query: GET_CURRENT_USER }, { query: GET_TRAINING_MODULES }], + onError (error){ + toast.error(`Failed to submit: ${error.message}`); + }, + onCompleted: (results) => {navigate(`results`); trainingSubmissionAnimation();} + }); + }; const cancelQuiz = async () => { diff --git a/server/src/resolvers/trainingModuleResolver.ts b/server/src/resolvers/trainingModuleResolver.ts index c8ac2c71..d30a2875 100644 --- a/server/src/resolvers/trainingModuleResolver.ts +++ b/server/src/resolvers/trainingModuleResolver.ts @@ -478,6 +478,12 @@ const TrainingModuleResolvers = { (item) => item.itemID === question.id )?.optionIDs; + //Stop if user hasn't answered all questions + if(correctOptionIDs.length !== submittedOptionIDs?.length || submittedOptionIDs == null){ + throw Error( + 'You have not answered all questions. Please try again.' + ) + } //Increment correcct if submitted options match correct options (order doesn't matter) //Increment incorrect otherwise From 311fe0e3cb73f041a1909b9813cce41f4037d350 Mon Sep 17 00:00:00 2001 From: Yi Xhan Date: Mon, 17 Nov 2025 17:48:58 -0500 Subject: [PATCH 2/6] display # of correct options, not gonna tell them how many they get right before submitting that doesn't seem like a good idea --- client/src/pages/maker/take_quiz/Question.tsx | 19 +++++++++-- .../src/pages/maker/take_quiz/QuizTaker.tsx | 4 ++- .../src/resolvers/trainingModuleResolver.ts | 32 +++++++++++++++++++ server/src/schemas/trainingModuleSchema.ts | 5 +++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/client/src/pages/maker/take_quiz/Question.tsx b/client/src/pages/maker/take_quiz/Question.tsx index 1ea757d9..92549f87 100644 --- a/client/src/pages/maker/take_quiz/Question.tsx +++ b/client/src/pages/maker/take_quiz/Question.tsx @@ -1,7 +1,9 @@ -import { QuizItem } from "../../../types/Quiz"; +import { QuizItem, QuizItemType } from "../../../types/Quiz"; import { Card, Typography } from "@mui/material"; import Option from "./Option"; import Markdown from "react-markdown"; +import gql from "graphql-tag"; +import { useQuery } from "@apollo/client"; const styles = { strongerBolds: { @@ -14,8 +16,16 @@ const styles = { } }; +const GET_CORRECT_ANSWER_COUNT = gql` + query GetModuleQuestionAnswerCount($id: ID!, $itemID: String!) { + moduleQuestionAnswerCount(id: $id, itemID: $itemID){ + count + } + } +`; interface QuestionProps { + moduleID: number; selectedOptionIDs: string[]; quizItem: QuizItem; onClick: (optionID: string) => void; @@ -23,11 +33,14 @@ interface QuestionProps { } export default function Question({ + moduleID, selectedOptionIDs, quizItem, onClick, disabled }: QuestionProps) { + const correctAnswerCount = useQuery(GET_CORRECT_ANSWER_COUNT, {variables: {id:moduleID, itemID: quizItem.id}}) + return ( @@ -37,7 +50,9 @@ export default function Question({ return {children}; }, }} - >{quizItem.text} + >{quizItem.type === QuizItemType.Checkboxes + ? quizItem.text + ` (Please select ${correctAnswerCount.data?.moduleQuestionAnswerCount.count} choices.)` + : quizItem.text} {quizItem.options?.map((o) => (