Added a diff viewer for the writing correction
This commit is contained in:
@@ -6,37 +6,11 @@ import Button from "../Low/Button";
|
||||
import {Dialog, Tab, Transition} from "@headlessui/react";
|
||||
import {writingReverseMarking} from "@/utils/score";
|
||||
import clsx from "clsx";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
import ReactDiffViewer, {DiffMethod} from "react-diff-viewer";
|
||||
|
||||
export default function Writing({id, type, prompt, attachment, userSolutions, onNext, onBack}: WritingExercise & CommonProps) {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
const formatSolution = (solution: string, errors: {correction: string | null; misspelled: string}[]) => {
|
||||
const misspelled = errors.map((x) => x.misspelled);
|
||||
console.log({misspelled});
|
||||
const errorRegex = new RegExp(errors.map((x) => `(${x.misspelled})`).join("|"), "g");
|
||||
console.log(errorRegex.global);
|
||||
|
||||
return (
|
||||
<>
|
||||
{solution.split(" ").map((word) => {
|
||||
if (!misspelled.includes(word)) return <>{word} </>;
|
||||
|
||||
const correction = errors.find((x) => x.misspelled === word)?.correction;
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
key={word}
|
||||
data-tip={correction ? correction : undefined}
|
||||
className={clsx("text-mti-red-light font-medium underline underline-offset-2", correction && "tooltip")}>
|
||||
{word}
|
||||
</span>{" "}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
const [showDiff, setShowDiff] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -93,16 +67,51 @@ export default function Writing({id, type, prompt, attachment, userSolutions, on
|
||||
|
||||
<div className="w-full h-full flex flex-col gap-8">
|
||||
{userSolutions && userSolutions.length > 0 && (
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<span>Your answer:</span>
|
||||
<div className="w-full h-full min-h-[320px] cursor-text px-7 py-8 input border-2 border-mti-gray-platinum bg-white rounded-3xl whitespace-pre-wrap">
|
||||
{userSolutions[0]!.evaluation && userSolutions[0]!.evaluation.misspelled_pairs
|
||||
? formatSolution(
|
||||
userSolutions[0]!.solution.replaceAll("\\n", "\n"),
|
||||
userSolutions[0]!.evaluation.misspelled_pairs,
|
||||
)
|
||||
: userSolutions[0]!.solution.replaceAll("\\n", "\n")}
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 w-full relative">
|
||||
{!showDiff && (
|
||||
<>
|
||||
<span>Your answer:</span>
|
||||
<div className="w-full h-full min-h-[320px] cursor-text px-7 py-8 input border-2 border-mti-gray-platinum bg-white rounded-3xl whitespace-pre-wrap">
|
||||
{userSolutions[0]!.solution.replaceAll("\\n", "\n")}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{showDiff && (
|
||||
<>
|
||||
<span>Correction:</span>
|
||||
<div className="w-full h-full max-h-[320px] overflow-y-scroll scrollbar-hide cursor-text border-2 overflow-x-hidden border-mti-gray-platinum bg-white rounded-3xl">
|
||||
<ReactDiffViewer
|
||||
styles={{
|
||||
contentText: {
|
||||
fontFamily: '"Open Sans", system-ui, -apple-system, "Helvetica Neue", sans-serif',
|
||||
padding: "32px 28px",
|
||||
},
|
||||
marker: {display: "none"},
|
||||
diffRemoved: {padding: "32px 28px"},
|
||||
diffAdded: {padding: "32px 28px"},
|
||||
|
||||
wordRemoved: {padding: "0px", display: "initial"},
|
||||
wordAdded: {padding: "0px", display: "initial"},
|
||||
wordDiff: {padding: "0px", display: "initial"},
|
||||
}}
|
||||
oldValue={userSolutions[0].solution.replaceAll("\\n", "\n")}
|
||||
newValue={userSolutions[0].evaluation!.fixed_text!.replaceAll("\\n", "\n")}
|
||||
splitView
|
||||
hideLineNumbers
|
||||
showDiffOnly={false}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{userSolutions[0].solution && userSolutions[0].evaluation?.fixed_text && (
|
||||
<Button
|
||||
color="green"
|
||||
variant="outline"
|
||||
className="w-full max-w-[200px] self-end absolute -top-4 right-0 !py-2"
|
||||
onClick={() => setShowDiff((prev) => !prev)}>
|
||||
{showDiff ? "View answer" : "View correction"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{userSolutions && userSolutions.length > 0 && userSolutions[0].evaluation && typeof userSolutions[0].evaluation !== "string" && (
|
||||
|
||||
@@ -30,20 +30,28 @@ export interface CommonProps {
|
||||
export const renderSolution = (exercise: Exercise, onNext: () => void, onBack: () => void, updateIndex?: (internalIndex: number) => void) => {
|
||||
switch (exercise.type) {
|
||||
case "fillBlanks":
|
||||
return <FillBlanks {...(exercise as FillBlanksExercise)} onNext={onNext} onBack={onBack} />;
|
||||
return <FillBlanks key={exercise.id} {...(exercise as FillBlanksExercise)} onNext={onNext} onBack={onBack} />;
|
||||
case "trueFalse":
|
||||
return <TrueFalseSolution {...(exercise as TrueFalseExercise)} onNext={onNext} onBack={onBack} />;
|
||||
return <TrueFalseSolution key={exercise.id} {...(exercise as TrueFalseExercise)} onNext={onNext} onBack={onBack} />;
|
||||
case "matchSentences":
|
||||
return <MatchSentences {...(exercise as MatchSentencesExercise)} onNext={onNext} onBack={onBack} />;
|
||||
return <MatchSentences key={exercise.id} {...(exercise as MatchSentencesExercise)} onNext={onNext} onBack={onBack} />;
|
||||
case "multipleChoice":
|
||||
return <MultipleChoice {...(exercise as MultipleChoiceExercise)} updateIndex={updateIndex} onNext={onNext} onBack={onBack} />;
|
||||
return (
|
||||
<MultipleChoice
|
||||
key={exercise.id}
|
||||
{...(exercise as MultipleChoiceExercise)}
|
||||
updateIndex={updateIndex}
|
||||
onNext={onNext}
|
||||
onBack={onBack}
|
||||
/>
|
||||
);
|
||||
case "writeBlanks":
|
||||
return <WriteBlanks {...(exercise as WriteBlanksExercise)} onNext={onNext} onBack={onBack} />;
|
||||
return <WriteBlanks key={exercise.id} {...(exercise as WriteBlanksExercise)} onNext={onNext} onBack={onBack} />;
|
||||
case "writing":
|
||||
return <Writing {...(exercise as WritingExercise)} onNext={onNext} onBack={onBack} />;
|
||||
return <Writing key={exercise.id} {...(exercise as WritingExercise)} onNext={onNext} onBack={onBack} />;
|
||||
case "speaking":
|
||||
return <Speaking {...(exercise as SpeakingExercise)} onNext={onNext} onBack={onBack} />;
|
||||
return <Speaking key={exercise.id} {...(exercise as SpeakingExercise)} onNext={onNext} onBack={onBack} />;
|
||||
case "interactiveSpeaking":
|
||||
return <InteractiveSpeaking {...(exercise as InteractiveSpeakingExercise)} onNext={onNext} onBack={onBack} />;
|
||||
return <InteractiveSpeaking key={exercise.id} {...(exercise as InteractiveSpeakingExercise)} onNext={onNext} onBack={onBack} />;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -110,6 +110,7 @@ interface InteractiveSpeakingEvaluation extends Evaluation {
|
||||
interface CommonEvaluation extends Evaluation {
|
||||
perfect_answer?: string;
|
||||
perfect_answer_1?: string;
|
||||
fixed_text?: string;
|
||||
}
|
||||
|
||||
export interface WritingExercise {
|
||||
|
||||
Reference in New Issue
Block a user