Reverted Level to only utas placement test exercises, Speaking, bug fixes, placeholder

This commit is contained in:
Carlos-Mesquita
2024-11-10 04:24:23 +00:00
parent c507eae507
commit 322d7905c3
39 changed files with 1251 additions and 279 deletions

View File

@@ -122,22 +122,50 @@ const ExerciseWizard: React.FC<Props> = ({
size={28}
color={!currentValue ? `#F3F4F6` : `#1F2937`}
/>
<Tooltip id={`${exerciseIndex}`} className="z-50 bg-white shadow-md rounded-sm" />
<a data-tooltip-id={`${exerciseIndex}`} data-tooltip-html="Generate or use placeholder?" className='ml-1 flex items-center justify-center'>
<Image src="/mat-icon-info.svg" width={24} height={24} alt={"AI Generated?"} />
</a>
</div>
);
}
if ('type' in param && param.type === 'text') {
return (
<div className="space-y-2">
<div className="flex items-center gap-2">
<label className="text-sm font-medium text-white">
{param.label}
</label>
{param.tooltip && (
<>
<Tooltip id={config.type} className="z-50 bg-white shadow-md rounded-sm" />
<a data-tooltip-id={config.type} data-tooltip-html={param.tooltip} className='ml-1 flex items-center justify-center'>
<Image src="/mat-icon-info.svg" width={24} height={24} alt={param.tooltip} />
</a>
</>
)}
</div>
<input
type="text"
value={config.params[param.param || ''] as string}
onChange={(e) => handleParameterChange(
exerciseIndex,
param.param || '',
e.target.value
)}
className="px-3 py-2 shadow-lg rounded-md text-mti-gray-dim w-full"
placeholder="Enter here..."
/>
</div>
);
}
const inputValue = Number(config.params[param.param || '1'].toString());
const isParagraphMatch = config.type.split("?name=")[1] === "paragraphMatch";
const maxParagraphs = isParagraphMatch ? extraArgs!.text.split("\n\n").length : 50;
return (
<div className="space-y-2">
<div className="flex items-center gap-2">
@@ -183,7 +211,8 @@ const ExerciseWizard: React.FC<Props> = ({
<exercise.icon className="h-5 w-5" />
<h3 className="font-medium text-lg">{exercise.label}</h3>
</div>
{generateParam && renderParameterInput(generateParam, exerciseIndex, config)}
{/* when placeholders are done uncomment this*/}
{/*generateParam && renderParameterInput(generateParam, exerciseIndex, config)*/}
</div>
);
};

View File

@@ -209,21 +209,29 @@ const listening = (section: number) => {
}
const EXERCISES: ExerciseGen[] = [
{
/*{
label: "Multiple Choice",
type: "multipleChoice",
icon: FaListUl,
extra: [
{
param: "name",
value: "multipleChoice"
},
quantity(10, "Amount"),
generate()
],
module: "level"
},
},*/
{
label: "Multiple Choice - Blank Space",
type: "mcBlank",
icon: FaEdit,
extra: [
{
param: "name",
value: "mcBlank"
},
quantity(10, "Amount"),
generate()
],
@@ -234,6 +242,10 @@ const EXERCISES: ExerciseGen[] = [
type: "mcUnderline",
icon: FaUnderline,
extra: [
{
param: "name",
value: "mcUnderline"
},
quantity(10, "Amount"),
generate()
],
@@ -255,10 +267,14 @@ const EXERCISES: ExerciseGen[] = [
module: "level"
},*/
{
label: "Fill Blanks: MC",
label: "Fill Blanks: Multiple Choice",
type: "fillBlanksMC",
icon: FaPen,
extra: [
{
param: "name",
value: "fillBlanksMC"
},
quantity(10, "Nº of Blanks"),
{
label: "Passage Word Size",
@@ -270,25 +286,26 @@ const EXERCISES: ExerciseGen[] = [
module: "level"
},
{
label: "Reading Passage",
label: "Reading Passage: Multiple Choice",
type: "passageUtas",
icon: FaBookOpen,
extra: [
{
param: "name",
value: "passageUtas"
},
// in the utas exam there was only mc so I'm assuming short answers are deprecated
/*{
label: "Short Answers",
param: "sa_qty",
value: "10"
},*/
{
label: "Multiple Choice Quantity",
param: "mc_qty",
value: "10"
},
quantity(10, "Multiple Choice Quantity"),
{
label: "Reading Passage Topic",
param: "topic",
value: ""
value: "",
type: "text"
},
{
label: "Passage Word Size",

View File

@@ -17,6 +17,6 @@ export interface ExerciseGen {
type: string;
icon: IconType;
sectionId?: number;
extra?: { param?: string; value?: string | number | boolean; label?: string; tooltip?: string}[];
extra?: { param?: string; value?: string | number | boolean; label?: string; tooltip?: string, type?: string}[];
module: string
}

View File

@@ -23,13 +23,15 @@ const ExercisePicker: React.FC<ExercisePickerProps> = ({
extraArgs = undefined,
}) => {
const { currentModule, dispatch } = useExamEditorStore();
const { difficulty} = useExamEditorStore((store) => store.modules[currentModule]);
const section = useExamEditorStore((store) => store.modules[currentModule].sections.find((s) => s.sectionId == sectionId)!);
const { state, selectedExercises } = section;
const { difficulty } = useExamEditorStore((store) => store.modules[currentModule]);
const section = useExamEditorStore((store) => store.modules[currentModule].sections.find((s) => s.sectionId == sectionId));
const [pickerOpen, setPickerOpen] = useState(false);
if (section === undefined) return;
const { state, selectedExercises } = section;
const getFullExerciseType = (exercise: ExerciseGen): string => {
if (exercise.extra && exercise.extra.length > 0) {
const extraValue = exercise.extra.find(e => e.param === 'name')?.value;
@@ -48,7 +50,7 @@ const ExercisePicker: React.FC<ExercisePickerProps> = ({
dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { module: currentModule, sectionId, field: "selectedExercises", value: newSelected } })
};
const moduleExercises = module === 'level' ? EXERCISES : (sectionId ? EXERCISES.filter((ex) => ex.module === module && ex.sectionId == sectionId) : EXERCISES.filter((ex) => ex.module === module));
const moduleExercises = (sectionId && module !== "level" ? EXERCISES.filter((ex) => ex.module === module && ex.sectionId == sectionId) : EXERCISES.filter((ex) => ex.module === module));
const onModuleSpecific = (configurations: ExerciseConfig[]) => {
const exercises = configurations.map(config => {
@@ -119,7 +121,15 @@ const ExercisePicker: React.FC<ExercisePickerProps> = ({
return (
<>
<Modal isOpen={pickerOpen} onClose={() => setPickerOpen(false)} title="Exercise Wizard">
<Modal isOpen={pickerOpen} onClose={() => setPickerOpen(false)} title="Exercise Wizard"
titleClassName={clsx(
"text-2xl font-semibold text-center py-4",
`bg-ielts-${module} text-white`,
"shadow-sm",
"-mx-6 -mt-6",
"mb-6"
)}
>
<ExerciseWizard
sectionId={sectionId}
exercises={moduleExercises}
@@ -165,8 +175,8 @@ const ExercisePicker: React.FC<ExercisePickerProps> = ({
>
{section.generating === "exercises" ? (
<div key={`section-${sectionId}`} className="flex items-center justify-center">
<BsArrowRepeat className="text-white animate-spin" size={25} />
</div>
<BsArrowRepeat className="text-white animate-spin" size={25} />
</div>
) : (
<>Set Up Exercises ({selectedExercises.length}) </>
)}

View File

@@ -6,7 +6,7 @@ import { capitalize } from 'lodash';
import { Module } from '@/interfaces';
import { toast } from 'react-toastify';
import useExamEditorStore from '@/stores/examEditor';
import { ReadingPart } from '@/interfaces/exam';
import { LevelPart, ReadingPart } from '@/interfaces/exam';
import { defaultSectionSettings } from '@/stores/examEditor/defaults';
const WordUploader: React.FC<{ module: Module }> = ({ module }) => {
@@ -72,7 +72,7 @@ const WordUploader: React.FC<{ module: Module }> = ({ module }) => {
setShowUploaders(false);
switch (currentModule) {
case 'reading':
case 'reading': {
const newSectionsStates = data.parts.map(
(part: ReadingPart, index: number) => defaultSectionSettings(module, index + 1, part)
);
@@ -88,6 +88,28 @@ const WordUploader: React.FC<{ module: Module }> = ({ module }) => {
}
});
break;
}
case 'level': {
const newSectionsStates = data.parts.map(
(part: LevelPart, index: number) => defaultSectionSettings(module, index + 1, part)
);
dispatch({
type: "UPDATE_MODULE", payload: {
updates: {
sections: newSectionsStates,
minTimer: data.minTimer,
importModule: false,
importing: false,
sectionLabels: Array.from({ length: newSectionsStates.length }, (_, index) => ({
id: index + 1,
label: `Part ${index + 1}`
}))
},
module
}
});
break;
}
}
} catch (error) {
toast.error(`An unknown error has occured while import ${module} exam!`);

View File

@@ -1,40 +1,49 @@
import { useState } from "react";
import Dropdown from "@/components/Dropdown";
import clsx from "clsx";
interface Props {
title: string;
content: string;
open: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
title: string;
content: string;
open?: boolean;
setIsOpen?: React.Dispatch<React.SetStateAction<boolean>>;
}
const Passage: React.FC<Props> = ({ title, content, open, setIsOpen}) => {
const paragraphs = content.split('\n\n');
const Passage: React.FC<Props> = ({ title, content, open: externalOpen, setIsOpen: externalSetIsOpen }) => {
const [internalOpen, setInternalOpen] = useState(false);
return (
<Dropdown
title={title}
const isOpen = externalOpen ?? internalOpen;
const setIsOpen = externalSetIsOpen ?? setInternalOpen;
const paragraphs = content.split('\n\n');
return (
<Dropdown
title={title}
className={clsx(
"bg-white p-6 w-full items-center",
isOpen ? "rounded-t-lg border-b border-gray-200" : "rounded-lg shadow-lg"
)}
titleClassName="text-2xl font-semibold text-gray-800"
contentWrapperClassName="p-6 bg-white rounded-b-lg shadow-md transition-all duration-300 ease-in-out"
open={isOpen}
setIsOpen={setIsOpen}
>
<div>
{paragraphs.map((paragraph, index) => (
<p
key={index}
className={clsx(
"bg-white p-6 w-full items-center",
open ? "rounded-t-lg border-b border-gray-200" : "rounded-lg shadow-lg"
"text-justify",
index < paragraphs.length - 1 ? 'mb-4' : 'mb-6'
)}
titleClassName="text-2xl font-semibold text-gray-800"
contentWrapperClassName="p-6 bg-white rounded-b-lg shadow-md transition-all duration-300 ease-in-out"
open={open}
setIsOpen={setIsOpen}
>
<div>
{paragraphs.map((paragraph, index) => (
<p
key={index}
className={clsx("text-justify", index < paragraphs.length - 1 ? 'mb-4' : 'mb-6')}
>
{paragraph.trim()}
</p>
))}
</div>
</Dropdown>
);
>
{paragraph.trim()}
</p>
))}
</div>
</Dropdown>
);
}
export default Passage;