isPractice hotfix

This commit is contained in:
Carlos-Mesquita
2024-11-12 17:53:16 +00:00
parent 311036fe86
commit 153d7f5448
21 changed files with 109 additions and 28 deletions

View File

@@ -351,7 +351,19 @@ const EXERCISES: ExerciseGen[] = [
type: "speaking_1",
icon: FaComments,
extra: [
generate()
generate(),
{
label: "First Topic",
param: "first_topic",
value: "",
type: "text"
},
{
label: "Second Topic",
param: "second_topic",
value: "",
type: "text"
},
],
module: "speaking"
},
@@ -360,7 +372,13 @@ const EXERCISES: ExerciseGen[] = [
type: "speaking_2",
icon: FaUserFriends,
extra: [
generate()
generate(),
{
label: "Topic",
param: "topic",
value: "",
type: "text"
},
],
module: "speaking"
},
@@ -369,7 +387,13 @@ const EXERCISES: ExerciseGen[] = [
type: "speaking_3",
icon: FaHandshake,
extra: [
generate()
generate(),
{
label: "Topic",
param: "topic",
value: "",
type: "text"
},
],
module: "speaking"
},

View File

@@ -112,6 +112,7 @@ const FillBlanksLetters: React.FC<{ exercise: FillBlanksExercise; sectionId: num
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});

View File

@@ -108,6 +108,7 @@ const FillBlanksMC: React.FC<{ exercise: FillBlanksExercise; sectionId: number }
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});
@@ -200,7 +201,7 @@ const FillBlanksMC: React.FC<{ exercise: FillBlanksExercise; sectionId: number }
useEffect(() => {
validateBlanks(blanksState.blanks, answers, alerts, setAlerts);
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [answers, blanksState.blanks, blanksState.textMode]);
useEffect(() => {
@@ -226,16 +227,16 @@ const FillBlanksMC: React.FC<{ exercise: FillBlanksExercise; sectionId: number }
solution
])
));
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleBlankRemove = (blankId: number) => {
if (!editing) setEditing(true);
const newAnswers = new Map(answers);
newAnswers.delete(blankId.toString());
setAnswers(newAnswers);
setLocal(prev => ({
...prev,
words: (prev.words as FillBlanksMCOption[]).filter(w => w.id !== blankId.toString()),
@@ -244,7 +245,7 @@ const FillBlanksMC: React.FC<{ exercise: FillBlanksExercise; sectionId: number }
solution
}))
}));
blanksDispatcher({ type: "REMOVE_BLANK", payload: blankId });
};

View File

@@ -79,6 +79,7 @@ const WriteBlanksFill: React.FC<{ exercise: WriteBlanksExercise; sectionId: numb
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});

View File

@@ -76,6 +76,7 @@ const MatchSentences: React.FC<{ exercise: MatchSentencesExercise, sectionId: nu
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});

View File

@@ -107,6 +107,7 @@ const UnderlineMultipleChoice: React.FC<{exercise: MultipleChoiceExercise, secti
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});

View File

@@ -186,6 +186,7 @@ const MultipleChoice: React.FC<MultipleChoiceProps> = ({ exercise, sectionId, op
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});

View File

@@ -55,6 +55,7 @@ const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise, module = "s
...state,
isPractice: !local.isPractice
};
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: updatedExercise, module: module } });
},
});

View File

@@ -67,6 +67,7 @@ const Speaking1: React.FC<Props> = ({ sectionId, exercise, module = "speaking" }
...state,
isPractice: !local.isPractice
};
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: updatedExercise, module: module } });
},
});

View File

@@ -54,6 +54,7 @@ const Speaking2: React.FC<Props> = ({ sectionId, exercise, module = "speaking" }
...state,
isPractice: !local.isPractice
};
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: updatedExercise, module: module } });
},
});

View File

@@ -3,21 +3,30 @@ import { SpeakingExercise, InteractiveSpeakingExercise } from "@/interfaces/exam
import Speaking2 from "./Speaking2";
import InteractiveSpeaking from "./InteractiveSpeaking";
import Speaking1 from "./Speaking1";
import { Module } from "@/interfaces";
interface Props {
sectionId: number;
exercise: SpeakingExercise | InteractiveSpeakingExercise;
qId?: number;
module: Module;
}
const Speaking: React.FC<Props> = ({ sectionId, exercise }) => {
const { currentModule } = useExamEditorStore();
const Speaking: React.FC<Props> = ({ sectionId, exercise, qId, module = "speaking" }) => {
const { dispatch } = useExamEditorStore();
const { state } = useExamEditorStore(
(state) => state.modules[currentModule].sections.find((section) => section.sectionId === sectionId)!
(state) => state.modules[module].sections.find((section) => section.sectionId === sectionId)!
);
const onFocus = () => {
if (qId) {
dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { module, sectionId, field: "focusedExercise", value: { questionId: qId, id: exercise.id } } })
}
}
return (
<>
<div className="mx-auto p-3 space-y-6">
<div tabIndex={0} className="mx-auto p-3 space-y-6" onFocus={onFocus}>
<div className="p-4">
<div className="flex flex-col space-y-6">
{sectionId === 1 && <Speaking1 sectionId={sectionId} exercise={state as InteractiveSpeakingExercise} />}

View File

@@ -107,12 +107,13 @@ const TrueFalse: React.FC<{ exercise: TrueFalseExercise, sectionId: number }> =
onPractice: () => {
const updatedExercise = {
...local,
isPractice: !local.isPractice
isPractice: false
};
const newState = { ...section };
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
updateLocal({...local, isPractice: !local.isPractice})
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});
@@ -140,6 +141,7 @@ const TrueFalse: React.FC<{ exercise: TrueFalseExercise, sectionId: number }> =
handleDelete={handleDelete}
handleDiscard={handleDiscard}
handlePractice={handlePractice}
isEvaluationEnabled={!local.isPractice}
/>
{alerts.length > 0 && <Alert className="mb-6" alerts={alerts} />}
<PromptEdit

View File

@@ -85,6 +85,7 @@ const WriteBlanks: React.FC<{ sectionId: number; exercise: WriteBlanksExercise;
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});

View File

@@ -71,6 +71,7 @@ const WriteBlanksForm: React.FC<{ sectionId: number; exercise: WriteBlanksExerci
newState.exercises = newState.exercises.map((ex) =>
ex.id === exercise.id ? updatedExercise : ex
);
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});

View File

@@ -68,6 +68,7 @@ const Writing: React.FC<Props> = ({ sectionId, exercise, module, index }) => {
...state,
isPractice: !local.isPractice
};
setLocal((prev) => ({...prev, isPractice: !local.isPractice}))
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
}
});

View File

@@ -7,6 +7,7 @@ import TrueFalse from "../../Exercises/TrueFalse";
import fillBlanks from "./fillBlanks";
import MatchSentences from "../../Exercises/MatchSentences";
import Writing from "../../Exercises/Writing";
import Speaking from "../../Exercises/Speaking";
const getExerciseItems = (exercises: Exercise[], sectionId: number): ExerciseItem[] => {
const items: ExerciseItem[] = exercises.map((exercise, index) => {
@@ -78,6 +79,34 @@ const getExerciseItems = (exercises: Exercise[], sectionId: number): ExerciseIte
),
content: <Writing key={exercise.id} exercise={exercise} sectionId={sectionId} index={index} module="level" />
};
case "speaking":
return {
id: index.toString(),
sectionId,
label: (
<ExerciseLabel
type={`Speaking Section 2`}
firstId={exercise.sectionId!.toString()}
lastId={exercise.sectionId!.toString()}
prompt={exercise.prompts[2]}
/>
),
content: <Speaking key={exercise.id} exercise={exercise} sectionId={sectionId} qId={index} module="level" />
};
case "interactiveSpeaking":
return {
id: index.toString(),
sectionId,
label: (
<ExerciseLabel
type={`Speaking Section 2`}
firstId={exercise.sectionId!.toString()}
lastId={exercise.sectionId!.toString()}
prompt={exercise.prompts[2].text}
/>
),
content: <Speaking key={exercise.id} exercise={exercise} sectionId={sectionId} qId={index} module="level" />
};
default:
return {} as unknown as ExerciseItem;
}

View File

@@ -181,7 +181,7 @@ const SectionExercises: React.FC<{ sectionId: number; }> = ({ sectionId }) => {
}
if (currentModule == "writing") return background(<Writing sectionId={sectionId} exercise={currentSection.state as WritingExercise} module="writing" />);
if (currentModule == "speaking") return background(<Speaking sectionId={sectionId} exercise={currentSection.state as SpeakingExercise} />);
if (currentModule == "speaking") return background(<Speaking sectionId={sectionId} exercise={currentSection.state as SpeakingExercise} module="speaking" />);
const questions = questionItems();

View File

@@ -18,12 +18,12 @@ const SectionPicker: React.FC<Props> = ({
updateLocalAndScheduleGlobal
}) => {
const { dispatch } = useExamEditorStore();
const [selectedValue, setSelectedValue] = React.useState<number | null>(null);
const [selectedValue, setSelectedValue] = React.useState<number | undefined>(undefined);
const sectionState = useExamEditorStore(state =>
state.modules["level"].sections.find((s) => s.sectionId === sectionId)
);
if (sectionState === undefined) return null;
const { readingSection, listeningSection } = sectionState;
@@ -32,14 +32,16 @@ const SectionPicker: React.FC<Props> = ({
const openPicker = module === "reading" ? "isReadingPickerOpen" : "isListeningPickerOpen";
const handleSectionChange = (value: number) => {
setSelectedValue(value);
const newValue = currentValue === value ? undefined : value;
setSelectedValue(newValue);
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: "level",
field: module === "reading" ? "readingSection" : "listeningSection",
value: value
value: newValue
}
});
};
@@ -67,17 +69,19 @@ const SectionPicker: React.FC<Props> = ({
className={`
flex items-center space-x-3 font-semibold cursor-pointer p-2 rounded
transition-colors duration-200
${currentValue === num
${currentValue === num
? `bg-ielts-${module}/90 text-white`
: `hover:bg-ielts-${module}/70 text-gray-700`}
`}
onClick={(e) => {
e.preventDefault();
handleSectionChange(num);
}}
>
<input
type="radio"
name={`${module === "reading" ? 'passage' : 'section'}-${sectionId}`}
value={num}
type="checkbox"
checked={currentValue === num}
onChange={() => handleSectionChange(num)}
onChange={() => {}}
className={`
h-5 w-5 cursor-pointer
accent-ielts-${module}
@@ -95,4 +99,4 @@ const SectionPicker: React.FC<Props> = ({
);
};
export default SectionPicker;
export default SectionPicker;

View File

@@ -114,7 +114,7 @@ const LevelSettings: React.FC = () => {
openDetachedTab("popout?type=Exam&module=level", router)
}
const speakingExercise = focusedExercise === undefined ? undefined : currentSection.exercises[focusedExercise] as SpeakingExercise | InteractiveSpeakingExercise;
const speakingExercise = focusedExercise === undefined ? undefined : currentSection.exercises.find((ex) => ex.id === focusedExercise.id) as SpeakingExercise | InteractiveSpeakingExercise;
return (
<SettingsEditor
@@ -249,7 +249,7 @@ const LevelSettings: React.FC = () => {
</Dropdown>
{speakingExercise !== undefined &&
<Dropdown title="Configure Speaking Exercise" className={
<Dropdown title={`Configure Speaking Exercise ${focusedExercise?.questionId}`} className={
clsx(
"w-full font-semibold flex justify-between items-center p-4 bg-gradient-to-r border",
"bg-ielts-speaking/70 border-ielts-speaking hover:bg-ielts-speaking",

View File

@@ -136,6 +136,7 @@ export const defaultSectionSettings = (module: Module, sectionId: number, part?:
state: part !== undefined ? part : defaultSection(module, sectionId),
generating: undefined,
genResult: undefined,
focusedExercise: undefined,
expandedSubSections: [],
levelGenerating: [],
levelGenResults: []
@@ -143,7 +144,7 @@ export const defaultSectionSettings = (module: Module, sectionId: number, part?:
}
const defaultModuleSettings = (module: Module, minTimer: number, states?: SectionState[]): ModuleState => {
const defaultModuleSettings = (module: Module, minTimer: number): ModuleState => {
const state: ModuleState = {
examLabel: defaultExamLabel(module),
minTimer,

View File

@@ -92,7 +92,7 @@ export interface SectionState {
genResult: {generating: string, result: Record<string, any>[], module: Module} | undefined;
levelGenerating: Generating[];
levelGenResults: {generating: string, result: Record<string, any>[], module: Module}[];
focusedExercise?: number;
focusedExercise?: {questionId: number; id: string} | undefined;
writingSection?: number;
speakingSection?: number;
readingSection?: number;