Navigation rework, added prompt edit to components that were missing
This commit is contained in:
@@ -12,6 +12,7 @@ import { AlertItem } from "../../Shared/Alert";
|
||||
import validateBlanks from "../validateBlanks";
|
||||
import { toast } from "react-toastify";
|
||||
import setEditingAlert from "../../Shared/setEditingAlert";
|
||||
import PromptEdit from "../../Shared/PromptEdit";
|
||||
|
||||
interface Word {
|
||||
letter: string;
|
||||
@@ -38,6 +39,12 @@ const FillBlanksLetters: React.FC<{ exercise: FillBlanksExercise; sectionId: num
|
||||
|
||||
const [editing, setEditing] = useState(false);
|
||||
|
||||
const updateLocal = (exercise: FillBlanksExercise) => {
|
||||
setLocal(exercise);
|
||||
setEditingAlert(true, setAlerts);
|
||||
setEditing(true);
|
||||
};
|
||||
|
||||
const [blanksState, blanksDispatcher] = useReducer(blanksReducer, {
|
||||
text: exercise.text || "",
|
||||
blanks: [],
|
||||
@@ -266,6 +273,8 @@ const FillBlanksLetters: React.FC<{ exercise: FillBlanksExercise; sectionId: num
|
||||
setEditing={setEditing}
|
||||
onPractice={handlePractice}
|
||||
isEvaluationEnabled={!local.isPractice}
|
||||
prompt={local.prompt}
|
||||
updatePrompt={(prompt: string) => updateLocal({...local, prompt})}
|
||||
>
|
||||
<>
|
||||
{!blanksState.textMode && <Card className="p-4">
|
||||
|
||||
@@ -36,6 +36,12 @@ const FillBlanksMC: React.FC<{ exercise: FillBlanksExercise; sectionId: number }
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
const [editing, setEditing] = useState(false);
|
||||
|
||||
const updateLocal = (exercise: FillBlanksExercise) => {
|
||||
setLocal(exercise);
|
||||
setEditingAlert(true, setAlerts);
|
||||
setEditing(true);
|
||||
};
|
||||
|
||||
const [blanksState, blanksDispatcher] = useReducer(blanksReducer, {
|
||||
text: exercise.text || "",
|
||||
blanks: [],
|
||||
@@ -268,6 +274,8 @@ const FillBlanksMC: React.FC<{ exercise: FillBlanksExercise; sectionId: number }
|
||||
setEditing={setEditing}
|
||||
onBlankRemove={handleBlankRemove}
|
||||
isEvaluationEnabled={!local.isPractice}
|
||||
prompt={local.prompt}
|
||||
updatePrompt={(prompt: string) => updateLocal({...local, prompt})}
|
||||
>
|
||||
{!blanksState.textMode && selectedBlankId && (
|
||||
<Card className="p-4">
|
||||
|
||||
@@ -24,6 +24,12 @@ const WriteBlanksFill: React.FC<{ exercise: WriteBlanksExercise; sectionId: numb
|
||||
const [selectedBlankId, setSelectedBlankId] = useState<string | null>(null);
|
||||
const [editing, setEditing] = useState(false);
|
||||
|
||||
const updateLocal = (exercise: WriteBlanksExercise) => {
|
||||
setLocal(exercise);
|
||||
setEditingAlert(true, setAlerts);
|
||||
setEditing(true);
|
||||
};
|
||||
|
||||
const [blanksState, blanksDispatcher] = useReducer(blanksReducer, {
|
||||
text: exercise.text || "",
|
||||
blanks: [],
|
||||
@@ -79,7 +85,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}))
|
||||
setLocal((prev) => ({ ...prev, isPractice: !local.isPractice }))
|
||||
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
|
||||
}
|
||||
});
|
||||
@@ -143,7 +149,7 @@ const WriteBlanksFill: React.FC<{ exercise: WriteBlanksExercise; sectionId: numb
|
||||
...prev,
|
||||
solutions: prev.solutions.filter(s => s.id !== blankId.toString())
|
||||
}));
|
||||
|
||||
|
||||
blanksDispatcher({ type: "REMOVE_BLANK", payload: blankId });
|
||||
};
|
||||
|
||||
@@ -175,6 +181,8 @@ const WriteBlanksFill: React.FC<{ exercise: WriteBlanksExercise; sectionId: numb
|
||||
onPractice={handlePractice}
|
||||
setEditing={setEditing}
|
||||
isEvaluationEnabled={!local.isPractice}
|
||||
prompt={local.prompt}
|
||||
updatePrompt={(prompt: string) => updateLocal({ ...local, prompt })}
|
||||
>
|
||||
{!blanksState.textMode && (
|
||||
<Card>
|
||||
|
||||
@@ -19,6 +19,7 @@ import clsx from "clsx";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Blank, DropZone } from "./DragNDrop";
|
||||
import { getTextSegments, BlankState, BlanksState, BlanksAction, BlankToken } from "./BlanksReducer";
|
||||
import PromptEdit from "../Shared/PromptEdit";
|
||||
|
||||
|
||||
interface Props {
|
||||
@@ -30,6 +31,8 @@ interface Props {
|
||||
editing: boolean;
|
||||
showBlankBank: boolean;
|
||||
alerts: AlertItem[];
|
||||
prompt: string;
|
||||
updatePrompt: (prompt: string) => void;
|
||||
setEditing: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
blanksDispatcher: React.Dispatch<BlanksAction>
|
||||
onBlankSelect?: (blankId: number | null) => void;
|
||||
@@ -42,25 +45,27 @@ interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const BlanksEditor: React.FC<Props> = ({
|
||||
const BlanksEditor: React.FC<Props> = ({
|
||||
title = "Fill Blanks",
|
||||
initialText,
|
||||
description,
|
||||
state,
|
||||
editing,
|
||||
module,
|
||||
children,
|
||||
children,
|
||||
showBlankBank = true,
|
||||
alerts,
|
||||
blanksDispatcher,
|
||||
blanksDispatcher,
|
||||
onBlankSelect,
|
||||
onBlankRemove,
|
||||
onSave,
|
||||
onDiscard,
|
||||
onSave,
|
||||
onDiscard,
|
||||
onDelete,
|
||||
onPractice,
|
||||
isEvaluationEnabled,
|
||||
setEditing
|
||||
setEditing,
|
||||
prompt,
|
||||
updatePrompt
|
||||
}) => {
|
||||
|
||||
useEffect(() => {
|
||||
@@ -105,21 +110,21 @@ const BlanksEditor: React.FC<Props> = ({
|
||||
const handleTextChange = useCallback(
|
||||
(newText: string) => {
|
||||
const processedText = newText.replace(/\[(\d+)\]/g, "{{$1}}");
|
||||
|
||||
|
||||
const existingBlankIds = getTextSegments(state.text)
|
||||
.filter(token => token.type === 'blank')
|
||||
.map(token => (token as BlankToken).id);
|
||||
|
||||
|
||||
const newBlankIds = getTextSegments(processedText)
|
||||
.filter(token => token.type === 'blank')
|
||||
.map(token => (token as BlankToken).id);
|
||||
|
||||
|
||||
const removedBlankIds = existingBlankIds.filter(id => !newBlankIds.includes(id));
|
||||
|
||||
|
||||
removedBlankIds.forEach(id => {
|
||||
onBlankRemove(id);
|
||||
});
|
||||
|
||||
|
||||
blanksDispatcher({ type: "SET_TEXT", payload: processedText });
|
||||
},
|
||||
[blanksDispatcher, state.text, onBlankRemove]
|
||||
@@ -171,10 +176,11 @@ const BlanksEditor: React.FC<Props> = ({
|
||||
isEvaluationEnabled={isEvaluationEnabled}
|
||||
/>
|
||||
{alerts.length > 0 && <Alert alerts={alerts} />}
|
||||
<PromptEdit value={prompt} onChange={(text: string) => updatePrompt(text)} />
|
||||
<Card>
|
||||
<CardContent className="p-4 text-white font-semibold flex gap-2">
|
||||
<button
|
||||
onClick={() => blanksDispatcher({ type: "ADD_BLANK" }) }
|
||||
onClick={() => blanksDispatcher({ type: "ADD_BLANK" })}
|
||||
className={`px-3 py-1.5 bg-ielts-${module} rounded-md hover:bg-ielts-${module}/50 transition-colors`}
|
||||
>
|
||||
Add Blank
|
||||
@@ -203,7 +209,7 @@ const BlanksEditor: React.FC<Props> = ({
|
||||
{state.textMode ? (
|
||||
<AutoExpandingTextArea
|
||||
value={state.text.replace(/{{(\d+)}}/g, "[$1]")}
|
||||
onChange={(text) => { handleTextChange(text); if (!editing) setEditing(true) } }
|
||||
onChange={(text) => { handleTextChange(text); if (!editing) setEditing(true) }}
|
||||
className="w-full h-full min-h-[200px] p-2 bg-white border rounded-md"
|
||||
placeholder="Enter text here. Use [1], [2], etc. for blanks..."
|
||||
/>
|
||||
|
||||
@@ -10,6 +10,7 @@ import useExamEditorStore from "@/stores/examEditor";
|
||||
import { useEffect, useState } from "react";
|
||||
import { MdAdd } from "react-icons/md";
|
||||
import Alert, { AlertItem } from "../../Shared/Alert";
|
||||
import PromptEdit from "../../Shared/PromptEdit";
|
||||
|
||||
|
||||
const UnderlineMultipleChoice: React.FC<{exercise: MultipleChoiceExercise, sectionId: number}> = ({
|
||||
@@ -125,7 +126,7 @@ const UnderlineMultipleChoice: React.FC<{exercise: MultipleChoiceExercise, secti
|
||||
isEvaluationEnabled={!local.isPractice}
|
||||
/>
|
||||
{alerts.length > 0 && <Alert className="mb-6" alerts={alerts} />}
|
||||
|
||||
<PromptEdit value={local.prompt} onChange={(prompt: string) => updateLocal({...local, prompt})} />
|
||||
<div className="space-y-4">
|
||||
<QuestionsList
|
||||
ids={local.questions.map(q => q.id)}
|
||||
|
||||
@@ -17,6 +17,7 @@ import QuestionsList from '../../Shared/QuestionsList';
|
||||
import SortableQuestion from '../../Shared/SortableQuestion';
|
||||
import setEditingAlert from '../../Shared/setEditingAlert';
|
||||
import { handleMultipleChoiceReorder } from '@/stores/examEditor/reorder/local';
|
||||
import PromptEdit from '../../Shared/PromptEdit';
|
||||
|
||||
interface MultipleChoiceProps {
|
||||
exercise: MultipleChoiceExercise;
|
||||
@@ -214,36 +215,7 @@ const MultipleChoice: React.FC<MultipleChoiceProps> = ({ exercise, sectionId, op
|
||||
isEvaluationEnabled={!local.isPractice}
|
||||
/>
|
||||
{alerts.length > 0 && <Alert className="mb-6" alerts={alerts} />}
|
||||
<Card className="mb-6">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex justify-between items-start gap-4">
|
||||
{editingPrompt ? (
|
||||
<textarea
|
||||
className="flex-1 p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none min-h-[100px]"
|
||||
value={local.prompt}
|
||||
onChange={(e) => updateLocal({ ...local, prompt: e.target.value })}
|
||||
onBlur={() => setEditingPrompt(false)}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium text-gray-800 mb-2">Question/Instructions displayed to the student:</h3>
|
||||
<p className="text-gray-600">{local.prompt}</p>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setEditingPrompt(!editingPrompt)}
|
||||
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
{editingPrompt ?
|
||||
<MdEditOff size={20} className="text-gray-500" /> :
|
||||
<MdEdit size={20} className="text-gray-500" />
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<PromptEdit value={local.prompt} onChange={(prompt: string) => updateLocal({...local, prompt})} />
|
||||
<div className="space-y-4">
|
||||
<QuestionsList
|
||||
ids={local.questions.map(q => q.id)}
|
||||
|
||||
@@ -6,44 +6,70 @@ import { MdEdit, MdEditOff } from "react-icons/md";
|
||||
interface Props {
|
||||
value: string;
|
||||
onChange: (text: string) => void;
|
||||
wrapperCard?: boolean;
|
||||
}
|
||||
|
||||
|
||||
const PromptEdit: React.FC<Props> = ({ value, onChange }) => {
|
||||
const PromptEdit: React.FC<Props> = ({ value, onChange, wrapperCard = true }) => {
|
||||
const [editing, setEditing] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card className="mb-6">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex justify-between items-start gap-4">
|
||||
{editing ? (
|
||||
<AutoExpandingTextArea
|
||||
className="flex-1 p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none min-h-[100px]"
|
||||
value={value}
|
||||
onChange={(text) => onChange(text)}
|
||||
onBlur={()=> setEditing(false)}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium text-gray-800 mb-2">Question/Instructions displayed to the student:</h3>
|
||||
<p className="text-gray-600">{value}</p>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setEditing(!editing)}
|
||||
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
{editing ?
|
||||
<MdEditOff size={20} className="text-gray-500" /> :
|
||||
<MdEdit size={20} className="text-gray-500" />
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default PromptEdit;
|
||||
const renderTextWithLineBreaks = (text: string) => {
|
||||
const unescapedText = text.replace(/\\n/g, '\n');
|
||||
return unescapedText.split('\n').map((line, index, array) => (
|
||||
<span key={index}>
|
||||
{line}
|
||||
{index < array.length - 1 && <br />}
|
||||
</span>
|
||||
));
|
||||
};
|
||||
|
||||
const handleTextChange = (text: string) => {
|
||||
const escapedText = text.replace(/\n/g, '\\n');
|
||||
onChange(escapedText);
|
||||
};
|
||||
|
||||
const promptEditTsx = (
|
||||
<div className="flex justify-between items-start gap-4">
|
||||
{editing ? (
|
||||
<AutoExpandingTextArea
|
||||
className="flex-1 p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none min-h-[100px]"
|
||||
value={value.replace(/\\n/g, '\n')}
|
||||
onChange={handleTextChange}
|
||||
onBlur={() => setEditing(false)}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium text-gray-800 mb-2">
|
||||
Question/Instructions displayed to the student:
|
||||
</h3>
|
||||
<p className="text-gray-600">
|
||||
{renderTextWithLineBreaks(value)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setEditing(!editing)}
|
||||
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
{editing ? (
|
||||
<MdEditOff size={20} className="text-gray-500" />
|
||||
) : (
|
||||
<MdEdit size={20} className="text-gray-500" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (!wrapperCard) {
|
||||
return promptEditTsx;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="mb-6">
|
||||
<CardContent className="p-4">
|
||||
{promptEditTsx}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default PromptEdit;
|
||||
|
||||
@@ -21,6 +21,7 @@ import { toast } from 'react-toastify';
|
||||
import { validateEmptySolutions, validateQuestionText, validateWordCount } from './validation';
|
||||
import { handleWriteBlanksReorder } from '@/stores/examEditor/reorder/local';
|
||||
import { ParsedQuestion, parseText, reconstructText } from './parsing';
|
||||
import PromptEdit from '../Shared/PromptEdit';
|
||||
|
||||
|
||||
const WriteBlanks: React.FC<{ sectionId: number; exercise: WriteBlanksExercise; }> = ({ sectionId, exercise }) => {
|
||||
@@ -85,7 +86,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}))
|
||||
setLocal((prev) => ({ ...prev, isPractice: !local.isPractice }))
|
||||
dispatch({ type: 'UPDATE_SECTION_STATE', payload: { sectionId, update: newState, module: currentModule } });
|
||||
}
|
||||
});
|
||||
@@ -246,30 +247,7 @@ const WriteBlanks: React.FC<{ sectionId: number; exercise: WriteBlanksExercise;
|
||||
{alerts.length > 0 && <Alert alerts={alerts} />}
|
||||
<Card className="mb-6">
|
||||
<CardContent className="p-4 space-y-4">
|
||||
<div className="flex justify-between items-start gap-4 mb-6">
|
||||
{editingPrompt ? (
|
||||
<AutoExpandingTextArea
|
||||
className="flex-1 p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none min-h-[100px]"
|
||||
value={local.prompt}
|
||||
onChange={(text) => updateLocal({ ...local, prompt: text })}
|
||||
onBlur={() => setEditingPrompt(false)}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium text-gray-800 mb-2">Question/Instructions displayed to the student:</h3>
|
||||
<p className="text-gray-600">{local.prompt}</p>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setEditingPrompt(!editingPrompt)}
|
||||
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
{editingPrompt ?
|
||||
<MdEditOff size={20} className="text-gray-500" /> :
|
||||
<MdEdit size={20} className="text-gray-500" />
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
<PromptEdit value={local.prompt} onChange={(prompt: string) => updateLocal({ ...local, prompt })} wrapperCard={false}/>
|
||||
<div className="flex justify-between items-start gap-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<label className="flex items-center gap-2">
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ParsedQuestion, parseLine, reconstructLine } from "./parsing";
|
||||
import { validateQuestions, validateEmptySolutions, validateWordCount } from "./validation";
|
||||
import Header from "../../Shared/Header";
|
||||
import BlanksFormEditor from "./BlanksFormEditor";
|
||||
import PromptEdit from "../Shared/PromptEdit";
|
||||
|
||||
|
||||
const WriteBlanksForm: React.FC<{ sectionId: number; exercise: WriteBlanksExercise }> = ({ sectionId, exercise }) => {
|
||||
@@ -220,49 +221,7 @@ const WriteBlanksForm: React.FC<{ sectionId: number; exercise: WriteBlanksExerci
|
||||
/>
|
||||
<div className="space-y-4">
|
||||
{alerts.length > 0 && <Alert alerts={alerts} />}
|
||||
<Card className="mb-6">
|
||||
<CardContent className="p-4 space-y-4">
|
||||
<div className="flex justify-between items-start gap-4 mb-6">
|
||||
{editingPrompt ? (
|
||||
<AutoExpandingTextArea
|
||||
className="flex-1 p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none min-h-[100px]"
|
||||
value={local.prompt}
|
||||
onChange={(text) => updateLocal({ ...local, prompt: text })}
|
||||
onBlur={() => setEditingPrompt(false)}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium text-gray-800 mb-2">Question/Instructions:</h3>
|
||||
<p className="text-gray-600">{local.prompt}</p>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setEditingPrompt(!editingPrompt)}
|
||||
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
{editingPrompt ?
|
||||
<MdEditOff size={20} className="text-gray-500" /> :
|
||||
<MdEdit size={20} className="text-gray-500" />
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex justify-between items-start gap-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<label className="flex items-center gap-2">
|
||||
<span className="font-medium text-gray-800">Maximum words per solution:</span>
|
||||
<input
|
||||
type="number"
|
||||
value={local.maxWords}
|
||||
onChange={(e) => updateLocal({ ...local, maxWords: parseInt(e.target.value) })}
|
||||
className="w-20 p-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
min="1"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<PromptEdit value={local.prompt} onChange={(prompt: string) => updateLocal({ ...local, prompt })}/>
|
||||
<div className="space-y-4">
|
||||
<QuestionsList
|
||||
ids={parsedQuestions.map(q => q.id)}
|
||||
|
||||
@@ -6,12 +6,12 @@ import clsx from "clsx";
|
||||
import ExercisePicker from "../ExercisePicker";
|
||||
import useExamEditorStore from "@/stores/examEditor";
|
||||
import useSettingsState from "../Hooks/useSettingsState";
|
||||
import { LevelSectionSettings, SectionSettings } from "@/stores/examEditor/types";
|
||||
import { LevelSectionSettings } from "@/stores/examEditor/types";
|
||||
import { toast } from "react-toastify";
|
||||
import axios from "axios";
|
||||
import { playSound } from "@/utils/sound";
|
||||
import { useRouter } from "next/router";
|
||||
import { usePersistentExamStore } from "@/stores/examStore";
|
||||
import { usePersistentExamStore } from "@/stores/exam";
|
||||
import openDetachedTab from "@/utils/popout";
|
||||
import ListeningComponents from "./listening/components";
|
||||
import ReadingComponents from "./reading/components";
|
||||
|
||||
@@ -13,7 +13,7 @@ import Input from "@/components/Low/Input";
|
||||
import openDetachedTab from "@/utils/popout";
|
||||
import { useRouter } from "next/router";
|
||||
import axios from "axios";
|
||||
import { usePersistentExamStore } from "@/stores/examStore";
|
||||
import { usePersistentExamStore } from "@/stores/exam";
|
||||
import { playSound } from "@/utils/sound";
|
||||
import { toast } from "react-toastify";
|
||||
import ListeningComponents from "./components";
|
||||
@@ -98,16 +98,16 @@ const ListeningSettings: React.FC = () => {
|
||||
const { urls } = response.data;
|
||||
|
||||
const exam: ListeningExam = {
|
||||
parts: sections.map((s) => {
|
||||
const exercise = s.state as ListeningPart;
|
||||
parts: sectionsWithAudio.map((s) => {
|
||||
const part = s.state as ListeningPart;
|
||||
const index = Array.from(sectionMap.entries())
|
||||
.findIndex(([id]) => id === s.sectionId);
|
||||
|
||||
return {
|
||||
...exercise,
|
||||
audio: exercise.audio ? {
|
||||
...exercise.audio,
|
||||
source: index !== -1 ? urls[index] : exercise.audio.source
|
||||
...part,
|
||||
audio: part.audio ? {
|
||||
...part.audio,
|
||||
source: index !== -1 ? urls[index] : part.audio.source
|
||||
} : undefined,
|
||||
intro: s.settings.currentIntro,
|
||||
category: s.settings.category
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ReadingSectionSettings } from "@/stores/examEditor/types";
|
||||
import useExamEditorStore from "@/stores/examEditor";
|
||||
import openDetachedTab from "@/utils/popout";
|
||||
import { useRouter } from "next/router";
|
||||
import { usePersistentExamStore } from "@/stores/examStore";
|
||||
import { usePersistentExamStore } from "@/stores/exam";
|
||||
import axios from "axios";
|
||||
import { playSound } from "@/utils/sound";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -98,9 +98,9 @@ const ReadingSettings: React.FC = () => {
|
||||
const preview = () => {
|
||||
setExam({
|
||||
parts: sections.map((s) => {
|
||||
const exercise = s.state as ReadingPart;
|
||||
const exercises = s.state as ReadingPart;
|
||||
return {
|
||||
...exercise,
|
||||
...exercises,
|
||||
intro: s.settings.currentIntro,
|
||||
category: s.settings.category
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import Option from "@/interfaces/option";
|
||||
import SettingsEditor from "..";
|
||||
import { InteractiveSpeakingExercise, SpeakingExam, SpeakingExercise } from "@/interfaces/exam";
|
||||
import { toast } from "react-toastify";
|
||||
import { usePersistentExamStore } from "@/stores/examStore";
|
||||
import { usePersistentExamStore } from "@/stores/exam";
|
||||
import { useRouter } from "next/router";
|
||||
import openDetachedTab from "@/utils/popout";
|
||||
import axios from "axios";
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import SettingsEditor from "..";
|
||||
import Option from "@/interfaces/option";
|
||||
import Dropdown from "../Shared/SettingsDropdown";
|
||||
import Input from "@/components/Low/Input";
|
||||
import { generate } from "../Shared/Generate";
|
||||
import useSettingsState from "../../Hooks/useSettingsState";
|
||||
import GenerateBtn from "../Shared/GenerateBtn";
|
||||
import { WritingSectionSettings } from "@/stores/examEditor/types";
|
||||
import useExamEditorStore from "@/stores/examEditor";
|
||||
import { useRouter } from "next/router";
|
||||
import { usePersistentExamStore } from "@/stores/examStore";
|
||||
import { usePersistentExamStore } from "@/stores/exam";
|
||||
import openDetachedTab from "@/utils/popout";
|
||||
import { WritingExam, WritingExercise } from "@/interfaces/exam";
|
||||
import { v4 } from "uuid";
|
||||
|
||||
Reference in New Issue
Block a user