212 lines
8.0 KiB
TypeScript
212 lines
8.0 KiB
TypeScript
import React, { useCallback, useState } from "react";
|
|
import SettingsEditor from ".";
|
|
import Option from "@/interfaces/option";
|
|
import Dropdown from "./Shared/SettingsDropdown";
|
|
import Input from "@/components/Low/Input";
|
|
import ExercisePicker from "../Shared/ExercisePicker";
|
|
import { generate } from "./Shared/Generate";
|
|
import GenerateBtn from "./Shared/GenerateBtn";
|
|
import useSettingsState from "../Hooks/useSettingsState";
|
|
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 {
|
|
setExam,
|
|
setExerciseIndex,
|
|
setPartIndex,
|
|
setQuestionIndex,
|
|
setBgColor,
|
|
} = usePersistentExamStore();
|
|
|
|
const { currentModule, title } = useExamEditorStore();
|
|
const {
|
|
focusedSection,
|
|
difficulty,
|
|
sections,
|
|
minTimer,
|
|
isPrivate,
|
|
} = useExamEditorStore(state => state.modules[currentModule]);
|
|
|
|
const { localSettings, updateLocalAndScheduleGlobal } = useSettingsState<ReadingSectionSettings>(
|
|
currentModule,
|
|
focusedSection
|
|
);
|
|
|
|
const currentSection = sections.find((section) => section.sectionId == focusedSection)?.state as ReadingPart;
|
|
|
|
|
|
const defaultPresets: Option[] = [
|
|
{
|
|
label: "Preset: Reading Passage 1",
|
|
value: "Welcome to {part} of the {label}. You will read texts relating to everyday topics and situations. These may include advertisements, brochures, manuals, or official documents. Answer questions that test your ability to locate specific information and understand main ideas."
|
|
},
|
|
{
|
|
label: "Preset: Reading Passage 2",
|
|
value: "Welcome to {part} of the {label}. You will read texts dealing with general interest topics that may include news articles, company policies, or workplace documents. Answer questions testing your understanding of main ideas, specific details, and the author's views."
|
|
},
|
|
{
|
|
label: "Preset: Reading Passage 3",
|
|
value: "Welcome to {part} of the {label}. You will read longer academic texts that may include journal articles, academic essays, or research papers. Answer questions testing your ability to understand complex arguments, identify key points, and follow the development of ideas."
|
|
}
|
|
];
|
|
|
|
|
|
const generatePassage = useCallback(() => {
|
|
generate(
|
|
focusedSection,
|
|
currentModule,
|
|
"context",
|
|
{
|
|
method: 'GET',
|
|
queryParams: {
|
|
difficulty,
|
|
...(localSettings.topic && { topic: localSettings.topic })
|
|
}
|
|
},
|
|
(data: any) => [{
|
|
title: data.title,
|
|
text: data.text
|
|
}]
|
|
);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [localSettings.topic, difficulty, focusedSection]);
|
|
|
|
const onTopicChange = useCallback((topic: string) => {
|
|
updateLocalAndScheduleGlobal({ topic });
|
|
}, [updateLocalAndScheduleGlobal]);
|
|
|
|
|
|
const canPreviewOrSubmit = sections.some(
|
|
(s) => (s.state as ReadingPart).exercises && (s.state as ReadingPart).exercises.length > 0
|
|
);
|
|
|
|
const submitReading = () => {
|
|
if (title === "") {
|
|
toast.error("Enter a title for the exam!");
|
|
return;
|
|
}
|
|
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: s.settings.currentIntro,
|
|
category: s.settings.category
|
|
};
|
|
}),
|
|
minTimer,
|
|
module: "reading",
|
|
id: title,
|
|
isDiagnostic: false,
|
|
variant: undefined,
|
|
difficulty,
|
|
private: isPrivate,
|
|
} as ReadingExam);
|
|
setExerciseIndex(0);
|
|
setQuestionIndex(0);
|
|
setPartIndex(0);
|
|
setBgColor("bg-white");
|
|
openDetachedTab("popout?type=Exam&module=reading", router)
|
|
}
|
|
|
|
return (
|
|
<SettingsEditor
|
|
sectionLabel={`Passage ${focusedSection}`}
|
|
sectionId={focusedSection}
|
|
module="reading"
|
|
introPresets={[defaultPresets[focusedSection - 1]]}
|
|
preview={preview}
|
|
canPreview={canPreviewOrSubmit}
|
|
canSubmit={canPreviewOrSubmit}
|
|
submitModule={submitReading}
|
|
>
|
|
<Dropdown
|
|
title="Generate Passage"
|
|
module={currentModule}
|
|
open={localSettings.isPassageOpen}
|
|
setIsOpen={(isOpen: boolean) => updateLocalAndScheduleGlobal({ isPassageOpen: isOpen }, false)}
|
|
>
|
|
<div className="flex flex-row gap-2 items-center px-2 pb-4">
|
|
<div className="flex flex-col flex-grow gap-4 px-2">
|
|
<label className="font-normal text-base text-mti-gray-dim">Topic (Optional)</label>
|
|
<Input
|
|
key={`section-${focusedSection}`}
|
|
type="text"
|
|
placeholder="Topic"
|
|
name="category"
|
|
onChange={onTopicChange}
|
|
roundness="full"
|
|
value={localSettings.topic}
|
|
/>
|
|
</div>
|
|
<div className="flex self-end h-16 mb-1">
|
|
<GenerateBtn
|
|
module={currentModule}
|
|
genType="context"
|
|
sectionId={focusedSection}
|
|
generateFnc={generatePassage}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Dropdown>
|
|
<Dropdown
|
|
title="Add Exercises"
|
|
module={currentModule}
|
|
open={localSettings.isExerciseDropdownOpen}
|
|
setIsOpen={(isOpen: boolean) => updateLocalAndScheduleGlobal({ isExerciseDropdownOpen: isOpen })}
|
|
disabled={currentSection === undefined || currentSection.text === undefined || currentSection.text.content === "" || currentSection.text.title === ""}
|
|
>
|
|
<ExercisePicker
|
|
module="reading"
|
|
sectionId={focusedSection}
|
|
difficulty={difficulty}
|
|
extraArgs={{ text: currentSection === undefined ? "" : currentSection.text.content }}
|
|
/>
|
|
</Dropdown>
|
|
</SettingsEditor>
|
|
);
|
|
};
|
|
|
|
export default ReadingSettings;
|