Compare commits
2 Commits
869e857f2c
...
fa8f705a75
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa8f705a75 | ||
|
|
cda04660bf |
21
package-lock.json
generated
21
package-lock.json
generated
|
|
@ -30,6 +30,7 @@
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
|
"react-intersection-observer": "^9.13.1",
|
||||||
"react-katex": "^3.0.1",
|
"react-katex": "^3.0.1",
|
||||||
"react-latex": "^2.0.0",
|
"react-latex": "^2.0.0",
|
||||||
"react-latex-next": "^3.0.0",
|
"react-latex-next": "^3.0.0",
|
||||||
|
|
@ -8928,6 +8929,20 @@
|
||||||
"react": "*"
|
"react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-intersection-observer": {
|
||||||
|
"version": "9.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.13.1.tgz",
|
||||||
|
"integrity": "sha512-tSzDaTy0qwNPLJHg8XZhlyHTgGW6drFKTtvjdL+p6um12rcnp8Z5XstE+QNBJ7c64n5o0Lj4ilUleA41bmDoMw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
|
@ -17330,6 +17345,12 @@
|
||||||
"integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
|
"integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"react-intersection-observer": {
|
||||||
|
"version": "9.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.13.1.tgz",
|
||||||
|
"integrity": "sha512-tSzDaTy0qwNPLJHg8XZhlyHTgGW6drFKTtvjdL+p6um12rcnp8Z5XstE+QNBJ7c64n5o0Lj4ilUleA41bmDoMw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
|
"react-intersection-observer": "^9.13.1",
|
||||||
"react-katex": "^3.0.1",
|
"react-katex": "^3.0.1",
|
||||||
"react-latex": "^2.0.0",
|
"react-latex": "^2.0.0",
|
||||||
"react-latex-next": "^3.0.0",
|
"react-latex-next": "^3.0.0",
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,6 @@ const LaTeXInput = ({name,label,...props}:ILaTeXInput) => {
|
||||||
const { ShowLatexOption } = useObjectToEdit();
|
const { ShowLatexOption } = useObjectToEdit();
|
||||||
const [showPreview, setShowPreview] = useState(false) ;
|
const [showPreview, setShowPreview] = useState(false) ;
|
||||||
const value = getFieldProps(name)?.value
|
const value = getFieldProps(name)?.value
|
||||||
const handleChangeInput =
|
|
||||||
(
|
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
|
||||||
) => {
|
|
||||||
setFieldValue(name,e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Preview = parseTextAndLatex(value ?? "") ;
|
const Preview = parseTextAndLatex(value ?? "") ;
|
||||||
|
|
||||||
|
|
@ -54,6 +48,12 @@ const LaTeXInput = ({name,label,...props}:ILaTeXInput) => {
|
||||||
setLatex(item)
|
setLatex(item)
|
||||||
setIsEditModalOpen(true)
|
setIsEditModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [curCentValue, setCurrentValue] = useState(value)
|
||||||
|
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
setFieldValue(name, e.target.value);
|
||||||
|
setCurrentValue(e.target.value)
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className='LaTeXInput'>
|
<div className='LaTeXInput'>
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ const LaTeXInput = ({name,label,...props}:ILaTeXInput) => {
|
||||||
autoSize={{ minRows: 6, maxRows: 10 }}
|
autoSize={{ minRows: 6, maxRows: 10 }}
|
||||||
style={{height:"400px"}}
|
style={{height:"400px"}}
|
||||||
onChange={handleChangeInput}
|
onChange={handleChangeInput}
|
||||||
value={value}
|
value={curCentValue}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
||||||
const { setFieldValue } = form;
|
const { setFieldValue } = form;
|
||||||
|
|
||||||
const { ShowLatexOption } = useObjectToEdit();
|
const { ShowLatexOption } = useObjectToEdit();
|
||||||
const [showPreview, setShowPreview] = useState(false);
|
const [showPreview, setShowPreview] = useState(false);
|
||||||
|
|
||||||
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
||||||
setFieldValue(name, e.target.value);
|
|
||||||
};
|
|
||||||
console.log(name,"name");
|
|
||||||
|
|
||||||
const Preview = parseTextAndLatex(value ?? "");
|
const Preview = parseTextAndLatex(value ?? "");
|
||||||
|
|
||||||
const onPreviewChange: CheckboxProps['onChange'] = (e) => {
|
const onPreviewChange: CheckboxProps['onChange'] = (e) => {
|
||||||
|
|
@ -50,6 +44,15 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
||||||
setIsEditModalOpen(true);
|
setIsEditModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [curCentValue, setCurrentValue] = useState(value)
|
||||||
|
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
setCurrentValue(e.target.value)
|
||||||
|
};
|
||||||
|
const onBlur = ()=>{
|
||||||
|
|
||||||
|
setFieldValue(name, curCentValue);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='LaTeXInput'>
|
<div className='LaTeXInput'>
|
||||||
<label htmlFor={name} className="text">
|
<label htmlFor={name} className="text">
|
||||||
|
|
@ -64,7 +67,8 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
||||||
autoSize={{ minRows: 6, maxRows: 10 }}
|
autoSize={{ minRows: 6, maxRows: 10 }}
|
||||||
style={{ height: "400px" }}
|
style={{ height: "400px" }}
|
||||||
onChange={handleChangeInput}
|
onChange={handleChangeInput}
|
||||||
value={value}
|
value={curCentValue}
|
||||||
|
onBlur={onBlur}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
67
src/Pages/Admin/question/Model/Malty/components/Question.tsx
Normal file
67
src/Pages/Admin/question/Model/Malty/components/Question.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import React, { useCallback } from "react";
|
||||||
|
import { Choice } from "../../../../../../types/Item";
|
||||||
|
import QuestionFIeld from "../QuestionFIeld/QuestionFIeld";
|
||||||
|
import Choices from "../ChoiceField/Choices";
|
||||||
|
import { FaCirclePlus } from "react-icons/fa6";
|
||||||
|
import ValidationField from "../../../../../../Components/ValidationField/ValidationField";
|
||||||
|
import MaltySelectTag from "../Tags/MaltySelectTag";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
export const Question: React.FC<any> = React.memo(({ index, data }) => {
|
||||||
|
const { values, setFieldValue, ShowHint, t } = data;
|
||||||
|
|
||||||
|
const handleAddChoice = useCallback((
|
||||||
|
parent_index: number,
|
||||||
|
fromKeyCombination: boolean = false,
|
||||||
|
) => {
|
||||||
|
setFieldValue(`Questions.[${parent_index}].answers`, [
|
||||||
|
...(values?.Questions?.[parent_index]?.answers as Choice[]),
|
||||||
|
{
|
||||||
|
answer: null,
|
||||||
|
content_image: null,
|
||||||
|
content: null,
|
||||||
|
isCorrect: 0,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (fromKeyCombination) {
|
||||||
|
toast.success(t("header.new_choice_have_been_added"));
|
||||||
|
}
|
||||||
|
}, [setFieldValue, values, t]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div >
|
||||||
|
<div className="exercise_form QuestionFIeld">
|
||||||
|
<QuestionFIeld setFieldValue={setFieldValue} values={values} key={index} index={index} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Choices setFieldValue={setFieldValue} values={values} parent_index={index} />
|
||||||
|
|
||||||
|
{values?.Questions?.[index]?.answers?.length < 5 && (
|
||||||
|
<p className="add_new_button">
|
||||||
|
<FaCirclePlus
|
||||||
|
onClick={() => handleAddChoice(index)}
|
||||||
|
size={23}
|
||||||
|
/>{" "}
|
||||||
|
{t("header.add_new_choice")}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="exercise_form_width">
|
||||||
|
{ShowHint && (
|
||||||
|
<ValidationField
|
||||||
|
className=" "
|
||||||
|
placeholder="_"
|
||||||
|
name={`Questions.${index}.hint`}
|
||||||
|
label="hint_question"
|
||||||
|
type="TextArea"
|
||||||
|
style={{ width: "100%", height: 60, resize: "none" }}
|
||||||
|
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
|
showCount={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<MaltySelectTag parent_index={index} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
import React, { useCallback, useMemo } from 'react';
|
|
||||||
import { FixedSizeList as List, areEqual } from 'react-window';
|
|
||||||
import { Choice } from '../../../../../../types/Item';
|
|
||||||
import QuestionFIeld from '../QuestionFIeld/QuestionFIeld';
|
|
||||||
import Choices from '../ChoiceField/Choices';
|
|
||||||
import { FaCirclePlus } from 'react-icons/fa6';
|
|
||||||
import ValidationField from '../../../../../../Components/ValidationField/ValidationField';
|
|
||||||
import MaltySelectTag from '../Tags/MaltySelectTag';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useObjectToEdit } from '../../../../../../zustand/ObjectToEditState';
|
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
|
|
||||||
interface QuestionsProps {
|
|
||||||
setFieldValue: (field: string, value: any) => void;
|
|
||||||
values: {
|
|
||||||
Questions: Choice[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const Row: React.FC<any> = React.memo(({ index, data }) => {
|
|
||||||
const { values, setFieldValue } = data;
|
|
||||||
const { ShowHint } = useObjectToEdit();
|
|
||||||
const [t] = useTranslation();
|
|
||||||
|
|
||||||
const handleAddChoice = useCallback((
|
|
||||||
parent_index: number,
|
|
||||||
fromKeyCombination: boolean = false,
|
|
||||||
) => {
|
|
||||||
setFieldValue(`Questions.[${parent_index}].answers`, [
|
|
||||||
...(values?.Questions?.[parent_index]?.answers as Choice[]),
|
|
||||||
{
|
|
||||||
answer: null,
|
|
||||||
content_image: null,
|
|
||||||
content: null,
|
|
||||||
isCorrect: 0,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (fromKeyCombination) {
|
|
||||||
toast.success(t("header.new_choice_have_been_added"));
|
|
||||||
}
|
|
||||||
}, [setFieldValue, values, t]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={index}>
|
|
||||||
<div className="exercise_form QuestionFIeld">
|
|
||||||
<QuestionFIeld setFieldValue={setFieldValue} values={values} key={index} index={index} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Choices setFieldValue={setFieldValue} values={values} parent_index={index} />
|
|
||||||
|
|
||||||
{values?.Questions?.[index]?.answers?.length < 5 && (
|
|
||||||
<p className="add_new_button">
|
|
||||||
<FaCirclePlus
|
|
||||||
onClick={() => handleAddChoice(index)}
|
|
||||||
size={23}
|
|
||||||
/>{" "}
|
|
||||||
{t("header.add_new_choice")}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="exercise_form_width">
|
|
||||||
{ShowHint && (
|
|
||||||
<ValidationField
|
|
||||||
className=" "
|
|
||||||
placeholder="_"
|
|
||||||
name={`Questions.${index}.hint`}
|
|
||||||
label="hint_question"
|
|
||||||
type="TextArea"
|
|
||||||
style={{ width: "100%", height: 60, resize: "none" }}
|
|
||||||
autoSize={{ minRows: 2, maxRows: 10 }}
|
|
||||||
showCount={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<MaltySelectTag parent_index={index} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}, areEqual);
|
|
||||||
|
|
||||||
const Questions: React.FC<QuestionsProps> = React.memo(({ setFieldValue, values }) => {
|
|
||||||
const questions = values.Questions || [];
|
|
||||||
|
|
||||||
const itemData = useMemo(() => ({ values, setFieldValue }), [values, setFieldValue]);
|
|
||||||
const itemSize = 1100;
|
|
||||||
const listHeight = useMemo(() => {
|
|
||||||
return Math.min(1300, questions.length * itemSize); // Adjust 400 to your desired max height
|
|
||||||
}, [questions.length]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<List
|
|
||||||
height={listHeight}
|
|
||||||
itemCount={questions.length}
|
|
||||||
itemSize={itemSize}
|
|
||||||
width="100%"
|
|
||||||
itemData={itemData}
|
|
||||||
direction='rtl'
|
|
||||||
>
|
|
||||||
{Row}
|
|
||||||
</List>
|
|
||||||
|
|
||||||
{/* {(values?.Questions || [])?.map(
|
|
||||||
(item: Choice, parent_index: number) => {
|
|
||||||
return (
|
|
||||||
<Row key={parent_index} index={parent_index} data={{values, setFieldValue}} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)} */}
|
|
||||||
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}, (prevProps, nextProps) => prevProps.values.Questions === nextProps.values.Questions);
|
|
||||||
|
|
||||||
export default Questions;
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import QuestionFIeld from '../QuestionFIeld/QuestionFIeld';
|
|
||||||
import { Choice } from '../../../../../../types/Item';
|
|
||||||
import Choices from '../ChoiceField/Choices';
|
|
||||||
import { FaCirclePlus } from 'react-icons/fa6';
|
|
||||||
import ValidationField from '../../../../../../Components/ValidationField/ValidationField';
|
|
||||||
import MaltySelectTag from '../Tags/MaltySelectTag';
|
|
||||||
import { useObjectToEdit } from '../../../../../../zustand/ObjectToEditState';
|
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
// Memoized Questions Component
|
|
||||||
const Questions = React.memo(({setFieldValue,values}:any) => {
|
|
||||||
const { ShowHint } = useObjectToEdit();
|
|
||||||
const [t] = useTranslation();
|
|
||||||
|
|
||||||
const handleAddChoice = (
|
|
||||||
parent_index: number,
|
|
||||||
fromKeyCombination: boolean = false,
|
|
||||||
) => {
|
|
||||||
setFieldValue(`Questions.[${parent_index}].answers`, [
|
|
||||||
...((values as any)?.Questions?.[parent_index]
|
|
||||||
?.answers as Choice[]),
|
|
||||||
{
|
|
||||||
answer: null,
|
|
||||||
content_image: null,
|
|
||||||
content: null,
|
|
||||||
isCorrect: 0,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (fromKeyCombination) {
|
|
||||||
toast.success(t("header.new_choice_have_been_added"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{(values?.Questions || [])?.map(
|
|
||||||
(item: Choice, parent_index: number) => {
|
|
||||||
return (
|
|
||||||
<div key={parent_index}>
|
|
||||||
<div className="exercise_form QuestionFIeld">
|
|
||||||
<QuestionFIeld setFieldValue={setFieldValue} values={values} key={parent_index} index={parent_index} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Choices setFieldValue={setFieldValue} values={values} parent_index={parent_index} />
|
|
||||||
|
|
||||||
{values?.Questions?.[parent_index]?.answers?.length < 5 && (
|
|
||||||
<p className="add_new_button">
|
|
||||||
<FaCirclePlus
|
|
||||||
onClick={() => handleAddChoice(parent_index)}
|
|
||||||
size={23}
|
|
||||||
/>{" "}
|
|
||||||
{t("header.add_new_choice")}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="exercise_form_width">
|
|
||||||
{ShowHint && (
|
|
||||||
<ValidationField
|
|
||||||
className=" "
|
|
||||||
placeholder="_"
|
|
||||||
name={`Questions.${parent_index}.hint`}
|
|
||||||
label="hint_question"
|
|
||||||
type="TextArea"
|
|
||||||
style={{ width: "100%", height: 60, resize: "none" }}
|
|
||||||
autoSize={{ minRows: 2, maxRows: 10 }}
|
|
||||||
showCount={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<MaltySelectTag parent_index={parent_index} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}, (prevProps, nextProps) => {
|
|
||||||
|
|
||||||
return prevProps.values.Questions === nextProps.values.Questions;
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Questions;
|
|
||||||
|
|
@ -1,14 +1,8 @@
|
||||||
import React, { useCallback, useMemo, useRef, useEffect } from 'react';
|
import React, { useCallback, useMemo, useRef, useEffect } from 'react';
|
||||||
import { VariableSizeList as List } from 'react-window';
|
import { VariableSizeList as List } from 'react-window';
|
||||||
import { Choice } from '../../../../../../types/Item';
|
|
||||||
import QuestionFIeld from '../QuestionFIeld/QuestionFIeld';
|
|
||||||
import Choices from '../ChoiceField/Choices';
|
|
||||||
import { FaCirclePlus } from 'react-icons/fa6';
|
|
||||||
import ValidationField from '../../../../../../Components/ValidationField/ValidationField';
|
|
||||||
import MaltySelectTag from '../Tags/MaltySelectTag';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useObjectToEdit } from '../../../../../../zustand/ObjectToEditState';
|
import { useObjectToEdit } from '../../../../../../zustand/ObjectToEditState';
|
||||||
import { toast } from 'react-toastify';
|
import { Question } from './Question';
|
||||||
|
|
||||||
interface QuestionsProps {
|
interface QuestionsProps {
|
||||||
setFieldValue: (field: string, value: any) => void;
|
setFieldValue: (field: string, value: any) => void;
|
||||||
|
|
@ -17,67 +11,8 @@ interface QuestionsProps {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Row: React.FC<any> = React.memo(({ index, style, data }) => {
|
|
||||||
const { values, setFieldValue, ShowHint, t } = data;
|
|
||||||
|
|
||||||
const handleAddChoice = useCallback((
|
|
||||||
parent_index: number,
|
|
||||||
fromKeyCombination: boolean = false,
|
|
||||||
) => {
|
|
||||||
setFieldValue(`Questions.[${parent_index}].answers`, [
|
|
||||||
...(values?.Questions?.[parent_index]?.answers as Choice[]),
|
|
||||||
{
|
|
||||||
answer: null,
|
|
||||||
content_image: null,
|
|
||||||
content: null,
|
|
||||||
isCorrect: 0,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (fromKeyCombination) {
|
|
||||||
toast.success(t("header.new_choice_have_been_added"));
|
|
||||||
}
|
|
||||||
}, [setFieldValue, values, t]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={style}>
|
|
||||||
<div className="exercise_form QuestionFIeld">
|
|
||||||
<QuestionFIeld setFieldValue={setFieldValue} values={values} key={index} index={index} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Choices setFieldValue={setFieldValue} values={values} parent_index={index} />
|
|
||||||
|
|
||||||
{values?.Questions?.[index]?.answers?.length < 5 && (
|
|
||||||
<p className="add_new_button">
|
|
||||||
<FaCirclePlus
|
|
||||||
onClick={() => handleAddChoice(index)}
|
|
||||||
size={23}
|
|
||||||
/>{" "}
|
|
||||||
{t("header.add_new_choice")}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="exercise_form_width">
|
|
||||||
{ShowHint && (
|
|
||||||
<ValidationField
|
|
||||||
className=" "
|
|
||||||
placeholder="_"
|
|
||||||
name={`Questions.${index}.hint`}
|
|
||||||
label="hint_question"
|
|
||||||
type="TextArea"
|
|
||||||
style={{ width: "100%", height: 60, resize: "none" }}
|
|
||||||
autoSize={{ minRows: 2, maxRows: 10 }}
|
|
||||||
showCount={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<MaltySelectTag parent_index={index} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const Questions: React.FC<QuestionsProps> = React.memo(({ setFieldValue, values }) => {
|
const Questions: React.FC<QuestionsProps> = React.memo(({ setFieldValue, values }) => {
|
||||||
const questions = values.Questions || [];
|
const questions = values?.Questions || [];
|
||||||
const { ShowHint } = useObjectToEdit();
|
const { ShowHint } = useObjectToEdit();
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const listRef = useRef<List>(null);
|
const listRef = useRef<List>(null);
|
||||||
|
|
@ -90,7 +25,8 @@ const Questions: React.FC<QuestionsProps> = React.memo(({ setFieldValue, values
|
||||||
if (question.answers?.length < 5) height += 40; // "Add new choice" button
|
if (question.answers?.length < 5) height += 40; // "Add new choice" button
|
||||||
if (ShowHint) height += 80; // Hint field
|
if (ShowHint) height += 80; // Hint field
|
||||||
height += 50; // MaltySelectTag
|
height += 50; // MaltySelectTag
|
||||||
|
console.log(height);
|
||||||
|
|
||||||
return height;
|
return height;
|
||||||
}, [questions, ShowHint]);
|
}, [questions, ShowHint]);
|
||||||
|
|
||||||
|
|
@ -108,19 +44,27 @@ const Questions: React.FC<QuestionsProps> = React.memo(({ setFieldValue, values
|
||||||
}, [questions, ShowHint]);
|
}, [questions, ShowHint]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List
|
<>
|
||||||
|
{/* <List
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
height={window.innerHeight - 20} // Adjust based on your layout
|
height={window.innerHeight - 450} // Adjust based on your layout
|
||||||
itemCount={questions.length}
|
itemCount={questions?.length}
|
||||||
itemSize={getItemSize}
|
itemSize={getItemSize}
|
||||||
width="100%"
|
width="100%"
|
||||||
itemData={itemData}
|
itemData={itemData}
|
||||||
direction='rtl'
|
direction='rtl'
|
||||||
className='ListQuestions'
|
className='ListQuestions'
|
||||||
>
|
>
|
||||||
{Row}
|
|
||||||
</List>
|
{Question}
|
||||||
|
</List> */}
|
||||||
|
{questions?.map((item:any,index:number)=>{
|
||||||
|
return (
|
||||||
|
<Question key={index} index={index} data={{ values, setFieldValue, ShowHint, t }} />
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}, (prevProps, nextProps) => prevProps.values.Questions === nextProps.values.Questions);
|
}, (prevProps, nextProps) => prevProps?.values?.Questions === nextProps?.values?.Questions);
|
||||||
|
|
||||||
export default Questions;
|
export default Questions;
|
||||||
|
|
@ -1,11 +1,29 @@
|
||||||
|
import { Formik,Form, Field } from "formik";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import LaTeXInputMemo from "./LaTeXInputMemo";
|
||||||
const Dummy = () => {
|
const Dummy = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div className="DummyHomePage">
|
<div className="DummyHomePage">
|
||||||
|
|
||||||
|
<Formik initialValues={{}} onSubmit={()=>{}}>
|
||||||
|
<Form>
|
||||||
|
{Array.from({length:1000}).map((item:any,index)=>{
|
||||||
|
return (
|
||||||
|
<div key={index}>
|
||||||
|
|
||||||
|
<Field
|
||||||
|
name={`content${index}`}
|
||||||
|
component={LaTeXInputMemo}
|
||||||
|
label={t("input.answer_content")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Form>
|
||||||
|
</Formik>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
63
src/Pages/Home/LaTeXInputMemo.tsx
Normal file
63
src/Pages/Home/LaTeXInputMemo.tsx
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import TextArea from 'antd/es/input/TextArea';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...props }) => {
|
||||||
|
const { name ,value} = field;
|
||||||
|
|
||||||
|
const { setFieldValue } = form;
|
||||||
|
const [curCentValue, setCurrentValue] = useState(value)
|
||||||
|
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
setFieldValue(name, e.target.value);
|
||||||
|
setCurrentValue(e.target.value)
|
||||||
|
};
|
||||||
|
console.log(name,"name");
|
||||||
|
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='LaTeXInput'>
|
||||||
|
<label htmlFor={name} className="text">
|
||||||
|
{t(label || name)}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className='LaTeXInputArea'>
|
||||||
|
<TextArea
|
||||||
|
size="large"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
autoSize={{ minRows: 6, maxRows: 10 }}
|
||||||
|
style={{ height: "400px" }}
|
||||||
|
onChange={handleChangeInput}
|
||||||
|
value={curCentValue}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, (
|
||||||
|
prevProps: any,
|
||||||
|
nextProps: any
|
||||||
|
): boolean => {
|
||||||
|
const prevError = prevProps.form.errors[prevProps.field.name];
|
||||||
|
const nextError = nextProps.form.errors[nextProps.field.name];
|
||||||
|
|
||||||
|
const prevTouched = prevProps.form.touched[prevProps.field.name];
|
||||||
|
const nextTouched = nextProps.form.touched[nextProps.field.name];
|
||||||
|
|
||||||
|
const prevValue = prevProps.field.value;
|
||||||
|
const nextValue = nextProps.field.value;
|
||||||
|
|
||||||
|
return (
|
||||||
|
prevValue === nextValue
|
||||||
|
&&
|
||||||
|
prevError === nextError &&
|
||||||
|
prevTouched === nextTouched
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
export default LaTeXInputMemo;
|
||||||
|
|
@ -357,5 +357,6 @@
|
||||||
|
|
||||||
|
|
||||||
.ListQuestions{
|
.ListQuestions{
|
||||||
@include Scrollbar()
|
@include Scrollbar();
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user