import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable"; import SortableSection from "../../Shared/SortableSection"; import { Exercise, LevelPart, ListeningPart, ReadingPart, SpeakingExercise, WritingExercise } from "@/interfaces/exam"; import ExerciseItem from "./types"; import Dropdown from "@/components/Dropdown"; import useExamEditorStore from "@/stores/examEditor"; import Writing from "../../Exercises/Writing"; import Speaking from "../../Exercises/Speaking"; import { ReactElement, ReactNode, useEffect, useState } from "react"; import { DndContext, PointerSensor, useSensor, useSensors, closestCenter, } from '@dnd-kit/core'; import GenLoader from "../../Exercises/Shared/GenLoader"; import { ExamPart, Generating } from "@/stores/examEditor/types"; import React from "react"; import getExerciseItems from "./exercises"; import { Action } from "@/stores/examEditor/reducers"; import { writingTask } from "@/stores/examEditor/sections"; interface QuestionItemsResult { ids: string[]; items: ExerciseItem[]; } const SectionExercises: React.FC<{ sectionId: number; }> = ({ sectionId }) => { const dispatch = useExamEditorStore(state => state.dispatch); const currentModule = useExamEditorStore(state => state.currentModule); const sections = useExamEditorStore(state => state.modules[currentModule].sections); const expandedSections = useExamEditorStore(state => state.modules[currentModule].expandedSections); const section = useExamEditorStore( state => state.modules[currentModule].sections.find( section => section.sectionId === sectionId ) ); const genResult = section?.genResult; const generating = section?.generating; const levelGenResults = section?.levelGenResults const levelGenerating = section?.levelGenerating; const sectionState = section?.state; useEffect(() => { if (genResult && genResult.generating === "exercises" && genResult.module === currentModule) { const newExercises = genResult.result[0].exercises; dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, module: genResult.module, update: { exercises: [...(sectionState as ExamPart).exercises, ...newExercises] } } }) dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: currentModule, field: "generating", value: undefined } }) dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: currentModule, field: "genResult", value: undefined } }) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [genResult, dispatch, sectionId, currentModule]); useEffect(() => { if (levelGenResults && levelGenResults.some(res => res.generating.startsWith("exercises"))) { const newExercises = levelGenResults .filter(res => res.generating.startsWith("exercises")) .map(res => res.result[0].exercises) .flat(); const updates = [ { type: "UPDATE_SECTION_STATE", payload: { sectionId, module: "level", update: { exercises: [...(sectionState as ExamPart).exercises, ...newExercises] } } }, { type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: currentModule, field: "levelGenerating", value: levelGenerating?.filter(g => !g?.startsWith("exercises")) } }, { type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: currentModule, field: "levelGenResults", value: levelGenResults.filter(res => !res.generating.startsWith("exercises")) } } ] as Action[]; updates.forEach(update => dispatch(update)); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [levelGenResults, sectionState, levelGenerating, sectionId, currentModule]); useEffect(() => { if (levelGenResults && levelGenResults.some(res => res.generating === "writing_letter" || res.generating === "writing_2")) { const results = levelGenResults.filter(res => res.generating === "writing_letter" || res.generating === "writing_2"); const updates = [ { type: "UPDATE_SECTION_STATE", payload: { sectionId, module: "level", update: { exercises: [...(sectionState as ExamPart).exercises, ...results.map((res)=> { return { ...writingTask(res.generating === "writing_letter" ? 1 : 2), prompt: res.result[0].prompt, variant: res.generating === "writing_letter" ? "letter" : "essay" } as WritingExercise; }) ] } } }, { type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: currentModule, field: "levelGenerating", value: levelGenerating?.filter(g => !results.flatMap(res => res.generating as Generating).includes(g)) } }, { type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: currentModule, field: "levelGenResults", value: levelGenResults.filter(res => !results.flatMap(res => res.generating as Generating).includes(res.generating)) } } ] as Action[]; updates.forEach(update => dispatch(update)); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [levelGenResults, sectionState, levelGenerating, sectionId, currentModule]); const currentSection = sections.find((s) => s.sectionId === sectionId)!; const sensors = useSensors( useSensor(PointerSensor), ); const questionItems = (): QuestionItemsResult => { const part = currentSection.state as ReadingPart | ListeningPart | LevelPart; const items = getExerciseItems(part.exercises, sectionId); return { items, ids: items.map(item => item.id) } }; const background = (component: ReactNode) => { return (
{component}
); } if (currentModule == "writing") return background(); if (currentModule == "speaking") return background(); const questions = questionItems(); // ############################################################################# // Typescript checks so that the compiler and builder don't freak out const filteredIds = (questions.ids ?? []).filter(Boolean); function isValidItem(item: ExerciseItem | undefined): item is ExerciseItem { return item !== undefined && typeof item.id === 'string' && typeof item.sectionId === 'number' && React.isValidElement(item.label) && React.isValidElement(item.content); } const filteredItems = (questions.items ?? []).filter(isValidItem); // ############################################################################# console.log(levelGenerating); return ( dispatch({ type: "REORDER_EXERCISES", payload: { event: e, sectionId, module: currentModule } })} > {expandedSections.includes(sectionId) && questions.items && questions.items.length > 0 && questions.ids && questions.ids.length > 0 && (
{filteredItems.map(item => (
{item.content}
))}
) } {generating === "exercises" && } {currentModule === "level" && ( <> { questions.ids?.length === 0 && !levelGenerating?.some((g) => g?.startsWith("exercises") || g?.startsWith("writing")) && generating !== "exercises" && background(Generated exercises will appear here!)} {levelGenerating?.some((g) => g?.startsWith("exercises") || g?.startsWith("writing")) && } ) }
); } export default SectionExercises;