import React, { useCallback, useEffect, useState } from 'react'; import AutoExpandingTextArea from "@/components/Low/AutoExpandingTextarea"; import { Card, CardContent } from "@/components/ui/card"; import { AiOutlineUnorderedList, AiOutlinePlus, AiOutlineDelete } from 'react-icons/ai'; import Header from "../../Shared/Header"; import GenLoader from "../Shared/GenLoader"; import useSectionEdit from "../../Hooks/useSectionEdit"; import useExamEditorStore from "@/stores/examEditor"; import { Difficulty, InteractiveSpeakingExercise, LevelPart } from "@/interfaces/exam"; import { BsFileText } from "react-icons/bs"; import { RiVideoLine } from 'react-icons/ri'; import { FaChevronLeft, FaChevronRight } from 'react-icons/fa6'; import { Module } from '@/interfaces'; interface Props { sectionId: number; exercise: InteractiveSpeakingExercise; module?: Module; } const Speaking1: React.FC = ({ sectionId, exercise, module = "speaking" }) => { const { currentModule, dispatch } = useExamEditorStore(); const difficulty = useExamEditorStore((state) => state.modules[currentModule].difficulty); const [local, setLocal] = useState(() => { const defaultPrompts = [ { text: "Hello my name is {avatar}, what is yours?", video_url: "" }, { text: "Do you work or do you study?", video_url: "" }, ...exercise.prompts.slice(2) ]; return { ...exercise, prompts: defaultPrompts }; }); const [currentVideoIndex, setCurrentVideoIndex] = useState(0); const { generating, genResult, state, levelGenResults, levelGenerating } = useExamEditorStore( (state) => state.modules[module].sections.find((section) => section.sectionId === sectionId)! ); const { editing, setEditing, handleSave, handleDiscard, handleEdit, handlePractice } = useSectionEdit({ sectionId, onSave: () => { setEditing(false); if (module === "level") { const updatedState = { ...state, exercises: (state as LevelPart).exercises.map((ex) => ex.id === local.id ? local : ex ) }; dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: updatedState, module } }); } else { dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: local, module } }); } if (genResult) { dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module, field: "genResult", value: undefined } }); } const speakingScript = levelGenResults?.find((res) => res.generating === `${local.id}-speakingScript`); if (module === "level" && speakingScript) { dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, field: "levelGenResults", value: levelGenResults.filter((res) => res.generating !== `${local.id}-speakingScript`), module } }); } }, onDiscard: () => { setLocal({ ...exercise, prompts: [ { text: "Hello my name is {avatar}, what is yours?", video_url: "" }, { text: "Do you work or do you study?", video_url: "" }, ...exercise.prompts.slice(2) ] }); }, onPractice: () => { const updatedLocal = { ...local, isPractice: !local.isPractice }; setLocal(updatedLocal); if (module === "level") { const updatedState = { ...state, exercises: (state as LevelPart).exercises.map((ex) => ex.id === local.id ? updatedLocal : ex ) }; dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: updatedState, module } }); } else { dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: updatedLocal, module } }); } }, }); useEffect(() => { if (genResult && generating === "speakingScript") { if (!difficulty.includes(genResult.result[0].difficulty)) { dispatch({ type: 'UPDATE_MODULE', payload: { updates: { difficulty: [...difficulty, genResult.result[0].difficulty]} } }); } const updatedLocal = { ...local, first_title: genResult.result[0].first_topic, second_title: genResult.result[0].second_topic, prompts: [ local.prompts[0], local.prompts[1], ...genResult.result[0].prompts.map((item: any) => ({ text: item, video_url: "" })) ], difficulty: genResult.result[0].difficulty }; setEditing(true); setLocal(updatedLocal); dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module, field: "generating", value: undefined } }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [genResult, generating]); useEffect(() => { if (genResult && generating === "video") { const updatedLocal = { ...local, prompts: genResult.result[0].prompts }; setLocal(updatedLocal); dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: updatedLocal, module } }); dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module, field: "generating", value: undefined } }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [genResult, generating]); useEffect(() => { const speakingScript = levelGenResults?.find((res) => res.generating === `${local.id}-speakingScript`); const isGenerating = levelGenerating?.includes(`${local.id}-speakingScript`); if (speakingScript && isGenerating) { if (!difficulty.includes(speakingScript.result[0].difficulty)) { dispatch({ type: 'UPDATE_MODULE', payload: { updates: { difficulty: [...difficulty, speakingScript.result[0].difficulty]} } }); } const updatedLocal = { ...local, first_title: speakingScript.result[0].first_topic, second_title: speakingScript.result[0].second_topic, difficulty: speakingScript.result[0].difficulty, prompts: [ local.prompts[0], local.prompts[1], ...speakingScript.result[0].prompts.map((item: any) => ({ text: item, video_url: "" })) ] }; setEditing(true); setLocal(updatedLocal); dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, field: "levelGenerating", value: levelGenerating.filter((g) => g !== `${local.id}-speakingScript`), module } }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [levelGenResults, levelGenerating]); useEffect(() => { const speakingVideo = levelGenResults?.find((res) => res.generating === `${local.id}-video`); const isGenerating = levelGenerating?.includes(`${local.id}-video`); if (speakingVideo && isGenerating) { const updatedLocal = { ...local, video_url: speakingVideo.result[0].video_url }; setLocal(updatedLocal); const updatedState = { ...state, exercises: (state as LevelPart).exercises.map((ex) => ex.id === local.id ? updatedLocal : ex ) }; dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: updatedState, module } }); dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, field: "levelGenerating", value: levelGenerating.filter((g) => g !== `${local.id}-video`), module } }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [levelGenResults, levelGenerating]); const addPrompt = () => { setLocal(prev => ({ ...prev, prompts: [...prev.prompts, { text: "", video_url: "" }] })); }; const removePrompt = (index: number) => { if (index < 2) return; setLocal(prev => ({ ...prev, prompts: prev.prompts.filter((_, i) => i !== index) })); }; const updatePrompt = (index: number, text: string) => { if (index < 2) return; setLocal(prev => { const newPrompts = [...prev.prompts]; newPrompts[index] = { ...newPrompts[index], text }; return { ...prev, prompts: newPrompts }; }); }; const isUnedited = local.prompts.length === 2; useEffect(() => { if (genResult && generating === "video") { setLocal({ ...local, prompts: genResult.result[0].prompts }); dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: { ...local, prompts: genResult.result[0].prompts }, module } }); dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: module, field: "generating", value: undefined } }); dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: module, field: "genResult", value: undefined } }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [genResult, generating]); const handlePrevVideo = () => { setCurrentVideoIndex((prev) => (prev > 0 ? prev - 1 : prev)); }; const handleNextVideo = () => { setCurrentVideoIndex((prev) => (prev < local.prompts.length - 1 ? prev + 1 : prev) ); }; const saveDifficulty = useCallback((diff: Difficulty)=> { if (!difficulty.includes(diff)) { dispatch({ type: 'UPDATE_MODULE', payload: { updates: { difficulty: [...difficulty, diff]} } }); } if (module !== "level") { const updatedExercise = { ...exercise, difficulty: diff }; dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: updatedExercise, module: currentModule } }); } else { const updatedExercise = { ...exercise, difficulty: diff }; const newState = { ...state as LevelPart }; newState.exercises = (newState as LevelPart).exercises.map((ex) => ex.id === exercise.id ? updatedExercise : ex ); dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } }); } }, [currentModule, difficulty, dispatch, exercise, module, sectionId, state]); return ( <>
{(generating && generating === "speakingScript") || (levelGenerating.find((g) => g === `${local.id}-speakingScript`)) ? ( ) : ( <> {editing ? ( <>

Titles

First Title

setLocal(prev => ({ ...prev, first_title: text }))} className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent min-h-[80px] transition-all" placeholder="Enter the first title" />

Second Title

setLocal(prev => ({ ...prev, second_title: text }))} className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent min-h-[80px] transition-all" placeholder="Enter the second title" />

Questions

{local.prompts.length === 2 ? (

No questions added yet

) : ( local.prompts.slice(2).map((prompt, index) => (

Question {index + 1}

updatePrompt(index + 2, text)} className="w-full p-3 border border-gray-200 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent min-h-[80px] transition-all bg-white" placeholder={`Enter question ${index + 1}`} />
)) )}
) : isUnedited ? (

Generate or edit the questions!

) : (
{local.prompts.every((p) => p.video_url !== "") && (

Videos

{currentVideoIndex + 1} / {local.prompts.length}
)} {(generating && generating === "video") || levelGenerating.find((g) => g === `${local.id}-video`) && }

Titles

First Title

{local.first_title || 'No first title'}

Second Title

{local.second_title || 'No second title'}

Questions

{local.prompts.slice(2) .filter(prompt => prompt.text !== "") .map((prompt, index) => (

Question {index + 1}

{prompt.text}

)) }
)} )} ); }; export default Speaking1;