Skip to content

Commit

Permalink
refactor: replace custom logic with react-hook-form (#345)
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-pajak authored Jan 9, 2025
1 parent 97f9c90 commit 898a993
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 102 deletions.
Original file line number Diff line number Diff line change
@@ -1,85 +1,21 @@
import { useState } from "react";

import Viewer from "~/components/RichText/Viever";
import { Card } from "~/components/ui/card";
import { FillInTheTextBlanks } from "~/modules/Courses/Lesson/Question/FillInTheBlanks/FillInTheTextBlanks";
import { TextBlank } from "~/modules/Courses/Lesson/Question/FillInTheBlanks/TextBlank";
import { handleCompletionForMediaLesson } from "~/utils/handleCompletionForMediaLesson";

import type { QuizQuestion } from "~/modules/Courses/Lesson/Question/types";
import { FillInTheTextBlanks } from "./FillInTheTextBlanks";
import { TextBlank } from "./TextBlank";

type Answer = {
id: string;
optionText: string;
displayOrder: number | null;
isStudentAnswer?: boolean | null;
isCorrect?: boolean | null;
studentAnswerText?: string | null;
};
import type { QuizQuestion } from "../types";

type FillInTheBlanksProps = {
question: QuizQuestion;
isQuizSubmitted?: boolean;
lessonItemId: string;
isCompleted: boolean;
};

type Word = {
index: number | null;
value: string | null;
};

export const FillInTheBlanks = ({
question,
isQuizSubmitted,
isCompleted,
}: FillInTheBlanksProps) => {
const [_words, setWords] = useState<Word[]>(
question.options!.map(({ displayOrder, studentAnswer }) => ({
index: displayOrder,
value: studentAnswer,
})),
);

if (!question.description || !question.options?.length) return null;

export const FillInTheBlanks = ({ question, isCompleted }: FillInTheBlanksProps) => {
const solutionExplanation =
"solutionExplanation" in question ? (question.solutionExplanation as string) : null;

const maxAnswersAmount = question.description?.match(/\[word]/g)?.length ?? 0;
const handleWordUpdate = (prevWords: Word[], index: number, value: string) => {
const trimmedValue = value.trim();
const existingWordIndex = prevWords.findIndex((word) => word.index === index);

let updatedWords = prevWords;

if (trimmedValue === "") {
updatedWords =
existingWordIndex !== -1 ? prevWords.filter((word) => word.index !== index) : prevWords;
} else if (existingWordIndex !== -1) {
updatedWords = [...prevWords];
updatedWords[existingWordIndex] = { index, value: trimmedValue };
} else if (prevWords.length < maxAnswersAmount) {
updatedWords = [...prevWords, { index, value: trimmedValue }];
}

const sortedWords = updatedWords.sort((a, b) => a.index - b.index);

if (sortedWords.length > 0 && sortedWords.length <= maxAnswersAmount) {
if (
handleCompletionForMediaLesson(isCompleted, true) &&
sortedWords.length === maxAnswersAmount
) {
// TODO: handle completion
}
}

return updatedWords;
};

const handleOnBlur = (value: string, index: number) => {
setWords((prev) => handleWordUpdate(prev, index, value));
};
if (!question.description) return null;

return (
<Card className="flex flex-col gap-4 p-8 border-none drop-shadow-primary">
Expand All @@ -90,15 +26,15 @@ export const FillInTheBlanks = ({
replacement={(index) => {
return (
<TextBlank
questionId={question.id}
studentAnswer={question.options?.[index]}
index={index}
handleOnBlur={handleOnBlur}
isQuizSubmitted={isQuizSubmitted}
isQuizSubmitted={isCompleted}
/>
);
}}
/>
{!!solutionExplanation && !question.passQuestion && (
{isCompleted && !!solutionExplanation && question.passQuestion && (
<div>
<span className="body-base-md text-error-700">Correct sentence:</span>
<Viewer content={solutionExplanation} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
import { useEffect, useRef } from "react";
import { useFormContext } from "react-hook-form";

import { cn } from "~/lib/utils";

import type { QuizQuestionOption } from "../types";
import type { TQuestionsForm } from "~/modules/Courses/Lesson/types";

type TextBlankProps = {
index: number;
studentAnswer?: {
id: string;
optionText: string;
displayOrder: number | null;
isStudentAnswer?: boolean | null;
isCorrect?: boolean | null;
studentAnswerText?: string | null;
};
handleOnBlur: (value: string, index: number) => void;
studentAnswer?: QuizQuestionOption;
isQuizSubmitted?: boolean;
questionId: string;
};

export const TextBlank = ({
index,
studentAnswer,
handleOnBlur,
isQuizSubmitted,
questionId,
}: TextBlankProps) => {
const { register } = useFormContext<TQuestionsForm>();
const inputRef = useRef<HTMLInputElement>(null);
const formFieldId = `${index + 1}`;

useEffect(() => {
if (!inputRef?.current) return;

if (isQuizSubmitted) {
inputRef.current.value = studentAnswer?.studentAnswerText ?? "";
inputRef.current.value = studentAnswer?.studentAnswer ?? "";
} else {
inputRef.current.value = "";
}
Expand All @@ -51,18 +50,11 @@ export const TextBlank = ({

return (
<input
ref={inputRef}
key={index}
type="text"
className={textBlankClasses}
disabled={!!isDisabled}
{...(!isDisabled && {
onBlur: (e) => {
const value = e.target.value;

handleOnBlur(value, index);
},
})}
{...register(`fillInTheBlanksText.${questionId}.${formFieldId}`)}
/>
);
};
10 changes: 2 additions & 8 deletions apps/web/app/modules/Courses/Lesson/Question/Question.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,7 @@ export const Question = ({ isSubmitted, question, isCompleted }: QuestionProps)
return <DetailedResponse question={question} />;

case isTextFillInTheBlanks:
return (
<FillInTheBlanks
question={question}
isQuizSubmitted={isSubmitted}
lessonItemId={questionId}
isCompleted={isCompleted}
/>
);
return <FillInTheBlanks question={question} isCompleted={isCompleted} />;

case isDraggableFillInTheBlanks:
return (
Expand All @@ -94,6 +87,7 @@ export const Question = ({ isSubmitted, question, isCompleted }: QuestionProps)
updateLessonItemCompletion={() => {}}
/>
);

case isSingleQuestion:
return <SingleChoice question={question} isQuizCompleted={true} />;

Expand Down
26 changes: 23 additions & 3 deletions apps/web/app/modules/Courses/Lesson/Quiz.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useParams } from "@remix-run/react";
import { useNavigate, useParams } from "@remix-run/react";
import { FormProvider, useForm } from "react-hook-form";

import { useSubmitQuiz } from "~/api/mutations";
Expand Down Expand Up @@ -95,6 +95,25 @@ function transformData(input: TQuestionsForm) {
}
}

for (const questionId in input.fillInTheBlanksText) {
const answers = input.fillInTheBlanksText[questionId];
const answerArray = [];

for (const [key, value] of Object.entries(answers)) {
if (answers[key]) {
answerArray.push({
value,
});
}
}
if (answerArray.length > 0) {
result.push({
questionId: questionId,
answer: answerArray,
});
}
}

for (const questionId in input.photoQuestionMultipleChoice) {
const answers = input.photoQuestionMultipleChoice[questionId];
const answerArray = [];
Expand Down Expand Up @@ -140,7 +159,8 @@ function transformData(input: TQuestionsForm) {
}

export const Quiz = ({ lesson }: QuizProps) => {
const { lessonId = "" } = useParams();
const { lessonId = "", courseId = "" } = useParams();
const navigate = useNavigate();

const questions = lesson.quizDetails?.questions;

Expand All @@ -151,7 +171,7 @@ export const Quiz = ({ lesson }: QuizProps) => {

const submitQuiz = useSubmitQuiz({
handleOnSuccess: () => {
// TODO: Add logic to handle success
navigate(`/course/${courseId}/lesson/${lesson.nextLessonId}`);
},
});

Expand Down
5 changes: 5 additions & 0 deletions apps/web/app/modules/Courses/Lesson/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@ export type TQuestionsForm = {
[key: string]: string | null;
};
};
fillInTheBlanksText: {
[key: string]: {
[key: string]: string | null;
};
};
};
6 changes: 6 additions & 0 deletions apps/web/app/modules/Courses/Lesson/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ const prepareAnswers = (questions: Questions, mode: "options" | "open"): Record<
);
}

if (question.type === "fill_in_the_blanks_text") {
result[question.id ?? ""] = question?.options?.map(({ studentAnswer }, index) => {
return { [`${index + 1}`]: studentAnswer ?? null };
});
}

if (mode === "options") {
result[question.id ?? ""] = question?.options?.reduce(
(optionMap, option) => {
Expand Down

0 comments on commit 898a993

Please sign in to comment.