ENCOA-228 Now when user navigates between modules the generation items persist. Reading, listening and writing added to level module

This commit is contained in:
Carlos-Mesquita
2024-11-12 14:17:54 +00:00
parent 696c968ebc
commit fdf411d133
66 changed files with 2546 additions and 1635 deletions

View File

@@ -12,53 +12,70 @@ import { InteractiveSpeakingExercise } from "@/interfaces/exam";
import { BsFileText } from "react-icons/bs";
import { FaChevronLeft, FaChevronRight } from "react-icons/fa6";
import { RiVideoLine } from "react-icons/ri";
import { Module } from "@/interfaces";
interface Props {
sectionId: number;
exercise: InteractiveSpeakingExercise;
module?: Module;
}
const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise }) => {
const { currentModule, dispatch } = useExamEditorStore();
const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise, module = "speaking" }) => {
const { dispatch } = useExamEditorStore();
const [local, setLocal] = useState(exercise);
const [currentVideoIndex, setCurrentVideoIndex] = useState(0);
const { generating, genResult } = useExamEditorStore(
(state) => state.modules[currentModule].sections.find((section) => section.sectionId === sectionId)!
const { generating, genResult, state } = useExamEditorStore(
(state) => state.modules[module].sections.find((section) => section.sectionId === sectionId)!
);
const { editing, setEditing, handleSave, handleDiscard, modeHandle } = useSectionEdit({
const { editing, setEditing, handleSave, handleDiscard, handleEdit, handlePractice } = useSectionEdit({
sectionId,
mode: "edit",
onSave: () => {
setEditing(false);
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId: sectionId, update: local } });
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId: sectionId, update: local, module: module } });
if (genResult) {
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: module,
field: "genResult",
value: undefined
}
});
}
},
onDiscard: () => {
setLocal(exercise);
},
onMode: () => { },
onPractice: () => {
const updatedExercise = {
...state,
//isPractice: !isPractice,
};
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: updatedExercise, module: module } });
},
});
useEffect(() => {
if (genResult && generating === "context") {
if (genResult && generating === "speakingScript") {
setEditing(true);
setLocal({
...local,
title: genResult[0].title,
prompts: genResult[0].prompts.map((item: any) => ({
title: genResult.result[0].title,
prompts: genResult.result[0].prompts.map((item: any) => ({
text: item || "",
video_url: ""
}))
});
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: currentModule,
field: "genResult",
module: module,
field: "generating",
value: undefined
}
});
@@ -91,27 +108,18 @@ const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise }) => {
const isUnedited = local.prompts.length === 0;
useEffect(() => {
if (genResult && generating === "media") {
setLocal({ ...local, prompts: genResult[0].prompts });
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: { ...local, prompts: genResult[0].prompts } } });
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: module } });
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: currentModule,
module: module,
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, generating]);
@@ -121,7 +129,7 @@ const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise }) => {
};
const handleNextVideo = () => {
setCurrentVideoIndex((prev) =>
setCurrentVideoIndex((prev) =>
(prev < local.prompts.length - 1 ? prev + 1 : prev)
);
};
@@ -134,14 +142,15 @@ const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise }) => {
description='Generate or write the scripts for the videos.'
editing={editing}
handleSave={handleSave}
modeHandle={modeHandle}
handleEdit={handleEdit}
handleDiscard={handleDiscard}
mode="edit"
handlePractice={handlePractice}
isEvaluationEnabled={true}
module="speaking"
/>
</div>
{generating && generating === "context" ? (
<GenLoader module={currentModule} />
{generating && generating === "speakingScript" ? (
<GenLoader module={module} />
) : (
<>
{editing ? (
@@ -160,8 +169,8 @@ const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise }) => {
onClick={handlePrevVideo}
disabled={currentVideoIndex === 0}
className={`p-2 rounded-full ${currentVideoIndex === 0
? 'text-gray-400 cursor-not-allowed'
: 'text-gray-600 hover:bg-gray-100'
? 'text-gray-400 cursor-not-allowed'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
<FaChevronLeft className="w-4 h-4" />
@@ -173,8 +182,8 @@ const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise }) => {
onClick={handleNextVideo}
disabled={currentVideoIndex === local.prompts.length - 1}
className={`p-2 rounded-full ${currentVideoIndex === local.prompts.length - 1
? 'text-gray-400 cursor-not-allowed'
: 'text-gray-600 hover:bg-gray-100'
? 'text-gray-400 cursor-not-allowed'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
<FaChevronRight className="w-4 h-4" />
@@ -196,8 +205,8 @@ const InteractiveSpeaking: React.FC<Props> = ({ sectionId, exercise }) => {
</CardContent>
</Card>
)}
{generating && generating === "media" &&
<GenLoader module={currentModule} custom="Generating the videos ... This may take a while ..." />
{generating && generating === "video" &&
<GenLoader module={module} custom="Generating the videos ... This may take a while ..." />
}
<Card>
<CardContent>

View File

@@ -10,14 +10,16 @@ import { InteractiveSpeakingExercise } 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<Props> = ({ sectionId, exercise }) => {
const { currentModule, dispatch } = useExamEditorStore();
const Speaking1: React.FC<Props> = ({ sectionId, exercise, module = "speaking" }) => {
const {dispatch} = useExamEditorStore();
const [local, setLocal] = useState(() => {
const defaultPrompts = [
{ text: "Hello my name is {avatar}, what is yours?", video_url: "" },
@@ -29,16 +31,26 @@ const Speaking1: React.FC<Props> = ({ sectionId, exercise }) => {
const [currentVideoIndex, setCurrentVideoIndex] = useState(0);
const { generating, genResult } = useExamEditorStore(
(state) => state.modules[currentModule].sections.find((section) => section.sectionId === sectionId)!
const { generating, genResult , state} = useExamEditorStore(
(state) => state.modules[module].sections.find((section) => section.sectionId === sectionId)!
);
const { editing, setEditing, handleSave, handleDiscard, modeHandle } = useSectionEdit({
const { editing, setEditing, handleSave, handleDiscard, handleEdit, handlePractice } = useSectionEdit({
sectionId,
mode: "edit",
onSave: () => {
setEditing(false);
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId: sectionId, update: local } });
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId: sectionId, update: local, module } });
if (genResult) {
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: module,
field: "genResult",
value: undefined
}
});
}
},
onDiscard: () => {
setLocal({
@@ -50,32 +62,37 @@ const Speaking1: React.FC<Props> = ({ sectionId, exercise }) => {
]
});
},
onMode: () => { },
onPractice: () => {
const updatedExercise = {
...state,
//isPractice: !isPractice,
};
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: updatedExercise, module: module } });
},
});
useEffect(() => {
if (genResult && generating === "context") {
if (genResult && generating === "speakingScript") {
setEditing(true);
setLocal(prev => ({
...prev,
first_title: genResult[0].first_topic,
second_title: genResult[0].second_topic,
first_title: genResult.result[0].first_topic,
second_title: genResult.result[0].second_topic,
prompts: [
prev.prompts[0],
prev.prompts[1],
...genResult[0].prompts.map((item: any) => ({
...genResult.result[0].prompts.map((item: any) => ({
text: item,
video_url: ""
}))
]
}));
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: currentModule,
field: "genResult",
module: module,
field: "generating",
value: undefined
}
});
@@ -111,15 +128,14 @@ const Speaking1: React.FC<Props> = ({ sectionId, exercise }) => {
useEffect(() => {
if (genResult && generating === "media") {
console.log(genResult[0].prompts);
setLocal({ ...local, prompts: genResult[0].prompts });
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: { ...local, prompts: genResult[0].prompts } } });
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: currentModule,
module: module,
field: "generating",
value: undefined
}
@@ -128,7 +144,7 @@ const Speaking1: React.FC<Props> = ({ sectionId, exercise }) => {
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: currentModule,
module: module,
field: "genResult",
value: undefined
}
@@ -155,14 +171,15 @@ const Speaking1: React.FC<Props> = ({ sectionId, exercise }) => {
description='Generate or write the scripts for the videos.'
editing={editing}
handleSave={handleSave}
modeHandle={modeHandle}
handleEdit={handleEdit}
handleDiscard={handleDiscard}
mode="edit"
handlePractice={handlePractice}
isEvaluationEnabled={true}
module="speaking"
/>
</div>
{generating && generating === "context" ? (
<GenLoader module={currentModule} />
{generating && generating === "speakingScript" ? (
<GenLoader module={module} />
) : (
<>
{editing ? (
@@ -305,8 +322,8 @@ const Speaking1: React.FC<Props> = ({ sectionId, exercise }) => {
</CardContent>
</Card>
)}
{generating && generating === "media" &&
<GenLoader module={currentModule} custom="Generating the videos ... This may take a while ..." />
{generating && generating === "video" &&
<GenLoader module={module} custom="Generating the videos ... This may take a while ..." />
}
<Card>
<CardContent className="pt-6">

View File

@@ -12,52 +12,69 @@ import { AiOutlineUnorderedList } from 'react-icons/ai';
import { BiQuestionMark, BiMessageRoundedDetail } from "react-icons/bi";
import GenLoader from "../Shared/GenLoader";
import { RiVideoLine } from 'react-icons/ri';
import { Module } from "@/interfaces";
interface Props {
sectionId: number;
exercise: SpeakingExercise;
module?: Module;
}
const Speaking2: React.FC<Props> = ({ sectionId, exercise }) => {
const { currentModule, dispatch } = useExamEditorStore();
const Speaking2: React.FC<Props> = ({ sectionId, exercise, module = "speaking" }) => {
const { dispatch } = useExamEditorStore();
const [local, setLocal] = useState(exercise);
const { generating, genResult } = useExamEditorStore(
(state) => state.modules[currentModule].sections.find((section) => section.sectionId === sectionId)!
const { generating, genResult, state } = useExamEditorStore(
(state) => state.modules[module].sections.find((section) => section.sectionId === sectionId)!
);
const { editing, setEditing, handleSave, handleDiscard, modeHandle } = useSectionEdit({
const { editing, setEditing, handleSave, handleDiscard, handleEdit, handlePractice } = useSectionEdit({
sectionId,
mode: "edit",
onSave: () => {
setEditing(false);
console.log(local);
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId: sectionId, update: local } });
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId: sectionId, update: local , module} });
if (genResult) {
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: module,
field: "genResult",
value: undefined
}
});
}
},
onDiscard: () => {
setLocal(exercise);
},
onMode: () => { },
onPractice: () => {
const updatedExercise = {
...state,
//isPractice: !isPractice,
};
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: updatedExercise, module: module } });
},
});
useEffect(() => {
if (genResult && generating === "context") {
if (genResult && generating === "speakingScript") {
setEditing(true);
setLocal({
...local,
title: genResult[0].topic,
text: genResult[0].question,
prompts: genResult[0].prompts
title: genResult.result[0].topic,
text: genResult.result[0].question,
prompts: genResult.result[0].prompts
});
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: currentModule,
field: "genResult",
module: module,
field: "generating",
value: undefined
}
});
@@ -66,27 +83,18 @@ const Speaking2: React.FC<Props> = ({ sectionId, exercise }) => {
}, [genResult, generating]);
useEffect(() => {
if (genResult && generating === "media") {
setLocal({...local, video_url: genResult[0].video_url});
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: {...local, video_url: genResult[0].video_url} } });
if (genResult && generating === "video") {
setLocal({...local, video_url: genResult.result[0].video_url});
dispatch({ type: "UPDATE_SECTION_STATE", payload: { sectionId, update: {...local, video_url: genResult.result[0].video_url} , module} });
dispatch({
type: "UPDATE_SECTION_SINGLE_FIELD",
payload: {
sectionId,
module: currentModule,
module: module,
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, generating]);
@@ -138,14 +146,15 @@ const Speaking2: React.FC<Props> = ({ sectionId, exercise }) => {
description='Generate or write the script for the video.'
editing={editing}
handleSave={handleSave}
modeHandle={modeHandle}
handleEdit={handleEdit}
handleDiscard={handleDiscard}
mode="edit"
handlePractice={handlePractice}
isEvaluationEnabled={true}
module="speaking"
/>
</div>
{generating && generating === "context" ? (
<GenLoader module={currentModule} />
{generating && generating === "speakingScript" ? (
<GenLoader module={module} />
) : (
<>
{editing ? (
@@ -260,8 +269,8 @@ const Speaking2: React.FC<Props> = ({ sectionId, exercise }) => {
</CardContent>
</Card>
}
{generating && generating === "media" &&
<GenLoader module={currentModule} custom="Generating the video ... This may take a while ..." />
{generating && generating === "video" &&
<GenLoader module={module} custom="Generating the video ... This may take a while ..." />
}
<Card>
<CardContent className="pt-6">

View File

@@ -1,12 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import useExamEditorStore from "@/stores/examEditor";
import { ModuleState } from "@/stores/examEditor/types";
import { SpeakingExercise, InteractiveSpeakingExercise } from "@/interfaces/exam";
import useSectionEdit from "../../Hooks/useSectionEdit";
import Header from "../../Shared/Header";
import GenLoader from "../Shared/GenLoader";
import { Card, CardContent } from "@/components/ui/card";
import AutoExpandingTextArea from "@/components/Low/AutoExpandingTextarea";
import Speaking2 from "./Speaking2";
import InteractiveSpeaking from "./InteractiveSpeaking";
import Speaking1 from "./Speaking1";