Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions client/src/pages/maker/take_quiz/Question.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
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";
Expand All @@ -14,7 +14,6 @@ const styles = {
}
};


interface QuestionProps {
selectedOptionIDs: string[];
quizItem: QuizItem;
Expand All @@ -37,7 +36,9 @@ export default function Question({
return <a target="_blank" rel="noopener noreferrer"{...props}>{children}</a>;
},
}}
>{quizItem.text}</Markdown>
>{quizItem.type === QuizItemType.Checkboxes
? quizItem.text + ` (Please select ${quizItem?.correctAnswers} choices.)`
: quizItem.text}</Markdown>
</Typography>
{quizItem.options?.map((o) => (
<Option
Expand Down
11 changes: 5 additions & 6 deletions client/src/pages/maker/take_quiz/QuizPage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useQuery } from "@apollo/client";
import { useParams } from "react-router-dom";
import { GET_MODULE } from "../../../queries/trainingQueries";
import { GET_MODULE_ANSWER_COUNT } from "../../../queries/trainingQueries";
import RequestWrapper2 from "../../../common/RequestWrapper2";
import { Module } from "../../../types/Quiz";
import QuizTaker from "./QuizTaker";
import { Stack } from "@mui/system";
import { Typography } from "@mui/material";
Expand Down Expand Up @@ -30,16 +29,16 @@ function _shuffle(array: any[] | undefined) {

export default function QuizPage() {
const { id } = useParams<{ id: string }>();
const result = useQuery(GET_MODULE, { variables: { id } });
const result = useQuery(GET_MODULE_ANSWER_COUNT, { variables: { id } });
const isMobile = useIsMobile();

return (
<RequestWrapper2
result={result}
render={({ module }: { module: Module }) => (
render={(data) => (
<Stack spacing={2} margin={"15px 30px"}>
<Typography variant={isMobile ? "h5" : "h3"}>{module.name}</Typography>
<QuizTaker module={module} />
<Typography variant={isMobile ? "h5" : "h3"}>{data.moduleWithAnswerCount?.name}</Typography>
<QuizTaker module={data?.moduleWithAnswerCount} />
</Stack>
)}
/>
Expand Down
24 changes: 15 additions & 9 deletions client/src/pages/maker/take_quiz/QuizTaker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,13 @@ export default function QuizTaker({ module }: QuizTakerProps) {
.filter((item) => item.type === QuizItemType.MultipleChoice || item.type === QuizItemType.Checkboxes)
.map((item) => ({ itemID: item.id, optionIDs: [] }));

const answerSheetReq = module.quiz
.filter((item) => item.type === QuizItemType.MultipleChoice || item.type === QuizItemType.Checkboxes)
.map((item) => ({itemID: item.id, reqCount: item.correctAnswers}));

const [answerSheet, setAnswerSheet] = useImmer<AnswerSheet>(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) => {
Expand All @@ -100,7 +101,9 @@ export default function QuizTaker({ module }: QuizTakerProps) {
})
setQuizProgressed(true);
};


const checkAllAnswered = (element: any, index: number) => (element.optionIDs.length != answerSheetReq[index].reqCount);

const trainingSubmissionAnimation = () => {
toast.success("Training Module Submitted", {
position: "bottom-left",
Expand Down Expand Up @@ -130,9 +133,12 @@ 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 }],
onCompleted() {navigate(`results`); trainingSubmissionAnimation();}
});

};

const cancelQuiz = async () => {
Expand Down Expand Up @@ -240,7 +246,7 @@ export default function QuizTaker({ module }: QuizTakerProps) {
loading={result.loading}
variant="contained"
sx={{ alignSelf: "flex-end" }}
disabled={module.isLocked ?? false}
disabled={(module.isLocked || (answerSheet.some(checkAllAnswered))) ?? false}
onClick={() => submitAndViewResults()}
>
Submit
Expand Down
13 changes: 13 additions & 0 deletions client/src/queries/trainingQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ export const GET_MODULE_WITH_ANSWERS = gql`
}
`;

export const GET_MODULE_ANSWER_COUNT = gql`
query GetModuleAnswerCount($id: ID!) {
moduleWithAnswerCount(id: $id){
id
name
quiz
reservationPrompt
archived
isLocked
}
}
`;

export const GET_ARCHIVED_MODULE = gql`
query GetArchivedModule($id: ID!) {
archivedModule(id: $id) {
Expand Down
1 change: 1 addition & 0 deletions client/src/types/Quiz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface QuizItem {
type: QuizItemType;
text: string;
options?: Option[];
correctAnswers?: number;
hint?: string;
affirmation?: string;
}
Expand Down
1 change: 1 addition & 0 deletions server/src/db/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@
type: string;
text: string;
options?: ModuleItemOption[];
correctAnswers?: number;
hint: string;
affirmation: string;
}
Expand Down Expand Up @@ -522,16 +523,16 @@
export interface SpecialHoursRow {
day: Date;
makerspaceID: number;
open: String | null;

Check failure on line 526 in server/src/db/tables.ts

View workflow job for this annotation

GitHub Actions / build

Prefer using the primitive `string` as a type name, rather than the upper-cased `String`
close: String | null;

Check failure on line 527 in server/src/db/tables.ts

View workflow job for this annotation

GitHub Actions / build

Prefer using the primitive `string` as a type name, rather than the upper-cased `String`
closed: boolean;
}

export interface DefaultHoursRow {
dayOfWeek: number;
makerspaceID: number;
open: String | null;

Check failure on line 534 in server/src/db/tables.ts

View workflow job for this annotation

GitHub Actions / build

Prefer using the primitive `string` as a type name, rather than the upper-cased `String`
close: String | null;

Check failure on line 535 in server/src/db/tables.ts

View workflow job for this annotation

GitHub Actions / build

Prefer using the primitive `string` as a type name, rather than the upper-cased `String`
closed: boolean;
}

Expand Down
33 changes: 32 additions & 1 deletion server/src/resolvers/trainingModuleResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,20 @@ const removeAnswersFromQuiz = (quiz: TrainingModuleItem[]) => {
}
};

function countQuizCorrectOptions(quiz: TrainingModuleItem[]){
for (const item of quiz) {
if(item.options){
var count = 0;
for (const option of item.options) {
if(option.correct == true){
count++;
}
}
item.correctAnswers = count;
}
}
}

/**
* Determine if an array of submitted options for a question is correct
* @param correct array of correct option IDs
Expand Down Expand Up @@ -219,6 +233,24 @@ const TrainingModuleResolvers = {
})
},

/**
* Finds a module based id of item. No restrictions on user. Only returns # of correct answers for options
* @argument id ID of TrainingModule
* @argument itemID id of item within TrainingModule
* @returns number of correct answers for a question
*/
moduleWithAnswerCount: async (
_parent: any,
args: { id: number, itemID: string },
{ ifAuthenticated }: ApolloContext
) => {
return ifAuthenticated(async (_user: any) => {
const module = await ModuleRepo.getModuleByID(args.id);
countQuizCorrectOptions(module.quiz)
return module;
})
},

/**
* Fetch all archived TrainingModules
* @returns TrainingModule
Expand Down Expand Up @@ -478,7 +510,6 @@ const TrainingModuleResolvers = {
(item) => item.itemID === question.id
)?.optionIDs;


//Increment correcct if submitted options match correct options (order doesn't matter)
//Increment incorrect otherwise
if (submittedOptionIDsCorrect(correctOptionIDs, submittedOptionIDs)) {
Expand Down
1 change: 1 addition & 0 deletions server/src/schemas/trainingModuleSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const TrainingModuleTypeDefs = gql`
modulesWithAnswers: [TrainingModule]
module(id: ID!): TrainingModule
moduleWithAnswers(id: ID!): TrainingModule
moduleWithAnswerCount(id: ID!): TrainingModule
archivedModules: [TrainingModule]
archivedModule(id: ID!): TrainingModule
relatedAccessProgress(sourceTrainingModuleID: ID!): [AccessProgress]
Expand Down
Loading