Blanks Exercises were removing the blanks on the editor and text but not on solutions, added submit and preview to writing and reading

This commit is contained in:
Carlos-Mesquita
2024-11-05 17:53:55 +00:00
parent 15c9c4d4bd
commit ffa2045a2d
28 changed files with 519 additions and 264 deletions

View File

@@ -1,5 +1,5 @@
import React, { ReactNode, useCallback, useEffect, useMemo, useState, useRef } from "react";
import { FaEye } from "react-icons/fa";
import { FaEye, FaFileUpload } from "react-icons/fa";
import clsx from "clsx";
import Select from "@/components/Low/Select";
import Input from "@/components/Low/Input";
@@ -18,6 +18,8 @@ interface SettingsEditorProps {
introPresets: Option[];
children?: ReactNode;
canPreview: boolean;
canSubmit: boolean;
submitModule: () => void;
preview: () => void;
}
@@ -28,7 +30,9 @@ const SettingsEditor: React.FC<SettingsEditorProps> = ({
introPresets,
children,
preview,
submitModule,
canPreview,
canSubmit
}) => {
const examLabel = useExamEditorStore((state) => state.modules[module].examLabel) || '';
const { localSettings, updateLocalAndScheduleGlobal } = useSettingsState<SectionSettings>(
@@ -76,6 +80,10 @@ const SettingsEditor: React.FC<SettingsEditorProps> = ({
});
}, [updateLocalAndScheduleGlobal]);
const submitExam = () => {
}
return (
<div className={`flex flex-col gap-8 border bg-ielts-${module}/20 rounded-3xl p-8 w-1/3 h-fit`}>
<div className={`w-full flex justify-center text-ielts-${module} font-bold text-xl`}>{sectionLabel} Settings</div>
@@ -118,7 +126,19 @@ const SettingsEditor: React.FC<SettingsEditorProps> = ({
</div>
</Dropdown>
{children}
<div className="flex flex-row justify-center mt-4">
<div className="flex flex-row justify-between mt-4">
<button
className={clsx(
"flex items-center justify-center px-4 py-2 text-white rounded-xl transition-colors duration-300",
`bg-ielts-${module}/70 border border-ielts-${module} hover:bg-ielts-${module} disabled:bg-ielts-${module}/30`,
"disabled:cursor-not-allowed disabled:text-gray-200"
)}
onClick={submitModule}
disabled={!canSubmit}
>
<FaFileUpload className="mr-2" size={18} />
Submit Module as Exam
</button>
<button
className={clsx(
"flex items-center justify-center px-4 py-2 text-white rounded-xl transition-colors duration-300",

View File

@@ -60,6 +60,8 @@ const LevelSettings: React.FC = () => {
introPresets={defaultPresets}
preview={()=>{}}
canPreview={false}
canSubmit={false}
submitModule={()=> {}}
>
<div>
<Dropdown title="Add Exercises" className={

View File

@@ -69,6 +69,8 @@ const ListeningSettings: React.FC = () => {
introPresets={[defaultPresets[focusedSection - 1]]}
preview={()=> {}}
canPreview={false}
canSubmit={false}
submitModule={()=> {}}
>
<Dropdown
title="Audio Context"

View File

@@ -7,21 +7,33 @@ import ExercisePicker from "../Shared/ExercisePicker";
import { generate } from "./Shared/Generate";
import GenerateBtn from "./Shared/GenerateBtn";
import useSettingsState from "../Hooks/useSettingsState";
import { ReadingPart } from "@/interfaces/exam";
import { ReadingExam, ReadingPart } from "@/interfaces/exam";
import { ReadingSectionSettings } from "@/stores/examEditor/types";
import useExamEditorStore from "@/stores/examEditor";
import openDetachedTab from "@/utils/popout";
import { useRouter } from "next/router";
import { usePersistentExamStore } from "@/stores/examStore";
import axios from "axios";
import { playSound } from "@/utils/sound";
import { toast } from "react-toastify";
const ReadingSettings: React.FC = () => {
const router = useRouter();
const { currentModule } = useExamEditorStore();
const {
setExam,
setExerciseIndex,
setPartIndex,
setQuestionIndex,
} = usePersistentExamStore();
const { currentModule, title } = useExamEditorStore();
const {
focusedSection,
difficulty,
sections,
minTimer,
isPrivate,
} = useExamEditorStore(state => state.modules[currentModule]);
const { localSettings, updateLocalAndScheduleGlobal } = useSettingsState<ReadingSectionSettings>(
@@ -68,18 +80,75 @@ const ReadingSettings: React.FC = () => {
}, [updateLocalAndScheduleGlobal]);
const canPreview = sections.some(
const canPreviewOrSubmit = sections.some(
(s) => (s.state as ReadingPart).exercises && (s.state as ReadingPart).exercises.length > 0
);
const submitReading = () => {
const exam: ReadingExam = {
parts: sections.map((s) => {
const exercise = s.state as ReadingPart;
return {
...exercise,
intro: localSettings.currentIntro,
category: localSettings.category
};
}),
isDiagnostic: false,
minTimer,
module: "reading",
id: title,
type: "academic",
variant: sections.length === 3 ? "full" : "partial",
difficulty,
private: isPrivate,
};
axios.post(`/api/exam/reading`, exam)
.then((result) => {
playSound("sent");
toast.success(`Submitted Exam ID: ${result.data.id}`);
})
.catch((error) => {
console.log(error);
toast.error(error.response.data.error || "Something went wrong while submitting, please try again later.");
})
}
const preview = () => {
setExam({
parts: sections.map((s) => {
const exercise = s.state as ReadingPart;
return {
...exercise,
intro: localSettings.currentIntro,
category: localSettings.category
};
}),
minTimer,
module: "reading",
id: title,
isDiagnostic: false,
variant: undefined,
difficulty,
private: isPrivate,
} as ReadingExam);
setExerciseIndex(0);
setQuestionIndex(0);
setPartIndex(0);
openDetachedTab("popout?type=Exam&module=reading", router)
}
return (
<SettingsEditor
sectionLabel={`Passage ${focusedSection}`}
sectionId={focusedSection}
module="reading"
introPresets={[defaultPresets[focusedSection - 1]]}
preview={() => { }}
canPreview={canPreview}
preview={preview}
canPreview={canPreviewOrSubmit}
canSubmit={canPreviewOrSubmit}
submitModule={submitReading}
>
<Dropdown
title="Generate Passage"

View File

@@ -87,6 +87,7 @@ const SpeakingSettings: React.FC = () => {
}
}
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [localSettings, difficulty]);
const onTopicChange = useCallback((topic: string) => {
@@ -105,6 +106,8 @@ const SpeakingSettings: React.FC = () => {
introPresets={[defaultPresets[focusedSection - 1]]}
preview={() => { }}
canPreview={false}
canSubmit={false}
submitModule={()=> {}}
>
<Dropdown
title="Generate Script"

View File

@@ -11,13 +11,17 @@ import useExamEditorStore from "@/stores/examEditor";
import { useRouter } from "next/router";
import { usePersistentExamStore } from "@/stores/examStore";
import openDetachedTab from "@/utils/popout";
import { WritingExercise } from "@/interfaces/exam";
import { WritingExam, WritingExercise } from "@/interfaces/exam";
import { v4 } from "uuid";
import axios from "axios";
import { playSound } from "@/utils/sound";
import { toast } from "react-toastify";
const WritingSettings: React.FC = () => {
const router = useRouter();
const [preview, setPreview] = useState({canPreview: false, openTab: () => {}});
const { currentModule } = useExamEditorStore();
const [canPreviewOrSubmit, setCanPreviewOrSubmit] = useState(false);
const { currentModule, title } = useExamEditorStore();
const {
minTimer,
difficulty,
@@ -26,7 +30,7 @@ const WritingSettings: React.FC = () => {
focusedSection,
} = useExamEditorStore((store) => store.modules["writing"]);
const states = sections.flatMap((s)=> s.state) as WritingExercise[];
const states = sections.flatMap((s) => s.state) as WritingExercise[];
const {
setExam,
@@ -73,34 +77,73 @@ const WritingSettings: React.FC = () => {
}, [updateLocalAndScheduleGlobal]);
useEffect(() => {
const openTab = () => {
setExam({
isDiagnostic: false,
minTimer,
module: "writing",
exercises: states.filter((s) => s.prompt && s.prompt !== ""),
id: v4(),
variant: undefined,
difficulty,
private: isPrivate,
});
setExerciseIndex(0);
openDetachedTab("popout?type=Exam&module=writing", router)
}
setPreview({
canPreview: states.some((s) => s.prompt && s.prompt !== ""),
openTab
})
setCanPreviewOrSubmit(states.some((s) => s.prompt !== ""))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [states.some((s) => s.prompt !== "")])
const openTab = () => {
setExam({
exercises: sections.map((s) => {
const exercise = s.state as WritingExercise;
return {
...exercise,
intro: s.settings.currentIntro,
category: s.settings.category
};
}),
minTimer,
module: "writing",
id: title,
isDiagnostic: false,
variant: undefined,
difficulty,
private: isPrivate,
});
setExerciseIndex(0);
openDetachedTab("popout?type=Exam&module=writing", router)
}
const submitWriting = () => {
const exam: WritingExam = {
exercises: sections.map((s) => {
const exercise = s.state as WritingExercise;
return {
...exercise,
intro: localSettings.currentIntro,
category: localSettings.category
};
}),
minTimer,
module: "writing",
id: title,
isDiagnostic: false,
variant: undefined,
difficulty,
private: isPrivate,
};
axios
.post(`/api/exam/reading`, exam)
.then((result) => {
playSound("sent");
toast.success(`Submitted Exam ID: ${result.data.id}`);
})
.catch((error) => {
console.log(error);
toast.error(error.response.data.error || "Something went wrong while submitting, please try again later.");
})
}
return (
<SettingsEditor
sectionLabel={`Task ${focusedSection}`}
sectionId={focusedSection}
module="writing"
introPresets={[defaultPresets[focusedSection - 1]]}
preview={preview.openTab}
canPreview={preview.canPreview}
preview={openTab}
canPreview={canPreviewOrSubmit}
canSubmit={canPreviewOrSubmit}
submitModule={submitWriting}
>
<Dropdown
title="Generate Instructions"