added access variable to exams soo we can distinguish private, public and confidential exams and also bugfixes and improvements

This commit is contained in:
José Lima
2025-02-09 04:28:34 +00:00
parent f95bce6fa2
commit b175d8797e
32 changed files with 1320 additions and 909 deletions

View File

@@ -38,7 +38,7 @@ const LevelSettings: React.FC = () => {
difficulty,
sections,
minTimer,
isPrivate,
access,
} = useExamEditorStore(state => state.modules[currentModule]);
const { localSettings, updateLocalAndScheduleGlobal } = useSettingsState<LevelSectionSettings>(
@@ -200,7 +200,7 @@ const LevelSettings: React.FC = () => {
module: "level",
id: title,
difficulty,
private: isPrivate,
access,
};
const result = await axios.post('/api/exam/level', exam);
@@ -243,7 +243,7 @@ const LevelSettings: React.FC = () => {
isDiagnostic: false,
variant: undefined,
difficulty,
private: isPrivate,
access,
} as LevelExam);
setExerciseIndex(0);
setQuestionIndex(0);

View File

@@ -27,7 +27,7 @@ const ListeningSettings: React.FC = () => {
difficulty,
sections,
minTimer,
isPrivate,
access,
instructionsState
} = useExamEditorStore(state => state.modules[currentModule]);
@@ -144,7 +144,7 @@ const ListeningSettings: React.FC = () => {
id: title,
variant: sections.length === 4 ? "full" : "partial",
difficulty,
private: isPrivate,
access,
instructions: instructionsURL
};
@@ -191,7 +191,7 @@ const ListeningSettings: React.FC = () => {
isDiagnostic: false,
variant: sections.length === 4 ? "full" : "partial",
difficulty,
private: isPrivate,
access,
instructions: instructionsState.currentInstructionsURL
} as ListeningExam);
setExerciseIndex(0);

View File

@@ -15,135 +15,137 @@ import ReadingComponents from "./components";
import { getExamById } from "@/utils/exams";
const ReadingSettings: React.FC = () => {
const router = useRouter();
const router = useRouter();
const {
setExam,
setExerciseIndex,
setPartIndex,
setQuestionIndex,
setBgColor,
} = usePersistentExamStore();
const {
setExam,
setExerciseIndex,
setPartIndex,
setQuestionIndex,
setBgColor,
} = usePersistentExamStore();
const { currentModule, title } = useExamEditorStore();
const {
focusedSection,
difficulty,
sections,
minTimer,
isPrivate,
type,
} = useExamEditorStore(state => state.modules[currentModule]);
const { currentModule, title } = useExamEditorStore();
const { focusedSection, difficulty, sections, minTimer, access, type } =
useExamEditorStore((state) => state.modules[currentModule]);
const { localSettings, updateLocalAndScheduleGlobal } = useSettingsState<ReadingSectionSettings>(
currentModule,
focusedSection
);
const { localSettings, updateLocalAndScheduleGlobal } =
useSettingsState<ReadingSectionSettings>(currentModule, focusedSection);
const currentSection = sections.find((section) => section.sectionId == focusedSection)?.state as ReadingPart;
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 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 canPreviewOrSubmit = sections.some(
(s) =>
(s.state as ReadingPart).exercises &&
(s.state as ReadingPart).exercises.length > 0
);
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: true, // using isDiagnostic to keep exam hidden until the respective approval workflow is completed.
minTimer,
module: "reading",
id: title,
variant: sections.length === 3 ? "full" : "partial",
difficulty,
private: isPrivate,
type: type!
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: true, // using isDiagnostic to keep exam hidden until the respective approval workflow is completed.
minTimer,
module: "reading",
id: title,
variant: sections.length === 3 ? "full" : "partial",
difficulty,
access,
type: type!,
};
axios.post(`/api/exam/reading`, exam)
.then((result) => {
playSound("sent");
// Successfully submitted exam
if (result.status === 200) {
toast.success(result.data.message);
} else if (result.status === 207) {
toast.warning(result.data.message);
}
})
.catch((error) => {
console.log(error);
toast.error(error.response.data.error || "Something went wrong while submitting, please try again later.");
})
}
axios
.post(`/api/exam/reading`, exam)
.then((result) => {
playSound("sent");
// Successfully submitted exam
if (result.status === 200) {
toast.success(result.data.message);
} else if (result.status === 207) {
toast.warning(result.data.message);
}
})
.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 exercises = s.state as ReadingPart;
return {
...exercises,
intro: s.settings.currentIntro,
category: s.settings.category
};
}),
minTimer,
module: "reading",
id: title,
isDiagnostic: false,
variant: undefined,
difficulty,
private: isPrivate,
type: type!
} as ReadingExam);
setExerciseIndex(0);
setQuestionIndex(0);
setPartIndex(0);
setBgColor("bg-white");
openDetachedTab("popout?type=Exam&module=reading", router)
}
const preview = () => {
setExam({
parts: sections.map((s) => {
const exercises = s.state as ReadingPart;
return {
...exercises,
intro: s.settings.currentIntro,
category: s.settings.category,
};
}),
minTimer,
module: "reading",
id: title,
isDiagnostic: false,
variant: undefined,
difficulty,
access: access,
type: type!,
} 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}
>
<ReadingComponents
{...{ localSettings, updateLocalAndScheduleGlobal, currentSection }}
/>
</SettingsEditor>
);
return (
<SettingsEditor
sectionLabel={`Passage ${focusedSection}`}
sectionId={focusedSection}
module="reading"
introPresets={[defaultPresets[focusedSection - 1]]}
preview={preview}
canPreview={canPreviewOrSubmit}
canSubmit={canPreviewOrSubmit}
submitModule={submitReading}
>
<ReadingComponents
{...{ localSettings, updateLocalAndScheduleGlobal, currentSection }}
/>
</SettingsEditor>
);
};
export default ReadingSettings;

View File

@@ -30,7 +30,7 @@ const SpeakingSettings: React.FC = () => {
} = usePersistentExamStore();
const { title, currentModule } = useExamEditorStore();
const { focusedSection, difficulty, sections, minTimer, isPrivate } = useExamEditorStore((store) => store.modules[currentModule])
const { focusedSection, difficulty, sections, minTimer, access } = useExamEditorStore((store) => store.modules[currentModule])
const section = sections.find((section) => section.sectionId == focusedSection)?.state;
@@ -185,7 +185,7 @@ const SpeakingSettings: React.FC = () => {
variant: undefined,
difficulty,
instructorGender: "varied",
private: isPrivate,
access,
};
const result = await axios.post('/api/exam/speaking', exam);
@@ -238,7 +238,7 @@ const SpeakingSettings: React.FC = () => {
isDiagnostic: false,
variant: undefined,
difficulty,
private: isPrivate,
access,
} as SpeakingExam);
setExerciseIndex(0);
setQuestionIndex(0);

View File

@@ -23,7 +23,7 @@ const WritingSettings: React.FC = () => {
const {
minTimer,
difficulty,
isPrivate,
access,
sections,
focusedSection,
type,
@@ -81,7 +81,7 @@ const WritingSettings: React.FC = () => {
isDiagnostic: false,
variant: undefined,
difficulty,
private: isPrivate,
access,
type: type!
});
setExerciseIndex(0);
@@ -134,7 +134,7 @@ const WritingSettings: React.FC = () => {
isDiagnostic: true, // using isDiagnostic to keep exam hidden until the respective approval workflow is completed.
variant: undefined,
difficulty,
private: isPrivate,
access,
type: type!
};